© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

Qt/C++ - Урок 049. QTranslator - динамический перевод мультиязычного приложения на Qt

Qt, Linguist, QTranslator

Рано или поздно разработчик приложений на Qt встречается с необходимостью поддержки мультиязычности в своём приложении. Вот тогда на помощь и приходит класс QTranslator и специализированное приложение для создания переводов Qt Linguist .

Объект класса QTranslator используется для загрузки переводов из специального файла с расширением .qm, который является шестнадцатеричным файлом переводов. Данный файл компилируется из файла переводов в XML формате, который имеет расширение ts и прописывается в pro файле проекта. Данный файл содержит все строки приложения, которые были заключены в функцию tr(). Рекомендую задавать весь интерфейс приложения на английском языке, который будет языком по умолчанию, а переводы уже с нужным языком подгружать из файлов переводов. Если нужный файл перевода не будет найден, то автоматически будет загружен перевод на английском языке. Хотя Вы, конечно, можете применить и другой язык в качестве языка по умолчанию.

Пример загрузки перевода

Структура имени файла перевода играет важную роль в работе с QTranslator. Разберём минимальный пример.

#include "mainwindow.h"
#include <QApplication>
#include <QTranslator>
#include <QLibraryInfo>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QTranslator qtLanguageTranslator;
    qtLanguageTranslator.load(QString("QtLanguage_") + QString("ru_RU"));
    qApp->installTranslator(&qtLanguageTranslator);

    MainWindow w;
    w.show();

    return a.exec();
}

В данном примере создаётся объект класса QTranslator, в который загружается интересующий нас файл с указанием языка. В данном случае полное название файла переводов следующее QtLanguage_ru.qm. То есть дано общее для файла переводов название QtLanguage, а также префикс языка перевода _ru . Но вы уже заметили, что в качестве аргумента для метода load формируется строка QtLanguage_ru_RU. Это делается для того, чтобы определить нужный диалект языка, например американский (en_US) или британский (en_GB) английский. Но если в названии файла перевода нет указания диалекта, то будет выбран файл без уточнения диалекта, то есть QtLanguage_ru.qm.

После того, как файл перевода загружен, его необходимо установить в приложение. В данном случае использован глобальный указатель на приложение qApp->installTranslator(&qtLanguageTranslator).

Создание файла перевода

После того, как мы разобрались с минимальным способом установки перевода в приложение, давайте разберёмся с тем, а как вообще можно создать перевод. Для создания перевода необходимо пользоваться функциями tr(), trUtf8(), translate() в приложении и т.д. То есть весь текст, который будет требовать перевода необходимо обрамлять именно в эти функции, чтобы потом создать файл перевода. Выглядеть это может следующим образом:

label->setText(QApplication::translate("MainWindow", "Select Language", 0));
label_2->setText(tr("Hello"));
label_3->setText(trUtf8("Hello world"));

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

  1. lupdate - программа для формирования файла перевода из поля TRANSLATIONS в pro файле, а также обновления информации о всех новых строках в приложении, требующих перевода.
  2. lrelease - программа для сборки итогового файла переводов, который будет использоваться в приложении.
  3. Qt Linguist - непосредственно сам пакет для создания переводов.

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

TRANSLATIONS += QtLanguage_ru.ts

CODECFORSRC     = UTF-8

Далее необходимо воспользоваться утилитой lupdate для создания файла QtLanguage_ru.ts. В Qt Creator ищите здесь: Инструменты -> Внешние -> Linguist -> lupdate .

lupdate сообщит о результате поиска строк для перевода.

Запускается внешняя утилита «D:\Qt\5.6\mingw49_32\bin\lupdate.exe» D:/AndroidQT/QTProjects/QtLanguage/QtLanguage.pro
Updating 'QtLanguage_ru.ts'...
    Found 4 source text(s) (0 new and 4 already existing)

«D:\Qt\5.6\mingw49_32\bin\lupdate.exe» завершилась

