最近vue项目需要中英文切换,查了资料,发现大部分都是采用 vue-i18n,但是写的比较简单,大部分都是全局引入语言包,遇到的几个问题
1、如何结合element-ui 实现中英文切换
2、如何在组件中使用各自的语言包
3、中英文切换如何刷新页面,特别是中英文切换时根据当前语言调用中文或者英文接口
全局引入语言包实现中英文切换
一、安装vue-i18n,我安装的版本是 "vue-i18n": "^8.22.0",
npm install --save vue-i18n
新建一个common文件夹,里面含有如下文件
en.js 为英文文件包,enLocale为element英文语言包
import enLocale from 'element-ui/lib/locale/lang/en'
const en = {
"person":{
"name":"name",
"gender":"gender",
"age":"age"
},
...enLocale
}
export default en
zh.js为中文文件包,
import zhLocale from 'element-ui/lib/locale/lang/zh-CN'
const zh = {
"person":{
"name":"名称new",
"gender":"性别",
"age":"年龄"
},
...zhLocale
}
export default zh
index.js
import en from "./en"
import zh from "./zh"
export default {
en,
zh
}
i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import messages from './index.js'
import store from '@/store'
Vue.use(VueI18n)
console.log("hi")
const i18n = new VueI18n({
locale: localStorage.getItem("currentLanage") || "zh",
messages,
// silentTranslationWarn: true
})
export default i18n
在main.js中引文i18n并注册到vue实例中
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import i18n from "./common/i18n/i18n.js"
import ElementUI from 'element-ui'
// 引入element-ui 样式文件
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI, {
i18n: (key, value) => i18n.t(key, value)
})
new Vue({
i18n,
router,
store,
render: h => h(App)
}).$mount('#app')
注意:不同的vue=i18n版本和element-ui结合的方式不同。具体见element-ui的官网 https://element.eleme.cn/#/zh-CN/component/i18n
使用方法
<div>
来自全局:
<span>{{ $t("person.name") }}</span>
<el-date-picker v-model="value1" type="date" ></el-date-picker>
</div>
<div class="page-top">
<div class>
<div class="left pull-left logo-wrap">
<img src="../assets/imgs/emerson-logo.png" alt class="pull-left" />
<span class="pull-left topName">GasNet Master</span>
</div>
<div class="right pull-right">
<span class="margin_r20 top_language">
<a href="javascript:void(0)" :class="{active:isZh}" @click="changeLanage('zh')">中文</a> |
<a href="javascript:void(0)" :class="{active:!isZh}" @click="changeLanage('en')">英文</a>
</span>
<a href="javascript:void(0)">About</a>
<a href="javascript:void(0)">Help</a>
<a href>Logout</a>
</div>
</div>
</div>
changeLanage(lang) {
if (lang == "zh") {
this.isZh = true;
this.$i18n.locale = lang;
localStorage.setItem("currentLanage", lang);
} else if (lang == "en") {
this.isZh = false;
this.$i18n.locale = lang;
localStorage.setItem("currentLanage", lang);
}
}
上面实现了基本的中英文切换,但是如果把所以得语言都放到全局,不容易维护,一般是把通用的放在全局,每个页面特有的放在组件中
安装vue-i18n-loader
npm install --save @kazupon/vue-i18n-loader
vue-cli3中配置 vue.config.js中配置
chainWebpack: config => {
config.module
.rule('i18n')
.resourceQuery(/blockType=i18n/)
.type("javascript/auto")
.use('i18n')
.loader('@kazupon/vue-i18n-loader')
.end()
},
使用方法
.vue页面
来自组件:{{ $t("helloworld") }}
<i18n>
{
"en": {
"placeholder":"pick a day",
"helloworld": "hello world!"
},
"zh": {
"placeholder":"选择日期",
"helloworld": "你好,世界new!"
}
}
</i18n>
关于如果实现中英文切换时根据当前语言调用中文或者英文接口 ( 通过provide inject 实现 ),假如中英切换按钮在Home.vue上,Home.vue含有
<router-view></router-view> 来承载子路由
App.vue
<template>
<div id="app">
<router-view v-if="isRouterAlive"/>
</div>
</template>
<script>
export default{
name:"app",
provide(){
return {reload:this.reload}
},
data(){
return {
isRouterAlive:true
}
},
methods:{
reload(){
this.isRouterAlive = false
this.$nextTick(function(){
this.isRouterAlive = true
})
}
}
}
</script>
Home.vue
<template>
<div>
<div>
来自全局:
<span>{{ $t("person.name") }}</span>
</div>
<div class="page-top">
<div class>
<div class="left pull-left logo-wrap">
<img src="../assets/imgs/emerson-logo.png" alt class="pull-left" />
<span class="pull-left topName">GasNet Master</span>
</div>
<div class="right pull-right">
<span class="margin_r20 top_language">
<a href="javascript:void(0)" :class="{active:isZh}" @click="changeLanage('zh')">中文</a> |
<a href="javascript:void(0)" :class="{active:!isZh}" @click="changeLanage('en')">英文</a>
</span>
<a href="javascript:void(0)">About</a>
<a href="javascript:void(0)">Help</a>
<a href>Logout</a>
</div>
</div>
</div>
<el-menu
router
mode="horizontal"
:default-active="$route.path"
background-color="#004b8e"
text-color="#fff"
active-text-color="#ffD04B"
>
<NavMenu v-for="item in menuData" :key="item.id" :menuItem="item"></NavMenu>
</el-menu>
<router-view></router-view>
</div>
</template>
<script>
import NavMenu from "@/components/NavMenu.vue";
export default {
inject: ["reload"],
data() {
return {
isZh:
localStorage.getItem("currentLanage") == null
? true
: localStorage.getItem("currentLanage") == "zh"
? true
: false
};
},
computed: {
menuData() {
return this.$store.state.menuData;
}
},
methods: {
changeLanage(lang) {
if (lang == "zh") {
this.isZh = true;
this.$i18n.locale = lang;
localStorage.setItem("currentLanage", lang);
this.reload();
} else if (lang == "en") {
this.isZh = false;
this.$i18n.locale = lang;
localStorage.setItem("currentLanage", lang);
this.reload();
}
// this.$i18n.locale = this.lang // 只对局部有效 ,删除局部倒是对全局有效
}
},
components: { NavMenu }
};
</script>
子组件
<template>
<div>
<div class="block">
<span class="demonstration">默认</span>
<el-date-picker v-model="value1" type="date" :placeholder="$t('placeholder')">
</el-date-picker>
</div>
<div>来自全局:{{$t("person.age")}}</div>
<div>来自组件:{{ $t("helloworld") }}</div>
<!-- 调用接口,切换语言时需要重新加载页面,home页面用到 inject:["reload"],-->
<h2>{{ info }}</h2>
<!-- 切换语言按钮在组件内 只能切换组件内的语言,如果删除组件内的语言则可以切换全局的语言,但是一般切换按钮也不会在组件内 -->
<el-button @click="changeLanage">切换语言</el-button>
</div>
</template>
<i18n>
{
"en": {
"placeholder":"pick a day",
"helloworld": "hello world!"
},
"zh": {
"placeholder":"选择日期",
"helloworld": "你好,世界new!"
}
}
</i18n>
<script>
import NavMenu from "@/components/NavMenu.vue";
export default {
data() {
return {
info: "",
value1: ''
};
},
computed: {
menuData() {
return this.$store.state.menuData;
},
},
components: { NavMenu },
created() {
this.getInfo();
},
methods: {
changeLanage(){
this.$i18n.locale = "en"
},
getInfo() {
let lang = localStorage.getItem("currentLanage") || "zh";
console.log(lang);
this.$axios.get("mock/data_" + lang + ".json").then((res) => {
console.log(res.data.info);
this.info = res.data.info;
});
},
},
};
</script>
发现在子组件中同时使用全局的语言包和局部语言包,会报警告
vue-i18n.esm.js?a925:33 [vue-i18n] Value of key 'person.age' is not a string or function !
[vue-i18n] Fall back to translate the keypath 'person.age' with root locale.
但是能正常切换语言,只需要在VueI18n 实例中配置silentTranslationWarn: true
const i18n = new VueI18n({
locale: localStorage.getItem("currentLanage") || "zh",
messages,
silentTranslationWarn: true
})