nuxt.jsのプロジェクトにvue-i18nを導入する
追記
成果物
目的
多言語対応したwebサイトを構築したい。日本語のページは /ja 、英語のページは /en に用意する。/にアクセスがあった場合は日本語のページを表示する。
要件
nuxt.jsでサイト構築するがSSRはせず静的ファイルを配信する。vue-i18nを使って多言語対応する。
nuxt.jsプロジェクトの準備
プロジェクト名は nuxt-vue-i18n-sandbox にした。これを機にvue-cli v3を触ろうと思ったが本質ではないので回避した。
code:bash
$ vue init nuxt-community/starter-template nuxt-vue-i18n-sandbox
$ yarn
$ yarn add vue-i18n
翻訳ファイルの用意
javascriptのオブジェクトに変換できればいいのでファイルはyamlでもjsonでも何でも良い。ただjsonで用意するのが一番簡単。
code:locales/ja.json
{
"hello": "こんにちは!"
}
code:loclaes/en.json
{
"hello": "Hello!"
}
i18n用のnuxt pluginの用意
fallbackLocale は何も言語が指定されていない時に選択されるデフォルトの言語。
code:plugins/i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
export default ({ app, store }) => {
// Set i18n instance on app
// This way we can use it in middleware and pages asyncData/fetch
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: 'ja',
messages: {
'en': require('~/locales/en.json'),
'ja': require('~/locales/ja.json')
}
})
}
i18n用のnuxt middlewareの用意
pathを解析してstateに現在の言語を設定した後に、/ja以下へのアクセスを/にリダイレクトする。
code:middleware/i18n.js
export default function ({ isHMR, app, store, route, params, error, redirect }) {
const defaultLocale = app.i18n.fallbackLocale
// If middleware is called from hot module replacement, ignore it
if (isHMR) return
// Get locale from params
const locale = params.lang || defaultLocale
if (store.state.locales.indexOf(locale) === -1) {
return error({ message: 'This page could not be found.', statusCode: 404 })
}
// Set locale
store.commit('SET_LANG', locale)
app.i18n.locale = store.state.locale
// If route is /<defaultLocale>/... -> redirect to /...
if (locale === defaultLocale && route.fullPath.indexOf('/' + defaultLocale) === 0) {
const toReplace = '^/' + defaultLocale + (route.fullPath.indexOf('/' + defaultLocale + '/') === 0 ? '/' : '')
const re = new RegExp(toReplace)
return redirect(
route.fullPath.replace(re, '/')
)
}
}
vuex store
actionのchangeLangにnuxtのrouterと言語を渡してやると各言語のindexページに遷移する。indexページ以外に対応するなら正規表現でreplaceしてやる必要がある。
code:store/index.js
export const state = () => ({
locale: 'ja'
})
export const mutations = {
SET_LANG(state, locale) {
if (state.locales.indexOf(locale) !== -1) {
state.locale = locale
}
}
}
export const actions = {
changeLang(_, {router, lang}) {
// ちゃんとやるならroute情報を貰って正規表現であれする
router.replace(/${lang})
}
}
nuxt.config.js
code:nuxt.config.js.diff
+ router: {
+ middleware: 'i18n'
+ },
+ generate: {
+ routes: '/en',
+ }
indexページ
サンプル用にボタンをクリックすると言語が切り替わるページを用意した。middlewareでvalidateしているのでここでは表示するだけ
code:pages/_lang/index.vue
<template>
<div>
<p>
{{ $t("hello") }}
</p>
<button @click="changeLang">change to {{otherLang}}</button>
</div>
</template>
<script>
export default {
computed: {
otherLang() {
return this.$i18n.locale == 'ja' ? 'en' : 'ja';
}
},
methods: {
changeLang() {
const router = this.$router;
this.$store.dispatch('changeLang', { router, lang: this.otherLang })
}
}
}
</script>
code:pages/index.vue
<script>
import Index from '~/pages/_lang/index'
export default Index
</script>
その他考えること
$t vs v-t
参考
ここがほぼ全てだった