You have written a program in Qt and want to translate it into other languages to make it useful for people in other countries. This is not easy, but very simple. For this we need to do just three simple steps.
Source program
Suppose we have a simple program:
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
#include <QtGui> #include <QtCore> int main( int argc, char *argv[]) { QApplication app(argc, argv); QLabel label( "Hello, World!" ); label.show(); return app.exec(); } * This source code was highlighted with Source Code Highlighter .
All she does is create a window that says “Hello, World!”. We will make for her a translation into Russian.
')
Step 1. Specify all lines for which translation is required.
All strings that the user sees should be processed by QObject :: tr () or QcoreApplication :: translate () functions.
All Qt classes inherited from QObject have a tr () member function. Since we are working with a string in a global function that does not belong to any class, we use the translate () function, which allows us to specify the translation context, that is, the class to which it belongs (in this case, QLabel).
- #include <QtGui>
- #include <QtCore>
- int main ( int argc, char * argv []) {
- QApplication app (argc, argv);
- QLabel label (app.translate ( "QLabel" , "Hello, World!" ));
- label.show ();
- return app.exec ();
- }
* This source code was highlighted with Source Code Highlighter .
In the tr () and translate () functions, after the string to be translated, you can specify a comment that will be shown to the translator when the application is translated into another language. Comments are used to eliminate ambiguity.
If you need to translate text that is outside the function, there are two macros for help: QT_TR_NOOP () and QT_TRANSLATE_NOOP (), similar to tr () and translate (). They unnoticeably mark the text to be extracted by the lupdate utility, about which we will discuss below:
- static const char * greeting_strings [] = {
- QT_TR_NOOP ( "Hello" ),
- QT_TR_NOOP ( "Goodbye" )
- };
- static const char * greeting_strings [] = {
- QT_TRANSLATE_NOOP ( "HelloWidget" , "Hello" ),
- QT_TRANSLATE_NOOP ( "HelloWidget" , "Goodbye" )
- };
* This source code was highlighted with Source Code Highlighter .
When disabling automatic conversion from const char * to QString by compiling a program with a specific macro QT_NO_CAST_FROM_ASCII, you can find all the lines that are skipped.
When we need to insert the values of any variables in the middle of the line, it is best to use the arg () function. For example, when copying files, we could display the process as follows:
- void FileCopier :: showProgress ( int done, int total,
- const QString (FtFile)
- {
- label.setText (tr ( "% 1 of% 2 files copied. \ nCopying:% 3" )
- .arg (done)
- .arg (total)
- .arg (currentFile));
- }
* This source code was highlighted with Source Code Highlighter .
If you need to change the order of the arguments during the translation, then during the translation you will need to change the variables with the% symbol in places, for example, like this:
“Copying file% 3. % 1 of% 2 files copied »
Rewriting the program because of this is not required.
Step 2. Create a translation
After we have used tr () throughout the application, we need to create a translation of the text. Text translation also contains 3 steps:
- Run lupdate to extract translatable text from Qt application source code in C ++, creating a message file for translators (.ts file). The utility recognizes the tr () and translate () constructors and the QT_TR * _NOOP () macros described above and produces .ts files (usually one for each language).
- Providing translations for source texts in a .ts file using Qt Linguist. Since .ts files are in XML format, they can also be edited manually.
- Run lrelease to get a lightweight message file (.qm file) from an .ts file that is convenient only for end use. Think of the .ts files as "source files", and of the .qm files as "object files." The translator edits the .ts files, but users of our application only need .qm files. Both file types are platform and locale independent.
Usually you need to repeat these steps for each release of the application. The lupdate utility does its best to reuse translations from previous releases.
Before running lupdate, you need to prepare a project file. This is how our project file will look like (helloworld.pro file):
TEMPLATE = app
TARGET = release
DEPENDPATH + =.
INCLUDEPATH + =.
SOURCES + = main.cpp
TRANSLATIONS + = helloworld_ru.ts
When you run lupdate or lrelease, you must provide the name of the project file as a command line argument.
Step 3. Downloading translation files in the application.
In our application, we need to load QTranslator :: load () files using QcoreApplication :: installTranslator (). The final version of the program will look like:
- #include <QtGui>
- #include <QtCore>
- int main ( int argc, char * argv []) {
- QApplication app (argc, argv);
- QTranslator myTranslator;
- myTranslator.load ( "helloworld_" + QLocale :: system (). name ());
- app.installTranslator (& myTranslator);
- QLabel label (app.translate ( "QLabel" , "Hello, World!" ));
- label.show ();
- return app.exec ();
- }
* This source code was highlighted with Source Code Highlighter .
We create a QTranslator object, load the translation file into it using the load () function. In it we indicate the beginning of the name of our translation file. By default, translation files are searched in the program folder, but you can specify any directory by passing its name as the second parameter to the function. The extension ".qm" will be added automatically. The Qlocale :: system (). Name () function returns the name of the current locale, in my case it was ru_RU.UTF-8. The search for the translation file using the load () function is as follows:
- helloworld_ru_RU.UTF-8.qm
- helloworld_ru_RU.UTF-8
- helloworld_ru_RU.qm
- helloworld_ru_RU
- helloworld_q.qm
- helloworld
- helloworld.qm
- helloworld
The truth is, when I tried to download the translation file in Windows XP in this way, it didn’t work for me. It turned out that (at least in my case) the function Qlocale :: system (). Name () always returned the value "C". Therefore, it is worthwhile to provide an additional method for specifying the language of the application interface, for example, through the program settings dialog or command line parameters.
That's all, our application is translated into Russian, but there are a couple more points that are worth mentioning in this article.
Additional text lines
Qt contains about 400 lines inside, which also need to be translated into the languages we need. In the $ QTDIR / translations directory you can find translation files for French, German and Simplified Chinese, as well as templates for translations into other languages. (This directory also contains some additional unsupported translations that may be useful, for example, a Russian translation).
Usually, these transfers are also loaded into main () functions:
- int main ( int argc, char * argv [])
- {
- ...
- QTranslator qtTranslator;
- qtTranslator.load ( "qt_" + QLocale :: system (). name (),
- QLibraryInfo :: location (QLibraryInfo :: TranslationsPath));
- app.installTranslator (& qtTranslator);
- ...
- }
* This source code was highlighted with Source Code Highlighter .
Note the use of QLibraryInfo :: location () to detect Qt translations. The developer must request a path to the translations by processing the QLibraryInfo :: TranslationsPath for this function instead of using the QTDIR environment variable in its applications. Although in cases where we are not sure that the user has the full version of Qt, it makes sense to ship this translation file along with the program and download it from the program directory (or any other one of your choice).
Dynamic translation
Some applications must provide changes to the user's language settings during operation. To warn widgets about changes to the set QTranslators, you can redo the function of the changeEvent () widget to check if the event is a LanguageChange event and update the text displayed by the widgets using the tr () function in the usual way. For example:
- void MyWidget :: changeEvent (QEvent * event )
- {
- if (e-> type () == QEvent :: LanguageChange) {
- titleLabel-> setText (tr ( "Document Title" ));
- ...
- okPushButton-> setText (tr ( "& OK" ));
- } else
- QWidget :: changeEvent ( event );
- }
* This source code was highlighted with Source Code Highlighter .
All other change events must be handled by calling the default implementation of this function.
The list of installed translations can be changed in response to the LocaleChange event, or the application can provide an interface to the user, which will allow him to change the current application language.
The default event handler for QWidget subclasses responds to the QEvent :: LanguageChange event and will call this function if necessary; In other application components, you can also force widgets to update themselves by sending them a LanguageChange event.
UPD: As prompted by
intellinside , the GUI classes generated by Qt Designer have a retranslateUi () function that can be called to dynamically change the language of the application.