Docusaurusの多言語化対応(i18n)の設定について情報をまとめます。
- 注意事項
- i18n対応の基本情報
- 多言語サイトをローカル起動する時の注意点
- 言語切り替え用プルダウンの設定
- ユースケース
- ブログ(blog)の言語切り替え
- footer / navbarの言語切り替え
- まとめ
注意事項
- 本記事は公式ドキュメント(Fast Track)を実行済みであることを前提とします。
- Docusaurusはv1,v2,v3で仕様が異なります。下記記事は特記事項がない限り、v3.1.1をベースにします。
- 仕様は変更されることがありますので、公式ドキュメントやissuesの確認をお願いします。
- 情報は適宜更新します。
i18n対応の基本情報
公式ドキュメントに記載されています。
以下を参照して設定すれば基本的な言語切り替え動作は確認できました。
多言語サイトをローカル起動する時の注意点
言語設定でサイトをローカルで起動する方法は下記ドキュメントに記載されている通りです。
https://docusaurus.io/docs/i18n/tutorial#start-your-site
日本語用のサイトであれば、yarn run start --locale ja
でja
で構築したサイトを起動できます。
しかし、以下警告の記載の通り、ja
->en
の切り替えても、実際にアクセスするとPage Not Found
になります。
言語を切り替えて表示する場合は、yarn build && yarn start
でビルドして起動する必要があります。startコマンドはあくまで指定言語の起動用のコマンドであることに注意が必要です。
WARNING
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.
<補足>yarn startとyarn build && yarn serveの違い
コマンドは公式ドキュメントでも記載されていますが、 https://docusaurus.io/docs/deployment#testing-build-locally
claudeでも確認しました。回答は以下の通りです。
yarn start
と yarn build
、yarn serve
の違いは以下の通りです。
yarn start
- Docusaurusの開発サーバーを起動します
- ファイルの変更を監視し、変更があれば自動的にリロードされます
- 開発用の設定が適用されています
- 本番用のビルドは行われません
yarn build
yarn serve
yarn build
で生成された本番用ビルド結果を、ローカルの一時サーバーで確認できます
つまり、yarn start
は開発用なので、i18nの多言語設定が適用されません。
一方で、yarn build
で本番用にビルドし、yarn serve
でその結果を確認すると、i18nの多言語設定が適切に適用されるため、言語切替えと正しいコンテンツの表示ができるようになります。
i18nの設定は、production buildした状態でのみ、適切に反映されることが理由だと考えられます。開発中は yarn start
で行い、最終的に yarn build
して動作確認することが推奨されているようです。
この挙動は、Docusaurusのドキュメントにも記載があり、production buildでのみi18nが有効になることが説明されています。
言語切り替え用プルダウンの設定
Docusaurusではdocusaurus.config.js
にi18nの設定を追加することで、言語変更に対応したプルダウンを表示することができます。i18n/ja,enフォルダ、ファイルを作成すれば、プルダウン選択で切り替えることができます。
/** @type {import('@docusaurus/types').Config} */ const config = { //省略 i18n: { defaultLocale: 'en', locales: ['en','ja'], },
ユースケース
以下内容では、言語差異がわかりやすいように、テキスト(単語、文章)は英語/日本語で切り替えています。
例えば、GitHubなどの単語は翻訳しなくても良いですが、翻訳が不要であれば後述するjsonファイル(例:code.json
)で定義しなければ翻訳はされません。
公開サイト
i18n設定したページ(en/ja)を紹介します。
サイトはGitHub Pagesで公開しています。
英語版(en)
https://7rikazhexde.github.io/test-website-docusaurus/
日本語版(ja)
https://7rikazhexde.github.io/test-website-docusaurus/ja/
キャプチャ
トップページ(en)
トップページ(ja)
ブログページ(en)
ブログページ(ja)
docsページ / チュートリアル(en)
docsページ / チュートリアル(ja)
続けてユースケース毎に設定方法を記載します。
ドキュメント(docs)の言語切り替え
Docs i18nの情報を元に対応します。
docsディレクト内のディレクトリ/ファイルをi18n/ja/docusaurus-plugin-content-docs/current
以下にコピー&ペーストします。
ドキュメント(docs)の言語切り替えの設定としては以上です。
トップページ(pages)の言語切り替え
トップページはsrc以下のファイルを元に実行されますが、トップページはReactコードで記載されています。
- src/pages/index.js
- src/components/HomepageFeatures/index.js
翻訳には翻訳用のAPIを使用します。 https://docusaurus.io/docs/i18n/tutorial#translate-your-site
翻訳用のAPIには以下2つが提供されていますが、ここでは<Translate/>
コンポーネントの例を示します。
公式ドキュメントの例では以下を参照してください。 https://docusaurus.io/docs/i18n/tutorial#translate-your-site
翻訳でポイントになるのは翻訳用のテキストを作成することです。
翻訳用のテキストはi18n/en/code.json
,i18n/ja/code.json
で定義します。
上記例ではcode.json
の例がないので具体的な処理がわかりづらいのですが、ポイントはprosに記載されているid
です。
ここで重要になる点はcode.json
の作成方法ですが、Docuaurusではjsonファイルを書き出すためのスクリプト(CLI)が提供されています。
https://docusaurus.io/docs/cli#docusaurus-write-translations-sitedir
https://docusaurus.io/docs/i18n/tutorial#translate-plugin-data
yarn write-translations //en yarn write-translations --locale ja //ja
上記コマンドを実行するとi18n/ja/code.json
含む、翻訳用のjsonファイルが出力されます。(環境により"message"
は下記と異なる可能性があります。)
また、翻訳対象のテキストはid
に対応する"message"
が対象になるため、必要に応じて変更してください。
i18n/ja/code.json
{ "homepage.title": { "message": "テストウェブサイト Docusaurus" }, "homepage.tagline": { "message": "私のウェブサイトへようこそ" }, "homepage.features.easy.title": { "message": "簡単に使える" }, "homepage.features.easy.description": { "message": "{docusaurus}は、簡単にインストールでき、すぐにWebサイトを立ち上げることができるよう設計されています。" }, // }
翻訳自体はこれで対応できますが、上記jsonには{docusaurus}
という変数を記載しています。
これは<Translate/>
コンポーネントではHTMLタグを含むテキストを含むことはできない仕様があります。つまり、props
はハードコードされた文字列でなければなりません。
例えば<code>docs</code>
のようにcodeタグを含むテキストをレンダリングする場合は、テキストとして表示されてしまいます。この場合はTranslate
コンポーネントのvalues
プロパティを使用することでHTMLタグに置き換える方法で対応可能です。
下記コードの通り、index.js側で<Translate/>
コンポーネントのvalues
プロパティに、翻訳テキスト中の変数を置き換えるための値を指定することで、HTMLタグに置き換えることができます。
src/components/HomepageFeatures/index.js
const translatedDescription = ( <Translate id={description} values={{ docusaurus: <strong>Docusaurus</strong>, docDir: <code>docs</code>, }} /> );
最後に作成したファイルを記載します。
src/pages/index.js
import clsx from 'clsx'; import Link from '@docusaurus/Link'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import Layout from '@theme/Layout'; import HomepageFeatures from '@site/src/components/HomepageFeatures'; import Heading from '@theme/Heading'; import styles from './index.module.css'; import Translate from '@docusaurus/Translate'; function HomepageHeader() { const {siteConfig} = useDocusaurusContext(); return ( <header className={clsx('hero hero--primary', styles.heroBanner)}> <div className="container"> <Heading as="h1" className="hero__title"> <Translate id="homepage.title">{siteConfig.title}</Translate> </Heading> <p className="hero__subtitle"> <Translate id="homepage.tagline">{siteConfig.tagline}</Translate> </p> <div className={styles.buttons}> <Link className="button button--secondary button--lg" to="/docs/tutorial/intro"> Docusaurus Tutorial - 5min ⏱️ </Link> </div> </div> </header> ); } export default function Home() { const {siteConfig} = useDocusaurusContext(); return ( <Layout title={`Hello from ${siteConfig.title}`} description="Description will go into a meta tag in <head />"> <HomepageHeader /> <main> <HomepageFeatures /> </main> </Layout> ); }
src/components/HomepageFeatures/index.js
import clsx from 'clsx'; import Heading from '@theme/Heading'; import Translate from '@docusaurus/Translate'; import styles from './styles.module.css'; const FeatureList = [ { title: 'homepage.features.easy.title', Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, description: 'homepage.features.easy.description', }, { title: 'homepage.features.focus.title', Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, description: 'homepage.features.focus.description', }, { title: 'homepage.features.react.title', Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, description: 'homepage.features.react.description', }, ]; function Feature({ Svg, title, description }) { const translatedTitle = <Translate id={title} />; const translatedDescription = ( <Translate id={description} values={{ docusaurus: <strong>Docusaurus</strong>, docDir: <code>docs</code>, }} /> ); return ( <div className={clsx('col col--4')}> <div className="text--center"> <Svg className={styles.featureSvg} role="img" /> </div> <div className="text--center padding-horiz--md"> <Heading as="h3">{translatedTitle}</Heading> <p>{translatedDescription}</p> </div> </div> ); } export default function HomepageFeatures() { return ( <section className={styles.features}> <div className="container"> <div className="row"> {FeatureList.map((props, idx) => ( <Feature key={idx} {...props} /> ))} </div> </div> </section> ); }
トップページ(pages)の言語切り替えの設定としては以上です。
ブログ(blog)の言語切り替え
ブログはdocsと同様に記事自体をブログ用のmarkdownファイルと著者ファイルのauthors.yml
を作成することで切り替えることができます。
https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#translation-files-location
しかし、ブログの設定ではブログ本体とは別にいくつか設定(configuration)があります。
https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#configuration
この中で、サイドバーのタイトルについて翻訳の設定例を紹介します。
サイドバーのタイトル変更
まず、ブログのi18n設定は以下に情報が記載されています。
https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#i18n
ここでブログ本文は.md
ファイルを作成すれば切り替えることができますが、サイドバーのタイトル(デフォルトではRecent Posts
)は変わりません。
ブログの設定は下記に記載されており、サイドバーのタイトル設定は下記です。
https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#blogSidebarTitle
単純にサイドバーのタイトルを変更したいのであればdocusaurus.config.js
でblogSidebarTitle
を追加すれば変更できます。
/** @type {import('@docusaurus/types').Config} */ const config = { //省略 presets: [ [ 'classic', /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { // docs以下のindex.mdを表示する場合はrouteBasePathを指定する //routeBasePath: '/', sidebarPath: './sidebars.js', // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: 'https://github.com/7rikazhexde/test-website-docusaurus/edit/main', }, blog: { showReadingTime: true, blogSidebarTitle: 'ブログ一覧', // ここを追加 // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, theme: { customCss: './src/css/custom.css', }, }), ], ],
しかし、これではi18nのプルダウンで言語を変更しても翻訳はされません。
翻訳するためには、options.json
が必要になります。
options.json
はトップページ(pages)の言語切り替えでも紹介した通り、CLI(write-translations)で作成することができます。
options.json
については下記ドキュメントにも記載されています。
https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#example-file-system-structure
│ # translations for the plugin options that will be rendered
サイドバーのタイトルの設定(一部)は下記の通りです。
i18n/ja/docusaurus-plugin-content-blog/options.json
{ "sidebar.title": { "message": "最近の投稿", "description": "The blog sidebar title" } }
i18n/en/docusaurus-plugin-content-blog/options.json
{ "sidebar.title": { "message": "Recent Posts", "description": "The blog sidebar title" } }
ブログ(blog)の言語切り替えの設定としては以上です。
footer / navbarの言語切り替え
ページ左上のDocsへのリンクはnavbar
やページ下部のSNSへのリンクはfooter
で設定できます。
デフォルト言語の表示はdocusaurus.config.js
のthemeConfig(footer,navbar)
で設定できます。
https://docusaurus.io/docs/api/themes/configuration#navbar
https://docusaurus.io/docs/api/themes/configuration#footer-1
一方で、i18n設定ではfooterとnavbarは以下のファイルで設定できます。
https://docusaurus.io/docs/api/themes/configuration#i18n
ここで、上記jsonファイルは、トップページ(pages)の言語切り替えでも紹介した通り、CLI(write-translations)で作成することができます。翻訳対象のテキストはid
(Theme configurationではtype)に対応する"message"
が対象になるため、必要に応じて変更してください。
まとめ
Docusaurusでi18n設定する方法について以下の項目について紹介しました。
- docs
- pages
- blog
- theme(footer / navbar)
基本的には本記事の内容で基本的な翻訳は対応できると思います。 また、Docusaurusでは他にも機能があるので気になるものがあれば情報としてまとめようと思います。
最後に、本記事参考になれば、
是非「はてなスター / はてなブックマーク」 をお願いします。
以上です。