Initial translation language with QTranslator
-
I have been spending several hours trying to understand how translations work in Qt and how to set them up properly.
However, I am stuck on setting the initial translation language of a QML Qt Quick application using QTranslator. The weird thing is that the resource with the translations is created successfully and even the terminal tells me that the initial translation language has been loaded (finnish in my project). But the project is still using the raw translation string values that I used to code the application, which is English.
QTranslator translator; if (translator.load(":/qt/qml/Translations/i18n/qml_fi.qm")) { app.installTranslator(&translator); qDebug() << "Finnish translation loaded at startup"; } else { qWarning() << "Failed to load Finnish translation at startup"; }
If I try to change the language by pressing one of the bottom buttons which change the language in QML by updating Qt.uiLanguage, the application then changes language. Therefore, I know that my .qm translation files are not the issue. The problem seems to be that this initial translation language, for whatever reason, is getting ignored.
Here is my very simple sample project which derivates from the Translation tutorial provided by Qt Academy. If I had to say, I guess there is something wrong with either CMakeLists.txt or the main.cpp file, but they look good to me.
-
Interesting - looks correct. Where / how do you load the other languages?
Does https://doc.qt.io/qt-6/qtranslator.html#translate after translator.load() give some useful results?
The same goes for https://doc.qt.io/qt-6/qcoreapplication.html#translate
Make sure to pass the correct context when using those functions. -
Please show how you load them. Especially how long your QTranslator lives.
-
Hi @oserrabassa,
What is your operating system / user's locale set to?
QTranslator::load()
only makes the translations for that language available. The actual translations that will get used depend on the current locale. So, for example, say you loaded the translations for English, German and Italian, then: if the user's locale was set to Italian, they would get Italian, but if their locale was set to Spanish, they would get the default untranslated text (since no Spanish translation was loaded). That's slightly simplified, but you get the idea.To test your scenario under Linux, for example, you can do something like:
export LANG=fi_FI.UTF-8 export LC_ALL=fi_FI.UTF-8 ./your-app-here
Cheers.
-
Please show how you load them. Especially how long your QTranslator lives.
@Christian-Ehrlicher Here are probably the files which you want to check. If you are interested, there is a link to my project in the main post.
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(Translations_Section4 VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(APP_NAME "Translations") add_compile_definitions(APP_NAME="${APP_NAME}") find_package(Qt6 6.5 REQUIRED COMPONENTS Quick LinguistTools) qt_standard_project_setup(REQUIRES 6.5) qt_add_executable( ${PROJECT_NAME} "main.cpp" # "cpp/LanguageManager.cpp" "h/LanguageManager.h" ) target_include_directories( ${PROJECT_NAME} PRIVATE "h/" ) qt_add_qml_module( ${PROJECT_NAME} URI ${APP_NAME} VERSION 1.0 QML_FILES "Main.qml" ) set( TRANSLATION_SOURCE_FILES "ts/qml_en.ts" "ts/qml_fi.ts" "ts/qml_fr.ts" ) set( QT_MESSAGE_TRANSLATION_FILES_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qm" ) qt_add_lupdate( SOURCE_TARGETS ${PROJECT_NAME} TS_FILES ${TRANSLATION_SOURCE_FILES} ) qt_add_lrelease( TS_FILES ${TRANSLATION_SOURCE_FILES} QM_OUTPUT_DIRECTORY ${QT_MESSAGE_TRANSLATION_FILES_OUTPUT} QM_FILES_OUTPUT_VARIABLE QM_FILES ) message(STATUS ".qm files generated at: ${QM_FILES}") qt_add_resources( ${PROJECT_NAME} "translations" PREFIX "/qt/qml/${APP_NAME}/i18n" BASE ${QT_MESSAGE_TRANSLATION_FILES_OUTPUT} FILES ${QM_FILES} ) # 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( ${PROJECT_NAME} PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.${PROJECT_NAME} 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(${PROJECT_NAME} PRIVATE Qt6::Quick ) include(GNUInstallDirs) install( TARGETS ${PROJECT_NAME} BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QTranslator> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QTranslator translator; if (translator.load(":/qt/qml/Translations/i18n/qml_fi.qm")) { app.installTranslator(&translator); qDebug() << "Finnish translation loaded at startup"; } else { qWarning() << "Failed to load Finnish translation at startup"; } QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/qt/qml/Translations/Main.qml"))); return app.exec(); }
I tried declaring the QTranslator object outside the main() function and even make the variable static but it does not work.
-
Interesting - looks correct. Where / how do you load the other languages?
Does https://doc.qt.io/qt-6/qtranslator.html#translate after translator.load() give some useful results?
The same goes for https://doc.qt.io/qt-6/qcoreapplication.html#translate
Make sure to pass the correct context when using those functions. -
Hi @oserrabassa,
What is your operating system / user's locale set to?
QTranslator::load()
only makes the translations for that language available. The actual translations that will get used depend on the current locale. So, for example, say you loaded the translations for English, German and Italian, then: if the user's locale was set to Italian, they would get Italian, but if their locale was set to Spanish, they would get the default untranslated text (since no Spanish translation was loaded). That's slightly simplified, but you get the idea.To test your scenario under Linux, for example, you can do something like:
export LANG=fi_FI.UTF-8 export LC_ALL=fi_FI.UTF-8 ./your-app-here
Cheers.
@Paul-Colby Tried 2 different settings:
- Changed operating system's (Windows) locale = Application still launches with no initial translation
- Started application via terminal with the flags you mentioned = Application does indeed start with the specified language
- Interestingly enough, I can start the application in any language which has translations. All the QTranslator code seems to be doing nothing? Unfortunately, this is not a solution to my issue because the user is not going to be able to launch the application with these flags
- Only the LANG flag seems to matter in my case. The flag LC_ALL does not seem to impact the application in any form.
I played with these settings a little bit and I found out that the below setup works. Is this reliable?
main.cpp#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QLocale> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QLocale::setDefault(QLocale::French); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/qt/qml/Translations/Main.qml"))); return app.exec(); }
As you can see, I am simply changing the locale. This should be functional because I could just change the locale to an available language or the last language that the user set in the application.
What I really do not understand, is how was the Qt Academy tutorial be able to change the language with the QTranslator object while I cannot and I am using the same application. Maybe it is something they changed in newer Qt Framework releases. Although, the approach that I tried is definitely more user-friendly and requires less code.
-
Interesting - looks correct. Where / how do you load the other languages?
Does https://doc.qt.io/qt-6/qtranslator.html#translate after translator.load() give some useful results?
The same goes for https://doc.qt.io/qt-6/qcoreapplication.html#translate
Make sure to pass the correct context when using those functions.@Christian-Ehrlicher
Where / how do you load the other languages?
I only have those 3 languages in the project: English, Finnish, French
All are created within CMakeLists.txt under the same resource file.
The QTranslator object was just to set a default start/launch/initial language.translate()
Translations seems to be working but UI is not getting translated
The "Translations" string refers to the window's title.
-
Not sure if this is the issue, but worth trying... I see you're using the non-Locale overload of
QTranslator::load()
, which specifically says:Usually, it is better to use the
QTranslator::load(const QLocale &, const QString &, const QString &, const QString &, const QString &)
function instead, because it usesQLocale::uiLanguages()
and not simply the locale name, which refers to the formatting of dates and numbers and not necessarily the UI language.So try using the locale-overload: https://doc.qt.io/qt-6/qtranslator.html#load-1
For example, here's how I do it in one of my projects:
const QLocale locale; QTranslator appTranslator; if (appTranslator.load(locale, u"cli"_s, u"/"_s, u":/i18n"_s)) { QCoreApplication::installTranslator(&appTranslator); } ... qCDebug(lc).noquote() << "Locale:" << locale << locale.uiLanguages(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) // QTranslator::filePath() added in Qt 5.15. qCDebug(lc).noquote() << "App translations:" << (appTranslator.filePath().isEmpty() ? u"<none>"_s : appTranslator.filePath()); #else qCDebug(lc).noquote() << "App translations:" << (!appTranslator.isEmpty()); #endif
So try something like:
const QLocale locale; qDebug().noquote() << "Locale:" << locale << locale.uiLanguages(); QTranslator translator; if (translator.load(locale, ":/qt/....")) { .... }
You might also try to calling
QmlEngine::retranslate()
after theQmlEngine
construction? -
Not sure why I am having so many problems in something which looks very straightforward.
Nothing really seems to work.
The only time that I have been successful in the User Interface displaying a non-default translation language was with QLocale::setDefault. I believe that I am just going to go and try with this approach. My overall language detection logic in main.cpp is going to be something like:
- 0. Check if user has already explicitly set an application language
- If that is the case, skip to step 3
- This information is going to be stored in an external configuration file outside the application.
- 1. Detect user's default locale with QLocale::QLocale()
- 2. Check if user's default locale has an available translation in the application
- If they do not, either do nothing else, or explicitly change the current locale to match with the default translation language (for the sake of readability)
- I need to think exactly how I am going to match the results but QLocale has both QLocale::language() and QLocale::name() and that should be more than enough.
- 3. Change default locale to expected locale using QLocale::setDefault
I am not planning in adding my languages to my application. So, I am not really worried about having a big switch statement.
- 0. Check if user has already explicitly set an application language
-