Pull to refresh

Comments 22

UFO just landed and posted this here
Налету, к сожалению, невозможно — я, когда нужно менять язык по выбору пользователя, просто сохраняю локаль в User Settings и применяю при запуске. Соот-но, чтобы изменить язык — надо выбрать нужный и перезапустить приложение.

А список доступных — можно взять через System.Globalization.CultureInfo.GetCultures()
UFO just landed and posted this here
Ну было бы удобнее, конечно, прямо на лету переключать — но мне показалось, что потраченное на разработку время не окупится от такой мелочи — и в своих проектах просто предлагаю пользователю сделать рестарт.
А список языков… ну как вариант — проще где-то в настройках просто хранить список доступных языков. Опять же — автоматическое построение такого списка можно сделать, но я не вижу чтобы без этого нельзя было бы обойтись.
UFO just landed and posted this here
Ну тогда пусть сначала приложение покажет окно выбора языка — интерациональное, а каждая кнопка будет ставить UICulture — и открывать основную форму. Выход есть )

Но я бы с радостью почитал о вашем способе многоязычности с поддержкой переключения «на лету» )
2. вообщето имелось ввиду — получить список языков, для которых есть «сборки-сателиты»

пробежать по всем DLL-кам в папке и посмотреть «что внутрях» посредством Assembly.LoadFile и Assembly.GetType? а можно не колупаться в потрошках, а сразу принять некие конвенции по именованию DLL-ок и список языков извлекать простым парсингом имен.
не пойдет?
Для WinForms в любом случае возможно «на лету» переключать язык, т.е. менять картинки, надписи, их размер и расположение. В своем блоге я приводил пример с исходными кодами как это сделать и автоматизировать при помощи рефлексии.

Немного подробнее: можно создать несколько .resx-файлов, для каждой из культур, и там будут содержаться соответствующие свойства контролов для каждого из языков: Text, Size, Position и т.д. При переключении языка приложения(т.е. когда пользователь инициализирует событие переключения) необходимо выполнить:

Thread.CurrentThread.CurrentUICulture = new CultureInfo(«ru-RU»);

следующий шаг — из менеджера ресурсов получать соответствующие свойства:

ResourceManager LocRM = new ResourceManager(«WindowsApplication1.WinFormStrings»,typeof(Form1).Assembly);
Label1.Text = LocRM.GetString(«Label1.Text»), Thread.CurrentThread.CurrentUICulture);
Label2.Text = LocRM.GetString(«Label2.Text»), Thread.CurrentThread.CurrentUICulture);

но чтобы не указывать каждому из контролов какое свойство ему получить, можно просто вызывать метод, который с помощью рефлексии будет смотреть, что есть на форме и в resx-файле, и сопоставлять. Итак, код метода:

//метод для установки локализации формы «на лету»
public void localizeForm(Form someForm, CultureInfo cultureInfo)
{
Type someFormType = someForm.GetType();
ResourceManager res = new ResourceManager(someFormType);

//зададим список свойств объектов, которые будем извлекать из файла ресурсов
string[] properties = { «Text», «Location» };

foreach (string propertyName in properties)
{
//выбор всех свойств класса формы, извлечение из файла ресурсов значения, и их установка
foreach (FieldInfo fieldInfo in someFormType.GetFields(BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance))
{
PropertyInfo propertyInfo = fieldInfo.FieldType.GetProperty(propertyName);
if (propertyInfo == null)
continue;
object objProperty = res.GetObject(fieldInfo.Name + '.' + propertyInfo.Name, cultureInfo);
if (objProperty == null) continue;
object field = fieldInfo.GetValue(someForm);
if (field != null)
propertyInfo.SetValue(field, objProperty, null);
}
//код для установки свойств самих форм
PropertyInfo propertyInfo1 = someFormType.GetProperty(propertyName);
if (propertyInfo1 == null)
continue;
object objProperty1 = res.GetObject("$this." + propertyInfo1.Name, cultureInfo);
if (objProperty1 == null) continue;
propertyInfo1.SetValue(someForm, objProperty1, null);
}
}

В результате, с помощью небольших затрат можно менять «на лету» язык приложения.
Это для WinForms. Для WPF это вынуждает нас выставлять Name для каждого элемента. Я думаю, для WPF лучше сделать вариант с Binding.
Для избавления от перезагрузок программы я сделал все очень просто: написал класс-синглтон, который парсит хмл-файл с локализациями. В нем есть событие, которое обозначает смену текущей локалицазии приложения. Все окна подписываются на данное событие если надо. Обработчик данного события представляет собой запрос у класса локализации всех необходимых строк по их имени рессура.

Например:
OpenFileMenu.Text = Localization.Instance.GetString("MainForm.MainMenu.File.Open");
SaveAsFileMenu.Text = Localization.Instance.GetString("MainForm.MainMenu.File.SaveAs");


Сейчас продумываю сделать расширяющий компонент для формы, который автоматизирует данный процесс, но пока руки не доходят.
Но это же потащит за собой кучу кода — установка значений свойств программно. А вот, допустим, сделать компонент, у которого будут DependencyProperty для локализованных строк, потом нужные значения Bindingом привязывать к ним — это идея. Завтра попробую посмотреть что из этого может получится )
На лету можно. Достаточно создать свой MarkupExtension, в котором подписываться на изменения культуры. При этом перегружать значения ресурс файлов. «WPF Localization on-the-fly».
Да, отсутствие переключения налету — это ооочень серьезный минус.
Я не вижу в этом серьезного минуса — ну может переключение на лету было бы приятной фичей, но не более. В каких случаях это действительно критично? Как я вижу — переключение интерфейса приложения — это не common-task, т.е. юзер не меняет язык интерфейса раз в 5 мин. В идеале — вообще не меняет, а один раз настраивает язык системы и софт подстраивается под него. В крайнем случае — меняет в настройках, видит сообщение — Язык будет изменен после рестарта приложения — и работает дальше.
тоже не вижу смысла переключения на лету. Вообще язык можно устанавливать при установки приложения. Пользователь настраивает это один раз, максимум два раза (если русский перевод не понравится).
Огромное спасибо за статью! Как раз возникла эта задача, а вариант через XAML действительно уж очень громоздкий.
Ещё хорошая новость — у меня получилось сделать переключение «на лету», причём именно используя Binding.
Если интересно — готов поделиться :)
Да, конечно интересно. Как вариант — вы можете оформить это небольшой статьей, а либо просто выложить проект куда-нибудь.
И когда собираетесь делиться?
я тоже попробовал, отлично работает. маленькая библиотека решает большие проблемы.
Sign up to leave a comment.

Articles