如何翻译PO文件而不影响应用程序运行

OpenL Team 2026/7/3
如何翻译PO文件而不影响应用程序运行

目录

PO 文件看起来像普通文本文件,但一旦翻译的 %s 出错、遗漏复数形式或修改了 msgid,你的应用就可能崩溃。请按照以下流程翻译面向用户的字符串,同时保持 gettext 结构不变。

不要把整个文件粘贴到普通文本翻译器里。PO 文件属于源码相关文件:其中的词语可以翻译,但文件结构、占位符、注释和复数索引必须保持不变。

方法一:使用 PO 文件翻译工具

如果你想要最快速且安全的初稿,并且不想手动编辑 msgid / msgstr 对,应选择此方法。

  1. 备份原始 .po 文件。 在发送给翻译人员之前,务必在你的代码库中保留一份干净的副本。如果翻译后的文件出现问题,你需要一个已知无误的版本进行比对。

  2. 打开支持 PO 的翻译工具。 使用专为 gettext 文件设计的工具,例如 OpenL PO Translator,这是一个按需付费的文档翻译工具。PO 文件专用工具会翻译目标字符串,同时保留源字符串、注释、占位符和文件结构。如果你还在选择工具,可以参考我们的 最佳 PO 文件翻译工具指南进行比较。

  3. 上传 .po 文件。 使用包含 msgidmsgstr 的语言文件。如果你只有 .pot 模板,先根据模板创建目标语言的 .po 文件,然后再上传该 .po 文件。

  4. 选择源语言和目标语言。 源语言要与 msgid 内的文本一致,而不是你的管理界面语言。例如,如果文件中的 msgid 是英文,而你需要西班牙语输出,则选择英文到西班牙语。

  5. 下载翻译后的文件。 按你的框架要求的本地化命名规范保存文件。WordPress 插件通常采用文本域加语言代码的命名方式,而 Django 通常将文件存放在 locale/<language>/LC_MESSAGES/ 目录下。

  6. 优先检查风险字符串。 在翻译文件中搜索 %{}<>msgid_pluralmsgctxt#, fuzzy。这些条目最容易影响运行时行为。

  7. 在应用中测试翻译文件。 本地加载该语言,并逐一点击使用翻译字符串的界面。PO 文件并不是翻译完成就算结束;只有在应用依然能正确渲染时才算真正完成。

方法二:在 Poedit 中翻译 PO 文件

当你需要人工审核、WordPress 兼容性或逐条细致翻译流程时,选择此方法。

  1. 在 Poedit 中打开文件。 Poedit 是专为 PO 及其他本地化格式设计的翻译编辑器;基础编辑器免费,付费专业版适合更复杂的工作流程。对于 WordPress,官方 Polyglots 手册说明 Poedit 可以根据 POT 文件创建 .po.mo 文件,并支持复数形式和 UTF-8 编码。

  2. 如果源文本有变,先用 POT 模板更新。 如果开发者修改了应用文本,在翻译前先用最新的 .pot 文件更新 .po 文件。这样可以让新增、删除和模糊字符串都可见,避免悄悄发布过时的界面文本。

  3. 只翻译 msgstr 字段。 msgid 是应用用于查找翻译的源字符串。在标准 gettext 工作流程中,译者只需编辑 msgstr,不要修改 msgid

  4. 严格保持占位符不变。 不要翻译或更改变量如 %s%d%1$s{name}%(count)s:name 或 HTML 标签。如果需要调整语序,请整体移动占位符。

  5. 复数形式需分别翻译。 复数条目包含 msgidmsgid_plural 和多个 msgstr[n] 值。请根据目标语言填写每个复数项,不要简单复制同一句话到所有位置。

  6. 保存并编译 .mo 文件(如果你的应用需要)。 有些技术栈在开发阶段会直接读取 .po 文件,但 WordPress 和许多 gettext 环境在运行时使用编译后的 .mo 文件。Poedit 可以在保存时自动编译 .mo 文件;Django 可以通过 django-admin compilemessages 命令编译消息文件。

  7. 在上传前解决所有警告。 在 Poedit 中,警告图标通常提示占位符损坏、变量缺失或复数形式不匹配。在将翻译导入 WordPress、Django、Drupal 或你的发布分支之前,务必修复这些问题。

