本页内容

编写可供翻译的源代码

编写 Qt Qml 和 Qt C++ 源代码时,请确保能够对应用程序进行本地化:

在开发 C++ 应用程序时,请另请参阅《C++ 代码的附加注意事项》。

标记待翻译的字符串

应用程序中需要翻译的大部分文本由单个单词或短语组成。这些通常出现在窗口标题、菜单项、工具提示以及按钮、复选框和单选按钮的标签中。

Qt 通过在创建每个窗口时即时翻译其短语,从而最大限度地降低了使用翻译带来的性能开销。在大多数应用程序中,主窗口仅创建一次。 对话框通常仅创建一次,随后根据需要显示或隐藏。一旦初始翻译完成,已翻译的窗口就不会产生进一步的运行时开销。只有那些被创建、销毁并随后再次创建的窗口才会产生翻译性能开销。

您可以创建在运行时切换语言的应用程序,但这需要额外的工作,并且会带来运行时性能开销。

请使用翻译函数在 Qt Qml 和 C++ 代码中标记用户可见的 UI 文本以供翻译。Qt 支持两种识别可翻译文本的方法:基于文本和 基于 ID。

在基于文本的翻译方法中,Qt 会根据翻译上下文(以及可选的、与其关联的消除歧义注释)为每个可翻译字符串建立索引。同一短语可能出现在多个上下文中而不会产生冲突。如果某个短语在特定上下文中出现多次,则仅翻译一次,且该翻译将应用于该上下文中的所有出现位置。

在基于 ID 的翻译方法中,每条翻译都通过一个显式的 ID 进行唯一标识。这些 ID 在整个项目范围内是唯一的。如果一个 ID 在项目中出现多次,则仅翻译一次,且该翻译将应用于该项目内的每次出现。

QML

在 QML 中,您可以使用以下函数在 .qml 文件中标记需翻译的用户可见字符串:

基于文本的 qsTr():

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

此代码将“Back”作为关键项添加到翻译源(TS)文件中。 在运行时,翻译系统会在当前上下文中(见下文)查找关键字“Back”,然后获取当前系统区域设置对应的翻译值。结果将返回给text 属性,用户界面将显示当前区域设置下“Back”的正确翻译。如果未找到翻译,qsTr() 将返回原始字符串。

可通过以下方式为特定文件设置翻译上下文:

pragma Translator: ChosenContext

或

pragma Translator: "Chosen::Context"

通过qsTranslate() 设置的上下文优先于通过pragma Translator 设置的上下文。在QML中,默认情况下,翻译上下文即为文件名。

基于 ID 的 qsTrId():

Text {
    id: txt1
    //% "Back"
    text: qsTrId("BackID")
}

此代码将“BackID”设为翻译源(TS)文件中的唯一键条目,并将其源文本写为“Back”。运行时,翻译系统会查询 ID“BackID”,然后获取当前系统区域设置对应的翻译值(若未翻译,则返回源文本)。 结果将返回给text 属性,用户界面将显示当前区域设置下“BackID”的相应翻译。如果在TS文件中未找到ID为“BackID”的条目,qsTrId() 将返回该ID本身。在正常情况下不应发生这种情况。

C++

在 C++ 中,您可以使用以下函数将用户可见的字符串标记为待翻译:

基于文本的 tr()

使用tr()函数将文本标记为可翻译,并显示翻译后的文本。翻译上下文即字符串所使用的QObject 子类的名称。若要为基于QObject 的新类定义翻译上下文,请在每个新类定义中使用Q_OBJECT 宏。

调用tr() 时,它会使用QTranslator 对象查找可翻译字符串,您必须按照“启用翻译”中的说明将该对象安装到应用程序对象上。

例如,假设LoginWidget 是QWidget 的子类:

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

这涵盖了您可能编写的 99% 的用户可见字符串。有关将字符串字面量标记为可翻译的信息,请参阅《标记可翻译数据文本字符串》。

