Evgenii Legotckoi
05 червня 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. з якими ми могли б працювати через 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

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

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
  • Останні коментарі
  • Evgenii Legotckoi
    16 квітня 2025 р. 17:08
    Благодарю за отзыв. И вам желаю всяческих успехов!
  • IscanderChe
    12 квітня 2025 р. 17:12
    Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
  • AK
    01 квітня 2025 р. 11:41
    Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
  • Evgenii Legotckoi
    09 березня 2025 р. 21:02
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    09 березня 2025 р. 16:14
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…