在软件国际化(i18n)和本地化(l10n)处理中,PO 文件是一个核心概念。对于参与过开源项目的翻译工作,或者作为开发者处理过多语言支持的人来说,很可能都接触过这种文件格式。本文将详细剖析 PO 文件的结构和内容。
什么是 PO 文件?
PO 代表 Portable Object(可移植对象)。它们是 文本文件,主要设计用于 供人类阅读和编辑。PO 文件的核心作用是将程序源代码中的原始、可翻译字符串与其在特定目标语言中的翻译关联起来。
每个 PO 文件通常只对应一种特定的目标语言。这意味着如果一个软件包支持多种语言,那么每种语言都会有一个对应的 PO 文件。
与 PO 文件密切相关的是 MO 文件(Machine Object)。MO 文件是 二进制文件,旨在 供程序在运行时读取 以快速检索翻译。它们由 msgfmt
工具从 PO 文件编译生成。PO 文件格式的设计灵感来源于 Uniforum 开发、Sun 在 Solaris 系统中首次实现的 NLS 标准。
PO 文件条目结构
一个 PO 文件由许多“条目”(entry)组成。每个条目都包含一个原始的未翻译字符串及其在目标语言中的翻译。虽然理解其整体结构很重要,但使用 PO 文件编辑器(如 Emacs 的 PO 模式)时,大多数格式细节都会由编辑器自动处理。
一个典型的 PO 文件条目 schematic 结构如下所示:
white-space
# translator-comments
#. extracted-comments
#: reference...
#, flag...
#| msgid previous-untranslated-string
msgid untranslated-string
msgstr translated-string
让我们分解这个结构中的主要部分:
1. 空白和注释 (white-space and comments)
条目可以包含空白行和以 #
开头的注释行。注释提供了关于条目的附加信息。根据开头的不同字符,注释有不同类型:
#
:翻译人员注释 (translator-comments)。这是翻译人员可以自由添加和编辑的注释,用于记录翻译过程中的思考或疑问。
#.
:提取的注释 (extracted-comments)。通常包含从源代码中提取的、与字符串相关的上下文信息。
#:
:引用 (reference)。这些行通常指示原始字符串在源代码中的位置,格式通常是 filename:line
。这些引用由 xgettext
等工具自动生成。虽然可以使用 --no-location
选项禁止生成这些行, 但来源指出这样做会使熟悉技术的翻译人员难以理解消息的上下文。默认情况下会生成引用信息,并且可以通过 --add-location=type
选项控制详细程度 (full
, file
, never
)。
#,
:标志 (flag)。这些标志提供关于条目的元信息,通常也是由程序(如 xgettext
或 msgmerge
)自动添加的。
#|
:表示旧的、不再使用的原始字符串 (previous-untranslated-string)。这通常在 PO 文件更新时由 msgmerge
添加,以帮助翻译人员理解字符串是如何变化的。
2. msgid
这是原始的、未翻译的字符串,它直接取自程序源代码。
3. msgstr
这是 msgid
字符串在特定目标语言中的翻译。
msgid
和 msgstr
字符串在 PO 文件中通常使用双引号 ("
) 括起来,特殊字符(如双引号本身或换行符)使用反斜杠 (\
) 进行转义。同样,翻译人员通常无需手动处理这些引用和转义的细节,PO 文件编辑器会负责。
处理长字符串
如果 msgid
或 msgstr
字符串很长,可以将其分割成多行书写,并通过连接多个双引号括起来的字符串来实现。例如:
msgid "" "Here is an example of how one might continue a very long string\n" "for the common case the string represents multi-line output.\n"
这里的空字符串 ""
是为了格式兼容性,因为 msgid
或 msgstr
关键字后必须紧跟一个字符串(即使是空字符串)在同一行。
头部条目 (Header Entry)
每个 PO 文件的第一个条目是一个特殊的头部条目,其 msgid
是一个空字符串 (msgid ""
)。这个条目不包含程序中实际的字符串翻译,而是用于存放整个翻译文件的元信息。
头部条目通常包含以下重要字段(这些字段的值很多由 msginit
程序在创建新 PO 文件时自动填充):
Project-Id-Version
:软件包的名称和版本。
PO-Revision-Date
:此 PO 文件的修订日期。
Last-Translator
:最后修改此文件的翻译人员信息。
Language-Team
:翻译团队的名称。
Language
:目标语言标识。语言命名约定通常是 ll_CC
(语言代码_国家/地区代码)或简单的 ll
(语言代码)。例如,在德国使用的德语标识可以是 de_DE
或更常用的 de
。此字段不包含 .encoding
或 @variant
后缀。所以,如果您的区域设置名称是 de_DE.UTF-8
,在 PO 文件中通常只写 de
。
MIME-Version
, Content-Type
, Content-Transfer-Encoding
:与字符编码相关的字段。
Content-Type
字段通常包含charset=ENCODING
,指定文件的字符编码。如果输入 POT 文件(PO 模板文件)是 UTF-8 且包含非 ASCII 字符,msginit
会保留 UTF-8 编码。如果 POT 文件是纯 ASCII,则使用区域设置的编码。PO 文件支持的字符编码限于 GNU libc 和 GNU libiconv 支持的列表。来源列举了许多支持的编码,包括 ISO-8859-_ 系列、各种 CP 编码、GB2312、EUC-JP、UTF-8 等。对于某些语言,特别是需要使用特定的引号字符(如弯引号 U+201C, U+201D 等)时,即使区域设置是 ISO-8859-_,也推荐使用 UTF-8 编码创建 PO 文件,因为 UTF-8 能表示更丰富的字符。Content-Transfer-Encoding
应设置为8bit
。
Plural-Forms
:这是一个可选字段,仅当 PO 文件包含复数形式时才需要。它定义了该语言的复数形式规则。格式为 nplurals=N; plural=EXPRESSION;
。nplurals
表示复数形式的数量,plural
后是一个 C 语言语法的表达式,用于根据数字 n
计算应使用的复数形式(索引从 0 开始)。翻译人员需要根据此信息为 msgid_plural
填写对应的 msgstr
, msgstr
, msgstr
等。msginit
包含了已知复数规则的数据库,可以帮助自动生成此字段。
Report-Msgid-Bugs-To
:用于报告原始字符串 (msgid
) 错误的电子邮件地址。
标志 (Flags)
标志出现在以 `#,’ 开头的行中。它们提供了关于条目属性的元信息。许多标志是程序自动生成的,不应由人工添加。一些重要的标志包括:
c-format
/ no-c-format
:指示 msgid
和 msgstr
是否应被视为 C 格式字符串。msgfmt
会检查带有 c-format
或 possible-c-format
标志的条目,验证其格式说明符(如 %d
)是否匹配。这些标志通常由 xgettext
添加。还有针对其他语言的类似格式标志,如 kde-format
, boost-format
, tcl-format
, perl-format
, php-format
, gcc-internal-format
等。
fuzzy
:表示该翻译是“模糊的”,可能需要人工修订。msgmerge
在更新 PO 文件时,如果发现原始字符串发生变化,可能会将旧的翻译标记为 fuzzy
。请注意,只有未标记为 fuzzy
且已填充 msgstr
的条目(即已翻译条目)会被 msgfmt
编译成 MO 文件。
obsolete
:表示原始字符串在程序源代码中已不再使用。这样的条目通常会被注释掉。
range
:可能表示源代码中的引用位置是一个范围。
上下文 (Contexts)
为了区分相同的原始字符串在不同上下文中的不同含义和翻译,PO 文件支持使用 msgctxt
字段。这允许同一个 msgid
字符串拥有不同的翻译。
文件有效性
为了使 PO 文件有效,必须遵循一定的规则。最重要的规则是,没有 msgctxt
的条目不能有重复的 msgid
(或 msgid_plural
)。同样,具有相同 msgctxt
的条目也不能有重复的 msgid
(或 msgid_plural
)。
使用编辑器
虽然理解 PO 文件格式的细节很有益处,但在实际翻译工作中,强烈推荐使用专门的 PO 文件编辑器。这些编辑器内置了对 PO 格式的支持,可以处理格式细节、引用、转义,并提供方便的功能,如导航、验证、模糊匹配处理等。常见的 PO 编辑器包括 Lokalize (KDE), Gtranslator (GNOME), Poedit, OmegaT, Virtaal Translation Editor, 以及 Emacs 的 PO 模式 和 vim 的支持。Emacs PO 模式还提供了诸如条目间移动、批量验证文件格式、查看源代码上下文 等高级功能。
总结
PO 文件作为 GNU gettext 国际化流程中的核心文件格式,通过结构化的文本格式,有效地存储了原始字符串及其在特定语言中的翻译,并辅以注释、引用、标志等信息。它设计为人可读和编辑,是连接程序员和翻译人员的重要桥梁。通过 GNU gettext 工具链中的 xgettext
(提取字符串创建模板)、msginit
(创建新翻译文件)、msgmerge
(更新翻译文件) 和 msgfmt
(编译为机器可读的 MO 文件) 等工具的配合,以及使用专门的 PO 文件编辑器,极大地简化了软件的国际化和本地化工作流程。