Після того, як ми ознайомилися з перекладами інтерфейсу програми на Qt/C++ , настав час вивчити можливості динамічного перекладу програми, інтерфейс якого написаний на * QML. *
При розробці на QML є пара моментів, які потрібно врахувати, на відміну від стандартної програми на QWidgets, а саме:
- Потрібне додаткове налаштування .pro файлу проекту;
- Сам процес завантаження перекладів для потрібної мови здійснюється у C++ шарі;
- Переініціалізація перекладу інтерфейсу здійснюється в QML шарі за допомогою функції qsTr();
- Після завантаження перекладу, потрібно відправити сигнал з C++ шару QML шар, щоб заново перевести інтерфейс програми, що аналогічно і для С++ програми, але вимагає налаштування взаємодії С++ шару з QML шаром.
Структура проекта
Створюємо проект, куди входять такі файлы:
- QmlLanguage.pro - профайл проекту;
- deployment.pri - файл налаштування деплою, що створюється за замовчуванням;
- main.cpp - файл вихідних кодів із функцією main;
- qmltranslator.h - заголовний файл класу завантаження перекладу;
- qmltranslator.cpp - файл вихідних кодів класу завантаження перекладу;
- main.qml - основний файл QML шару.
QmlLanguage.pro
Створення файлу перекладу буде аналогічним тому, як це робиться під час створення перекладів для Qt/C++ програми. Тобто потрібно підключити файл перекладу, з яким працюватиме Qt Linguist :
- # Добавляем файл переводов,
- # который является по сути файлом "исходных кодов" для нашего перевода
- TRANSLATIONS += QmlLanguage_ru.ts
Далі запускаємо утиліту lupdate, щоб створити файл перекладів, редагуємо його в Qt Linguist , і запустимо утиліту lrelease створюємо бінарний файл перекладу, який буде підключатися в додаток.
Докладніше про це Ви можете прочитати у попередній статті з використання QTranslator .
Найважливішим моментом для роботи з перекладами в QML є те, що потрібно підключити всі файли QML як вихідні дані, як звичайні C++ файли. Але з позначкою, що лише для використання lupdate_only.
- lupdate_only {
- SOURCES += main.qml
- }
Нижче повний листинг .pro файл проекту.
- TEMPLATE = app
- QT += qml quick widgets
- CONFIG += c++11
- SOURCES += main.cpp \
- qmltranslator.cpp
- # Для того, чтобы создать файл переводов со строками из ресурсов qml
- # понадобится включить файл qml в качестве обычных исходников в pro файле
- # но только для использования утилиты lupdate, чтобы она могла узнать,
- # какие строки нуждаются в переводе
- lupdate_only {
- SOURCES += main.qml
- }
- RESOURCES += qml.qrc \
- translations.qrc
- # Additional import path used to resolve QML modules in Qt Creator's code model
- QML_IMPORT_PATH =
- # Default rules for deployment.
- include(deployment.pri)
- # Добавляем файл переводов,
- # который является по сути файлом "исходных кодов" для нашего перевода
- TRANSLATIONS += QmlLanguage_ru.ts
- HEADERS += \
- qmltranslator.h
main.cpp
Оскільки підключення файлів перекладів здійснюється в C++ шарі, то потрібно зареєструвати об'єкт класу перекладів у контексті QML. з якими ми могли б працювати через QML.*
- #include <QApplication>
- #include <QQmlApplicationEngine>
- #include <QtQml>
- #include "qmltranslator.h"
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- // Создаём объект для работы с переводами ...
- QmlTranslator qmlTranslator;
- QQmlApplicationEngine engine;
- // и регистрируем его в качестве контекста в Qml слое
- engine.rootContext()->setContextProperty("qmlTranslator", &qmlTranslator);
- engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
- return app.exec();
- }
qmltranslator.h
У класі є метод встановлення перекладу, в який передається префікс мови перекладу. А з даного методу буде випускатися сигнал про зміну перекладу, щоб була можливість перевести весь інтерфейс з новим перекладом.
Метод установки перекладу необхідно помітити макросом Q_INVOKABLE, щоб була можливість використовувати його в шарі *QML.
- #ifndef QMLTRANSLATOR_H
- #define QMLTRANSLATOR_H
- #include <QObject>
- #include <QTranslator>
- class QmlTranslator : public QObject
- {
- Q_OBJECT
- public:
- explicit QmlTranslator(QObject *parent = 0);
- signals:
- // Сигнал об изменении текущего языка для изменения перевода интерфейса
- void languageChanged();
- public:
- // Метод установки перевода, который будет доступен в QML
- Q_INVOKABLE void setTranslation(QString translation);
- private:
- QTranslator m_translator;
- };
- #endif // QMLTRANSLATOR_H
qmltranslator.cpp
- #include "qmltranslator.h"
- #include <QApplication>
- QmlTranslator::QmlTranslator(QObject *parent) : QObject(parent)
- {
- }
- void QmlTranslator::setTranslation(QString translation)
- {
- m_translator.load(":/QmlLanguage_" + translation, "."); // Загружаем перевод
- qApp->installTranslator(&m_translator); // Устанавливаем его в приложение
- emit languageChanged(); // Сигнализируем об изменении текущего перевода
- }
main.qml
Інтерфейс програми буде виглядати так:
Логіка програми наступна: при зміні мови в комбобоксі змінюватиметься мова програми.
Оскільки ми зареєстрували qmlTranslator у контексті QML шару, то в обробнику зміни тексту в комбобоксі будемо викликати метод зміни мови в об'єкті qmlTranslator. А щоб відстежувати сигнал зміни мови, необхідно за допомогою типу Connections підключити до цього сигналу та написати обробник, в якому буде викликатися функція retranslateUi(). У функції retranslateUi() винесені всі текстові властивості всіх об'єктів, які необхідно передати. Зроблено це для спрощення логіки та зменшення надлишкового коду.
- import QtQuick 2.6
- import QtQuick.Controls 1.5
- ApplicationWindow {
- id: applicationWindow
- visible: true
- width: 640
- height: 480
- Label {
- id: helloLabel
- height: 50
- anchors {
- top: parent.top
- left: parent.left
- right: parent.horizontalCenter
- margins: 10
- }
- }
- ComboBox {
- id: comboBox
- anchors {
- top: parent.top
- left: parent.horizontalCenter
- right: parent.right
- margins: 10
- }
- model: ["ru_RU", "en_US"]
- // При изменении текста, инициализируем установку перевода через С++ слой
- onCurrentTextChanged: {
- qmlTranslator.setTranslation(comboBox.currentText)
- }
- }
- Label {
- id: labelText
- wrapMode: Text.Wrap
- anchors {
- top: helloLabel.bottom
- left: parent.left
- right: parent.right
- margins: 10
- }
- }
- // Подключаемся к объекту переводчика
- Connections {
- target: qmlTranslator // был зарегистрирован в main.cpp
- onLanguageChanged: { // при получении сигнала изменения языка
- retranslateUi() // инициализируем перевод интерфейса
- }
- }
- // Функция перевода интерфейса
- function retranslateUi() {
- applicationWindow.title = qsTr("Hello World")
- helloLabel.text = qsTr("Hello World")
- labelText.text = qsTr("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.")
- }
- // Запускаем перевод приложения, когда окно приложения было создано
- Component.onCompleted: {
- retranslateUi();
- }
- }
Підсумок
У цілому нині динамічний переклад програми на Qt/QML мало чим відрізняється від перекладу програми з використанням лише Qt/C++. Ключовим моментом є те, що потрібно правильно підключити сигнали та слоти та правильно викликати методи для ініціалізації перекладу.
Завантажити QML програму з динамічним перекладом
Всё отлично :)
Только у меня вопрос: а как вместо ru_RU и en_US написать в ComboBox'e Russian и English чтобы сохранить функцию смены языка :)
UPD Разобрался
В comboBox model я пишу так:
И перед отправкой кода ru_RU или en_US в С++ делаю проверку
В Qt 5.10 была добавлена новая функция по переводу qml файлов. Теперь не нужно писать класс оболочку, достаточно вызвать функцию engine.retranslate(); и все обновится само.
Это хорошая новость!!!!