Vue.js+Vuetify.jsを使ったWEBアプリケーション構築 ～多言語対応(Vue I18n)～

# はじめに
Vueアプリケーションの多言語対応には、Vue I18nプラグインを使います。

Vue I18nプラグインの設定方法、使い方について、以前投稿した記事「[Vue.js+Vuetify.jsを使ったWEBアプリケーション構築](https://qiita.com/pmtech-masayuki-miyata/items/e884eb3c7608cc266226)」のサンプルアプリケーションを基に説明したいと思います。


# 説明
## Vue I18nの設定
Vue I18nの設定はとても簡単です。
以下の3ステップとなります。

1. メッセージ情報を作成
1. VueI18nインスタンスの生成（デフォルト表示言語と、メッセージ情報を指定）
1. Vueインスタンス生成時にVueI18nインスタンスを渡す

###1. メッセージ情報を作成
```javascript:/src/configs/message.json
{
    // ja, enはVue18nに設定する言語
    "ja": {
        // caption, messegeに分けているのは個人的な趣味なのでお好みで。
        "caption": {
            // メッセージコード：メッセージの形で。メッセージコードを日本語にしているのは個人的な趣味なのでお好みで。
            "VUEサンプル": "VUEサンプル",
            // ・・・省略
            "": ""
        },
        "message": {
            "M00001": "システムエラーが発生しました。\nエラーコード：{0}",
            // ・・・省略
            "": ""
        }
    },
    "en": {
        "caption": {
            "VUEサンプル": "VUE SAMPLE",
            // ・・・省略
            "": ""
        },
        "message": {
            "M00001": "An system error has occurred.\nError Code: {0}",
            // ・・・省略
            "": ""
        }
    }
}
```

###2. VueI18nインスタンスの生成（デフォルト表示言語と、メッセージ情報を指定）
```javascript:/src/i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n';

// VueアプリケーションでVueI18nプラグインを使う宣言
Vue.use(VueI18n);

// メッセージ定義ファイルの読み込み
const messages = require('./configs/message.json');

// デフォルト言語の設定
export const DEFAULT_LANG = 'ja';

// 言語切替用の定義
export const enableLangs = Object.keys(messages);
export const langCodes = {
  "ja": "日本語",
  "en": "English"
};

// VueI18nインスタンスの生成（言語とメッセージオブジェクトを渡す）
const i18n = new VueI18n({
  locale: DEFAULT_LANG,
  messages: messages
});

export default i18n;
```
###3. Vueインスタンス生成時にVueI18nインスタンスを渡す
```javascript:/src/main.js
import Vue from 'vue'
import './plugins/vuetify'
import router from "./router";
// VueI18nインスタンスを読み込む
import i18n from "./i18n";
// ・・・省略

new Vue({
  render: h => h(App),
  router,
  // VueI18nインスタンスを渡す。
  i18n,
  store
}).$mount('#app');
```

## Vue I18nの使い方
今回VueI18nの基本的な使い方として以下を説明します。

* Vueテンプレート構文内でメッセージを取得する
* Javascrpit内でメッセージを取得する
* 言語を切り替える

###Vueテンプレート構文内でメッセージを取得する
```vuejs:/src/components/parts/NyuryokuCard.vue
<template>
  <v-card>
    <v-card-text>
      <!-- $tメソッドにmessage.jsonで定義したメッセージコードを渡す。 -->
      <div class="subheading">{{ $t(`caption['登録情報']`) }}</div>
      <hr />
      <!-- 省略 -->
    </v-card-text>
  </v-card>
</template>
```

###Javascrpit内でメッセージを取得する
```vuejs:/src/components/parts/JohoList.vue
<script>
import Tooltip from "@/components/base/Tooltip";

export default {
  // ・・・省略
  computed: {
    headers: function() {
      let headers = [
        // this.$i18n.t(メッセージコード)メソッドを呼び出す。
        // computedで定義することでVueI18nで言語切替を行ったときにリアクティブに表示が変わる。
        // dataで定義するとVueI18nで言語切替を行っても表示が変わらないので注意。
        { text: this.$i18n.t('caption["名前"]'), enableSort: true, align: 'center', value: 'name'},
        { text: this.$i18n.t('caption["メールアドレス"]'), enableSort: true, align: 'center', value: 'mailAddress'},
        { text: this.$i18n.t('caption["電話番号"]'), enableSort: true, align: 'center', value: 'phoneNo'},
        { text: this.$i18n.t('caption["登録日時"]'), enableSort: true, align: 'center', value: 'torokuNichiji'},
      ];
      if (this.isNeedDeleteButton) headers.push({ text: '', enableSort: false, align: 'center', value: 'delete'}); 
      return headers;
    },
  },
  // ・・・省略
}
</script>
```

###言語を切り替える
```javascript:/src/store/index.js
// VueI18nインスタンスをインポート
import {default as i18n, enableLangs, DEFAULT_LANG} from '@/i18n';
// ・・・省略

const store = new Vuex.Store({
  // ・・・省略
  actions: {
    [aTypes.CHANGE_LANG](context, lang) {
      // VueI18nインスタンスのlocaleプロパティの値を変える。
      // サンプルアプリケーションはURLの変更により言語切替を行っている都合で、javascriptからlocaleを変更しているが、
      // Vueコンポーネントから言語を切り替える場合は、$i18n.localeプロパティを変更すればよい。
      i18n.locale = lang;

      // htmlのlang属性とtitleの表示の切替も行う。（VueI18nは関係ない）
      document.documentElement.setAttribute('lang', i18n.locale);
      document.title = i18n.t('caption.VUEサンプル');
      context.commit(mTypes.SET_LANG, lang);
    },
  // ・・・省略
```

# おわりに
所感として、Vueアプリケーションの多言語対応はとても簡単と思いました。
但し、言語切替の際に動的にメッセージが変わらなかった時にどう対応すれば良いかは迷いました。
Vueの初心者には、「算出プロパティを使って対応する」というところは、なかなか気付かないところかもしれません。

それと、大規模システムになるとメッセージファイルの肥大化に伴う性能問題が懸念されます。
規模が大きくなってくるとメッセージをWebAPIで必要なものだけ取得するなどの仕組みを自前で作成する必要があると思いました。