Skip to main content
Version: 3.5.1

国际化 - 使用 Crowdin

¥i18n - Using Crowdin

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

¥The i18n system of Docusaurus is decoupled from any translation software.

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

¥You can integrate Docusaurus with the tools and SaaS of your choice, as long as you put the translation files at the correct location.

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

¥We document the usage of Crowdin, as one possible integration example.

警告

这并不是认可 Crowdin 作为翻译 Docusaurus 网站的唯一选择,但 Facebook 已成功使用它来翻译 JestDocusaurusReasonML 等文档项目。

¥This is not an endorsement of Crowdin as the unique choice to translate a Docusaurus site, but it is successfully used by Facebook to translate documentation projects such as Jest, Docusaurus, and ReasonML.

请参阅 Crowdin 文档Crowdin 支持 寻求帮助。

¥Refer to the Crowdin documentation and Crowdin support for help.

提示

使用此 社区驱动的 GitHub 讨论 讨论与 Docusaurus + Crowdin 相关的任何内容。

¥Use this community-driven GitHub discussion to discuss anything related to Docusaurus + Crowdin.

Crowdin 概述

¥Crowdin overview

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

¥Crowdin is a translation SaaS, offering a free plan for open-source projects.

我们推荐以下翻译工作流程:

¥We recommend the following translation workflow:

  • 将源文件上传到 Crowdin(未翻译的文件)

    ¥Upload sources to Crowdin (untranslated files)

  • 使用 Crowdin 翻译内容

    ¥Use Crowdin to translate the content

  • 从 Crowdin 下载翻译(本地化翻译文件)

    ¥Download translations from Crowdin (localized translation files)

Crowdin 提供了 CLI 来上传源文件和下载翻译,允许你自动化翻译过程。

¥Crowdin provides a CLI to upload sources and download translations, allowing you to automate the translation process.

crowdin.yml configuration file 对于 Docusaurus 来说很方便,并且允许在预期位置(在 i18n/[locale]/.. 中)下载本地化翻译文件。

¥The crowdin.yml configuration file is convenient for Docusaurus, and permits to download the localized translation files at the expected location (in i18n/[locale]/..).

阅读 官方文档 以了解有关高级功能和不同翻译工作流程的更多信息。

¥Read the official documentation to know more about advanced features and different translation workflows.

Crowdin 教程

¥Crowdin tutorial

这是使用 Crowdin 将新初始化的英语 Docusaurus 网站翻译成法语的演练,并假设你已经关注了 国际化教程

¥This is a walk-through of using Crowdin to translate a newly initialized English Docusaurus website into French, and assume you already followed the i18n tutorial.

最终结果可以在 docusaurus-crowdin-example.netlify.apprepository)处看到。

¥The end result can be seen at docusaurus-crowdin-example.netlify.app (repository).

准备 Docusaurus 站点

¥Prepare the Docusaurus site

初始化一个新的 Docusaurus 站点:

¥Initialize a new Docusaurus site:

npx create-docusaurus@latest website classic

添加法语站点配置:

¥Add the site configuration for the French language:

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

翻译主页:

¥Translate the homepage:

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 项目

¥Create a Crowdin project

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

¥Sign up on Crowdin, and create a project.

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

¥Use English as the source language, and French as the target language.

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

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

¥Your project is created, but it is empty for now. We will upload the files to translate in the next steps.

创建 Crowdin 配置

¥Create the Crowdin configuration

此配置 (doc) 提供了 Crowdin CLI 可以理解的映射:

