Локализация....
От: Аноним  
Дата: 09.09.04 13:21
Оценка:
Привет, попробую внятно описать то что мне нужно.

Я пишу приложение на С№ и мне нужно чтобы оно поддерживало локализацию, в том смысле что все надписи на меню кнопках и т.д. могут меняться. Нужно чтобы они подгружались из файла и таким образом их легко будет изменять. Ну и язык можно менять соответвтвенно тоже довольно просто.

Мне кажется что для этого нужно сделать статик класс, который видели бы все остальные классы, но я не знаю как его таким сделать... в С++ это была бы static переменная, но в С# по моему такого нельзя сделать или все таки можно???

И ещё, если такое таки можно сделать, то как сделать чтобы если вдруг посреди работы приложения ты поменяешь все надписи подгрузив новый файлик, то как сделать чтобы текущие надписи поменялись???

Огромное спасибо.

Простите если не внятно объяснил или сформулировал что-то.
Re: Локализация....
От: StepanM Россия  
Дата: 09.09.04 15:01
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет, попробую внятно описать то что мне нужно.


А>Я пишу приложение на С№ и мне нужно чтобы оно поддерживало локализацию, в том смысле что все надписи на меню кнопках и т.д. могут меняться. Нужно чтобы они подгружались из файла и таким образом их легко будет изменять. Ну и язык можно менять соответвтвенно тоже довольно просто.


А>Мне кажется что для этого нужно сделать статик класс, который видели бы все остальные классы, но я не знаю как его таким сделать... в С++ это была бы static переменная, но в С# по моему такого нельзя сделать или все таки можно???


А>И ещё, если такое таки можно сделать, то как сделать чтобы если вдруг посреди работы приложения ты поменяешь все надписи подгрузив новый файлик, то как сделать чтобы текущие надписи поменялись???


А>Огромное спасибо.


А>Простите если не внятно объяснил или сформулировал что-то.


Локализация формы в C# делается следующим образом:
1. Найти свойство формы Localizable. По умолчанию его значение false, сделать его true.
2. Найти свойство формы Language. В качестве значения выбрать язык, который нужен.
3. Теперь все надписи на элементах управлений (кнопках, пунктах меню и т.д.) переписать на нужном языке.
4. В конструктор формы не забыть добавить инструкцию.
System.Threading.Thread.CurrentThread.CurrentUICulture 
    = System.Threading.Thread.CurrentThread.CurrentCulture;

И все.
Re: Локализация....
От: Mink Россия  
Дата: 09.09.04 15:51
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет, попробую внятно описать то что мне нужно.


А>Я пишу приложение на С№ и мне нужно чтобы оно поддерживало локализацию, в том смысле что все надписи на меню кнопках и т.д. могут меняться. Нужно чтобы они подгружались из файла и таким образом их легко будет изменять. Ну и язык можно менять соответвтвенно тоже довольно просто.


Basics of .NET Internationalization

Best Practices for Developing World-Ready Applications
Сила, она в ньютонах
Re[2]: Локализация....
От: Туленцев Сергей Россия http://software.tulentsev.com
Дата: 11.09.04 12:38
Оценка:
Здравствуйте, StepanM, Вы писали:

SM>Локализация формы в C# делается следующим образом:

SM>1. Найти свойство формы Localizable. По умолчанию его значение false, сделать его true.
SM>2. Найти свойство формы Language. В качестве значения выбрать язык, который нужен.
SM>3. Теперь все надписи на элементах управлений (кнопках, пунктах меню и т.д.) переписать на нужном языке.
SM>4. В конструктор формы не забыть добавить инструкцию.
SM>
SM>System.Threading.Thread.CurrentThread.CurrentUICulture 
SM>    = System.Threading.Thread.CurrentThread.CurrentCulture;
SM>

SM>И все.

Все сделал так, как написано. Но мне хочется менять язык приложения "на лету".
Как я пытаюсь это сделать?
Есть у меня два пункта меню, для русского и английского.
Для английского код выглядит так:
        private void langEnglish_Click(object sender, System.EventArgs e)
        {
            //System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);
            Application.CurrentCulture   = new CultureInfo("en-US", true);
            System.Threading.Thread.CurrentThread.CurrentUICulture 
                = System.Threading.Thread.CurrentThread.CurrentCulture;
            MessageBox.Show("Current UI Culture: " + CultureInfo.CurrentUICulture.Name);
            
            langEnglish.Checked = true;
            langRussian.Checked = false;
        }


MessageBox показывает, что культура изменилась правильно, а вот интерфейс не меняется.
В MSDN сказано, что при установке CurrentThread.CurrentUICulture ResourceManager загружает данные для указанной культуры.
Что я делаю не так?
... << Rsdn@Home 1.1.4 beta 1 >>
--
Re[3]: Локализация....
От: Mab Россия http://shade.msu.ru/~mab
Дата: 11.09.04 13:23
Оценка:
ТС>В MSDN сказано, что при установке CurrentThread.CurrentUICulture ResourceManager загружает данные для указанной культуры.
Не "загружает", а "будет в дальнейшем загружать".

ТС>Что я делаю не так?

Все ты делаешь так, но смену культуры 'на лету' WinForms не поддерживает. Все свойства, зависящие от культуры, выставляются при создании формы, поэтому для того, чтобы изменения вступили в силу, нужно пересоздать все формы. В общем случае задача эта нетривиальна и требует написания в каком-то виде своего persistence framework-а.

