公司后台管理系统需要使用多语言版本,本次记录使用i18n实现多语言切换的流程步骤:
1、安装工具包
npm install vue-i18n
2、在项目src目录下新建lang文件夹,目录结构如下:
-lang|----index.js // 脚本文件|----en.js // 我们自己的英文包|----zh.js // 我们自己的中文包
element-ui本身有自己的语言包,我们需要先引入。我这里引入了js-cookie工具包来读写cookie,从cookie中看有没有设置中英文标识,没有,就获取浏览器的语言信息来确定中英文标识。
上面indexjs文件内容:
// lang/index.jsimport Vue from 'vue'import VueI18n from 'vue-i18n'import Cookies from 'js-cookie'import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui langimport elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui langimport enLocale from './en'import zhLocale from './zh'Vue.use(VueI18n)const messages = {en: {...enLocale,...elementEnLocale},zh: {...zhLocale,...elementZhLocale}}export function getLanguage() {const chooseLanguage = Cookies.get('language')if (chooseLanguage) return chooseLanguage// if has not choose languageconst language = (navigator.language || navigator.browserLanguage).toLowerCase()const locales = Object.keys(messages)for (const locale of locales) {if (language.indexOf(locale) > -1) {return locale}}return 'zh'}const i18n = new VueI18n({// set locale// options: en | zh | eslocale: getLanguage(),// set locale messagesmessages})export default i18n
zh.js中文包,我是按页面分的,页面下的标识符对应中英文翻译。到时候在页面中使用标识符就可以了。
// lang/zh.jsexport default {navbar: {dashboard: '首页',logOut: '退出登录',profile: '个人中心',theme: '换肤',size: '布局大小'},login: {title: '系统登录',logIn: '登录',usernameTips: '请输入用户名',passwordTips: '请输入密码',remeberPsd: '记住密码',forgotPsd: '忘记密码?',freeRegister: '免费注册',usernameCheckedTips: '请输入用户名',passwordCheckedTips: '请输入密码',codeCheckedTips: '请输入验证码'}}
对应的en.js英文包
// lang/en.jsexport default {navbar: {dashboard: 'Home',logOut: 'Logout',profile: 'Personal Center',theme: 'Change Theme',size: 'Layout Size'},login: {title: 'xxx',logIn: 'xxx',usernameTips: 'xxx',passwordTips: 'xxx',remeberPsd: 'xxx',forgotPsd: 'xxx?',freeRegister: 'xxx',usernameCheckedTips: 'xxx',passwordCheckedTips: 'xxx',codeCheckedTips: 'xxx'}}
3、在项目的main.js文件中引入多语言国际化
// main.jsimport Vue from 'vue'import App from './App'import store from './store'import router from './router'// 引入element-ui框架import ElementUI from 'element-ui'import 'element-ui/lib/theme-chalk/index.css'Vue.use(ElementUI, {i18n: (key, value) => i18n.t(key, value)})import i18n from './lang' // 语言国际化方案new Vue({el: '#app',router,store,i18n, // 挂载i18nrender: h => h(App)})
element-ui需要按照官方说的配置多语言方案。再引入我们自己的i8n配置, 最好挂载到根vue实例上。
4、(可选)在vuex和cookie中保存选择语言的标识
我的vuex目录文件夹为store
store|---modules|---app.js|---getters.js|---index.js
app.js文件内容为
// store/modules/app.jsimport Cookies from 'js-cookie'import { getLanguage } from '@/lang/index'const state = {language: getLanguage()}const mutations = {SET_LANGUAGE: (state, language) => {state.language = languageCookies.set('language', language)}}const actions = {setLanguage({ commit }, language) {commit('SET_LANGUAGE', language)}}export default {namespaced: true,state,mutations,actions}
getters.js内容为
const getters = {language: state => state.app.language}export default getters
index.js内容
// store/index.jsimport Vue from 'vue'import Vuex from 'vuex'import getters from './getters'import app from './modules/app'Vue.use(Vuex)const store = new Vuex.Store({modules: {app},getters})export default store
一样的,最后在main.js引入store并且挂载到vue根实例。
5、在页面中使用
例如, 我在login.vue文件中使用多语言
原来的是这样的
<div class="login-title"><span>登录</span></div>
替换为
<div class="login-title"><span>{{ $t('login.title') }}</span></div>
$t(' ')
来获取i8n,属性上使用需要属性绑定,script中使用需要this.$t('')
,加this来获取。
在中英文切换按钮上绑定一个切换中英文的方法
<div ><span @click="handleSetLanguage('zh')">简体中文</span><span>|</span><span @click="handleSetLanguage('en')">English</span></div>// 中间省略 handleSetLanguage(lang) {this.$i18n.locale = langthis.$store.dispatch('app/setLanguage', lang)this.reload() // fix语言切换后,element-ui弹窗提示文字不能切换,必须强制刷新页面才能解决的bug},
备注:this.reload()是我为了修复element-ui,输入框错误提示文字,不会随着切换语言而自动切换的bug,添加了一个强制刷新当前页面的全局方法,使用了vue的provide/reject方式,有需要的可以自己百度。
6、附加需求,我的请求接口也需要传递中英文切换后的语言代码给后台,返回对应的语言版本的后台数据。
所有我的请求头需要配置多语言支持。
可以在axios请求拦截器中统一设置,其他代码略。
service.interceptors.request.use(config => {// 请求发送前的设置config.headers['lan'] = store.getters.languagereturn config},error => {console.log(error) // for debugreturn Promise.reject(error)})
7、路由菜单导航面包屑的i18n国际化
我的菜单名称是根据路由中的meta中的title字段来显示的,譬如我的路由定义:
// 首页{path: '/',component: Layout,redirect: '/home',children: [{path: 'home',name: 'Home',component: () => import('@/views/home/index'),meta: { title: 'Home', icon: 'home', affix: true }}]},
并且我的导航菜单,有一部分是定义在本地的,有一部分是异步从服务器获取的。
so,需要一个定义一个转换函数:
// 路由与面包屑导航栏国际化工具函数export function generateTitle(title) {const hasKey = this.$te('route.' + title)if (hasKey) {const translatedTitle = this.$t('route.' + title)return translatedTitle}return title}
$te
和$t
一样,是i18n定义的函数,测试参数是否在语言包中定义,返回布尔值。文章末尾参考连接中讲i8n源码的文章有提到这些函数,可以参考。
然后在导航菜单的组件内引入使用:
// menu.vue<template> <span>{{ generateTitle(item.meta.title) }}</span> // 使用函数</template><script>import { generateTitle } from '@/utils/i18n' //引入函数methods: {generateTitle, // 这里需要声明一下。其他函数...}</script>
最后附上两个参考文字地址:
1、https://blog.csdn.net/DOCALLEN/article/details/78408137
2、https://blog.csdn.net/wxl1555/article/details/85112530
3、vue中如何使用i18n实现国际化:https://segmentfault.com/a/1190000016445415
4、前端国际化之Vue-i18n源码分析,提到了$te等其他i18n全局方法。