跳到主要内容
版本:3.8.1

i18n - 使用 Crowdin

Docusaurus 的 i18n 系统与任何翻译软件都是解耦的。

只要您将翻译文件放置在正确的位置,Docusaurus 就可以与您选择的工具和 SaaS 集成。

我们记录了 Crowdin 的使用,作为一个可能的集成示例。

警告

这并非推荐 Crowdin 是翻译 Docusaurus 站点的唯一选择,但 Facebook 已成功使用它来翻译 JestDocusaurusReasonML 等文档项目。

请参阅 Crowdin 文档Crowdin 支持以获取帮助。

提示

请使用此社区驱动的 GitHub 讨论来讨论与 Docusaurus + Crowdin 相关的所有内容。

Crowdin 概览

Crowdin 是一款翻译 SaaS,为开源项目提供免费计划

我们推荐以下翻译工作流

  • 将源文件**上传**到 Crowdin(未翻译的文件)
  • 使用 Crowdin **翻译**内容
  • 从 Crowdin **下载译文**(本地化翻译文件)

Crowdin 提供一个 CLI 工具来**上传源文件**和**下载译文**,使您能够自动化翻译流程。

crowdin.yml 配置文件对 Docusaurus 很方便,它允许将**本地化翻译文件下载到预期位置**(在 i18n/[locale]/.. 中)。

阅读**官方文档**,了解更多高级功能和不同的翻译工作流。

Crowdin 教程

这是一个使用 Crowdin 将新初始化的英文 Docusaurus 网站翻译成法文的演练,并假设您已经完成了i18n 教程

最终结果可在 docusaurus-crowdin-example.netlify.app (仓库) 查看。

准备 Docusaurus 站点

初始化一个新的 Docusaurus 站点

npx create-docusaurus@latest website classic

添加法语站点的配置

docusaurus.config.js
export default {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
themeConfig: {
navbar: {
items: [
// ...
{
type: 'localeDropdown',
position: 'left',
},
// ...
],
},
},
// ...
};

翻译首页

src/pages/index.js
import React from 'react';
import Translate from '@docusaurus/Translate';
import Layout from '@theme/Layout';

export default function Home() {
return (
<Layout>
<h1 style={{margin: 20}}>
<Translate description="The homepage main heading">
Welcome to my Docusaurus translated site!
</Translate>
</h1>
</Layout>
);
}

创建 Crowdin 项目

Crowdin 上注册,并创建一个项目。

使用英语作为源语言,法语作为目标语言。

Create a Crowdin project with english as source language, and french as target language

您的项目已创建,但目前为空。我们将在接下来的步骤中上传要翻译的文件。

创建 Crowdin 配置

此配置 (文档) 为 Crowdin CLI 提供了映射,以理解

  • 在哪里找到要上传的源文件(JSON 和 Markdown)
  • 翻译后文件下载到哪里(在 i18n/[locale] 中)

website 中创建 crowdin.yml

crowdin.yml
project_id: '123456'
api_token_env: CROWDIN_PERSONAL_TOKEN
preserve_hierarchy: true
files:
# JSON translation files
- source: /i18n/en/**/*
translation: /i18n/%two_letters_code%/**/%original_file_name%
# Docs Markdown files
- source: /docs/**/*
translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%
# Blog Markdown files
- source: /blog/**/*
translation: /i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%

Crowdin 有其自己的语法来声明源/翻译路径

  • **/*: 子文件夹中的所有内容
  • %two_letters_code%: Crowdin 目标语言的两字母变体(在本例中为 fr
  • **/%original_file_name%: 译文将保留原始文件夹/文件层级结构
信息

Crowdin CLI 的警告并非总是容易理解。

我们建议

  • 一次只更改一项
  • 在任何配置更改后重新上传源文件
  • 使用以 / 开头的路径(./ 不起作用)
  • 避免使用像 /docs/**/*.(md|mdx) 这样的复杂通配符模式(不起作用)

访问令牌

api_token_env 属性定义了 Crowdin CLI 读取的环境变量名称。

您可以在您的个人资料页面上获取“个人访问令牌”。

提示

您可以保留默认值 CROWDIN_PERSONAL_TOKEN,并将此环境变量设置到您的电脑和 CI 服务器上,以使用生成的访问令牌。

警告

个人访问令牌授予对您所有 Crowdin 项目的读写访问权限。

您不应**提交**它,最好为您的公司创建一个专用的 **Crowdin 配置文件**,而不是使用个人账户。

其他配置字段

  • project_id: 可以硬编码,可在 https://crowdin.com/project/<MY_PROJECT_NAME>/settings#api 上找到
  • preserve_hierarchy: 在 Crowdin UI 上保留文档的文件夹层级结构,而不是将其全部扁平化

安装 Crowdin CLI