Далее открываем Qt Linguist производим перевод всех строк, помечая, какие из них переведены (Это чисто служебная информация для самого переводчика, чтобы не вспоминать, что было переведено, а что нет.)

После создания перевода сохраните файл и скомпилируйте шестнадцатеричный файл перевода, воспользовавшись утилитой lrelease. Её можно найти в Qt Creator там же, где и lupdate, либо запустить из Qt Linguist: File -> Release.

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

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

Загрузка перевода приложения - это хорошо, но что если необходимо менять перевод динамически? Давайте рассмотрим небольшой пример, в котором имеется QComboBox с указанием двух языков: английского и русского, по изменению которого будет происходить смена перевода в приложении.

Структура проекта

  • QtLanguage.pro - профайл проекта;
  • main.cpp - файл проекта с функцией main
  • mainwindow.h - заголовочный файл главного окна приложения;
  • mainwindow.cpp - файл исходных кодов главного окна приложения;
  • mainwindow.ui - файл формы главного окна приложения.

mainwindow.ui

Я предпочитаю использовать графический дизайнер для создания графического интерфейса приложения, поскольку это ускоряет разработку, если не требуется чего-то сложного во внешнем виде приложения, поэтому создадим окно со следующим внешним видом.

В данном окне имеется:

  • label
  • label_2
  • comboBox

С переводом которых мы и будем работать. Удобство графического дизайнера заключается также и в том, что он автоматически формирует метод retranslateUi(), который используется для изменения перевода всех подписей, которые используются в приложении, хотя можно и самим прописать вручную подобный метод, но лично я не хочу терять время на то, что отлично может быть создано автоматически. Например в данном уроке он выглядит следующим образом:

void retranslateUi(QMainWindow *MainWindow)
{
    MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
    label_2->setText(QApplication::translate("MainWindow", "The QTranslator class provides internationalization support for text output.An object of this class contains a set of translations from a source language to a target language. QTranslator provides functions to look up translations in a translation file. Translation files are created using Qt Linguist.", 0));
    label->setText(QApplication::translate("MainWindow", "Select Language", 0));
} // retranslateUi

QtLanguage.pro

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

#-------------------------------------------------
#
# Project created by QtCreator 2016-05-22T14:34:42
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = QtLanguage
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

TRANSLATIONS = QtLanguage_ru.ts

CODECFORSRC     = UTF-8

main.cpp

А вот в этом файле ничего не будем менять.

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

В заголовочном файле главного окна приложения необходимо объявить объекта класса QTranslator и переопределить метод changeEvent(QEvent *event) , в котором будет определяться событие смены языка приложения.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTranslator>
#include <QEvent>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    // Метод получения событий в главном окне приложения
    // В нём будет производиться проверка события смены перевода приложения
    void changeEvent(QEvent * event) override;

private:
    Ui::MainWindow *ui;
    QTranslator qtLanguageTranslator;   // Выделяем перевод в отдельном поле, иначе ничего работать не будет
};

#endif // MAINWINDOW_H

mainwindow.cpp

Логика работы приложения будет следующей: при смене пункта в комбобоксе будет меняться перевод приложения.

Примечание. Не забудьте положить файл перевода с расширением qm рядом с исполняемым файлом приложения и собрать необходимые dll , иначе не заработает.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QTranslator>
#include <QLibraryInfo>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // Задаём два пункта с текстом локалей в комбобоксе
    ui->comboBox->addItems(QStringList() << "ru_RU" << "en_US");

    // подключаем к сигналу изменения пункта комбобокса лямбда функцию,
    // в которой будет изменяться перевод приложения
    // Здесь имеется интересный момент. Поскольку QComboBox имеет перегрузку сигнатуры сигнала,
    // то нам необходимо скастовать сигнал к нужной сигнатуре.
    // В данном случае будем использовать название пункта при его изменении
    connect(ui->comboBox, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
            [=](const QString &str){
        qtLanguageTranslator.load("QtLanguage_" + str, ".");   // Загружаем перевод
        qApp->installTranslator(&qtLanguageTranslator);        // Устанавливаем перевод в приложение
    });

    // Сделаем первоначальную инициализацию перевода для окна прилоежния
    qtLanguageTranslator.load(QString("QtLanguage_") + QString("ru_RU"));
    qApp->installTranslator(&qtLanguageTranslator);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *event)
{
    // В случае получения события изменения языка приложения
    if (event->type() == QEvent::LanguageChange) {
        ui->retranslateUi(this);    // переведём окно заново
    }
}

