I have been trying to create a minimal multilingual app using Qt Quick. Since I am new to Qt I tried to follow the implementation steps in this blog/tutorial post. However, I cannot get the qsTr() strings to translate when I change the UI language. How can I make all strings wrapped in qsTr() translate when the UI language is changed?
The application does build and run, but the strings are not translated when the button is clicked.
The only issues noted during the build process are the following warnings:
[cmake] Running C:\Qt\Tools\CMake_64\bin\cmake.exe -S C:/BasicMultilingualApp -B C:/BasicMultilingualApp/build/Desktop_Qt_6_8_1_MinGW_64_bit-Debug in C:\BasicMultilingualApp\build\Desktop_Qt_6_8_1_MinGW_64_bit-Debug.
[cmake] -- Could NOT find WrapVulkanHeaders (missing: Vulkan_INCLUDE_DIR)
[cmake] -- Could NOT find WrapVulkanHeaders (missing: Vulkan_INCLUDE_DIR)
and
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:348: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:847: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:861: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:879: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:893: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:907: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:922: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:936: Ignoring definition of undeclared qualified class
C:/Qt/6.8.1/mingw_64/include/QtQml/qqmlprivate.h:950: Ignoring definition of undeclared qualified class
Updating '../../i18n/qml_de_DE.ts'...
Found 2 source text(s) (0 new and 2 already existing)
Updating '.lupdate/qml_en.ts'...
Found 2 source text(s) (2 new and 0 already existing)
System details:
cmake.exe --build C:/Users/<MyName>/Desktop/QT_Projects/multilingual_demo/build/Desktop_Qt_6_8_1_MinGW_64_bit-Debug --target all multilingual_demo_lrelease multilingual_demo_lupdate
Below I have included the major code components Main.qml and main.cpp along with CMakeLists.txt and the .ts translation file so that my implementation can be easily replicated.
Main.qml
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: "Basic Multilingual App" // We choose the app title to be language indifferent
Component.onCompleted: Qt.uiLanguage = "en" // Set the UI language to English (so that we all start in the same place)
Column {
anchors.centerIn: parent
spacing: 10
Text {
id: stringToTranslate
//: Example string to translate
text: qsTr("This string must be translated on button click")
}
Button {
id: translateText
//: Clicking this button translates the text fields
text: qsTr("Translate text")
onClicked: {
Qt.uiLanguage = Qt.uiLanguage === "en" ? "de" : "en" // If UI is English translate to German. Else translate to English
console.log(Qt.uiLanguage) // Print the UI language to console so we can monitor its changes
}
}
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.loadFromModule("BasicMultilingualApp", "Main");
return app.exec();
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(BasicMultilingualApp VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Quick LinguistTools)
qt_standard_project_setup(REQUIRES 6.5 I18N_TRANSLATED_LANGUAGES de_DE)
qt_add_executable(appBasicMultilingualApp
main.cpp
)
qt_add_qml_module(appBasicMultilingualApp
URI BasicMultilingualApp
VERSION 1.0
QML_FILES
Main.qml
)
qt_add_translations(appBasicMultilingualApp
TS_FILE_BASE qml
TS_FILE_DIR i18n
RESOURCE_PREFIX qt/qml/BasicMultilingualApp/i18n
LRELEASE_OPTIONS -idbased
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(appBasicMultilingualApp PROPERTIES
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appBasicMultilingualApp
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
target_link_libraries(appBasicMultilingualApp
PRIVATE Qt6::Quick
)
include(GNUInstallDirs)
install(TARGETS appBasicMultilingualApp
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
qml_de_DE.ts (German translation file, located in the folder 'i18n'
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>Main</name>
<message>
<location filename="../Main.qml" line="19"/>
<source>This string must be translated on button click</source>
<extracomment>Example string to translate</extracomment>
<translation>Diese Zeichenfolge muss beim Klicken auf die Schaltfläche übersetzt werden</translation>
</message>
<message>
<location filename="../Main.qml" line="25"/>
<source>Translate text</source>
<extracomment>Clicking this button translates the text fields</extracomment>
<translation>Text übersetzen</translation>
</message>
</context>
</TS>
Disclaimer: This answer may not be entirely accurate, as I am not fully up to date with both CMake and the Linguist system in Qt 6. What I am about to show you is based on my understanding of the Linguist system in Qt 5, with an attempt to extrapolate it to Qt 6 to provide you with a starting point.
C:\Qt\Apps\BasicMultilingualApp>C:\Qt\Qt6.8.2\6.8.2\mingw_64\bin\lupdate . -ts myapp.ts -ts myapp_de.ts
Scanning directory '.'...
Updating 'myapp.ts'...
Found 3 source text(s) (0 new and 3 already existing)
Updating 'myapp_de.ts'...
Found 3 source text(s) (0 new and 3 already existing)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>Main</name>
<message>
<location filename="build/Desktop_Qt_6_8_2_MinGW_64_bit-Debug/BasicMultilingualApp/Main.qml" line="8"/>
<location filename="Main.qml" line="8"/>
<source>Basic Multilingual App</source>
<translation>Grundlegende mehrsprachige App</translation>
</message>
<message>
<location filename="build/Desktop_Qt_6_8_2_MinGW_64_bit-Debug/BasicMultilingualApp/Main.qml" line="19"/>
<location filename="Main.qml" line="19"/>
<source>This string must be translated on button click</source>
<extracomment>Example string to translate</extracomment>
<translation>Diese Zeichenfolge muss beim Klicken auf die Schaltfläche übersetzt werden.</translation>
</message>
<message>
<location filename="build/Desktop_Qt_6_8_2_MinGW_64_bit-Debug/BasicMultilingualApp/Main.qml" line="25"/>
<location filename="Main.qml" line="25"/>
<source>Translate text</source>
<extracomment>Clicking this button translates the text fields</extracomment>
<translation>Text übersetzen</translation>
</message>
</context>
</TS>
C:\Qt\Apps\BasicMultilingualApp>C:\Qt\Qt6.8.2\6.8.2\mingw_64\bin\lrelease myapp.ts myapp_de.ts
Updating 'myapp.qm'...
Generated 0 translation(s) (0 finished and 0 unfinished)
Ignored 3 untranslated source text(s)
Updating 'myapp_de.qm'...
Generated 3 translation(s) (3 finished and 0 unfinished)
qt_add_resources(appBasicMultilingualApp "translations"
PREFIX "/"
FILES myapp.qm myapp_de.qm
)
// translatehelper.h
#ifndef TRANSLATEHELPER_H
#define TRANSLATEHELPER_H
#include <QObject>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QTranslator>
#include <QDebug>
class TranslateHelper : public QObject
{
Q_OBJECT
public:
QGuiApplication& m_app;
QQmlApplicationEngine& m_engine;
TranslateHelper(QGuiApplication& app, QQmlApplicationEngine& engine) :
m_app(app),
m_engine(engine)
{
}
Q_INVOKABLE void setLanguage(const QString& name)
{
QLocale locale(name);
QLocale::setDefault(locale);
QTranslator translator;
bool ok = translator.load(":/myapp_" + locale.name());
qDebug() << Q_FUNC_INFO << "translator.load: " << ok;
m_app.installTranslator(&translator);
m_engine.retranslate();
}
};
#endif // TRANSLATEHELPER_H
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "translatehelper.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
TranslateHelper translateHelper(app, engine);
engine.rootContext()->setContextProperty("translateHelper", &translateHelper);
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.loadFromModule("BasicMultilingualApp", "Main");
return app.exec();
}
Main.qml
to call TranslateHelperimport QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("Basic Multilingual App") // We choose the app title to be language indifferent
Component.onCompleted: Qt.uiLanguage = "en" // Set the UI language to English (so that we all start in the same place)
Column {
anchors.centerIn: parent
spacing: 10
Text {
id: stringToTranslate
//: Example string to translate
text: qsTr("This string must be translated on button click")
}
Button {
id: translateText
//: Clicking this button translates the text fields
text: qsTr("Translate text")
onClicked: {
Qt.uiLanguage = Qt.uiLanguage === "en" ? "de" : "en" // If UI is English translate to German. Else translate to English
console.log(Qt.uiLanguage) // Print the UI language to console so we can monitor its changes
translateHelper.setLanguage(Qt.uiLanguage);
}
}
}
}
Here's a screen recording of it running:
Here's a GitHub link: https://github.com/stephenquan/QtBasicMultilingualApp