Evgenii Legotckoi
5 июня 2016 г. 22:43

QML - Урок 025. Динамический перевод мультиязычного приложения на QML

После того, как мы ознакомились с переводами интерфейса приложения на Qt/C++ , настало время изучить возможности динамического перевода приложения, интерфейс которого написан на QML.

При разработке на QML есть пара моментов, которые нужно учесть, в отличие от стандартного приложения на QWidgets, а именно:

  1. Требуется дополнительная настройка .pro файла проекта;
  2. Сам процесс загрузки переводов для нужного языка осуществляется в C++ слое;
  3. Переинициализация перевода интерфейса осуществляется в QML слое с помощью функции qsTr();
  4. После загрузки перевода, нужно отправить сигнал из C++ слоя в QML слой, чтобы заново перевести интерфейс приложения, что аналогично и для С++ приложения, но требует настройки взаимодействия С++ слоя с QML слоем.

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

Создаём проект, в который будут входит следующие файлы:

  • QmlLanguage.pro - профайл проекта;
  • deployment.pri - файл настройки деплоя, создаётся по умолчанию;
  • main.cpp - файл исходных кодов с функцией main;
  • qmltranslator.h - заголовочный файл класса загрузки перевода;
  • qmltranslator.cpp - файл исходных кодов класса загрузки перевода;
  • main.qml - основной файл QML слоя.

QmlLanguage.pro

Создание файла перевода будет аналогичным тому, как это делается при создании переводов для Qt/C++ приложения. То есть нужно подключить файл перевода, с которым будет работать Qt Linguist :

  1. # Добавляем файл переводов,
  2. # который является по сути файлом "исходных кодов" для нашего перевода
  3. TRANSLATIONS += QmlLanguage_ru.ts

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

Подробнее об этом Вы можете прочитать в предыдущей статье по использованию QTranslator .

Самый важный момент для работы с переводами в QML то, что нужно подключить все файлы QML в качестве исходников, как обычные C++ файлы. Но с отметкой, что только для использования lupdate_only.

  1. lupdate_only {
  2. SOURCES += main.qml
  3. }

Ниже полный листинг .pro файла проекта.

  1. TEMPLATE = app
  2.  
  3. QT += qml quick widgets
  4.  
  5. CONFIG += c++11
  6.  
  7. SOURCES += main.cpp \
  8. qmltranslator.cpp
  9.  
  10. # Для того, чтобы создать файл переводов со строками из ресурсов qml
  11. # понадобится включить файл qml в качестве обычных исходников в pro файле
  12. # но только для использования утилиты lupdate, чтобы она могла узнать,
  13. # какие строки нуждаются в переводе
  14. lupdate_only {
  15. SOURCES += main.qml
  16. }
  17.  
  18. RESOURCES += qml.qrc \
  19. translations.qrc
  20.  
  21. # Additional import path used to resolve QML modules in Qt Creator's code model
  22. QML_IMPORT_PATH =
  23.  
  24. # Default rules for deployment.
  25. include(deployment.pri)
  26.  
  27. # Добавляем файл переводов,
  28. # который является по сути файлом "исходных кодов" для нашего перевода
  29. TRANSLATIONS += QmlLanguage_ru.ts
  30.  
  31. HEADERS += \
  32. qmltranslator.h

main.cpp

Поскольку подключение файлов переводов осуществляется в C++ слое, то потребуется зарегистрировать объект класса переводов в контексте QML. В данном случае мы напишем класс QmlTranslator, который будет обёрткой над QTranslator, поскольку тот класс не имеет методов, с которыми мы могли бы работать через QML.

  1. #include <QApplication>
  2. #include <QQmlApplicationEngine>
  3. #include <QtQml>
  4. #include "qmltranslator.h"
  5.  
  6. int main(int argc, char *argv[])
  7. {
  8. QApplication app(argc, argv);
  9.  
  10. // Создаём объект для работы с переводами ...
  11. QmlTranslator qmlTranslator;
  12.  
  13. QQmlApplicationEngine engine;
  14. // и регистрируем его в качестве контекста в Qml слое
  15. engine.rootContext()->setContextProperty("qmlTranslator", &qmlTranslator);
  16. engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  17.  
  18. return app.exec();
  19. }

qmltranslator.h

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

Метод установки перевода необходимо пометить макросом Q_INVOKABLE, чтобы была возможность использовать его в QML слое.

  1. #ifndef QMLTRANSLATOR_H
  2. #define QMLTRANSLATOR_H
  3.  
  4. #include <QObject>
  5. #include <QTranslator>
  6.  
  7. class QmlTranslator : public QObject
  8. {
  9. Q_OBJECT
  10.  
  11. public:
  12. explicit QmlTranslator(QObject *parent = 0);
  13.  
  14. signals:
  15. // Сигнал об изменении текущего языка для изменения перевода интерфейса
  16. void languageChanged();
  17.  
  18. public:
  19. // Метод установки перевода, который будет доступен в QML
  20. Q_INVOKABLE void setTranslation(QString translation);
  21.  
  22. private:
  23. QTranslator m_translator;
  24. };
  25.  
  26. #endif // QMLTRANSLATOR_H

