- 1. Структура проекта
- 2. QmlLanguage.pro
- 3. main.cpp
- 4. qmltranslator.h
- 5. qmltranslator.cpp
- 6. main.qml
- 7. Итог
- 8. Видеоурок
После того, как мы ознакомились с переводами интерфейса приложения на 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. В данном случае мы напишем класс QmlTranslator, который будет обёрткой над QTranslator, поскольку тот класс не имеет методов, с которыми мы могли бы работать через 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(); и все обновится само.
Это хорошая новость!!!!