Vue.JS + Nuxt で i18n (yaml使用) 対応

Install
==========

```
npm i -S vue-i18n
npm i -S @kazupon/vue-i18n-loader
npm i -S yaml-loader
```

下記ファイルの追加

```js:modules/vue-i18n.js
module.exports = function () {
  this.extendBuild(config => {
    const rule = config.module.rules.find(el => el.loader === 'vue-loader')
    rule.options.preLoaders = rule.options.preLoaders || {}
    rule.options.preLoaders.i18n = 'yaml-loader'
    rule.options.loaders.i18n = '@kazupon/vue-i18n-loader'
  })
}
```

```js:plugins/vue-i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

export default ({ app }) => {
  app.i18n = new VueI18n({
    locale: navigator.language  // ブラウザの設定を利用
  })
}
```

`nuxt.config.js` に下記の項目を追加。

```js:nuxt.config.js
module.exports = {
  plugins: [
    { src: '@/plugins/vue-i18n.js', ssr: false },
  ],
  modules: [
    '@/modules/vue-i18n.js',
  ],
  build: {
    vendor: ['vue-i18n'],
  },
}
```

多言語の指定
============

### 通常

```vuejs
<i18n>
en:
  ppap:
    1: "This is a pen."
    2: "This is an apple."
  "これは何？": "What is this?"
</i18n>

<template>
  <div>
    <div>{{$t('ppap.1')}}</div>
    <div>{{$t('ppap.2')}}</div>
    <div>{{$t('これは何？')}}</div>
  </div>
</template>
```

### パラメータ渡す

```vuejs
<i18n>
en:
  ppap: "This is a {item}."
</i18n>

<template>
  <p>{{ $t('ppap', { item: 'pen' }) }}</p>
</template>
```

### i18n を別ファイルに切り出す

```yml:messages/en/global.yml
en:
  ppap:
    1: "This is a pen."
    2: "This is an apple."
  "これは何？": "What is this?"
```

```vuejs
<i18n src="../../messages/en/global.yml"></i18n>
```

### 言語名のclassを有効化する

```vuejs
<div :class="{[`lang-${$i18n.locale}`]: true}">

# locale = en の場合の output
<div class="lang-en">
```

### script の中で使う場合

```js
data() {
  const $t = this.$t.bind(this)
  return {
    ppap: $t('ppap.1'),
  }
},
```

### 文言の中にタグが含まれるなど複雑な分を使う

`<i18n>` タグ使う。

```vuejs
<i18n>
en:
  'aaa': 'There are {a}, {b} and {c}.'
  'りんご': 'Apple'
</i18n>

<template>
  <div>
    <i18n path="aaa" tag="p" :places="{a: 'バナナ'}">
      <span place="b">パイナップル</span>
      <a place="c" href="/url">{{ $t('りんご') }}</a>
    </i18n>
  </div>
</template>

# 出力
<div>
  <p>
    There are バナナ, パイナップル and Apple.
  </p>
</div>
```

### v-t を使う方法

```vuejs
<p v-t="ppap1"></p>
<p v-t="{path: 'ppap2', locale: 'ja', args: {item: 'pen'}}"></p>
```

リアルタイムで変える必要がないなら `v-t` を使った方が良さそうだが、パフォーマンスにさほど影響がないなら可読性の高い `$t` でも良さそう。

- `v-t`
    - メリット: パフォーマンス。vue-i18n-extensions を使えば事前翻訳も。
    - デメリット: 柔軟ではない。dom の textContent に保存される。
- `$t`
    - メリット: 柔軟。
    - デメリット: 再描画のたびに計算される翻訳コスト。

### 言語セレクター

```vuejs
<template>
  <div class="locale-changer">
    <select v-model="$i18n.locale">
      <option v-for="(lang, i) in langs" :key="`Lang${i}`" :value="lang">{{ lang }}</option>
    </select>
  </div>
</template>

<script>
export default {
  name: 'locale-changer',
  data () {
    return { langs: ['ja', 'en'] }
  }
}
</script>
```

### クエリパラメータで locale 注入

```js:middleware/i18n-locale.js
export default async function ({route, app}) {
  if (route.query['locale']) {
    console.log('locale', route.query['locale'])
    app.i18n.locale = route.query['locale']
  }
}
```

```js:nuxt.config.js
module.exports = {
  router: {
    middleware: ['i18n-locale'],
  },
}
```