В мире разработки программного обеспечения интернационализация (i18n) и локализация (l10n) играют важную роль, позволяя адаптировать приложения для различных языков и культур. В Lazarus и Delphi, особенно при работе с пакетами, не зависящими от LCL, возникает вопрос: как реализовать поддержку перевода строк без прямой зависимости от LCL?
В данной статье мы рассмотрим модуль "translations" из пакета LazUtils, который предоставляет функциональность для перевода строк в приложениях Lazarus, не требуя при этом зависимости от LCL. Мы также обсудим, как использовать этот модуль для runtime-only пакетов и как обрабатывать языковые параметры, передаваемые через командную строку.
Проблема:
Как активировать перевод строк в runtime-only пакете (например, пакете, содержащем только функции форматирования), не добавляя зависимости от LCL? Использование SetDefaultLang не подходит, так как требует LCL.
Решение:
Модуль "translations" из пакета LazUtils предоставляет необходимые инструменты для работы с переводами. Он включает в себя функции для загрузки PO-файлов, перевода строк и определения текущего языка. Важно отметить, что LazUtils не зависит от LCL и может быть использован в пакетах, не связанных с графическим интерфейсом.
Ключевые функции модуля "translations":
TranslateUnitResourceStrings(UnitName: string; POFileName: string): Переводит все resource strings в указанном модуле, используя данные из указанного PO-файла. UnitName - имя модуля, содержащего строки для перевода, а POFileName - путь к PO-файлу.
GetLanguageID: Возвращает информацию о текущем языке системы. GetLanguageID.LanguageCode содержит код языка (например, "en", "ru", "de").
Пример использования:
Предположим, у нас есть пакет fp-humanize, содержащий функции для форматирования чисел и дат в удобочитаемом формате. Мы хотим добавить поддержку перевода строк в этот пакет.
Установка LazUtils: Убедитесь, что пакет LazUtils установлен в вашей среде Lazarus.
Создание PO-файлов: Создайте PO-файлы для каждого языка, который вы хотите поддерживать (например, humanize.ru.po, humanize.de.po). Эти файлы содержат пары "оригинальная строка - перевод".
Использование TranslateUnitResourceStrings: В коде пакета вызовите TranslateUnitResourceStrings для каждого модуля, содержащего строки для перевода.
uses
translations;
procedure InitializeTranslations(ALang: string);
var
folder: String;
begin
// Определяем папку, где хранятся PO-файлы
folder := '';
if DirectoryExists('locale') then
folder := 'locale';
if DirectoryExists('languages') then
folder := 'languages';
if folder <> '' then
begin
TranslateUnitResourceStrings('humanize', Format('%s/humanize.%s.po', [folder, ALang]));
end;
end;
initialization
// Пример: Загрузка перевода для русского языка
InitializeTranslations('ru');
end.
Обработка языковых параметров из командной строки:
Иногда необходимо передавать языковой параметр через командную строку (например, myapp -l ru или myapp --lang=de). В этом случае, нужно написать функцию, которая извлекает этот параметр и использует его для загрузки соответствующего PO-файла.
function GetLanguageFromCommandLine: string;
var
index: Integer;
begin
Result := '';
for index := 1 to ParamCount do // Начинаем с 1, ParamStr(0) - имя исполняемого файла
begin
if ParamStr(index) = '-l' then
begin
if (index + 1) <= ParamCount then
Result := ParamStr(index + 1);
break;
end;
if Pos('--lang', ParamStr(index)) > 0 then
begin
if Pos('=', ParamStr(index)) > 0 then
Result := Copy(ParamStr(index), Pos('=', ParamStr(index)) + 1, Length(ParamStr(index)))
else
if (index + 1) <= ParamCount then
Result := ParamStr(index + 1);
break;
end;
end;
if Result = '' then
Result := GetLanguageID.LanguageCode; // Язык системы по умолчанию
end;
procedure InitializeTranslations;
var
lang: string;
begin
lang := GetLanguageFromCommandLine;
if lang <> '' then
InitializeTranslations(lang);
end;
initialization
InitializeTranslations;
end.
Альтернативное решение:
Вместо использования TranslateUnitResourceStrings, можно реализовать собственный механизм перевода, используя словари (TStringList, TDictionary) для хранения соответствий между оригинальными строками и их переводами. Это даст больше гибкости в управлении процессом перевода, но потребует больше усилий по реализации. Преимуществом является возможность динамической загрузки и обновления переводов без перекомпиляции пакета.
Пример альтернативного решения:
uses
Classes, SysUtils;
type
TTranslationDictionary = class(TStringList)
private
function GetTranslation(const Key: string): string;
public
constructor Create;
destructor Destroy; override;
function Translate(const Source: string): string;
procedure LoadFromFile(const FileName: string);
end;
constructor TTranslationDictionary.Create;
begin
inherited Create;
Sorted := True;
Duplicates := dupIgnore;
end;
destructor TTranslationDictionary.Destroy;
begin
inherited Destroy;
end;
function TTranslationDictionary.GetTranslation(const Key: string): string;
var
Index: Integer;
begin
Index := IndexOf(Key);
if Index >= 0 then
Result := StringReplace(Strings[Index], Key + '=', '', [rfReplaceAll])
else
Result := Key;
end;
function TTranslationDictionary.Translate(const Source: string): string;
begin
Result := GetTranslation(Source);
end;
procedure TTranslationDictionary.LoadFromFile(const FileName: string);
var
FS: TStringList;
i: integer;
s: string;
begin
FS := TStringList.Create;
try
FS.LoadFromFile(FileName);
for i := 0 to FS.Count - 1 do
begin
s := Trim(FS[i]);
if (Length(s) > 0) and (s[1] <> '#') then // Игнорируем комментарии
Add(s);
end;
finally
FS.Free;
end;
end;
var
TranslationDictionary: TTranslationDictionary;
function Translate(const Source: string): string;
begin
Result := TranslationDictionary.Translate(Source);
end;
initialization
TranslationDictionary := TTranslationDictionary.Create;
// Пример загрузки файла перевода
TranslationDictionary.LoadFromFile('locale/humanize.ru.txt');
finalization
TranslationDictionary.Free;
end.
// Пример использования
procedure MyProcedure;
begin
ShowMessage(Translate('Hello, world!'));
end;
В этом примере, TTranslationDictionary загружает переводы из текстового файла (например, humanize.ru.txt), где каждая строка имеет формат оригинальная строка=перевод. Функция Translate использует этот словарь для поиска перевода.
Заключение:
Модуль "translations" из LazUtils предоставляет удобный и эффективный способ добавления поддержки перевода строк в runtime-only пакеты Lazarus. Он позволяет избежать зависимости от LCL и обеспечивает хорошую поддержку UTF8. Альтернативные решения, такие как использование собственных словарей, могут предоставить большую гибкость, но требуют больше усилий по реализации. Выбор подхода зависит от конкретных требований вашего проекта.
В статье рассматривается использование модуля "translations" из пакета LazUtils для добавления поддержки перевода строк в Lazarus-проекты, не зависящие от LCL, и предлагаются альтернативные подходы, такие как использование собственных словарей для больше
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.