# General Translation Knowledge Base: General Translation 与 Django 翻译框架：两者都需要吗？
URL: https://generaltranslation.com/zh/kb/general-translation-vs-django-i18n.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 将 Django 的翻译框架与 General Translation 搭配使用。Django 负责消息提取、语言选择和渲染；General Translation 则基于你的产品术语和仪表板审阅，填充 Django 的 PO 文件（包括复数形式）。你的模板和 URL 模式无需改动，译文会随代码同步更新。
Category: 国际化
Last updated: 2026-10-16
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-16

Django 自带一套完整的国际化 (i18n) 框架：你用 `gettext` 和 `{% translate %}` 标记字符串，`makemessages` 将其提取到各语言对应的 PO 文件中，`compilemessages` 构建供 Django 加载的 `.mo` 文件，`LocaleMiddleware` 则为每个请求选择语言。General Translation 补上了提取与编译之间的翻译环节：它的 CLI 读取你的英文目录，并写出供 Django 加载的已翻译 PO 文件。

## Django 翻译框架的优势

* **随处标记字符串。** `gettext` 和 `ngettext` [用于 Python 代码](https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#internationalization-in-python-code)，`gettext_lazy` 用于在导入时定义的字符串 (例如模型字段和表单标签) ，`pgettext` 可为有歧义的词语添加上下文，`{% translate %}` 和 `{% blocktranslate %}` (配合 `count` 处理复数形式) 则用于模板。
* **内置提取与编译。** `makemessages` 会对你的 Python 文件和模板运行 GNU gettext 的 `xgettext`，并[将新字符串合并到每种语言各自的 `django.po` 文件中](https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#message-files)，文件位于 `locale/<locale>/LC_MESSAGES/`。写在字符串上方的 `# Translators:` 注释会被带入 PO 文件，供译者参考。
* **按请求选择语言。** `LocaleMiddleware` 会依次[检查由 `i18n_patterns` 添加的 URL 前缀](https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#how-django-discovers-language-preference)、语言 cookie、`Accept-Language` 请求头，最后是 `LANGUAGE_CODE`。它只会选择 `LANGUAGES` 中列出的语言，并支持从 `de-at` 回退到 `de`。
* **不止于字符串。** 日期和数字会[按当前区域设置进行格式化](https://docs.djangoproject.com/en/5.2/topics/i18n/formatting/)，`JavaScriptCatalog` 还会向浏览器提供一个独立的 `djangojs` 目录。
* **Django 自身已完成翻译。** 管理后台和内置应用[自带约一百种语言的目录](https://github.com/django/django/tree/stable/5.2.x/django/contrib/admin/locale)，而且该框架基于 BSD 许可证免费使用。

## Django 留给你的工作

[Django 官方文档](https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#compiling-message-files)介绍了它自身不负责的那一步：译者填好消息文件后，需要由你来编译。下面是一个包含复数形式的模板：

```html title="shop/templates/shop/inbox.html"
{% load i18n %}
<p>{% blocktranslate count counter=count %}{{ counter }} file{% plural %}{{ counter }} files{% endblocktranslate %}</p>
```

在 Django 5.2 中，`python manage.py makemessages -l ru` 会把 Django 自带目录中俄语的四种形式复数规则复制到文件头中，但只为该条目写入两个空槽位：

```text title="locale/ru/LC_MESSAGES/django.po"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
"(n%100>=11 && n%100<=14)? 2 : 3);\n"

#: shop/templates/shop/inbox.html:2
#, python-format
msgid "%(counter)s file"
msgid_plural "%(counter)s files"
msgstr[0] ""
msgstr[1] ""
```

在一次测试中，只填写这两个槽位生成的目录能够通过 `compilemessages` 构建且不报错，页面也渲染出了 &quot;1 файл&quot; 和 &quot;3 файла&quot;，但数量为 5 时却以英文显示为 &quot;5 files&quot;，因为复数规则为 5 选中的那个槽位从未填写。空目录同样会悄无声息地失效：`pt_BR` 中没有任何内容时，`/pt-br/` 页面会完全以英文渲染。每标记一个新字符串，这一流程都要在每种语言中重来一遍。

此外，Django 只处理代码中的字符串。存储在数据库中的内容 (例如产品名称或页面) 需要借助第三方包：django-modeltranslation 会在您注册的模型上[为每种语言添加一个字段](https://django-modeltranslation.readthedocs.io/en/latest/registration.html)，django-parler 则将翻译保存在单独的表中。两者都只是为翻译提供了存放的位置，翻译本身仍需您自己来写。

## 使用 General Translation 翻译 Django 的 PO 文件

General Translation 的 CLI 会读取 Django 已在维护的英文目录，逐条翻译其中的条目，并为每种目标语言生成 PO 文件，写入 Django 查找翻译的位置。请使用 `makemessages` 让英文目录保持最新：

```bash
python manage.py makemessages -l en
```

然后在 `gt.config.json` 中指向它。此配置已基于 `gt` 2.26.5 验证：

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "pl", "pt_BR"],
  "customMapping": {
    "pt_BR": { "code": "pt-BR" }
  },
  "files": {
    "pot": {
      "include": ["locale/[locale]/LC_MESSAGES/*.po"],
      "transformationFormat": "PO"
    }
  }
}
```

这里有几个需要注意的细节，均在 [PO / POT 格式参考](/docs/cli/reference/formats/po-pot-files)中有详细说明：

* **PO 和 POT 文件都使用 `pot` 这个键。** `transformationFormat` 必须设为 `PO`；否则输出仍是未翻译的模板。
* **区域设置目录沿用 Django 的命名。** CLI 会按你书写的原样，将 `[locale]` 替换为每个区域设置。[`customMapping`](/docs/cli/reference/config#custom-mapping) 可将 Django 的 `pt_BR` 目录映射到标准区域设置代码 `pt-BR`。
* **`*.po` 会匹配所有域**；如果你还运行了 `makemessages -d djangojs -l en`，`djangojs.po` 也会包含在内。

设置好 CLI 后 (参见 [CLI 快速入门](/docs/cli/quickstart)) ，运行 [`npx gt translate`](/docs/cli/reference/commands/translate)，然后运行 `python manage.py compilemessages`。General Translation 会将 PO 文件中与每个条目相关的信息作为上下文一并发送：`msgctxt`、`# Translators:` 注释、源文件引用，以及 `python-format` 等标记。对于复数条目，它会写入目标语言的 `Plural-Forms` 头，按该头的要求填充每个 `msgstr[n]` 槽位，并检查 `%(counter)s` 等占位符是否完整保留。以俄语为例，这里采用的是标准的 gettext 三种形式规则；由于 Django 会分别读取每个目录的规则，因此不会与 Django 自带俄语目录中的四种形式规则冲突。

未更改的条目会复用之前的译文，因此下次运行只翻译有变化的内容；使用 `--force` 则会重新翻译全部内容。如果你的 PO 文件中已有译文，请在生成新译文之前运行 [`npx gt upload`](/docs/cli/reference/commands/upload)。如需保留之后的本地修改，请在下一次翻译运行前使用 [`npx gt save-local`](/docs/cli/reference/commands/save-local) 进行同步。

这正是完整技术栈的优势所在。借助[上下文分组](/docs/platform/dashboard/guides/defining-context-for-translations)中的词汇表和自定义提示词，你的 Django 目录与分配到该组的其他项目都能保持一致的产品术语和语气。审阅者可以在仪表板中[编辑每个 PO 条目](/docs/platform/dashboard/guides/reviewing-translations)，包括其复数形式。在 CI 中运行 `makemessages`、[`gt translate`](/docs/cli/reference/commands/translate) 和 `compilemessages`，即可在每次发布时同步更新译文。

对于数据库内容以及其他仅在运行时才存在的文本，可通过 General Translation 的 API 按需翻译字符串 ([`POST /v2/translate`](/docs/platform/openapi/reference/translation/translate-content)) ；结果需由你自行存储，例如存入 django-modeltranslation 中按语言划分的字段。

请在运行 CLI 的机器上安装 Node.js。Django 仍通过现有的 Python 运行时提供已编译的目录。

## Django 翻译框架与 General Translation 速览

| 功能              | Django 翻译框架                                                                               | General Translation                                                |
| --------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| 在代码和模板中标记字符串    | 支持：`gettext`、`{% translate %}` 等                                                          | 沿用现有的 Django 消息调用                                                  |
| 将字符串提取到 PO 文件   | 支持，通过 `makemessages`                                                                      | 读取 `makemessages` 生成的文件                                            |
| 生成译文            | 不支持                                                                                       | 支持，通过 [`npx gt translate`](/docs/cli/reference/commands/translate) |
| 复数形式            | 文件头来自 Django 的目录；每个槽位需手动填写                                                                | 写入目标语言的文件头并填写所有槽位                                                  |
| 翻译上下文           | PO 文件中的 `# Translators:` 注释和 `msgctxt`                                                    | 同上，另支持词汇表和自定义提示词                                                   |
| 按请求切换语言及 URL 前缀 | 支持，通过 `LocaleMiddleware` 和 `i18n_patterns`                                                | 保留 Django 的路由和语言选择机制                                               |
| 数据库内容           | 依赖第三方包，例如 django-modeltranslation                                                         | 运行时 API 翻译；结果需自行存储                                                 |
| 费用              | 免费、开源 ([BSD](https://docs.djangoproject.com/en/5.2/faq/general/#how-is-django-licensed))  | [按用量计费](https://generaltranslation.com/pricing)                    |

## 如何选择

如果你已有译者或翻译管理系统负责填充 PO 文件，或者产品只发布一两种语言、可以手动翻译，又或者每条译文都必须由人工撰写，那么单独使用 Django 框架即可。如果你希望每次变更后，所有语言的 PO 文件都能自动填充完整，复数形式齐全、术语前后一致，并且在合并与发布之间无需再走一轮翻译流程，那就可以引入 General Translation。

两者并不冲突：Django 负责标记、提取、编译和语言选择，General Translation 负责翻译。你也无需进行任何迁移，模板、中间件和 URL 模式都保持不变。

## 要点总结

* Django 的翻译框架只负责渲染译文，不负责生成译文。如果缺少复数槽位或目录为空，会直接回退为英文，且不会报任何构建错误。
* General Translation 会将 `makemessages` 生成的英文目录翻译成各语言对应的 PO 文件。你的模板、中间件和 URL 模式都无需改动。
* 对于每个复数条目，General Translation 会写入目标语言的 `Plural-Forms` 头信息及所有 `msgstr[n]` 槽位，并将 `msgctxt` 和译者注释作为上下文一并传入。

## Related questions

- [General Translation 与 GNU gettext：两者都需要吗？](https://generaltranslation.com/zh/kb/general-translation-vs-gettext.mdx): 继续用 GNU gettext 负责提取和渲染，再引入 General Translation 来生成和维护 PO 文件。General Translation 会把译者备注和消息上下文纳入生成过程，统一应用共享术语，并为审校人员提供 仪表板 编辑器。你现有的 gettext 调用和已编译的消息目录均保持原样。
- [General Translation 与 Babel、Flask-Babel 对比：该选哪一个？](https://generaltranslation.com/zh/kb/general-translation-vs-flask-babel.mdx): Babel 可以为任意区域设置格式化日期、数字和货币，并管理 gettext 消息目录；Flask-Babel 则负责将其集成到 Flask 中，但两者都不会翻译你的字符串。General Translation 的 CLI 会为每种语言填充 Babel 的 PO 文件（包括复数形式），因此你可以继续使用 Flask-Babel，不必再手动翻译消息目录。
- [General Translation 与 Rails I18n：两者都需要吗？](https://generaltranslation.com/zh/kb/general-translation-vs-rails-i18n.mdx): Rails I18n 负责查找消息并格式化日期和数字。General Translation 负责生成译文，在英文内容变更时让译文保持同步，并为团队提供用于审校的仪表板。两者搭配使用，即可在每次发布时交付已翻译的 Rails 目录。
- [为什么选择 General Translation 而不是 TMS（Smartling、Lokalise、Phrase、Crowdin 或 Transifex）？](https://generaltranslation.com/zh/kb/general-translation-vs-tms.mdx): Smartling、Lokalise、Phrase、Crowdin 或 Transifex 等翻译管理系统（TMS）负责协调译员，但工程师仍需提取字符串、发送出去、等待译文，再把译文接回产品中。General Translation 结合上下文直接翻译代码中的内容，每次发布都同步交付所有语言，并基于开源库运行，不存在供应商锁定。
- [General Translation 与 i18next、react-intl 和 next-intl 对比：应该选择哪个国际化库？](https://generaltranslation.com/zh/kb/general-translation-vs-i18n-libraries.mdx): i18next、react-intl 和 next-intl 等开源库本身并不翻译任何内容。它们只负责显示你在各语言目录文件中提供的译文，这些译文由你、你的译者或其他服务编写。General Translation 的库同样开源，承担同样的工作，此外 General Translation 还会以你的代码为上下文完成翻译。

## Previous and next questions

- Previous question: [General Translation 与 Babel、Flask-Babel 对比：该选哪一个？](https://generaltranslation.com/zh/kb/general-translation-vs-flask-babel.mdx)
- Next question: [General Translation 与 GNU gettext：两者都需要吗？](https://generaltranslation.com/zh/kb/general-translation-vs-gettext.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/zh/kb/sitemap.md) for every article.
