在构建多语言网站或应用时,使用 gettext 工具链处理 .po 文件和 .pot 模板是标准流程。但随着项目规模扩大,你可能会发现 msgmerge 处理大文件非常慢,且翻译条目行为有些“诡异”:明明写了翻译,实际却显示原文。本文从开发者角度深入拆解这些坑,并提供一整套高效、可靠的处理方案。
典型工作流:
.pot(通过 xgettext).pot 与已有 .po 合并(通过 msgmerge).po.mo 文件供程序使用(msgfmt)本文重点关注第 2 步:msgmerge 合并行为及其性能与正确性问题。

msgmerge 合并太慢,怎么办?当 .po 文件有成千上万个条目时,默认合并速度可能非常慢。原因在于:
msgid 做模糊比对;#, fuzzy,需要人工审核。使用 --no-fuzzy-matching 可大幅提升速度,跳过所有模糊匹配逻辑,只保留精确匹配项:
msgmerge --no-fuzzy-matching old.po template.pot -o merged.po
fuzzy 是 gettext 系统的“翻译保守机制”:
"Save" 改为 "Save file"),会尝试找到旧翻译;#, fuzzy,表示 “可能对,但需要人类确认”。#, fuzzy
msgid "Save file"
msgstr "保存"
重点:fuzzy 条目不会在实际运行中生效,gettext 会忽略其 msgstr!
是的!特别适合以下场景:
推荐做法:
msgmerge --no-fuzzy-matching old.po template.pot -o merged.po
搭配清理工具:
msgattrib --no-obsolete merged.po -o clean.po
fuzzy 条目的运行行为再总结一下:
| 条目状态 | 实际显示内容 | 使用 msgstr 吗? |
|---|---|---|
| 正常翻译 | 翻译内容 | ✅ 是 |
#, fuzzy 标记 | 原文(msgid) | ❌ 否 |
空的 msgstr | 原文(msgid) | ❌ 否 |
误解警告:我看有些文章,包括 AI 回复都是不对的。--previous 不会提升性能,反而略微拖慢。
实际作用是:
把旧的
msgid作为注释保留下来,供翻译者参考。
例子:
#| msgid "Save"
msgid "Save file"
msgstr "保存文件"
适合在关闭 fuzzy 后仍保留一点上下文提示,但它会:
.po 文件体积仅建议用于人工翻译或 GUI 工具(如 Poedit)环境下。
msgid 会不会残留在 .po 文件里?是的,但是以“废弃条目”的形式存在:
#~ msgid "Save"
#~ msgstr "保存"
这些是 gettext 特有的 obsolete 条目,不会影响翻译,但会让 .po 文件臃肿。
可用 msgattrib 清理:
msgattrib --no-obsolete merged.po -o clean.po
msgattrib --no-obsolete merged.po -o merged.po # 是否可以?
不推荐!
虽然工具允许,但:
推荐更安全的做法:
msgattrib --no-obsolete merged.po -o tmp.po && mv tmp.po merged.po
或使用临时文件自动生成:
tmp=$(mktemp)
msgattrib --no-obsolete merged.po -o "$tmp" && mv "$tmp" merged.po
#!/bin/bash
set -e
OLD_PO=$1
POT=$2
OUT_PO=${3:-merged.po}
TMP_MERGED=$(mktemp)
TMP_CLEANED=$(mktemp)
# 合并并禁用 fuzzy
msgmerge --no-fuzzy-matching "$OLD_PO" "$POT" -o "$TMP_MERGED"
# 清理废弃条目
msgattrib --no-obsolete "$TMP_MERGED" -o "$TMP_CLEANED"
# 移动到目标文件
mv "$TMP_CLEANED" "$OUT_PO"
| 问题/目标 | 推荐做法 |
|---|---|
| 合并过慢 | 使用 --no-fuzzy-matching |
| 想保留旧 msgid 提示信息 | 使用 --previous |
| fuzzy 条目被显示为原文 | 清除 fuzzy 或人工确认后移除 fuzzy 标记 |
| 旧 msgid 仍留在文件中 | 使用 msgattrib --no-obsolete 清理 |
安全写入 .po 文件 | 输出到临时文件后 mv 覆盖 |
| 场景 | 是否关闭 fuzzy | 是否使用 previous | 是否清理 obsolete |
|---|---|---|---|
| 个人项目 / 自动化 | ✅ 是 | ❌ 否 | ✅ 是 |
| 需要上下文提示 / GUI 翻译工具 | ❌ 否 | ✅ 是 | 可选 |
| 内容频繁变化 / 快速迭代项目 | ✅ 是 | 可选 | ✅ 是 |
| 专业翻译团队 / 翻译一致性要求 | ❌ 否 | ✅ 是 | 可选 |
如果你正在构建国际化支持的 CI/CD 流程、开发自动翻译工具链、或者维护一个翻译量大的项目,希望这篇文章能为你节省大量时间,并避免一些不易察觉的陷阱。