Qt 本地化(翻译)
翻译流程大致是这样的:首先源代码产生 ts 文件,然后送给 Qt Linguist(Qt 语言家)这个 Qt 自带的小工具进行处理产生 qm 翻译文件,最后源代码里加载这个 qm 翻译文件。
凡是你要进行翻译的文本都要用 tr() 函数来包裹。这个 tr() 是 QObject 类的一个函数,用它包裹的文本会被 Qt Linguist(Qt 语言家)捕捉到从而进行翻译工作。或者你也可以这样理解,用 tr() 包裹的文本会添加到 ts 文件中。关于 ts 文件在下文会说到。例如我们的示例工程就是这样写的:
QMessageBox msgBox;
msgBox.setWindowTitle(tr("HelloWorld"));
QML 的翻译是用 qsTr() 来代替 tr() 函数。Design(设计师)中的的文本默认是可翻译的,不用担心是否会被捕捉到。
生成 ts 文件
在. pro 文件中添加如下代码:
TRANSLATIONS = \
language.zh_CN.ts
注意 ts 文件名,标明区域语言对运行时加载何种语言会很有用。如果要生成多个 ts 文件,只需要在行末加 , 在下一行添加 ts 文件名即可。Qt Linguist 会根据 ts 文件名自动设置区域。ts 文件的命名方式下文再介绍。
在 Qt Creator 的菜单栏中依次点击 Tools->External->Linguist->Update Translations(lupdate),就会在源代码文件所在的目录生成 ts 文件。
翻译并生成 qm 文件
在工具栏中找到 Linguist,打开 ts 文件并逐条翻译后保存,ts 文件制作完毕,接下来就是 qm 文件的生成。
qm 文件生成可以直接在 Qt Linguist 里点击 File->Release,或者在 Qt Creator 中点击 Tools->External->Linguist->Release Translations(lrelease) 都可以。
至此,qm 文件生成完毕。
源代码中加载翻译文件
加载翻译文件的代码很简单,需要注意的是要在创建窗口前加载翻译文件。
#include "MainWindow.h"
#include <QApplication>
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator qtTranslator;
QString dir = a.applicationDirPath() + "/" + "translations";
if (qtTranslator.load(QLocale(), "language", ".", dir, ".qm"))
{
a.installTranslator(&qtTranslator);
}
MainWindow w;
w.show();
return a.exec();
}
基本流程就是新建 QTranslator 对象,通过 load 函数加载 qm 文件,然后将 QTranslator 对象添加到 QApplication 对象中。这里我把翻译文件放在子目录 translations 中,如果检测到系统是大陆地区的简体中文的话则加载翻译文件,否则不加载。其中的重点就是 load 函数,让我们来看看 load 函数的用法。
bool QTranslator::load(const QLocale &locale, const QString &filename, const QString &prefix = QString(), const QString &directory = QString(),const QString &suffix = QString())
Loads filename + prefix + ui language name + suffix (".qm" if the suffix is not specified), which may be an absolute file name or relative to directory. Returns
true
if the translation is successfully loaded; otherwise returnsfalse
.The previous contents of this translator object are discarded.
If the file name does not exist, other file names are tried in the following order:
- File name without suffix appended.
- File name with ui language part after a "_" character stripped and suffix.
- File name with ui language part stripped without suffix appended.
- File name with ui language part stripped further, etc.
For example, an application running in the locale with the following ui languages - "es", "fr-CA", "de" might call
load(QLocale(), "foo", ".", "/opt/foolib", ".qm")
. load() would replace '-' (dash) with '_' (underscore) in the ui language and then try to open the first existing readable file from this list:
- /opt/foolib/foo.es.qm
- /opt/foolib/foo.es
- /opt/foolib/foo.fr_CA.qm
- /opt/foolib/foo.fr_CA
- /opt/foolib/foo.de.qm
- /opt/foolib/foo.de
- /opt/foolib/foo.fr.qm
- /opt/foolib/foo.fr
- /opt/foolib/foo.qm
- /opt/foolib/foo.
- /opt/foolib/foo
On operating systems where file system is case sensitive, QTranslator also tries to load a lower-cased version of the locale name.
This function was introduced in Qt 4.8.
第一个参数是获取系统的区域环境代码;第二个参数是文件名,不包括所在的目录;第三个参数是语言区域代码的前缀(分隔符);第四个参数是文件所在的目录,注意这里用的是绝对路径,相对路径我没有试过;第五个参数是文件后缀,一般为. qm。
一般的语言区域代码由两部分组成:语言 - 区域。例如上文中的 fr_CA,fr 表示法语,CA 表示加拿大,加起来就是加拿大法语。也就是一种语言会有多个地区的区别。再举个中文的例子:
- zh-CN 简体中文,*
- zh-HK 繁体中文,香港特别行政区
- zh-MO 繁体中文,澳门特别行政区
- zh-SG 简体中文,新加坡
- zh-TW 繁体中文,*
一个完整的翻译文件名由:文件名 + 分隔符 + 语言区域代码 + 后缀组成。以上文中的引用部分为例,如果有多个翻译文件或者文件名不完整缺失的话:
- 按照检测到的语言区域顺序优先读取文件。
- 如果文件名相同,优先加载有后缀的文件。
- 如果没有符合语言区域代码的文件,则放弃匹配区域,加载符合的语言的文件。
- 如果连语言都不符合,则加载不包含语言区域代码的文件。
最后一步
以 Release 方式运行代码后,将生成的 exe 文件放到一个新文件夹中,然后打开 Linguist(语言家)下面的命令行工具 Qt5.12.1,切换到 .exe 文件所在路径,运行
windeployqt 文件名. exe
windeployqt 会自动把运行 exe 文件需要的动态链接库(dll)复制过来,同时生成的还有 translations 文件夹,这个文件夹是用来存放翻译文件的。我们把里面的自动生成的翻译文件删掉,然后把 language.zh_CN.qm 复制到里面。这样就大功告成,软件在大陆内以简体中文显示,在其他地方以英文显示(源代码里是英文)。