Итог

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

Скачать пример приложения с QTranslator

Видеоурок

Комментарии

16 мая 2017 г. 4:45

Не работает....

16 мая 2017 г. 4:51

Очень содержательный комментарий. По моему опыту, не работает всегда потому, что кто-то что-то не правильно делает. А в видео показано, что все отлично работает.

24 августа 2017 г. 13:56

А к чему относится такая проблема? Есть QPlainTextEdit. У него есть горячие клавиши. Но они работает только на английском языке : Когда на клавиатуре нажимается ctrl + 'x', горячая клавиша "вырезать" срабатывает. Но при нажатии ctrl + 'ч' не срабатывает. Стоит создать тему на форуме или это что-то само собой разумеющиеся?
Данный код в main.cpp не помог :

    QString translatorFileName = QLatin1String("qt_");
    translatorFileName += QLocale::system().name();
    QTranslator *translator = new QTranslator(&a);
    if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        a.installTranslator(translator);
24 августа 2017 г. 14:08

А вы случаем не переводили эти сочетания клавиш там, где они устанавливаются? Если где-то есть этот перевод, то есть там подставлена tr() b trUtf8() функция, то могут быть проблемы, лучше те куски кода не оборачивать в функции перевода и не делать перевода, тем более, что это и не нужно. Скорее всего коды клавиш неправильно определяются.

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
25 июня 2018 г. 11:55
lebendig

C++ - Тест 006. Перечисления

  • Результат 100 баллов
  • Очки рейтинга 10
25 июня 2018 г. 11:24
lebendig

C++ - Тест 005. Структуры и Классы

  • Результат 100 баллов
  • Очки рейтинга 10
25 июня 2018 г. 8:48
lebendig

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 100 баллов
  • Очки рейтинга 10
Последние комментарии
25 июня 2018 г. 9:34
EVILEG

Как написать игру на Qt - Урок 4. Враг - смысл в выживании

Там неправильный подсчёт был по направлению и полный бардак был с поведением, эти 45 градусов исправляли ситуацию. Точную причину уже совсем не помню. А вообще все эти расчёты довольно...
25 июня 2018 г. 9:13
MarkSD

Как написать игру на Qt - Урок 4. Враг - смысл в выживании

Здравствуйте, Подскажите, пжлст, как работает этот код : QLineF lineToTarget(QPointF(0, 0), mapFromItem(target, 0, 0));  // Проводим линию от паука к мухе qreal angl...
25 июня 2018 г. 7:51
EVILEG

PyQt5 - Урок 003. QSystemTrayIcon - Как свернуть приложение в трей

Если не ошибаюсь, можно просто удалить вот эту строку central_widget.setLayout(grid_layout) Там указатель на парента передаётся в само размещение, что автоматически заменяет в размещен...
Сейчас обсуждают на форуме
25 июня 2018 г. 17:38
IscanderChe

Иконка исполняемого файла

Спасибо!
25 июня 2018 г. 13:12
Arrow

QComboBox и База данных

И если можно еще один вопрос. Таблицы во вложении. Если писать: mainModel = new QSqlRelationalTableModel(this);mainModel-&g...;
25 июня 2018 г. 7:49
EVILEG

На чём сделан этот сайт?

Добрый день! На сервере сайта установлена Ubuntu 16.04. В качестве сервера используется VDS. Хостинг-провайдер Timeweb . Сайт написан на Django/Python, для...
19 июня 2018 г. 7:56
EVILEG

как редактировать порядок обхода этементов по нажатию TAB в Qt5 qml

Что-то наподобие такого TextField { Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()}

Рекомендуемые страницы