- 1. Project Structure
- 2. QmlLanguage.pro
- 3. main.cpp
- 4. qmltranslator.h
- 5. qmltranslator.cpp
- 6. main.qml
- 7. Result
- 8. Video
Once we have learn how to make the translation of the application interface at Qt/C++ , it is time to research possibilities of dynamic translation application interface which is written in QML.
In developing the QML to have a couple of moments that need to be taken into account, as opposed to the standard application on QWidgets, namely:
- Requires additional configuration .pro file;
- Process of the loading of translation for your language is carried in C ++ layer;
- Reinitialize the translation interface implemented in QML layer using qsTr() function;
- After loading the translation, you need to send a signal from the C ++ layer in QML layer to re-translate the application interface.
Project Structure
Create a project, which will include the following files:
- QmlLanguage.pro - profile of project;
- deployment.pri - configuration file of deployment, created by default;
- main.cpp - source file of file with main function;
- qmltranslator.h - header file of class for translation loading;
- qmltranslator.cpp - sourcefile of class for translation loading;
- main.qml - main file of QML layer.
QmlLanguage.pro
Creating a translation file will be similar to how it is done when creating a translation for Qt / C ++ applications. That is, you need to connect the translation file. We will work with this file useing Qt Linguist:
# Add the translation file # Which is in fact the file "source code" for our translation TRANSLATIONS += QmlLanguage_ru.ts
Then run the utility lupdate, to create the translation file, edit it in the Qt Linguist, and launch lrelease create a binary translation file, which will be connected to the application.
Read more about this in a previous article on the use of QTranslator .
The most important thing to work with translations in QML is what you need to connect all the QML file as the source, as ordinary C ++ files. But with a mark that only use lupdate_only.
lupdate_only { SOURCES += main.qml }
Below is the complete listing of the project .pro file.
TEMPLATE = app QT += qml quick widgets CONFIG += c++11 SOURCES += main.cpp \ qmltranslator.cpp # To create a translation file with strings of resources qml<br># need to include qml file as normal source in the .pro file<br># But only for use lupdate utility, so that she could learn,<br># Which strings need to be translated 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) # Add the translation file # Which is in fact the file "source code" for our translation TRANSLATIONS += QmlLanguage_ru.ts HEADERS += \ qmltranslator.h
main.cpp
Because of connection of the translation file is carried in C ++ layer, you will need to register the class object in QML context. In this case, we will write QmlTranslator class that is a wrapper over QTranslator, because the class has no methods with which we could work through QML.
#include <QApplication> #include <QQmlApplicationEngine> #include <QtQml> #include "qmltranslator.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); // Create an object to work with translations ... QmlTranslator qmlTranslator; QQmlApplicationEngine engine; // and register it as a context in Qml layer engine.rootContext()->setContextProperty("qmlTranslator", &qmlTranslator); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
qmltranslator.h
In the class there is method for the translation loading, in which we will pass the target language prefix. And from this method will emit a signal of the translation change to be able to re-translate the interface with a new translation.
Translation installation method you have to mark macro Q_INVOKABLE, to be able to use it in QML layer.
#ifndef QMLTRANSLATOR_H #define QMLTRANSLATOR_H #include <QObject> #include <QTranslator> class QmlTranslator : public QObject { Q_OBJECT public: explicit QmlTranslator(QObject *parent = 0); signals: // The signal of change the current language to change the interface translation void languageChanged(); public: // Translation installation method, which will be available in 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, "."); // load translation qApp->installTranslator(&m_translator); // Set it to the application emit languageChanged(); // Signaling a change in the current translation }
main.qml
Application interface will appear as follows:
The application logic is as follows: when you change the language in the combo box will change the language of the application.
Since we registered qmlTranslator in the context of QML layer, the change in the output text in the combo box will cause a change of language in the object method qmlTranslator. And in order to keep track of changes in the language signal, you must use type Connections to connect to this signal and write a handler which will be called retranslateUi(). The function retranslateUi() rendered all the text properties of all the objects that need to be subjected to transfer. This is to simplify the logic and reduce redundancy.
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"] // If you change the text, initialize the translation unit via C++ Layer onCurrentTextChanged: { qmlTranslator.setTranslation(comboBox.currentText) } } Label { id: labelText wrapMode: Text.Wrap anchors { top: helloLabel.bottom left: parent.left right: parent.right margins: 10 } } // Connect to an interpreter object Connections { target: qmlTranslator // was registered in main.cpp onLanguageChanged: { // upon receipt of the signal to change the language retranslateUi() // initialize interface translation } } // interface translation function 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.") } // Start translating the application window when the application was created Component.onCompleted: { retranslateUi(); } }
Result
In general, the dynamic translation application on Qt/QML is not much different from the translation application using only Qt/C ++. The key point is that you need to properly connect the signals and slots, and the right to call methods for the transfer initialization.
Download QML application with dynamic translation
Всё отлично :)
Только у меня вопрос: а как вместо ru_RU и en_US написать в ComboBox'e Russian и English чтобы сохранить функцию смены языка :)
UPD Разобрался
В comboBox model я пишу так:
И перед отправкой кода ru_RU или en_US в С++ делаю проверку
В Qt 5.10 была добавлена новая функция по переводу qml файлов. Теперь не нужно писать класс оболочку, достаточно вызвать функцию engine.retranslate(); и все обновится само.
Это хорошая новость!!!!