Qt linguist что это
Перейти к содержимому

Qt linguist что это

  • автор:

15.4. Перевод существующих приложений.

В качестве примера, рассмотрим процесс перевода приложения Spreadsheet, которое было написано нами в Главе 3. Оно уже содержит все необходимые вызовы tr().

Прежде всего, необходимо внести изменения в файл проекта .pro, чтобы указать — какие языки будут поддерживаться приложением. Допустим, что мы собираемся включить поддержку немецкого, французского и русского языков, дополнительно к английскому, тогда необходимо в файл spreadsheet.pro добавить раздел TRANSLATIONS:

TRANSLATIONS = spreadsheet_de.ts \ spreadsheet_fr.ts \ spreadsheet_ru.ts

Здесь мы указали три файла переводов: для немецкого, французского и русского языков. Эти файлы будут созданы при первом запуске утилиты lupdate, а на последующих запусках будут просто дополняться.

Обычно исходные файлы с переводом имеют расширение .ts. Они записываются в формате XML и потому занимают больше места на диске, чем скомпилированные файлы с переводом .qm. Для тех, кому это интересно — .ts означает «translation source» (исходный текст перевода), а .qm — «Qt message».

Допустим, что мы уже находимся в каталоге с исходными текстами приложения Spreadsheet. Теперь запускаем lupdate из командной строки:

lupdate -verbose spreadsheet.pro

Ключ -verbose — необязательный. Он просто заставляет lupdate выводить более подробную информацию в ходе своей работы. Ниже приведен примерный вывод, полученный во время работы утилиты:

Updating spreadsheet_de.ts . 0 known, 101 new and 0 obsoleted messages Updating spreadsheet_fr.ts . 0 known, 101 new and 0 obsoleted messages Updating spreadsheet_ru.ts . 0 known, 101 new and 0 obsoleted messages

Каждая строка, которая «завернута» в вызов tr(), заносится в .ts, с пустым местом для перевода. Строки, которые находятся в файле .ui, так же включаются в исходный файл перевода.

По-умолчанию, lupdate предполагает, что все строки, завернутые в вызовы tr(), набраны в кодировке Latin-1. Если это не так, необходимо указать элемент CODEC в файле .pro, например так:

CODEC = EUC-JP

Это необходимо делать в дополнение к вызову QTextCodec::setCodecForTr() в приложении.

Перевод, в файлы spreadsheet_de.ts, spreadsheet_fr.ts и spreadsheet_ru.ts, добавляется переводчиком, с помощью утилиты Qt Linguist .

Чтобы запустить Qt Linguist , в среде Windows, выберите пункт Qt 3.2.x | Qt Linguist в меню Пуск, в среде Unix — наберите команду linguist. Затем, с помощью меню File|Open, откройте файл с исходным текстом перевода.

С левой стороны главного окна Qt Linguist находится список контекстов переводов. Для Spreadsheet существуют следующие контексты: «FindDialog», «GoToCellDialog», «MainWindow», «SortDialog» и «Spreadsheet». В верхней части с правой стороны находится список строк для текущего контекста. Каждая строка отображается вместе с переводом и флагом Done («Готово»). В средней области, с правой стороны, вводится текст перевода для текущей строки. И внизу находится список переводов, автоматически предлагаемых утилитой Qt Linguist .

По окончании работы над переводом, файл .ts необходимо преобразовать в файл .qm. Для этого, в приложении Qt Linguist выберите пункт меню File|Release. Обычно, после перевода нескольких строк, выполняются пробные запуски приложения, с созданным файлом .qm, чтобы визуально оценить качество перевода.

Рисунок 15.2. Qt Linguist в действии.

Чтобы перегенерировать все файлы .qm сразу, необходимо запустить утилиту командной строки lrelease:

lrelease -verbose spreadsheet.pro

Предположим, что мы сделали перевод на русский язык 19-ти строк, причем установили признак Done для 17-ти из них. В этом случае мы получим от lrelease примерно такой вывод:

