翻译应用程序¶
Qt Linguist¶
Qt Linguist 及其相关工具可用于为应用程序提供翻译。
Qt Linguist 示例 示例说明了这一点。该示例非常简单,它有一个菜单并显示了一个支持多选的编程语言列表。
翻译工作通过将消息字符串传递给查找翻译的函数调用来完成。每个QObject实例都提供了一个tr()函数用于此目的。还有一个QCoreApplication.translate()用于将翻译文本添加到非QObject类中。
Qt 自带包含错误信息和标准对话框标题的翻译。
语言学家示例中有许多消息被包含在self.tr()中。
响应选择更改显示的状态栏消息根据计数使用复数形式:
count = len(self._list_widget.selectionModel().selectedRows())
message = self.tr("%n language(s) selected", "", count)
示例的翻译工作流程如下:
翻译的消息使用lupdate工具提取,
生成基于XML的.ts文件:
pyside6-lupdate main.py -ts example_de.ts
如果 example_de.ts 已经存在,它将会更新为代码中添加的新消息。
如果项目中有表单文件(.ui)和/或QML文件(.qml),
它们也应该传递给pyside6-lupdate工具:
pyside6-lupdate main.py main.qml form.ui -ts example_de.ts
由pyside6-uic从表单文件生成的源文件不应被传递。
pyside6-project 的 lupdate 模式也可以用于此。它收集所有源文件并在 .pyproject 文件中给出 .ts 文件时运行 pyside6-lupdate:
pyside6-project lupdate .
.ts 文件使用 Qt Linguist 进行翻译。完成后,文件被转换为二进制形式(.qm 文件):
pyside6-lrelease example_de.ts -qm example_de.qm
pyside6-project 将在 .pyproject 文件中提供 .ts 文件时自动构建 .qm 文件:
pyside6-project build .
为了避免必须分发.qm文件,建议将它们与图标和其他应用程序资源一起放入Qt资源文件中(参见using_qrc_files)。
资源文件linguist.qrc在:/translations下提供了example_de.qm:
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="translations">
<file>example_de.qm</file>
</qresource>
</RCC>
在运行时,需要使用 QTranslator 类加载翻译:
path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
translator = QTranslator(app)
if translator.load(QLocale.system(), 'qtbase', '_', path):
app.installTranslator(translator)
translator = QTranslator(app)
path = ':/translations'
if translator.load(QLocale.system(), 'example', '_', path):
app.installTranslator(translator)
代码首先加载为Qt提供的翻译,然后从资源中加载应用程序的翻译。
然后可以在德语中运行该示例:
LANG=de python main.py
GNU gettext¶
GNU gettext 模块 可用于为应用程序提供翻译。
GNU gettext 示例 示例说明了这一点。该示例非常简单,它有一个菜单并显示了一个支持多选的编程语言列表。
翻译工作通过将消息字符串传递给查找翻译的函数调用来完成。通常会将主要的翻译函数别名为_。对于包含根据计数变化的复数形式的句子(“{0} items(s) selected”),有一个特殊的翻译函数。它通常别名为ngettext。
这些函数在顶部定义:
import gettext
# ...
_ = None
ngettext = None
然后按如下方式分配:
src_dir = Path(__file__).resolve().parent
try:
translation = gettext.translation('example', localedir=src_dir / 'locales')
if translation:
translation.install()
_ = translation.gettext
ngettext = translation.ngettext
except FileNotFoundError:
pass
if not _:
_ = gettext.gettext
ngettext = gettext.ngettext
这指定了我们的翻译文件具有基本名称 example,并且
将在源代码树中的 locales 下找到。代码将尝试
加载与当前语言匹配的翻译。
需要翻译的消息看起来像:
file_menu = self.menuBar().addMenu(_("&File"))
状态栏消息在选择更改时显示的复数形式取决于计数:
count = len(self._list_widget.selectionModel().selectedRows())
message = ngettext("{0} language selected",
"{0} languages selected", count).format(count)
ngettext() 函数接受单数形式、复数形式和计数。
返回的字符串仍然包含格式化占位符,因此需要通过 format() 进行处理。
为了将消息翻译成德语,首先创建一个模板文件(.pot):
mkdir -p locales/de_DE/LC_MESSAGES
xgettext -L Python -o locales/example.pot main.py
此文件包含一些通用的占位符,可以用适当的值替换。然后将其复制到de_DE/LC_MESSAGES目录中。
cd locales/de_DE/LC_MESSAGES/
cp ../../example.pot .
需要进一步调整以适应德语复数形式和编码:
"Project-Id-Version: PySide6 gettext example\n"
"POT-Creation-Date: 2021-07-05 14:16+0200\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
下面,可以给出翻译后的消息:
#: main.py:57
msgid "&File"
msgstr "&Datei"
最后,.pot 被转换为其二进制形式(机器对象文件,
.mo),需要部署:
msgfmt -o example.mo example.pot
然后可以在德语中运行该示例:
LANG=de python main.py