もなかアイスの試食品

「とりあえずやってみたい」そんな気持ちが先走りすぎて挫折が多い私のメモ書きみたいなものです.

Vue+VuetifyでVueI18nを使ってみた

はじめに

ここ最近は、個人的な勉強でVue.js+Vuetifyを使うことが多い

Vue.js楽しい

Androidアプリの作成やらSpringBoot + Thymeleafを使ってきた影響で、外部ファイルに文字列を定義するクセがついた

いわゆるi18n対応

Vue.js+Vuetifyでi18n対応するためには、VueI18nというライブラリを使用する。

ただ、参考サイトの通りにしても(したつもりのだけか?)上手くいかなかった・・・

上手くできた環境・設定やら、ちょっと工夫したことをメモ書き

環境

  • typescript: 4.1.5
  • vue: 2.6.11
  • vuetify: 2.4.0
  • vue-i18n: 8.24.1

とりあえず使用できるところまで

参考サイト

kazupon.github.io

vuetifyjs.com

Vue CLIで作ったプロジェクトディレクトリで以下のコマンドを実行し、VueI18nライブラリを追加

$ npm install vue-i18n

テキストを取り出す外部ファイルを追加

// src/i18n/ja.ts
import ja from 'vuetify/src/locale/ja'

export const ja = {
  ...ja,

  sample1: 'Hello sample!!!!!',
  sample2: 'こんにちは',
  sample3: 'つよくなりたい'
}

Vuetifyで外部ファイルから読み込むコードを追加

// src/plugins/vuetify.ts
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'
import VueI18n from 'vue-i18n'
import ja from '@/i18n/ja'

Vue.use(Vuetify)
Vue.use(VueI18n)

const messages = {
  ja: ja
}

export default new Vuetify({
  lang: {
    current: 'ja',
    locales: messages
  }
})

Typescriptの設定を追加

{
  "compilerOptions": {
    // (中略)
    "types": [
      "webpack-env",
      "vuetify"
    ],
    // (中略)
}

Viewで呼び出す

<p v-text="$vuetify.lang.t('$vuetify.sample1')"/>
<p v-text="$vuetify.lang.t('$vuetify.sample2')"/>
<p v-text="$vuetify.lang.t('$vuetify.sample3')"/>

実際の表示

f:id:monakaice88:20210321191941p:plain

もっと短く書けるように

「$vuetify」を2回記述しないといけないし、もっと短く書けるようにしたい

Vueのプラグイン機能を利用して、短く書けるようにした

参考サイト

stackoverflow.com

github.com

blog.asial.co.jp

Vuetifyのコードを元に戻しておく

// src/plugins/vuetify.ts
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'

Vue.use(Vuetify)

export default new Vuetify({
})

新しいプラグインを作成

// src/plugins/myText.ts
import { PluginObject } from 'vue/types/plugin'
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import ja from '@/i18n/ja'

// Typescriptでエラーにならないようにするために追加
// @see https://github.com/vuejs/vue/issues/5641
declare module 'vue/types/vue' {
  interface Vue {
    $myText: (key: string, ...params: Array<string | number>) => string;
  }
}

Vue.use(VueI18n)

const i18n = new VueI18n({
  locale: 'ja',
  messages: {
    ja: ja
  }
})

export const MyText: PluginObject<void> = {
  install (vue: typeof Vue): void {
    // 統合開発環境では、どこでも使用されていないことになっているが、Vueで使用しているので削除しないこと
    vue.prototype.$myText = (key: string, ...params: Array<string | number>): string => {
      const t = i18n.t(key, params)
      if (typeof t === 'string') {
        return t
      }
      throw new Error('not found key.')
    }
  }
}

新しく作成したプラグインを使用するために、設定を追記

// src/main.ts
import Vue from 'vue'
import App from '@/App.vue'
import vuetify from '@/plugins/vuetify'
import { MyText } from '@/plugins/myText'

Vue.use(MyText)

Vue.config.productionTip = false

new Vue({
  vuetify,
  render: h => h(App)
}).$mount('#app')

Viewで実際に使ってみる

<p v-text="$myText('sample3')"/>
<p v-text="$myText('sample2')"/>
<p v-text="$myText('sample1')"/>

実際の表示

f:id:monakaice88:20210321191906p:plain