Вопрос: Как осуществить в Лазарусе интернационализацию приложения?
Ответ:Описанный ниже способ проверен на версии Lazarus 0.9.24 beta, версия fpc 2.2.0
ОС: MS WINDOWS XP SP2, Linux Mandriva 2008.0
В Linux Mandriva 2008.0 Lazarus собран для GTK2
Итак, для интернационализации приложения требуется:
1. Определить языковой состав проекта.
2. Вынести в ресурсы строковые константы.
3. Настроить проект
4. Использовать процедуры из модулей Translations, Gettext.
5.
Правильно отредактировать .po-файл
Рассмотрим пример1. Создадим новый проект. Реализовываться будет на двух языках: английском и русском. В качестве основного языка лучше выбрать английский язык, об этом будет сказано ниже.
2. На форме разместим компонент
Label1 и кнопку
Button13. Очистим в инспекторе объектов свойство Caption у компонентов, размещенных на форме, а также у самой формы. Иначе эти свойства попадут в po-файл дважды.
4. Определим имена строковых констант для наших компонентов. Можно использовать имя компонента слитно с именем свойства без разделяющей точки.
Например, для
Label1.Caption имя константы выглядит как
Label1Caption.
5. Строковые константы необходимо вынести в ресурсы. Для этого в модуле формы создаем раздел
resourcestring и помещаем в него строковые константы с присвоением им значений:
- Код: Выделить всё
resourcestring
Form1Caption = 'Lazarus Application';
Label1Caption = 'This is testing application!';
Button1Caption = 'Run';
Раздел
resourcestring может находиться как в модуле формы, так и в отдельном модуле.
В отдельном модуле раздел
resourcestring размещается в разделе
interface.
6. Сохраняем проект в отдельную папку. В этой же папке создаем вложенную папку для языковых файлов. В нашем примере создадим папку с именем languages.
7. В Лазарусе выбираем пункт меню
Проект->Настройки проекта. Переходим на вкладку
i18n. Ставим галочку
Использовать i18n.
В текстовом поле
Каталог вывода файлов PO указываем нашу папку languages, воспользовавшись кнопкой выбора справа от поля.
Важно: В текстовом поле отображается только имя папки без указания пути. Тем не менее путь нужно указывать полностью, именно поэтому лучше воспользоваться кнопкой выбора.
Для закрытия окна настроек нажимаем кнопку ОК.
8. Собираем проект (выбираем меню
Запуск -> Собрать все). Теперь в папке languages создан языковой файл с именем проекта и расширением po, например
project1.po.
Важно: В проекте не должно быть ошибок, иначе сборка завершится неудачей и po-файл не будет создан. Если ошибки обнаружились, их нужно исправить и повторить полную сборку проекта.
10. Перейдем в папку languages и сделаем в этой папке копию находящегося там po-файла с добавлением к имени файла суффикса языка.
Например, файл
project1.po для русского языка копируем с именем
project1.ru.po.
11. Теперь напишем необходимый код. В раздел
Uses модуля формы добавим модули Translations и Gettext.
Из этих модулей нам потребуются две процедуры.
Procedure TranslateUnitResourceStrings
(const ResUnitName
, BaseFilename
, Lang
, FallbackLang
: string); из модуля Translations.
Параметры:const ResUnitName
: string - имя модуля, в который вынесены строковые константы
BaseFilename
: string - имя языкового файла с указанием пути к нему
Lang
: string - языковая настройка системы, например ru
FallbackLang
: string - сочетание обозначений языковой раскладки и страны, например ru_RU
Procedure GetLanguageIDs
(var Lang
, FallbackLang
: string); из модуля GetText. Используется для определения значений Lang и FallBackLang
Вызов этих процедур должен выполняться до присвоения значений свойствам компонентов формы. Т.е. эти процедуры должны вызываться в обработчике события создания формы.
Важно: В модуле Translations кроме
процедуры TranslateUnitResourceStrings существует
функция с таким же именем, но с другим набором параметров. Нам требуется именно процедура, а не функция.
Также процедура TranslateUnitResourceStrings объявлена в модуле GetText, нам нужна процедура из модуля Translations, поэтому перед вызовом процедуры нужно указать имя модуля.
В результате код обработчика события создания формы для нашего примера выглядит так:
- Код: Выделить всё
procedure TForm1.FormCreate(Sender: TObject);
var
PODirectory, Lang, FallbackLang: String;
begin
PODirectory:='path/to/languages/'; //здесь укажите полный путь к языковым файлам
GetLanguageIDs(Lang,FallbackLang); // определение языковых параметров системы
//Перед именем процедуры TranslateUnitResourceStrings указываем
имя модуля Translations во избежание разночтений.
//'project1.%s.po' - имя языкового файла. %s - языковой суффикс.
Translations.TranslateUnitResourceStrings('Unit1',PODirectory+'project1.%s.po',lang,Fallbacklang);
//присваиваем значения свойствам компонентов формы
Form1.caption:=Form1Caption;
Button1.Caption:=Button1Caption;
end;
Важно: Путь к языковым файлам, помещаемый в переменную PODirectory, не должен содержать символов, преобразуемых в код (т.е. пробелов, символов кириллицы и т.д.)
Обработчик события нажатия кнопки выглядит так:
- Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:=Label1Caption;
end;
12. Сохраняем проект.
13. Осталось отредактировать языковой файл (файл перевода).
Языковой файл, сгенерированный при сборке нашего проекта имеет следующий вид:
#: unit1.form1captionmsgid "Lazarus Application"msgstr ""#: unit1.label1captionmsgid "This is testing application!"msgstr ""#: unit1.button1captionmsgid "Run"msgstr ""msgid - идентификатор элемента перевода (т.е. фразы), в качестве которого используется значение константы из раздела
resourcestring.
Именно поэтому в качестве основного языка лучше выбрать английский, т.к. константам задаются англоязычные значения и мы имеем в языковом файле англоязычные идентификаторы.
Если же в качестве основного языка выбран русский (соответственно константам заданы русскоязычные значения), то идентификаторы в языковом файле преобразуются в коды символов, т.к. не могут содержать символы кириллицы. В этом случае с языковым файлом работать очень неудобно.
msgstr - значение элемента перевода (т.е. фраза на языке, отличном от основного). В нашем примере в кавычках вписываются значения констант на русском языке.
В результате файл для русского языка
project1.ru.po получается таким:
#: unit1.form1captionmsgid "Lazarus Application"msgstr "Приложение Лазарус"#: unit1.label1captionmsgid "This is testing application!"msgstr "Это тестовое приложение!"#: unit1.button1captionmsgid "Run"msgstr "Пуск"Одной из причин, по которой не работает интернационализация описанным способом является нарушение формата языкового файла. Языковой файл - это обычный текстовый файл и при редактировании его в Windows символы конца строки в файле вставляются по стандарту Windows. После этого интернационализация перестает работать.
Если же сохранить po-файл с концами строк как в UNIX, проблема исчезает. Поэтому пользователям Windows для редактирования po-файлов лучше использовать редакторы типа Poedit, выставив в настройках формат конца строки как в UNIX.
Другой причиной является неверное указание пути к файлам локализации. В процедуру TranslateUnitResourceStrings должен передаваться полный путь к po-файлу, не содержащий пробелов и символов кириллицы.
Теперь можно запустить проект и убедиться, что надписи на форме отображаются на русском языке. Если сменить системные языковые настройки, то надписи на форме будут отображаться на английском языке. Если отсутствует языковой файл для русского языка, то надписи на форме отображаются на основном языке (в данном случае английский).