Updating spreadsheet_de.qm . 0 finished, 0 unfinished and 101 untranslated messages Updating spreadsheet_fr.qm . 0 finished, 0 unfinished and 101 untranslated messages Updating spreadsheet_ru.qm . 17 finished, 2 unfinished and 82 untranslated messages

Непереведенные строки, при пробном запуске приложения, будут отображаться на языке оригинала. Флаг Done никак не используется утилитой lrelease, он предназначен исключительно для переводчика, чтобы напоминать о том, какие строки имеют окончательный перевод, а какие требуют уточнения.

В случае внесения изменений в исходный код приложения, содержимое файлов .ts может «устареть». Чтобы этого не происходило нужно всякий раз запускать утилиту lupdate, добавлять перевод для вновь появляющихся строк и пересобирать файлы .qm. Некоторые команды разработчиков синхронизируют перевод так часто, насколько это только возможно, другие предпочитают дождаться окончательного релиза приложения и только тогда приступают к переводу.

Утилиты lupdate и Qt Linguist достаточно «умны». Переведенные строки, необходимость в которых уже отпала, все равно сохраняются в исходных файлах с переводами, на тот случай, если они могут понадобиться в будущем. При обновлении файлов .ts, утилита lupdate использует интеллектуальный алгоритм объединения, который помогает избежать лишней работы по переводу одинаковых строк в различных контекстах.

За дополнительной информацией о программах Qt Linguist , lupdate и lrelease, обращайтесь к справочному руководству Qt Linguist , которое доступно по адресу: http://doc.trolltech.com/3.2/linguist-manual.html. Это руководство содержит полное описание пользовательского интерфейса программы и пошаговый самоучитель для программистов.

Пред. В начало След.
Динамическое переключение языков. На уровень выше Разработка справочной системы приложения.

Локализация Qt-приложений

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

Данная статья будет полезна для любителей и начинающих Qt-разработчиков, которые желают разобраться с механизмом интернационализации в фреймворке Qt, чтобы в будущем добавлять локализации в свои приложения. Примеры из данной статьи выполнены на языке Python с применением фреймворка PySide2, это обертка для pyQt5 так что, отличия минимальны, но и применение Qt на других языках не имеет принципиальных отличий. Материал статьи основан на моем личном опыте, который был получен в процессе разработки утилиты для частного применения, которая выполняет пакетную конвертацию изображений и видео в GIF-файлы – GIF Builder и самостоятельного изучения упомянутого фреймворка. В тексте я упомяну о трудностях, которые возникли на пути и о способах их решения. Лишний раз напомню, что в данном деле я всего лишь любитель, поэтому опытным товарищам, возможно, лучше воздержаться от чтения. Я предупредил.

Типичный порядок действий при разработке

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

  • написание/генерация кода: модули с классами пользовательского интерфейса (как правило это окна, виджеты) и классы/модули, которые будут хранить текстовую информацию, которая подлежит переводу на другие языки;
  • конвертация программного кода в файлы переводов с помощью утилиты pylupdate5, или обновление уже существующих;
  • перевод сгенерированных файлов перевода на целевые языки;
  • написание кода, который отвечает за реализацию перевода интерфейса и служебной текстовой информации.

Пожалуй, перейдем уже к делу. Специально для этого я подготовил демонстрационный проект, вот его исходный код на GitHub, откройте его в отдельной вкладке, потому что я будут на него ссылаться в дальнейшем.

Проект имеет следующую структуру:

└Spaceship Control Panel.ui

В папке ��forms:

  • Spaceship Control Panel.ui — исходный макет главного окна, созданный в QtDesigner, работа в этой программе выходит за рамки этой статьи.

В папке ��Translates, в отдельных папках находятся словари с переводами для каждого конкретного языка. В данному случае: русский, английский, немецкий. Файл qtbase_.qm – словарь с переводами, встроенного в Qt текста, просто скопировано из библиотеки PySide2; spaceship_gui_.qm – словарь, содержащий переводы для текстовых данных из нашего кода (в папке ��Русский нет этого файла потому, текстовые данные в программе написаны на этом языке).

