编写翻译源代码

以启用本地化应用程序的方式,编写 QML 和 Qt C++ 源代码:

当开发 C++ 应用程序时,另请参阅 用于 C++ 代码的额外注意事项 .

标记翻译字符串

Most of the text that must be translated in an application consists of either single words or short phrases. These typically appear as window titles, menu items, tooltips, and labels to buttons, check boxes, and radio buttons.

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.

You can create applications that switch language at runtime, but it requires an effort and comes with a runtime performance cost.

Use translation functions to mark user-visible UI text for translation in QML and C++ code. Qt indexes each translatable string by the translation context it is associated with. The same phrase may occur in more than one context without conflict. If a phrase occurs more than once in a particular context, it is translated only once and the translation is applied to every occurrence within the context.

QML:使用 qsTr()

In QML, you can use the following functions to mark user-visible strings for translation in .qml files:

通常,使用 qsTr() 函数:

Text {
    id: txt1
    text: qsTr("Back")
}
					

This code makes Back a key entry in the translation source (TS) files. At runtime, the translation system looks up the keyword Back and then gets the corresponding translation value for the current system locale. The result is returned to the text property and the UI shows the appropriate translation of Back for the current locale. If no translation is found, qsTr() 返回原始字符串。

The translation context can be set for a given file with:

pragma Translator: ChosenContext
					

or

pragma Translator: "Chosen::Context"
					

The context set via qsTranslate() takes precedent over the context set via pragma Translator . In QML, by default, the translation context is the file name.

C++:使用 tr()

在 C++,使用 tr () function to mark text as translatable and to display translated text. The translation context is the name of the QObject subclass the string is used in. To define translation context for new QObject -based classes, use the Q_OBJECT macro in each new class definition.

tr() is called, it looks up the translatable string using a QTranslator object, which you must install on the application object, as described in 启用翻译 .

例如,假定 LoginWidget 是子类化的 QWidget :

LoginWidget::LoginWidget()
{
    QLabel *label = new QLabel(tr("Password:"));
    ...
}
					

This accounts for 99% of the user-visible strings you're likely to write. For information about marking string literals translatable, see 标记可翻译数据文本字符串 .

若引号文本不在成员函数中对于 QObject 子类,使用 tr() 函数从适当类,或 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(
                QCoreApplication::translate("LoginWidget", "Password:"), logwid);
}
					

注意: 若禁用 const char * to QString automatic conversion by compiling your application with the macro QT_NO_CAST_FROM_ASCII defined, you will most likely catch any strings you are missing. See QString::fromUtf8 () 和 QString::fromLatin1 () 了解更多信息。

使用参数而不是串联字符串

Different languages arrange words differently in phrases, clauses, and sentences, so do not create strings by concatenating words and data. Instead, use % to insert parameters into strings.

For example, in the string After processing file %1, file %2 is next in line , %1 and %2 are numbered parameters. At runtime, %1 and %2 are replaced with the first and second file names, respectively. The same numbered parameters must appear in the translation, but not necessarily in the same order. A German translation of the string might reverse the phrases. For example, Datei %2 wird bearbeitet, wenn Datei %1 fertig ist . Both numbered parameters appear in the translation, but in the reverse order.

QML:使用 .arg()

The following QML snippet has a string with two number parameters %1 and %2 . These parameters are inserted with the .arg() 函数。

Text {
    text: qsTr("File %1 of %2").arg(counter).arg(total)
}
					

%1 refers to the first parameter and %2 refers to the second parameter, so this code produces output like: File 2 of 3 .

C++:使用 QString::arg()

在 C++,使用 QString::arg () functions to substitute parameters:

void FileCopier::showProgress(int done, int total,
                              const QString &currentFile)
{
    label.setText(tr("%1 of %2 files copied.\nCopying: %3")
                  .arg(done)
                  .arg(total)
                  .arg(currentFile));
}
					

This code produces output like: 5 of 10 files copied. Copying: somefile.txt .

句柄复数形式

You can pass an additional integer parameter ( n ) to the translation functions and use a special notation for plural forms ( %n ) in each translatable string.

Depending on the value of n , the translation function returns a different translation, with the correct grammatical number for the target language. Also, any occurrence of %n 被替换采用 n 's value.

