こんにちは。てぃろです。
今回はVue.jsで作ったフロントを多言語化し、日本語と英語を切り替えできるようにした話です。Vue I18nというモジュールを使用して、Vue.jsのアプリを簡単に多言語化できました。
本記事は個人的に開発したVueSlsAppというサーバーレスアプリフレームワークへ修正を入れていった過程をもとに、基本的な導入方法から独自に工夫した点も含めて解説しています。
デプロイしてあるので、以下のリンクから実際にアプリを触ってみてもらえます。(多言語済)
https://vueslsapp.thiroyoshi.com/
VueSlsAppのことをご存じない方は、以下の記事を参照してみてください。
VusSlsAppのリポジトリは以下です。
日本語と英語を切り替えられるようにしました
言語切替のボタンをフッターに追加して、いつでも切り替えができるようにしています。もともと英語で表記していたので、↓ が最初の状態。
日本のマークをクリックすると、↓ のように日本語になります。
ここではフッターしか見せていませんが、もちろん画面全体でメッセージは切り替わっています。Vue.jsの機能で実現しているので言語が変化するのは一瞬です。
ちなみに、画像で見せている国旗は↓ のモジュールを使っています。
多言語化は”メッセージとアプリを分離すること”にメリットがある
多言語化をすると、Vue.jsの中に書いていた各種メッセージを他のファイルに分離することができます。
Vue.jsでは非常にわかりやすく関心事が分離できているところが大きなメリットだったと思いますが、これでメッセージ部分も分離できたということです。
なお、Vue I18nは言語設定が1つであっても使用可能です。そのためこのモジュールを入れた一番のメリットは、多言語化ではなく、メッセージ部分の分離だと思っています。
Vue I18nの基本的な使い方
Vue I18nを導入していきます。
https://kazupon.github.io/vue-i18n/
まずインストールしていきます。以下のリンクから自分の環境にあった形でインストールをしていきます。私はnpmでインストールしています。
https://kazupon.github.io/vue-i18n/installation.html
ここから、本題のコードの修正です。
多言語化するには、main.jsに以下の様に書くのが基本です。これらすべてを自分のコードの中に追加していきましょう。
const messages = {
en: {
message: {
hello: 'hello world'
}
},
ja: {
message: {
hello: 'こんにちは、世界'
}
}
}
// Create VueI18n instance with options
const i18n = new VueI18n({
locale: 'ja', // set locale
messages, // set locale messages
})
// Create a Vue instance with `i18n` option
new Vue({ i18n }).$mount('#app')
メッセージの表示部分は以下のように書き直します。
<div id="app">
<p>{{ $t("message.hello") }}</p> // ここでメッセージが表示される
</div>
つまり、messagesというjsonオブジェクトとして言語ごとのメッセージを分けて定義しておき、{{ $t(“message.hello”) }}という形でHTMLの中に書くと定義したメッセージを表示することができます。
$t()の中では、jsonオブジェクト内の値を呼び出す形で書くので、messageのjsonオブジェクトは自由にネストして書くことができます。ページごとにまとめる・コンテンツごとにまとめるなど柔軟に設定できます。
このとき、jsonオブジェクトは外部ファイルを読み出す形で書き換えることが可能です。私の以下のように実装しています。
const i18n = new VueI18n({
locale: 'en',
messages: require('./assets/messages.json') // ここでjsonを読み込む
})
このようにすると、Vue.jsの中に書いていた各種メッセージを他のファイルに分離することができて、コードの見通しがよくなります。
ここまでが基本的な使い方です。他にもたくさん機能を持っているので使い込みたい方はぜひ公式ドキュメントを見てください。
3つの実装時に工夫したことと注意すべきこと
ここからは、実装時の工夫や注意すべき点について書いていきます。以下の3点を紹介します。
- ルーティングはrouterをかならず使う
- labelを多言語化するときは”:label”と書く
- ajaxで読み込む利用規約は、事前に読み出しておく
ルーティングはrouterをかならず使う
必ずVueで提供されているrouterを使ってルーティングしましょう。
公式のRouterはコチラから確認することができます。
HTMLのaタグリンクで遷移させると、そのたびにJavascriptの読み込みが最初から行われてしまい、パラメータが初期化されます。
つまり、遷移直後は言語設定のlocaleも初期値が使われてしまいますので、デフォルトと違う言語を使っていたユーザにとっては、突然デフォルト言語で見せられるということになってしまいます。
これを防ぐためにも、多言語化の段階でrouterを導入したり、aタグリンクで遷移させてるところがないかチェックしてみてください。
labelを多言語化するときは”:label”と書く
HTMLのタグで挟んで表示するテキストについては、先述したとおりですが、Vue.jsで私が多用している”label”というパラメータについては書き方が異なります。多言語化する前は以下のように書いていました。
<v-text-field
v-model="email"
:rules="[rules.required]"
label="Username" // ここを多言語化したい
autocomplete="username"
required
/>
これは、以下のようにv-bindを使った書き方にしないといけません。
<v-text-field
v-model="email"
:rules="[rules.required]"
:label="$t('login.username')" // ここがv-bindの書き方にしている
autocomplete="username"
required
/>
変わったところというと、labelの前に”:”を追加しているだけです。
もちろん、これはlabelだけに言えることではなく、placeholderなどすべてのパラメータで使える方法だと思います。
この方法については、以下の記事を参考にさせてもらいました。
ajaxで読み込む利用規約は、事前に読み出しておく
利用規約はajaxを使ってterms.txtというテキストファイルを読み出して表示しています。そのため、以下の対応が必要でした。
- 言語ごとの利用規約のテキストファイルを用意する
- 言語設定によって、利用規約のテキストファイルを呼び分ける
- フッターで言語切替されたときにも切り替える
言語ごとの利用規約のテキストファイルを用意する
VueSlsAppはサンプルなので適当に日本語化した(ことにした)テキストファイルを用意しました。本番の場合は特に、都度の機械翻訳では法的な観点で正しく翻訳できないことがあると思うので、利用規約のテキストファイルは事前に用意することが必要になるでしょう。
言語設定によって、利用規約のテキストファイルを呼び分ける
利用規約のテキストファイルの読み込みは以下のようになっています。
mounted: function () {
this.axios.get('terms.txt')
.then(res => {
this.termsText = res.data
})
}
つまり、Vue.jsのマウント後にajaxで読み出しています。先にテキストファイルは言語ごとに分けていますので、言語設定によってテキストファイルのパスで呼び分ければいいわけです。
呼び分ければいいとなれば、以下のようにしたくなりますが、これでは言語切替ボタンを押したときに利用規約は切り替わりません。
mounted: function () {
this.axios.get(this.$i18n.locale + '/terms.txt') // localeでパスを変える
.then(res => {
this.termsText = res.data
})
}
このajax読み出しはmountedに書いているので、フッターのボタンを押したところで発火しないから、なんですね。
フッターで言語切替されたときにも切り替える
言語設定の切り替えできれいに呼び分ける方法を考えましたが、今回は断念してます…。少しダサいですがそれぞれのテキストファイルをマウント時に読み込んでおいて、言語設定によってv-showで見せる要素を切り替える、という方法にしました。
まず、mountedの部分は以下のようになります。
mounted: function () {
this.axios.get('ja/terms.txt')
.then(res => {
this.termsTextJa = res.data
})
this.axios.get('en/terms.txt')
.then(res => {
this.termsTextEn = res.data
})
}
これでテキストファイルをそれぞれ呼び出して、termsTextJaやtermsTextEnに利用規約のテキストを読み込んでいます。利用規約のテキスト部分は以下のようになっています。
<v-textarea
v-show="this.$i18n.locale==='ja'" // ここで切り替え判定
v-model="termsTextJa"
outlined
no-resize
readonly
height="50vh"
/>
<v-textarea
v-show="this.$i18n.locale==='en'" // ここで切り替え判定
v-model="termsTextEn"
outlined
no-resize
readonly
height="50vh"
/>
this.$i18n.localeはどこでも呼び出して言語設定の値を読み出せます。これとv-showを利用し、言語設定が切り替わるごとに見せるtextareaを切り替えることで実現しています。
ここまでで、利用規約も言語設定を切り替えるごとに切り替わるようにできました。
まとめ
Vue.jsのフロントをVue I18nで多言語化してみました。
一部で工夫が必要になってしまいましたが、思ったよりは簡単に多言語化ができたと思います。利用規約の部分はもう少しスマートな方法がないかな、と思っているのでどなたか思いついた方は教えていただけるとうれしいです。
とはいえ、やはり一番のメリットはメッセージを分離できることだと思うので、多言語化の予定がない場合でも導入を検討してみることをオススメします。
題材として使っているVueSlsAppはアーキテクチャについても解説しています。よければこちらもチェックしてみてください。