В папке ��Translation:

  • fix_coding.py – скрипт для исправления кодировки в коде, сгенерированном QtDesigner, это актуально в случаях, когда язык оригинала имеет символы отличные от латиницы;
  • файлыspaceship_gui_.ts— файлы словарей (en -английский, de — немецкий);
  • TS creation.ps1 – скрипт PowerShell для конвертации исходного кода в файлы перевода.

В корневой папке��:

  • constants.py – содержит языковые константы, которые будут задействованы в коде;
  • main.py – основной код программы;
  • ui_spaceship_control_panel.py- код класса главного окна после экспорта из QtDesigner;
  • ui_spaceship_control_panel2.py — код класса главного окна после исправления, об этом моменте будет сказано далее.

Разработка формы главного окна

Хочу предупредить, что я решил попробовать нестандартный подход, и написал исходный текст интерфейса на русском языке. Если текст написан не латиницей, то программа QtDesigner при генерации кода заменит эти символы на коды юникод (вроде этого- \u1234).

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

Главное окно проекта в программе Qt Designer

На рисунке выше показано окно QtDesigner. При выборе виджетов, которые содержат текстовую информацию на панели «Редактора свойств» у некоторых свойств есть параметр переводимый, если он установлен, то это свойство при генерации словаря будет в него включено; параметр уточнение является вспомогательной информацией от разработчика, например, в английском в отличие от русского нет родов и падежей, поэтому в некоторых случаях нужно довести некоторую информацию до переводчика, чтобы он сделал корректный перевод. В Qt, кроме отображаемого текста у виджетов есть свойства, такие как: всплывающие подсказки, статусные подсказки, горячие клавиши и пр., которые тоже могут подлежать переводу.

После завершения редактирования формы нужно конвертировать его в python-код, вызвав функцию Форма –>Показать код Python, затем сохраняем код на диске. Код из примера в файле ui_spaceship_control_panel.py. Заметьте, что весь переводимый текст обернут в метод translate (подробнее о нем в следующем разделе), также все операции записи текста находятся в теле метода retranslateUi класса окна MainWindow, этот метод нужно вызывать после установки в приложение новых словарей, чтобы перевести исходный текст. Так как текст напечатан кириллицей, то строки имеют нечитаемый вид, если использовать латинский алфавит, то все будет в порядке. Чтобы привести строки в приличный вид, я написал скрипт fix_coding.py, код закомментирован, поэтому разобраться в нем будет несложно.

Генератор кода Qt Designer не хочет отображать кириллицу корректно

Написание классов/модулей с текстовой информацией

Не только в классах форм используется отображаемая текстовая информация, подлежащая переводу на другие языки. Хранить эту информацию можно многими способами, но она должна быть оформлена надлежащим образом. Чтобы объявить переменную с информацией, подлежащей переводу следует воспользоваться методом translate(context, key[, disambiguation=None[, n=-1]]) -> str класса QCoreApplication (PySide2.QtCore), он возвращает перевод исходного текста, используя установленные в приложении словари, он имеет следующие параметры:

  • context – строка содержащая контекст, обычно это имя класса, но может любой, служит для группировки строк;
  • key – исходный текст (он будет впоследствии переводится);
  • disambiguation – служебная информация для переводчика (необязательный параметр).

Метод translate() переводит исходный текст, переданный через параметр key, поиск перевода производится в словарях, которые установлены в приложении (экземпляре класса QApplication).

Класс-хранилище языковых констант

Один из вариантов хранения текстовых констант – это класс. В приведенном примере класс имеет единственный метод retranslate(), выполняющий перевод исходной текстовой информации.

from PySide2.QtCore import QCoreApplication as QA class : ''' Класс с языковыми константами''' @classmethod def retranslate(cls): ''' Метод переводит языковые константы, используя установленные в приложении словари''' cls. = QA.translate("", "< исходный текст 1>", [" "]) cls. = QA.translate("", "< исходный текст N>", [" "])
Модуль-хранилище языковых констант

