需求
项目为多页应用,包含产品a、b、c、d、e,每个产品都有自己的翻译文件。
一次加载所有翻译文件是极度不合理的。于是考虑动态加载。
实现
参考官方文档:延迟加载翻译
项目结构
│
├── dist // 静态资源输出目录
│
├── src
│ ├── assets
│ ├── components
│ ├── lang // 语言翻译文件
│ ├── a
│ ├── en_US.js
│ └── zh_CN.js
│ ├── b
│ ├── en_US.js
│ └── zh_CN.js
│ ├── c
│ ├── en_US.js
│ └── zh_CN.js
│ ├── d
│ ├── en_US.js
│ └── zh_CN.js
│ ├── e
│ ├── en_US.js
│ └── zh_CN.js
│ ├── pages
│ ├── a
│ ├── b
│ ├── c
│ ├── d
│ ├── e
│ ├── utils
│ ├── i18n.js
│ ├── ...
i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import ElementLocale from 'element-ui/lib/locale'
import enLocale from 'element-ui/lib/locale/lang/en'
import zhLocale from 'element-ui/lib/locale/lang/zh-CN'
// LANG:全局变量,从cookie中获取的当前语言版本,'zh_CN'、'en_US'
// IS_INTL:全局变量,是否为国际版
import { LANG, IS_INTL } from '@/constant'
Vue.use(VueI18n)
const i18n = new VueI18n({
silentTranslationWarn: true
})
// 这里需要覆盖Element本地化函数,不然会冲突
ElementLocale.i18n((key, value) => i18n.t(key, value))
export default i18n
/**
* 更改vueI18n实例
* @param lang 'zh_CN'、'en_US'
*/
function setI18nLang (lang) {
i18n.locale = lang
// axios.defaults.headers.common['Accept-Language'] = lang
document.querySelector('html').setAttribute('lang', lang)
return lang
}
/**
* 动态加载语言
* @param path 当前路径(对应lang下文件夹名)
*/
const _LANGS = ['zh_CN', 'en_US']
const ELEMENT_LANG = {
zh_CN: zhLocale,
en_US: enLocale
}
let loadedLanguages = []
export function loadLanguageAsync (path) {
// lang目前是从cookie中获取,所以没有作为参数传递,此处lang也可作为变量传递
// 如果cookie中没有获取到语言项,国际版默认初始化为英文
const lang = LANG || (IS_INTL ? 'en_US' : 'zh_CN')
if (!path || !_LANGS.includes(lang)) return
if (i18n.locale !== lang) {
if (!loadedLanguages.includes(lang)) {
// 文件大时可拆分打包,目前项目中翻译文件均为4、5K左右,就没拆
// return import(/* webpackChunkName: "lang-[request]" */ `@/lang/${path}/${lang}`).then(msgs => {
return import(`@/lang/${path}/${lang}`).then(msgs => {
const _temp = Object.assign(msgs.default, ELEMENT_LANG[lang])
i18n.setLocaleMessage(lang, _temp)
loadedLanguages.push(lang)
return setI18nLang(lang)
})
}
return Promise.resolve(setI18nLang(lang))
}
return Promise.resolve(lang)
}
main.js
import Vue from 'vue'
import App from './label.vue'
import store from './store/index'
import router from './router/index'
import i18n, { loadLanguageAsync } from '@/utils/i18n'
import '@label/plugins/element-ui'
import '@/assets/styles/common.less'
import AppComponents from '@label/components/index' // 注册全局组件
Vue.config.productionTip = false
Vue.use(AppComponents)
// a页
loadLanguageAsync('a').then(_ => {
new Vue({
i18n,
store,
router,
render: h => h(App)
}).$mount('#app')
})
切换语言组件
主要操作:切换时setCookie后重刷页面
原因:本来直接调用loadLanguageAsync是可以正常重刷语言包的,但是这里由于页面某些显示内容是来源于后端接口的,还是得重新请求,所以重刷了整页
setCookie('jd.erp.lang', lang || 'en_US', 1, { path: '/', domain: CUR_HOST_SUFFIX })
window.history.go(0)
组件内容如下:
// langs.vue
<template>
<el-dropdown
class="icon-info icon-langs"
@command="changeLang"
>
<img :src="imgSrc">
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in langs"
:key="item.value"
:command="item.value"
:disabled="item.value === locale"
>
{{ item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
import { LANG, CUR_HOST_SUFFIX } from '@/constant'
import { setCookie } from '@/utils/utils'
export default {
name: 'langs',
data () {
return {
imgSrc: require('@label/assets/icons/header-langs.svg'),
locale: LANG,
langs: [
{ label: '中文', value: 'zh_CN' },
{ label: 'English', value: 'en_US' }
]
}
},
methods: {
changeLang (lang) {
this.locale = lang
setCookie('jd.erp.lang', lang || 'en_US', 1, { path: '/', domain: CUR_HOST_SUFFIX })
window.history.go(0)
}
}
}
</script>