Vue I18n は、Vue.js アプリケーションにおいて国際化(i18n)を実装するためのプラグイン。国際化とは、アプリケーションを多言語化し、異なる地域や文化に適応させるプロセスのこと。Vue I18n を使用すると、アプリケーションのテキストコンテンツを動的に変更でき、ユーザーのロケール設定や言語設定に基づいてコンテンツを表示することができる。

今回はVue3 Composition APIならびに、TypeScriptのプロジェクトでVue I18n を使用する方法をまとめる。

初期設定

ライブラリのインストール

npm install vue-i18n@9

必要なファイル構成

以下の構成でファイルを準備する。

src
└ lang
  └ ja.json
  └ en.json
App.vue
main.ts

main.ts

import { createApp } from 'vue'
import { createI18n } from 'vue-i18n' // ←追加
import App from './App.vue'
import router from './router'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
import ja from './lang/ja.json' // ←追加
import en from './lang/en.json' // ←追加

// ←追加
const i18n = createI18n({
  legacy: false,
  locale: 'ja', // 初期ロケール
  fallbackLocale: 'ja', // 好みの言語で翻訳が利用できない時にどの言語を使用するか選択するためのオプション
  messages: {
    ja: ja,
    en: en
  }
})

loadFonts()

createApp(App).use(router).use(vuetify).use(i18n).mount('#app')

上記の記述により、グローバルスコープでVueI18nが利用できるようになった。グローバルスコープを使用すると、Vueアプリケーションのすべてのコンポーネントでスコープを参照できる。

言語ファイルを定義(ja.json、en.json)

{
  "welcomePage": {
    "message": "こんにちは"
  }
}
{
  "welcomePage": {
    "message": "Hello"
  }
}

コンポーネントで表示(App.vue)

<template>
  <div>{{ t('welcomePage.message') }}</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'

export default defineComponent({
  setup() {
    const { t } = useI18n()
    return {
      t
    }
  }
})
</script>

以上で初期設定は完了。コンポーネントで表示ができるようになる。

実践的な使い方

アプリケーション全体の言語を変更する

上記の初期設定を利用して、アプリ全体の言語を変更する方法を以下に示す。

要件: プルダウンで選択可能な言語のリストを表示し、選択された言語をアプリに適用する。

App.vueを以下のように記述することで実現できる。

<template>
  <v-container>
    <v-card>{{ t('welcomePage.message') }}</v-card>
    <!-- 言語選択のプルダウン -->
    <v-select
      label="言語を選択"
      v-model="$i18n.locale"
      :items="$i18n.availableLocales"
      class="mt-4"
    >
    </v-select>
  </v-container>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'

export default defineComponent({
  name: 'MultilingualPane',
  setup() {
    const { t } = useI18n()
    return {
      t
    }
  }
})
</script>

参照: Scope and Locale Changing

グローバルスコープでVueI18nを定義している場合、$i18nでVueI18nインスタンスにアクセスできるようになる。$i18n.availableLocalesで利用可能な言語のリストを取得でき、v-model="$i18n.locale"はアクティブな言語を参照している。

変数を使用する: Interpolations

Vue I18nは、JavaScriptで定義された変数名を使用してプレースホルダーに割り当てができる。

この機能の使用ケースは実務でも多く、例えば、ユーザー名が日本語と英語の両方用意されている場合に、アプリの言語設定に応じて出し分ける必要がある。

日本語: こんにちは、ジェームズさん
英語: Hello James.

このケースでは、名前の部分を変数化して表現する必要がある。以下のようにすることで実現できる。

言語ファイルを以下のように変更する。名前の部分を{name}とする。

{
  "welcomePage": {
    "message": "こんにちは {name}さん"
  }
}
{
  "welcomePage": {
    "message": "Hello {name}"
  }
}

App.vueを以下のようにする。

<template>
  <v-container>
    <v-card>{{ t('welcomePage.message', { name: name[$i18n.locale] }) }}</v-card>
    <!-- 言語変更 -->
    <v-select
      label="言語を選択"
      v-model="$i18n.locale"
      :items="$i18n.availableLocales"
      class="mt-4"
    >
    </v-select>
  </v-container>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'

export default defineComponent({
  setup() {
    const { t } = useI18n()
    // 名前
    const name = {
      ja: 'ジェームズ',
      en: 'James'
    }
    return {
      t,
      name
    }
  }
})
</script>

t()の第二引数に、代入する変数を格納したオブジェクトを渡す。オブジェクトのkeyは言語ファイルで定義したものと同じにする。

参照: https://vue-i18n.intlify.dev/guide/essentials/syntax.html#interpolations

localeに応じて、日付時間の表示形式を変更する

日付と時間の表示をローカリゼーションすることは、多言語や多国籍のユーザーをターゲットにするアプリケーションの開発において非常に重要である。

Vue I18nは、localeに応じて日付時間の表示フォーマットを定義できる。以下のように実装する。

main.ts > createI18n に、datetimeFormatsを定義する。

