# General Translation Knowledge Base: General Translation 与 Babel、Flask-Babel 对比：该选哪一个？
URL: https://generaltranslation.com/zh/kb/general-translation-vs-flask-babel.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Babel 可以为任意区域设置格式化日期、数字和货币，并管理 gettext 消息目录；Flask-Babel 则负责将其集成到 Flask 中，但两者都不会翻译你的字符串。General Translation 的 CLI 会为每种语言填充 Babel 的 PO 文件（包括复数形式），因此你可以继续使用 Flask-Babel，不必再手动翻译消息目录。
Category: 国际化
Last updated: 2026-10-16
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-16

Babel 基于 Unicode CLDR 数据格式化日期、数字和货币，其 `pybabel` 命令可用于提取、更新和编译 gettext 消息目录。Flask-Babel 则将这些工具接入 Flask 的请求处理流程和 Jinja 模板。General Translation 在提取与编译之间填充消息目录，让你的应用无需改动现有的 Flask-Babel 初始化设置，即可实现自动化翻译。

## Babel 和 Flask-Babel 的优势

* **基于 CLDR 的区域设置格式化。** [Babel 2.18.0 内置了 CLDR 47](https://babel.pocoo.org/en/latest/changelog.html#version-2-18-0) 数据，覆盖一千多个区域设置标识符。`format_currency(1234.5, "EUR")` 在西班牙语下输出“1.234,50 €”，`format_date` 在波兰语下输出“16 października 2026”。
* **消息目录工具。** [`pybabel extract`](https://babel.pocoo.org/en/latest/cmdline.html) 通过 `babel.cfg` 映射读取 Python 文件和 Jinja 模板；`pybabel init` 会创建 PO 文件，并预置正确的复数规则和对应槽位 (波兰语为三个) ；`pybabel update` 会合并新增字符串，并将有改动的字符串标记为 fuzzy；`pybabel compile` 则负责构建 `.mo` 文件。
* **Flask 集成。** `locale_selector` 和 `timezone_selector` [为每个请求确定区域设置和时区](https://python-babel.github.io/flask-babel/#configuration)；`lazy_gettext` 用于处理在导入时定义的字符串；Jinja 模板中可使用 `_()`、`{% trans %}` 以及格式化过滤器；`force_locale` 可临时切换区域设置，例如用于以其他语言发送邮件。
* **稳定且免费。** 两者均采用 BSD 许可证 (参见 [Babel 的许可证](https://babel.pocoo.org/en/latest/license.html)) 。Babel 适用于任何 Python 程序；Flask-Babel 的[当前版本为 4.0.0](https://github.com/python-babel/flask-babel/releases/tag/v4.0.0)。

## Babel 和 Flask-Babel 需要你自行处理的部分

下面是一个简单的 Flask-Babel 应用：

```python title="app.py"
from datetime import date
from flask import Flask, request
from flask_babel import Babel, gettext, ngettext, format_currency, format_date


def select_locale():
    return request.accept_languages.best_match(["en", "es", "pl"])


app = Flask(__name__)
babel = Babel(app, locale_selector=select_locale)


@app.route("/inbox/<int:count>")
def inbox(count):
    return {
        "title": gettext("Inbox"),
        "unread": ngettext("You have %(num)d unread message.", "You have %(num)d unread messages.", count),
        "price": format_currency(1234.5, "EUR"),
        "date": format_date(date(2026, 10, 16), format="long"),
    }
```

依次运行 `pybabel extract`、`pybabel init -l pl` 和 `pybabel compile` 后，会生成一个所有 `msgstr` 均为空的波兰语消息目录。在 Flask-Babel 4.0.0 下，发送一个带有 `Accept-Language: pl` 的请求，返回结果如下：

```json title="Output"
{
  "date": "16 października 2026",
  "price": "1 234,50 €",
  "title": "Inbox",
  "unread": "You have 5 unread messages."
}
```

Babel 会按波兰语的习惯格式化日期和价格，但所有字符串依然是英文，而且不会有任何警告。每个字符串都得等人填好对应的 PO 条目 (包括波兰语全部三种复数形式) ，再运行 `pybabel compile` 并重新部署。每新增或修改一个字符串，每种语言都要把这套流程重走一遍。

## 使用 General Translation 翻译 Babel 的消息目录

如果 Flask-Babel 已经能满足你的需求，可以继续沿用，由 General Translation 的 CLI 负责写入消息目录。只需创建一次英文消息目录，并在每次提取后更新，这样源文本就会与译文位于同一目录树中：

```bash
pybabel extract -F babel.cfg -k lazy_gettext -o messages.pot .
pybabel init -i messages.pot -d translations -l en     # 只需执行一次
pybabel update -i messages.pot -d translations -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": ["translations/[locale]/LC_MESSAGES/messages.po"],
      "transformationFormat": "PO"
    }
  }
}
```

`pot` 键用于读取 PO 和 POT 文件，`"transformationFormat": "PO"` 则会输出翻译后的 `.po` 文件 (参见 [PO / POT 格式参考](/docs/cli/reference/formats/po-pot-files)) 。[`customMapping`](/docs/cli/reference/config#custom-mapping) 会将 Babel 的 `pt_BR` 目录映射到标准区域设置代码 `pt-BR`。请先设置好 [CLI](/docs/cli/quickstart)。如果你已有译文，请在生成新译文之前，先使用 [`npx gt upload`](/docs/cli/reference/commands/upload) 导入。然后运行 [`npx gt translate`](/docs/cli/reference/commands/translate)，再运行 `pybabel compile -d translations`。

General Translation 会将每个条目连同其 `msgctxt`、译者注释、源文件引用和标志一并作为上下文发送。对于复数条目，它会写入目标语言的 `Plural-Forms` 头，并填满每个 `msgstr[n]` 槽位 (例如波兰语的三种形式都会生成) ，同时检查 `%(num)d` 等占位符是否完整保留。未更改的条目在下次运行时会直接复用之前的译文。借助[上下文分组](/docs/platform/dashboard/guides/defining-context-for-translations)中的词汇表和自定义提示词，你的消息目录与产品其他部分的术语可以保持一致；审校人员也可以在仪表板中[逐条编辑](/docs/platform/dashboard/guides/reviewing-translations)。在 CI 中运行 CLI，确保每次部署都带上最新的消息目录。之后如有本地修改，请在再次生成之前使用 [`npx gt save-local`](/docs/cli/reference/commands/save-local) 保存。

## Babel 和 Flask-Babel 与 General Translation 对比一览

| 功能          | Babel 和 Flask-Babel                             | General Translation                                               |
| ----------- | ----------------------------------------------- | ----------------------------------------------------------------- |
| 字符串编写方式     | 使用 `gettext` 调用和 Jinja `{% trans %}`，并提取到 PO 文件 | 沿用这些调用和模板，直接翻译提取出的消息目录                                            |
| 翻译您的内容      | 否                                               | 是，使用 [`npx gt translate`](/docs/cli/reference/commands/translate) |
| 复数形式        | `pybabel init` 生成各个槽位，需由您逐一填写                   | 自动为目标语言生成全部 PO 槽位                                                 |
| 日期、数字和货币格式化 | 是，基于 CLDR                                       | 沿用 Babel 的格式化功能                                                   |
| Jinja 模板    | 是                                               | 翻译从现有模板中提取的消息                                                     |
| 框架          | Babel 适用于任何环境；Flask-Babel 适用于 Flask             | CLI 可处理 Flask 或其他 gettext 应用中的 PO 消息目录                            |
| 许可证         | BSD                                             | CLI 采用 MIT 许可证                                                    |
| 费用          | 免费                                              | [翻译按用量计费](https://generaltranslation.com/pricing)                 |

## 如何选择

如果译者或 TMS 已经能交付你所需的消息目录，请沿用现有的翻译流程。如果你希望在开发阶段就完成新增和变更消息的翻译，并使用团队跨项目共享的术语和审校工具，请引入 General Translation。Flask-Babel 仍会负责处理 Jinja、请求区域设置、日期和货币，你的应用代码无需任何改动。

## 要点总结

* Babel 可按任意区域设置格式化日期、数字和货币，并管理 gettext 消息目录；Flask-Babel 则负责将其集成到 Flask 中。但二者都不会帮你翻译字符串。
* General Translation 的 CLI 借助 `pot` 键、`"transformationFormat": "PO"`，以及针对 `pt_BR` 等目录的 `customMapping` 来翻译 Babel 的 PO 文件，并为每种语言补全所有复数形式。
* 继续沿用 Flask-Babel 的渲染和格式化功能，导入现有译文，并在提取与编译之间加入 General Translation 这一步。

## 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 与 Django 翻译框架：两者都需要吗？](https://generaltranslation.com/zh/kb/general-translation-vs-django-i18n.mdx): 将 Django 的翻译框架与 General Translation 搭配使用。Django 负责消息提取、语言选择和渲染；General Translation 则基于你的产品术语和仪表板审阅，填充 Django 的 PO 文件（包括复数形式）。你的模板和 URL 模式无需改动，译文会随代码同步更新。
- [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 还会以你的代码为上下文完成翻译。
- [为什么选择 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 结合上下文直接翻译代码中的内容，每次发布都同步交付所有语言，并基于开源库运行，不存在供应商锁定。
- [不用翻译文件也能做 i18n 吗？](https://generaltranslation.com/zh/kb/i18n-without-translation-files.mdx): 可以。使用 gt-react 或 gt-next 时，内容以内联方式直接写在组件中的 `<T>` 组件内，译文在构建时作为输出生成，因此无需编写键，也无需为每个区域设置编写 JSON 文件并保持同步。

## Previous and next questions

- Previous question: [Crowdin 替代方案：General Translation 与 Crowdin 对比](https://generaltranslation.com/zh/kb/general-translation-vs-crowdin.mdx)
- Next question: [General Translation 与 Django 翻译框架：两者都需要吗？](https://generaltranslation.com/zh/kb/general-translation-vs-django-i18n.mdx)

## Sitemap

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