如果引号内的文本不在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);
}

基于 ID 的 qtTrId()

qtTrId() 会返回一个由 ID 标识的已翻译字符串。因此,无需在函数中直接写入可翻译的字符串本身,只需写入该翻译的 ID 即可。 源文本(默认字符串)使用元字符串表示法//% 写入。如果文本未被翻译,则返回由//% 标注的源文本。如果未找到匹配的ID,则返回ID本身。在正常情况下不应发生这种情况。

//% "Password:"
QLabel *label = new QLabel(qtTrId("PasswordID"));

这段代码将“PasswordID”设为翻译源(TS)文件中的唯一键条目,并将其源文本写为“Password:”。 在运行时,翻译系统会查询 ID “PasswordID”,然后获取当前系统区域设置下对应的翻译值(若未翻译,则返回源文本)。

注意:如果您通过 在编译应用程序时定义宏QT_NO_CAST_FROM_ASCII 来禁用const char * 到QString 的自动转换,您很可能就能发现任何缺失的字符串。有关更多信息,请参阅QString::fromUtf8() 和QString::fromLatin1()。

使用参数代替字符串拼接

不同语言在短语、从句和句子中对单词的排列方式各不相同,因此请勿通过连接单词和数据来构建字符串。相反,应使用% 将参数插入字符串中。

例如,在字符串After processing file %1, file %2 is next in line 中,%1 和%2 是编号参数。在运行时,%1 和%2 将分别被替换为第一个和第二个文件名。翻译中必须出现相同的编号参数,但顺序不一定相同。 该字符串的德语翻译可能会颠倒短语的顺序。例如:Datei %2 wird bearbeitet, wenn Datei %1 fertig ist 。两个编号参数均出现在翻译中,但顺序相反。

QML:使用 .arg()

以下 QML 代码片段中包含一个带有两个编号参数%1 和%2 的字符串。这些参数通过.arg() 函数插入。

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

%1 表示第一个参数,%2 表示第二个参数,因此该代码生成的输出如下:File 2 of 3。

请避免使用带参数的模板字符串,因为生成的字符串是在运行时而非编译时定义的。因此,翻译工具无法为这些模板字符串找到正确的翻译。

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

在 C++ 中,请使用QString::arg() 函数来替换参数:

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));
}

该代码生成的输出如下:已复制 5 个文件(共 10 个)。正在复制:somefile.txt。

处理复数形式

您可以向翻译函数传递一个额外的整数参数 (n),并在每个可翻译字符串中使用复数形式的特殊标记(%n )。

根据n 的值,翻译函数会返回不同的翻译结果,并确保目标语言中数词的语法正确。此外,所有出现的%n 都会被替换为n 的值。

例如,字符串“%n message(s) saved ”的英语和法语译文需要不同的复数形式。

n无翻译法语英语
0“已保存0条消息”“已保存0条消息”“已保存 0条消息”
1“已保存 1 条消息”“已保存 1 条消息”“已保存1条消息”
2“已保存 2 条消息”“已保存 2条消息”“已保存 2条消息”
37“已保存37条消息”“已保存 37条消息”"已保存 37条消息"

该惯用表达也适用于具有多种复数形式(例如双数形式)的目标语言。此外,对于法语等要求使用单数形式的语言,该惯用表达也能正确处理n == 0 的情况。

有关“Qt Linguist ”和“lrelease ”在翻译包含复数形式的字符串时所遵循的规则概览,请参阅《复数形式的翻译规则》。

要处理源语言中的复数形式,还需加载该语言的 TS 文件。请使用lupdate 工具的-pluralonly 命令行选项,以创建仅包含复数形式条目的 TS 文件。

或者,您可以使用lconvert 工具的-pluralonly 命令行选项,从现有TS文件中移除所有非复数形式。

QML 示例

以下 QML 代码片段将源文本转换为正确的复数形式,并将 `%n ` 替换为 `total` 的值:

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

C++ 示例

