简介

本文档使用了 Google 提供的 mdbook-i18n-helpers 来提供国际化支持。mdbook-i18n-helpers 中主要包含了 mdbook-xgettext 和 mdbook-gettext 这两个可执行程序,其中,mdbook-xgettext 是一个 mdbook 渲染器,帮助我们提取需要翻译的源文本,而 mdbook-gettext 是一个 mdbook 预处理器,负责将翻译后的文本重新注入到 Markdown 文件中。

翻译

mdbook-i18n-helpers 使用的是 GNU 的 Gettext 系统进行翻译。GNU gettext 是一组实用程序,它提供了一个框架,在这个框架中我们可以方便的进行多种语言的翻译。该系统广泛用于开源软件的翻译,并且对于文档的翻译也相当有效。

.po 文件

在 GNU gettext 中,每种语言都对应一个以 ISO 639 中定义的语言名为文件名的 .po 文件,例如,en.po,其中记录了所有原始需要翻译的内容以及对应的翻译后的内容。因此,我们的翻译工作无需复制原始的 Markdown 文件并手动跟踪更改,而只需要修改.po 文件即可。

新增翻译

当我们的原始文档编写完成之后,首先需要创建所需要的语言对应的 .po 文件,以实现国际化支持。mdbook-xgettext 可以帮助我们提取原始文档中所有需要翻译的内容,并生成一个 .pot 文件(一个 PO 模板),我们以此为基础创建出不同语言的 .po 文件即可。

  1. 执行 MDBOOK_OUTPUT='{"xgettext": {"pot-file": "messages.pot"}}' mdbook build -d po 自动提取原始文档中所有需要翻译的内容并生成 messages.pot 文件。命令执行之后就会生成默认的 po/messages.pot 文件

    如果在 book.toml 文件中添加了 output.xgettext.pot-file = messages.pot 配置项,则每次执行 mdbook build 时都会自动输出 book/xgettext/messages.pot

    不要编辑 po/messages.pot 文件,也不要将它签入你的存储库,因为它是完全从源 Markdown 文件生成。

  2. 执行 msginit -i po/messages.pot -l xx -o po/xx.po 生成对应语言的 .po 文件。其中,xx 为 ISO 639 中定义的语言名,例如,en、zh-CN 等

    可以直接将 po/messages.pot 修改为 po/xx.po,但是必须手动将标题(第一个带有 msgid "" 条目)更新为正确的语言

  3. 手动翻译 po/xx.po 文件中各条 msgstr 对应的内容即可。其中,xx 为 ISO 639 中定义的语言名,例如,en、zh-CN 等

    不要编辑 po/xx.po 文件中的 msgid 条目

更新翻译

随着文档内容的逐步增加或者减少,对应的翻译内容也需要进行对应变动。此时,我们需要使用 mdbook-xgettext 重新提取文档中所有需要翻译的内容生成 .pot 文件,然后根据 .pot 文件更新各种语言对应的 .po 文件,而不是简单的直接编辑原始文档和.po 文件。

  1. 执行 MDBOOK_OUTPUT='{"xgettext": {"pot-file": "messages.pot"}}' mdbook build -d po 自动提取原始文档中所有需要翻译的内容并生成 messages.pot 文件。命令执行之后就会生成默认的 po/messages.pot 文件

    如果在 book.toml 文件中添加了 output.xgettext.pot-file = messages.pot 配置项,则每次执行 mdbook build 时都会自动输出 book/xgettext/messages.pot

    不要编辑 po/messages.pot 文件,也不要将它签入你的存储库,因为它是完全从源 Markdown 文件生成。

  2. 执行 msgmerge --update po/xx.po po/messages.pot 更新对应语言的 .po 文件。其中,xx 为 ISO 639 中定义的语言名,例如,en、zh-CN 等

    未更改的内容将保持原样,删除的讯息会被标记为旧内容,更新的讯息则标注为“fuzzy”。“fuzzy” 条目会沿用之前的翻译,我们需要检查并根据需要更新它,再移除 “fuzzy” 标记。

  3. 手动翻译 po/xx.po 文件中有变动的各条 msgstr 对应的内容即可。其中,xx 为 ISO 639 中定义的语言名,例如,en、zh-CN 等

    不要编辑 po/xx.po 文件中的 msgid 条目

