需求提的比较着急,匆忙看了一些相关文章就开始上手,踩了些坑,不过好歹是完成了。
前提
一般来说,语言环境存储在本地还是服务器上是个值得根据产品来思考的事情。
最开始,我是把用户设置的语言存储在 cookies 和 localstorage 中,当用户刷新的时候,可以保持当前的语言不变。
出现的问题是当用户手动清除了浏览器的缓存,那么语言就会设置为初始值,不过经过产品的讨论,认为这样是可以接受的。
因为后端有导出和生成文件的一些操作,所以每次用户点击导出或生成,将当前语言携带过去就可以了。
elementUI 国际化
elementui 自身携带了国际化,所以我们要做的就是让他和 vue-i18n 兼容,关于这一点,elementUI 的官方文档上写的非常清楚。这里
附上地址 :
关于兼容 vue-i18n ,实际上代码也介绍的非常清楚,大家简单看看就能明白,实在有困难的,接着往下看就好。
项目中其他的文本内容,包括后端返回的内容,都是通过 vue-i18n 翻译后展示在前台的,下面我来讲一下具体的实现思路
正题
vue-i18n 就非常简单了,我们利用 vue 的脚手架 vue-cli 快速搭建一个项目,然后再 main.js 的同级目录新
建一个 .js 的文件,叫 i18n.js, 然后开始编辑
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import ElementLocale from 'element-ui/lib/locale'
import elementEnLocale from 'element-ui/lib/locale/lang/en' // elementui 的英文语言包
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' // elementui 的中文语言包
import output_dicts from './lang' // 将对应的语言包引入
Vue.use(VueI18n)
const messages = {
'zh': { // 中文包
...output_dicts.zh,
...elementZhLocale
},
'en': { // 英文包
...output_dicts.en,
...elementEnLocale
}
}
const i18n = new VueI18n({
locale: 'zh',
messages,
})
ElementLocale.i18n((key, value) => i18n.t(key, value))
export default i18n
在 vue 项目的入口文件 main.js 中编辑
import Vue from 'vue'
import i18n from './i18n'
import App from './App'
import router from './router'
import elementui from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(elementui)
new Vue({
el: '#app',
i18n,
router,
components: { App },
template: '<App/>'
})
整体大框架已经弄完了,剩下的工作是将页面所有的内容翻译好,然后填充到页面。
vue-i18n 需要的文件是对象格式的,即
const zh = {
hello: '你好',
world: '世界'
}
const en = {
hello: 'hello',
world: 'world'
}
但是维护几个对象是非常繁琐的事情,比如后期要修改某些文字,或者增加删除某些内容,就要去不同的地方修改。
所以我将翻译内容作成一个原数据格式,增删改查都可以很方便的进行,使用的时候利用一段 js 代码将数据转换为 i18n 需要的格式。
{
"version": "1.0.1",
"lang_order": ["option_key", "zh", "en", "ru"],
"desc": "key, 中文,英文,俄文",
"dict": {
"userRole": [
["超级管理员", "超级管理员", "Super administrator", ""],
["普通用户", "普通用户", "Common user", ""]
],
"account": [
["选择日期", "选择日期", "choose dete", ""]
]
}
}
这样每次针对内容进行增删改查就只需要修改这个文件就可以了。在 src 目录下新建一个 commonresouce 文件夹,然后将上面的 json
文件命名为 diction.json 保存在 commonresource 中。
然后在 commonresource 的同级新建 lang 文件夹,里面创建一个 index.js 的文件。接着开始编辑:
import diction from '../commonresouce/diction.json'
let {dict, lang_order} = diction
let output_dicts = {}
for (let lang in lang_order) {
if (lang == 0) continue
let dd = {}
for (let key in dict){
let d = {}
dict[key].forEach(item=>{
d[item[0]] = item[lang]
})
dd[key] = d
}
output_dicts[lang_order[lang]] = dd
}
export default output_dicts
这样翻译的内容就准备好了,并且我们前面已经在 i18n.js 中引入了。接下来写一点页面,编辑 components 文件夹下的 HelloWorld.vue
<template>
<div>
<h3>{{user}}</h3>
<button @click="toEn">EN</button>
<button @click="toZh">ZH</button>
<el-date-picker
v-model="value"
type="date"
:placeholder="$t('account.选择日期')">
</el-date-picker>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
value: ''
}
},
computed:{
user(){
return this.$t('userRole.超级管理员')
},
},
methods:{
toEn(){
this.$i18n.locale = 'en'
},
toZh(){
this.$i18n.locale = 'zh'
}
}
}
</script>
由于我们默认设置的中文,所以打开页面看到的是中文
点击 EN 切换语言,可以看到内容都变成了英文
可以把 this.$i18n.locale 的值存储在 store 和 cookie 中,这样全局也可以访问,并且页面刷新的时候也不会有问题。
一些小问题
有些惰性的组件,在语言切换的时候不会随着 i18n.locale 的值变化而变化,比如一些 echarts 的图表,虽然语言环境
了,但是!!!echarts 不重新渲染,就无法使内容改变。
这里有几种办法可以选择:
1. 利用 watch 监听语言环境,当变化的时候手动调用 echarts 重新渲染
import store from 'store'
export default {
computed: {
lang(){ return store,getters.lang }
},
watch:{
lang(n, o){
myCharts.resize()
}
}
}
2. 利用 computed 属性,有些内容(如下拉列表里的值)可以放到 computed 计算属性中,这样也能解决问题
4. 通过 vue 的 this.reload ,在语言变化的时候直接刷新页面。