缘起 前段时间测试对于项目切换中英文后页面会闪一下标为bug,想了想肯定是前任开发者在切换中英文后对页面进行了强制刷新。查看源码发现果不其然,并且前任仅将中英文状态存储在cookie中,然后在需要的组件中通过cookie获取中英文状态。发现接口都是同时有返回中英文,这样完全可以通过vuex全局状态管理中英文状态,达到在一处修改了中英文后全局自动修改。
本文以 vue+ElementUI 并且以和vue组合的 vue-i18n 为例
准备阶段 1、安装相关插件
1 2 3 4 5 6 // 安装 vue-i18n npm install --save vue-i18n // 安装 js-cookie npm install --save js-cookie // 安装 vuex npm install --save vuex
2、目录结构
国际化部分 i18n 封装
将i18n的引入与注册实例封装在了./langs/index.js中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import Vue from 'vue' import VueI18n from 'vue-i18n' import Cookies from 'js-cookie' import elementEnLocale from 'element-ui/lib/locale/lang/en' import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' import 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 language const language = (navigator.language || navigator.browserLanguage).toLowerCase() const locales = Object.keys(messages) for (const locale of locales) { if (language.indexOf(locale) > -1) { return locale } } return 'en' } const i18n = new VueI18n({ locale: getLanguage(), // set locale messages messages }) export default i18n
语言配置样例
en.js
1 2 3 4 5 6 7 8 9 export default { settings: { title: 'Page style setting', theme: 'Theme Color', tagsView: 'Open Tags-View', fixedHeader: 'Fixed Header', sidebarLogo: 'Sidebar Logo' } }
zh.js
1 2 3 4 5 6 7 8 9 export default { settings: { title: '系统布局配置', theme: '主题色', tagsView: '开启 Tags-View', fixedHeader: '固定 Header', sidebarLogo: '侧边栏 Logo' } }
vuex
通过vuex实现国际化状态切换状态管理功能
index
./store/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import Vue from 'vue' import Vuex from 'vuex' import getters from './getters' // 使用vuex Vue.use(Vuex) // 这种方式很好的将modules中的所有文件全部导出,这样以后修改modules不用再在此处进行添加导出 const modulesFiles = require.context('./modules', true, /\.js$/) const modules = modulesFiles.keys().reduce((modules, modulePath) => { const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') const value = modulesFiles(modulePath) modules[moduleName] = value.default return modules }, {}) // 创建vuex实例 const store = new Vuex.Store({ modules, getters }) export default store
getters
./store/getters.js
1 2 3 4 5 6 // 监听 vuex 中state下language的改变 // 外部通过 this.$store.getters.language 调用 const getters = { language: state => state.app.language, } export default getters
app.js
./store/modules/app.js 单独建立一个app.js的目的是以后如果需要扩展其他的全局状态,可以封装在其他独立的js中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // 获取当前国际化状态封装在了上面的./langs/index.js中,相当于是初始化国际化 import { getLanguage } from '@/i18n/langs/index' import Cookies from 'js-cookie' // 数据,外部可以通过 this.$store.state.language 调用 const state = { language: getLanguage() } // 外部可以通过提交mutation来修改state中的值 // this.$store.commit("SET_LANGUAGE") const mutations = { SET_LANGUAGE: (state, language) => { // 修改state并将其保存在Cookies中,这样用户下次打开仍然是上次选择的国际化状态 state.language = language Cookies.set('language', language) }, } // 官方推荐我们去提交一个actions,在actions中提交mutation再去修改state // this.$store.dispatch("setLanguage") const actions = { setLanguage({ commit }, language) { commit('SET_LANGUAGE', language) }, } export default { namespaced: true, state, mutations, actions }
main
main.js配置导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' // 导入封装的i18n配置 import i18n from './i18n/langs'; import Cookies from 'js-cookie' import store from './store' // 应用 Vue.use(ElementUI, { i18n: (key, value) => i18n.t(key, value) }) // 将i18n、store注入到vue实例中 new Vue({ el: '#app', router, i18n, store, render: h => h(App) })
应用 1、切换语言,向vuex的actions提交改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <template> <el-dropdown trigger="click" class="international" @command="handleSetLanguage"> <div> <svg-icon class-name="international-icon" icon-class="language" /> </div> <el-dropdown-menu slot="dropdown"> <el-dropdown-item :disabled="language==='zh'" command="zh"> 中文 </el-dropdown-item> <el-dropdown-item :disabled="language==='en'" command="en"> English </el-dropdown-item> </el-dropdown-menu> </el-dropdown> </template> <script> export default { computed: { language() { return this.$store.getters.language } }, methods: { handleSetLanguage(lang) { // 设置i18n,以便后面通过$t('settings.title')使用 this.$i18n.locale = lang // 向vuex提交修改后的国际化,以便后面获取 this.$store.dispatch('app/setLanguage', lang) this.$message({ message: 'Switch Language Success', type: 'success' }) } } } </script>
2、在需要的组件中使用与获取国际化状态
1 2 3 4 5 6 7 8 9 10 11 12 // html中使用 {{ $t('settings.title') }} // js中使用 $t('settings.title') // 通过computed获取vuex中的language状态,这样其他地方修改后这边可以监测到,并同步修改DOM中的值 computed: { language() { return this.$store.getters.language } },