Adding multi-language option to a Qt app with hard-coded text - c++

I'm a beginner in Qt. I have an app designed using Qt which has multiple windows with each consisting of several labels with hard coded text. What would be the easiest way to add multi language support for this app? Which built in Qt objects/functions I should use?
My current idea is to maybe create a separate xml file including the text for all labels for a language. Then once the user selects a language icon from the menu, load the relevant xml file. But I have no idea how to do this. Any help would be highly appreciated!
UPDATE:
I have tried to implement the example given here. But it throws the following error and I can't fix it. 'class Ui::MainWindow' has no member named 'menuLanguage'
QActionGroup* langGroup = new QActionGroup(ui->menuLanguage);

Try Qt Linguist:
I made you a simple example:
.pro
TRANSLATIONS += translation_fa.ts
.h
#include <QTranslator>
QTranslator translator;
.cpp
if(translator.load("E:/Qt/Linguist/linguist/translation_fa.qm"))
qDebug()<<"successfully load qm file.";
else
qDebug()<<"problem in load qm file.";
// change language to second language
qApp->installTranslator(&translator);
// change language to default language
qApp->removeTranslator(&translator);
Don't forget to use Qt Linguist Tools.
This is a sample project for your question on github download here.

Qt has translation support. Look into Qt Linguist
Basically, you mark all you hard coded texts with a call to QObject::tr, e.g.
lbl->setText(tr("My text to translate"));
Qt Linguist parses all source files and UI forms for such calls (using lupdate.exe) and builds a ts file. With the Qt Linguist GUI application, you can translate them. With lrelease you create a qm file that will be loaded at runtime, and automatically translate the texts

Qt has built in functions for managing multiple languages:
see: https://wiki.qt.io/How_to_create_a_multi_language_application
Research lupdate lrelease and linguist

Related

How to use QML_ELEMENT with cmake

The doc shows I can use QML_ELEMENT macro to create QML types from C++ by adding some variables in qmake's .pro file. But I'm using cmake
Update (Qt 6.2+)
As of Qt 6.2, qt_add_qml_module is a single command for building qml modules that should take care of virtually everything, replacing amongst others the old qt6_qml_type_registration command.
Old answer (Qt 6.0/6.1)
Now that Qt 6.0 is out this is supported, albeit poorly documented. What you need now is:
set_target_properties(foo PROPERTIES
QT_QML_MODULE_VERSION 1.0
QT_QML_MODULE_URI Foo
)
qt6_qml_type_registration(foo)
you can then do in qml:
import Foo
and you'll have access to types that have QML_ELEMENT and friends. Notes:
Two files are created in the build output folder, <project>_qmltyperegistrations.cpp and <project>.qmltypes, if your imports are failing you can look at those to see which types are missing. I found that I needed to do full recompiles sometimes after adding/removing registered types.
Qt examples have been migrated to cmake, so take a look at e.g. Examples/Qt-6.0.0/quick/tableview/gameoflife to see it in action
There are now pro2cmake.py and run_pro2cmake.py files in the Qt sources at Qt/6.0.0/Src/qtbase/util/cmake. They are mentioned on this Readme page, you can find them here, haven't tried it myself.
Edit (Qt 6.x)
This answer was originally posted for Qt 5.15. Now that Qt 6 is available, and if you are using Qt 6, refer to the answer from #Adversus.
Original answer (Qt 5.x)
From what I can see, CONFIG += qmltypes, which is required to use QML_ELEMENT, is not yet supported in CMake by looking at the documentation, even for the master branch.
And the efforts to provide a python .pro to cmake converter are for Qt6, not merged, and not functional as far as I can tell, by testing them from util on the wip/cmake branch (the CMakeLists.txt didn't have relevant information).
You can see that the actual conversion script does test for qmltypes presence in CONFIG, but it doesn't seem to map to anything usable for CMake.
Solution
Instead of using QML_ELEMENT and CONFIG += qmltypes, which is brand new from Qt 5.15 (latest when writing this), and not supported at this time with CMake, use the good old qmlRegisterType from C++:
#include "YouCustomCppClass.h"
int main(int argc, char** argv) {
// Let you import it with "import ModuleName 1.0" on the QML side
qmlRegisterType<YouCustomCppClass>("ModuleName", 1, 0, "YourQmlComponent");
//Create your QML view or engine
}
This won't require anything specific on the project file side, as long as your code/plugin executes qmlRegisterType statement.
You can refer to Qt's documentation, same page as yours, but for Qt 5.14 instead of latest, which describes exactly that: Writting QML extensions for C++ | Qt 5.14

Make a Qt/C++ program show its file types as known on Windows

Using Qt 5.9 I codded a spreadsheet program and then created an installer for it by Qt Installer Framework (QtIFW2.0.1). Then I sent the program to many of my friends. They installed the app on their Windows machine and now using it, but they have all have a common problem:
when they save files of the app, those files are shown as "unknown" files on Desktop.
The problem is only with the shape and appearance of the stored files not their functionality, and they are opened by the app if double clicked.
The question is, what changes in the code is needed to have the program make its files' shape/appearance shown known?
For example, we offer the code a specific shape using an image file or like that, to be mapped on the stored files and that way they are shown known.
This has actually nothing to do with Qt or C++ itself. You just need to register your file extension in Windows shell, so it can be understood by other Windows components/shells.
Here is general information about File Types and File Associations under windows.
You need to make some Windows Registry entries which look like this:
example.reg:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\myfirm.myapp.v1\shell\open\command]
#="c:\path\to\your\app.exe \"%1\""
[HKEY_CURRENT_USER\Software\Classes\.myextension]
#="myfirm.myapp.v1"
Here you can read how it works in general
change myfirm.myapp.v1, .myextension and path to your .exe to your prefered names.
Now Windows will know what the files with extension .myextension should be opened by your app. And if you double click on this files your app will be run with path to file as an argument. You can get it in your main() function
To set icon for your extension add Registry entry in Software\\Classes\\.myextension\\DefaultIcon and set it default value to the full path to your app, so windows can get an icon for extension from your .exe app file.
You can also do it at runtime directly in your app:
QSettings s("HKEY_CURRENT_USER\\SOFTWARE\\CLASSES", QSettings::NativeFormat);
QString path = QDir::toNativeSeparators(qApp->applicationFilePath());
s.setValue(".myextension/DefaultIcon/.", path);
s.setValue(".myextension/.","myfirm.myapp.v1");
s.setValue("myfirm.myapp.v1/shell/open/command/.", QStringLiteral("\"%1\"").arg(path) + " \"%1\"");
EDIT: One more, to do it with Qt Installer look at the answers here