For example, the English and French translations of the string %n message(s) saved require different plural forms.

n 不翻译 法语 English
0 "0 message(s) saved" "0 message sauvegardé" "0 message s saved"
1 "1 message(s) saved" "1 message sauvegardé" "1 message saved"
2 "2 message(s) saved" "2 message s sauvegardé s " "2 message s saved"
37 "37 message(s) saved" "37 message s sauvegardé s " "37 message s saved"

This idiom also works with target languages that have several plural forms, such as a dual form. In addition, the idiom handles the n == 0 case correctly for languages such as French that require the singular.

For a summary of the rules that Qt Linguist and lrelease use to translate strings that contain plural forms, see 复数形式翻译规则 .

To handle plural forms in the native language, load a TS file for this language, too. Use the lupdate tool -pluralonly command line option, to create TS files that contain only entries with plural forms.

Alternatively, you can use the lconvert tool's -pluralonly command line option to remove all non-plural forms from an existing TS file.

QML 范例

The following QML code snippet translates the source text into the correct plural form and replaces %n with the value of total :

Text {
    text: qsTr("%n message(s) saved", "", total)
}
					

C++ 范例

The following C++ code snippet replaces %n with the value that the count() function returns:

int n = messages.count();
showMessage(tr("%n message(s) saved", "", n));
					

使用地区编号设置

If you include the %L modifier when you specify a parameter, the number is localized according to the current regional settings. The conversion uses the default locale if you set it or the system-wide locale, otherwise.

QML:使用 %L

For example, in the following QML snippet, %L1 formats the first parameter according to the number formatting conventions of the currently selected locale (geographical region):

Text {
    text: qsTr("%L1").arg(total)
}
					

total is the number 4321.56 , with English regional settings (locale) the output is 4,321.56 , whereas with German regional settings it is 4.321,56 .

C++:使用 %Ln

在 C++,可以使用 %Ln 以产生本地化表示 n 。使用 QLocale::setDefault () 以设置默认区域设置。

国际化日期、时间和货币

Present date, time, and currency using the locally preferred formats.

QML:使用 QtQml 函数

QML does not have special in-string modifiers for formatting dates and times. Instead, you need to query the current locale (geographical region) and use the methods of Date to format the string.

Qt.locale() 返回 Locale object which contains information about the locale. In particular, the Locale.name property contains the language and country of the current locale. You can use the value as is or parse it to determine the appropriate content for the current locale.

The following snippet gets the current date and time with Date() , then converts that to a string for the current locale. Then it inserts the date string into the %1 parameter for the appropriate translation.

Text {
    text: qsTr("Date %1").arg(Date().toLocaleString(Qt.locale()))
}
					

To localize currency numbers, use the Number type. It has similar functions as the Date type for converting numbers into localized currency strings.

C++:使用 QLocale 类

在 c++,使用 QLocale::timeFormat () 或 QLocale::toString ( QTime ) 或 toString(QDate) :