Так что если переключение на лету -- это принципиальное требование, то делать много придется ручками. Но я бы забил на такую возможность.
Re[4]: Локализация....
От: Туленцев Сергей Россия http://software.tulentsev.com
Дата: 11.09.04 13:29
Оценка:
Здравствуйте, Mab, Вы писали:

ТС>>В MSDN сказано, что при установке CurrentThread.CurrentUICulture ResourceManager загружает данные для указанной культуры.

Mab>Не "загружает", а "будет в дальнейшем загружать".

ТС>>Что я делаю не так?

Mab>Все ты делаешь так, но смену культуры 'на лету' WinForms не поддерживает. Все свойства, зависящие от культуры, выставляются при создании формы, поэтому для того, чтобы изменения вступили в силу, нужно пересоздать все формы. В общем случае задача эта нетривиальна и требует написания в каком-то виде своего persistence framework-а.

Mab>Так что если переключение на лету -- это принципиальное требование, то делать много придется ручками. Но я бы забил на такую возможность.


Хм, но я пробовал менять основной язык и местоположение через панель управления.
Результат неизменен. Язык все равно русский при Localizable == true.
Если false, то английский.
... << Rsdn@Home 1.1.4 beta 1 >>
--
Re[5]: Локализация....
От: Mab Россия http://shade.msu.ru/~mab
Дата: 11.09.04 15:07
Оценка:
ТС>Хм, но я пробовал менять основной язык и местоположение через панель управления.
ТС>Результат неизменен. Язык все равно русский при Localizable == true.
Ничего не понял. Если UI-культуру треда выставить правильным образом до инициализации формы (в частности, до вызова InitializeComponent), то все должно работать. Этого не происходит?
Re[6]: Локализация....
От: Туленцев Сергей Россия http://software.tulentsev.com
Дата: 11.09.04 16:03
Оценка:
Здравствуйте, Mab, Вы писали:

ТС>>Хм, но я пробовал менять основной язык и местоположение через панель управления.

ТС>>Результат неизменен. Язык все равно русский при Localizable == true.
Mab>Ничего не понял. Если UI-культуру треда выставить правильным образом до инициализации формы (в частности, до вызова InitializeComponent), то все должно работать. Этого не происходит?
Хех, а я вызывал после InitializeComponent(). В том месте было еще написано //Add your constructor logic here...
Если написать до, то все хорошо.
Кстати, в порядке эксперимента воткнул InitializeComponent() в обработчики тех менюайтемов, что культуру меняют. Проявился интересный эффект: язык меняется только у меню. Все остальное остается.
Спасибо за помощь, общую идею понял. Просто я в нескольких приложениях видел, как менялся язык интерфейса на лету. Там, скорее всего, это дело в ini-файлах хранилось. Вот и я и подумал, а раз дотнет такой весь из себя навороченный, то он может это уметь.
... << Rsdn@Home 1.1.4 beta 1 >>
--
Re[7]: Локализация....
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.09.04 10:14
Оценка:
Здравствуйте, Туленцев Сергей, Вы писали:

ТС>Спасибо за помощь, общую идею понял. Просто я в нескольких приложениях видел, как менялся язык интерфейса на лету. Там, скорее всего, это дело в ini-файлах хранилось. Вот и я и подумал, а раз дотнет такой весь из себя навороченный, то он может это уметь.


А зачем это нужно?
... << RSDN@Home 1.1.4 beta 2 rev. 181>>
AVK Blog
Re[8]: Локализация....
От: Туленцев Сергей Россия http://software.tulentsev.com
Дата: 12.09.04 16:06
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Туленцев Сергей, Вы писали:


ТС>>Спасибо за помощь, общую идею понял. Просто я в нескольких приложениях видел, как менялся язык интерфейса на лету. Там, скорее всего, это дело в ini-файлах хранилось. Вот и я и подумал, а раз дотнет такой весь из себя навороченный, то он может это уметь.


AVK>А зачем это нужно?


Хмммм... Ну Вы меня прямо в тупик поставили. А и в самом деле, зачем? Я такой вопрос поднял из-за того, что мне показалось это интересной идеей (ведь делает же кто-то, значит, это кому-нибудь нужно). Но последую лучше совету Mab'а и забью на это.
... << Rsdn@Home 1.1.4 beta 1 >>
--
Re[2]: Локализация....
От: Аноним  
Дата: 12.09.04 18:38
Оценка:
Здравствуйте, StepanM, Вы писали:

SM>Здравствуйте, Аноним, Вы писали:


А>>Привет, попробую внятно описать то что мне нужно.


А>>Я пишу приложение на С№ и мне нужно чтобы оно поддерживало локализацию, в том смысле что все надписи на меню кнопках и т.д. могут меняться. Нужно чтобы они подгружались из файла и таким образом их легко будет изменять. Ну и язык можно менять соответвтвенно тоже довольно просто.


А>>Мне кажется что для этого нужно сделать статик класс, который видели бы все остальные классы, но я не знаю как его таким сделать... в С++ это была бы static переменная, но в С# по моему такого нельзя сделать или все таки можно???


А>>И ещё, если такое таки можно сделать, то как сделать чтобы если вдруг посреди работы приложения ты поменяешь все надписи подгрузив новый файлик, то как сделать чтобы текущие надписи поменялись???


