i18n - チュートリアル
このチュートリアルでは、Docusaurus i18nシステムの基本について説明します。
新しく初期化された英語 Docusaurus ウェブサイト にフランス語の翻訳を追加します。
npx create-docusaurus@latest website classic
で新しいサイトを初期化します( ここのように)
サイトの設定
docusaurus.config.js
を変更して、フランス語の i18n サポートを追加します。
サイト設定
サイトに i18n ロケールを宣言するには、 サイト i18n 設定 を使用してください:
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
でカスタマイズできます。
Theme configuration
navbar item に localeDropdown
タイプを追加して、ユーザーが望むロケールを選択できるようにします:
export default {
themeConfig: {
navbar: {
items: [
{
type: 'localeDropdown',
position: 'left',
},
],
},
},
};
ユーザーがドロップダウンを使用してロケールを変更したときにURLに追加されるクエリパラメータを渡すことができます。(例: queryString: '?persistLocale=true'
)
これは、サーバーに自動ロケール検出を実装する場合に便利です。 たとえば、このパラメータを使用して、ユーザーの好みのロケールをクッキーに保存できます。
サイトを動かしましょう
指定したロケールで、ローカライズされたサイトを開発モードで起動します。
- npm
- Yarn
- pnpm
npm run start -- --locale fr
yarn run start --locale fr
pnpm run start --locale fr
あなたのサイトは、 http://localhost:3000/fr/
でアクセスできます。
サイトを翻訳していないので、ほとんど未翻訳のままです。
Docusaurusでは、ページネーションの「Next」や「Previous」のような一般的なテーマラベルにデフォルトの翻訳を提供しています。
**デフォルトの翻訳**を完成させるためにご協力をお願いいたします。
各ロケールは 個別のスタンドアロンシングルページアプリケーションです: Docusaurusサイトをすべてのロケールで同時に起動することはできません。
サイトを翻訳
フランス語ロケールのすべての翻訳データは、 website/i18n/fr
に保存されます。 各プラグインは、対応するフォルダの下にある独自の翻訳コンテンツをソースとし、code.json
ファイルにはReactコードで使用されるすべてのテキストラベルが定義されています。
ファイルをコピーした後、サイトを npm run start -- -locale fr
で再起動します。 ホットリロードは、既存のファイルを編集するときにうまく動作します。
React のコードを翻訳
あなた自身で書いた React のコード: React のページ、React のコンポーネントなどについては、 翻訳 API を使用します。
Reactのコードの中で、ユーザーに見えるテキストラベルをすべて探し出し、翻訳APIでマークします。 APIには2種類あります。
<Translate>
コンポーネントは文字列を JSX 要素としてラップします。translate()
コールバックは、メッセージを受け取り、文字列を返します。
より意味的に文脈に合った方を使ってください。 例えば、 <Translate>
は React の子要素として使用でき、文字列を期待する props ではコールバックを使用できます。
- Before
- After
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>
);
}
import React from 'react';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import Translate, {translate} from '@docusaurus/Translate';
export default function Home() {
return (
<Layout>
<h1>
<Translate>Welcome to my website</Translate>
</h1>
<main>
<Translate
id="homepage.visitMyBlog"
description="The homepage message to ask the user to visit my blog"
values={{
blogLink: (
<Link to="https://docusaurus.io/blog">
<Translate
id="homepage.visitMyBlog.linkLabel"
description="The label for the link to my blog">
blog
</Translate>
</Link>
),
}}>
{'You can also visit my {blogLink}'}
</Translate>
<img
src="/img/home.png"
alt={
translate({
message: 'Home icon',
description: 'The homepage icon alt message',
})
}
/>
</main>
</Layout>
);
}
Docusaurus は意図的に 非常に小型で軽量の翻訳ランタイム を提供し、 ICU メッセージ形式 のサブセットを使用した基本的な プレースホルダ補間 のみをサポートします。
ほとんどのドキュメントのウェブサイトは一般的に 静的 であり、高度なi18n機能(複数形、 性別など) は必要ありません。 より高度なユースケースには、 react-intl のようなライブラリを使用してください。
docusaurus write-translations
コマンドは、サイトで使用されているすべての React コード ファイルを静的に分析し、これらの API への呼び出しを抽出して、code.json
ファイルに集約します。 翻訳ファイルは、IDから翻訳メッセージオブジェクト(翻訳ラベルとラベルの説明を含む) までのマップとして保存されます。 翻訳 API (<Translate>
または translate()
) の呼び出しでは、Docusaurus が正しく翻訳できるように、デフォルトの未翻訳メッセージまたは ID を指定する必要があります。各翻訳エントリを 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>
);
}
これは実行時でも正しく動作します。 しかし、将来的には、"no-runtime"メカニズムを提供するかもしれません。 実行時にAPIを呼び出すのではなく、Babelの変換を介してReactコード内で直接インライン化できるようにします。 したがって、将来に備えて、常に静的に分析可能なメッセージにしておく必要があります。 例えば、上記のコードをリファクタリングできます。
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
を実行すると、いくつかのラベルが複数形になっていることがわかります。
{
// ...
"theme.blog.post.plurals": "One post|{count} posts"
// ...
}
どの言語にも複数形化可能なカテゴリーのリストがあります。 Docusaurusは ["0", "1", "2", "few", "many", "other"]
の順に並べます。 たとえば、英語 (en
) には 2 つの複数形 (「one」と「other」) があるため、翻訳メッセージにはパイプ (|
) で区切られた 2 つのラベルが含まれます。 3 つの複数形 (「one」、「few」、「many」) を持つポーランド語 (pl
) の場合、3 つのラベルをこの順序でパイプで結合して指定します。
独自のコードのメッセージを複数形にすることもできます。
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
のドキュメントサイドバーカテゴリラベル- プラグインオプションのサイドバータイトル
- ...
write-translations コマンドを実行します。
- npm
- Yarn
- pnpm
npm run write-translations -- --locale fr
yarn write-translations --locale fr
pnpm run write-translations --locale fr
翻訳する必要がある JSON 翻訳ファイルを抽出し、初期化します。 ルートの code.json
ファイルには、ソース コードから抽出されたすべての翻訳 API 呼び出しが含まれています。これはユーザーが作成したもの、またはテーマによって提供されたもので、デフォルトですでに翻訳されているものもあります。
{
// 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:
{
"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ファイルを幅広く使用し、それらを翻訳できます。
ドキュメントを翻訳
docs/
から i18n/fr/docusaurus-plugin-content-docs/current
にMarkdownファイルをコピーして、それから翻訳します。
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""が意味することの詳細については、 ドキュメントバージョン管理ガイド を参照してください。
ブログを翻訳
docs/ から i18n/fr/docusaurus-plugin-content-docs-blog
にMarkdownファイルをコピーして、それから翻訳します。
mkdir -p i18n/fr/docusaurus-plugin-content-blog
cp -r blog/** i18n/fr/docusaurus-plugin-content-blog
ページを翻訳
docs/ から i18n/fr/docusaurus-plugin-content-docs-pages
にMarkdownファイルをコピーして、それから翻訳します。
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
We only copy .md
and .mdx
files, as React pages are translated through JSON translation files already.
デフォルトでは、マークダウンの見出し ### 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
- Yarn
- pnpm
npm run build
yarn build
pnpm run build
Docusaurus は、ロケールごとに 1 つのシングルページ アプリケーションを構築します。
website/build
: デフォルト、英語website/build/fr
: フランス語用
You can now deploy the build
folder to the static hosting solution of your choice.
以下のDocusaurusウェブサイトはこの戦略を使用しています。
静的ホスティングプロバイダは、通常、 /unknown/url
を /404.html
にリダイレクトし、常に 英語の 404 ページ を表示します。
/fr/*
を /fr/404.html
にリダイレクトするようにホストを設定することで、404ページをローカライズします。
This is not always possible, and depends on your host: GitHub Pages can't do this, Netlify can.
マルチドメインデプロイメント
単一のロケールでサイトを構築することもできます:
- npm
- Yarn
- pnpm
npm run build -- --locale fr
yarn build --locale fr
pnpm run build --locale fr
Docusaurusは /fr/
URLプレフィックスを追加しません。
- ロケールごとにデプロイメントを1つ作成する
--locale
オプションを使用して適切な build コマンドを構成する- 各デプロイメントに対して選択したサブドメインを設定する
この戦略は GitHub Pages ではできません。なぜなら、 1 つのデプロイメント しかないからです。
ハイブリッド
一部のロケールではサブパスを使用し、他のロケールではサブドメインを使用することができます。
各ロケールを個別のサブドメインとしてデプロイし、CDN レベルで単一の統合ドメインにサブドメインを組み立てることも可能です。
- サイトを
fr.docusaurus.io
として展開 - CDNでは
docusaurus.io/fr
を提供するように設定
翻訳の管理
Docusaurus は翻訳の管理方法を気にしません。必要なのは、ビルド中にすべての翻訳ファイル (JSON、Markdown、またはその他のデータ ファイル) がファイルシステムで利用可能であることだけです。 しかし、サイト制作者としては、翻訳者がうまくコラボレーションできるように翻訳の管理方法を検討する必要があります。
We will share two common translation collaboration strategies: using git and using Crowdin.