Після того, як ми ознайомилися з перекладами інтерфейсу програми на 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(); и все обновится само.
Это хорошая новость!!!!