¥This configuration (doc) provides a mapping for the Crowdin CLI to understand:

  • 在哪里可以找到要上传的源文件(JSON 和 Markdown)

    ¥Where to find the source files to upload (JSON and Markdown)

  • 翻译后的文件在哪里下载(i18n/[locale]

    ¥Where to download the files after translation (in i18n/[locale])

website 中创建 crowdin.yml

¥Create crowdin.yml in website:

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 有自己的语法来声明源/翻译路径:

¥Crowdin has its own syntax for declaring source/translation paths:

  • **/*:子文件夹中的所有内容

    ¥**/*: everything in a subfolder

  • %two_letters_code%:Crowdin 目标语言的 2 个字母变体(在我们的例子中为 fr

    ¥%two_letters_code%: the 2-letters variant of Crowdin target languages (fr in our case)

  • **/%original_file_name%:翻译将保留原始文件夹/文件层次结构

    ¥**/%original_file_name%: the translations will preserve the original folder/file hierarchy

信息

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

¥The Crowdin CLI warnings are not always easy to understand.

我们建议:

¥We advise to:

  • 一次改变一件事

    ¥change one thing at a time

  • 任何配置更改后重新上传源

    ¥re-upload sources after any configuration change

  • 使用以 / 开头的路径(./ 不起作用)

    ¥use paths starting with / (./ does not work)

  • 避免像 /docs/**/*.(md|mdx) 这样的奇特的通配模式(不起作用)

    ¥avoid fancy globbing patterns like /docs/**/*.(md|mdx) (does not work)

访问令牌

¥Access token

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

¥The api_token_env attribute defines the env variable name read by the Crowdin CLI.

你可以在 你的个人资料页面 上获得 Personal Access Token

¥You can obtain a Personal Access Token on your personal profile page.

提示

你可以保留默认值 CROWDIN_PERSONAL_TOKEN,并在你的计算机和 CI 服务器上将此环境变量设置为生成的访问令牌。

¥You can keep the default value CROWDIN_PERSONAL_TOKEN, and set this environment variable and on your computer and on the CI server to the generated access token.

警告

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

¥A Personal Access Tokens grant read-write access to all your Crowdin projects.

你不应该提交,为你的公司创建专用的 Crowdin 个人资料而不是使用个人账户可能是个好主意。

¥You should not commit it, and it may be a good idea to create a dedicated Crowdin profile for your company instead of using a personal account.

其他配置字段

¥Other configuration fields

  • project_id:可以硬编码,可以在 https://crowdin.com/project/<MY_PROJECT_NAME>/settings#api 上找到

    ¥project_id: can be hardcoded, and is found on https://crowdin.com/project/<MY_PROJECT_NAME>/settings#api

  • preserve_hierarchy:在 Crowdin UI 上保留文档的文件夹层次结构,而不是展平所有内容

    ¥preserve_hierarchy: preserve the folder's hierarchy of your docs on Crowdin UI instead of flattening everything

安装 Crowdin CLI

¥Install the Crowdin CLI

本教程使用 CLI 版本 3.5.2,但我们希望 3.x 版本继续工作。

¥This tutorial uses the CLI version 3.5.2, but we expect 3.x releases to keep working.

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

¥Install the Crowdin CLI as an npm package to your Docusaurus site:

npm install @crowdin/cli@3

添加 crowdin 脚本:

¥Add a crowdin script:

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

测试你是否可以运行 Crowdin CLI:

¥Test that you can run the Crowdin CLI:

npm run crowdin -- --version

在你的计算机上设置 CROWDIN_PERSONAL_TOKEN 环境变量,以允许 CLI 通过 Crowdin API 进行身份验证。

¥Set the CROWDIN_PERSONAL_TOKEN env variable on your computer, to allow the CLI to authenticate with the Crowdin API.

提示

暂时,你可以将你的个人令牌硬编码在 crowdin.ymlapi_token: 'MY-TOKEN' 中。

¥Temporarily, you can hardcode your personal token in crowdin.yml with api_token: 'MY-TOKEN'.

上传源码

¥Upload the sources

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

¥Generate the JSON translation files for the default language in website/i18n/en:

npm run write-translations

上传所有 JSON 和 Markdown 翻译文件:

¥Upload all the JSON and Markdown translation files:

npm run crowdin upload

Crowdin CLI uploading Docusaurus source files

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

¥Your source files are now visible on the Crowdin interface: https://crowdin.com/project/<MY_PROJECT_NAME>/settings#files

Crowdin UI showing Docusaurus source files

翻译来源

¥Translate the sources

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

¥On https://crowdin.com/project/<MY_PROJECT_NAME>, click on the French target language.

Crowdin UI showing French translation files

翻译一些 Markdown 文件。

¥Translate some Markdown files.

Crowdin UI to translate a Markdown file

提示

使用 Hide String 确保译者不会翻译不应该翻译的内容:

¥Use Hide String to make sure translators don't translate things that should not be:

  • 前置事项:idslugtags...

    ¥Front matter: id, slug, tags ...

  • 警告:::::::note:::tip...

    ¥Admonitions: :::, :::note, :::tip ...

Crowdin UI hide string

翻译一些 JSON 文件。

¥Translate some JSON files.

Crowdin UI to translate a JSON file

信息

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

¥The description attribute of JSON translation files is visible on Crowdin to help translate the strings.

提示

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

¥**Pre-translate** your site, and fix pre-translation mistakes manually (enable the Global Translation Memory in settings first).

首先使用 Hide String 功能,因为 Crowdin 的预翻译过于乐观。

¥Use the Hide String feature first, as Crowdin is pre-translating things too optimistically.

下载翻译

¥Download the translations

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

¥Use the Crowdin CLI to download the translated JSON and Markdown files.

npm run crowdin download

翻译内容应在 i18n/fr 年下载。

¥The translated content should be downloaded in i18n/fr.

在法语语言环境中启动你的网站:

¥Start your site on the French locale:

npm run start -- --locale fr

确保你的网站现已翻译成法语,地址为 http://localhost:3000/fr/

¥Make sure that your website is now translated in French at http://localhost:3000/fr/.

使用 CI 实现自动化

¥Automate with CI

我们将配置 CI 在构建时下载 Crowdin 翻译并将它们保存在 Git 之外。

¥We will configure the CI to download the Crowdin translations at build time and keep them outside of Git.

website/i18n 添加到 .gitignore

¥Add website/i18n to .gitignore.

在 CI 上设置 CROWDIN_PERSONAL_TOKEN 环境变量。

¥Set the CROWDIN_PERSONAL_TOKEN env variable on your CI.

sync Crowdin 创建一个 npm 脚本(提取源代码、上传源代码、下载翻译):

¥Create an npm script to sync Crowdin (extract sources, upload sources, download translations):

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

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

¥Call the npm run crowdin:sync script in your CI, just before building the Docusaurus site.

提示

保持部署预览快速:不要下载翻译,并使用 npm run build -- --locale en 作为功能分支。

¥Keep your deploy-previews fast: don't download translations, and use npm run build -- --locale en for feature branches.

警告

Crowdin 不太支持多个并发上传/下载:最好只将翻译包含到生产部署中,并保持部署预览不翻译。

¥Crowdin does not support well multiple concurrent uploads/downloads: it is preferable to only include translations to your production deployment, and keep deploy previews untranslated.

高级 Crowdin 主题

¥Advanced Crowdin topics

MDX

警告

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

¥Pay special attention to the JSX fragments in MDX documents!

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

¥Crowdin does not support officially MDX, but they added support for the .mdx extension, and interpret such files as Markdown (instead of plain text).

MDX 问题

¥MDX problems

Crowdin 认为 JSX 语法是嵌入的 HTML,当你下载翻译时可能会弄乱 JSX 标记,从而导致网站因无效的 JSX 而无法构建。

¥Crowdin thinks that the JSX syntax is embedded HTML and can mess up with the JSX markup when you download the translations, leading to a site that fails to build due to invalid JSX.

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

¥Simple JSX fragments using simple string props like <Username name="Sebastien"/> will work fine; more complex JSX fragments using object/array props like <User person={{name: "Sebastien"}}/> are more likely to fail due to a syntax that does not look like HTML.

MDX 解决方案

¥MDX solutions

我们建议将复杂的嵌入式 JSX 代码提取为单独的独立组件。我们还添加了 mdx-code-block 应急方案语法:

¥We recommend extracting the complex embedded JSX code as separate standalone components. We also added an mdx-code-block escape hatch syntax:

# 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>
````

这会:

¥This will:

  • 被 Crowdin 解释为代码块(并且不会弄乱下载时的标记)

    ¥be interpreted by Crowdin as code blocks (and not mess-up with the markup on download)

  • 被 Docusaurus 解释为常规 JSX(就好像它没有被任何代码块封装一样)

    ¥be interpreted by Docusaurus as regular JSX (as if it was not wrapped by any code block)

  • 不幸的是,选择退出 MDX 工具(IDE 语法高亮、Prettier...)

    ¥unfortunately opt-out of MDX tooling (IDE syntax highlighting, Prettier...)

文档版本控制

¥Docs versioning

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

¥Configure translation files for the website/versioned_docs folder.

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

¥When creating a new version, the source strings will generally be quite similar to the current version (website/docs), and you don't want to translate the new version docs again and again.

Crowdin 提供了 Duplicate Strings 设置。

¥Crowdin provides a Duplicate Strings setting.

Crowdin Duplicate Strings option setting

我们建议使用 Hide,但理想的设置取决于你的版本的差异程度。

¥We recommend using Hide, but the ideal setting depends on how much your versions are different.

警告

不使用 Hide 会导致配额中的 source strings 数量大大增加,并且会影响定价。

¥Not using Hide leads to a much larger amount of source strings in quotas, and will affect the pricing.

多实例插件

¥Multi-instance plugins

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

¥You need to configure translation files for each plugin instance.

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

¥If you have a docs plugin instance with id=ios, you will need to configure those source files as well

  • website/ios

  • website/ios_versioned_docs(如果有版本)

    ¥website/ios_versioned_docs (if versioned)

维护你的网站

¥Maintaining your site

有时,你会删除或重命名 Git 上的源文件,Crowdin 会显示 CLI 警告:

¥Sometimes, you will remove or rename a source file on Git, and Crowdin will display CLI warnings:

Crowdin CLI: download translation warning

当你的源代码被重构时,你应该使用 Crowdin UI 手动更新你的 Crowdin 文件:

¥When your sources are refactored, you should use the Crowdin UI to update your Crowdin files manually:

Crowdin UI: renaming a file

VCS (Git) 集成

¥VCS (Git) integrations

Crowdin 具有针对 GitHub、GitLab、Bitbucket 的多个 VCS 集成。

¥Crowdin has multiple VCS integrations for GitHub, GitLab, Bitbucket.

TL;DR

我们建议避免使用它们。

¥We recommend avoiding them.

如果能够在 Git 和 Crowdin 中编辑翻译,并在两个系统之间进行双向同步,可能会很有帮助。

¥It could have been helpful to be able to edit the translations in both Git and Crowdin, and have a bi-directional sync between the 2 systems.

在实践中,由于以下几个原因,它的工作不太可靠:

¥In practice, it didn't work very reliably for a few reasons:

  • Crowdin -> Git 同步工作正常(带有拉取请求)

    ¥The Crowdin -> Git sync works fine (with a pull request)

  • Git -> Crowdin 同步是手动的(你必须按一个按钮)

    ¥The Git -> Crowdin sync is manual (you have to press a button)

  • Crowdin 用于将现有 Markdown 翻译与现有 Markdown 源进行匹配的启发式方法并非 100% 可靠,在从 Git 同步后,你必须在 Crowdin UI 上验证结果

    ¥The heuristics used by Crowdin to match existing Markdown translations to existing Markdown sources are not 100% reliable, and you have to verify the result on Crowdin UI after any sync from Git

  • 2 个用户同时在 Git 和 Crowdin 上编辑可能会导致翻译丢失

    ¥2 users concurrently editing on Git and Crowdin can lead to a translation loss

  • 它要求 crowdin.yml 文件位于存储库的根目录下

    ¥It requires the crowdin.yml file to be at the root of the repository

上下文本地化

¥In-Context localization

Crowdin 具有 上下文本地化 功能。

¥Crowdin has an In-Context localization feature.

警告

不幸的是,由于技术原因,它还无法工作,但我们很好地希望它能够得到解决。

¥Unfortunately, it does not work yet for technical reasons, but we have good hope it can be solved.

Crowdin 用 crowdin:id12345 等技术 ID 替换了 Markdown 字符串,但这样做太过激进,包括隐藏字符串,并且弄乱了前言、警告、JSX……

¥Crowdin replaces Markdown strings with technical IDs such as crowdin:id12345, but it does so too aggressively, including hidden strings, and messes up with front matter, admonitions, JSX...

本地化编辑 URL

¥Localize edit URLs

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

¥When the user is browsing a page at /fr/doc1, the edit button will link by default to the unlocalized doc at website/docs/doc1.md.

你可能更喜欢将编辑按钮链接到 Crowdin 界面,而不是使用 editUrl 函数根据区域设置自定义编辑 URL。

¥You may prefer the edit button to link to the Crowdin interface instead by using the editUrl function to customize the edit URLs on a per-locale basis.

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 中的特定文件。

¥It is currently not possible to link to a specific file in Crowdin.

配置示例

¥Example configuration

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

¥The Docusaurus configuration file is a good example of using versioning and multi-instance:

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)问题:链接/图片处理

¥Machine Translation (MT) issue: links/image handling

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

¥Crowdin recently rolled out some major changes to the markdown file format and now the links are treated differently than they were before. Before they were considered as tags, but now they appear as plain text. Because of these changes the plain text links are passed to the MT engine which attempts to translate the target, thus breaking the translation (for instance: this string Allez voir [ma merveilleuse page](/ma-merveilleuse-page) is translated Check out [my wonderful page](/my-wonderful-page), and this breaks docusaurus i18n workflow as the page name should not be translated).

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

¥As of 2023 Dec.7, they are not planning to change the logic of how links are treated, so you should have this in mind if you plan to use Crowdin with MT.