Support for multiple languages is extremely simple in Qt applications, and adds little overhead to the programmer's workload.
Qt minimizes the performance cost of using translations by translating the phrases for each window as they are created. In most applications the main window is created just once. Dialogs are often created once and then shown and hidden as required. Once the initial translation has taken place there is no further runtime overhead for the translated windows. Only those windows that are created, destroyed and subsequently created will have a translation performance cost.
Creating applications that can switch language at runtime is possible with Qt, but requires a certain amount of programmer intervention and will of course incur some runtime performance cost.
Programmers should make their application look for and load the appropriate translation file and mark user-visible text and Ctrl keyboard accelerators as targets for translation.
Each piece of text that requires translating requires context to help the translator identify where in the program the text occurs. In the case of multiple identical texts that require different translations, the translator also requires some information to disambiguate the source texts. Marking text for translation will automatically cause the class name to be used as basic context information. In some cases the programmer may be required to add additional information to help the translator.
Translation files consist of all the user-visible text and Ctrl key accelerators in an application and translations of that text. Translation files are created as follows:
For
lupdate
to work successfully, it must know which translation files to produce. The files are simply listed in the application's
.pro
Qt project file, for example:
TRANSLATIONS = arrowpad_fr.ts \
arrowpad_nl.ts
If your sources contain genuine non-Latin1 strings,
lupdate
needs to be told about it in the
.pro
file by using, for example, the following line:
CODECFORTR = UTF-8
int main(int argc, char *argv[]) { QApplication app(argc, argv);
This is how a simple
main()
function of a Qt application begins.
int main(int argc, char *argv[]) { QApplication app(argc, argv); QTranslator translator; translator.load("hellotr_la"); app.installTranslator(&translator);
For a translation-aware application a translator object is created, a translation is loaded and the translator object installed into the application.
int main(int argc, char *argv[]) { QApplication app(argc, argv); QString locale = QLocale::system().name(); QTranslator translator; translator.load(QString("arrowpad_") + locale); app.installTranslator(&translator);
For non-Latin1 strings in the sources you will also need for example:
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
In production applications a more flexible approach, for example, loading translations according to locale, might be more appropriate. If the TS files are all named according to a convention such as
appname_locale
,如
tt2_fr
,
tt2_de
etc, then the code above will load the current locale's translation at runtime.
If there is no translation file for the current locale the application will fall back to using the original source text.
Note that if you need to programmatically add translations at runtime, you can reimplement QTranslator::translate ().
User-visible strings are marked as translation targets by wrapping them in a
tr()
call, for example:
button = new QPushButton("&Quit", this);
would become
button = new QPushButton(tr("&Quit"), this);
所有
QObject
subclasses that use the
Q_OBJECT
macro implement the
tr()
函数。
尽管
tr()
call is normally made directly since it is usually called as a member function of a
QObject
subclass, in other cases an explicit class name can be supplied, for example:
QPushButton::tr("&Quit")
or
QObject::tr("&Quit")
The
lupdate
program automatically provides a
context
for every source text. This context is the class name of the class that contains the
tr()
call. This is sufficient in the vast majority of cases. Sometimes however, the translator will need further information to uniquely identify a source text; for example, a dialog that contained two separate frames, each of which contained an "Enabled" option would need each identified because in some languages the translation would differ between the two. This is easily achieved using the two argument form of the
tr()
call, e.g.
rbc = new QRadioButton(tr("Enabled", "Color frame"), this);
and
rbh = new QRadioButton(tr("Enabled", "Hue frame"), this);
Ctrl key accelerators are also translatable:
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcut(tr("Ctrl+Q", "Quit"));
It is strongly recommended that the two argument form of
tr()
is used for Ctrl key accelerators. The second argument is the only clue the translator has as to the function performed by the accelerator.
In large complex applications it may be difficult for the translator to see where a particular source text comes from. This problem can be solved by adding a comment using the keyword TRANSLATOR which describes the navigation steps to reach the text in question; e.g.
/*
TRANSLATOR FindDialog
Choose Edit|Find from the menu bar or press Ctrl+F to pop up the
Find dialog.
...
*/
These comments are particularly useful for widget classes.
Qt includes a
tr()
overload that will make it very easy to write "plural-aware" internationalized applications. This overload has the following signature:
QString tr(const char *text, const char *comment, int n);
Depending on the value of
n
,
tr()
function will return a different translation, with the correct grammatical number for the target language. Also, any occurrence of
%n
被替换采用
n
's value. For example:
tr("%n item(s) replaced", "", count);
If a French translation is loaded, this will expand to "0 item remplacé", "1 item remplacé", "2 items remplacés", etc., depending on
n
's value. And if no translation is loaded, the original string is used, with
%n
replaced with count's value (e.g., "6 item(s) replaced").
To handle plural forms in the native language, you need to load a translation file for this language, too.
lupdate
拥有
-pluralonly
command line option, which allows the creation of TS files containing only entries with plural forms.
见 Qt 季刊 Article Plural Forms in Translations for further details on this issue.
C++ namespaces and the
using namespace
statement can confuse
lupdate
. It will interpret
MyClass::tr()
as meaning just that, not as
MyNamespace::MyClass::tr()
, even if
MyClass
is defined in the
MyNamespace
namespace. Runtime translation of these strings will fail because of that.
You can work around this limitation by putting a
TRANSLATOR
comment at the beginning of the source files that use
MyClass::tr()
:
/*
TRANSLATOR MyNamespace::MyClass
Necessary for lupdate.
...
*/
After the comment, all references to
MyClass::tr()
will be understood as meaning
MyNamespace::MyClass::tr()
.
若引号文本不在成员函数中对于 QObject subclass, use either the tr() function of an appropriate class, or the QCoreApplication::translate () 函数直接:
void some_global_function(LoginWidget *logwid) { QLabel *label = new QLabel( LoginWidget::tr("Password:"), logwid); } void same_global_function(LoginWidget *logwid) { QLabel *label = new QLabel( qApp->translate("LoginWidget", "Password:"), logwid); }
If you need to have translatable text completely outside a function, there are two macros to help: QT_TR_NOOP () 和 QT_TRANSLATE_NOOP (). These macros merely mark the text for extraction by lupdate . The macros expand to just the text (without the context).
Example of QT_TR_NOOP ():
QString FriendlyConversation::greeting(int greet_type) { static const char* greeting_strings[] = { QT_TR_NOOP("Hello"), QT_TR_NOOP("Goodbye") }; return tr(greeting_strings[greet_type]); }
Example of QT_TRANSLATE_NOOP ():
static const char* greeting_strings[] = { QT_TRANSLATE_NOOP("FriendlyConversation", "Hello"), QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye") }; QString FriendlyConversation::greeting(int greet_type) { return tr(greeting_strings[greet_type]); } QString global_greeting(int greet_type) { return qApp->translate("FriendlyConversation", greeting_strings[greet_type]); }
Three tutorials are presented:
tr()
function to mark user-visible source text for translation.
tr()
which provides additional information to the translator.
These tutorials cover all that you need to know to prepare your Qt applications for translation.
At the beginning of a project add the translation source files to be used to the project file and add calls to lupdate and lrelease to the Makefile.
During the project all the programmer must do is wrap any user-visible text in
tr()
calls. They should also use the two argument form for Ctrl key accelerators, or when asked by the translator for the cases where the same text translates into two different forms in the same context. The programmer should also include
TRANSLATION
comments to help the translator navigate the application.