2020, Oct 28

【i18n】gatsby-plugin-intlを導入する手順

gatsby-plugin-intlを使ってinternationalizationする方法について解説します。

Gatsby.js で i18n 対応をする際に、gatsby-plugin-intl を使ってみたので導入手順をメモしておきます。

インストール

公式サイト(https://www.gatsbyjs.com/plugins/gatsby-plugin-intl/)に従ってインストールします。

npm install --save gatsby-plugin-intl

次に、gatsby-config.js を編集します。プラグインのところに以下を追加します。

{
  resolve: `gatsby-plugin-intl`,
  options: {
    // language JSON resource path
    path: `${__dirname}/src/intl`,
    // supported language
    languages: [`en`, `ja`],
    // language file path
    defaultLanguage: `ja`,
    // option to redirect to `/ja` when connecting `/`
    redirect: false,
  },
},

リダイレクト設定は、ルートパス「/」にアクセスした時に defaultLanguage のパスである「/ja」にリダイレクトするかどうかになります。

言語別ファイルを作る

/src/intlというディレクトリを作成し、その中にen.jsonja.jsonの2つのファイルを新規に作成します。

そして、それぞれ英語と日本語変換したときの文章を入れていきます。

// ja.json
{
  "title": "日本語サイト",
  "description": "こちらは日本語ですよ。",
  "category": {
    "home": "ホーム",
    "blog": "ブログ",
  }
}
// en.json
{
  "title": "English site",
  "description": "This page is in English",
  "category": {
    "home": "home",
    "blog": "blog",
  }
}

"category"のところのように、JSON をネストしてグループ化しておくことも出来ます。

実際に使ってみる

実際にコンポーネントやページの中で使ってみます。

// index.js
import React from 'react'
import { useIntl, Link } from 'gatsby-plugin-intl'

const IndexPage = () => {
  const intl = useIntl()
  return (
    <Layout>
      <SEO title={intl.formatMessage({ id: 'title' })} />
      <h3>{intl.formatMessage({ id: 'title' })}</h3>
      <p>{intl.formatMessage({ id: 'description' })}</p>
      <Link to="/blog/">{intl.formatMessage({ id: 'category.blog' })}</Link>
    </Layout>
  )
}
export default IndexPage

useIntlLinkgatsby-plugin-intlからインポートします。Link はgatsbyのものがあったら削除して、gatsby-plugin-intlを使うようにします。そうしないと、言語別に自動でルーティングしてくれる機能が使えません。

次に言語の切り替えボタンを実装します。コンポーネントとして、components/language.jsを作り、このように実装しました。

// components/language.js
import React from 'react'
import { IntlContextConsumer, changeLocale } from 'gatsby-plugin-intl'

const languageName = {
  ja: '日本語',
  en: 'English',
}

const Language = () => {
  return (
    <div>
      <IntlContextConsumer>
        {({ languages, language: currentLocale }) =>
          languages.map(language => (
            <a
              key={language}
              onClick={() => changeLocale(language)}
              className={
                currentLocale === language
                  ? `font-bold underline cursor-pointer mx-2`
                  : `none cursor-pointer mx-2`
              }
            >
              {languageName[language]}
            </a>
          ))
        }
      </IntlContextConsumer>
    </div>
  )
}
export default Language

changeLocale関数を使って言語変換をします。上のコンポーネントはこんな感じになります。(className のところは現在のロケールを自動で判別して太字にする処理が書いてあります。なお、tailwindCSS という CSS フレームワークを使ってます。)

出来上がったコンポーネントはこんな感じです。

pic 1

これで完成!

これで、日本語の場合は、「/ja」配下にページが作成され、英語の場合は「/en」配下にページが生成され、changeLocale()の関数を叩かない限り、ロケールは変更されなくなります。

非常にシンプルに実装できるのはありがたいですね。

以上です。