[vue/Nuxt]マルチ言語対応(plugin/custom directive)

#はじめに

ログインユーザーにより、日本語・英語に表示を切り替える。
日本語・英語のテキストはjsonファイルに定義する。

#前提条件
windows 10
npm 6.9.0
node v12.17.0
nuxt 2.15.7

#Nuxtインストール

各バージョンを確認

```コマンドプロンプト
C:\pj\ml-project>npm -v
6.9.0

C:\pj\ml-project>node -v
v12.17.0
```
※node13系以降はエラーになる可能性があるため、12系に変更。

nuxtプロジェクトをインストール

```
npx create-nuxt-app ml-project
```
※初期設定でプロジェクト作成

ディレクトリ変更

```
cd ml-project
```

nodeサーバ実行

```
npm run dev
```

http://localhost:3000/
にアクセスし表示されればOK。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97130/65cf28bf-a7cc-0000-6810-bc2151e04aab.png)

#ログインユーザーstoreを準備
```ml-project\store\loginUser.js
export default {
  state: {
    lang: 'ja' // 「jp」 or 「en」
  },
  mutations: {
    setLang(state, text){
      state.lang = text;
    }
  }
};
```

#多言語ファイルを準備
```ml-project\assets\lang\jp.json
{
    "MSG0001": "Nuxtアプリケーションへようこそ"
}
```

```ml-project\assets\lang\en.json
{
    "MSG0001": "Welcome to your Nuxt Application"
}
```

#多言語メッセージプラグイン
多言語プラグインを追加

```ml-project\nuxt.config.js
  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
    // 多言語共通処理
    '~/plugins/ml', // 追加
  ],
```

```ml-project\plugins\ml.js
/**
 * 多言語プラグイン
 */
import { mlService } from '../services/mlService'

export default ({store} ,inject) => {
  const lang = store.state.loginUser.lang;
  const ml = new mlService(lang);
  inject('ml', ml);
}
```

```ml-project\services\mlService.js
/**
 * 多言語サービス
 */
import jp from '../assets/lang/jp.json'
import en from '../assets/lang/en.json'

export class mlService {
  lang = 'jp';    // 言語モード
  messages = jp;  // 言語リスト
  
  constructor(lang = 'jp'){
    this.lang = lang ? lang : 'jp';
    this.setLangList();
  }

  /**
   * テキスト取得
   */
  get(id, params = null){
    if(!this.messages[id]){
      throw new TypeError(`id not found: ${id}`);
    }
    let text = this.messages[id];
    if(Array.isArray(params)){
      for(let i=0; i < params.length; i++){
        text = text.replace(`{${i}}`, params[i]);
      }
    }
    return text;
  }
  /**
   * 言語設定
   */
   setLang(lang = 'jp'){
    this.lang = lang ? lang : 'jp';
    this.setLangList();
  } 
  /**
   * 言語リスト設定
   */
  setLangList(){
    switch(this.lang){
      case 'jp':
        this.messages = jp;
        break;
      case 'en':
        this.messages = en;
        break;
    }
  }
}
```

```ml-project\components\Tutorial.vue
        <h2 class="text-2xl leading-7 font-semibold">
          Welcome to your Nuxt Application
        </h2>
　　　　↓
        <h2 class="text-2xl leading-7 font-semibold">
          {{this.$ml.get('MSG0001')}}
        </h2>
```

![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97130/19133d67-600f-3da4-07d0-b6efbf02a940.png)

loginUser.jsの『lang:'ja'』のため、日本語化されています。

言語を変更したい場合は、create時にstoreの値を変更する。

```ml-project\pages\index.vue
export default {
    　created: function(){
        　// 多言語：英語
        　this.$store.commit('loginUser/setLang', 'en');
    　},
}
```
![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97130/957c94cd-beee-39fa-e6dc-48b9244e9a63.png)

英語化されます。


#[応用]多言語custom directive
```ml-project\nuxt.config.js
  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
    // 多言語共通処理
    '~/plugins/ml',
    // custom directive
    '~/plugins/customDirective', // 追加
  ],
```

```ml-project\plugins\customDirective.js
import Vue from 'vue'
import { mlService } from '../services/mlService'
/**
 * 多言語一括ディレクティブ
 */
Vue.directive('ml',{
  bind(el, binding, vnode){
    const ml = new mlService(vnode.context.$store.state.loginUser.lang);
    [].forEach.call(el.querySelectorAll('[data-label]'), function(e,i){
      try {
        // json形式の場合
        let label = JSON.parse(e.dataset.label);
        e.innerText = ml.get(label.id, label.params);
      } catch(exception) {
        // idの場合
        let label = e.dataset.label;
        e.innerText = ml.get(label);
      }
    });
  }
})
```

```ml-project\components\Tutorial.vue
  <div v-ml class="relative flex items-top justify-center min-h-screen bg-gray-100 sm:items-center sm:pt-0">
(省略)
        <h2 class="text-2xl leading-7 font-semibold" data-label='MSG0001'>
          data-labelを設定すれば自動置換
        </h2>
```
※『v-ml』を追加。v-ml内のタグに、『data-label='MSG0001'』を追加することで中の文字列が言語に合わせ自動で置換されます。

![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97130/c34b930a-10a4-5d7a-9136-20925819cb68.png)