Автоматизированное место врача от Leybasoft®
Главная » 2017 » Август » 19 » Интернационализация (локализация) приложения на Lazarus
9:12 PM
Интернационализация (локализация) приложения на Lazarus
Видя мучения дельфистов, которые для добавления многоязычного интерфейса вынуждены либо пользоваться сторонним софтом, помещая варианты перевода в ресурсы, либо загружая из базы данных, я решил выяснить, как с этим обстоит дело в Лазаре.

За основу взял мануалы: раз, два и три. Увы, материалы написаны в разное время, для разных версий IDE (и как мне показалось, нерабочие). Поэтому результаты своего опыта опишу здесь.


1. Создаем обычный проект, кладем на форму TRadioGroup с тремя Item, два TLabel и кнопку



2. Заходим в настройки проекта, в пункте i18n указываем папку, в которой будут лежать файлы локализации (у меня этот папка /lang), указываем принудительное обновление *.po (начиная с Lazarus r.
60417 изменилось расширение файлов на *.pot) файлов при изменении формы



и сохраняем настройки проекта.

 

Если поставить галочку "Принудительно обновить файлы PO при следующей компиляции", то в папке lang после компиляции обязательно появится исходный файл для локализации <название проекта>.po , даже если вы его оттуда предварительно (намеренно или случайно) удалили.




3. Добавляем в секции interface в uses модуль LCLTranslator (не добавляйте DefaultTranslator - он пустой; если попытаетесь из него вызвать SetDefaultLang, при компиляции получите ошибку "Identifier not found "SetDefaultLang")

 

4. Теперь компилируем проект и смотрим содержимое папки /lang. Там имеется единственный файл <название проекта>.po (подозреваю, что название главного юнита должно отличаться от имени проекта). Открываем его обычным блокнотом и смотрим содержимое



msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"

#: tform1.button1.caption
msgid "Button1"
msgstr ""

#: tform1.caption
msgid "Form1"
msgstr ""

#: tform1.label1.caption
msgid "Label1"
msgstr ""

 
#: tform1.label2.caption
msgid "Label2"
msgstr ""

Пустые двойные кавычки msgstr "" означают, что их содержимое повторяет содержимое кавычек предыдущей msgid. Если бы я в интерфейсе программы поменял название (Caption), например c "TLabel" на "Надпись", то в файле мы бы увидели msgstr "Надпись" (или загляните в корень своего Лазаруса, в папке /languages откройте любой *.po файл и посмотрите его содержимое).


Чтобы сделать немецкую локализацию, меняем содержимое на следующее
 
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"

#: tform1.button1.caption
msgid "Button1"
msgstr "Taste"

#: tform1.caption
msgid "Form1"
msgstr "Bilden"

#: tform1.label1.caption
msgid "Label1"
msgstr "Etikette"

 

и сохраняем файл под именем <название проекта>.de.po в папке /lang.

То же самое делаем для русской и английской локализации, сохраняя файлы соответственно с префиксом ru.po и en.po

Что делать, если какой-то элемент интерфейса не отображается в *.po файле (например, заголовки Rx-грида) или нам необходимо локализовать пользовательские сообщения (например, в MessageBox)?

Для этого достаточно задать имя  и строковое значение сообщения в resourcestring, например

 

uses
 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
 StdCtrls, LCLTranslator;

resourcestring
  MsgCaption = 'Hello, World';

type 
...

Тогда в *.po-файле проекта появится

#: unit1.msgcaption
msgid "Hello, World"
msgstr ""


Достаточно будет определить ее значение для каждого языка, потом использовать в коде.

5. Теперь пропишем смену языка интерфейса по клику на радиокнопки

procedure TForm1.rgLangClick(Sender: TObject);
begin
 case rgLang.ItemIndex of
 0: SetDefaultLang('en','lang');
 1: SetDefaultLang('ru','lang');
 2: SetDefaultLang('de','lang');
 end;

Label2.Caption:= MsgCaption;
end;

У функции SetDefaultLang(Lang: string; Dir: string = ''; LocaleFileName: string = ''; ForceUpdate: boolean = true): string; четыре параметра:

  • первый (Lang: string;) -  язык (например, «ru», «de»); пустой аргумент является языком по умолчанию, т.е.берется исходный файл <название проекта>.po) - название *.po файла (я подозреваю, что того самого префикса),
  • второй (Dir: string = ' ';) -подкаталог пользовательских файлов перевода (например, «mylng»); пустой аргумент означает поиск только в предопределенных подкаталогах,
  • третий (LocaleFileName: string = ' ';) - имя файла пользовательского перевода; пустой аргумент означает, что имя совпадает с именем исполняемого файла,  
  • четверый (ForceUpdate: boolean = true;) - true означает принудительное немедленное обновление интерфейса. Должно быть установлено значение false, когда процедура вызывается из раздела инициализации устройства. Пользовательский код обычно не должен указывать его.
​​​​​​
В результате получаем
Архив с проектом можно скачать здесь.
 
Категория: Программирование | Просмотров: 2513 | Добавил: leyba | Рейтинг: 5.0/1
Всего комментариев: 1
avatar
1
1 wofs • 3:14 PM, 12.06.2018
Спасибо! Коротко, емко и результативно!
avatar