7rikazhexde’s tech log

技術的な興味関心、備忘録、アウトプットなどを書いています。

Docusaurusのi18n設定について

Docusaurusの多言語化対応(i18n)の設定について情報をまとめます。

注意事項

  • 本記事は公式ドキュメント(Fast Track)を実行済みであることを前提とします。
  • Docusaurusはv1,v2,v3で仕様が異なります。下記記事は特記事項がない限り、v3.1.1をベースにします。
  • 仕様は変更されることがありますので、公式ドキュメントやissuesの確認をお願いします。
  • 情報は適宜更新します。

i18n対応の基本情報

公式ドキュメントに記載されています。
以下を参照して設定すれば基本的な言語切り替え動作は確認できました。

多言語サイトをローカル起動する時の注意点

言語設定でサイトをローカルで起動する方法は下記ドキュメントに記載されている通りです。
https://docusaurus.io/docs/i18n/tutorial#start-your-site

日本語用のサイトであれば、yarn run start --locale jajaで構築したサイトを起動できます。

しかし、以下警告の記載の通り、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 startyarn buildyarn serve の違いは以下の通りです。

yarn start

  • Docusaurusの開発サーバーを起動します
  • ファイルの変更を監視し、変更があれば自動的にリロードされます
  • 開発用の設定が適用されています
  • 本番用のビルドは行われません

yarn build

  • 本番用の静的なウェブサイトをビルドします
  • ソースコードを最適化し、JS/CSSなどのリソースをバンドルします
  • i18n対応の設定が適用されています

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.jsi18nの設定を追加することで、言語変更に対応したプルダウンを表示することができます。i18n/ja,enフォルダ、ファイルを作成すれば、プルダウン選択で切り替えることができます。

/** @type {import('@docusaurus/types').Config} */
const config = {
  //省略
  i18n: {
    defaultLocale: 'en',
    locales: ['en','ja'],
  },

ユースケース

以降はユースケース毎にi18nの設定方法を記載します。

以下内容では、言語差異がわかりやすいように、テキスト(単語、文章)は英語/日本語で切り替えています。 例えば、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)

docusaurus-top-i18n-en

トップページ(ja)

docusaurus-top-i18n-ja

ブログページ(en)

docusaurus-blog-i18n-en

ブログページ(ja)

docusaurus-blog-i18n-ja

docsページ / チュートリアル(en)

docusaurus-tutolial-i18n-en

docsページ / チュートリアル(ja)

docusaurus-tutolial-i18n-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.jsblogSidebarTitleを追加すれば変更できます。

/** @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)の言語切り替えの設定としては以上です。

ページ左上のDocsへのリンクはnavbarやページ下部のSNSへのリンクはfooterで設定できます。 デフォルト言語の表示はdocusaurus.config.jsthemeConfig(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

  • i18n/ja/docusaurus-theme-classic/footer.json
  • i18n/ja/docusaurus-theme-classic/navbar.json

ここで、上記jsonファイルは、トップページ(pages)の言語切り替えでも紹介した通り、CLI(write-translations)で作成することができます。翻訳対象のテキストはid(Theme configurationではtype)に対応する"message"が対象になるため、必要に応じて変更してください。

まとめ

Docusaurusでi18n設定する方法について以下の項目について紹介しました。

  • docs
  • pages
  • blog
  • theme(footer / navbar)

基本的には本記事の内容で基本的な翻訳は対応できると思います。 また、Docusaurusでは他にも機能があるので気になるものがあれば情報としてまとめようと思います。

最後に、本記事参考になれば、
是非「はてなスター / はてなブックマーク」 をお願いします。

以上です。