跳到主要内容
版本:3.6.2

i18n - 教程

This tutorial will walk you through the basics of the Docusaurus i18n system.

We will add French translations to a newly initialized English Docusaurus website.

Initialize a new site with npx create-docusaurus@latest website classic (like this one).

Configure your site

Modify docusaurus.config.js to add the i18n support for the French language.

Site configuration

Use the site i18n configuration to declare the i18n locales:

docusaurus.config.js
export default {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'zh-Hans'],
localeConfigs: {
en: {
htmlLang: 'en-GB',
},
// 如果不需要重写默认值,可以忽略 locale (例如 fr)
'zh-Hans': {
direction: 'rtl',
},
},
},
};

语言名称会被用于翻译文件的位置以及你的本地化网站的 base URL。 构建所有语言时,只有默认语言才会在 base URL 中省略它的名字。

Docusaurus uses the locale names to provide sensible defaults: the <html lang="..."> attribute, locale label, calendar format, etc. You can customize these defaults with the localeConfigs.

Theme configuration

Add a navbar item of type localeDropdown so that users can select the locale they want:

docusaurus.config.js
export default {
themeConfig: {
navbar: {
items: [
{
type: 'localeDropdown',
position: 'left',
},
],
},
},
};
提示

You can pass a query parameter that will be appended to the URL when a user changes the locale using the dropdown (e.g. queryString: '?persistLocale=true').

这对于在服务器上实现自动区域设置检测非常有用。 譬如,您可以使用此参数将用户的首选区域设置存储在 cookie 中。

Start your site

以开发模式启动你的本地化站点,并使用你所选择的语言:

npm run start -- --locale zh-Hans

Your site is accessible at http://localhost:3000/fr/.

由于我们尚未添加任何译文,所以站点的大部分内容都没有被翻译。

提示

Docusaurus provides default translations for generic theme labels, such as "Next" and "Previous" for the pagination.

Please help us complete those default translations.

警告

Each locale is a distinct standalone single-page application: it is not possible to start the Docusaurus sites in all locales at the same time.

Translate your site

All translation data for the French locale is stored in website/i18n/fr. Each plugin sources its own translated content under the corresponding folder, while the code.json file defines all text labels used in the React code.

备注

After copying files around, restart your site with npm run start -- --locale fr. Hot-reload will work better when editing existing files.

Translate your React code

For any React code you've written yourself: React pages, React components, etc., you will use the translation APIs.

Locate all text labels in your React code that will be visible to your users, and mark them with the translation APIs. There are two kinds of APIs:

  • The <Translate> component wraps a string as a JSX element;
  • The translate() callback takes a message and returns a string.

复制文件后,请用 npm run start -- --locale zh-Hans 重新启动站点。 For example, the <Translate> can be used as React children, while for props that expect a string, the callback can be used.

警告

A JSX element is an object, not a string. Using it in contexts expecting strings (such as the children of <option>) would coerce it to a string, which returns "[object Object]". While we encourage you to use <Translate> as JSX children, only use the element form when it actually works.

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

export default function Home() {
return (
<Layout>
<h1>Welcome to my website</h1>
<main>
You can also visit my
<Link to="https://docusaurus.io/blog">blog</Link>
<img
src="/img/home.png"
alt="Home icon"
/>
</main>
</Layout>
);
}
信息

Docusaurus provides a very small and lightweight translation runtime on purpose, and only supports basic placeholders interpolation, using a subset of the ICU Message Format.

Most documentation websites are generally static and don't need advanced i18n features (plurals, genders, etc.). Use a library like react-intl for more advanced use-cases.

The docusaurus write-translations command will statically analyze all React code files used in your site, extract calls to these APIs, and aggregate them in the code.json file. The translation files will be stored as maps from IDs to translation message objects (including the translated label and the description of the label). In your calls to the translation APIs (<Translate> or translate()), you need to specify either the default untranslated message or the ID, in order for Docusaurus to correctly correlate each translation entry to the API call.

text labels must be static

The docusaurus write-translations command only does static analysis of your code. 如果有更高级的需要,请使用如 react-intl 一类的库。 Therefore, dynamic messages can't be extracted, as the message is an expression, not a string:

const items = [
{id: 1, title: 'Hello'},
{id: 2, title: 'World'},
];

function ItemsList() {
return (
<ul>
{/* DON'T DO THIS: doesn't work with the write-translations command */}
{items.map((item) => (
<li key={item.id}>
<Translate>{item.title}</Translate>
</li>
))}
<ul>
);
}

This still behaves correctly at runtime. However, in the future, we may provide a "no-runtime" mechanism, allowing the translations to be directly inlined in the React code through Babel transformations, instead of calling the APIs at runtime. Therefore, to be future-proof, you should always prefer statically analyzable messages. For example, we can refactor the code above to:

const items = [
{id: 1, title: <Translate>Hello</Translate>},
{id: 2, title: <Translate>World</Translate>},
];

function ItemsList() {
return (
<ul>
{/* The titles are now already translated when rendering! */}
{items.map((item) => (
<li key={item.id}>{item.title}</li>
))}
<ul>
);
}

You can see the calls to the translation APIs as purely markers that tell Docusaurus that "here's a text label to be replaced with a translated message".

Pluralization

When you run write-translations, you will notice that some labels are pluralized:

i18n/en/code.json
{
// ...
"theme.blog.post.plurals": "One post|{count} posts"
// ...
}

Every language will have a list of possible plural categories. Docusaurus will arrange them in the order of ["zero", "one", "two", "few", "many", "other"]. For example, because English (en) has two plural forms ("one" and "other"), the translation message has two labels separated by a pipe (|). For Polish (pl) which has three plural forms ("one", "few", and "many"), you would provide three labels in that order, joined by pipes.

你可以把翻译 API 的调用看作是纯标记,告诉 Docusaurus「这里有一个文本标签,把它替换成翻译好的信息」。

import {translate} from '@docusaurus/Translate';
import {usePluralForm} from '@docusaurus/theme-common';

function ItemsList({items}) {
// `usePluralForm` will provide the plural selector for the current locale
const {selectMessage} = usePluralForm();
// Select the appropriate pluralized label based on `items.length`
const message = selectMessage(
items.length,
translate(
{message: 'One item|{count} items'},
{count: items.length},
),
);
return (
<>
<h2>{message}</h2>
<ul>{items.map((item) => <li key={item.id}>{item.title}</li>)}<ul>
</>
);
}
备注

Docusaurus uses Intl.PluralRules to resolve and select plural forms. It is important to provide the right number of plural forms in the right order for selectMessage to work.

Translate plugin data

你也可以给你自己的代码提供复数形式:

  • React 代码,包括你在上面标记的待翻译文本
  • 主题配置中的导航栏和页脚标签
  • Docs sidebar category labels in sidebars.js
  • 插件选项中的博客侧边栏标题
  • ……

Run the write-translations command:

npm run write-translations -- --locale zh-Hans

Docusaurus 使用 Intl.PluralRules 来解析并选择复数形式。 The code.json file at the root includes all translation API calls extracted from the source code, which could either be written by you or provided by the themes, some of which may already be translated by default.

i18n/fr/code.json
{
// No ID for the <Translate> component: the default message is used as ID
"Welcome to my website": {
"message": "Welcome to my website"
},
"home.visitMyBlog": {
"message": "You can also visit my {blog}",
"description": "The homepage message to ask the user to visit my blog"
},
"homepage.visitMyBlog.linkLabel": {
"message": "Blog",
"description": "The label for the link to my blog"
},
"Home icon": {
"message": "Home icon",
"description": "The homepage icon alt message"
}
}

Plugins and themes will also write their own JSON translation files, such as:

i18n/fr/docusaurus-theme-classic/navbar.json
{
"title": {
"message": "My Site",
"description": "The title in the navbar"
},
"item.label.Docs": {
"message": "Docs",
"description": "Navbar item with label Docs"
},
"item.label.Blog": {
"message": "Blog",
"description": "Navbar item with label Blog"
},
"item.label.GitHub": {
"message": "GitHub",
"description": "Navbar item with label GitHub"
}
}

Translate the message attribute in the JSON files of i18n/fr, and your site layout and homepage should now be translated.

Translate Markdown files

运行 写入翻译 命令:

Translate the docs

Copy your docs Markdown files from docs/ to i18n/fr/docusaurus-plugin-content-docs/current, and translate them:

mkdir -p i18n/zh-Hans/docusaurus-plugin-content-docs/current
cp -r docs/** i18n/zh-Hans/docusaurus-plugin-content-docs/current
信息

Notice that the docusaurus-plugin-content-docs plugin always divides its content by versions. The data in ./docs folder will be translated in the current subfolder and current.json file. See the doc versioning guide for more information about what "current" means.

Translate the blog

Copy your blog Markdown files to i18n/fr/docusaurus-plugin-content-blog, and translate them:

mkdir -p i18n/zh-Hans/docusaurus-plugin-content-blog
cp -r blog/** i18n/zh-Hans/docusaurus-plugin-content-blog

Translate the pages

Copy your pages Markdown files to i18n/fr/docusaurus-plugin-content-pages, and translate them:

mkdir -p i18n/zh-Hans/docusaurus-plugin-content-pages
cp -r src/pages/**.md i18n/zh-Hans/docusaurus-plugin-content-pages
cp -r src/pages/**.mdx i18n/zh-Hans/docusaurus-plugin-content-pages
警告

We only copy .md and .mdx files, as React pages are translated through JSON translation files already.

Use explicit heading IDs

By default, a Markdown heading ### Hello World will have a generated ID hello-world. Other documents can link it with [link](#hello-world). However, after translation, the heading becomes ### Bonjour le Monde, with ID bonjour-le-monde.

我们只复制了 .md.mdx 文件,因为 React 页面已经在前文中用 JSON 文件翻译好了。

- [link](#hello-world).
+ [link](#bonjour-le-monde)

For localized sites, it is recommended to use explicit heading IDs.

Deploy your site

You can choose to deploy your site under a single domain or use multiple (sub)domains.

Single-domain deployment

这样,你就得本地化所有锚点链接。所以,自动生成 ID 通常不适合本地化站点。

npm run build

Docusaurus will build one single-page application per locale:

  • website/build: for the default, English language
  • website/build/fr: for the French language

You can now deploy the build folder to the static hosting solution of your choice.

备注

The Docusaurus website uses this strategy:

提示

Static hosting providers generally redirect /unknown/url to /404.html by convention, always showing an English 404 page.

Localize your 404 pages by configuring your host to redirect /fr/* to /fr/404.html.

This is not always possible, and depends on your host: GitHub Pages can't do this, Netlify can.

Multi-domain deployment

静态托管商通常会按惯例把 /unknown/url 重定向到 /404.html,这样就会始终显示英文版 404 错误页面

npm run build -- --locale zh-Hans

Docusaurus will not add the /fr/ URL prefix.

On your static hosting provider:

  • 为每种语言做一份部署
  • configure the appropriate build command, using the --locale option
  • 为每份部署配置一个(子)域名
警告

This strategy is not possible with GitHub Pages, as it is only possible to have a single deployment.

Hybrid

在你的静态托管商上:

It is also possible to deploy each locale as a separate subdomain, assemble the subdomains in a single unified domain at the CDN level:

  • Deploy your site as fr.docusaurus.io
  • Configure a CDN to serve it from docusaurus.io/fr

Managing translations

Docusaurus doesn't care about how you manage your translations: all it needs is that all translation files (JSON, Markdown, or other data files) are available in the file system during building. However, as site creators, you would need to consider how translations are managed so your translation contributors could collaborate well.

We will share two common translation collaboration strategies: using git and using Crowdin.