А>>Огромное спасибо.


А>>Простите если не внятно объяснил или сформулировал что-то.


SM>Локализация формы в C# делается следующим образом:

SM>1. Найти свойство формы Localizable. По умолчанию его значение false, сделать его true.
SM>2. Найти свойство формы Language. В качестве значения выбрать язык, который нужен.
SM>3. Теперь все надписи на элементах управлений (кнопках, пунктах меню и т.д.) переписать на нужном языке.
SM>4. В конструктор формы не забыть добавить инструкцию.
SM>
SM>System.Threading.Thread.CurrentThread.CurrentUICulture 
SM>    = System.Threading.Thread.CurrentThread.CurrentCulture;
SM>

SM>И все.

О, вижу тут народ по нужной мне теме общается, может тогда на это мне кто то ответит:

Линк хере!
Автор: Batiskaf
Дата: 31.08.04
Re[3]: Локализация....
От: Аноним  
Дата: 15.09.04 07:35
Оценка:
Здравствуйте, Аноним, Вы писали:



А>О, вижу тут народ по нужной мне теме общается, может тогда на это мне кто то ответит:


А>Линк хере!
Автор: Batiskaf
Дата: 31.08.04


И гробовое молчание, ну что, никто этими аспектами не занимался?
Re[2]: Локализация....
От: SeeSharper  
Дата: 21.01.06 11:28
Оценка:
SM>Локализация формы в C# делается следующим образом:
...
SM>И все.

С формой-то все, а как быть с прочим текстом? К примеру, сообщения для StatusBar и обозначения типов документов собственного формата в диалогах открытия/сохранения файлов?
Хотелось бы что-то типа функции tr в Qt, чтобы через нее прогонять все, что перевести нужно. Руками — муторно...
Re[2]: Локализация....
От: Grizzli  
Дата: 21.01.06 11:57
Оценка:
SM>Локализация формы в C# делается следующим образом:
SM>1. Найти свойство формы Localizable. По умолчанию его значение false, сделать его true.
SM>2. Найти свойство формы Language. В качестве значения выбрать язык, который нужен.
SM>3. Теперь все надписи на элементах управлений (кнопках, пунктах меню и т.д.) переписать на нужном языке.
SM>4. В конструктор формы не забыть добавить инструкцию.
SM>
SM>System.Threading.Thread.CurrentThread.CurrentUICulture 
SM>    = System.Threading.Thread.CurrentThread.CurrentCulture;
SM>

SM>И все.


забавлял меня всегда такой подход. А что, переводчик который будет эти тексты переводить, тоже будет по формам лазить? В общем, проще все текстовые ресурсы собрать в одном файле. Как статик переменные. А потом, в конструкторе вызывать функцию инициализации, где и присваивать все эти переменные в свойства .Text. Если проект большой, то лучше написать простенькую генерилку файла текстовых ресурсов. Т.е. программу, которая грузит асемблю, проходит по всем элементам гуи, и автоматом генерирует

1) объявление статик строки, вставляется в этот самый текстовый файл
2) функцию инициализации, для каждого контрола или формы, вызов её вставляется в конструктор.

в текстовом файле можно сделать комментарии к каждой строке(для переводчика), можно сгруппировать их так как хочется и т.д.
Re[2]: Локализация....
От: Аноним  
Дата: 21.01.06 15:08
Оценка:
>... мне хочется менять язык приложения "на лету". ...

http://www.gotdotnet.ru/Forums/Common/1768.aspx?page=next&amp;page=next&amp;page=next#124263


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[3]: Локализация....
От: Mike Chaliy Украина http://chaliy.name
Дата: 21.01.06 19:29
Оценка: +1
Здравствуйте, Grizzli, Вы писали:

G>забавлял меня всегда такой подход. А что, переводчик который будет эти тексты переводить, тоже будет по формам лазить? В общем, проще все текстовые ресурсы собрать в одном файле. Как статик переменные. А потом, в конструкторе вызывать функцию инициализации, где и присваивать все эти переменные в свойства .Text. Если проект большой, то лучше написать простенькую генерилку файла текстовых ресурсов. Т.е. программу, которая грузит асемблю, проходит по всем элементам гуи, и автоматом генерирует


G>1) объявление статик строки, вставляется в этот самый текстовый файл

G>2) функцию инициализации, для каждого контрола или формы, вызов её вставляется в конструктор.

G>в текстовом файле можно сделать комментарии к каждой строке(для переводчика), можно сгруппировать их так как хочется и т.д.


А меня забавляют программы в которых русские буквы вылазят за пределы контролов. А вот дотНетовский механизм позволяет этого избежать. Ктомуже он может локализировать картинки, да вобщемто практически все что можно назвать ресурсами. Кстати, он еще и на автомате менеджет какой ресурс пременять. Например если УИ поток для русского(укринского) но именно такого ресурса под этот язык нет, то менеджер автоматически возьмет его из дефаултов. Кстати для переводчиков есть специальная тулза. Перводчик тыкается в кнопку и меняет ей все что нужно.
А тут я живу и пишу...
Re[4]: Локализация....
От: Grizzli  
Дата: 22.01.06 09:32
Оценка:
Здравствуйте, Mike Chaliy, Вы писали:


MC>А меня забавляют программы в которых русские буквы вылазят за пределы контролов. А вот дотНетовский механизм позволяет этого избежать. Ктомуже он может локализировать картинки, да вобщемто практически все что можно назвать ресурсами. Кстати, он еще и на автомате менеджет какой ресурс пременять. Например если УИ поток для русского(укринского) но именно такого ресурса под этот язык нет, то менеджер автоматически возьмет его из дефаултов. Кстати для переводчиков есть специальная тулза. Перводчик тыкается в кнопку и меняет ей все что нужно.


это чтоже за тулза то такая? И она позволяет переводчику без знания например, понятия "Panel" русифицировать интерфейс который находится на 10 панелях, каждая из которых скрыта другой? А в отдельный файл можно и картинки вынести, тут проблем нет. Нащет автоматического применения — спорный аргумент. Пользователь сам укажет, какой из существующих языков он хочет видеть, да dll и подгрузится. какие то автоматические угадывания я вообще не понимаю, зачем тут нужны. И за пределы контролов... Что, дот нетовский механизм расширит ширину label чтоли? Если текст на русском будет много больше текста на английском? а если справа от label кнопка находится?
Re[5]: Локализация....
От: Mike Chaliy Украина http://chaliy.name
Дата: 22.01.06 09:51
Оценка:
Здравствуйте, Grizzli, Вы писали:

G>Здравствуйте, Mike Chaliy, Вы писали:


G>это чтоже за тулза то такая?


WinRes.exe из SDK. Насколько я знаю существуют и другие подобные утилиты.

G>И она позволяет переводчику без знания например, понятия "Panel" русифицировать интерфейс который находится на 10 панелях, каждая из которых скрыта другой?


Переводчик должен знать начальные понятия. Что такое кнопки и так далее. А вот панели которые скрыты друг другом это просто неправильный дизайн приложения. Достаточно использовать ЮзерКонтролы..

G>А в отдельный файл можно и картинки вынести, тут проблем нет.


Это дополнительный кодинг.

G>Нащет автоматического применения — спорный аргумент. Пользователь сам укажет, какой из существующих языков он хочет видеть, да dll и подгрузится. какие то автоматические угадывания я вообще не понимаю, зачем тут нужны.


Почемуже он сопрный. Зачем пользователь должен что-то указывать если у него это указано в винде? Ну а для случаев когда всетаки нужно, то это тоже не проблема. Достаточно утсановить культуру УИ потока. Хотя я немного не про то говорил.

G>И за пределы контролов... Что, дот нетовский механизм расширит ширину label чтоли? Если текст на русском будет много больше текста на английском? а если справа от label кнопка находится?


Господи может быть проще поглядеть как тут это все реализовано? Я же сказал что локализировать можно большую часть свойств контрола(Включая размеры, позицию, цвета, шрифты и так далее). Для отдельного языка можно весь лаяут поменять.
А тут я живу и пишу...
Re: Локализация....
От: Golakoff Россия  
Дата: 23.01.06 06:48
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет, попробую внятно описать то что мне нужно.


А>Я пишу приложение на С№ и мне нужно чтобы оно поддерживало локализацию, в том смысле что все надписи на меню кнопках и т.д. могут меняться. Нужно чтобы они подгружались из файла и таким образом их легко будет изменять. Ну и язык можно менять соответвтвенно тоже довольно просто.


А>Мне кажется что для этого нужно сделать статик класс, который видели бы все остальные классы, но я не знаю как его таким сделать... в С++ это была бы static переменная, но в С# по моему такого нельзя сделать или все таки можно???


А>И ещё, если такое таки можно сделать, то как сделать чтобы если вдруг посреди работы приложения ты поменяешь все надписи подгрузив новый файлик, то как сделать чтобы текущие надписи поменялись???


А>Огромное спасибо.


А>Простите если не внятно объяснил или сформулировал что-то.


Доброго дня.
Действительно, если заглянуть в соседнюю ветку, то станет ясно, что встроенный метод локализации не годится так как не поддерживает изменение языка "на лету".
В свое время тоже занимался подобной проблемой...
Написал даже небольшую dll.
Смысл сводится к тому, что руками делаем XML файл и потом весь перевод упирается в перевод строчек XML-файла.

Вот кратко, что успел сделать:

v. 1.0.1881.30275
1. первый релиз. худо-бедно — с задачей справился — перевел что дали...
v. 1.0.1882.23785
1.Добавлено сохрание заголовка формы
v. 1.0.1886.28317
1. Добавлено сохрание заголовка формы
2. Комбо-боксы обрабатываются поаккуратнее — теперь если стиль DropDownList — то свойство Text не сохраняется и не читается!
v. 1.0.1902.27996
1. Добавлена обработка статус бара (сохранение теста панелей)
2. Добавлена обработка контекстного меню (правда пока только для элементов управления, владельцем которой является форма)
3. Добавлена обработка строковых ресурсов! появилась функция public string GetStringResource(string key), которая вытаскивает из файла ресурсов (общего для всех форм — т.е. единого для объекта класса CLanguage) строчку по имени нода в xml-документе! Минус в том, что пока он сильно ругается на отсутствие данного файла.

// author : Andrew A. Golyakov
// 

using System;
using System.Xml;
using System.Windows.Forms;
using System.Collections;
using System.Collections.Specialized;

