概述

用Qt开发多语言界面应用程序, 主要包括以下几个步骤:

  • 在程序设计阶段, 程序代码中每一个用户可见的字符串都用tr()函数封装, 以便Qt提取界面字符串用于生成翻译资源文件。用UI设计器可视化设计窗体时统一用一种语言,如汉语。
  • 在项目配置文件(.pro文件)中设置需要导出的翻译文件(.ts文件)名称,使用lupdate工具扫描项目文件中需要翻译的字符串,并生成翻译文件。
  • 使用Qt的Linguist程序打开生成的翻译文件,将程序中的字符串翻译为需要的语言,如将所有中文字符串翻译为英文。
  • 使用lrelease工具编译翻译好的翻译文件,生成更为紧凑的.qm文件。
  • 在应用程序中用QTranslate调用不同的”.qm“文件,实现不同的语言界面。

一、tr()函数的使用

为了让Qt能自动提取程序中用户可见的字符串:

  • 在使用Q_OBJECT宏定义的类或QObject的子类,可直接使用tr()函数对每个字符串进行封装;否则使用QObject::tr()
  • 在类定义中用 Q_DECLARE_TR_FUNCTIONStr()函数添加到类中,再直接调用 tr() 函数

    1.1 定义:

    1. static QString tr(const char *sourceText, const char *comment = Q_NULLPTR, int n = -1);
  • sourceText 是源字符串

  • *comment 为翻译者提供额外信息的字符串

1.2 注意事项

1.2.1 尽量使用常量字符串,不要使用字符串变量。

tr() 函数中应直接传递字符串常量,而不是用变星传递字符串,如下面的代码使用了字符串变量,使用 lupdate 工具提取项目中的字符串时, 将不能提取“不能删除记录” 这个字符串。

  1. // 不能提取该字符串
  2. const char* errorStr = "不能删除记录";
  3. QString str1 = tr(errorStr);

1.2.2 使用字符串变量时需要用 QT_TR_NOOP() 宏进行标记

若要在 tr() 函数中使用字符串变量,需要在定义字符串的地方用 QT_TR_NOOP() 宏进行标记,这在使用字符串数组时比较有用,例如:

  1. QComboBox* comboBox = new QComboBox(this);
  2. const char* cities[4] = {
  3. QT_TR_NOOP("Beijing"),
  4. QT_TR_NOOP("Shanghai"),
  5. QT_TR_NOOP("Qingdao"),
  6. QT_TR_NOOP("Wuhan")
  7. };
  8. for (int i = 0; i < 4; i++) {
  9. comboBox->addItem(cities[i]);
  10. }

1.2.3 tr()不能使用拼接的动态字符串

tr()不能使用拼接的动态字符串。
例如:
下面的用法是错误的:

  1. QLabel* label = new QLabel(this);
  2. for (int i = 0; i < 4; i++) {
  3. // 仅能识别 第一个字: "第"
  4. QString text = QT_TR_NOOP("第" + QString::number(i) + "行");
  5. label->setText(text);
  6. }

正确的使用方式

  1. QLabel* label = new QLabel(this);
  2. for (int i = 0; i < 4; i++) {
  3. // 识别出 "第%1行"
  4. label->setText(tr("第%1行").arg(i));
  5. }

翻译的字符串是”第%1行”,然后再用QStringarg()去替换占位符%1的内容。

1.2.4 QT_NO_CAST_FROM_ASCII的作用

在一个需要翻译为多语言的应用程序中,如果编写程序时忘了对某个字符串使用 tr() 函数,lupdate 生成的翻译资源文件就会遗漏这个字符串。为了避免这种疏忽错误,可以在项目配置文件(. pro 文件)中添加如下的定义:

  1. DEFINES+= QT_NO_CAST_FROM_ASCII

这样在编译时,会禁止从 const char*QString 的隐式转换,强制每个字符串都必须使用tr()QLatinlString() 封装,避免出现遗漏未翻译的字符串。

1.3 生成语言翻译文件

要生成多语言界面相关的翻译文件,需要以下三步:

  • 对每个字符串都使用 tr() 函数封装,
  • 在项目配置文件( .pro 文件)中使用 TRANSLATIONS 定义语言翻译文件( .ts 文件)
  • 使用 lupdate 工具生成语言翻译文件。

    1. TRANSLATIONS = test_cn.ts \
    2. test_en.ts

    使用:lupdate

  • 点击:Tools -> External -> Qt语言家 -> UpdateTranslations(lupdate)

  • TRANSLATIONS设置的文件不存在,则会自动生成;若文件已存在,则更新这些文件的内容

    1.4 使用 Qt Linguist 翻译ts文件

    生成的ts文件包含了项目源程序和UI界面所有字符串,使用Qt Linguist可以将这些字符串翻译未需要的语言版本。在Qt安装后的程序组里可以找到Qt Linguist软件。

    如: C:\Qt5.15\5.15.2\msvc2019_64\bin\linguist.exe C:\Qt5.7\msvc2015\bin\linguist.exe

1.4.1 第一次打开一个ts文件,会要求选择源语言和目标语言:

image.png

1.4.2 进行翻译

image.png

  • 字符串 列表里列出了从项目的UI窗口和代码文件中提取的字符串,
  • 短语和表单 会显示窗口界面的预览或字符串在源程序中出现的代码段。
  • 译文编辑框,在此填写字符串对应的英文译文。

1.5 调用翻译文件改变界面语言

1.5.1 生成qm语言
项目所有字符串都翻译后,通过lrelease生成与ts文件对应的qm文件,这是更为紧凑的翻译文件。
lrelease的位置:

Tools -> External -> Qt语言家 -> Release Translations(lrelease)

1.5.2 项目启动时设置界面语言

使用 QTranslator 类设置界面的不同语言版本,需在应用程序启动时设置界面语言翻译文件,即在 main() 函数中进行处理。

  1. #include "widget.h"
  2. #include <QApplication>
  3. #include <QSettings>
  4. #include <QString>
  5. #include <QTranslator>
  6. QTranslator* trans = nullptr;
  7. QString readSetting();
  8. int main(int argc, char* argv[])
  9. {
  10. QApplication a(argc, argv);
  11. trans = new QTranslator;
  12. QString curLang = readSetting(); //读取语言设置
  13. curLang = QObject::tr("EN");
  14. if (curLang == QObject::tr("EN"))
  15. trans->load(QObject::tr("test_cn.qm"));
  16. else
  17. trans->load(QObject::tr("test_en.qm"));
  18. a.installTranslator(trans);
  19. Widget w;
  20. w.show();
  21. return a.exec();
  22. }
  23. QString readSetting()
  24. {
  25. // 从注册表读取上次设置的语言
  26. QString organization = QObject::tr("WWB-Qt");
  27. QString appName = QObject::tr("test");
  28. QSettings settting(organization, appName);
  29. QString language = settting.value(QObject::tr("Language"), QObject::tr("EN")).toString();
  30. return language;
  31. }