概述
用Qt开发多语言界面应用程序, 主要包括以下几个步骤:
- 在程序设计阶段, 程序代码中每一个用户可见的字符串都用
tr()
函数封装, 以便Qt提取界面字符串用于生成翻译资源文件。用UI设计器可视化设计窗体时统一用一种语言,如汉语。 - 在项目配置文件(
.pro
文件)中设置需要导出的翻译文件(.ts
文件)名称,使用lupdate
工具扫描项目文件中需要翻译的字符串,并生成翻译文件。 - 使用Qt的
Linguist
程序打开生成的翻译文件,将程序中的字符串翻译为需要的语言,如将所有中文字符串翻译为英文。 - 使用
lrelease
工具编译翻译好的翻译文件,生成更为紧凑的.qm
文件。 - 在应用程序中用
QTranslate
调用不同的”.qm
“文件,实现不同的语言界面。
一、tr()函数的使用
为了让Qt能自动提取程序中用户可见的字符串:
- 在使用Q_OBJECT宏定义的类或QObject的子类,可直接使用
tr()
函数对每个字符串进行封装;否则使用QObject::tr()
在类定义中用
Q_DECLARE_TR_FUNCTIONS
把tr()
函数添加到类中,再直接调用tr()
函数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
工具提取项目中的字符串时, 将不能提取“不能删除记录” 这个字符串。
// 不能提取该字符串
const char* errorStr = "不能删除记录";
QString str1 = tr(errorStr);
1.2.2 使用字符串变量时需要用 QT_TR_NOOP()
宏进行标记
若要在 tr()
函数中使用字符串变量,需要在定义字符串的地方用 QT_TR_NOOP()
宏进行标记,这在使用字符串数组时比较有用,例如:
QComboBox* comboBox = new QComboBox(this);
const char* cities[4] = {
QT_TR_NOOP("Beijing"),
QT_TR_NOOP("Shanghai"),
QT_TR_NOOP("Qingdao"),
QT_TR_NOOP("Wuhan")
};
for (int i = 0; i < 4; i++) {
comboBox->addItem(cities[i]);
}
1.2.3 tr()
不能使用拼接的动态字符串
tr()
不能使用拼接的动态字符串。
例如:
下面的用法是错误的:
QLabel* label = new QLabel(this);
for (int i = 0; i < 4; i++) {
// 仅能识别 第一个字: "第"
QString text = QT_TR_NOOP("第" + QString::number(i) + "行");
label->setText(text);
}
正确的使用方式
QLabel* label = new QLabel(this);
for (int i = 0; i < 4; i++) {
// 识别出 "第%1行"
label->setText(tr("第%1行").arg(i));
}
翻译的字符串是”第%1行”,然后再用QString
的arg()
去替换占位符%1的内容。
1.2.4 QT_NO_CAST_FROM_ASCII的作用
在一个需要翻译为多语言的应用程序中,如果编写程序时忘了对某个字符串使用 tr()
函数,lupdate
生成的翻译资源文件就会遗漏这个字符串。为了避免这种疏忽错误,可以在项目配置文件(. pro
文件)中添加如下的定义:
DEFINES+= QT_NO_CAST_FROM_ASCII
这样在编译时,会禁止从 const char*
到 QString
的隐式转换,强制每个字符串都必须使用tr()
或 QLatinlString()
封装,避免出现遗漏未翻译的字符串。
1.3 生成语言翻译文件
要生成多语言界面相关的翻译文件,需要以下三步:
- 对每个字符串都使用
tr()
函数封装, - 在项目配置文件(
.pro
文件)中使用TRANSLATIONS
定义语言翻译文件(.ts
文件) 使用
lupdate
工具生成语言翻译文件。TRANSLATIONS = test_cn.ts \
test_en.ts
使用:
lupdate
:点击:Tools -> External -> Qt语言家 -> UpdateTranslations(lupdate)
- 若
TRANSLATIONS
设置的文件不存在,则会自动生成;若文件已存在,则更新这些文件的内容1.4 使用
生成的ts文件包含了项目源程序和UI界面所有字符串,使用Qt Linguist
翻译ts
文件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文件,会要求选择源语言和目标语言:
1.4.2 进行翻译
- 字符串 列表里列出了从项目的UI窗口和代码文件中提取的字符串,
- 短语和表单 会显示窗口界面的预览或字符串在源程序中出现的代码段。
- 译文编辑框,在此填写字符串对应的英文译文。
1.5 调用翻译文件改变界面语言
1.5.1 生成qm语言
项目所有字符串都翻译后,通过lrelease生成与ts文件对应的qm文件,这是更为紧凑的翻译文件。
lrelease的位置:
Tools -> External -> Qt语言家 -> Release Translations(lrelease)
1.5.2 项目启动时设置界面语言
使用 QTranslator
类设置界面的不同语言版本,需在应用程序启动时设置界面语言翻译文件,即在 main()
函数中进行处理。
#include "widget.h"
#include <QApplication>
#include <QSettings>
#include <QString>
#include <QTranslator>
QTranslator* trans = nullptr;
QString readSetting();
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
trans = new QTranslator;
QString curLang = readSetting(); //读取语言设置
curLang = QObject::tr("EN");
if (curLang == QObject::tr("EN"))
trans->load(QObject::tr("test_cn.qm"));
else
trans->load(QObject::tr("test_en.qm"));
a.installTranslator(trans);
Widget w;
w.show();
return a.exec();
}
QString readSetting()
{
// 从注册表读取上次设置的语言
QString organization = QObject::tr("WWB-Qt");
QString appName = QObject::tr("test");
QSettings settting(organization, appName);
QString language = settting.value(QObject::tr("Language"), QObject::tr("EN")).toString();
return language;
}