namespace Language
{
    /// <summary>
    /// Languages enumeration <br>
    /// - English<br>
    /// - Russian<br>
    /// - Dutch<br>
    /// </summary>    
    public enum Languages
    {
        English,
        Russian,
        Dutch,
        Swedish
    }

    /// <summary>
    /// Langeage Lybrary - helps to translate your applications to any language.<br>
    /// Developed with the XML Technology.<br>
    /// Just create your own language file with specefied language and use it any time you need.<br>
    /// <br>
    /// Now it provide processing such controls as:<br>
    /// - MainMenu<br>
    /// - Button<br>
    /// - Label<br>
    /// - TextBox<br>
    /// - CheckBox<br>
    /// - RadioButton<br>
    /// - ComboBox<br>
    /// - ListBox<br>
    /// - TabControl<br>
    /// - GroupBox<br>
    /// </summary>
    public class CLanguage
    {
        /// <summary>
        /// <font color='red'>Private.</font> Xml document to store language information.
        /// </summary>
        private XmlDocument doc;
        /// <summary>
        /// <font color='red'>Private.</font> The root node of xml docement.
        /// </summary>
        private XmlNode root;
        /// <summary>
        /// <font color='red'>Private.</font> Node to store Mainmenu control.
        /// </summary>
        private XmlNode MainMenuNode;
        /// <summary>
        /// <font color='red'>Private.</font> Node to store other controls.
        /// </summary>
        private XmlNode ControlsNode;
        /// <summary>
        /// <font color='red'>Private.</font> Node to store other context menus of controls.
        /// </summary>
        private XmlNode ContextMenusNode;
        /// <summary>
        /// <font color='red'>Private.</font> Node to store string resources.
        /// </summary>
         private XmlNode StringsNode;
        /// <summary>
        /// <font color='red'>Private.</font> Node to store form caption.
        /// </summary>
        private XmlNode FormCaptionNode;
        /// <summary>
        /// <font color='red'>Private.</font> Contains directory of languages files.
        /// </summary>
        private string filename_prefix;
        /// <summary>
        /// <font color='red'>Private.</font> Contains extention of languages files.
        /// </summary>
        private string filename_postfix;

        private Languages mCurrentLanguage;

        /// <summary>
        /// <font color='blue'><b>Public.</b></font> Use this property to choose another language.
        /// </summary>
        public Languages currentLanguage
        {
            get
            {
                return mCurrentLanguage;
            }
            set
            {
                mCurrentLanguage = value;
                //LoadStringResources();
            }
        }

        private ArrayList mStringResources;
            
        /// <summary>
        /// <font color='blue'><b>Public.</b></font> Simple constructor sets the current language.
        /// </summary>
        /// <param name="newCurrentLanguage">Current language to default parameters</param>
        public CLanguage(Languages newCurrentLanguage)
        {
            // creating xml-document
            doc = new XmlDocument();
            root = doc.CreateNode(XmlNodeType.Element, "Language", "");
         MainMenuNode = doc.CreateNode(XmlNodeType.Element, "MainMenu", "");
            ControlsNode = doc.CreateNode(XmlNodeType.Element, "Controls", "");
            FormCaptionNode = doc.CreateNode(XmlNodeType.Element, "FormCaption", "");
            ContextMenusNode = doc.CreateNode(XmlNodeType.Element, "ContextMenus", "");

            root.AppendChild(FormCaptionNode);
            root.AppendChild(MainMenuNode);
            root.AppendChild(ControlsNode);
            root.AppendChild(ContextMenusNode);

            doc.AppendChild(root);
            XmlDeclaration xmldecl;
            xmldecl = doc.CreateXmlDeclaration("1.0",null,null);
            doc.InsertBefore(xmldecl, root);

            // set default language
            currentLanguage = newCurrentLanguage;

         // file name
            filename_prefix = "Language/";
            filename_postfix = ".lng.xml";

            // creating string resources array
            mStringResources = new ArrayList();
            LoadStringResources();
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetStringResource(string key)
        {
            foreach(DictionaryEntry mStringResource in mStringResources)
            {
                if (mStringResource.Key as string == key)
                {
                    return mStringResource.Value as string;
                }
            }
            return String.Empty;
        }

        /// <summary>
        /// <font color='red'>Private.</font> Saving menu items from the Menu.
        /// </summary>
        /// <param name="m">Menu to save</param>
        /// <param name="parent_node">Parent node to save</param>
        private void SaveMenuItem(Menu m, XmlNode parent_node)
        {
            foreach (MenuItem mi in m.MenuItems)
            {                
                XmlNode Elem = doc.CreateNode(XmlNodeType.Element, "Item" + mi.Index.ToString(), "");
                XmlAttribute LanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                LanguageText.Value = mi.Text;
                Elem.Attributes.Append(LanguageText);
                parent_node.AppendChild(Elem);                

                if (mi.IsParent == true)
                {
                    SaveMenuItem(mi, Elem);                    
                }
            }
        }


        /// <summary>
        /// <font color='red'>Private.</font> Loading menu items to the Menu.
        /// </summary>
        /// <param name="m">Menu to load</param>
        /// <param name="parent_node">Parent node to load</param>
        private void LoadMenuItem(Menu m, XmlNode parent_node)
        {
            foreach (MenuItem mi in m.MenuItems)
            {
                XmlNode cur_item = parent_node.SelectSingleNode("Item" + mi.Index.ToString());
                mi.Text = cur_item.Attributes["LanguageText"].Value;
                
                if (mi.IsParent == true)
                {
                    LoadMenuItem(mi, cur_item);
                }
            }
        }


        /// <summary>
        /// <font color='red'>Private.</font> Saving all menuitems (with sub-menus) from  form's MainMenu.
        /// </summary>
        /// <param name="lang">Language to save</param>
        /// <param name="frm">Form name</param>
        /// <returns>True if all correct, or False</returns>
        private bool SaveMenuItems(Languages lang, Form frm)
        {
            if (frm.Menu == null) return true;

         MainMenuNode.RemoveAll();
            SaveMenuItem(frm.Menu, MainMenuNode);

            return true;
        }


        /// <summary>
        /// <font color='red'>Private.</font> Loading all menuitems (with sub-menus) to form's MainMenu.
        /// </summary>
        /// <param name="lang">Language to load</param>
        /// <param name="frm">Form name</param>
        /// <returns>True if all correct, or False</returns>
        private bool LoadMenuItems(Languages lang, Form frm)
        {
            if (frm.Menu == null) return true;
        
            LoadMenuItem(frm.Menu, MainMenuNode);            

            return true;
        }

        /// <summary>
        /// <font color='red'>Private.</font> Saving all controls to the Xml-Node.
        /// </summary>
        /// <param name="lang">Target language</param>
        /// <param name="ctrls">Control collection</param>
        /// <param name="parentNode">Parent node</param>
        /// <returns>True if all correct, or False</returns>
        private bool SaveContextMenus(Languages lang, Form frm, XmlNode parentNode)
        {
            ContextMenusNode.RemoveAll();

            foreach (Control c in frm.Controls)
            {
                if (c.ContextMenu != null)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    parentNode.AppendChild(Elem);
                    
                    SaveMenuItem(c.ContextMenu, Elem);
                }
            }
            return true;
        }