方法三:使用本地化平台

当有多位译者、审校人员或发布经理需要协作处理同一个 PO 文件时,建议选择这种方式。

  1. 将 PO 文件导入支持 gettext 的平台。 Weblate 等本地化平台支持 PO 文件工作流。团队本地化平台通常是付费产品,不过 Weblate 也提供开源自托管选项。它们对注释、头部信息、模糊字符串和占位符的处理方式各有不同,上传生产文件前请先检查格式设置。

  2. 设置占位符和标签检查。 启用针对 printf 风格占位符、命名变量、HTML/XML 标签和复数形式的 QA 规则。这些检查能发现普通拼写检查无法检测的错误。

  3. 保持开发者注释可见。 PO 文件中的注释可以包含上下文信息,如源代码引用、开发者提取的备注、标记和之前的源字符串。当遇到像“Open”这样简短的界面标签时,译者需要这些备注来判断它是动词、形容词还是菜单命令。

  4. 结合审校使用翻译记忆库。 翻译记忆库对于重复的界面字符串很有用,但它可能会将旧翻译复制到新的上下文中。当 msgctxt、源引用或周边界面发生变化时,要审查复用的字符串。

  5. 导出 PO 文件并进行本地检查。 不要盲目相信导出的文件。将翻译文件重新放回应用中,必要时编译,并在合并前测试界面。

PO 文件绝对不能违反的规则

PO 项目是否翻译?安全示例为什么重要
msgidmsgid "Save changes"应用程序在许多 gettext 工作流程中使用此源字符串作为查找键。
msgstrmsgstr "Guardar cambios"这是用户看到的目标语言文本。
msgctxtmsgctxt "button"上下文用于区分相同的源字符串。
%s, %d, %1$sHello, %s -> Hola, %s运行时代码会用实际值替换这些占位符。
{name}, %(count)s, :nameWelcome, {name}命名变量必须与应用代码保持一致。
HTML 标签通常不翻译<strong>Warning</strong>只翻译文本,不要改动标签语法。
msgid_pluralmsgid_plural "%d files"源复数属于原始代码路径。
msgstr[0], msgstr[1]是,但需谨慎msgstr[0] "%d file"每种目标语言都有自己的复数规则。
#, fuzzy需先审核#, fuzzyfuzzy 表示翻译可能已过时或未确认。
#. 开发者注释通常不翻译#. Button label这些注释帮助译者理解上下文。

快速示例:安全与错误的 PO 翻译

以下是一个常规的 gettext 条目:

#. %s 是用户的显示名称。
#, c-format
msgid "Welcome back, %s"
msgstr ""

安全的西班牙语翻译会保持 %s 不变:

#. %s 是用户的显示名称。
#, c-format
msgid "Welcome back, %s"
msgstr "Bienvenido de nuevo, %s"

错误的翻译则改动了占位符:

msgid "Welcome back, %s"
msgstr "Bienvenido de nuevo, % s"

这个微小的空格可能会造成问题。GNU msgfmt --check-format 就是用来检测格式字符串不匹配,比如错误的 % 占位符,Poedit 也会提醒常见的占位符问题。想了解更多需要保持不变的字符串,请参考我们的 不可翻译内容指南

如何检查已翻译的 PO 文件

  1. 如果你已安装 gettext,请运行 gettext 校验。
msgfmt --check --check-format -o /tmp/messages.mo path/to/messages.po

此命令会检查语法、头部信息和格式字符串,并在文件有效时生成一个临时编译目录。

  1. 按照你的框架要求编译文件。