Можно константы объявлять прямо в теле модуля, только нужно учесть следующие нюансы: константы нельзя импортировать с помощью инструкции from import; чтобы перевести текст нужно перезагрузить модуль функцией reload из модуля importlib, тогда ее объявлять следует так:

from PySide2.QtCore import QCoreApplication as QA = QA.translate("", "< исходный текст 1>", [" "]) = QA.translate("", "< исходный текст N>", [" "])

На мой взгляд, использование модуля удобнее, поскольку IDE (в моем случае PyCharm) будет выдавать подсказки при вводе, что не работает при использовании статического класса. Также можно объявить константы в методе __init__() и просто использовать экземпляр класса, а для перевода просто вызвать его снова.

Сборка файлов перевода

Когда работа над исходным кодом завершена, наступает этап сборки файлов перевода (файлы с расширением .ts). В этом нам поможет утилита pylupdate5.exe, все действия производились в ОС Windows. Чтобы собрать файлы из исходного кода нужно в терминале ввести команду (в демопроекте есть файл TS cretation.ps1):

  • список путей к файлам с исходным кодом – указать пути в файлам с исходным кодом, которые будут проанализированы и текст, переданный в метод translate()будет внесен в файлы с переводом; пути разделяются пробелом;
  • список путей к файлам переводов, которые будут созданы/обновлены – тут следует ввести пути к файлам, которые будут созданы, если файлы существуют, то информация в них будет обновлена; ее придется обновлять, ведь программу придется исправлять и дополнять; пути разделяются пробелом.

Имена файлов с переводами могут быть любыми, но желательно соблюдать следующее соглашение имен: _.ts, например, main_en.ts.

Перевод текста

Итак, переводимый текст собран в специальных файлах, теперь надо его перевести на целевой язык. Запускаем утилиту Qt Linguist и открываем наши ts-файлы. При первой загрузке нужно выбрать исходный язык и язык перевода. У утилиты есть одна фишка — можно открыть сразу несколько словарей, чтобы сразу выполнить перевод на несколько языков, такое поведение может быть несколько непривычным.

В разделе Контекст мы видим, что все текстовые данные сгруппированы в соответствии с тем текстом, который был перед методу translate() через аргумент context. В разделе Строки выделяем строку и в поле перевод на целевой язык вводим соответственно перевод исходного текста и жмем Alt+Enter, тогда строка будет помечена зеленой галочкой. Проводим эту операцию над всем строками, если некоторые из них не будут иметь перевода, то текст останется оригинальным – все просто.

После завершения перевода нужно скомпилировать файлы словарей, для этого нужно выбрать одну из команд Скомпилировать в разделе Файл главного верхнего меню.

Также есть возможность скомпилировать файлы переводов утилитой lrelease, можно прочитать информацию по ней здесь.

Использование словарей в коде программы

Наконец-то пришло время поговорить о том, как же использовать словари в своей программе, все предельно просто, смотрим код из демо: main.py, акцентирую свое внимание только на тех операциях, которые необходимы для решения поставленной задачи.

У нас имеется класс MainWindow, в методе __init__() запускается метод _init_lang(). В _init_lang() происходит следующее:

  1. загружается список имен папок, находящихся в папке Translates (такой подход позволяет добавлять новую локализацию просто добавлением новой папки со словарями);
  2. полученный список папок устанавливается в виджет выпадающего списка comboBox_language (QComboBox), устанавливается текущий элемент;
  3. создается переменная, которая будет содержать словари (_translators);
  4. запускается процедура обновления текущего языка (on_lang_changed()).

Метод on_lang_changed() выполняет загрузку словарей и перевод текста, он также привязан к сигналу currentTextChanged comboBox_language (QComboBox), чтобы он выполнялся, когда пользователь выбирает другой язык.

Чтобы полученные словари использовать их нужно установить, поэтому для каждого словаря создается экземпляр класса QTranslator (PySide2.QtCore) и тот заносится в список _translators, затем файл словаря загружается вызовом метода load(). Словари в приложение (экземпляр класса QApplication (PySide2. QtWidgets), каждое Qt-приложение его содержит) устанавливаются методом installTranslator(). В случае, когда словари уже установлены и нужно установить другие, то нужно их сперва удалить методом removeTranslator(). После установки нужно обновить интерфейс и языковые константы, за это отвечают эти две строчки:

self.ui.retranslateUi(self) # перевести текст в элементах интерфейса LC.retranslate() # в классе с языковыми константами

Резюме

Все переводимые текстовые данные в коде должны быть обернуты в метод translate(context, key[, disambiguation=None[, n=-1]]) -> str класса QCoreApplication (PySide2.QtCore), это метод переводит исходный текст, переданный через параметр key, поиск перевода производится в установленных в приложении словарях.

Файлы перевода (имеют расширение .TS) создаются из файлов исходного кода утилитой pylupdate5.exe, текст в них переводится с помощью программы QtLinguist и компилируются в словари (имеют расширение .QM).

Словари загружаются в экземпляры класса QTranslator методом load(), затем экземпляр устанавливается в приложение (экземпляр класса QApplication) при помощи метода installTranslator(). Ранее установленные словари удаляются методом removeTranslator().

Отображаемая информация обновляется. У классов, сгенерированных QtDesigner обновление производится методом retranslateUi().

  • python3
  • pyside2
  • pyqt5
  • локализация по
  • интернационализация
  • доступность информации

Qt — трудности перевода

Вы написали программу на Qt и хотите перевести ее на другие языки, что бы сделать ее полезной для людей в других странах. Сделать это не просто, а очень просто. Для этого нам потребуется сделать всего три простых шага.

Исходная программа

Пусть у нас есть простая программа:

  1. #include
  2. #include
  3. int main( int argc, char *argv[])
  4. QApplication app(argc, argv);
  5. QLabel label( «Hello, World!» );
  6. label.show();
  7. return app.exec();
  8. >

Все что она делает — создает окно с надписью «Hello,World!». Сделаем для нее перевод на русский язык.

Шаг 1. Указание всех строк, для которых требуется сделать перевод

Все строки, которые увидит пользователь должны быть обработаны функциями QObject::tr() или QcoreApplication::translate().
У всех классов Qt, наследуемых от QObject, есть функция-член tr(). Так как мы работаем со строкой в глобальной функции которая не относится ни к какому классу, то используем функцию translate(), которая позволяет указать контекст перевода, то есть класс, к которому он относится (в данном случае — QLabel).

  1. #include
  2. #include
  3. int main( int argc, char *argv[])
  4. QApplication app(argc, argv);
  5. QLabel label(app.translate( «QLabel» , «Hello, World!» ));
  6. label.show();
  7. return app.exec();
  8. >

В фунцкиях tr() и translate() после переводимой строки можно указать комментарий, который будет показан переводчику во время перевода приложения на другой языка. Комментарии используются для устранения двусмысленности.
Если вам потребуется перевести текст, который находится вне функции, есть два макроса для помощи: QT_TR_NOOP() и QT_TRANSLATE_NOOP(), аналогичные tr() и translate(). Они незаметно помечают текст для извлечения утилитой lupdate, про которую мы поговорим ниже:

  1. static const char *greeting_strings[] =
  2. QT_TR_NOOP( «Hello» ),
  3. QT_TR_NOOP( «Goodbye» )
  4. >;
  5. static const char *greeting_strings[] =
  6. QT_TRANSLATE_NOOP( «HelloWidget» , «Hello» ),
  7. QT_TRANSLATE_NOOP( «HelloWidget» , «Goodbye» )
  8. >;

При отключении автоматического преобразования из const char * в QString путем компиляции программы с определенным макросом QT_NO_CAST_FROM_ASCII можно найти все строки, которые пропустили.
Когда в середину строки нам понадобится вставлять значения каких-либо переменных, лучше всего использовать функцию arg(). Например, при копировании файлов мы могли бы отображать ход процесса следующим образом:

  1. void FileCopier::showProgress( int done, int total,
  2. const QString &currentFile)
  3. label.setText(tr( «%1 of %2 files copied.\nCopying: %3» )
  4. .arg(done)
  5. .arg(total)
  6. .arg(currentFile));
  7. >