        /// <summary>
        /// <font color='red'>Private.</font> Loading all controls from the Xml-Node.
        /// </summary>
        /// <param name="lang">Target language</param>
        /// <param name="ctrls">Control collection</param>
        /// <param name="parentNode">Parent node</param>
        /// <returns>True if all correct, or False</returns>
        private bool LoadContextMenus(Languages lang, Form frm, XmlNode parentNode)
        {
            foreach (Control c in frm.Controls)
            {
            if (c.ContextMenu != null)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name)
                            LoadMenuItem(c.ContextMenu, xmlnode);
                    }                    
                }
            }
            return true;
        }

        /// <summary>
        /// <font color='red'>Private.</font> Loading all controls from the Xml-Node.
        /// </summary>
        /// <param name="lang">Target language</param>
        /// <param name="ctrls">Control collection</param>
        /// <param name="parentNode">Parent node</param>
        /// <returns>True if all correct, or False</returns>
        private bool LoadControls(Languages lang, Control.ControlCollection ctrls, XmlNode parentNode)
        {
            foreach (Control c in ctrls)
            {
                if (c is Button || c is Label || c is TextBox || c is CheckBox || c is RadioButton)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name)
                            c.Text = xmlnode.Attributes["LanguageText"].Value;
                    }
                }

                if (c is ComboBox)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name)
                        {
                            if (
                                (c as ComboBox).DropDownStyle == ComboBoxStyle.DropDown ||
                                (c as ComboBox).DropDownStyle == ComboBoxStyle.Simple
                                )
                            c.Text = xmlnode.Attributes["LanguageText"].Value;

                            if (xmlnode.HasChildNodes == true)
                            {
                                int i = -1;
                                foreach (XmlNode node in xmlnode.ChildNodes)
                                {                                    
                                    (c as ComboBox).Items[++i] = node.Attributes["LanguageText"].Value;
                                }
                            }
                        }
                    }                    
                }
                if (c is ListBox)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name && xmlnode.HasChildNodes == true)
                        {
                            int i = -1;
                            foreach (XmlNode node in xmlnode.ChildNodes)
                            {
                                (c as ListBox).Items[++i] = node.Attributes["LanguageText"].Value;
                            }
                        }                    
                    }
                }
                if (c is TabControl)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name)
                        {
                            foreach (XmlNode node in parentNode.ChildNodes)
                            {
                                if (node.Name == c.Name && node.HasChildNodes == true)
                                {
                                    System.Collections.IEnumerator e = (c as TabControl).TabPages.GetEnumerator();
                     
                                    foreach (XmlNode n in xmlnode.ChildNodes)
                                    {
                                        e.MoveNext();
                                        (e.Current as TabPage).Text =    n.Attributes["LanguageText"].Value;

                                        if (n.HasChildNodes == true)
                                            LoadControls(lang, (e.Current as TabPage).Controls, n);
                                    }
                                }                    
                            }
                        }
                    }
                }

                if (c is GroupBox)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name && xmlnode.HasChildNodes == true)
                        {
                            c.Text = xmlnode.Attributes["LanguageText"].Value;
                            LoadControls(lang, (c as GroupBox).Controls, xmlnode);
                        }
                    }
                }
                
                if (c is StatusBar)
                {
                    foreach (XmlNode xmlnode in parentNode.ChildNodes)
                    {
                        if (xmlnode.Name == c.Name && xmlnode.HasChildNodes == true)
                        {
                            int i = -1;
                            foreach (XmlNode node in xmlnode.ChildNodes)
                            {
                                (c as StatusBar).Panels[++i].Text = node.Attributes["LanguageText"].Value;
                            }
                        }                    
                    }
                }
            }
        
            return true;
        }

        private bool SaveFormCaption(Languages lang, Form frm)
        {
            FormCaptionNode.RemoveAll();

            XmlAttribute LanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
            LanguageText.Value = frm.Text;
            FormCaptionNode.Attributes.Append(LanguageText);
      
            return true;
        }

        private bool LoadFormCaption(Languages lang, Form frm)
        {
            frm.Text = FormCaptionNode.Attributes["LanguageText"].Value;
            return true;
        }

        /// <summary>
        /// <font color='red'>Private.</font> Saving all controls to the Xml-Node.
        /// </summary>
        /// <param name="lang">Target language</param>
        /// <param name="ctrls">Control collection</param>
        /// <param name="parentNode">Parent node</param>
        /// <returns>True if all correct, or False</returns>
        private bool SaveControls(Languages lang, Control.ControlCollection ctrls, XmlNode parentNode)
        {
            foreach (Control c in ctrls)
            {
                if (c is Button || c is Label || c is TextBox || c is CheckBox || c is RadioButton)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    XmlAttribute LanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                    LanguageText.Value = c.Text;
                    Elem.Attributes.Append(LanguageText);
                    parentNode.AppendChild(Elem);
                }
                if (c is ComboBox)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    if (
                        (c as ComboBox).DropDownStyle == ComboBoxStyle.DropDown ||
                        (c as ComboBox).DropDownStyle == ComboBoxStyle.Simple
                        )
                    {
                        XmlAttribute LanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                        LanguageText.Value = c.Text;
                        Elem.Attributes.Append(LanguageText);
                    }
                    parentNode.AppendChild(Elem);
                    
                    if ((c as ComboBox).Items.Count > 0)
                    {
                        for(int i=0; i<(c as ComboBox).Items.Count; i++)
                        {
                            XmlNode SubElem = doc.CreateNode(XmlNodeType.Element, "Item" + i.ToString(), "");
                            XmlAttribute SubLanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                            SubLanguageText.Value = (c as ComboBox).Items[i].ToString();
                            SubElem.Attributes.Append(SubLanguageText);
                            Elem.AppendChild(SubElem);
                        }
                    }
                }

                if (c is ListBox)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    parentNode.AppendChild(Elem);
                    
                    if ((c as ListBox).Items.Count > 0)
                    {
                        for(int i=0; i<(c as ListBox).Items.Count; i++)
                        {
                            XmlNode SubElem = doc.CreateNode(XmlNodeType.Element, "Item" + i.ToString(), "");
                            XmlAttribute SubLanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                            SubLanguageText.Value = (c as ListBox).Items[i].ToString();
                            SubElem.Attributes.Append(SubLanguageText);
                            Elem.AppendChild(SubElem);
                        }
                    }
                }
                if (c is TabControl)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    parentNode.AppendChild(Elem);

                    foreach (TabPage p in (c as TabControl).TabPages)
                    {
                        XmlNode SubElem = doc.CreateNode(XmlNodeType.Element, p.Name, "");                        
                        XmlAttribute SubLanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                        SubLanguageText.Value = p.Text;
                        SubElem.Attributes.Append(SubLanguageText);
                        Elem.AppendChild(SubElem);
                        parentNode.AppendChild(Elem);                 
                        SaveControls(lang, p.Controls, SubElem);
                    }
                }

                if (c is GroupBox)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    XmlAttribute LanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                    LanguageText.Value = c.Text;
                    Elem.Attributes.Append(LanguageText);
                    parentNode.AppendChild(Elem);          
                    SaveControls(lang, (c as GroupBox).Controls, Elem);
                }

                if (c is StatusBar)
                {
                    XmlNode Elem = doc.CreateNode(XmlNodeType.Element, c.Name, "");
                    parentNode.AppendChild(Elem);

                    SaveStatusBarPanels(lang, (c as StatusBar).Panels, Elem);
                }
            }
            return true;
        }

        private void SaveStatusBarPanels(Languages lang, StatusBar.StatusBarPanelCollection  ctrls, XmlNode parentNode)
        {
            int index = 0;                 // index of panels 
            foreach (StatusBarPanel p in ctrls)
            {
                XmlNode Elem = doc.CreateNode(XmlNodeType.Element, "Panel"+index.ToString(), "");
                XmlAttribute LanguageText = doc.CreateAttribute(String.Empty, "LanguageText", "");
                LanguageText.Value = p.Text;
                Elem.Attributes.Append(LanguageText);
                parentNode.AppendChild(Elem);
                index++;
            }
        }

        /// <summary>
        /// <font color='blue'><b>Public.</b></font> Loading luanguage data (of current language) of window's controls from xml-file.
        /// </summary>
        /// <param name="frm">Form, which controls must be translated</param>
        /// <returns>True if all correct, or False</returns>
        public bool Load(Form frm)
        {
            string filename = "";
            if (currentLanguage == Languages.Russian) filename = "russian";
            if (currentLanguage == Languages.English) filename = "english";
            if (currentLanguage == Languages.Dutch) filename = "dutch";
            if (currentLanguage == Languages.Swedish) filename = "swedish";
            filename = filename_prefix + filename;
            filename += "." + frm.Name;
            filename += filename_postfix;

            try 
            {
                doc.Load(filename);                
            }
            catch (Exception e) 
            {
                if (e is System.IO.FileNotFoundException)
                    MessageBox.Show(String.Format("Can't find language file \"{0}\"\nPlease sure that it placed in the application directory!", filename), "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);

                return false;
            }
            
            root = doc.DocumentElement;
            
            // reading nodes
            FormCaptionNode = root.ChildNodes.Item(0);
            MainMenuNode =    root.ChildNodes.Item(1);
            ControlsNode = root.ChildNodes.Item(2);
            ContextMenusNode = root.ChildNodes.Item(3);

            LoadFormCaption(currentLanguage, frm);
         LoadMenuItems(currentLanguage, frm);
            LoadControls(currentLanguage, frm.Controls, ControlsNode);
            LoadContextMenus(currentLanguage, frm, ContextMenusNode);
        
            return true;        
        }

        /// <summary>
        /// <font color='red'><b>Private.</b></font> Loading luanguage data (of current language) of string resources from xml-file.
        /// </summary>
        /// <returns>True if all correct, or False</returns>
        private bool LoadStringResources()
        {
            string filename = "";
            if (currentLanguage == Languages.Russian) filename = "russian";
            if (currentLanguage == Languages.English) filename = "english";
            if (currentLanguage == Languages.Dutch) filename = "dutch";
            if (currentLanguage == Languages.Swedish) filename = "swedish";
            filename = filename_prefix + filename;
            filename += ".resources";
            filename += filename_postfix;

            XmlDocument doc = new XmlDocument();
            XmlNode root = doc.CreateNode(XmlNodeType.Element, "Language", "");

            StringsNode = doc.CreateNode(XmlNodeType.Element, "StringRecources", "");
            root.AppendChild(StringsNode);

            doc.AppendChild(root);
            XmlDeclaration xmldecl;
            xmldecl = doc.CreateXmlDeclaration("1.0",null,null);
            doc.InsertBefore(xmldecl, root);

            try 
            {
                doc.Load(filename);                
            }
            catch (Exception e) 
            {
                if (e is System.IO.FileNotFoundException)
                    MessageBox.Show(String.Format("Can't find language file \"{0}\"\nPlease sure that it placed in the application directory!", filename), "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);

                return false;
            }
            
            root = doc.DocumentElement;
            
            // reading nodes
            StringsNode = root.ChildNodes.Item(0);

            mStringResources.Clear();
            foreach (XmlNode xmlnode in StringsNode.ChildNodes)
            {
                DictionaryEntry mStringResource = new DictionaryEntry(xmlnode.Name, xmlnode.Attributes["LanguageText"].Value);
                mStringResources.Add(mStringResource);
            }

            return true;        
        }

        /// <summary>
        /// <font color='blue'><b>Public.</b></font> Saving luanguage data of window's controls to xml-file.<br>
        /// <font color='red'><b>NOTE!</b></font> It's not used only during projetion process to create sample language file.<br>
        /// <font color='blue'>This method creates directory [/Language] if needed.</font>
        /// </summary>
        /// <param name="lang">Target language of saving file ()</param>
        /// <param name="frm">Form, which control's texts must be saved</param>
        /// <returns>True if all correct, or False</returns>
        public bool Save(Languages lang, Form frm)
        {
            SaveFormCaption(lang, frm);
            SaveMenuItems(lang, frm);            
            ControlsNode.RemoveAll();
            SaveControls(lang, frm.Controls, ControlsNode);
            SaveContextMenus(lang, frm, ContextMenusNode);

            if (System.IO.Directory.Exists(filename_prefix) == false)
                System.IO.Directory.CreateDirectory(filename_prefix);

            string filename = "";
            if (lang == Languages.Russian) filename = "russian";
            if (lang == Languages.English) filename = "english";
            if (lang == Languages.Dutch) filename = "dutch";
            if (lang == Languages.Swedish) filename = "swedish";
            filename = filename_prefix + filename;
            filename += "." + frm.Name;
            filename += filename_postfix;

         try 
            {
                doc.Save(filename);
            }
            catch (Exception e)
            {
            MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return false;
            }
            
            return true;
        }
    }
}


Использовать не сложно — сначала вешаешь на какое-нибудь событие формы вызов метода — Save(form, language)
затем у тебя появляются языковые файлы. не помню точно — создастся ли автоматически файл со строчками... может и нет...
Но результат должен быть таким:
в директории проекта должна появиться папка Language а в ней файл "english.Form1.lng.xml" для английского или "russian.Form1.lng.xml" для русского.
в независимости от количества форм приложения файл со строковыми ресурсами всегда один на каждый язык: "english.resources.lng.xml" или "russian.resources.lng.xml" соответственно.
Сами возможные языки перечисляются в
enum
.

Если будут вопросы или понадобится демка — вышлю почтой или положу куда-нибудь
Удачи
_____________________________
With respect, Andrew A. Golyakoff
Re: Локализация....
От: Аноним  
Дата: 21.08.07 01:56
Оценка:
А не подскажете, если я сделал локализацию с помощью ресурс-файлов, как мне получить список существующих локалей по ресурсам?

Спасибо.


Данное сообщение получено с сайта www.gotdotnet.ru
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.