应用翻译

应用我们翻译好的内容是通过 mdbook-gettext 预处理器完成的。

配置

首先,需要将如下配置项添加到我们的 book.toml 文件中,以便在项目中启用它。这将使能在执行完诸如 {{ #include }} 等操作后对源码运行 mdbook-gettext,从而使得翻译包含的源代码成为可能。

[preprocessor.gettext]
after = ["links"]

如果要在每次更改 po/xx.po 文件时自动重新加载我们的文档,则需要将如下配置项添加到项目的 book.toml 文件中:

[build]
extra-watch-dirs = ["po"]

构建

增加了以上配置项之后,每当我们执行 mdbook build 构建时,将自动根据 book.toml 文件中的 book.language 指定的语言选择并应用对应的 po/xx.po 并在 book 目录下生成对应语言的文档。

如果没有设置语言或者找不到与该语言对应的 .po 文件,那么将自动使用未翻译的内容

如果要单独构建指定语言的文档,则可以使用 MDBOOK_BOOK__LANGUAGE=xx mdbook build -d book/xx 命令在 book/xx 目录中生成 xx 语言的文档 。其中,xx 为 ISO 639 中定义的语言名,例如,en、zh-CN 等

每种语言都对应一个独立的完整文档

在线预览

由于构建是根据 book.toml 文件中的 book.language 指定的语言生成的对应语言的文档,因此,使用 mdbook serve 名在本地在线查看的也是对应语言的文档。

如果要单独查看指定语言的文档,则可以使用 MDBOOK_BOOK__LANGUAGE=xx mdbook serve -d book/xx 命令来在线查看。其中,xx 为 ISO 639 中定义的语言名,例如,en、zh-CN 等

动态切换

多语言的支持需要动态切换,而不是分别独立部署。但是,由于 mdbook 本身不支持国际化,其默认主题中也没有用于切换不同语言的菜单,因此,我们需要修改默认的主题模板文件才能实现动态切换不同的语言。

index.hbs

index.hbs 是 mdbook 的生成的所有页面的基础 HTML 模板,我们可以创建 theme/index.hbs 文件然后修改其中的内容,在构建时,mdbook 将自动使用当前目录下的 theme/index.hbs 文件,从而实现自定义主题!

对于要支持国际化的需求,我们首先需要在原在 index.hbs 的基础上,在顶部菜单栏的右侧增加一个切换不同语言的图标以及各种语言的菜单,并实现用户单击语言图标显示语言菜单以及点击语言菜单项时切换对应的语言的文档的功能。其次,当切换对应语言之后,还需要同步更新 URL 的路径并刷新显示。具体修改参见 theme/index.hbs 文件!

增加样式

为了美化样式,我们还需要增加了一个 CSS 样式文件 theme/language-picker.css,用于控制新增的语言选择菜单的样式。而且,要使该文件生效,需要在 book.toml 文件中的 output.html.additional-css 中显式指明该文件。

部署 Github Pages

mdbook 生成的文档本身就支持部署在 Github Pages,但是,在我们增加了国际化之后需要增加一些额外的执行步骤。

在没有国际化时,我们只需要通过 mdbook build 构建出文档,而支持国际化之后,则需要额外构建出每个语言对应的文档,并将构建出的不同语言的文档放到原构建目录中以 ISO 639 中定义的语言名为文件夹名字的子目录中即可(这是由于我们修改的 index.hbs 中强制写死了文件名)。具体修改见 .github/workflows/build_deploy.yml

局限性

  1. 由于 mdbook 本身不支持国际化,因此需要对 mdbook 做比价多的改动

  2. mdbook 的搜索不支持中文

  3. 目前无法再本地同时预览多个语言的版本(我们添加的动态切换无效),这是由于 mdbook 会清理掉其他语言的文档。暂时的解决方法是,在启动 mdbook serve 之后,再把构建的其他语言的文档放到 book 目录下

    Copyright © 2025 • Created by ArceOS Team