qmltranslator.cpp

  1. #include "qmltranslator.h"
  2. #include <QApplication>
  3.  
  4. QmlTranslator::QmlTranslator(QObject *parent) : QObject(parent)
  5. {
  6.  
  7. }
  8.  
  9. void QmlTranslator::setTranslation(QString translation)
  10. {
  11. m_translator.load(":/QmlLanguage_" + translation, "."); // Загружаем перевод
  12. qApp->installTranslator(&m_translator); // Устанавливаем его в приложение
  13. emit languageChanged(); // Сигнализируем об изменении текущего перевода
  14. }

main.qml

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

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

Поскольку мы зарегистрировали qmlTranslator в контексте QML слоя, то в обработчике изменения текста в комбобоксе будем вызывать метод изменения языка в объекте qmlTranslator. А чтобы отслеживать сигнал изменения языка, необходимо с помощью типа Connections подключить к этому сигналу и написать обработчик, в котором будет вызываться функция retranslateUi(). В функции retranslateUi() вынесены все текстовые свойства всех объектов, которые необходимо подвергнуть переводу. Сделано это для упрощения логики и уменьшения избыточного кода.

  1. import QtQuick 2.6
  2. import QtQuick.Controls 1.5
  3.  
  4. ApplicationWindow {
  5. id: applicationWindow
  6. visible: true
  7. width: 640
  8. height: 480
  9.  
  10. Label {
  11. id: helloLabel
  12. height: 50
  13. anchors {
  14. top: parent.top
  15. left: parent.left
  16. right: parent.horizontalCenter
  17. margins: 10
  18. }
  19. }
  20.  
  21. ComboBox {
  22. id: comboBox
  23. anchors {
  24. top: parent.top
  25. left: parent.horizontalCenter
  26. right: parent.right
  27. margins: 10
  28. }
  29.  
  30. model: ["ru_RU", "en_US"]
  31.  
  32. // При изменении текста, инициализируем установку перевода через С++ слой
  33. onCurrentTextChanged: {
  34. qmlTranslator.setTranslation(comboBox.currentText)
  35. }
  36. }
  37.  
  38. Label {
  39. id: labelText
  40. wrapMode: Text.Wrap
  41. anchors {
  42. top: helloLabel.bottom
  43. left: parent.left
  44. right: parent.right
  45. margins: 10
  46. }
  47. }
  48.  
  49. // Подключаемся к объекту переводчика
  50. Connections {
  51. target: qmlTranslator // был зарегистрирован в main.cpp
  52. onLanguageChanged: { // при получении сигнала изменения языка
  53. retranslateUi() // инициализируем перевод интерфейса
  54. }
  55. }
  56.  
  57. // Функция перевода интерфейса
  58. function retranslateUi() {
  59. applicationWindow.title = qsTr("Hello World")
  60. helloLabel.text = qsTr("Hello World")
  61. labelText.text = qsTr("The QTranslator class provides internationalization" +
  62. "support for text output.An object of this class contains " +
  63. "a set of translations from a source language to a target language. " +
  64. "QTranslator provides functions to look up translations in a translation file. " +
  65. "Translation files are created using Qt Linguist.")
  66. }
  67.  
  68. // Запускаем перевод приложения, когда окно приложения было создано
  69. Component.onCompleted: {
  70. retranslateUi();
  71. }
  72. }

Итог

В целом динамический перевод приложения на Qt/QML мало чем отличается от перевода приложения с использованием только Qt/C++. Ключевым моментом является то, что нужно правильно подключить сигналы и слоты и правильно вызывать методы для инициализации перевода.

Скачать QML приложение с динамическим переводом

Видеоурок

Вам это нравится? Поделитесь в социальных сетях!

ДЧ
  • 31 января 2019 г. 16:25
  • (ред.)

Всё отлично :)
Только у меня вопрос: а как вместо ru_RU и en_US написать в ComboBox'e Russian и English чтобы сохранить функцию смены языка :)

UPD Разобрался
В comboBox model я пишу так:

  1. model: ["English", "Russian"]

И перед отправкой кода ru_RU или en_US в С++ делаю проверку

  1. onCurrentTextChanged: {
  2. if(comboBox.currentText === "Russian")
  3. qmlTranslator.setTranslation("ru_RU")
  4. if(comboBox.currentText === "English")
  5. qmlTranslator.setTranslation("en_US")
  6. }
zloi
  • 15 июля 2019 г. 15:32

В Qt 5.10 была добавлена новая функция по переводу qml файлов. Теперь не нужно писать класс оболочку, достаточно вызвать функцию engine.retranslate(); и все обновится само.

Evgenii Legotckoi
  • 15 июля 2019 г. 15:35

Это хорошая новость!!!!

Комментарии

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