本页内容

基于文本 ID 的翻译

文本 ID 翻译机制是一种用于国际化和本地化的行业级系统。应用程序中的每段文本都有一个唯一的标识符(文本 ID),您可以在源代码中使用该标识符代替文本本身。这使得管理大量翻译文本变得更加容易。

使用文本 ID 进行国际化

当使用文本 ID 代替纯文本时,应用程序国际化的总体方法相同,但具体细节略有不同:

  1. 基于文本 ID 的翻译系统所使用的函数和宏与纯文本系统不同。您需要使用 qsTrId() 函数代替 qsTr(),使用QT_TRID_NOOP() 宏代替QT_TR_NOOP(),以及使用QT_TRID_N_NOOP() 宏代替QT_TR_N_NOOP()。
  2. 请将文本 ID 用作用户界面字符串,而非纯文本字符串。例如,qsTrId("id-back-not-front")
  3. 您无法为文本 ID 指定上下文参数,因此拼写相同但含义不同的词需要单独的文本 ID。例如,qsTrId("id-back-backstep") 将后退操作Back与id-back-not-front 中的Back 区分开来。
  4. 由于基于文本 ID 的翻译不允许使用上下文名称,Qt Linguist 会在文件中以不带上下文名称的形式列出这些 ID。
  5. 在开发版本的用户界面中,工程英语文本会通过//% 注释进行标识。若未包含此注释,用户界面中将显示文本 ID。当文本包含参数时,这一点尤为重要。//% 注释需要在字符串中包含参数指示符。例如://% "Number of files: %1"
  6. 在纯文本系统中,为译员提供额外信息的//: 注释是可选的。但在基于文本 ID 的系统中,这些额外信息变得至关重要,因为如果没有它们,您只有文本 ID,而译员在缺乏进一步上下文的情况下可能无法据此进行合理的翻译。 您可以使用长而描述性的文本 ID 而不添加注释,但注释通常更易于理解。

下面的并排代码片段展示了基于文本 ID 和基于纯文本的翻译之间的对比:

基于文本 ID基于纯文本
Text {
    id: backTxt;
    //: The back of the object, not the front
    //% "Back"
    //~ Context Not related to back-stepping
    text: qsTrId("id-back-not-front");
}
Text {
    id: backTxt;
    //: The back of the object, not the front
    //~ Context Not related to back-stepping
    text: qsTr("Back","Not front")
}

使用文本 ID 进行本地化

使用文本 ID 进行本地化的流程与纯文本本地化基本相同。

您需要使用lupdate工具生成 TS 文件,并在其中添加翻译。翻译文件中的源值将是文本 ID 而非纯文本,因此您需要使用描述性文本 ID 或添加详细的注释(或两者兼备),以确保翻译的准确性。

上文中的基于文本 ID 的用户界面文本示例,在 .ts 文件中生成以下内容:

<message id="id-back-not-front">
    <source>Back</source>
    <extracomment>The back of the object, not the front</extracomment>
    <translation type="unfinished"></translation>
    <extra-Context>Not related to back-stepping</extra-Context>
</message>

如果某个文本尚无翻译(在开发后期之前通常都是这种情况),用户界面中将显示文本 ID 而不是正确的文本。 为了提高应用程序在测试阶段的可用性,您可以让lrelease 使用工程英语源文本(来自//% 中的注释)作为翻译文本,并用某些标记(例如感叹号 (!))进行标注,以便您能识别出尚未翻译的文本。

基于 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") ` 加载,而无需引用标签。标签仅用于改善翻译人员的导航体验,不会改变运行时行为。

自动生成标签

无需手动指定标签名称,您可以使用占位符根据代码结构自动生成标签:

  • //@ <context> - 自动使用完整上下文(命名空间::类)
  • //@ <class> - 仅自动使用类名(不包含命名空间)
  • //@ <file> - 自动使用源文件名
组合占位符

可以将占位符与自定义文本结合,以创建更具描述性的标签:

  • //@ <file>:<class> - 组合文件名和类名:filehandler.cpp:FileHandler
  • //@ <context>_customSuffix - 添加后缀:MyApp::FileHandler_customSuffix
  • //@ module_<file>_<class>-label - 自定义前缀和后缀:module_filehandler.cpp_FileHandler-label
  • //@ <context>:<file> - 结合文件上下文:MyApp::FileHandler:filehandler.cpp

例如,在 C++ 中:

namespace MyApp {
class FileHandler : QObject {
    Q_OBJECT
    void open() {
        //% "Open file"
        //@ <context>
        qtTrId("msg.open"); // Label: MyApp::FileHandler

        //% "Save file"
        //@ <class>
        qtTrId("msg.save"); // Label: FileHandler

        //% "Export"
        //@ <file>
        qtTrId("msg.export"); // Label: filehandler.cpp
    }
};
}

或在 QML 中:

Item {
    id: myComponent
    Component.onCompleted: {
        //% "Loading"
        //@ <context>
        qsTrId("msg.loading") // Label: <component-name>

        //% "Ready"
        //@ <file>
        qsTrId("msg.ready") // Label: main.qml

        //% "Initialized"
        //@ <file>:<context>-state
        qsTrId("msg.init") // Label: main.qml:<component-name>-state
    }
}

自动标签在大型项目中尤为有用,因为在众多文件中手动管理标签名称可能会非常繁琐。它们能确保根据代码结构进行一致的分组,并向译者提示翻译内容将用于何处。

注意: 在 C++ 代码中,若在 任何类之外使用<class> ,系统会发出警告,并且生成的标签中将使用<unnamed> 。

注意: 在 QML中使用 <class> 会触发警告,且生成的标签将使用<unnamed> ,因为 QML 组件并非类。请改用<context> 获取组件名称,或使用<file> 获取 QML 文件名。

注意:自动 标签仅适用于基于 ID 的翻译(qtTrId ,qsTrId )。若在基于文本的翻译(tr ,qsTr )中使用自动标签,将触发警告,且该标签会被忽略。

CMake 配置

使用 CMake 构建时,请为 .ts 文件使用前缀qml_ 。 例如:qml_en.ts 。在 CMakeLists.txt 文件中,添加qt_add_translations函数,将 *.ts 文件作为TS_FILES 的值列出,并将 RESOURCE_PREFIX 的值设置为项目 main.qml 文件的 URI 后跟 /i18n:

qt_add_translations(${CMAKE_PROJECT_NAME}
    TS_FILES i18n/qml_de_DE.ts i18n/qml_en_US.ts
    RESOURCE_PREFIX Main/i18n
)

qmake 的高级用法

对于针对大量语言环境的项目,您可以从 .pro 文件中移除 TRANSLATIONS 信息,转而通过一个独立的脚本管理翻译。该脚本可以针对每个目标分别调用lrelease 和lupdate 。

更新过程可通过脚本实现,示例如下:

lupdate -recursive <project-dir> -ts <project-dir>/i18n/myapp-text_en_GB.ts
lupdate -recursive <project-dir> -ts <project-dir>/i18n/myapp-text_en_US.ts
...

最终 .qm 文件的生成可通过脚本实现,示例如下:

lrelease <project-dir>/i18n/myapp-text_en_GB.ts
lrelease <project-dir>/i18n/myapp-text_en_US.ts
...

© 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.