nuxt-i18nもう使えるらしいのでやろうとしたらエラーでたのでとりあえずvue-i18nでドキュメントみて実装しました。
※ 要所のファイルしか載せてないので他気になる箇所は国際化(i18n) - Nuxt.jsを見てください。
yarn add vue-i18n -D
nuxt.config.ts
const config = {
head: {
title: '...',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '...' }
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},
loading: { color: '#3B8070' },
// 追加 //////////////////////////////////////////////////////////////////
router: {
middleware: 'i18n'
},
generate: {
routes: [
'/',
'/en'
]
},
/////////////////////////////////////////////////////////////////////////
css: [
...
],
build: {
...
},
// 追加 //////////////////////////////////////////////////////////////////
plugins: [
'~/plugins/i18n.js'
],
//////////////////////////////////////////////////////////////////////////
modules: [
...
]
}
export default config
~/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')
}
})
app.i18n.path = (link) => {
if (app.i18n.locale === app.i18n.fallbackLocale) {
return `/${link}`
}
return `/${app.i18n.locale}/${link}`
}
}
~/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, '/')
)
}
}
~/locales/ja.json
{
"links": {
"home": "トップ",
"message": "ご挨拶",
"info": "企業情報",
"english": "English",
"japanese": "Japanese"
},
"home": {
"title": "ようこそ",
"introduction": "これはトップページです。"
},
"message": {
"title": "ご挨拶",
"introduction": "これはご挨拶ページです。"
},
"info": {
"title": "企業情報",
"introduction": "これは企業情報ページです。"
}
}
~/locales/en.json
{
"links": {
"home": "Home",
"message": "Message",
"info": "Info",
"english": "英語",
"japanese": "日本語"
},
"home": {
"title": "Home",
"introduction": "This is the home page."
},
"message": {
"title": "Message",
"introduction": "This is the message page."
},
"info": {
"title": "Info",
"introduction": "This is the info page."
}
}
~/layouts/Header.vue
<template>
<header class="header">
<nav class="nav">
<NuxtLink :to="$i18n.path('')" class="header__link" exact>
{{ $t('links.home') }}
</NuxtLink>
<NuxtLink :to="$i18n.path('message')" class="header__link" exact>
{{ $t('links.message') }}
</NuxtLink>
<NuxtLink :to="$i18n.path('info')" class="header__link" exact>
{{ $t('links.info') }}
</NuxtLink>
<NuxtLink v-if="$i18n.locale === 'ja'" :to="`/en` + $route.fullPath" class="header__link" active-class="none" exact>
{{ $t('links.english') }}
</NuxtLink>
<NuxtLink v-else :to="$route.fullPath.replace(/^\/[^\/]+/, '')" class="header__link" active-class="none" exact>
{{ $t('links.japanese') }}
</NuxtLink>
</nav>
</header>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component({
})
export default class HeaderLayout extends Vue {}
</script>
<style lang="scss" scoped>
.header {
}
.nav {
.header__link {
}
}
</style>
~/pages/index.vue
<script>
import Index from '~/pages/_lang/index'
export default Index
</script>
~/pages/_lang/index.vue
<template>
<div>
<section>
<h1>{{ $t('home.title') }}</h1>
</section>
<p>{{ $t('home.sentence1') }}</p>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component({
components: {
}
})
export default class IndexPage extends Vue {}
</script>
<style lang="scss" scoped>
</style>