以下 C++ 代码片段将 `%n ` 替换为 `count() ` 函数返回的值:

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

使用区域数字设置

如果在指定参数时包含%L 修饰符,则该数字将根据当前区域设置进行本地化。转换时,如果已设置默认区域设置,则使用该设置;否则,使用系统范围的区域设置。

QML:使用 %L

例如,在下面的 QML 代码片段中,%L1 会根据当前所选区域(地理区域)的数字格式规范对第一个参数进行格式化:

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

如果total 是数字4321.56,在英语区域设置(语言环境)下,输出结果为4,321.56;而在德语区域设置下,输出结果为4.321,56。

C++:使用 %Ln

在 C++ 中,您可以使用 `%Ln ` 生成 `n` 的本地化表示形式。请使用 `QLocale::setDefault()` 设置默认区域设置。

日期、时间和货币的国际化

使用当地首选的格式呈现日期、时间和货币。

QML:使用 QtQml 函数

QML 没有用于格式化日期和时间的特殊字符串修饰符。相反,您需要查询当前区域设置(地理区域),并使用Date的方法来格式化字符串。

Qt.locale() 该方法返回一个Locale 对象,其中包含有关区域设置的信息。特别是,Locale.name 属性包含当前区域设置的语言和国家/地区。您可以直接使用该值,或对其进行解析以确定适合当前区域设置的内容。

以下代码片段使用Date() 获取当前日期和时间,然后将其转换为当前区域设置的字符串。接着,将该日期字符串插入%1 参数中以进行相应的翻译。

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

要对货币数值进行本地化,请使用Number类型。它与Date 类型具有类似的功能,可将数字转换为本地化的货币字符串。

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 宏(在 C++ 中)来标记可翻译的字符串字面量,以便由lupdate 工具进行提取。

QML:使用 _NOOP 函数

在 QML 中,请使用以下函数来标记可翻译的字符串字面量:

如果用户在未重启系统的情况下更改了系统语言,根据系统的不同,数组、列表模型及其他数据结构中的字符串可能不会自动刷新。若要强制在用户界面中显示文本时刷新这些字符串,则需要使用QT_TR_NOOP() 函数来声明这些字符串。 随后,在为显示对象填充内容时,需要显式地为每个文本检索相应的翻译。

例如:

ListModel {
    id: myListModel

    ListElement {
        //: Capital city of Finland
        name: QT_TR_NOOP("Helsinki")
    }
}

...

Text {
    text: qsTr(myListModel.get(0).name)
    // Get the translation of the name property in element 0
}

C++:使用 _NOOP 宏

对于完全位于函数之外的可翻译文本,请使用QT_TR_NOOP()、QT_TRID_NOOP()和QT_TRANSLATE_NOOP()宏,这些宏展开后仅保留文本本身,不包含上下文。

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]);
}

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]);
}

为译者添加注释

您可以在源代码中,在标记为可翻译的字符串之前添加注释,以阐明其用途。这些注释将包含在您交付给翻译人员的 TS 文件中。

注意: TS 文件是 XML 文件,其中包含源文本以及翻译文本的放置位置。更新后的 TS 文件将转换为二进制翻译文件,并作为最终应用程序的一部分被包含其中。

QML:使用 //: 和 //~

在下面的代码片段中,//: 这一行的文本是面向译者的主要注释。

//~ 这一行的文本是可选的补充信息。该文本的第一个单词将作为 TS 文件中 XML 元素的附加标识符,因此请确保第一个单词不属于句子的一部分。例如,注释“Context Not related to back-stepping”在 TS 文件中会被转换为<extra-Context>Not related to back-stepping 。

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++:使用注释字符

要在 C++ 中添加注释,请在代码中的 `tr() ` 调用处添加形式为 `//: ` 的注释,或通过标记注释的起始和结束位置来实现。

在以下示例中,注释与每次调用中传递给 `tr() ` 的字符串相关联:

