Nuxt.jsの国際化(i18n)対応
Nuxt.jsで英語、日本語の多言語対応したサイトを構築します。
[ 目次 ]
はじめに
こんにちは、香港に住んでいるWEBデベロッパーのなかむ(@nakanakamu0828)です。
この記事は過去に運用していたブログからの移行記事になります。
Nuxt.jsのリポジトリの国際化対応をしていきます。
■ 前回の投稿
言語の切り替えをサブディレクトリで行えるように実装していきます。
http://[domain]/
が英語ページ、http://[domain]/ja/
が日本語ページになるイメージです。
以下のNuxt.jsの公式ページを参考に進めていきます。
https://ja.nuxtjs.org/examples/i18n/
vue-i18nのインストール
$ npm install vue-i18n --save
package.json
を確認するとdependencies
にvue-i18n
が追加されます。
・・・
"dependencies": {
"nuxt": "^1.0.0",
"vue-i18n": "^7.6.0",
"vuetify": "^1.0.0"
},
・・・
各種ファイルの作成・更新
コマンドにてディレクトリ・ファイルを作成する
テンプレートとして作成されているpages/index.vue
の内容を修正して、多言語化を試します。
※pages/inspire.vue
は削除します
_langを作成するのは、URL内に言語を埋め込む為です。
$ mkdir -p pages/_lang
$ cp pages/index.vue pages/_lang/index.vue
$ rm -f pages/inspire.vue
翻訳ファイルはjsonで管理します
$ mkdir -p locales
$ touch locales/{en.json,ja.json}
$ touch plugins/i18n.js
$ touch middleware/i18n.js
pages/_lang/index.vue
タイトルを言語ごとに切り替えられるようにします
<template>
<v-layout column justify-center align-center>
<v-flex xs12 sm8 md6>
<h1>{{ $t('welcome.title') }}</h1>
</v-flex>
</v-layout>
</template>
pages/index.vue
<script>
import Index from '~/pages/_lang/index'
export default Index
</script>
locales/en.json
英語用の翻訳ファイル
{
"welcome": {
"title": "Welcome"
}
}
locales/ja.json
日本語用の翻訳ファイル
{
"welcome": {
"title": "ようこそ"
}
}
plugins/i18n.js
pluginにてi18nライブラリの読み込みと設定を行います。
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
export default ({ app, store }) => {
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: 'en',
messages: {
'en': require('~/locales/en.json'),
'ja': require('~/locales/ja.json')
}
})
app.i18n.path = (link) => {
if (app.i18n.locale === app.i18n.fallbackLocale) {
return `/${link}`
}
return `/${app.i18n.locale}/${link}`
}
}
middleware/i18n.js
HTTPリクエスト毎に現在の言語を設定します
export default function ({ isHMR, app, store, route, params, error, redirect }) {
const defaultLocale = app.i18n.fallbackLocale
if (isHMR) return
const locale = params.lang || defaultLocale
if (store.state.locales.indexOf(locale) === -1) {
return error({ message: 'This page could not be found.', statusCode: 404 })
}
store.commit('SET_LANG', locale)
app.i18n.locale = store.state.locale
if (locale === defaultLocale && route.fullPath.indexOf('/' + defaultLocale) === 0) {
const toReplace = '^/' + defaultLocale
const re = new RegExp(toReplace)
return redirect(
route.fullPath.replace(re, '/')
)
}
}
store/index.js
ストアに言語を設定して共通利用します
export const state = () => ({
sidebar: false,
locales: ['en', 'ja'],
locale: 'en'
})
export const mutations = {
toggleSidebar (state) {
state.sidebar = !state.sidebar
},
SET_LANG (state, locale) {
if (state.locales.indexOf(locale) !== -1) {
state.locale = locale
}
}
}
nuxt.config.js
nuxt.config.js
にプラグイン、ライブラリの設定を追加
・・・
plugins: [
'~/plugins/vuetify.js',
'~/plugins/i18n.js' <-- 追加
],
・・・
vendor: [
'~/plugins/vuetify.js',
'vue-i18n' <-- 追加
],
・・・
以下を追加
router: {
middleware: 'i18n'
},
generate: {
routes: ['/', '/ja']
}
layouts/default.vue
ヘッダーに言語切り替え用のdropdownを用意します。
inspireページのリンクは不要なので削除します。
<template>
<v-app dark>
<v-navigation-drawer
:mini-variant.sync="miniVariant"
:clipped="clipped"
v-model="drawer"
fixed
app
>
<v-list>
<v-list-tile
router
:to="item.to"
:key="i"
v-for="(item, i) in items"
exact
>
<v-list-tile-action>
<v-icon v-html="item.icon"></v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title v-text="item.title"></v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar fixed app :clipped-left="clipped">
<v-toolbar-side-icon @click="drawer = !drawer"></v-toolbar-side-icon>
<v-btn
icon
@click.stop="miniVariant = !miniVariant"
>
<v-icon v-html="miniVariant ? 'chevron_right' : 'chevron_left'"></v-icon>
</v-btn>
<v-btn
icon
@click.stop="clipped = !clipped"
>
<v-icon>web</v-icon>
</v-btn>
<v-btn
icon
@click.stop="fixed = !fixed"
>
<v-icon>remove</v-icon>
</v-btn>
<v-toolbar-title v-text="title"></v-toolbar-title>
<v-spacer></v-spacer>
<v-menu bottom left>
<v-btn icon slot="activator" dark>
<v-icon>language</v-icon>
</v-btn>
<v-list>
<v-list-tile v-for="(language, i) in languages" :key="i" :to="language.to">
<v-list-tile-title>{{ language.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<v-btn
icon
@click.stop="rightDrawer = !rightDrawer"
>
<v-icon>menu</v-icon>
</v-btn>
</v-toolbar>
<v-content>
<v-container>
<nuxt />
</v-container>
</v-content>
<v-navigation-drawer
temporary
:right="right"
v-model="rightDrawer"
fixed
>
<v-list>
<v-list-tile @click.native="right = !right">
<v-list-tile-action>
<v-icon light>compare_arrows</v-icon>
</v-list-tile-action>
<v-list-tile-title>Switch drawer (click me)</v-list-tile-title>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-footer :fixed="fixed" app>
<span>&copy; 2017</span>
</v-footer>
</v-app>
</template>
<script>
export default {
data () {
return {
clipped: false,
drawer: true,
fixed: false,
items: [
{ icon: 'apps', title: 'Welcome', to: '/' }
],
languages: [
{ title: 'English', to: this.$route.fullPath.replace(/^\/[^/]+/, '') },
{ title: '日本語', to: '/ja' + this.$route.fullPath.replace(/^\/[^/]+/, '') }
],
miniVariant: false,
right: true,
rightDrawer: false,
title: 'Vuetify.js'
}
}
}
</script>
plugins/vuetify.js
言語切り替えで利用した、v-menuのコンポーネントを読み込む為、plugins/vuetify.js
に設定を追加します。
import Vue from 'vue'
import {
Vuetify,
VApp,
VCard,
VNavigationDrawer,
VFooter,
VList,
VBtn,
VIcon,
VGrid,
VToolbar,
VMenu <-- 追加
} from 'vuetify'
Vue.use(Vuetify, {
components: {
VApp,
VCard,
VNavigationDrawer,
VFooter,
VList,
VBtn,
VIcon,
VGrid,
VToolbar,
VMenu <-- 追加
}
})
サーバー起動
開発環境としてサーバーを起動してみましょう。
$ npm run dev
ブラウザから http://localhost:3000 を開いて確認しましょう。
ヘッダーメニューの言語メニューから英語・日本語を切り替えてみてください。
今回の成果物は こちら になります。
Netlifyでデモ環境を用意しています。以下のURLにてご確認ください。
https://goofy-feynman-3a61d1.netlify.com/
修正(2018/10/24)
デモページに関しては、サンプルで作ったものなので閉鎖しました。