django-admin compilemessages

对于 Django 项目,compilemessages 会将由 makemessages 创建的 .po 文件编译成 .mo 文件,以支持 gettext。

  1. 查找空翻译项。
grep -n 'msgstr ""' path/to/messages.po

空的 msgstr 字段可能是故意保留未翻译,但在发布时不应让你感到意外。

  1. 查找模糊翻译。
grep -n '#, fuzzy' path/to/messages.po

模糊翻译在发布前应由人工审核。默认情况下,msgfmt 不会使用模糊翻译,除非你编译时加上 --use-fuzzy,因此模糊项在最终目录中会表现为未翻译字符串。

  1. 测试真实界面。 打开包含表单、复数计数、错误信息、账户菜单和支付流程的页面。PO 文件校验能发现文件问题,只有界面测试才能发现措辞不自然、内容溢出和上下文缺失等问题。

应该使用哪种方法?

情况最佳方法原因
你需要为单个 PO 文件快速生成初稿PO 文件翻译器保持结构的最快路径
你维护 WordPress 插件或主题Poedit熟悉的 WordPress 工作流程,支持 .mo 编译
你维护 Django 应用PO 翻译器或 Poedit,然后运行 compilemessages翻译可以很快完成,但框架编译仍然必需
你有多种语言和多个审核人员本地化平台更好的分配、历史记录、质量控制和审核管理
你在翻译面向开发者的字符串机器翻译后人工审核代码术语、占位符和上下文更为重要
你还要本地化 JSON 或前端 i18n 文件使用针对格式的工作流程PO 规则并不总适用于 JSON、YAML 或 ICU 消息

如果你的项目同时使用 gettext PO 文件和 JSON 语言文件,请分别用能理解其结构的工具进行翻译。PO 文件以 msgidmsgstr 为核心;JSON 本地化则围绕键和值展开。相关工作流程请参考我们的2026 年最佳 JSON 翻译工具指南

常见问题

我可以用 Google Translate 翻译 PO 文件吗?

你可以将单个 msgstr 内容复制到通用翻译器中,但将整个 PO 文件上传或粘贴到纯文本翻译器存在风险。通用翻译器可能会修改 msgid、注释、引号转义、复数索引或占位符。建议使用支持 PO 格式的翻译器、Poedit 或本地化平台。

.po.pot.mo 有什么区别?

.pot 是从源代码提取的模板,通常只包含原始字符串,不含翻译内容。.po 是针对某种目标语言的可编辑翻译文件。.mo 是编译后的二进制目录,许多基于 gettext 的应用在运行时加载它。

我应该翻译 msgid 吗?

不,正常的工作流程中不会这样做。请翻译 msgstr。GNU gettext 手册将 msgid 描述为原始未翻译字符串,而 msgstr 是翻译内容;msgid 字符串由 gettext 工具生成和管理。

如何检查 PO 文件是否有效?

如果你安装了 gettext,可以运行 msgfmt --check --check-format,也可以用 Poedit 打开文件,或者使用你的本地化平台的 QA 检查功能。之后,将文件编译并在应用内测试。校验是必要的,但不能替代 UI 测试。

如果我破坏了占位符会发生什么?

最好的情况是应用显示一个奇怪的字符串。更糟糕的是,运行时格式化器会抛出错误,因为翻译后的字符串不再与代码传入的变量匹配。占位符只能作为完整的标记移动,绝不能翻译或部分编辑。

OpenL 能翻译 PO 文件吗?

可以。OpenL PO Translator 专为 gettext .po 文件设计,并声明在翻译超过 100 种语言时会保持占位符和变量不变。它采用按需付费的文档翻译流程,因此当你更看重保留 PO 结构而不是手动处理时,可以用它快速生成初稿。如果你只有 .pot 模板,请先创建目标语言的 .po 文件再使用 OpenL。

参考资料