QLabel *label = new QLabel(this);
label->setText(tr("Date %1").arg(QLocale().toString(QDate::currentDate()));
					

标记可翻译数据文本字符串

使用 _NoOp 函数 (在 QML) 和 _NOOP macros (in C++) to mark translatable string literals for extraction by the lupdate 工具。

QML:使用 _NoOp 函数

In QML, use the following functions to mark translatable string literals:

  • qsTrNoOp()
  • qsTranslateNoOp()
  • qsTrIdNoOp()

If the user changes the system language without a reboot, depending on the system, the strings in arrays and list models and other data structures might not be refreshed automatically. To force the texts to be refreshed when they are displayed in the UI, you need to declare the strings with the qsTrNoOp() function. Then, when you populate the objects for display, you need to explicitly retrieve the translation for each text.

例如:

ListModel {
    id: myListModel
    ListElement {
        //: Capital city of Finland
        name: qsTrNoOp("Helsinki")
    }
}
...
Text {
    text: qsTr(myListModel.get(0).name)
    // Get the translation of the name property in element 0
}
					

C++:使用 _NOOP 宏

For translatable text completely outside a function, use the QT_TR_NOOP () 和 QT_TRANSLATE_NOOP () macros that expand to just the text without the context.

An example of QT_TR_NOOP() :

QString FriendlyConversation::greeting(int type)
{
    static const char *greeting_strings[] = {
        QT_TR_NOOP("Hello"),
        QT_TR_NOOP("Goodbye")
    };
    return tr(greeting_strings[type]);
}
					

An example of QT_TRANSLATE_NOOP() :

static const char *greeting_strings[] = {
    QT_TRANSLATE_NOOP("FriendlyConversation", "Hello"),
    QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye")
};
QString FriendlyConversation::greeting(int type)
{
    return tr(greeting_strings[type]);
}
QString global_greeting(int type)
{
    return QCoreApplication::translate("FriendlyConversation",
                                       greeting_strings[type]);
}
					

为翻译者添加注释

You can add comments in the source code before a string you mark as translatable to clarify its purpose. The comments are included in the TS files that you deliver to the translator.

注意: The TS files are XML files with the source texts and a place for the translated text. The updated TS files are converted into binary translation files and included as part of the final application.

QML:使用//: 和//~

In the following code snippet, the text on the //: line is the main comment for the translator.

The text on the //~ line is optional extra information. The first word of the text is used as an additional identifier in the XML element in the TS file so make sure the first word is not part of the sentence. For example, the comment Context Not related to back-stepping is converted to <extra-Context>Not related to back-stepping in the TS file.

Text {
    id: txt1;
    // This UI string is only used here
    //: The back of the object, not the front
    //~ Context Not related to back-stepping
    text: qsTr("Back");
}
					

C++:使用注释字符

To add comments in C++, annotate the tr() calls in your code with comments of the form //: or by marking the beginning and end of the comment.

In the following examples, the comments are associated with the strings passed to tr() in the context of each call:

//: This name refers to a host name.
hostNameLabel->setText(tr("Name:"));
/*: This text refers to a C++ code example. */
QString example = tr("Example");
					

To add optional comments, use:

//~ <field name> <field contents>
					

The field name should consist of a domain prefix (possibly the conventional file extension of the file format the field is inspired by), a hyphen, and the actual field name in underscore-delimited notation. For storage in TS files, the field name together with the prefix extra- will form an XML element name. The field contents will be XML-escaped, but otherwise appear verbatim as the element's contents. You can add any number of unique fields to each message.

范例:

//: This is a comment for the translator.
//= qtn_foo_bar
//~ loc-layout_id foo_dialog
//~ loc-blank False
//~ magic-stuff This might mean something magic.
QString text = MyMagicClass::tr("Sim sala bim.");
					

In C++, you use an equals sign to add a unique identifier:

//= <id>
					

You can use the keyword TRANSLATOR for translator comments. Metadata appearing right in front of the TRANSLATOR keyword applies to the whole TS file.

消除恒等文本歧义

The translation system consolidates the UI text strings into unique items to avoid having to translate the same text multiple times. However, a text might look identical to another text but have a different meaning. For example, in English, back means both a step backward and the part of an object opposite to the front. You need to tell the translation system about these two separate meanings, so the translator can create two separate translations.

QML:为 qsTr() 添加消歧器

In QML, add a disambiguating string as the second parameter of the qsTr() 函数。

In the following code snippet, the ID not front differentiates this Back text from the backstepping Back text:

Text {
    id: txt1
    // This UI string is used only here
    //: The back of the object, not the front
    //~ Context Not related to back-stepping
    text: qsTr("Back", "not front")
}
					

C++:为 tr() 添加消歧器

In C++, pass a disambiguating string in the call to tr ().

In the following code snippet, the ID recipient differentiates the name of the recipient from that of the sender:

MyWindow::MyWindow()
{
    QLabel *senderLabel = new QLabel(tr("Name:"));
    QLabel *recipientLabel = new QLabel(tr("Name:", "recipient"));
    ...
					

使键盘快捷键可翻译

In its most common form, a keyboard shortcut describes a combination of keys that you press to perform some action. For 标准快捷键 , use a standard key to request the platform-specific key sequence associated with each shortcut.

For custom shortcuts, use human-readable strings, such as Ctrl+Q or Alt+F . You can translate them into the appropriate shortcuts for the speakers of different languages.

If you hard-code keyboard shortcuts in your application, translators cannot override them.

When you use keyboard shortcuts in menu item and button text, a mnemonic character (marked by underlining) indicates that pressing Alt or Ctrl with the underlined character performs the same action as clicking the menu item or pressing the button.

For example, applications often use F as the mnemonic character in the File menu, so you can either click the menu item or press Alt+F to open the menu. To define the mnemonic character in the translatable string ("File"), prefix it with an ampersand: "&File" . The translation for the string should also have an ampersand in it, preferably in front of the same character.

QML 范例

在 QML:

Menu {
    id: fileMenu
    title: qsTr("&File")
    MenuItem {
        objectName: "quitMenuItem"
        text: qsTr("E&xit")
        onTriggered: Qt.quit()
    }
}
					

C++:使用 QKeySequence 类

在 c++,使用 QAction and QKeySequence objects to specify the keyboard shortcuts that trigger actions:

exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
					

The translations of keyboard shortcuts are associated with the QShortcut 上下文。

使用区域设置扩展本地化特征

You might find different graphics or audio more suitable for different geographical regions.

Generally, try to avoid localizing images. Create icons that are globally appropriate, rather than relying on local puns or stretched metaphors. However, you might have to reverse images of left and right pointing arrows for Arabic and Hebrew locales.

Locale is one of the default file selectors, so you can use file selection to display different images that you deliver as resources depending on the system locale.

The QML and C++ code examples in the following sections assume that you deliver the following files in the application resources and use language and country codes as the subfolder names:

images
├── language-icon.png
├── +en_GB
│   └── language-icon.png
└── +fi_FI
    └── language-icon.png
					

QML:设置图像源

The following QML code snippet shows how to select an icon source image according to the current locale:

icon.source: "qrc:/images/language-icon.png"
					

C++:使用 QFileSelector

以下 C++ 代码片段使用 QFileSelector to pick a language icon from the images folder according to the system locale:

const QFileSelector selector;
const QIcon languageIcon(selector.select(":/images/language-icon.png"));
					

启用翻译

TS file names must contain ISO language and country codes:

  • 语言 ISO-639 language code in lowercase.
  • country ISO-3166 two-letter country code in uppercase.

例如, qml_de.ts sets the target language to German, and qml_de_CH.ts sets the target language to German and the target country to Switzerland. The lrelease tool generates QM files called qml_de.qm and qml_de_CH.qm that the application loads depending on the system locale.

QML:使用 QQmlApplicationEngine

在 QML,使用 QQmlApplicationEngine to automatically load translation files from a subdirectory called i18n in the directory that contains the main QML file. The translation file names must have the prefix qml_ 。例如, qml_en_US.qm .

Applications reload translations when the QJSEngine::uiLanguage or Qt.uiLanguage property value changes.

C++:使用 QTranslator

In C++, the TS file names must contain the application name. For example, app_de_DE.ts .

Typically, your Qt C++ application's main() 函数看起来像这样:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QTranslator myappTranslator;
    if (myappTranslator.load(QLocale::system(), u"myapp"_s, u"_"_s, u":/i18n"_s))
        app.installTranslator(&myappTranslator);
    return app.exec();
}
					

For a translation-aware application, you create a QTranslator 对象, load a translation according to the user's UI display locale at runtime, and install the translator object into the application.

为动态语言改变做准备

Both Qt Widgets and Qt Quick use Qt's event system to inform classes about translation changes.

LanguageChange events are posted when you use the QCoreApplication::installTranslator () function to install a new translation. Other application components can also force widgets or QML types derived from the Item type to update themselves by posting LanguageChange events to them.

默认情况下, LanguageChange events are propagated to all top-level windows, and from there they're propagated through the entire tree of widgets or QML types derived from Item.

Qt Widgets:覆写 changeEvent

The default event handler for QWidget subclasses responds to the QEvent::LanguageChange event and calls the changeEvent() function when necessary.

To make Qt widgets aware of changes to the installed QTranslator objects, reimplement the widget's changeEvent () function to check whether the event is a LanguageChange event and update the text displayed by widgets using the tr () 函数。例如:

void MyWidget::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::LanguageChange) {
        titleLabel->setText(tr("Document Title"));
        ...
        okPushButton->setText(tr("&OK"));
    } else
        QWidget::changeEvent(event);
}
					

