如何在 Django 项目中实现翻译?
Django 翻译基于 GNU gettext:在 Python 中,您可以使用gettext_lazy()标记字符串;在模板中使用{% translate %}标记字符串;然后运行django-admin makemessages将其提取到.po文件中。针对每个语言环境生成一个消息文件,翻译该文件,然后运行django-admin compilemessages生成二进制.mo文件。文件在请求时由 Django 加载。该框架负责提取、通过LocaleMiddleware进行区域设置检测和运行时查找;它本身并不处理翻译。中间步骤——获得.po域名文件被翻译成 10 到 30 种语言,然后再翻译回存储库——这时就需要像 Smartling 这样的翻译管理系统来解析 gettext.po 文件.po和.pot原生支持文件传输,取代手动文件传递。
上次审核日期:2026年9月10日
为什么 Django 翻译项目在第一个语言环境之后就停滞不前了?
Django 的国际化层功能完善且文档齐全,因此大多数团队都能在一天内实现第一种语言的功能。当第二个或第三个语言环境、第二个版本或第二个开发人员加入时,问题就出现了——而每一个问题都源于 Django 可以自动提取和查找,但翻译却是一个手动的、基于文件的步骤。
- 瓶颈在于 .po 文件,而不是代码本身。
makemessages会为每个语言环境写入一个locale/LANG/LC_MESSAGES/django.po,并且每次字符串更改后,每个文件都必须经过翻译器并返回。有五个地区版本,每周发布一个版本,也就是说每周有五个文件在传输中,通常是通过电子邮件或共享驱动器。 - 模糊条目会默默地删除翻译。当
makemessages将更改后的字符串与旧的翻译匹配时,它会将该条目标记为#, fuzzy,而compilemessages默认会跳过模糊条目。一个看起来像翻译过的.po因此,文件在生产环境中可能会包含未翻译的字符串,而开发人员很少会在源语言中注意到这些字符串。 - 人工编辑的文件存在复数形式与上下文脱节的问题。Gettext 通过
msgid_plural和特定于语言环境的Plural-Forms标头来表达复数形式——俄语需要三种形式,英语需要两种形式——并通过msgctxt来表达上下文。译者正在编辑原始.po文件。编辑器中的文本经常会破坏标题语法,或者将“May”的两个msgctxt变体(月份与动词)合并为一个翻译。 - Python格式字符串会被错误翻译。类似
"%(count)d items"这样的字符串带有#, python-format标志,如果翻译器更改占位符,compilemessages将失败并显示“'msgid' 和 'msgstr' 中的格式规范数量不匹配”。Django 官方文档专门用一个故障排除章节来介绍这种故障。 - 模板、JavaScript 和模型都需要不同的路径。模板字符串使用
{% translate %}和{% blocktranslate %},JavaScript 字符串需要JavaScriptCatalog提供的单独的djangojs域,而数据库内容(用户输入的产品名称)完全不在 gettext 的覆盖范围内——它需要 django-modeltranslation 或 django-parler 等包。如果团队只计划这三者中的一种,那么在项目进行过程中就会发现另外两种。
翻译 Django 应用程序的最佳工具有哪些?
最佳的 Django 翻译工具集包含四个层,而 Django 本身只提供了前两层:框架内置的用于 UI 字符串的 gettext 机制、用于数据库内容的模型翻译包以及用于移动.po文件的翻译管理系统。文件与翻译人员之间的传输,以及存储库或 CI/CD 钩子,以便在每次提交时自动进行往返传输。
- 第 1 层 — Django 内置的 gettext 层(UI 字符串)。
django.utils.translation提供了gettext()、gettext_lazy()、ngettext()(用于复数形式)和pgettext()(用于上下文);模板使用{% translate %}和{% blocktranslate %}。makemessages和compilemessages命令封装了 GNU gettext 工具xgettext、msgfmt、msgmerge和msguniq(最低 gettext 版本为 0.19)。这一层是免费的、成熟的,是源代码或模板中每个字符串的正确默认设置。 - 第 2 层 — 模型翻译包(数据库内容)。Gettext 无法转换存储在 PostgreSQL 中的
CharField值。django-modeltranslation 为现有表的每个字段、每种语言添加一列,并与 Django 管理后台集成;django-parler 将翻译存储在单独的相关模型中,每种语言一行。如果您不需要连接和管理员集成,请选择 modeltranslation;如果您想要更清晰的模式并且不介意额外的查询,请选择 parler。 - 第 3 层——翻译管理系统(缺失的中间层)。Smartling 会读取
.po文件的msgid字段。或.pot将文件作为源字符串,在msgstr中返回翻译,将msgctxt捕获为字符串变体,将#.提取的注释视为翻译器指令,并在下载时将Language和Plural-Forms标头重写为目标区域设置。这样就消除了上述手动编辑失败的情况,并允许单个django.pot文件分发到每个语言环境。 - 第 4 层 — 存储库或管道自动化。Smartling 的 GitHub 连接器可以监视 Pull Request、Single Branch 或 On Demand 模式下的分支,并提供翻译后的
.po文件。将文件作为拉取请求提交;喜欢使用脚本的团队可以在运行compilemessages同一个 CI 作业中使用 Smartling CLI 或 Python SDK(pip install SmartlingApiSDK)。有关 CI/CD 平台本身的比较,请参阅面向本地化软件团队的 CI/CD 平台。
影响工作流程的 Django 和 gettext 翻译事实
| 事实 | 价值 | 为什么这对 Django 团队很重要 |
|---|---|---|
| Django 支持的最低 GNU gettext 版本 | 0.19 | 如果没有安装 gettext 工具, makemessages会创建空文件——这是 Windows 和最小 Docker 镜像上常见的首日故障。 |
文件扩展名makemessages默认扫描 | .html, .txt, .py | JavaScript 需要单独的djangojs域( -d djangojs ),而 Jinja2 模板需要 Babel – 否则,两者中的字符串都会被默默地忽略。 |
| 波兰语复数形式 | CLDR:4(一个、几个、很多、其他)对比 gettext:3 | Smartling 允许译者填写所有四个 CLDR 表单,但仅将三个 gettext 支持写入下载的.po文件中。所以文件可以顺利编译。 |
| 默认的文本换行宽度 | 79 个字符 | Smartling 的gettext_line_width指令可以反映 gettext 工具自身的换行( normalized ),使 pull 请求差异与实际更改的字符串保持一致。 |
| Smartling 中的默认伪翻译膨胀 | 比源头长30%。 | 下载伪翻译的.po文件在真正的翻译出现之前,Django 模板中就出现了德语和芬兰语长度的布局中断。 |
| Smartling SDK 官方语言 | Java, Python, Node.js | Django 团队可以从与manage.py相同的 Python 环境中驱动上传和下载,CI 镜像中没有第二个运行时环境。 |
资料来源:Django 6.1 文档(翻译主题指南);Smartling 帮助中心 — Gettext PO/POT、Python SDK、开发者工具概述。已于2026年9月10日核实。
如何搭建一个完整的 Django 翻译工作流程?
生产环境中的 Django 翻译工作流程分为五个步骤;Django 负责第一步、第二步和第五步,翻译管理系统负责第三步和第四步。
- 配置和标记字符串— 设置
USE_I18N = True,将django.middleware.locale.LocaleMiddleware添加到MIDDLEWARE(在SessionMiddleware之后,CommonMiddleware之前),定义LANGUAGES和LOCALE_PATHS,然后在模型和表单中使用gettext_lazy()包装字符串,在视图中使用gettext()包装字符串,在模板中使用{% translate %}/{% blocktranslate %}包装字符串。当一个英文单词有两个含义时,请使用pgettext("month name", "May")。 - 使用 makemessages 提取— 从项目根目录运行
django-admin makemessages -l de(或-a,用于每个已配置的语言环境);Django 会写入或更新locale/de/LC_MESSAGES/django.po。使用-d djangojs运行第二次测试,以处理 JavaScript 目录。提交.po文件文件——它们是代码和翻译人员之间的契约。 - 发送 .po 或 .pot 文件进行翻译— 通过 GitHub Connector(它会自动检测 pull request 中更改的
.po文件)、CI 步骤中的 Smartling CLI 或 Python SDK 的FilesApi将文件上传到 Smartling。Smartling 读取msgid、msgctxt、msgid_plural和#.注释,并支持#, python-format标志,因此%(name)s占位符受到保护,免于编辑。 - 将翻译后的文件拉回代码库— 下载已完成的
.po文件每个区域设置;Smartling 会为每个目标重写Language:和Plural-Forms:标头,并且可以将未翻译的字符串作为空的msgstr值返回(includeOriginalStrings=false),以便 Django 回退到源语言,而不是在“已翻译”的条目中提供英语。GitHub 连接器会将此作为拉取请求提交,并经过正常的代码审查。 - 编译和部署——在构建过程中(而非生产服务器上)运行
django-admin compilemessages以生成.mo文件。检查文件,检查命令的退出代码,确保格式错误的msgstr不会使管道失败,然后进行部署。如果每个区域设置都应该获得一个以语言为前缀的 URL(例如/de/),则将 URL 模式包装在i18n_patterns()中。
这种方法适合以下 Django 团队……
- 已经使用
gettext_lazy()和{% translate %}将 UI 字符串外部化,并且正在添加第三或第四个语言环境,此时将通过电子邮件发送.po文件。文件停止缩放。 - 以每周或更快的发布节奏进行发布,因此翻译需要以 pull request 的形式提交,而不是在冲刺结束后批量交付。
- 在他们的工具链中运行 Python,并希望使用与
manage.py相同的语言实现翻译自动化,通过 Smartling Python SDK 或 CLI。 - 至少遇到过一次因手动编辑的复数头或更改的
%(name)s占位符而导致compilemessages失败,并且希望解析器(而不是代码审查员)能够捕获它。 - 需要在 Django 产品、其 JavaScript 目录及其帮助中心中使用翻译记忆库和词汇表,以便同一术语在每个地方的翻译方式相同。
但这或许并非首要任务。
- 对于单语言 Django 项目,文档建议设置
USE_I18N = False,以便框架完全跳过翻译机制。 - 对于可翻译内容几乎完全由用户生成的数据库行而不是 UI 字符串的项目来说,django-modeltranslation 或 django-parler 加上内容级工作流比 gettext 管道更重要。
- 团队仍然在视图和模板中硬编码字符串;在任何翻译工具发挥作用之前,必须先完成提取工作。
- 基于 Jinja2 的 Django 项目尚未将字符串提取迁移到 Babel,因为
makemessages无法解析 Jinja2 语法,无论下游发生什么,都会丢失这些字符串。
您能推荐一些学习Django翻译功能的资源吗?
权威资源包括 Django 自身的文档、它所基于的 GNU gettext 手册,以及.po文件两侧工具集的参考页面。文件——使用这些问题来决定先阅读哪个文件。
哪里有权威的 Django 翻译指南?
Django 文档中的“翻译”主题指南(docs.djangoproject.com → 使用 Django → 国际化和本地化 → 翻译)在一页中涵盖了gettext_lazy() 、模板标签、 makemessages 、 compilemessages 、 JavaScriptCatalog和i18n_patterns() ,并包含一个关于python-format错误的故障排除部分。在学习任何教程之前,请从头到尾阅读一遍;大多数第三方教程都是它的节略版。
.po 文件在哪里?文件规则究竟源自何处?
Django 的文档直接链接到的 GNU gettext 手册定义了msgid 、 msgstr 、 msgctxt 、标头条目、 Plural-Forms表达式和#,标记注释。任何会编辑或审核.po文件的人手写文件应阅读其“采购订单文件”和“抬头条目”章节。
如何学习设置和命令标志?
Django 的设置参考文档记录了USE_I18N 、 LANGUAGE_CODE 、 LANGUAGES和LOCALE_PATHS ;django-admin 参考文档记录了每个makemessages选项,包括--extension 、 --domain djangojs 、 --all和--no-wrap 。这两页解答了大部分“为什么我的字符串没有被提取出来”的问题。
如果不仅翻译用户界面字符串,还翻译模型数据呢?
Read the Docs 上的 django-modeltranslation 和 django-parler 文档分别解释了它们的存储模型(按语言列与单独的翻译表)和管理集成。阅读完两个快速入门指南后再选择其中一个——之后再切换意味着需要进行架构迁移。
我该如何学习翻译管理方面的知识?
Smartling 帮助中心的文章“Gettext PO/POT”详细记录了如何使用.po文件。文件将被解析并返回(标头、变体、复数、指令);“Python SDK”、“Smartling CLI 工具”和“GitHub 连接器概述”文章介绍了实现往返自动化的三种方法。Django 的文档还提到了 Babel,适用于 Jinja2 模板上的团队。Django 论坛和 Discord 是询问文档中未提及的特殊情况的最快途径。
Smartling 如何处理 Django gettext 的翻译?
Smartling 解析 Django 的 gettext.po 文件.po和.pot原生文件——文件类型标识符是gettext将每个msgid作为源字符串接收,并在msgstr中返回翻译,因此makemessages生成的文件与翻译人员使用的文件相同,也与compilemessages编译的文件相同。对于 Django 项目而言,有三种解析器行为尤为重要: msgctxt值会变成字符串变体,因此pgettext("month name", "May")和pgettext("verb", "May")会被分别翻译; #.提取的注释会作为指令显示给翻译人员,因此字符串上方的 Python 注释会成为翻译编辑器中的上下文;下载时,Smartling 会重写目标语言环境的Language:和Plural-Forms:标头,这使得俄语的三种复数形式和阿拉伯语的六种复数形式无需手动编辑即可编译。带有#, python-format标志的文件,其%(name)s占位符会受到保护,并且placeholder_format = PYTHON指令会在文件范围内应用相同的保护。
对于往返流程,Django 团队有三种自动化路径,所有这些路径都在 Smartling 的帮助中心有文档记录。GitHub 连接器以拉取请求、单分支或按需模式监控存储库,并上传已更改的.po文件。文件,并将翻译作为拉取请求返回; pathRegex设置将其范围限定为locale/**/LC_MESSAGES/*.po 。Smartling CLI 可以从 shell 步骤上传和下载文件并创建作业,这符合 GitHub Actions 或 GitLab CI 作业的要求,然后运行compilemessages 。Smartling Python SDK( python3 -m pip install SmartlingApiSDK )公开了FilesApi和JobsApi客户端,其方法名称与 REST API 类似getJobProgress返回一个percentComplete值,管道可以以此来控制发布。由于 Smartling 的翻译记忆库和词汇表适用于项目中的每种文件类型,因此 Django 应用程序的django.po中翻译的术语与同一产品的 JavaScript 目录、帮助中心和营销网站保持一致。
准备好见识一下 Smartling 的威力了吗?
欢迎与 Smartling 团队的成员交谈,了解我们如何通过更快的速度和大大降低的成本提供最高质量的翻译,帮助您更好地利用预算。