//: This name refers to a host name.
hostNameLabel->setText(tr("Name:"));

/*: This text refers to a C++ code example. */
QString example = tr("Example");

要添加可选注释,请使用:

//~ <field name> <field contents>

字段名应由域前缀(可能是该字段所借鉴的文件格式的常规文件扩展名)、连字符以及以下划线分隔的实际字段名组成。 在 TS 文件中存储时,字段名连同前缀extra- 将构成一个 XML 元素名称。字段内容将进行 XML 转义,但除此之外将原样作为元素内容显示。您可以为每条消息添加任意数量的唯一字段。

示例:

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

注意: 在 Qt 6.10 中,使用 //= 元字符串注释为基于文本的翻译设置 ID的做法 已被废弃,并在后续版本中将被移除。

您可以使用关键字TRANSLATOR来添加翻译注释。紧跟在 TRANSLATOR 关键字前面的元数据适用于整个 TS 文件。

注意:当在 Qt Linguist 中打开TS文件时, 使用//: 标注的注释会显示在Qt Linguist 的消息编辑器中。而使用//~ 语法提供的文本属于附加信息,仅在TS文件中生成。这些内容主要用于转换为其他格式,在Qt Linguist 中被隐藏。

基于 ID 的翻译分组

您可以为每个基于 ID 的翻译分配一个标签,以便将大型项目中的基于 ID 的条目组织成较小的组。

要为基于 ID 的条目分配标签,请添加一个//@ 注释并指定标签名称,例如在 C++ 中:

//% "Open file"
//@ FileOperations
qtTrId("msg.open");

或在 QML 中:

//% "Open file"
//@ FileOperations
qsTrId("msg.open");

当您在 Qt Linguist中打开 TS 文件时,具有相同标签的ID 基于条目会被分组在一起,这与按上下文分组的文本基于条目类似。任何未标记的条目都会显示在“<unnamed label> ”下。

注意:标签名称 不会影响查找或唯一性:ID 仍保持全局唯一性,且仍可通过 `qtTrId("msgid") ` 加载,无需引用标签。标签仅用于改善翻译人员的导航体验,不会改变运行时行为。

消除相同文本的歧义

翻译系统会将 UI 文本字符串合并为唯一的条目,以避免重复翻译相同的文本。然而,某些文本虽然外观与另一文本相同,但含义可能不同。例如,在英语中,“back”既表示“向后走”,也表示物体与“front”相对的一面。 您需要向翻译系统说明这两种不同的含义,以便译者能分别创建两条独立的翻译。

QML:向 qsTr() 添加消歧符

在 QML 中,将消除歧义的字符串作为qsTr() 函数的第二个参数添加。

在下面的代码片段中,ID“not front ”将此处的“Back”文本与表示“后退”的“Back”文本区分开来:

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() 添加消歧符

在 C++ 中,调用tr() 时传入一个消除歧义的字符串。

在下面的代码片段中,IDrecipient 将收件人的姓名与发件人的姓名区分开来:

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

使键盘快捷键可翻译

最常见的键盘快捷键是指为执行某项操作而按下的键组合。对于 `standard shortcuts`,请使用标准键来请求与每个快捷键关联的特定于平台的键序列。

对于自定义快捷键,请使用易于理解的字符串,例如Ctrl+Q或Alt+F。您可以将其翻译成适合不同语言用户的相应快捷键。

如果您在应用程序中硬编码了键盘快捷键,翻译人员将无法覆盖它们。

当您在菜单项和按钮文本中使用键盘快捷键时,助记符(以下划线标记)表示按住Alt或Ctrl键并同时按下该下划线字符,可执行与单击菜单项或按下按钮相同的操作。

例如,应用程序通常在“File ”菜单中使用F作为助记符,因此您可以单击菜单项或按Alt+F来打开该菜单。 要在可翻译字符串(“File”)中定义助记符,请在字符串前加上“&”符号:"&File" 。该字符串的翻译中也应包含“&”符号,最好放在相同字符的前面。

