Databend 的社区官网使用 Docusaurus 构建,托管在 Vercel 上,并使用 Crowdin 进行自动化的 i18n。

这套 SaaS 服务栈有如下好处:

  • 源代码中只需要维护源文件,不需要额外存放翻译后的文件
  • 翻译与源文件始终保持一致,不需要处理过期的翻译等问题
  • 关注点分离,编写文档与翻译的同学可以并行展开工作
  • 无额外学习成本,配置完成后翻译同学可以快速上手,无需学习命令行工具
  • 充分利用机器学习的发展来就降低工作量

今天这一期的周报主要介绍 Databend 文档基于这些服务的 i18n 实践。

Databend 社区官网 i18n 功能上线的主要贡献者为 @PsiACE@Xuanwo,其中 @Xuanwo 完成了前期调研和初步配置,@PsiACE 后续作为接手,解决了所有残留问题,清理了过期内容,推动了功能最终落地。

背景

Databend 是一个基于 Rust 开发的开源 Cloud Data Warehouse,支持了众多 SQL 语法,因此它的文档量也非常庞大。根据 Crowdin 的后台统计,去重后有将近 12W 个单词。不仅如此,Databend 的迭代速度非常的快,文档一直在持续更新。此外,Databend 社区刚刚发展起来,贡献者只有 100 多人,缺少人力物力去组织专门的翻译团队或者聘请第三方翻译公司。因此,Databend 社区需要一个低成本,弱侵入性,上手容易的 i18n 方案。

Docusaurus 的官方文档提供了 Git 和 Crowdin 两种方案,本质上它们是同一种思路的不同实现:Docusaurus 制定了一套 i18n 的规则,将所有的 i18n 相关文件都放在项目目录的 i18n/<locale> 下,构建时根据制定的 locale 选择相应的文件进行构建。Git 方案就是把文件复制到指定目录,然后进行翻译;而 Crowdin 就是把源文件上传到翻译平台,在翻译平台上进行翻译,并把结果下载到指定目录。考虑到 Git 方案带来的维护复杂度,这个方案被快速排除,接下来主要考虑如何结合 Github / Crowdin / Vercel 尽可能降低对开发者的侵入性并保障翻译体验。

可能的方案包括:

根据我们的实际体验,Crowdin 自带的 Github 集成不是特别好用,最低只能设置为 10 分钟同步粒度且不说,同步感觉经常有延迟,出一些奇怪的问题,感觉上不是特别靠谱,在调试上需要花费不少时间。Github Action 相对更好一些,最起码出了任何错都能看到明确的错误日志。如果开启了 download_translations,它会自动发起带有已翻译内容的 PR,维护者预览之后就可以直接合并或者配置自动化的流程在构建通过后自动合并。缺点是这种方式需要将已翻译的内容直接添加到仓库中,如果翻译的文本量很大会迅速增长仓库体积。

流程

最终我们选择了使用 Github Action 来上传源文件,使用 Vercel 在构建之前下载翻译文件。具体的流程如下:

  • 配置 Github Action,每次 main 更新时上传待翻译的文件
  • 在 Crowdin 平台上进行翻译
  • Vercel 构建在构建页面时下载已翻译的文件,并进行 i18n 构建

配置

接下来我们介绍如何来实现这套流程。

Docusaurus

首先我们需要正确的在 Docusaurus 配置好相应的 locale,以及它在页面上的展示。在 docusaurus.config.js 上添加如下配置:

const config = {
  i18n: {
    defaultLocale: 'en-US',
    locales: ['en-US', 'zh-CN'],
    localeConfigs: {
        'en-US': {
            label: 'English',
        },
        'zh-CN': {
            label: '简体中文',
        },
    },
  },
  themeConfig: ({
    navbar: {
      items: [
        {
          type: 'localeDropdown',
          position: 'right',
          dropdownItemsAfter: [
            {
              to: 'https://databend.crowdin.com/databend',
              label: 'Help Us Translate',
            },
          ],
        },
      ]
    }
  })
}
  • i18n.defaultLocale 决定了页面默认展示使用的 locale
  • i18n.localeConfigs 决定当前页面支持哪些 locale
  • i18n.localeConfigs 则分别配置不同的 locale,这里主要用到 locale 展示出来的 Label
  • themeConfig.navbar.items 中增加 typelocaleDropdown 的项目能在导航栏中增加语言切换的按钮
    • 通过增加一个 dropdownItemsAfter 能在已有的 locale 外额外增加一些项目

此外,可以通过修改 editUrl 来修改编辑按钮指向的连接:

editUrl: ({locale, devPath}) => {
  if (locale !== config.i18n.defaultLocale) {
    return `https://databend.crowdin.com/databend/${locale}`;
  }
  return `https://github.com/datafuselabs/databend/edit/main/docs/dev/${devPath}`;
},

Docusaurus 配置完成后,我们就可以使用 docusaurus 提供的命令生成 Docusaurus 主题和插件相关的待翻译内容:

docusaurus write-translations

Crowdin

Crowdin 工作依赖于项目提供的 crowdin.yml 配置,目前 Databend 使用的配置如下:

