3.1 案例5 怎样实现国际化
本案例对应的源代码目录:src/chapter03/ks03_01。程序运行效果见图3-1。
图3-1 案例5运行效果
Qt提供的方案其实也很简单:显示文本时调用特定的翻译接口,然后需要开发者提供一个中英文对照的qm文件(二进制翻译文件),最后在程序启动时加载这个翻译文件。下面介绍具体步骤。
(1)在ui界面或代码中使用英文。
(3)在pro文件中添加TRANSLATIONS配置。
(4)使用lupdate命令,提取待翻译内容到ts文件。
(5)使用linguist(Qt语言家)在ts文件中添加中英文对照翻译,并导出qm文件。
(6)程序启动时加载qm文件。
现在分步骤进行详细介绍。
1.在UI文件或代码中使用英文
首先,在UI文件或者在编程时需要显示汉字的地方使用英文。在UI中显示文本时直接键入英文即可,在编程中显示文本时需要调用类的tr()接口进行翻译:
m_pLabel2->setText(tr("this is translated by source code")); |
tr()接口是QObject类的接口,所以调用tr()的类要从QObject类派生。如果待翻译的文本所在的类不是QObject的派生类,那么请使用QObject类或它的派生类来调用tr()接口。
2.在提供翻译的类中编写Q_OBJECT宏
如果某个类中有文本需要翻译,那么除了要求该类从QObject类派生,还需要使用Q_OBJECT宏。假设类名为CDialog,就需要在CDialog类定义开头添加Q_OBJECT宏,如代码清单3-1所示。
代码清单3-1
class CDialog : public QDialog { Q_OBJECT ... }; |
如果不编写Q_OBJECT宏,那么在使用lupdate命令提取ts文件时将会报错。
ks03_01/dialog.cpp:7: Class 'CDialog' lacks Q_OBJECT macro Updating 'ks03_01.ts'... |
该错误提示的含义是:在更新ks03_01.ts文件时发现类CDialog缺少Q_OBJECT宏。
3.在pro文件中添加TRANSLATIONS配置
ts文件是Qt用来进行中英文翻译的文本文件,通过Qt的lupdate命令提取得到ts文件,然后由人工完成翻译。如果想得到ts文件,需要在ks03_01.pro中添加如下内容:
TRANSLATIONS = ks03_01.ts |
ks03_01.ts是lupdate命令提取得到的ts文件名称。在配置TRANSLATIONS时也可以带文件路径。
TRANSLATIONS = $$TRAIN_SRC_PATH/translations/ks03_01.ts |
这表示将lupdate命令提取的ts文件放到项目的src/translations目录下,文件名称为ks03_01.ts。
4.使用lupdate命令,提取待翻译内容到ts文件
完成pro文件中的TRANSLATIONS配置后,执行lupdate命令。
lupdate ks03_01.pro
lupdate将读取pro文件中的TRANSLATIONS配置并读取源代码文件,将待翻译的文本提取到TRANSLATIONS配置项所指示的ts文件。如果未配置TRANSLATIONS将导致lupdate命令执行失败。
5.使用linguist在ts文件中添加中英文对照翻译,并导出qm文件
启动linguist,选择【文件】|【打开】菜单项打开ts文件。然后选择【上下文】中的类名,在【字符串】的列表框里选中某行源文,将翻译后的文本写在【Translation to 简体中文(中国)】下面的文本框内(见图3-2)。
图3-2 Qt语言家界面
注意:标点符号也要一一翻译。
完成一个源文的翻译后,单击源文前面的?(见图3-3)并将其改为√。
图3-3 未翻译的源文
完成全部翻译工作后,可以查看图3-3中【上下文】列表框的内容,检查是否还有未翻译的项目(未翻译的源文前面显示“?”,已翻译的显示√)。完成所有翻译后,将ts文件发布为二进制的qm文件。方法是选择【文件】|【另外发布为】菜单项,然后选择发布目录即可。比如,可以将qm文件发布到 $$(PRJROOT)/system/lang目录下。
6.程序启动时加载qm文件
在main()函数或其他合适的位置加载qm文件。
1)首先包含所需的头文件(见代码清单3-2)
代码清单3-2
#include <QApplication> #include <QTranslator> // 国际化 #include <QLibraryInfo> // 国际化 |
2)加载Qt自带的翻译文件
Qt自带的翻译文件用来实现Qt类中文本的翻译。如代码清单3-3所示,在标号①处得到本机的语言环境,在标号②处构建QTranslator对象,然后在标号③处安装翻译文件。标号③处处调用了QTranslator的load()接口,该接口的参数1用来描述翻译文件名,参数2用来描述翻译文件所在目录。
代码清单3-3
// 安装qt自带的中文翻译 const QString localSysName = QLocale::system().name();// 获取本机系统的语言环境 ① QScopedPointer<QTranslator> qtTranslator(new QTranslator(QCoreApplication::instance())); ② if (qtTranslator->load(QStringLiteral("qt_") + localSysName, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) ③ QCoreApplication::installTranslator(qtTranslator.take()); } |
Qt的翻译文件并未把所有英文都翻译成中文(比如从Designer中拖出的QDialogButtonBox中的OK、Cancel按钮上的文本),开发者需要自己翻译这些英文。翻译Qt自带文本的方法是将这些文本按照ts文件的格式键入ts文件(见代码清单3-4)。<context>和</context>之间是QPlatformTheme类的翻译内容。name用来描述类名,每一组message用来描述一个源文和翻译的对照,其中source表示源文,translation表示翻译,location表示包含源文的代码行(可能不止一处)。完成人工翻译后,用linguist进行发布即可。
代码清单3-4
<context> <name>QPlatformTheme</name> <message> <location filename="../src/widgets/qdialogbuttonbox.cpp" line="+42"/> <location line="+18"/> <source>OK</source> </message> <message> <location line="+54"/> <source>Cancel</source> <translation>取消</translation> </message> </context> |
为什么QDialogButtonBox中的按钮没有被翻译成中文呢?这是因为在Qt的源代码里,为QDialogButtonBox的按钮进行翻译时,使用的是QPlatformTheme类。
QCoreApplication::translate ("QPlatformTheme" , "OK" ); |
这里的ts文件可以作为Qt的补丁。可以将上述ts文件的内容专门保存为一个公共的ts文件,然后把这个文件提供给各项目组使用。
3)加载项目的翻译文件
加载完Qt自带的翻译文件后,应加载项目的翻译文件,见代码清单3-5。
代码清单3-5
QString strPath = qgetenv("TRAINDEVHOME"); // 获取环境变量所指向的路径 strPath += "/system/lang"; // $TRAINDEVHOME/system/lang/ks03_01.qm QScopedPointer<QTranslator> gpTranslator(new QTranslator(QCoreApplication::instance())); if (gpTranslator->load("ks03_01.qm", strPath)) { ① QCoreApplication::installTranslator(gpTranslator.take()); } |
国际化在Qt软件开发过程中是非常重要的组成部分。即使目前没有计划将产品推向国际市场,软件开发者也应该养成使用国际化进行编程的习惯。因为一旦将来需要将产品推向国际市场时,无须对源代码做任何修改就能马上推出产品,这会减少很多不必要的工作量。
----------------------------------------------------------------------------------------------------------------------------------------------