Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: avc от 16-05-2019, 18:19:58

Название: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 16-05-2019, 18:19:58
Некоторым пользователям удобно в английском Автокаде видеть русские диалоги настройки плагинов. Я создал локализованные компоненты WinForms, закинул их в один общий компонент OptionsCommonList (в нем уже локализация выключена ибо нет никаких своих ресурсов) и далее закидываю его в диалог настроек Автокада:
Код - C# [Выбрать]
  1.     private void Application_DisplayingOptionDialog(object sender, TabbedDialogEventArgs e)
  2.     {
  3.       CultureInfo old = Thread.CurrentThread.CurrentUICulture;
  4.       if (MySettings.UseWinLocale) // пользователь хочет диалоги на языке Windows, а не AutoСAD
  5.       {
  6.         CultureInfo win = Thread.CurrentThread.CurrentCulture;
  7.         if (old != win) Thread.CurrentThread.CurrentUICulture = win;
  8.       }
  9.       try
  10.       {
  11.         if (_CommonList == null) _CommonList = new OptionsCommonList();
  12.         TabbedDialogExtension tde = new TabbedDialogExtension(_CommonList, save, load, help, save);
  13.         e.AddTab("A>V>C>", tde);
  14.       }
  15.       finally
  16.       {
  17.         if (old != Thread.CurrentThread.CurrentUICulture)
  18.           Thread.CurrentThread.CurrentUICulture = old;
  19.       }
  20.     }
На моей Win7 все прекрасно работает. Но у пользователей с Win10 твориться полный бардак - компоненты переведены через строчку - часть на русском, часть на английском. На некоторых системах даже в русском Автокаде выводятся настройки по английски. А сегодня мне написали что и под Win7 не срабатывает перевод на русский.
Вопрос в том есть ли какой-то более корректный способ переключения языка у конкретного компонента WinForm? Свойство Language вижу в редакторе форм, но не вижу из кода (protected?)
Извините, вам запрещён просмотр содержимого спойлеров.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Александр Ривилис от 17-05-2019, 00:03:45
Думаю, что так ничего не получится. AutoCAD сам переопределяет Thread.CurrentThread.CurrentUICulture и Thread.CurrentThread.CurrentCulture. И в разных версиях это по-разному.
Если тебя интересует CultureInfo для Windows, то CultureInfo.InstalledUICulture
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 12:03:59
Как вариант - можно попробовать напрямую подключать ресурсы для нужного языка: https://www.dotnetcurry.com/ShowArticle.aspx?ID=174
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 12:12:40
Я видел, что у resources.ApplyResources есть параметр CultureInfo, но стандартный редактор форм его не использует. Писать свой код с вызовом ApplyResources для КАЖДОГО компонента форм - это пожалуй через чур сложно... Хотя можно попробовать... Спасибо за идею
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 12:15:30
Писать свой код с вызовом ApplyResources для КАЖДОГО компонента форм - это пожалуй через чур сложно...
Я так понимаю, что вот эта функция из статьи применяет локализацию сразу ко всей форме:
Код - C# [Выбрать]
  1. private void ChangeLanguage(string lang)
  2.         {
  3.             foreach (Control c in this.Controls)
  4.             {
  5.                 ComponentResourceManager resources = new ComponentResourceManager(typeof(Form1));
  6.                 resources.ApplyResources(c, c.Name, new CultureInfo(lang));
  7.             }
  8.         }
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 12:38:45
Вот ещё интересный код на эту тему: https://stackoverflow.com/a/10389737
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Александр Ривилис от 17-05-2019, 13:31:57
avc,
Я правильно понимаю, что у тебя эта форма на двух языках (русский/английский)? В самом крайнем случае сделай две формы на двух языках и в зависимости от условия вызывай или одну или другую.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 14:43:58
Я так понимаю, что вот эта функция из статьи применяет локализацию сразу ко всей форме:
Да, я именно это и попытался сделать:
Код - C# [Выбрать]
  1.     /// <summary>
  2.     /// Подменить язык текущего потока (Автокада) на язык Windows, если это настроено в AvcSettings.WinLocale
  3.     /// </summary>
  4.     internal static void Language(System.Windows.Forms.ContainerControl control)
  5.     {
  6.       if (!AvcSettings.WinLocale) return;
  7.       CultureInfo win = Thread.CurrentThread.CurrentCulture;
  8.       if (Thread.CurrentThread.CurrentUICulture == win) return;
  9.       ComponentResourceManager resources = new ComponentResourceManager(control.GetType());
  10.       ApplyResources(control.Controls, resources, win);
  11.     }
  12.  
  13.     /// <summary>
  14.     /// рекурсивный обход всех контролов
  15.     /// </summary>
  16.     private static void ApplyResources(ControlCollection controls, ComponentResourceManager resources, CultureInfo lng)
  17.     {
  18.       foreach (System.Windows.Forms.Control c in controls)
  19.       {
  20.         string t = c.Text;
  21.         resources.ApplyResources(c, c.Name, lng);
  22.         ApplyResources(c.Controls, resources, lng);
  23.       }
  24.     }