QML 示例

在 QML 中:

Menu {
    id: fileMenu
    title: qsTr("&File")

    MenuItem {
        objectName: "quitMenuItem"
        text: qsTr("E&xit")
        onTriggered: Qt.quit()
    }
}

C++:使用 QKeySequence 类

在 C++ 中,使用 `QAction ` 和 `QKeySequence ` 对象来指定触发操作的键盘快捷键:

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

键盘快捷键的翻译与QShortcut 上下文相关联。

使用 Locale 扩展本地化功能

您可能会发现,针对不同的地理区域,某些图形或音频内容更为合适。

通常,应尽量避免对图像进行本地化。应创建全球通用的图标,而不是依赖于本地双关语或牵强的隐喻。不过,对于阿拉伯语和希伯来语区域设置,您可能需要将指向左侧和右侧的箭头图像进行左右翻转。

“区域设置”是默认的文件选择器之一,因此您可以利用文件选择功能,根据系统区域设置显示作为资源提供的不同图像。

以下各节中的 QML 和 C++ 代码示例假设您在应用程序资源中提供了以下文件,并使用语言和国家代码作为子文件夹名称:

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

QML:设置图像源

以下 QML 代码片段演示了如何根据当前区域设置选择图标源图像:

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

C++:使用 QFileSelector

以下 C++ 代码片段使用 `QFileSelector ` 根据系统区域设置从 `images ` 文件夹中选择语言图标:

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

启用翻译

TS文件名必须包含ISO语言和国家代码:

  • language是一个小写的ISO-639语言代码。
  • country表示大写的ISO-3166两位字母国家代码。

例如,qml_de.ts 将目标语言设置为德语,而qml_de_CH.ts 将目标语言设置为德语,并将目标国家设置为瑞士。lrelease 工具会生成名为qml_de.qm 和qml_de_CH.qm 的 QM 文件,应用程序会根据系统区域设置加载这些文件。

QML:使用 QQmlApplicationEngine

在 QML 中,使用 `QQmlApplicationEngine ` 可自动从包含主 QML 文件的目录下的 `i18n ` 子目录中加载翻译文件。翻译文件名必须以 `qml_` 为前缀,例如 `qml_en_US.qm`。有关如何设置多语言应用程序,请参阅以下 CMake 代码片段:

...
find_package(Qt6 6.5 REQUIRED COMPONENTS Quick LinguistTools)
qt_standard_project_setup(REQUIRES 6.5 I18N_TRANSLATED_LANGUAGES ja_JP)

qt_add_qml_module(appmultilingual_demo
    URI multilingual_demo
    QML_FILES
        Main.qml
)

qt_add_translations(appmultilingual_demo
    TS_FILE_BASE qml
    TS_FILE_DIR i18n
    RESOURCE_PREFIX /qt/qml/multilingual_demo/i18n
)
...

当QJSEngine::uiLanguage 或Qt.uiLanguage 属性的值发生变化时,应用程序会重新加载翻译。以下代码片段演示了当用户点击按钮时动态更改语言的方法:

Button {
    anchors.centerIn: parent
    text: qsTr("Translate")
    onClicked: {
        Qt.uiLanguage = Qt.uiLanguage === "en" ? "ja" : "en"
    }
}

C++:使用 QTranslator

在 C++ 中,TS 文件名必须包含应用程序名称。例如:app_de_DE.ts 。

通常,您的 Qt C++ 应用程序的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();
}

对于支持翻译的应用程序,您需要创建一个 `QTranslator ` 对象,根据用户在运行时 UI 显示的区域设置进行翻译(load ),并将该翻译器对象安装到应用程序中。

为动态语言切换做好准备

Qt Widgets 和Qt Quick 都使用Qt 的事件系统来通知类翻译变更。

LanguageChange 当您使用QCoreApplication::installTranslator() 函数安装新翻译时,会发布事件。其他应用程序组件也可以通过向小部件或从Item 类型派生的 QML 类型发布LanguageChange 事件,强制它们更新自身。