Если потребуется изменить порядок аргументов при переводе, то при переводе надо будет поменять переменные с символом % местами, например, вот так:

«Копируем файл %3. %1 из %2 файлов скопировано»

Переписывать программу из-за этого не потребуется.

Шаг 2. Создание перевода
  1. Запуск lupdate для извлечения переводимого текста из исходного кода приложения Qt на C++, создавая файл сообщений для переводчиков (файл .ts). Утилита распознает конструкторы tr() и translate() и макросы QT_TR*_NOOP(), описанные выше, и производит файлы .ts (обычно один на каждый язык).
  2. Обеспечение переводов для исходных текстов в файле .ts, используя Qt Linguist. Так как файлы .ts в формате XML, их можно также отредактировать вручную.
  3. Запуск lrelease для получения легкого файла сообщений (файл .qm) из файла .ts, удобного только для конечного пользования. Думайте о файлах .ts как об «исходных файлах», и о файлах .qm как об «объектных файлах». Переводчик редактирует файлы .ts, но пользователям нашего приложения требуются только файлы .qm. Оба типа файлов не зависят от платформы и локали.

Обычно надо повторять эти шаги для каждого выпуска приложения. Утилита lupdate делает все возможное по повторному использованию переводов от предыдущих релизов.
Перед запуском lupdate, вам потребуется подготовить файл проектов. Вот как будет выглядеть наш файл проекта (файл helloworld.pro):

TEMPLATE = app
TARGET = release
DEPENDPATH +=.
INCLUDEPATH +=.
SOURCES += main.cpp
TRANSLATIONS += helloworld_ru.ts

Когда вы запускаете lupdate или lrelease, вы должны предоставить имя файла проекта в качестве аргумента командной строки.

Шаг 3. Загрузка файлов переводов в приложении.

В нашем приложении мы должны загрузить QTranslator::load() файлы используя QcoreApplication::installTranslator(). Окончательная версия программы примет вид:

  1. #include
  2. #include
  3. int main( int argc, char *argv[])
  4. QApplication app(argc, argv);
  5. QTranslator myTranslator;
  6. myTranslator.load( «helloworld_» + QLocale::system().name());
  7. app.installTranslator(&myTranslator);
  8. QLabel label(app.translate( «QLabel» , «Hello, World!» ));
  9. label.show();
  10. return app.exec();
  11. >

Мы создаем объект QTranslator, загружаем в него файл перевода с помощью функции load(). В ней мы указываем начало имени файла нашего перевода. По умолчанию файлы переводов ищутся в папке с программой, но можно указать любую директорию, передав ее имя в качестве второго параметра функции. Расширение «.qm» будет добавлено автоматически. Функция Qlocale::system().name() возвращает имя текущей локали, в моем случае это было ru_RU.UTF-8. Порядок поиска файла переводов функцией load() будет следующим:

  1. helloworld_ru_RU.UTF-8.qm
  2. helloworld_ru_RU.UTF-8
  3. helloworld_ru_RU.qm
  4. helloworld_ru_RU
  5. helloworld_ru.qm
  6. helloworld_ru
  7. helloworld.qm
  8. helloworld

Правда когда я попробовал загрузить таким образом файл переводов в Windows XP, у меня ничего не вышло. Оказалось, что (по крайней мере у меня так) функция Qlocale::system().name() все время возвращала значение «С». Поэтому стоит предусмотреть дополнительный способ указания языка интерфейса приложения, например, через диалог настроек программы или параметры командной строки.

Вот и все, наше приложение переведено на русский язык, но есть еще парочка моментов, о которых стоит упомянуть в данной статье.

Дополнительные текстовые строки