const i18n = createI18n({
  legacy: false,
  locale: 'ja',
  fallbackLocale: 'ja', // 好みの言語で翻訳が利用できない時にどの言語を使用するか選択するためのオプション
  messages: {
    ja: ja,
    en: en
  },
  // 追記
  datetimeFormats: {
    'en-US': {
      short: {
        year: 'numeric',
        month: 'short',
        day: 'numeric'
      },
      long: {
        year: 'numeric',
        month: 'short',
        day: 'numeric',
        weekday: 'short',
        hour: 'numeric',
        minute: 'numeric'
      }
    },
    'ja-JP': {
      short: {
        year: 'numeric',
        month: 'short',
        day: 'numeric'
      },
      long: {
        year: 'numeric',
        month: 'short',
        day: 'numeric',
        weekday: 'short',
        hour: 'numeric',
        minute: 'numeric',
        hour12: true
      }
    }
  }
})

次に、App.vueで以下のように実装する。

<template>
  <v-container>
    <v-card class="mt-4">
      日付: {{ d(new Date(), 'long', datetimeLocale) }}
      <i18n-d tag="p" :value="new Date()" :locale="datetimeLocale" format="long"></i18n-d>
    </v-card>
    <!-- 言語変更 -->
    <v-select
      label="言語を選択"
      v-model="$i18n.locale"
      :items="$i18n.availableLocales"
      class="mt-4"
    >
    </v-select>
  </v-container>
</template>

<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useI18n } from 'vue-i18n'

export default defineComponent({
  setup() {
    const { locale, d } = useI18n()

    // datetimeFormatのlocaleを返す
    const datetimeLocale = computed(() => {
      if (locale.value === 'ja') {
        return 'ja-JP'
      }
      return 'en-US'
    })

    return {
      datetimeLocale,
      d
    }
  }
})
</script>

Vue I18nでDateTimeの値をローカライズするためには、d()を使用する。

以下は、テンプレート内でのd()の使用例

<p>{{ $d(new Date(), 'short') }}</p>
<p>{{ $d(new Date(), 'long', datetimeLocale) }}</p>
  • 第一引数: 日付時間可能な値(例えば、Date、タイムスタンプ)
  • 第二引数: 日付時間の書式名
  • 第三引数: ロケールの値

localeによって以下のように表示される。

'en-US': Sat, Sep 30, 2023, 9:43 AM
'ja-JP': 2023年9月30日(土) 午前9:54

もしくは、i18n-dというコンポーネントを使用しても同じように表現できる。

<i18n-d tag="p" :value="new Date()" :locale="datetimeLocale" format="long"></i18n-d>

参照: Datetime Formatting

localeに応じて、数字のフォーマットを変更する

日付と時間の表示と同じく、数値についてもlocaleに応じて表示形式が異なるため、多言語対応のアプリを開発する際は対応しなければならない。特に「金額」の表示については必須であると言える。

とある商品の金額をlocaleに合わせて表示する場合、Vue I18nを使用して以下のように実装できる。

main.ts > createI18n に、numberFormatsを定義する。

const i18n = createI18n({
  legacy: false,
  locale: 'ja',
  fallbackLocale: 'ja', // 好みの言語で翻訳が利用できない時にどの言語を使用するか選択するためのオプション
  messages: {
    ja: ja,
    en: en
  },
  // 追記
  numberFormats: {
    'en-US': {
      currency: {
        style: 'currency',
        currency: 'USD',
        notation: 'standard'
      },
      decimal: {
        style: 'decimal',
        minimumFractionDigits: 2,
        maximumFractionDigits: 2
      },
      percent: {
        style: 'percent',
        useGrouping: false
      }
    },
    'ja-JP': {
      currency: {
        style: 'currency',
        currency: 'JPY',
        useGrouping: true,
        currencyDisplay: 'symbol'
      },
      decimal: {
        style: 'decimal',
        minimumSignificantDigits: 3,
        maximumSignificantDigits: 5
      },
      percent: {
        style: 'percent',
        useGrouping: false
      }
    }
  }
})

次に、App.vueで以下のように実装する。

算出プロパティ > feeValueにて、ドル円レートでの計算を行なっている。本来ならば、リアルタイムでの為替レート情報の取得が必要になる。これには、外部の為替レート提供APIを使用しなければならないため、今回は定数で置き換えた。

<template>
  <v-container>
    <v-card class="mt-4">
      数値:
      <p>{{ n(feeValue, 'currency', datetimeLocale) }}</p>
      <i18n-n tag="span" :value="feeValue" format="currency" :locale="datetimeLocale"></i18n-n>
    </v-card>
    <!-- 言語変更 -->
    <v-select
      label="言語を選択"
      v-model="$i18n.locale"
      :items="$i18n.availableLocales"
      class="mt-4"
    >
    </v-select>
  </v-container>
</template>

<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useI18n } from 'vue-i18n'

export default defineComponent({
  setup() {
    const { locale, n } = useI18n()

    // 日本円の金額
    const feeOfJPY = 10000

    // ドル円レート
    const ExchangeRateUSDJPY = 150

    // localeが英語の場合は、ドル円レートでUSDを算出する
    const feeValue = computed(() => {
      if (locale.value === 'ja') return feeOfJPY
      return Math.floor(feeOfJPY / ExchangeRateUSDJPY)
    })

    return {
      feeValue,
      n
    }
  }
})
</script>

解説

  • 第一引数: パラメータとしての数値
  • 第二引数: 数値フォーマット名
  • 第三引数: ロケールの値

localeによって以下のように表示される。

'en-US': $66.00
'ja-JP': ¥10,000

もしくは、i18n-nというコンポーネントを使用しても同じように表現できる。

<i18n-n tag="span" :value="feeValue" format="currency" :locale="datetimeLocale"></i18n-n>

参照: Number Formatting

カテゴリー: Vue.js