本教程使用 CLI 版本 3.5.2,但我们预计 3.x 版本仍将可用。

将 Crowdin CLI 作为 npm 包安装到您的 Docusaurus 站点

npm install @crowdin/cli@3

添加一个 crowdin 脚本

package.json
{
"scripts": {
// ...
"write-translations": "docusaurus write-translations",
"crowdin": "crowdin"
}
}

测试您是否可以运行 Crowdin CLI

npm run crowdin -- --version

在您的电脑上设置 CROWDIN_PERSONAL_TOKEN 环境变量,以允许 CLI 使用 Crowdin API 进行身份验证。

提示

您可以暂时在 crowdin.yml 中硬编码您的个人令牌,使用 api_token: 'MY-TOKEN'

上传源文件

website/i18n/en 中生成默认语言的 JSON 翻译文件

npm run write-translations

上传所有 JSON 和 Markdown 翻译文件

npm run crowdin upload

Crowdin CLI uploading Docusaurus source files

您的源文件现在在 Crowdin 界面上可见:https://crowdin.com/project/<MY_PROJECT_NAME>/settings#files

Crowdin UI showing Docusaurus source files

翻译源文件

https://crowdin.com/project/<MY_PROJECT_NAME> 上,点击法语目标语言。

Crowdin UI showing French translation files

翻译一些 Markdown 文件。

Crowdin UI to translate a Markdown file

提示

使用**“隐藏字符串”**功能,确保译者**不会翻译不应翻译的内容**

  • Front matter(头部元数据):id, slug, tags ...
  • 提示块(Admonitions)::::, :::note, :::tip ...

Crowdin UI hide string

翻译一些 JSON 文件。

Crowdin UI to translate a JSON file

信息

JSON 翻译文件的 description 属性在 Crowdin 上可见,以帮助翻译字符串。

提示

**预翻译**您的站点,并**手动修复预翻译错误**(首先在设置中启用全局翻译记忆库)。

首先使用**“隐藏字符串”**功能,因为 Crowdin 会过于乐观地进行预翻译。

下载译文

使用 Crowdin CLI 下载翻译后的 JSON 和 Markdown 文件。

npm run crowdin download

翻译后的内容应该下载到 i18n/fr 中。

以法语区域设置启动您的站点

npm run start -- --locale fr

确保您的网站现在已在 https://:3000/ 处翻译成法文。

使用 CI 自动化

我们将配置 CI 在**构建时下载 Crowdin 译文**,并将其保留在 Git 之外。

website/i18n 添加到 .gitignore

在您的 CI 上设置 CROWDIN_PERSONAL_TOKEN 环境变量。

创建一个 npm 脚本来 sync Crowdin(提取源文件、上传源文件、下载译文)

package.json
{
"scripts": {
"crowdin:sync": "docusaurus write-translations && crowdin upload && crowdin download"
}
}

在您的 CI 中,在构建 Docusaurus 站点之前调用 npm run crowdin:sync 脚本。

提示

保持您的部署预览快速:不要下载译文,并对功能分支使用 npm run build -- --locale en

警告

Crowdin 对多个并发上传/下载的支持不佳:最好只将译文包含在您的生产部署中,并保持部署预览未翻译。

高级 Crowdin 主题

MDX

警告

请特别注意 MDX 文档中的 JSX 片段!

Crowdin **官方不支持 MDX**,但他们添加了**对 .mdx 扩展的支持**,并将此类文件解释为 Markdown(而非纯文本)。

MDX 问题

Crowdin 认为 JSX 语法是嵌入式 HTML,并且在您下载译文时可能会弄乱 JSX 标记,导致站点因无效 JSX 而无法构建。

使用简单字符串属性(如 <Username name="Sebastien"/>)的简单 JSX 片段将正常工作;使用对象/数组属性(如 <User person={{name: "Sebastien"}}/>)的更复杂 JSX 片段则更有可能因其语法不像 HTML 而失败。

MDX 解决方案

我们建议将复杂的嵌入式 JSX 代码提取为单独的独立组件。我们还添加了一个 mdx-code-block 逃逸语法

# How to deploy Docusaurus

To deploy Docusaurus, run the following command:

````mdx-code-block 

import Tabs from '@theme/Tabs';

import TabItem from '@theme/TabItem';

<Tabs>
<TabItem value="bash" label="Bash">

```bash
GIT_USER=<GITHUB_USERNAME> yarn deploy
```

</TabItem>
<TabItem value="windows" label="Windows">

```batch
cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy"
```

</TabItem>
</Tabs>
````

这将

  • 被 Crowdin 解释为代码块(并且在下载时不会弄乱标记)
  • 被 Docusaurus 解释为常规 JSX(就像它没有被任何代码块包裹一样)
  • 不幸的是,这会退出 MDX 工具链(IDE 语法高亮、Prettier 等)