Qt содержит внутри около 400 строк, которые так же должны быть переведены на языки которые нам необходимы. В директории $QTDIR/translations можно найти файлы переводов для французского, немецкого и упрощенного китайского, так же как и шаблоны для перевода на другие языки. (Эта директория так же содержит некоторые дополнительные неподдерживаемые переводы, которые могут быть полезны, например, перевод на русский язык).
Обычно эти переводы подгружают так же в фунции main():

  1. int main( int argc, char *argv[])
  2. .
  3. QTranslator qtTranslator;
  4. qtTranslator.load( «qt_» + QLocale::system().name(),
  5. QLibraryInfo::location(QLibraryInfo::TranslationsPath));
  6. app.installTranslator(&qtTranslator);
  7. .
  8. >

Обратите внимание на использование QLibraryInfo::location() для обнаружения переводов Qt. Разработчик должен запросить путь к переводам обрабатывая QLibraryInfo::TranslationsPath для этой функции вместо использования переменной среды QTDIR в своих приложениях. Хотя в случаях, когда мы не уверены что у пользователя стоит полная версия Qt, имеет смысл поставлять этот файл переводов вместе с программой и загружать его из директории программы (или любой другой на выбор).

Динамический перевод

Некоторые приложения должны обеспечивать изменения настроек языка пользователя во время работы. Что бы предупредить виджеты об изменениях установленного QTranslators, можно переделать фунцкцию виджета changeEvent() для проверки не является ли событие событием LanguageChange, и обновите текст, отображаемый виджетами, используя функцию tr() обычным способом. Например:

  1. void MyWidget::changeEvent(QEvent * event )
  2. if (e->type() == QEvent::LanguageChange)
  3. titleLabel->setText(tr( «Document Title» ));
  4. .
  5. okPushButton->setText(tr( «&OK» ));
  6. > else
  7. QWidget::changeEvent( event );
  8. >

Все остальные события изменения должны быть обработаны вызовом реализации по умолчанию данной функции.
Список установленных переводов может быть изменен в реакции на событие LocaleChange, или приложение может предоставлять интерфейс пользователю, который позволит ему изменить текущий язык приложения.
Обработчик событий по умолчанию для подклассов QWidget отвечает на событие QEvent::LanguageChange и вызовет эту функцию при необходимости; в других компонентах приложения можно так же заставить виджеты обновить себя отправив им событие LanguageChange.
UPD: Как подсказывает intellinside, классы графического интерфейса пользователя, сгенерированные Qt Designer’ом, имеют функцию retranslateUi(), которую можно вызвать для динамического изменения языка приложения.

LInvert

Как известно, правила локализации Qt-приложений требуют, чтобы все строковые константы в программе были обрамлены в функции tr() или translate(). Также считается хорошей практикой (хотя и не требуется разработчиками Qt), чтобы эти константы содержали только латинские символы. В противном случае надо либо заменять tr() на trUtf8(), либо колдовать с кодеками и CODECFORTR/CODECFORSRC. Ситуация осложняется, когда для национального языка имеют хождение несколько разных кодировок, с русским языком дела обстоят именно так. Как правило, в текстах программы все сообщения пишут на английском языке, а остальные языки существуют только в файлах переводов. Единственный минус такой схемы — если программа изначально разрабатывалась для неанглоязычных пользователей (особенно это относится к заказному ПО, которое изначально делается под конкретного заказчика), то размещая английский текст в коде, а перевод где-то ещё, мы проделываем двойную работу. Поэтому зачастую текст хардкодится в программе на родном для программистов и пользователей языке (в этом случае крайне рекомендуется применение UTF-8). Но что делать, если ПО изначально делалось для конкретных клиентов, а потом начало перерастать в международный продукт? Описанная ситуация характерна для закрытого коммерческого ПО. Но схожая проблема может возникнуть и в открытых проектах: программист делал программу «для себя», не особо задумываясь о переводах, а потом увидел, что его детище может быть полезным ещё кому-то, и захотел выложить исходники в общий доступ. Если строки в программе не английские, это может осложнить привлечение к проекту разработчиков из других стран. Здесь есть два способа. Простейший — оставить всё как есть и файлы переводов делать «с русского на финский». Linguist такое позволяет, и в формате файла .ts предусмотрены соответствующие атрибуты. Правда, с отображением контекста перевода в исходниках из Linguist возможны косяки. Кроме того, найти переводчиков на какой-нибудь экзотический язык может оказаться проще с английского, чем с русского (особенно для некоммерческого проекта). Для некоммерческого проекта также важно, что при этом вряд ли удастся работать с иноязычными программистами. Второй способ — привести программу к общепринятой практике, то есть заменить все национальные строковые константы английскими, а национальные вынести в файлы перевода. Если заниматься этим вручную, это очень трудоёмкая процедура. Утилита LInvert позволяет частично автоматизировать второй способ.