Пришлось повозиться, перелопачивать все компоненты и вставлять этот метод в конструктор после InitializeComponent. Но увы под Win7 у меня все заработало в таком варианте как и раньше работало. А под win10 метод ApplyResources тупо игнорируется. Проверяю c.Text - там как был английский так и остается, хотя lng передается русский.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 14:47:29
avc,
Я правильно понимаю, что у тебя эта форма на двух языках (русский/английский)? В самом крайнем случае сделай две формы на двух языках и в зависимости от условия вызывай или одну или другую.
Компоненты и формы где на 3-4 языках, но шаманства нужны только для русского, у остальных так и так латиница и им нет резона ставить английский Автокад. Плодить формы конечно вариант и конечно крайне неприятный... если только попытаться унаследовать....
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 14:54:38
Вот ещё интересный код на эту тему: https://stackoverflow.com/a/10389737
Там ровно то же самое сделано - вызов ApplyResources для каждого контрола. И у них работает :(
p.s.
А! Так это 7 лет назад написано. Этой говнодесятки еще и в проекте не было :(
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 16:07:05
и вставлять этот метод в конструктор после InitializeComponent
Тут может быть проблема. Мне как-то нужно было принудительно перетащить форму в центр окна AutoCAD. Но автокадовский метод отрисовки диалога размещал его сам по своей логике. Пришлось задавать положение диалога в событии Activated формы. Подробнее - тут: http://adn-cis.org/forum/index.php?topic=7560.0
Возможно, что тут тоже идёт переназначение ресурсов внутренними методами AutoCAD уже после того, как отрабатывает InitializeComponent
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 16:14:15
Я попробую конечно, но сомневаюсь. Проблема то не в том что ресурсы кто-то потом обатно переключает на английский, а в том что они вообще не хотят назначаться русские...
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 16:49:53
Активации у компонентов нет, из OnLoad попробовал - бесполезно. Боюсь сглазить, но вроде заработал вызов из конструктора вот такого велосипеда:
Код - C# [Выбрать]
  1.     /// <summary>
  2.     /// Подменить язык текущего потока (Автокада) на язык Windows, если это настроено в AvcSettings.WinLocale
  3.     /// </summary>
  4.     internal static void Language(System.Windows.Forms.ContainerControl control)
  5.     {
  6.       if (!AvcSettings.WinLocale) return;
  7.       CultureInfo win = Thread.CurrentThread.CurrentCulture;
  8.       if (Thread.CurrentThread.CurrentUICulture == win) return;
  9.       CultureInfo old = Thread.CurrentThread.CurrentUICulture;
  10.       try
  11.       {
  12.         Thread.CurrentThread.CurrentUICulture = win;
  13.         ComponentResourceManager resources = new ComponentResourceManager(control.GetType());
  14.         ApplyResources(control.Controls, resources, win);
  15.       }
  16.       finally
  17.       {
  18.         Thread.CurrentThread.CurrentUICulture = old;
  19.       }
  20.     }
  21.  
  22.     /// <summary>
  23.     /// рекурсивный обход всех контролов
  24.     /// </summary>
  25.     private static void ApplyResources(ControlCollection controls, ComponentResourceManager resources, CultureInfo lng)
  26.     {
  27.       foreach (System.Windows.Forms.Control c in controls)
  28.       {
  29.         resources.ApplyResources(c, c.Name, lng);
  30.         ApplyResources(c.Controls, resources, lng);
  31.       }
  32.     }
Не могу утверждать, что это работает всегда ибо не понимаю почему на разных системах локализация работает по разному. Буду ждать откликов от пользователей.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 18:07:54
Я проверил на простом примере - у меня с локализацией WinForm никаких проблем нет. Windows 10 Rus, Civil 3D as AutoCAD 2019:

Тестовый проект прикладываю (VS 2019).
Локализацию делал по мануалу: https://docs.microsoft.com/en-us/previous-versions//y99d1cd3(v=vs.85)
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 18:15:19
Чудеса да и только...  :-\
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 18:19:44
Код - C# [Выбрать]
  1. CultureInfo win = Thread.CurrentThread.CurrentCulture;
Посмотри что тебе Александр Наумович в первом ответе написал. Если нужна локализация системы, то не то читаешь. Возможно именно в этом проблема.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 18:28:34
Да, я видел. Но на той системе, которую сегодня исправлял, там Английский Автокад возвращал именно язык Windows - русский. Т.е. в чем-то другом была проблема. И на этой системе я добился нормальной работы. Сейчас жду ответа от ребят у которых тоже были проблемы - посмотрим.
А откуда можно надежно получить язык именно Windows? CultureInfo.InstalledUICulture ?
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 18:38:50
Да, я видел. Но на той системе, которую сегодня исправлял, там Английский Автокад возвращал именно язык Windows - русский
Так если английский AutoCAD установлен на русский Windows, то это нормально же?
А откуда можно надежно получить язык именно Windows?
Если тебя интересует CultureInfo для Windows, то CultureInfo.InstalledUICulture
В общем, я так понял, что если тебе надо гарантированно получить язык системы в форме, то можно сделать так:
Код - C# [Выбрать]
  1. CultureInfo oldCulture = CultureInfo.CurrentUICulture;            
  2. bool needSwitch = CultureInfo.InstalledUICulture.LCID != oldCulture.LCID;
  3. if (needSwitch)
  4. {
  5.     // тут объект ссылочного типа, поэтому, на всякий случай создаём новый
  6.     CultureInfo.CurrentUICulture = new CultureInfo(CultureInfo.InstalledUICulture.LCID);
  7. }
  8. try
  9. {
  10.     TestForm form = new TestForm();
  11.     Application.ShowModalDialog(form);
  12. }
  13. finally
  14. {
  15.     CultureInfo.CurrentUICulture = oldCulture;
  16. }
  17.  
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 18:55:14
Кажется, я понял, в чём у тебя загвоздка - непонимание, какая CultureInfo за что отвечает:
CurrentCulture - это языковые настройки текущего потока. Используются, например, для преобразования числовых форматов, денежных единиц и т.п.
CurrentUICulture - это языковые настройки, которые используются для локализации диалогов текущего потока.
Эти два параметра AutoCAD меняет внутри себя как хочет. Иногда даже в разных версиях они имеют разные значения, я на этом уже обжигался: http://adn-cis.org/forum/index.php?topic=9132.0
Какой язык установлен в операционной системе, скорее всего, влияет на эти значения только косвенно. То, что это непостоянное значение, легко подтверждается тем, что мы сами можем их менять.
А вот именно язык операционной системы - это InstalledUICulture. Его можно только прочитать. Изменяется только в настройках Windows и требует завершения сеанса для применения изменений.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 18:59:31
Ок. Попробую так. Думаю не важно сравнивать CultureInfo или их LCID. А CultureInfo.CurrentUICulture в Net 4.5 только для чтения. Так что пишу Thread.CurrentThread.CurrentUICulture. Вроде бы не должно быть разницы.
Спасибо!
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: Дмитрий Загорулькин от 17-05-2019, 19:11:44
Думаю не важно сравнивать CultureInfo или их LCID.
Я не знаю, как там внутри сравнение идёт. В теории - да, наверное, неважно. А так, мы можем взять, например, две одинаковые культуры (например, "ru-RU") и у одной из них поменять какие-то внутренние настройки (например, десятичный числовой разделитель). Если потом их сравнить - вернут ли они одинаковый результат? Я не знаю - может да, а может и нет... А вот их LCID (а также Name и другие идентификаторы) останутся одинаковыми. Но всё это мелочи, на самом деле. Так как, в данном случае, можно вообще не делать проверку, а просто подставлять CultureInfo системы.
А CultureInfo.CurrentUICulture в Net 4.5 только для чтения. Так что пишу Thread.CurrentThread.CurrentUICulture. Вроде бы не должно быть разницы.
Думаю да - это одно и то же должно быть.
Название: Re: Локализация компонентов WinForms для OptionDialog
Отправлено: avc от 17-05-2019, 21:16:39
например, десятичный числовой разделитель
Хм, в самом деле... Я ж так все время делаю - меняю запятую на точку... Опять спасибо за комментарий - буду сравнивать по LCID.