Локализация интерфейса и сообщений в приложениях .NET и Delphi
Статья была опубликована в журнале "Мир ПК" №2-2008
Не так давно в журнале уже затрагивалась тема локализации (см. «Мир ПК», №6/07, с. 68). В своей статье «Локализация приложений в Delphi для Win32» Михаил Перов рассказал о различных инструментах — коммерческих и бесплатных. Вернуться к сюжету мне пришлось по двум причинам: во-первых, хотелось бы описать непосредственно суть проблемы, вызвавшей появление ряда дополнительных инструментов, и, во-вторых, показать на примере, что разработчики вполне могут решить задачу своими силами.
В действительности технология локализации предлагается поставщиком как для среды разработки Microsoft Visual Studio.NET 2003/2005 (подгружаемые ресурсы), так и для CodeGear Delphi (Data Translation Wizard).
Основное неудобство штатных средств проявляется прежде всего при вовлечении в цикл локализации других исполнителей. В самом деле, вряд ли разработчики смогут самостоятельно сделать корректный перевод текста на несколько языков. Просить же далекого от программирования переводчика (а в заказных проектах зачастую ими являются ключевые пользователи) «набить текст», пользуясь средой Visual Studio или Delphi, не самая лучшая идея. Также всегда есть неприятные, хотя и преодолимые проблемы при локализации уже существующих приложений, где такая возможность не была предусмотрена изначально.
В связи с этим разработана простая, как нам кажется, но удобная с точки зрения контроля процесса технология локализации, подходящую как для автономных разработчиков, так и для небольших групп.
Локализация для .NET
Примечание: см. также более общий подход к локализации для .NET и Mono gettext for .NET/Mono.
Ресурсы редактируются в удобной для переводчика табличной форме в среде MS Excel (рис. 1). Выбор Excel позволяет привлечь к переводу практически любого пользователя, однако при большом количестве задействованных людей, которым рассылаются файлы при децентрализованной работе, могут возникнуть другие проблемы: корректное слияние изменений, версии. Их можно решить, например, используя файл, размещенный на сервере SharePoint: в этом случае пользователь сам синхронизирует сделанные изменения через веб-сервис. При работе внутри сети предприятия возможно простое разделение доступа к файлу на сетевом диске или в системе управления исходным кодом (Visual SourceSafe, SVN и др.). То есть данная схема вполне может масштабироваться до небольших групп переводчиков, работающих в автономном режиме.
Рис. 1. Файл со строковыми ресурсами
Цифрами отмечены:
- 1 и 2 — таблица должна содержать как минимум две колонки: «Message» (идентификатор) и «Neutral» (значение по умолчанию). Идентификатор должен быть уникален для каждой строки.
- 3 — таблица должна иметь название «Messages».
- 4 — для локализации можно добавлять неограниченное число колонок с заголовком в виде «язык-страна», соответствующим значениям культур, поддерживаемых платформой.NET.
- Пустые ячейки: будет использовано значение из колонки «Neutral», соответственно эта колонка должна быть заполнена всегда.
Далее, исходный Excel-файл обрабатывается утилитой, генерирующей ресурсные файлы для платформы .NET. Файлы включаются в проект разработчиком, компилируются как встроенные ресурсы (embedded resource) и затем с использованием небольшой вспомогательной библиотеки классов загружаются в приложение с минимальным написанием программного кода (рис.2).
Рис. 2. Схема локализации для .NET
Чтобы избежать коллизий при наличии нескольких исходных файлов, с которыми работают разные сотрудники, рекомендуется придерживаться именования, соответствующего проекту, например <project name>.Messages.xls
.
Для генерации используется утилита ResourceMaker, конвертирующая файл Excel во множество файлов .NET с расширениями *.resx. Для обеспечения минимального уровня автоматизации утилита запускается из командной строки с параметрами:
Arbinada.Utils.ResourceMaker.exe <имя файла Excel> <Каталог генерации (проекта)>
Например:
Arbinada.Utils.ResourceMaker.exe "C:\Arbinada\Arbinada.MyApp\Arbinada.MyApp.messages.xls" "C:\Arbinada\Arbinada.MyApp" "Messages"
Рекомендуется использовать имя файла ресурсов (BaseName) «Messages», чтобы в дальнейшем при использовании строковых ресурсов в приложении уменьшить количество необходимого для этого кода.
Утилита генерирует один или более файлов *.resx
для каждого определенного вами языка в формате: resx
для значений по умолчанию (neutral), .ru-Ru.resx
для русского, .fr-Fr.resx
для французского и т.д.
Далее вам нужно включить эти ресурсы в проект приложения и перестроить его, после чего они будут готовы к использованию.
Для удобной работы с ресурсами применяется небольшая библиотека Arbinada.Utils.Localizer
. Вам необходимо скомпилировать эту сборку и добавить на нее ссылку в вашем проекте. Чтобы просто извлечь строку по ее идентификатору, используйте следующий код:
using System.Reflection;
using Arbinada.Utils.Localizer;
…
/* Где-то в коде */
string myMessage = ResExtractor.GetMessage(
Assembly.GetExecutingAssembly(),
"MyResourceStringId");
/* Если имя ресурсного файла (BaseName) нестандартное,
то вам нужно всякий раз указывать его явно */
string myMessage2 = ResExtractor.GetMessage(
Assembly.GetExecutingAssembly(),
"MyMessagesFile", "MyResourceStringId");
Чтобы избежать написания большого количества однообразного кода, для локализации визуальных элементов (текст — labels, опции — checkboxes и т. д.) в ваших веб-формах или пользовательских элементах управления (user controls) вы можете использовать класс WebFormLocalizer внутри события Page_Load:
private void Page_Load (object sender, System. EventArgs e)
{
WebFormLocalizer localizer = new WebFormLocalizer (
Assembly.GetExecutingAssembly(),
this,
“MyMessages”, // параметр не нужен, если используется файл “Messages”
“DirThemesCtl_” // префикс идентификатора уровня формы, ресурс ищется по строке
// <Префикс — ID формы> + <WebControl.ID>
);
…
}
Этот фрагмент программы меняет текст (caption) у элементов веб-формы по их идентификатору (WebControl. ID) на соответствующий, найденный в ресурсах. В прилагаемом к статье примере поддерживаются элементы типов: Label, CheckBox, LinkButton, Button и DataGrid.
Для DataGrid используется трехуровневая сигнатура для идентификатора ресурса:
<Префикс — ID формы> + + "_" + <Суффикс — ID колонки>.
Поддерживаются BoundColumn и TemplateColumn. Для ButtonColumn суффикс может принимать значения Edit, Cancel и Update. Более подробно вы можете посмотреть в исходном тексте файла WebFormLocalizer.cs
.
Локализация для Delphi
Технология не имеет принципиальных отличий, она была успешно адаптирована для Delphi 2007 Win32 (рис.3).
Рис.3. Схема локализации для Delphi
Как видно из приведенной схемы, непосредственной компиляции в ресурсы Windows-приложения не происходит. Вместо этого мы используем XML-файлы, содержащие метаинформацию об используемых языках и собственно переведенные строки (рис.4, 5).
Рис.4. Метаинформация об используемых языках локализации
Рис.5. Строковые ресурсы
Вместо написания нескольких строк текста выбираем в палитре компонент TA3FormLocalizer
и в качестве источника назначаем ему LocalizerStore
(рис.6).
Рис.6. Локализация формы в Delphi. Просто "кидаем компонент".
В самом приложении необходимо только проинициализировать хранилище локализованных данных.
{
Читаем данные из директории Localization по заданным SourceFileName и SelectedLocale.
Например, если свойство SourceFileName = 'SampleApp', а SelectedLocale = 'ru-RU',
то будет загружен файл: .\Localization\SampleApp.ru-RU.xml
}
procedure TFormMain.FormCreate(Sender: TObject);
begin
LocalizerStore.SelectedLocale.Parse(TLocaleInfo.GetSystemLocale);
LocalizerStore.LoadData;
end;
После запуска приложение показывает информацию на выбранном языке (в примере используются текущие настройки локализации Windows для пользователя).
Рис.7. Локализованное Delphi-приложение
Взяв исходные тексты (файл A3Localization. pas), вы сможете изучить имеющиеся возможности по локализации широкого круга VCL-компонентов (стандартные элементы управления форм, сетки, компоненты доступа к БД TDataSet с локализацией на уровне названий полей, TActionList и другие). При необходимости в подсистему легко добавить недостающую функциональность, например по локализации ваших собственных компонентов, на основе механизма информации о типах времени выполнения (RTTI — runtime type information), не меняя статической связанности модулей.
Исходные тексты
Zip-архивы, содержащие примеры локализации для веб-приложения .NET и Delphi-приложения под Windows, вы можете скачать по ссылке в конце страницы или на прилагаемом к журналу диске.
Сергей Тарасов, октябрь 2005. Декабрь 2007 (с добавлениями).
blog comments powered by Disqus