文档版本控制

website/versioned_docs 文件夹配置翻译文件。

创建新版本时,源字符串通常与当前版本 (website/docs) 非常相似,您不会希望一次又一次地翻译新版本文档。

Crowdin 提供**“重复字符串”**设置。

Crowdin Duplicate Strings option setting

我们建议使用**“隐藏”**,但理想设置取决于您的版本差异有多大。

警告

不使用**“隐藏”**会导致配额中的源字符串数量大大增加,并会影响定价。

多实例插件

您需要为每个插件实例配置翻译文件。

如果您有一个 id=ios 的文档插件实例,您还需要配置这些源文件

  • website/ios
  • website/ios_versioned_docs(如果已版本化)

维护您的站点

有时,您会在 Git 上**删除或重命名源文件**,Crowdin 将显示 CLI 警告

Crowdin CLI: download translation warning

当您的源文件重构时,您应该使用 Crowdin UI **手动更新您的 Crowdin 文件**

Crowdin UI: renaming a file

VCS (Git) 集成

Crowdin 有多个 VCS 集成,适用于 GitHub、GitLab、Bitbucket。

TL;DR

我们建议避免使用它们。

能够在 Git 和 Crowdin 中同时编辑译文,并在两个系统之间进行**双向同步**本可能有所帮助。

实际上,由于以下几个原因,它**工作得不太可靠**

  • Crowdin -> Git 同步工作正常(通过拉取请求)
  • Git -> Crowdin 同步是手动的(您必须按一个按钮)
  • Crowdin 用于将现有 Markdown 译文与现有 Markdown 源文件匹配的启发式算法并非 100% 可靠,您必须在从 Git 同步后在 Crowdin UI 上验证结果
  • 2 个用户同时在 Git 和 Crowdin 上编辑可能导致译文丢失
  • 它要求 crowdin.yml 文件位于仓库的根目录

情境化本地化

Crowdin 有一个情境化本地化功能。

警告

不幸的是,由于技术原因,它目前尚无法工作,但我们很有希望能够解决。

Crowdin 用诸如 crowdin:id12345 这样的技术 ID 替换 Markdown 字符串,但它这样做过于激进,包括隐藏字符串,并会弄乱 front matter、提示块、JSX 等。

本地化编辑 URL

当用户在 /doc1 浏览页面时,编辑按钮默认会链接到 website/docs/doc1.md 处的未本地化文档。

您可能更希望编辑按钮链接到 Crowdin 界面,可以通过使用 editUrl 函数根据每个区域设置自定义编辑 URL。

docusaurus.config.js
const DefaultLocale = 'en';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
editUrl: ({locale, versionDocsDirPath, docPath}) => {
// Link to Crowdin for French docs
if (locale !== DefaultLocale) {
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
}
// Link to GitHub for English docs
return `https://github.com/facebook/docusaurus/edit/main/website/${versionDocsDirPath}/${docPath}`;
},
},
blog: {
editUrl: ({locale, blogDirPath, blogPath}) => {
if (locale !== DefaultLocale) {
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
}
return `https://github.com/facebook/docusaurus/edit/main/website/${blogDirPath}/${blogPath}`;
},
},
},
],
],
};
注意

目前**无法链接到 Crowdin 中的特定文件**。

示例配置

Docusaurus 配置文件是使用版本控制和多实例的一个很好的例子

crowdin.yml
project_id: '428890'
api_token_env: CROWDIN_PERSONAL_TOKEN
preserve_hierarchy: true
languages_mapping: &languages_mapping
two_letters_code:
pt-BR: pt-BR
files:
- source: /website/i18n/en/**/*
translation: /website/i18n/%two_letters_code%/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/docs/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/community/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-docs-community/current/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/versioned_docs/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-docs/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/blog/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/src/pages/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-pages/**/%original_file_name%
ignore: [/**/*.js, /**/*.jsx, /**/*.ts, /**/*.tsx, /**/*.css]
languages_mapping: *languages_mapping

机器翻译 (MT) 问题:链接/图片处理

Crowdin 最近对 Markdown 文件格式进行了一些重大更改,现在链接的处理方式与以前不同。之前它们被视为标签,但现在显示为纯文本。由于这些更改,纯文本链接会传递给 MT 引擎,该引擎会尝试翻译目标,从而破坏翻译(例如:字符串 Allez voir [ma merveilleuse page](/ma-merveilleuse-page) 被翻译成 Check out [my wonderful page](/my-wonderful-page),这破坏了 Docusaurus 的 i18n 工作流,因为页面名称不应被翻译)。

截至 2023 年 12 月 7 日,他们不打算改变链接处理的逻辑,因此如果您计划将 Crowdin 与 MT 一起使用,应牢记这一点。