Автоматизация lrelease средствами qmake

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

Запуск lupdate в Qt Creator

Запуск lupdate в Qt Creator

Далее в .pro файле в переменной TRANSLATIONS указываются имена одного или нескольких файлов для сбора всех текстовых строк из исходников, традиционно с расширением .ts. Несколько файлов — если переводов планируется несколько, на разные языки. Сбором строк занимается программа lupdate, которая, получив на вход имя .pro файла, из всех исходников проекта собирает все строки из вызовов tr и помещает их в каждый из файлов, перечисленных в переменной TRANSLATIONS. Существующие в .ts файлах строки не перезаписываются. В Qt Creator lupdate можно запустить через меню.

Файлы .ts (внутри — xml) далее попадают к переводчику, который работает в программе Qt Linguist, добавляя в эти файлы переводы строк.

Текстовый формат удобен для редактирования переводов, но не особо — для использования в программе. Qt предлагает бинарный формат, оптимизированный для быстрого поиска строк. Эти файлы (с расширением .qm) создаются из .ts файлов с помощью еще одной программы, lrelease.

Чтобы программа использовала перевод, нужно назначить объекту приложения соответствующий .qm файл с помощью вызова QCoreApplication::installTranslator. При этом ничто не мешает .qm файлам загружаться из ресурсов, я обычно так и поступаю.

Что мне в этой схеме не нравится? Да в общем, все нравится, кроме одного момента: лишние ручные операции с lrelease. Проблема тут не в самих ручных операциях, они необременительные (команда для вызова lrelease в Qt Creator располагается в меню рядом с lupdate) , а в том, что их можно забыть сделать. Забыл запустить lrelease — перевод каких-то строк потеряется. И хорошо еще, если этот факт обнаружите вы, а не заказчик.

Фича my_translations

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

Фича включается в том случае, если переменная TRANSLATIONS не пуста, а переменная RESOURCES содержит имя файла translations.qrc. После этого — в том случае, если значение переменной TRANSLATIONS поменялось с момента последнего запуска qmake — создается файл ресурсов для переводов translations.qrc.

Я создаю файл ресурсов в каталоге исходников и требую, чтобы он был вручную добавлен в переменную RESOURCES (мог бы сам в фиче добавить) для того, чтобы проект собирался даже в случае отсутствия фичи. Кроме того, я столкнулся с неприятным багом при обработке .qrc файлов в OUT_PWD, при котором не генерируются зависимости для файлов из ресурса. Баг вроде бы пофиксили, но осадок остался 😉

Файл translations.qrc создается прямо в фиче для того, чтобы он существовал на момент отработки механизма QMAKE_EXTRA_COMPILERS, с помощью которого реализована обработка переменной RESOURCES. Таким образом гарантируется правильное создание зависимостей от содержащихся в ресурсе файлов; в Makefile создавать файл ресурсов уже поздно. По этой причине работоспособность фичи зависит от того факта, что qmake вызывается тогда, когда нужно. Когда нужно? Когда меняется переменная TRANSLATIONS или когда файл translations.qrc не существует; можно еще когда файл $$OUT_PWD/translations.txt не существует.

К сожалению, мне не удалось создать работающих затычек по этому поводу. Для $$OUT_PWD/translations.txt мне помогло следующее:

Но для translations.qrc я не смог ничего сделать. Что еще более печально, под MSVC qmake имеет привычку не запускаться даже при изменившемся .pro файле, что ни в какие ворота.

Эта проблема с перезапуском qmake встречается постоянно, и в конце концов я сдался и перестал пытаться сделать красиво. Я нарисовал фичу следующего содержания, которая удаляет Makefile после построения проекта:

К сожалению, эта фича не работает в том случае, если построение завершается с ошибкой. Для таких случаев я нацарапал скрипт на питоне, который рекурсивно мочит все встреченные Makefile в указанном каталоге и прицепил его в Qt Creator в меню Tools. Или можно из контекстного меню проекта qmake запустить, но что-то я стал сторонником железобетонных гарантий…

Цикл: qmake

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