Nuxt3+Vuetify3で多言語化(i18n)
vue-i18n
というパッケージを使用します。
nuxt/i18nというのもあり、そっちで苦戦した方などはこちらを試してみるのが良いかと。
基本は公式ページの説明の通りです。
実用的な範囲の最小構成でまとめ直したのと、少しばかり書き方の補足をしたものです。
インストール
npm install --save-dev vue-i18n
/plugins/i18n.ts
にファイル作成
plugins
フォルダがなければ作成し、その下に以下の内容のi18n.ts
を作成。
import { createI18n } from 'vue-i18n'
import en from '../locales/en.json'
import ja from '../locales/ja.json'
export default defineNuxtPlugin(({ vueApp }) => {
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: 'en',
messages: {
en,
ja
}
})
vueApp.use(i18n)
})
/locales/en.json
と/locales/ja.json
を作成
locales
フォルダを作成し、各言語ごとに翻訳リストを作成。
{
"hello": "Hello, {name}!",
"delte": "Delete"
}
{
"hello": "こんにちは, {name}!",
"delte": "削除"
}
- リストの最後にカンマが付いているとエラーになるので注意
Vue (Vuetify3)での書き方の例
<v-alert
:title="$t('cofirm_delete_account')"
type="error"
variant="text"
>
{{ $t('description_delete_account') }}
</v-alert>
言語切り替え (Vuetify3)
v-selectで実装した例です。
<script setup>
const languages = [
{ title: 'English', value: 'en' },
{ title: '日本語', value: 'ja' },
];
</script>
<v-select
v-model="$i18n.locale"
:items="languages"
item-title="title"
item-value="value"
single-line
></v-select>
URLのパラメータで振り分け
公式ページによると、URLによるルーティングはNuxt3インテグレーションではまだ対応していないそうです。(正確にはチュートリアルに記載されていないだけとも読めますが。)
route.query
を使う
URLで指定した言語で出力する例です。
https://your_url.com/?lang=ja
という感じで言語を指定した場合に、日本語で出力されるようにするには、plugins/i18n.ts
の中で、const route = useRoute()
を追加し、locale
にroute.query.lang
を代入してやります。
全体のコードは以下のようになります。
import { createI18n } from 'vue-i18n'
import en from '../locales/en.json'
import ja from '../locales/ja.json'
export default defineNuxtPlugin(({ vueApp }) => {
const route = useRoute();
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: route.query.lang ?? "en",
messages: {
en,
ja
}
})
vueApp.use(i18n)
})
動的ルーティングを使う
上述の方法で一応ルーティングはできますが、URLに?lang=ja
が付くのはなんとも格好がよくありません。
まったくエレガントではない方法ですが、https://your_url.com/ja
みたいな分け方は、動的ルーティングで実現することができるので、書いておきます。
index.vue
を言語分けしたいとして、同じ階層のディレクトリで、[lang].vue
というのを作ります。中身はindex.vue
をコピペして作ります。
-pages
- index.vue
- [lang].vue
こうしておいて、上述のts:i18n.ts
の中でroute.query.lang
をroute.params.lang
にします:
import { createI18n } from 'vue-i18n'
import en from '../locales/en.json'
import ja from '../locales/ja.json'
export default defineNuxtPlugin(({ vueApp }) => {
const route = useRoute();
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: route.params.lang ?? "en",
messages: {
en,
ja
}
})
vueApp.use(i18n)
})
すると、https://your_url.com/ja
とすることで$i18n.locale
にja
が入ります。
「これって単にファイル複製しているだけだから多言語化じゃないじゃん」と不満が聞こえてきそうです。確かにほとんどそんな感じです。ただ、メリットを言うならば
- コピペするファイルは、
index.vue
に対応するようなファイルなので、その下の階層のファイルを逐一コピーする必要はない - 一応i18nを使っているのでlocaleで管理する"スッキリさ"はある
- 他のページに遷移しても、
$i18n.locale
の情報は引き継がれるので、サイト内で違うところに移っても言語設定が引き継がれる
などがあります。
nuxt/i18n
を使えば良いのでは?
冒頭で触れたように、vue-i18n
以外にnuxt/i18nというのもあります。
ただ、私の場合、こちらはどうしてもエラーが出て動かない箇所があったので(サンプルコードは動くので、何かパッケージが競合しているか何か...)、vue-i18n
を採用しました。
それでは。頑張りましょう。
Discussion