vue搭配i18n国际化语言插件开发多语言网站
安装过程直接略过,安装步骤链接:
vue命令行工具 (CLI)
vue-i18n插件
vue-i18n基本使用
使用vue开发,使用最多的是单文件组件,所以碰到的坑都是在这一部分;
开发使用版本:
"vue": "^2.5.2",
"vue-router": "^3.0.1"
====================================
"vue-i18n": "^7.4.0",
"@kazupon/vue-i18n-loader": "^0.2.1",
问题一、vue-i18n-loader如何添加在vue的配置文件
为了使用单文件组件时配合i18n存储map数据,需要先安装vue-i18n-loader
,然后使用<i18n></i18n>
标签定义map数据。
原谅小白,以前使用vue时,都没好好研究vue的配置文件,直到这次碰到问题,才稍微认真看了一会(还没全部弄明白);
根据i18n给的添加方法:
module.exports = {
// ...
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// you need to specify `i18n` loaders key with `vue-i18n-loader` (https://github.com/kazupon/vue-i18n-loader)
i18n: '@kazupon/vue-i18n-loader'
}
}
},
// ...
]
},
// ...
}
但是,vue的配置文件都是封装好的一系列方法,中间尝试过各种办法,这里就不一一列举出来(PS:主要是时间有点久,记不住了😢)。
最后,尝试在webpack.base.conf.js
文件console vueLoaderConfig
变量(编译时能看到输出结果)
npm run dev
vueLoaderConfig
的输出结果:
{ loaders:
{ css: [ 'vue-style-loader', [Object] ],
postcss: [ 'vue-style-loader', [Object] ],
less: [ 'vue-style-loader', [Object], [Object] ],
sass: [ 'vue-style-loader', [Object], [Object] ],
scss: [ 'vue-style-loader', [Object], [Object] ],
stylus: [ 'vue-style-loader', [Object], [Object] ],
styl: [ 'vue-style-loader', [Object], [Object] ]
cssSourceMap: true,
cacheBusting: true,
transformToRequire:
{ video: [ 'src', 'poster' ],
source: 'src',
img: 'src',
image: 'xlink:href' } }
看到这里,客官就该明白,要如何添加了~
没错,直接给vueLoaderConfig
对象添加一条属性值即可;
vueLoaderConfig.loaders.i18n = '@kazupon/vue-i18n-loader';
重新编译,结果如下:
{ loaders:
{ css: [ 'vue-style-loader', [Object] ],
postcss: [ 'vue-style-loader', [Object] ],
less: [ 'vue-style-loader', [Object], [Object] ],
sass: [ 'vue-style-loader', [Object], [Object] ],
scss: [ 'vue-style-loader', [Object], [Object] ],
stylus: [ 'vue-style-loader', [Object], [Object] ],
styl: [ 'vue-style-loader', [Object], [Object] ],
i18n: '@kazupon/vue-i18n-loader' },
cssSourceMap: true,
cacheBusting: true,
transformToRequire:
{ video: [ 'src', 'poster' ],
source: 'src',
img: 'src',
image: 'xlink:href' } }
到此,vue-i18n-loader我们就正确添加到vue配置文件里啦。
问题二、 如何全局修改i18n的语言切换,使各个组件能够同步切换语言
根据i18n
文档,全局修改i18n的语言配置,可以这么用:
const i18n = new VueI18n({
locale: 'en',
// ...
})
const app = new Vue({ i18n }).$mount('#app')
// change locale
i18n.locale = 'ja'
// or
app.$i18n.locale = 'ja'
看到这个,瞬间觉得自己明白了,开心地继续往下码
根据使用文档,先引入i18n
//main.js
import router from './router';
import layOut from '@/components/layout';
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
const i18n = new VueI18n({
locale: 'cn',
messages: {
cn: {
},
en: {
}
}
})
new Vue({
el: '#app',
router,
i18n,
components: { layOut },
template: '<layOut/>'
});
//layout.vue 片段(英文翻译为了测试随便写,因为公司翻译还没翻译完😂)
<i18n>
{
"en": {
"navTitle": {
"ivf": {
"name": "ivf",
"path": "ivf"
},
"juanLuan": {
"name": "Egg Donation",
"path": "egg_donation"
},
"surrogacy": {
"name": "Surrogacy",
"path": "surrogacy"
},
"law": {
"name": "Law",
"path": "law"
},
"recruit": {
"name": "Recruit",
"path": "recruit",
"detail": {
"juanLuan": {
"name": "As Egg Donation",
"path": "recruit/egg_donation"
},
"daiMa": {
"name": "As Baby Mama",
"path": "recruit/baby_mama"
}
}
},
"successCase": {
"name": "successCase",
"path": "successCase"
},
"aboutUs": {
"name": "aboutUs",
"path": "aboutUs"
}
}
},
"cn": {
"navTitle": {
"ivf": {
"name": "ivf",
"path": "ivf"
},
"juanLuan": {
"name": "捐卵",
"path": "egg_donation"
},
"surrogacy": {
"name": "代孕",
"path": "surrogacy"
},
"law": {
"name": "法律政策",
"path": "law"
},
"recruit": {
"name": "捐卵者/代码招募",
"path": "recruit",
"detail": {
"juanLuan": {
"name": "成为捐卵者",
"path": "recruit/egg_donation"
},
"daiMa": {
"name": "成为代妈",
"path": "recruit/baby_mama"
}
}
},
"successCase": {
"name": "成功案例",
"path": "successCase"
},
"aboutUs": {
"name": "关于我们",
"path": "aboutUs"
}
}
}
}
</i18n>
<template>
<div class="u-icon-block">
<span class="u-icon u-icon--cn" @click="changeLang('cn')"></span>
<span class="u-icon u-icon--en" @click="changeLang('en')"></span>
<span class="u-icon u-icon--ua" @click="changeLang('ua')"></span>
</div>
<keep-alive>
<router-view></router-view>
</keep-alive>
<template>
<script>
methods: {
changeLang (lan) {
this.$i18n.locale = lan
}
}
</script>
OK,到了这里,测试一下,导航的标题能够正常切换了,但是router组件却没变化,瞬间懵逼了(原谅小白的不懂)
怎么回事呢,为什么没有全部替换呢?
原因一、此时的this.$i18n
所替换的作用域仅是在当前组件里面,router子组件没有收到来自父组件的通信,所以没有跟着一起变化;
原因二、没有使用i18n文档里面的全局替换方法(这个暂时还没想好怎么换,请大神指教,谢谢)
想明白了这点,那么为了能够全局跟踪i18n
的locale
的变化,我决定使用Vuex
状态管理
撸起袖子,重新编写
//main.js
import Vue from 'vue';
import router from './router';
import layOut from '@/components/layout';
import store from './store/locale';
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
i18n: store.i18n,
store: store.store,
components: { layOut },
template: '<layOut/>'
});
//store.js
import Vue from 'vue';
import Vuex from 'vuex';
import VueI18n from 'vue-i18n';
Vue.use(Vuex);
Vue.use(VueI18n);
let status = {
store: new Vuex.Store({
state: {
locale: 'cn'
},
getters: {
locale (state) {
console.log(state.locale);
return state.locale;
}
},
mutations: {
changeLang (state, payload) {
state.locale = payload;
console.log(state);
status.i18n.locale = payload;
}
}
}),
i18n: new VueI18n({
locale: 'cn',
messages: {
cn: {
},
en: {
}
}
})
};
export default status;
//layout.vue 片段
export default {
methods: {
changeLang (lang) {
this.$store.commit('changeLang', lang);
}
}
};
OK,到了这里,我们就能实现全局变换i18n的locale了。但是,接下来,又碰到一个问题。
问题三、想要在组件里面使用v-for
数据,及想往子组件里面传递props数据怎么办?
现在我们的mpa数据都是存储在<i18n></i18n>
里面的,要怎么取出来呢?
这里就要用到i18n
提供的一个method getLocaleMessage( locale )
//描述
getLocaleMessage( locale )
Arguments:
{Locale} locale
Return: LocaleMessageObject
Get the locale message of locale.
我们依然通过Vuex来获取变化的locale
//banner组件
<template>
<div class="u-grid-fluid banner">
<div class="u-grid u-title">
<h3 class="u-title__item u-title__item--border--b">{{ bannerData.title1 }}</h3>
<h3 class="u-title__item">{{ bannerData.title2 }}</h3>
<p v-if="bannerData.desc" class="u-title__desc">{{ bannerData.desc }}</p>
</div>
</div>
</template>
<script>
export default {
props: ['bannerData']
};
</script>
//index.vue(父组件)
<template>
<div>
<banner :banner-data="bannerData"></banner>
<div>
</template>
//map数据
<i18n>
{
"en": {
"banner": {
"title1": "Freyja",
"title2": "乌克兰捐卵,代孕服务专家",
"desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magnavel scelerisque nisl consectetur et."
},
"sectionOne": {
"title": "Freyja",
"content": "芙蕾雅成立于2016年,致力于为有需要的用户提供专业的乌克兰捐卵,代孕服务。芙蕾雅团队由专业的生殖医疗专家,律师,生活服务人员组成。为用户的乌克兰捐卵,代孕之旅提供科学可信赖的保障。",
"desc": "Freyja- healtch for you"
},
"sectionTwo": {
"title": "Freyja",
"content1": "乌克兰支持捐卵与代孕,您的权益将受到法律的保护"
}
},
"cn": {
"banner": {
"title1": "芙蕾雅",
"title2": "乌克兰捐卵,代孕服务专家",
"desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magnavel scelerisque nisl consectetur et."
},
"sectionOne": {
"title": "关于芙蕾雅",
"content": "芙蕾雅成立于2016年,致力于为有需要的用户提供专业的乌克兰捐卵,代孕服务。芙蕾雅团队由专业的生殖医疗专家,律师,生活服务人员组成。为用户的乌克兰捐卵,代孕之旅提供科学可信赖的保障。",
"desc": "Freyja- healtch for you"
},
"sectionTwo": {
"title": "为什么选择芙蕾雅?",
"content1": "乌克兰支持捐卵与代孕,您的权益将受到法律的保护"
}
}
}
</i18n>
<script>
import banner from '../components/banner';
export default {
data () {
return {
locale: this.$store.getters.locale
};
},
computed: {
bannerData () {
let label = this.$store.getters.locale;
return this.$i18n.getLocaleMessage(label).banner;
}
},
components: {
banner
}
};
</script>
至此,我们就能顺利把<i18n></i18n>里面的数据顺利提取出来为我们所用了。
PS:<i18n>里面的json数据,最后的一条json对象里面不能有多余的逗号",",否则就会报错
//错误示例 sectionTwo的content1不小心加了一个逗号,结果就报错了
{
"banner": {
"title1": "Freyja",
"title2": "乌克兰捐卵,代孕服务专家",
"desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magnavel scelerisque nisl consectetur et."
},
"sectionOne": {
"title": "Freyja",
"content": "芙蕾雅成立于2016年,致力于为有需要的用户提供专业的乌克兰捐卵,代孕服务。芙蕾雅团队由专业的生殖医疗专家,律师,生活服务人员组成。为用户的乌克兰捐卵,代孕之旅提供科学可信赖的保障。",
"desc": "Freyja- healtch for you"
},
"sectionTwo": {
"title": "Freyja",
"content1": "乌克兰支持捐卵与代孕,您的权益将受到法律的保护",
}
}
//==================报错信息
error in ./src/pages/index.vue
Syntax Error: Unexpected token } in JSON at position 707
at JSON.parse (<anonymous>)
@ ./src/pages/index.vue 31:18-136
这个错误,让我蒙圈了好一会儿,坑惨了😭
====================== The End =================================
流水式记录,不足之处,还请各位大神多多指教,谢谢!