需求提的比较着急,匆忙看了一些相关文章就开始上手,踩了些坑,不过好歹是完成了。

前提

一般来说,语言环境存储在本地还是服务器上是个值得根据产品来思考的事情。

最开始,我是把用户设置的语言存储在 cookies 和 localstorage 中,当用户刷新的时候,可以保持当前的语言不变。

出现的问题是当用户手动清除了浏览器的缓存,那么语言就会设置为初始值,不过经过产品的讨论,认为这样是可以接受的。

因为后端有导出和生成文件的一些操作,所以每次用户点击导出或生成,将当前语言携带过去就可以了。

elementUI 国际化

elementui 自身携带了国际化,所以我们要做的就是让他和 vue-i18n 兼容,关于这一点,elementUI 的官方文档上写的非常清楚。这里
附上地址 :

https://element.eleme.cn/#/zh-CN/component/i18n

关于兼容 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>
由于我们默认设置的中文,所以打开页面看到的是中文

elemntuiplus国际化 elementui国际化_App

点击 EN 切换语言,可以看到内容都变成了英文

elemntuiplus国际化 elementui国际化_App_02

可以把 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 ,在语言变化的时候直接刷新页面。