一、多语言界面设计
1.多语言界面设计概述
有些软件需要开发多语言界面版本,如中文版和英文版,并且在软件里可以方便地切换界面语言。Qt 为多语言界面提供了很好的支持,使用 Qt 的一些规则和工具,可以很方便地为应用程序开发提供多语言界面支持。
Qt 开发多语言界面应用程序的步骤:
- 在程序设计阶段,程序代码中每一种用户可见的字符串都,以便 Qt 提取界面字符串用于生成翻译资源文件。用 Ul 设计器可视化设计窗体时统一用一种语言,如汉语。
- 在项目配置文件(.pro文件),,
- 使用工具扫描项目文件中需要翻译的字符串,并生成翻译文件。
- 使用 打开生成的翻译文件,将程序中的字符串翻译为需要的语言,如将所有中文字符串翻译为英文
- ==使用 lrelease 工具编译翻译好的翻译文件,生成更为紧凑的 “.qm” 文件
- 在应用程序中用 QTranslator 类调用不同的 “.qm” 文件,实现不同的语言界面。
2.tr函数的使用
为了让 Qt 自动提取程序中用户可见的字符串,对于每个字符串都需要使用 tr() 函数封装。tr() 是 QObject 类的一个静态函数,在使用了 Q_OBJECT
宏定义的类或 QObject 的子类中,都可以直接使用 tr()
函数,否则需要使用 QObject::tr()
进行调用 。或者在类定义中用 Q_DECLARE_TR_FUNCTIONS
宏把 tr()
函数添加到类中之后,再直接调用 tr() 函数。
tr()
函数的定义是:
[static] QString QObject::tr(const char *sourceText, const char *disambiguation = nullptr, int n = -1)
-
函数说明:
如果存在 sourceText 的翻译版本,则返回翻译后的文本;如果没有则返回 sourceText 的 UTF-8 编码字符串。
-
参数说明:
-
参数
sourceText
:表示源字符串 -
参数
disambiguation
:是为翻译者提供额外信息的字符串,用于对一些容易混淆的地方作说明 -
参数
n
:可选参数,用于处理含有复数形式的文本
-
-
示例:
LabCellPos = new QLabel(tr("当前单元格"), this); QMessageBox::information(this, tr("信息"), tr("信息提示? "), QMessageBox::Yes); QString str1 = tr("左右", "大约的意思"); QString str2 = tr("左右", "掌握、控制的意思");
-
注意事项:
-
尽量使用常量字符串,不要使用字符串变量。在 tr() 函数中应该直接传递字符串常量,而不是用变量传递字符串
-
使用字符串变量时需要用
Qt_TR_NOOP()
宏进行标记。若要在tr()
函数中使用字符串变量,需要在定义字符串的地方用Qt_TR_NOOP()
进行标记,这在使用字符串数组时比较有用,例如: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(tr(cities[i]));
-
tr() 函数不能使用拼接的动态字符串
错误的方式:
LabCellPos->setText(tr("第" + QString::number(current.row()) + "行"));
正确的方式:
LabCellPos->setText(tr("第 %1 行").arg(current.row()));
用 QString 的 arg() 去替换占位符 “%1” 的内容。
-
Qt_NO_CAST_FROM_ASCII
的作用。在一个需要翻译为多语言的应用程序中,如果编写程序时忘了对某个字符串使用tr()
函数,lupdate
生成的翻译资源文件就会遗漏这个字符串。为了避免这种疏忽错误,可以在项目配置文件(.pro文件)中添加如下的定义:DEFINES += Qt_NO_CAST_FROM_ASCII
这样在编译时,会禁止从 const char* 到 QString 的隐式转换,强制每个字符串都必须使用
tr()
或QLatin1String()
封装,避免出现遗漏未翻译的字符串。
-
3. 生成语言翻译文件
要生成多语言界面相关的翻译文件,除了对每个字符串都使用 tr() 函数封装之外,还需要在项目配置文件(.pro文件)中使用 TRANSLATIONS 定义语言翻译文件(.ts文件),并使用 lupdate
工具生成语言翻译文件。
首先,在项目的配置文件中增加如下的设置语句:
TRANSLATIONS = trans_cn.ts \
trans_en.ts
这里设置生成两个语言翻译文件 “trans_cn.ts” 和 “trans_en.ts” 分别是中文和英文翻译文件。文件名称可以任意设计,只要有所区分即可。
然后,为了使用lupdate
工具来扫描源代码中的tr()
函数调用,并生成.ts
格式的翻译文件。需要对项目中的字符串全部采用 tr()
函数封装,对于不符合 tr() 函数使用规则的地方进行修改。例如:
LabCellPos->setText(tr("当前单元格:%1 行,%2 列").arg(current.row()).arg(current.column()));
在项目设计期间,任何时候都可以使用 lupdate
工具生成或更新翻译文件,方法是单击 Qt Creator 主菜单的 “Tools”–>“External” --> “Qt 语言家” --> “Update Translations(lupdate)” 菜单项,若项目的源程序目录没有 trans_cn.ts 和 trans_en.ts 这两个文件,就会自动生成,如果文件已经存在 ,则会更新这两个文件的内容。
4.使用 Qt Linguist 翻译 ts 文件
生成的 trans_cn.ts 和 trans_en.ts 文件内包含了项目源程序和 UI 界面里的所有字符串,使用 Qt Linguist 软件可以将这些字符串翻译为需要的语言版本。trans_cn.ts
是中文界面的翻译文件,由于源程序的界面就是用中文设计的,所以无需再翻译。trans_en.ts
是英文翻译文件,需要将提取的所有中文字符串翻译为英文。
使用 Qt Linguist 软件打开文件 trans_en.ts
,当第一次打开一个 ts 文件时,Linguist 会出现如下所示的语言设置对话框,用于设置目标语言和所在国家和地区。这个对话框也可以通过 Linguist 主菜单 “编辑“ --> “翻译文件设置” 菜单项调出。
打开 trans_en.ts 文件后的 Qt Linguist 软件界面如下:
- 左侧 “上下文” 列表里列出项目中的所有窗口或类
- “字符串” 列表列出了从项目的 UI 窗口和代码文件中提取的字符串
- 右侧 “短语和表单” 会显示窗口界面的预览或字符串在源程序中出现的代码段
在“字符串” 列表中选中一个源文后,在下方会出现译文编辑框,在此处填写字符串对应的英文译文。Linguist 可以同时打开项目的多个 ts 文件,在选中一个源文后,在下方会出现对应的多个语言的译文编辑框,可以同时翻译为多个语言版本。最后将 ts 文件进行保存。
5.生成 qm 文件
使用 Qt Linguist 软件编辑翻译文件,将所有字符串都翻译并保存。在 Qt Creator 中单击主菜单项 “Tools” --> “External” --> “Qt 语言家” --> "Release Translations(lrelease) ",会在项目源程序目录下生成与 ts 文件对应的 qm 文件, 这是更为紧凑的翻译文件。
6.调用翻译文件改变界面语言
在源程序中使用 QTranslator 类设置界面的不同语言版本,需要在应用程序启动(即 main() 函数中) 时设置界面语言翻译文件。代码如下:
QTranslator *trans=NULL;
QString readSetting();
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
trans=new QTranslator;
QString curLang=readSetting(); //读取语言设置
if (curLang=="EN")
trans->load("D:/Project/QtProject/trans/trans_en.qm");
else
trans->load("D:/Project/QtProject/trans/trans_cn.qm");
app.installTranslator(trans);
MainWindow w;
w.show();
return app.exec();
}
QString readSetting()
{
QString organization="WWB-Qt";//用于注册表,
QString appName="trans"; //HKEY_CURRENT_USER/WWB-Qt/trans
QSettings settings(organization,appName);//创建
settings.setValue("Language","EN"); //调整这个值可分别创建英文与中文界面
QString Language=settings.value("Language","CN").toString();//读取Language键的值
return Language;
}
- readSetting() 函数,用于从注册表里读取设置的界面语言版本,注册表里数据的读取和写入使用到 QSettings 类。
- main() 函数中,调用 readSetting() 函数从注册表中读取界面语言版本,然后用 load() 函数载入对应的翻译文件,最后,调用
installTranslator()
函数为应用程序安装翻译器,实现需要的界面版本。
动态切换语言:
在软件运行时可以动态切换语言,即无需重启软件就可以切换界面语言。一个应用程序只能加载一个翻译器,因为在 main() 函数里已经加载了一个翻译器,所以需要先移除当前的翻译器,才能重新创建新的翻译器,加载翻译文件,并为应用程序重新加载新翻译器。完成这些后还必须调用 UI 的 retranslateUi()
函数来刷新界面。
void MainWindow::on_actLang_CN_triggered()
{//中文界面
qApp->removeTranslator(trans);
delete trans;
trans=new QTranslator;
trans->load("C:/Users/85733/Desktop/QT5.12Samp2019/chap16Aux/samp16_1MultiLanguage/samp16_1_cn.qm");
qApp->installTranslator(trans);
ui->retranslateUi(this);
QSettings settings("WWB-Qt","trans"); //注册表键组
settings.setValue("Language","CN"); //界面语言,汉语
}
void MainWindow::on_actLang_EN_triggered()
{//英文界面
qApp->removeTranslator(trans);
delete trans;
trans=new QTranslator;
trans->load("C:/Users/85733/Desktop/QT5.12Samp2019/chap16Aux/samp16_1MultiLanguage/samp16_1_en.qm");
qApp->installTranslator(trans);
ui->retranslateUi(this);
QSettings settings("WWB-Qt","trans"); //注册表键组
settings.setValue("Language","EN"); //界面语言,英语
}
大型软件的多语言设计:
大型的软件在重新设置语言版本后,一般要求重新启动软件才生效 ,在程序启动时根据上次的设置加载一次翻译器即可。代码如下:
QTranslator *trans=NULL;
QString readSetting();
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
trans=new QTranslator;
QString curLang=readSetting(); //读取语言设置
if (curLang=="EN")
trans->load("D:/Project/QtProject/trans/trans_en.qm");
else
trans->load("D:/Project/QtProject/trans/trans_cn.qm");
app.installTranslator(trans);
MainWindow w;
w.show();
return app.exec();
}
QString readSetting()
{
QString organization="WWB-Qt";//用于注册表,
QString appName="trans"; //HKEY_CURRENT_USER/WWB-Qt/trans
QSettings settings(organization,appName);//创建
QString Language=settings.value("Language","CN").toString();//读取Language键的值
return Language;
}
当点击工具栏按钮进行中文和英文的界面切换时,只修改注册表的值,不删除当前的翻译器。
void MainWindow::on_actLang_CN_triggered()
{//中文界面
QSettings settings("WWB-Qt","trans"); //注册表键组
settings.setValue("Language","CN"); //界面语言,汉语
}
void MainWindow::on_actLang_EN_triggered()
{//英文界面
QSettings settings("WWB-Qt","trans"); //注册表键组
settings.setValue("Language","EN"); //界面语言,英语
}