最新配置参见 crowdin.yml

project_id: "2"
api_token_env: CROWDIN_PERSONAL_TOKEN
preserve_hierarchy: true
base_url: "https://databend.crowdin.com"
base_path: "../"
export_only_approved: true

# See docs from https://docusaurus.io/docs/i18n/crowdin
files:
  # JSON translation files
  - source: /website/i18n/en-US/**/*
    translation: /website/i18n/%locale%/**/%original_file_name%
  # Blog Markdown files
  - source: /website/blog/**/*
    translation: /website/i18n/%locale%/docusaurus-plugin-content-blog/**/%original_file_name%
  # Docs Markdown files
  - source: /docs/doc/**/*
    translation: /website/i18n/%locale%/docusaurus-plugin-content-docs/current/**/%original_file_name%
  - source: /docs/dev/**/*
    translation: /website/i18n/%locale%/docusaurus-plugin-content-docs-dev/current/**/%original_file_name%
  • project_id 是当前项目的数字 ID(在管理后台点击项目设置可以看到)
  • api_token_env 用来指定 API TOKEN 所使用的环境变量名,接下来将 CROWDIN_PERSONAL_TOKEN 环境变量设置为正确的 Token 即可(Token 可以在用户设置中创建)
  • preserve_hierarchy 用户保持目录结构,推荐开启
  • base_url 是组织的地址,根据实际情况设置
  • base_path 是项目文件相对于配置文件的地址,根据实际情况设置(databend 将配置文件放在了 .github/ 目录下,所以使用了 ../
  • export_only_approved 只导出已经批准的翻译,推荐开启,避免翻译不经 Review 被直接上线
  • files 维护原始文件到翻译文件的映射关系,需要小心斟酌,根据项目的实际情况调整

crowdin.yml 配置正确后我们已经可以尝试 upload 和 download 文件开始调试了。crowdin-cli 使用 Java 开发,但是提供了多种语言的分发方式。出于后续的使用方便考虑,我们直接使用 yarn add @crowdin/cli 来使用 npm 版本。

export CROWDIN_PERSONAL_TOKEN=<your_token>
# 上传文件
./node_modules/.bin/crowdin upload sources --config=.github/crowdin.yml
# 下载文件
./node_modules/.bin/crowdin download --config=.github/crowdin.yml

可以在 package.json 中增加新的 scripts 简化后续流程:

{
  "scripts": {
    "download-translations": "crowdin download --config=../.github/crowdin.yml --export-only-approved --all",
  },
}

如果都工作正常的话,我们可以继续配置。

上传待翻译文件

本次测试流程跑通之后,我们可以添加 Github Action 来自动化翻译文件的上传流程:

最新配置参见 i18n.yml

新增文件 .github/workflows/i18n.yml

name: Crowdin Action

on:
  push:
    branches: [main]

jobs:
  synchronize-with-crowdin:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: crowdin action
        uses: crowdin/github-action@1.5.1
        with:
          config: ".github/crowdin.yml"
          upload_sources: true
          # Delete obsolete files and folders from Crowdin project
          upload_sources_args: "--delete-obsolete"
        env:
          CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
  • 只有 main 分支更新时上传待翻译文件
  • upload_sources 设置为 true 以上传待翻译文件,其他的都不用开启
  • upload_sources_args 中增加 --delete-obsolete 参数能够清理已经失效的文件

Action 调试成功之后就可以开展最后一步 ->

下载已翻译文件

Vercel 支持我们重载项目构建使用的命令,我们只需要将 Build 重载为:

yarn run download-translations && yarn run build

这个命令会首先从 Crowdin 下载已翻译文件,并执行构建。

记得要同样在环境变量中配置 CROWDIN_PERSONAL_TOKEN

后续维护

配置成功之后不需要复杂的维护,只需要在 Docusaurus 升级之后执行 docusaurus write-translations 来更新插件的翻译即可,平时翻译相关的绝大多数操作都可以在 Crowdin 平台内进行。

技巧

开启机器翻译

Crowdin 作为翻译平台,支持并接入了绝大多数翻译引擎和第三方的翻译公司,可以轻松定制自己的翻译流程。Databend 使用的流程如下:

  • 首先我们使用 Crowdin 自带的机器翻译引擎对所有内容进行预翻译
  • 然后使用 Crowdin 记录的翻译历史对未翻译内容进行翻译
  • 之后使用进行人工翻译
  • 最后对翻译的内容进行 Review,Approve 之后就可以上线

Crowdin 支持了大量的机器翻译引擎,比如 DeepL,Google Translte 等,可以根据自己的财力和实际需求来选择。

In-Context for Web

根据 Crowdin CEO 的强势安利,Crowdin 支持开启当前页面上的实时翻译功能。

效果如图:

它能够实现在当前页面上直接选取文本内容进行翻译,翻译结果也是实时同步到页面上。这个功能跟我们现有的流程比较冲突,所以没有开启。

总结

本文介绍了如何基于 DocusaurusVercelCrowdin 以及 Github 实现一套低成本,弱侵入性,上手容易,开源友好的 i18n 协作流程,希望对其他开源社区的文档建设有所助益~

参考资料