Введение
Локализация Qt-приложения строится вокруг трёх типов файлов: .ts (исходные файлы переводов в XML, редактируемые в Qt Linguist), .qm (скомпилированные бинарные файлы переводов, используемые в рантайме) и непосредственно вызовы tr() в коде, которые помечают строки для перевода. Процесс извлечения строк (lupdate) и компиляции переводов (lrelease) можно автоматизировать прямо в CMake-сборке, чтобы переводы обновлялись и пересобирались без ручного запуска консольных утилит. В статье рассмотрим, как это настроить.
Концепция
Qt предоставляет CMake-функции qt_add_translations() (современный, высокоуровневый способ в Qt 6.2+) или более ручной набор qt6_create_translation()/qt6_add_translation() для интеграции переводов в сборку. Эти функции автоматически вызывают lupdate для синхронизации .ts-файлов с исходным кодом (поиск новых вызовов tr()) и lrelease для компиляции в .qm, который затем подключается к ресурсам приложения или копируется отдельно для загрузки через QTranslator в рантайме.
Пример кода: Подключение Qt Linguist
find_package(Qt6 REQUIRED COMPONENTS Core Widgets LinguistTools)
set(TS_FILES
translations/myapp_ru.ts
translations/myapp_en.ts
translations/myapp_de.ts
)
add_executable(MyApp main.cpp mainwindow.cpp mainwindow.h)
target_link_libraries(MyApp PRIVATE Qt6::Core Qt6::Widgets)
# Современный высокоуровневый способ (Qt 6.2+):
# автоматически вызывает lupdate/lrelease и подключает .qm файлы
qt_add_translations(MyApp
TS_FILES ${TS_FILES}
RESOURCE_PREFIX "/i18n"
)
// main.cpp — загрузка перевода в зависимости от системной локали
#include <QApplication>
#include <QTranslator>
#include <QLocale>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTranslator translator;
const QString locale = QLocale::system().name(); // например, "ru_RU"
if (translator.load(QLocale(locale), ":/i18n/myapp", "_")) {
app.installTranslator(&translator);
}
MainWindow window;
window.show();
return app.exec();
}
// mainwindow.cpp — пометка строк для перевода
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setWindowTitle(tr("Главное окно приложения"));
auto *button = new QPushButton(tr("Нажмите меня"), this);
setCentralWidget(button);
}
Пояснения к коду
qt_add_translations() связывает список .ts-файлов с целью MyApp: при сборке CMake вызовет lupdate для обновления файлов переводов на основе вызовов tr() в исходниках, а затем lrelease для компиляции их в .qm-файлы, которые автоматически встраиваются в ресурсы приложения с указанным префиксом /i18n.
В main.cpp QTranslator загружает подходящий перевод на основе системной локали через QLocale::system().name() и устанавливает его в приложение через installTranslator() — после этого все вызовы tr() в интерфейсе автоматически возвращают переведённые строки, если соответствующий перевод найден в .qm-файле.
Подводные камни
lupdateне запускается автоматически при изменении исходников без явной пересборки. Если в проект добавлены новые строки сtr(), но.ts-файлы не обновлены и не пересобраны, переводчики не увидят новые строки для перевода — стоит включить обновление.tsв регулярный CI-процесс или pre-commit хук.- Незакрытые контексты перевода (
tr()внутри методов классов, не наследующихQObject) не получают автоматического контекста для группировки в Qt Linguist — переводчику сложнее ориентироваться, в каком месте кода используется конкретная строка. - Отсутствие перевода для конкретной локали «тихо» откатывается на исходный (обычно английский или язык кода) текст, без явной ошибки — это легко не заметить при тестировании только на одной локали разработчика.
- Множественное число (plural forms) обрабатывается неверно при использовании обычного
tr()безQCoreApplication::translateс указанием количества. Для строк, зависящих от числа (например, «1 файл» / «5 файлов»), нужно использоватьtr("%n файл(ов)", "", count)с правильным форматом, иначе перевод на языки с более сложными правилами множественного числа (как русский, с тремя формами) будет некорректным.