跳到主要內容
版本:3.5.2

i18n - 教學

本教學將帶您深入了解 Docusaurus i18n 系統 的基本知識。

我們將在 新初始化的英文 Docusaurus 網站 中新增 法文 翻譯。

使用 npx create-docusaurus@latest website classic 初始化一個新網站(像 這個)。

設定你的網站

修改 docusaurus.config.js 來新增對法文語言的 i18n 支援。

網站組態

使用 網站 i18n 組態 來宣告 i18n 的區域設定

docusaurus.config.js
export default {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'fa'],
localeConfigs: {
en: {
htmlLang: 'en-GB',
},
// You can omit a locale (e.g. fr) if you don't need to override the defaults
fa: {
direction: 'rtl',
},
},
},
};

地區名稱用於翻譯檔案的位置,以及您所翻譯地區的基本 URL。在建置所有地區時,僅有預設地區的名稱會被省略在基本 URL 中。

Docusaurus 使用地區名稱來提供**合理的預設值**:<html lang="..."> 屬性、地區標籤、行事曆格式等。您可以使用 localeConfigs 來自訂這些預設值。

佈景主題設定

新增一個**導覽列項目**類型為 localeDropdown,讓使用者可以選擇他們想要的語言

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

當使用者使用下拉式選單變更地區時,您可以傳遞一個查詢參數,該參數將附加到 URL 裡(例如:queryString: '?persistLocale=true')。

這對於在您的伺服器上實作自動地區偵測非常有用。例如,您可以使用這個參數來將使用者的偏好地區儲存在 cookie 裡。

啟動您的網站

使用您選擇的地區,在開發模式下啟動您的地區化網站

npm run start -- --locale fr

您的網站位址為 https://127.0.0.1:3000/fr/

我們尚未提供任何翻譯,因此該網站大多未翻譯。

提示

Docusaurus 提供**預設翻譯**給佈景主題的一般標籤,例如分頁的「下一頁」和「上一頁」。

請協助我們完成這些**預設翻譯

警告

每個地區都是一個**獨立的單頁應用程式**:不可能同時啟動所有地區的 Docusaurus 網站。

翻譯您的網站

法語區的翻譯資料都儲存在 website/i18n/fr 中。各個外掛會在其對應的資料夾裡提供自身的翻譯內容,而 code.json 檔案定義 React 程式碼中所有使用的文字標籤。

注意事項

複製檔案後,使用 npm run start -- --locale fr 重新啟動你的網站。編輯現有檔案時,熱重載功能會發揮更好的作用。

翻譯你的 React 程式碼

對於你自行撰寫的 React 程式碼(例如 React 頁面、React 元件等),你將會使用translation API

在你的 React 程式碼中找出所有會顯示給使用者的文字標籤,並利用 translation API 標示它們。共有兩種 API

  • <Translate> 元件會將字串包覆為 JSX 元素
  • translate() 回呼會接收訊息並傳回字串

使用在語意上比較符合情境的 API。例如,<Translate> 可以用作 React 子代,而對於預期使用字串的屬性,則可以使用回呼。

警告

JSX 元素是一種物件,而非字串。在預期為字串的情境中使用它(例如:<option> 的子代),會將其轉換為字串,並傳回 "[object Object]"。雖然我們建議你將 <Translate> 用作 JSX 子代,但只有在它實際運作時才使用元素形式。

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.dev.org.tw/blog">blog</Link>
<img
src="/img/home.png"
alt="Home icon"
/>
</main>
</Layout>
);
}
資訊

Docusaurus 特意提供一個非常小巧精簡的翻譯執行時期環境,且僅支援利用 佔位符插入 子集執行的基本 ICU 訊息格式

大多數的文件網站通常是靜態的,不需要進階的 i18n 功能(複數性別等)。對於進階使用案例,使用套件庫,例如 react-intl

docusaurus write-translations 命令會在您的網站中靜態分析所有使用的 React 程式碼檔案,擷取對這些 API 的呼叫,並將它們集中在 code.json 檔案中。翻譯檔案會儲存在 ID 對應到翻譯訊息物件(包括已翻譯標籤和標籤描述)的對應中。在呼叫翻譯 API(translate())時,您需要指定預設未翻譯訊息或 ID,以便 Docusaurus 正確將每個翻譯項目與 API 呼叫關聯。

文字標籤必須是靜態的

docusaurus write-translations 命令只會針對您的程式碼做靜態分析。它不會實際執行您的網站。因此,動態訊息無法擷取,因為該訊息是表達式,而不是字串

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>
);
}

這在執行時期仍然執行正確。然而,在未來,我們可能會提供「無執行時期」機制,讓翻譯可以透過 Babel 轉換直接內嵌在 React 程式碼中,而不必在執行時期呼叫 API。因此,要達到讓它未來適用,您應該總是偏好能被靜態分析的訊息。例如,我們可以將上方的程式碼重構為

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>
);
}

您可以將對翻譯 API 的呼叫視為純粹的標記,告訴 Docusaurus「這裡有一個要替換成已翻譯訊息的文字標籤」。

複數化方式

