Nuxt.js: i18nで国際化対応(localeメッセージ管理の工夫)

多言語化案件に携わることになり、Nuxt.js + i18nの導入を経験できたので備忘録的に残します。

ドキュメント
https://nuxt-community.github.io/nuxt-i18n/

要件

今回の要件は以下

  1. locale: en, ja の2言語
  2. url: /en, /ja ( /へのアクセスはcookie制御、デフォルト /en )
  3. localeファイルはpage(component)ごとに管理
  4. メッセージはテンプレート方式で引数を与えられるようにする

導入手順

  1. nuxt-i18n のインストール
  2. nuxt-i18n.config.js の作成
  3. 言語ファイルの作成
  4. nuxt.config.js の設定
  5. Template側での呼び出し

nuxt-i18n のインストール

これはドキュメントの通り。

yarn add nuxt-i18n

or

npm i -S nuxt-i18n

nuxt-i18n.config.js の作成

今回は、 ページごとにメッセージファイルを管理したいので、locales[].file ではなく、 vueI18n.message を使用します。

nuxt-i18n.config.js

import messages from './locales/message' <- これは次項で説明

export default {
  strategy: 'prefix',
  locales: [
    { code: 'en', iso: 'en_US' }, <- fileプロパティは使用しない
    { code: 'ja', iso: 'ja_JP' }
  ],
  defaultLocale: 'en',
  vueI18n: {
    fallbackLocale: 'en',
    messages
  },
  rootRedirect: 'en',
  detectBrowserLanguage: {
    useCookie: true,
    cookieKey: 'i18n_locale'
  }
}

言語ファイルの作成

要件#3のページごとにlocaleファイルを分けるために、このようなディレクトリ構造で管理します。
各localeごとにページ単位のjsファイルを用意して、message.jsでそれらをがっちんこしてexport。
それを nuxt-i18n.config.js でimport。

./locales
├── en
│   ├── top.js
│   └── sub.js
├── ja
│   ├── top.js
│   └── sub.js
└── message.js

./locales/ja/top.js

export default {
    top_title: 'TOPページへようこそ',
    top_title_service: 'サービス概要',
    top_label_service: 'サービス {index}: {name}',
    top_service_price: '{0} 円',
    top_service_description: 'こんなサービスです。詳しくは<a herf="{0}">こちら</a>までどうぞ!'
}

./locales/en/top.js

export default {
    top_title: 'Welcome to TOP page',
    top_title_service: 'Services'
    top_label_service: 'Service {index}: {name}',
    top_service_price: 'USD {0}',
    top_service_description: 'This is the service description. For more information, please reach out ot us <a herf="{0}">here</a>.'
}

./locales/message.js

import localeENTop from './en/top'
import localeENSub from './en/sub'

import localeJATop from './ja/top'
import localeJASub from './ja/sub'

export default {
  en: {
    ...localeENTop,
    ...localeENASub
  },
  ja: {
    ...localeJATop,
    ...localeJASub
  }
}

これでページが量産されても管理しやすくなります。

nuxt.config.js の設定

作成した i18n.config.js を利用して、nuxt.config.js のi18n設定を行います。

import i18n from './nuxt-i18n.config'

export default {
  ...
  modules: [
    ...
    [ 'nuxt-i18n, i18n ]
  ]
}

Template側での呼び出し

こんな感じで利用します。$message() の引数にはオブジェクトの指定も可能。

<template>
  <div>
    <h2>{{ $t('top_title') }}</h2>

    <section>
      <h3>{{ $t('top_title_service') }}</h3>
      <div v-for="(item, i) in services" :key="item.id">
        <h4>{{ $t('top_label_service', { index: i + 1, name: item.name }) }}<h4>
        ...
        <p>{{ $t('top_service_price', [item.price.toLocaleString()]) }}</p>
        <p v-html="$t('top_service_description', [localePath({ path: '/contact' })])" />
      </div>
    </section>
  </div>
</template>
...

Cookie制御とか自前で実装しようとしていたけど、これ使えばバッチリでした。