国际化 - 使用 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 已成功使用它来翻译 Jest、Docusaurus 和 ReasonML 等文档项目。
¥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.app(repository)处看到。
¥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:
export default {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
themeConfig: {
navbar: {
items: [
// ...
{
type: 'localeDropdown',
position: 'left',
},
// ...
],
},
},
// ...
};
翻译主页:
¥Translate the homepage:
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.
你的项目已创建,但目前是空的。我们将在接下来的步骤中上传要翻译的文件。
¥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
:
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 onhttps://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
- Yarn
- pnpm
npm install @crowdin/cli@3
yarn add @crowdin/cli@3
pnpm add @crowdin/cli@3
添加 crowdin
脚本:
¥Add a crowdin
script:
{
"scripts": {
// ...
"write-translations": "docusaurus write-translations",
"crowdin": "crowdin"
}
}
测试你是否可以运行 Crowdin CLI:
¥Test that you can run the Crowdin CLI:
- npm
- Yarn
- pnpm
npm run crowdin -- --version
yarn crowdin --version
pnpm 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.yml
和 api_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
- Yarn
- pnpm
npm run write-translations
yarn write-translations
pnpm run write-translations
上传所有 JSON 和 Markdown 翻译文件:
¥Upload all the JSON and Markdown translation files:
- npm
- Yarn
- pnpm
npm run crowdin upload
yarn crowdin upload
pnpm run crowdin upload
你的源文件现在在 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
翻译来源
¥Translate the sources
在 https://crowdin.com/project/<MY_PROJECT_NAME>
,单击法语目标语言。
¥On https://crowdin.com/project/<MY_PROJECT_NAME>
, click on the French target language.
翻译一些 Markdown 文件。
¥Translate some Markdown files.
使用 Hide String
确保译者不会翻译不应该翻译的内容:
¥Use Hide String
to make sure translators don't translate things that should not be:
-
前置事项:
id
、slug
、tags
...¥Front matter:
id
,slug
,tags
... -
警告:
:::
、:::note
、:::tip
...¥Admonitions:
:::
,:::note
,:::tip
...
翻译一些 JSON 文件。
¥Translate some JSON files.
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
- Yarn
- pnpm
npm run crowdin download
yarn crowdin download
pnpm run crowdin download
翻译内容应在 i18n/fr
年下载。
¥The translated content should be downloaded in i18n/fr
.
在法语语言环境中启动你的网站:
¥Start your site on the French locale:
- npm
- Yarn
- pnpm
npm run start -- --locale fr
yarn run start --locale fr
pnpm 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):
{
"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.
我们建议使用 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 UI 手动更新你的 Crowdin 文件:
¥When your sources are refactored, you should use the Crowdin UI to update your Crowdin files manually:
VCS (Git) 集成
¥VCS (Git) integrations
Crowdin 具有针对 GitHub、GitLab、Bitbucket 的多个 VCS 集成。
¥Crowdin has multiple VCS integrations for GitHub, GitLab, Bitbucket.
我们建议避免使用它们。
¥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.
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:
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.