默认情况下,LanguageChange 事件会传播到所有顶级窗口,并由此向下传播至整个由Item派生的控件或QML类型树。

Qt Widgets: 重写 changeEvent

QWidget 子类的默认事件处理程序会响应QEvent::LanguageChange 事件,并在必要时调用changeEvent() 函数。

要使 Qt Widgets 控件能够感知已安装的 `QTranslator ` 对象的变更,请重写控件的 `changeEvent()` 函数,以检查该事件是否为 `LanguageChange ` 事件,并使用 `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 Widgets Designer UI文件(.ui)和uic 时,您可以读取新的翻译文件并直接调用ui.retranslateUi(this) :

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

若要传递其他变更事件,请调用该函数的默认实现。

已安装的翻译器列表可能会因LocaleChange 事件而发生变化,或者应用程序可能会提供一个用户界面,允许用户更改当前的应用程序语言。

QML:针对从 Item 派生的类型的事件重写

对于没有注册任何自定义 C++ 类型的普通 QML应用程序,使用 QQmlApplicationEngine即可触发所有翻译绑定的更新。

但是,如果您注册了一个从 `QQuickItem` 派生的类型,且其某个属性暴露了翻译后的文本(或以其他方式依赖于语言),则应重写其 `event method ` 方法,并在其中发出该属性的 `change` 信号(如果是可绑定属性,则调用 `notify `)。例如:

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);
    }
};

这可确保 QML 中使用该属性的任何绑定都会被重新评估,并考虑语言变更的情况。

通用的 QObject 派生类:使用事件过滤器

有些类既未继承自QWidget ,也未继承自QQuickItem ,但可能仍需要处理语言变更事件。在这种情况下,请在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;
    }
};

当类提供了后续将在用户界面中显示的翻译字符串(例如,自定义的item model )时,或者当类作为 Widget 或 Quick Item 的容器,因此负责将事件转发给它们时,这可能是必要的。

C++ 代码的其他注意事项

以下各节提供了有关在可翻译应用程序中使用 Qt C++ 类和函数的更多信息:

对所有用户可见的文本使用 QString

QString 内部采用Unicode编码,因此您可以使用熟悉的文本处理操作来透明地处理世界上所有语言。此外,由于所有向用户显示文本的Qt函数都将QString 对象作为参数,因此不存在从char * 到QString 的转换开销。

定义翻译上下文

对于 `QObject ` 及其每个 `QObject ` 子类而言,其翻译上下文即为类名本身。若您继承了 `QObject`,请在类定义中使用 `Q_OBJECT ` 宏来覆盖翻译上下文。该宏将上下文设置为子类的名称。

例如,以下类定义包含Q_OBJECT 宏,实现了使用MainWindow 上下文的新tr() 函数:

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow();
    ...

如果在类定义中未使用Q_OBJECT ,则上下文将从基类继承。例如,由于Qt XML中所有基于QObject 的类都提供了一个上下文,因此,如果调用一个未定义Q_OBJECT 宏的新QWidget 子类的tr() 函数,该子类将使用QWidget 上下文。

翻译非 Qt 类

对于未继承QObject 或未使用Q_OBJECT 宏的类中的字符串,您必须为lupdate 提供额外信息。要为非 Qt 类添加翻译支持,可以使用Q_DECLARE_TR_FUNCTIONS() 宏。例如:

class MyClass
{
    Q_DECLARE_TR_FUNCTIONS(MyClass)

public:
    MyClass();
    ...
};

这将为该类提供tr() 函数,您可以使用这些函数来翻译与该类相关的字符串,并使lupdate 能够在源代码中查找可翻译的字符串。

此外,您还可以使用lupdate 和Qt Linguist 能够识别的特定上下文来调用QCoreApplication::translate() 函数。

翻译位于 QObject 子类之外的文本

如果引用的文本不在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);
}

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.