當您執行 write-translations 時,您會注意到有些標籤是已複數化的

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

每種語言都會有一列 可能的複數類別。Docusaurus 會將它們排列成 ["zero", "one", "two", "few", "many", "other"] 的順序。例如,因為英文(en)有兩種複數形式(「單數」和「其他」),所以翻譯訊息有兩種標籤,以直線(|)分隔。對於波蘭文(pl)有三種複數形式(「單數」、「少數」和「多數」),您會按順序提供三個標籤,再以直線連接起來。

您也可以將自己的程式碼訊息變成複數

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 使用 Intl.PluralRules 來解決並選擇複數形式。為 selectMessage 提供正確數量與順序的複數形式很重要。

翻譯外掛數據

JSON 翻譯檔案會使用在你的程式碼中穿插的所有內容

  • React 程式碼,包含你標示在上面的已翻譯標籤
  • 主題設定檔中的導覽列和頁尾標籤
  • sidebars.js 中的 Docs 側邊欄類別標籤
  • 外掛選項中的部落格側邊欄標題
  • ...

執行 write-translations 指令

npm run write-translations -- --locale fr

它將提取你需翻譯的 JSON 翻譯檔案並加以初始化。根目錄中的 code.json 檔案包含從原始程式碼提取的所有翻譯 API 呼叫,這些呼叫可能是你編寫的,或由主題提供的,其中有些可能已經預設翻譯。

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"
}
}

外掛和主題也會寫入自己的 JSON 翻譯檔案,例如

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"
}
}

i18n/fr 的 JSON 檔案中翻譯 message 屬性,你的網站版面和首頁現在應該已經翻譯完成。

翻譯 Markdown 檔案

官方的 Docusaurus 內容外掛廣泛使用 Markdown/MDX 檔案,並允許你翻譯它們。

翻譯文件

將你的文件 Markdown 檔案從 docs/ 複製到 i18n/fr/docusaurus-plugin-content-docs/current,並翻譯它們

mkdir -p i18n/fr/docusaurus-plugin-content-docs/current
cp -r docs/** i18n/fr/docusaurus-plugin-content-docs/current
資訊

請注意,docusaurus-plugin-content-docs 外掛始終依據版本區分其內容。./docs 資料夾中的資料將翻譯為 current 子資料夾和 current.json 檔案。關於「current」的進一步資訊,請參閱文件版本指南

翻譯部落格

將你的部落格 Markdown 檔案複製到 i18n/fr/docusaurus-plugin-content-blog,並翻譯它們

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

翻譯網頁

將你的網頁 Markdown 檔案複製到 i18n/fr/docusaurus-plugin-content-pages,並翻譯它們

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

我們只會複製 .md.mdx 檔案,因為 React 頁面已經透過 JSON 翻譯檔案翻譯了。

使用明確的標題 ID

預設情況下,Markdown 標題 ### Hello World 會產生 ID hello-world。其他文件可以用 [link](#hello-world) 連結這個標題。然而,翻譯標題後會變成 ### Bonjour le Monde,其 ID 則會變成 bonjour-le-monde

由於所有錨點連結都必須翻譯,因此產生 ID 未必適用於在地化網站。

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

若您的網站有在地化需求,建議您使用 明確標題 ID

部署您的網站

你可以選擇在 單一網域多個(次級)網域之下部署您的網站。

單網域部署

執行以下指令

npm run build

Docusaurus 會在 每個地區設定中組建單一頁面應用程式

  • website/build:預設的英文
  • website/build/fr:法文

現在您可以 部署 build 資料夾至您選擇的靜態託管解決方案。

注意事項
提示

根據慣例,靜態託管供應商通常會將 /unknown/url 重新導向至 /404.html,總是顯示 英文 404 頁面

在地化您的 404 頁面,方法是設定您的主機將 /fr/* 重新導向至 /fr/404.html

這並不總是可行,而且視您的主機而定:GitHub Pages 無法這麼做,但 Netlify 可以。

多網域部署

您也可以為單一地區設定組建您的網站

npm run build -- --locale fr

Docusaurus 不會加上 /fr/ URL 前置詞。

在您 靜態託管供應商

  • 為每個地區設定建立一個部署
  • 設定適當的組建指令,使用 --locale 選項
  • 為每個部署設定您選擇的(次級)網域
警告

此策略無法搭配 GitHub Pages 使用,因為它只允許 單一部署

混合式

可以讓一些地區設定使用子路徑,而其他地區設定使用次網域。

也可以將每個地區設定部署為單獨的子網域,並在 CDN 層級將這些子網域組裝成單一統一網域。

  • 將您的網站部署為 fr.docusaurus.io
  • 設定 CDN,讓它透過 docusaurus.io/fr 提供服務

管理翻譯

Docusaurus 不在乎你如何管理你的翻譯:它需要的只是所有翻譯檔案(JSON、Markdown 或其他資料檔案)在建置期間在檔案系統中可用。不過,身為網站建立者,你需要考慮翻譯的管理方式,以便翻譯貢獻者順利合作。

我們將分享兩種常見的翻譯合作策略:使用 Git使用 Crowdin.