需求背景
实现多语言切换,借助 vue-i18n 动态加载模块实现。但是前端过多语言文件或者与后端翻译保持不一致,开发效率低,于是约定共用一套语言文件并开放接口。后端实现多语言,前端只需要获取即可,不需要区分那种语言。
方案
方案 1
不需要后端接口数据实现多语言,可以使用 vue-i18n 实现需求。
方案 2
借助后端实现多语言,使用 vue-i18n, 路由拦截器去获取接口语言数据,然后更新语言文件,注意去重。此次只要针对此方案做详解。
方案 3
不使用 vue-i18n, 直接把接口数据保存在 localStorage / store 全局状态里,但是需要在每个组件再次赋值给组件 data,才能渲染到 template。
方案 1
如果不需要后端接口数据实现多语言,可以使用 vue-i18n 实现需求。如果有很多多语言文件,可以参考方案 2 中的动态加载。
main.js
// 准备翻译的语言环境信息
const messages = {
en: {
message: {
hello: 'hello world'
}
},
ja: {
message: {
hello: 'こんにちは、世界'
}
}
}
// 通过选项创建 VueI18n 实例
const i18n = new VueI18n({
locale: 'ja', // 设置地区
messages, // 设置地区信息
})
// 通过 `i18n` 选项创建 Vue 实例
new Vue({ i18n }).$mount('#app')
Index.vue
<div id="app">
<p>{{ $t("message.hello") }}</p>
</div>
方案 2
借助后端实现多语言,使用 vue-i18n, 路由拦截器去获取接口语言数据,然后更新语言文件,注意去重。
route.js // 路由文件
export default {
{
path: '/demo',
component: BasicLayout,
meta: {
title: 'Demo'
},
children: [
{
path: 'index',
name: 'demo-index',
meta: {
title: 'Home',
// 标知符,代表访问该路由需要加载这个模块的多语言接口数据
requiresLang: 'demo'
},
component: () => import('@/views/demo/Index.vue')
}
]
},
}
index.js // 路由入口文件
// 在路由拦截器处理
router.beforeEach((to, from, next) => {
// 获取当前选中的语言项
const lang = store.getters['user/lang'];
if (to.matched.some(record => record.meta.requiresLang)) {
// handler
loadLanguageAsync(lang, to.meta.requiresLang)
.then(() => next())
.catch(() => {
alert('Load multi-language fail, Please try to refresh or report to admin!');
});
} else {
next();
}
});
/lang/index.js 语言入口文件
import en from './en.json';
const DEFAULT_LANG = 'en';
const messages = {
en
};
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: DEFAULT_LANG,
messages,
fallbackLocale: DEFAULT_LANG
});
export default i18n;
function setI18nLanguage(lang) {
i18n.locale = lang;
return lang;
}
// 传入当前选中的语言项和需要加载多语言的模块
export function loadLanguageAsync(lang, group) {
// 优化,去重
if (!i18n.getLocaleMessage(lang)[group]) {
const params = {
language: lang,
group_keys: group
};
// 发起请求
return languageApi.getGroupLanguage(params).then((data) => {
// 处理数据,重要步骤是 getLocaleMessage, setLocaleMessage,set locale。这里不建议直接用 mergeLocaleMessage, 有些情况不起效果。
const originMessages = i18n.getLocaleMessage(lang);
i18n.setLocaleMessage(lang, { ...originMessages, ...toSnakeCase(data) });
setI18nLanguage(lang);
});
}
return Promise.resolve();
}
注意:如果不借助后端实现多语言,则需要在前端创建多个语言文件,可以使用动态加载多语言文件实现优化。代码如下:
const loadedLanguages = [DEFAULT_LANG]
function setI18nLanguage(lang) {
i18n.locale = lang;
return lang;
}
export function loadLanguageAsync(lang, group) {
// 动态加载多语言模块
if (i18n.locale !== lang) {
if (!loadedLanguages.includes(lang)) {
import(/* webpackChunkName: "lang-[request]" */ `@/lang/${lang}`).then(msgs => {
i18n.setLocaleMessage(lang, msgs)
loadedLanguages.push(lang)
setI18nLanguage(lang)
})
}
}
return Promise.resolve();
}
心得
小小心得分享,有更加好的方案欢迎分享喔~