本地化是当今软件开发中一个重要但通常被忽视的部分。 大多数应用的作者,无论这些应用是商业应用还是开源应用,都希望为他们的应用赢得大量用户。 这意味着越来越多地需要在多个地区支持多种语言,而且通常需要在一个地区支持多种语言(可以将其视为在加拿大共存的法语和英语)。
很长一段时间以来,Qt 都有一个使应用易于本地化的框架,其工具可以帮助您避免在应用中硬编码字符串,还有一个名为Qt Languist的 GUI 来帮助管理翻译。 在本章中,我们将介绍 Qt 的本地化策略,讨论 Qt 提供的三种工具(lupdate
、lrelease
和 Qt Languist)以及如何使用它们,以及在编写应用以利用 Qt 的本地化框架时需要做些什么。
在本章中,我们将介绍以下主题:
- 理解本地化的任务
- 标记用于本地化的字符串
- 使用 QLanguist 本地化您的应用
- 使用 QLocale 本地化特殊参数-货币和日期
本章的技术要求包括 Qt 5.12.3、MinGW 64 位、Qt Creator 4.9.0 和 Windows 10。
如果您想要在全球销售您的产品,本地化是其重要功能。 当用户看到他们的母语在一款软件中被显示和使用时,他们更有可能会依恋它,成为你的忠实客户之一。 然而,本地化并不总是一个容易实现的特性,至少在 Qt 引入了一种更简单的方式之前是这样。
本地化应用有几个阶段,在整个项目生命周期中通常会重叠。
下图显示了这些阶段的交互方式:
这些阶段如下:
- 在编写应用时,将需要本地化的字符串放入特定函数中(请参见步骤 5),以便 Qt 可以识别需要本地化的字符串。
- 定期提取应用中的所有字符串,并将它们交给翻译人员进行翻译。
- 翻译器为应用中的字符串提供翻译。
- 您可以使用要支持的每种语言的翻译字符串编译翻译文件。
- C++ 和 QML 的
tr
和qsTr
函数允许您识别应用中需要本地化的字符串。 Qt 提供了四个工具来简化这些阶段。 lupdate
命令生成应用中需要本地化的字符串的列表。- 翻译者使用 Qt Languist 为您的应用中的字符串提供翻译。
lrelease
命令从 Qt Creator 获取翻译后的字符串,并将它们打包成供您的应用使用的格式。
软件开发是迭代的,本地化也不例外。 小型项目可能更喜欢只本地化一次或两次,等到应用接近完成后再提交应用字符串进行本地化。 大型应用或拥有专职翻译人员的大型公司可能更喜欢迭代的方法,在整个应用开发过程中多次经历本地化周期。 Qt 支持这两种型号。
我们已经了解了本地化的重要性以及如何在 Qt 中实施本地化。 在下一节中,我们将学习如何使用 C++ 方法完成此操作。
回到第 1 章,Qt Creator 入门,我告诉过您要始终使用tr
和qsTr
函数将字符串标记为本地化:tr
用于 C++,qsTr
用于 QML 字符串。 这样做有两个关键优势:
- 它使 Qt 能够找到每个需要本地化的字符串。
- 如果在应用中安装 Qt Translator 对象并提供翻译文件,则用这些函数包装的字符串将自动替换为它们的本地化等效项。
让我们更详细地研究一下tr
的用法。 所有在声明中包含Q_OBJECT
宏的 Qt 对象都包含tr
函数。 你已经看到了它的一个论点,如下所示:
button = new QPushButton(tr("&Quit"), this);
字符串中的前导&
不是用于tr
函数,而是用于键盘快捷键;您可以在字母前面加上&
来指定键盘快捷键,它将获得默认系统(对于 Windows,Alt、对于 Apple,cmd和对于 Linux,Alt是一个组合键)。 如果该字符串的翻译版本未出现在应用的当前转换表中,tr
函数将使用您在用户界面中作为字符串传递的字符串,或者使用当前转换表中的字符串(如果存在)。
tr
函数可以接受第二个参数,即tr
用于可能需要不同翻译的同一字符串的消歧上下文。 如下所示:
tr("&Copy", "Menu");
此函数还可以处理带复数的字符串,如下所示:
tr("%n item(s) replaced", "", count);
根据count
的值和区域设置,返回不同的字符串。 因此,本地英语翻译可以返回"0 items replaced"
、"1 item replaced"
、"2 items replaced"
等,而法语翻译可以返回"0 item remplacé"
、"1 item remplacé"
、"2 items remplacés"
等。
在 QML 中,您只需使用qsTr
函数,该函数的工作方式与 C++ 中的tr
方法完全相同。
在本节中,我们了解了如何标记字符串,让 Qt 知道哪个字符串需要本地化。 接下来,我们将学习如何在 Qt 中运行本地化过程,并根据用户的语言偏好显示正确的语言。
一旦使用tr
或qsTr
标记了字符串,就需要生成这些字符串的表,以便 Qt 语言学家进行本地化。 可以使用lupdate
命令实现这一点,该命令获取.pro
文件并遍历源代码以查找要本地化的字符串,并为 Qt 语言学家创建需要翻译的字符串的 XML 文件。 您需要为您想要支持的每种语言执行一次此操作。 在执行此操作时,最好系统地命名生成的文件;一种方法是使用项目文件的名称,后跟破折号,然后是该语言的 ISO-639-2 语言代码。
下面是一个具体的例子。 本章使用QtLinguistExample
;我们可以使用如下命令运行lupdate
,以创建要转换为世界语(ISO-639-2 语言代码,ePO)的字符串列表:
% lupdate -pro .\QtLinguistExample.pro -ts .\QtLinguistExample-epo.ts
Don't forget that the %
character is the Command Prompt, which might differ from system to system.
这里,-pro
文件表示.pro
文件包含要扫描以查找要翻译的字符串的源列表,而-ts
参数表示要写入的翻译文件的名称。 当然,您需要在您的道路上使用lupdate
。 如何设置路径将取决于您使用的是 Windows、MacOSX 还是 Linux,以及 Qt 的安装位置。 Qt 的某些安装可能会自动更新您的路径,而其他安装可能不会这样做。 例如,在我的 Windows 机器上,我可以在C:\Qt\5.13.0\msvc2017_64\bin\lupdate.exe
处找到lupdate
。
.ts
文件是一个带有标记的 XML 文件,用于指示要翻译的字符串、它们在应用源代码中的上下文等。 Qt 语言学家会将翻译保存到它的输出文件中,该文件的名称也带有一个 QM 后缀,但是不要担心:lupdate
足够聪明,如果您在提供一些翻译之后再次运行它,它不会覆盖现有的翻译。
您还可以轻松地从 Qt Creator 运行命令提示符,方法是在项目面板中右键单击.pro
命令文件,然后选择 Build Environment(构建环境)选项,以自动配置命令提示符相对于项目目录的路径,如下所示:
除了使用命令外,您还可以直接从 Qt Creator 中使用lupdate
和lrelease
,方法是转到工具|外部|语言学家|更新翻译(Lupdate)或发布翻译(Lrelease)。 请注意,这将更新或释放所有翻译文件。 如果您只想更新或发布特定的文件/语言,命令仍然是您最好的朋友。
以下屏幕截图显示了lupdate
工具在应用菜单上的位置:
Qt Language ist 是一个 GUI 应用;在启动该应用时,您将看到一个与下一个屏幕截图非常相似的屏幕:
首先,您需要打开您通过导航到文件|打开文件并选择翻译文件生成的.ts
文件。 系统将提示您输入目标语言,然后给出找到的字符串列表:
您或您的翻译人员只需遍历每个字符串,然后以翻译的语言输入相应的字符串。 这样做时,您可以在最右边的窗格中看到源代码中字符串的上下文;从中捕获字符串的源代码所在的行会高亮显示。
Qt 语言学家可以让您跟踪已翻译的字符串以及仍需翻译的字符串。 每个字符串左侧的图标可以是以下图标之一:
- 黑色问号,表示字符串尚未翻译
- 黄色问号,表示该字符串没有通过 Qt 语言学家的所有验证测试,但您忽略了这些失败
- 一个感叹号,表示您提供的字符串没有通过 Qt 语言学家的验证测试
- 黄色的复选框,表示您提供了翻译,但 Qt Creator 可能发现翻译有问题
- 绿色的复选框,表示字符串已翻译完毕,可以开始使用了
Qt Languist 提供了一些简单的验证测试,比如确保具有printf
样式参数的字符串在每次翻译中都有相同数量的参数。
Qt 语言学家还支持词汇书;您可以下载包含已本地化为目标语言的常用字符串的词汇书。
在任何时候,您都可以通过运行lrelease
来生成要包含在应用中的转换文件。 例如,要为世界语字符串创建一个,我们将使用lrelease
,如下所示:
% lrelease .\QtLinguistExample-epo.ts .\QtLinguistExample-epo.qm
这将获取传入的.ts
文件,并生成包含字符串的.qm
文件。 .qm
文件是 Qt 在呈现应用的过程中直接使用的高度压缩的二进制文件。
我们已经了解了如何使用 Qt Languist 将所有文本导出到列表中,并允许您和您的翻译人员进行翻译。 接下来,我们将继续在我们的应用中包含本地化文本。
为了向应用中的tr
和qsTr
函数提供翻译后的字符串,您的应用需要包括一个QTranslator
对象来读取.qm
文件,并将提供给tr
和qsTr
的字符串替换为翻译后的对应字符串。
我们可以在您的主要入口点函数中执行此操作,如下所示:
QApplication a(argc, argv);
QTranslator translator;
bool result = translator.load("QtLinguistExample-epo.qm");
a.installTranslator(&translator);
// Other window setup stuff goes here
return a.exec();
此代码分配一个QTranslator
对象,并在将其安装到QApplication
对象之前将指定的翻译文件加载到转换器中。 在本例中,我们对语言进行了硬编码,以便将其本地化为世界语。
请注意,如果您希望支持系统选择的区域设置,则可以选择这样做:
QString locale = QLocale::system().name();
QTranslator translator;
translator.load(QString("QtLinguistExample-") + locale);
这里的QLocale
类是用于管理系统区域设置的类。 在这里,我们使用它来确定系统的区域设置,然后尝试加载系统当前区域设置的本地化字符串文件。
要实现这一点,应用的.qm
文件需要可由应用定位。 它们应该在输出目录中;在开发过程中,一种方法是在 Qt Creator 中关闭影子构建,在项目窗格的 Build 和 Settings 下。 构建应用安装程序是一项特定于平台的任务,这超出了本书的范围,为此,您需要在应用二进制文件中包含.qm
个文件。
For more information on Qt Linguist, refer to its manual at https://doc.qt.io/qt-5/qtlinguist-index.html.
接下来,我们将了解如何本地化一些特殊参数以满足我们的要求。
您可能需要做的一件常见的事情是本地化货币和日期。 Qt 使这一点变得简单,尽管解决方案在您仔细考虑之前并不明显。 让我们试试看吧。
- 您需要了解
QString arg
方法。 这将用其参数的格式化版本替换转义数字。 例如,如果我们编写以下内容:
QString s = QString("%1 %2").arg("a").arg("b");
然后,s
将包含字符串"a b"
。
- 您需要了解
QLocale
的toString
方法,该方法以特定于区域设置的方式格式化其参数。 因此,我们可以写下以下内容:
QString currencyValue = QString("%1 %2")
.arg(tr("$")).arg(QLocale::toString(value, 'g', 2)
它使用tr
本地化货币符号,并使用QLocale
类的静态方法toString
将货币值转换为带有区域设置特定小数分隔符(在美国和加拿大为句点,在欧洲为逗号)的字符串。
日期格式类似;QLocale
的toString
方法重载了QDateTime
、QDate
和QTime
参数,因此只需编写以下代码:
QDateTime whenDateTime = QDateTime::currentDateTime();
QString when = QLocale::toString(whenDate);
这将获取当前日期和时间并将其存储在whenDateTime
中,然后使用区域设置的默认格式将其转换为字符串。 toString
方法可以采用第二个参数来确定输出格式;它是以下参数之一:
QLocale::LongFormat
:这使用长版本的月份和日期名称。QLocale::ShortFormat
:这使用月和日名称的简短版本。QLocale::NarrowFormat
:这提供了日期和时间的最窄格式。
就这样。 我们不仅学习了如何使用 Qt 本地化文本,还学习了如何本地化货币和日期等特殊字符。
使用 Qt 语言学家和 Qt 中的本地化框架,可以轻松地使用 Qt 本地化应用。 不过,要使用该框架,您必须将字符串标记为在源代码中使用tr
或qsTr
进行本地化,无论它们出现在哪里。 完成此操作后,您可以使用 Qt 的lupdate
命令创建要使用 QLanguist 进行翻译的字符串的源文件,然后为每个字符串提供翻译。 提供翻译后,使用lrelease
编译它们,然后通过在应用的主函数中安装QTranslator
对象并加载由lrelease
生成的翻译表,将它们包含在应用中。
在本章中,我们学习了如何标记可翻译文本,以便 Qt 知道哪些文本需要本地化。 接下来,我们还学习了如何使用 Qt Language ist 将这些文本导出到列表中,以便您和您的翻译人员可以轻松地针对每种语言进行编辑。 然后,我们了解了如何将翻译后的文本重新加载到 Qt 应用中,并根据用户的喜好显示它们。 最后,我们还学习了如何本地化特殊字符,如货币和日期。
在下一章中,我们将介绍 Qt Creator 支持的软件开发的另一个重要方面:使用 QML Profiler 和 Valgrind 进行性能分析。