当使用 Qt Designer UI files (.ui) and uic , you can read the new translation files and call ui.retranslateUi(this) 直接:

void MyWidget::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::LanguageChange) {
        ui.retranslateUi(this);
    } else
        QWidget::changeEvent(event);
}
					

To pass on other change events, call the default implementation of the function.

The list of installed translators might change in response to a LocaleChange event, or the application might provide a UI that allows the user to change the current application language.

QML:覆写派生自项的类型的事件

For plain QML applications without any custom C++ registered types, using QQmlApplicationEngine is enough to trigger an update of all translation bindings.

However, if you registered a type derived from QQuickItem , and one of its properties exposes translated text (or is otherwise language dependent), override its event method and emit the property's change signal in it (or call notify in case of bindable properties). For example:

class MyItem : public QQuickItem
{
    Q_OJBECT
    QML_ELEMENT
    Q_PROPERTY(QString greeting READ greeting NOTIFY greetingChanged)
public signals:
    void greetingChanged();
public:
    QString greeting() const
    {
        return tr("Hello World!");
    }
    bool event(QEvent *ev) override
    {
        if (ev->type() == QEvent::LanguageChange)
            emit greetingChanged();
        return QQuickItem::event(ev);
    }
};
					

This ensures that any binding in QML in which the property is used is reevaluated and takes the language change into account.

