Runtime translation / i18n - QML C++ engine
-
Hi there,
I'm new in here, and it's about a couple of months I'm using Qt.
What I'm doing now is playing with dynamic translation in QML.
I started with those references:
How to do dynamic translation in QML
Dynamic translations for mobile apps at runtime?The instructions worked, in fact I'm able to change language at runtime.
But...it doesn't apply to items defined in external qml files and included into the main qml.
I guess I'm missing something related to C++ and QML linking.Here the code I'm using:
translationtest.h
#ifndef TRANSLATIONTEST_H #define TRANSLATIONTEST_H #include <QObject> #include <QTranslator> class TranslationTest : public QObject { Q_OBJECT Q_PROPERTY(QString emptyString READ getEmptyString NOTIFY languageChanged) public: explicit TranslationTest(QObject *parent = 0); QString getEmptyString(); Q_INVOKABLE void selectLanguage(QString language); QTranslator * translator; signals: void languageChanged(); private: }; #endif // TRANSLATIONTEST_H
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QQmlComponent> #include "translationtest.h" TranslationTest::TranslationTest(QObject *parent) : QObject(parent) { translator = new QTranslator(this); translator->load(QLocale(QLocale::English), QLatin1String("provaTranslate"), QLatin1String("_"), QLatin1String(":/translations")); } QString TranslationTest::getEmptyString() { return ""; } void TranslationTest::selectLanguage(QString language) { if(language == QString("it")) { qApp->removeTranslator(translator); translator->load(QLocale(QLocale::Italian), QLatin1String("provaTranslate"), QLatin1String("_"), QLatin1String(":/translations")); qApp->installTranslator(translator); } if(language == QString("de")) { qApp->removeTranslator(translator); translator->load(QLocale(QLocale::German), QLatin1String("provaTranslate"), QLatin1String("_"), QLatin1String(":/translations")); qApp->installTranslator(translator); } if(language == QString("en")) { qApp->removeTranslator(translator); translator->load(QLocale(QLocale::English), QLatin1String("provaTranslate"), QLatin1String("_"), QLatin1String(":/translations")); qApp->installTranslator(translator); } emit languageChanged(); } int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); /*! Dynamic translation */ TranslationTest translator; app.installTranslator(translator.translator); QQmlApplicationEngine engine; QQmlComponent component(&engine, QUrl(QLatin1String("qrc:/main.qml"))); engine.rootContext()->setContextProperty("rootItem",&translator); component.create(); return app.exec(); }
So, with those files "main.qml" is aware of "rootItem" context, which will in fact be linked to the TranslatorTest class.
Now, that's my main.qml
import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") + rootItem.emptyString SwipeView { id: swipeView anchors.fill: parent currentIndex: tabBar.currentIndex Page1 { } Page { Label { text: qsTr("Second page") + rootItem.emptyString anchors.centerIn: parent } } } footer: TabBar { id: tabBar currentIndex: swipeView.currentIndex TabButton { text: qsTr("First") + rootItem.emptyString } TabButton { text: qsTr("Second") + rootItem.emptyString } } }
The text contained here is successfully changing while choosing another language.
But the "Page1" item, extenally defined, is not showing the same behaviour. It is simply not changing at all.
Here my Page1.qml file (extending "Page1Form.ui.qml" functionalities)
import QtQuick 2.7 Page1Form { button1 { text: qsTr("Press Me") + rootItem.emptyString onClicked: console.log("Button Pressed. Entered text: " + textField1.text) } textField1.placeholderText: qsTr("Text Field") + rootItem.emptyString label { text: "Test: " + Number(23.7).toLocaleString(Qt.locale()) + " °C" + rootItem.emptyString } italiano.onClicked: { rootItem.selectLanguage("it") } deutsch.onClicked: { rootItem.selectLanguage("de") } english.onClicked: { rootItem.selectLanguage("en") } }
So the C++ "selectLanguage" function is actually called even from "Page1.qml", while it's not receiving any updates given by "emptyString". Everything of "Page1" will be displayed as it's written into the code, even if the first language loaded into the constructor is e.g. "Italian".
Do you know how to fix this?
Thank you very much, even just for reading the whole story!
-
In the end everything was fine with the example above.
I just had to update and release my translation files, because in the meantime I changed the name of a .qml file, and the filename is directly linked into the .ts files created by linguist and used by Qt.
I feel a bit ashamed but yes, it was really trivial and kinda stupid :)