How to use translation in Qt?

I'm trying to use Qt's tr() function for translation.
In .pro file I have:
TRANSLATIONS += languages/myapp_en.ts \
languages/myapp_es.ts
and in main.cpp:
QTranslator translator;
translator.load("myapp_es"); //espanol
app.installTranslator(&translator);
I run lupdate and the files myapp_en.ts, myapp_es.ts are generated.
I edit the file myapp_es.ts, for example:
<context>
<name>Example</name>
<message>
<location filename="../example.cpp" line="24"/>
<source>Good night</source>
<translation>Buenas noches</translation> <!-- THIS IS MY EDIT -->
</message>
</context>
Then I run lrelease so the files myapp_en.qm, myapp_es.qm are generated.
Then I use tr() in code like this:
button->setText(tr("Good night"));
inside the constructor of a Q_OBJECT class.
But the text is still showing in English ("Good night"), and not in Spanish.
What am I doing wrong?
Edit:
Putting the *.qm files in the correct directory solved the problem. Just had to make sure it's in the Release directory and not the Debug.
You need to include the extension .qm and correct path when calling translator.load:
QTranslator translator;
translator.load("languages/myapp_es.qm"); //espanol
app.installTranslator(&translator);
after installing translator you have to call retranslate of ui generated class if applied or call tr again
From the other answers I can see that you're now getting true for load, so it's finding the translation file. What it could then be is that you're installing the translation after the system has already initialised the UI, so you can do one of two things:
Install the translator before you create your UI, for me it would go:
translator.load(someTranslation)
a.installTranslator(&translator)
MainWindow w;
Install the translator after you create the UI, which if you're providing multiple language support is most likely where you'll want it. Qt provides a retranslateUi() function, which when called will update the user interface. There's a question here which shows this in more depth: How to translate language in Qt on the fly. There's a bit more code required for handling the language change event, but it does allow for dynamic language updates.

How do I create multipul Forms / .ui in qt?

I'm new to qt so this may be a basic question. I want to create multipul ui pages but I don't really know how to do it. I've gone Add New -> C++ Class -> include QWidget. Although this creates new source and header files, it does not create and additional .ui file. I've tried building and running QMake but that hasn't helped. I've also tried adding temperature.ui to the forms section of the .pro files but that just gives me the
":-1: error: No rule to make target 'temperature.ui', needed by 'ui_temperature.h'. Stop." error. Any suggestions? Many thanks
One thing is a C++ Class and another thing is a Qt class. The first one has a *.cpp and a *.h and the second one has, in addition, a *.ui file which contains the ui made with Qt designer.
So that, you need to Add a Designer Form Class instead of a C++ class

Opening files from Finder with a Qt-based application?

Apparently, for Cocoa applications, you're supposed to implement [[NSApp delegate] application:openFile:] or something like that to allow your application to open files double clicked in Finder.
How do you achieve this functionality using Qt, as the name of the file to be opened is not passed on the command line?
QFileOpenEvent (Qt4/Qt5) should do the trick.
Also see https://doc.qt.io/archives/qq/qq18-macfeatures.html