一般 QObject 派生类:使用事件过滤器

Some classes are neither derived from QWidget nor from QQuickItem , but might still need to handle language change events. In that case, install 事件过滤器 on QCoreApplication .

class CustomObject : public QObject
{
    Q_OBJECT
public:
    QList<QQuickItem *> managedItems;
    CustomObject(QOject *parent = nullptr) : QObject(parent)
    {
        QCoreApplication::instance()->installEventFilter(this);
    }
    bool eventFilter(QObject *obj, QEvent *ev) override
    {
        if (obj == QCoreApplication::instance() && ev->type() == QEvent::LanguageChange) {
            for (auto item : std::as_const(managedItems))
                QCoreApplication::sendEvent(item, ev);
            // do any further work on reaction, e.g. emit changed signals
        }
        return false;
    }
};
					

This might be necessary when translated strings are provided by the class that later get displayed in a user interface (for example, a custom 项模型 ), or when the class acts as a container of Widgets or Quick Items, and is therefore responsible for forwarding the event to them.

用于 C++ 代码的额外注意事项

The following sections contain more information about using the Qt C++ classes and functions in translatable applications:

为所有用户可见文本使用 QString

QString 使用 Unicode encoding internally, and therefore you can use familiar text processing operations to transparently process all languages in the world. Also, since all Qt functions that present text to the user take a QString object as a parameter, there is no char * to QString conversion overhead.

定义翻译上下文

The translation context for QObject and each QObject subclass is the class name itself. If you subclass QObject ,使用 Q_OBJECT macro in the class definition to override the translation context. The macro sets the context to the name of the subclass.

For example, the following class definition includes the Q_OBJECT macro, implementing a new tr() function that uses the MainWindow 上下文:

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow();
    ...
					

若不使用 Q_OBJECT in a class definition, the context is inherited from the base class. For example, since all QObject -based classes in Qt provide a context, a new QWidget subclass defined without a Q_OBJECT macro uses the QWidget context if you invoke its tr() 函数。

翻译非 Qt 类

You must provide extra information for lupdate about strings in classes that do not inherit QObject 或使用 Q_OBJECT macro. To add translation support to a non-Qt class, you can use the Q_DECLARE_TR_FUNCTIONS () macro. For example:

class MyClass
{
    Q_DECLARE_TR_FUNCTIONS(MyClass)
public:
    MyClass();
    ...
};
					

This provides the class with tr () functions that you can use to translate strings associated with the class, and enables lupdate to find translatable strings in the source code.

Alternatively, you can call the QCoreApplication::translate () function with a specific context that lupdate and Qt Linguist recognize.

翻译 QObject 子类外的文本

若引号文本不在成员函数中对于 QObject 子类,使用 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(
            QCoreApplication::translate("LoginWidget", "Password:"),
            logwid);
}
					

Qt 国际化 本地化应用程序