📚

Nuxtでi18n化対応

2021/07/06に公開

Nuxtでi18n化対応

昨今、というかだいぶ前からグローバリゼーションが進んできていますが、それにつれアプリ多言語化が必要な場面が増えてきたかと思います。

規模やコンテクストにもよると思いますが、現在ではほとんどのアプリで多言語化が必要ではないでしょうか?

そもそもi18nとは

そもそもi18nってなんぞ?って疑問に思われたかもしれないですが、私も最初はそうでした笑
i18nとはInternationalizationつまり国際化の略です。
最初のIと最後のnの間に18文字あるからi18nなんですね。k8sといい、これ初見じゃ絶対わからないでしょ
(余談ですが、こうゆう略し方をヌメロニム(数略語)と言うらしいですね)

nuxt-i18n

nuxt-i18n

Nuxt.jsのプロジェクトで多言語化の対応をしようとした際、よほど複雑なことをしようとしない限りおそらくこちらのライブラリで事足りるかと思います。

このnuxt-i18nはvue-i18nと統合されており、そっちを使ったことがある人ならかなり使いやすいのではないかと思います。

そのほかにも、言語ごとに自動でルートを生成してくれたり、辞書の遅延読み込みを行ってくれたり、辞書の検索エンジンが最適化されていたりと結構使い勝手の良いものとなっています。

How to Use

パッケージのインストールはこちらのみで大丈夫です。

$ yarn add nuxt-i18n

nuxt.config.jsonに言語設定を追加

export default {
  // 略...
  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    // https://go.nuxtjs.dev/axios
    '@nuxtjs/axios',
    [
      'nuxt-i18n',
      {
        // 使用する言語
        locales: [
          { code: 'ja', name: 'Japanese', iso: 'ja_JP', file: 'ja.json' },
          { code: 'en', name: 'English', iso: 'en-US', file: 'en.json' },
          { code: 'hi', name: 'Hieroglyph', file: 'hi.json' },
          { code: 'ru', name: 'Rune', file: 'ru.json' },
        ],
        defaultLocale: 'en', // デフォルトの言語
        langDir: 'locales/', // 翻訳ファイルのディレクトリパス
        strategy: 'no_prefix', // URLに言語のプレフィックスを追加するかの指定
        vueI18n: {
          // 翻訳ファイルが見つからなかった場合の言語を指定
          fallbackLocale: 'en',
        },
        vueI18nLoader: true,
        lazy: true, // 遅延読み込みの有効化
      },
    ],
  ],
  // 略...
}

このような感じでconfigのmoduelsの中に追記していきます。
対応言語を増やしたい時などは、localesに追加すればいい感じですね!

辞書ファイルの作成

このままだと肝心の翻訳する辞書がないためそれを作成していきます。
まず、プロジェクト直下にlocalesというディレクトリとnuxt.config.jsonlocalesで指定した言語ファイルを作成します。

./myproject
├── locales
│   ├── ja.json
|   ├── en.json
|   ├── hi.json
│   └── ru.json

そして、各ファイルで辞書を追加してきます。

en.json
{
  "apple": "Apple"
}

ja.json
{
  "apple": "りんご"
}

Vue内で使用

実際にvueファイルで使用する際は以下のように書くことで多言語化された文言を使用することができます。

<p>{{ $t('apple') }}</p>

また、辞書をネストすることもでき、その場合は辞書のjsonファイルを以下のよう編集し、

en.json
{
  "fruit": {
    "apple": "Apple"
  }
}

vueファイル内で以下のように使用することができます。

<p>{{ $t('fruit.apple') }}</p>

言語の切り替え

実際どうやって日本語から英語、英語から日本語に切り替えればいいのかですが、ここは割とサクッとできます。

まず、すべての対応言語のボタンを作成します。
といってもそんなに難しくなく後述するavailableLocalesをv-forで回し、そのリンクを作成しているだけです。

<template>
      <!-- 略... -->
      <div v-for="locale in availableLocales" :key="locale.code">
        <a @click="() => changeLocale(locale.code)">
          {{ locale.name }}
        </a>
      </div>
      <!-- 略... -->
</template>

export default {
  components: {},
  computed: {
    availableLocales() {
      return this.$i18n.locales.filter((i) => i.code !== this.$i18n.locale)
    },
  },
  methods: {
    /**
     * リロードあり
     * クッキーへ言語設定。リロード後、言語切替
     */
    changeLocale(locale) {
      this.$i18n.setLocaleCookie(locale)
      this.$router.go(0)
    },

    /**
     * リロードなし
     * クッキーと、$i18n独自ストアのlocaleに言語を設定する
     * 直接storeを書き換えるためリロードは不要
     */
    // async changeLocale(locale) {
    //   await this.$i18n.setLocale(locale)
    // },
  },
}

こっちが本題。
まず、computedにあるavailableLocalesの部分ですが、ここではnuxt.config.jsonにて登録したlocalesの一覧を取得し、現在使用されている言語を除いた一覧を返しています。

  computed: {
    availableLocales() {
      return this.$i18n.locales.filter((i) => i.code !== this.$i18n.locale)
    },
  },

そして、ここが実際の言語切り替え部分になります。
コメントにもある通り、上の関数がリロードあり、下の関数がリロードなしになります。
ここはお好きな方を選んでいただいて使うのがいいかなと思います。

  methods: {
    /**
     * リロードあり
     * クッキーへ言語設定。リロード後、言語切替
     */
    changeLocale(locale) {
      this.$i18n.setLocaleCookie(locale)
      this.$router.go(0)
    },

    /**
     * リロードなし
     * クッキーと、$i18n独自ストアのlocaleに言語を設定する
     * 直接storeを書き換えるためリロードは不要
     */
    // async changeLocale(locale) {
    //   await this.$i18n.setLocale(locale)
    // },
  },

ちょっと凝った翻訳をしたい時

ここからは単純な翻訳ではうまく行かないような場合に使用することが多いものになります。
Vue i18n FormattingこちらのVue i18nのサイトが非常によくできているので一読することをおすすめします。

翻訳時に変数を使用したい場合

翻訳といってもただ単にりんごをAppleに翻訳する場合だけでなく、翻訳時に変数を使用したい場面が多々あると思います。
例えば、日本語だと〇〇様のところが、英語だとDear 〇〇になるなど、、、
そうゆう場合にはどうすればいいのかと言うと

まず、翻訳ファイル内で{変数名}と書きます。

{
  "name": "Dear {name}"
}

そして、表示する時は第二引数に変数名を含めたオブジェクトを渡すことで、展開され変数を含めた翻訳をすることができます。

<p>{{ $t('name', { name: 'hogehoge' }) }}</p>

翻訳辞書にHTML要素を入れたい

例えば、改行タグを入れたいなどですが、こちらはそのままできます。

{
  "greet": "hello <br> world"
}

実際vueファイル内で使う際にはv-htmlに指定する必要があります。

<p v-html="$t('message.greet')"></p>

終わりに

個人的にnuxt-i18nのいいなと思ったポイントが翻訳の設定をnuxt.config.jsonにおけるところと、言語ごとの辞書をJSONとしてもてるところかなと思っています。
翻訳する量が多くなればなるほとメンテナンスがしやすそうなので。

Discussion