Технология применения

  • Проводим ревизию исходных текстов. Проверяется, что все файлы программы выполнены в кодировке UTF-8, а все строки, подлежащие переводу, обрамлены в функцию trUtf8. Эти строки не должны составляться слишком сложным образом, другими словами, их должна понимать утилита lupdate из Qt Linguist (подробнее об этом в разделе «Ограничения»). Для упрощения унификации кодировок unix-программисты могут воспользоваться программой enca (о чём я писал в Башне).
  • Создаём прототипы файлов перевода. Прототипы — это обычные файлы .ts, но теги source и translation у него «перепутаны». Создаются обычной командой lupdate из состава Qt Linguist.
  • Переводим файлы .ts на английский с помощью Linguist. Переводчикам (если это отдельные люди) надо объяснить, что национальный текст будет в графе «Исходный текст», а английский — в графе «Русский перевод», и это нормально. Если часть сообщений уже была на английском языке, их можно перевести обратно.
    • По окончании этого шага можно пометить сообщения, которые уже были на английском языке, чтобы linvert их не переводил. Для этого в элемент добавляется атрибут linvert=»false». До вызова Linguist это делать смысла нет, поскольку Linguist такого атрибута не знает и просто удалит его при перезаписи файла. Атрибут linvert=»true», наоборот, сообщит, что сообщение надо переводить, даже если программа вызвана с ключом -i (см. «Вызов программы»).

    На этом адаптация закончена. Можно включать полученный .ts в проект, загружать .qm в программу и переводить проект на другие языки.

    Вызов программы

    Как lupdate и lrelease, LInvert — утилита командной строки. Вызов выглядит следующим образом:

    linvert -l LANG_CODE [-p] [-i] ts-file [ts-file].

    Ключ -l задаёт код национального языка (напр. ru_RU), который будет использован в качестве суффикса для имён выходных .ts-файлов, а также в атрибуте language элемента TS.

    Ключи -p и -i определяют поведение программы, если для некоторого элемента message отсутствует атрибут linvert. Ключ -p предписывает обрабатывать такие записи (поведение по умолчанию), ключ -i — игнорировать.

    Ограничения

    В текущей версии linvert поддерживается преобразование файлов исходного кода C++ и файлов *.ui. Поддержки QML пока нет.

    Программа linvert накладывает на файлы исходного кода те же ограничения, что и программа lupdate из состава Qt Linguist.

    • простая конкатенация строк;
    • перенос строковой константы на следующую строку исходного кода (обратный слэш);
    • несколько конструкций trUtf8() в одной строке исходного кода.
    • определения #define и поименованные строковые константы, включаемые в trUtf8();
    • вложенные круглые скобки.

    К примеру, в закомментированной части файла test/testsourcesample.cpp из выражения, присваиваемого строке s3, lupdate определит только фрагмент «Строка31». Соответственно, если у Вас в строковых операциях фигурирует макроопределение #define национальном языке, в trUtf8 надо обрамлять само макроопределение, а не его использование.

    Условия распространения

    Программа распространяется по лицензии LGPL 2.1 либо LGPL 3, так же, как и утилиты lupdate и lrelease из состава Qt Linguist.

    Двоичных сборок я не делаю, поскольку программист, применяющий Qt, легко соберёт программу под свою ОС, версию Qt, архитектуру и разрядность процессора ;).

    Исходный текст на гитхабе
    Обсудить в блоге М.З., 26.01.2016

    Пишите! Designed by
    Arachnophilia

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *