给Vue项目添加i18n支持(一)中我们介绍了如何给Vue项目添加国际化支持,但是在真实的项目中,将所有翻译写在一个文件中通常会带来一些问题,比如容易引起代码冲突,也不方便维护。

我们期望的i18n配置大概长这样,

1
2
3
4
5
6
7
8
|--src/
| |--locales/
| | |--index.js
| | |--app.js
| | |--common.js
| | |--module/
| | | |--sys-user.js
| | | |--sys-role.js

app.js用来存放与整个应用相关的一些翻译,比如应用标题,slogan等等。

common.js用来存放公共翻译。

module下则是各个模块单独的翻译。

各个模块的翻译配置可能是多层级的,例如公共翻译:

1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
dialog: {
delete: {
title: { en: "Delete", zhcn: "删除" },
message: {
en: "Deleted items cannot be retrieved, do you want to continue?",
zhcn: "删除的条目将无法找回,是否继续?"
},
yes: { en: "Delete", zhcn: "删除" },
no: { en: "Cancel", zhcn: "取消" }
}
}
};

接下来我们来实现它。

locales

locales目录下用来存放所有翻译配置,它最终导出的数据应该是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
_: {
dialog: {
delete: {
message: { en: "", zhcn: ""}
}
}
},
app: {
name: { en: "", zhcn: "" }
},
user: {
username: { en: "", zhcn: "" }
}
}

像这个示例中的一样。

.env

在.env中定义语言列表

1
VUE_APP_LANGS=en,zhcn

vue-i18n

我们需要在引入vue-i18n的地方将上面的数据结构进行转换,转换的结果符合vue-i18n的预期。

i18n.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
import Vue from "vue";
import VueI18n from "vue-i18n";
import i18nConf from "@/locales";

Vue.use(VueI18n);

const langs = process.env.VUE_APP_LANGS.split(",");

function load(conf, lang, result) {
for (let k in conf) {
if (
langs.every(item => Object.prototype.hasOwnProperty.call(conf[k], item))
) {
result[k] = conf[k][lang];
} else {
result[k] = {};
load(conf[k], lang, result[k]);
}
}
}

function loadLocaleMessages() {
const messages = {};
langs.forEach(lang => {
messages[lang] = {};
load(i18nConf, lang, messages[lang]);
});
return messages;
}

export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || "en",
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en",
messages: loadLocaleMessages()
});

main.js

引入就好了

1
2
3
4
5
6
7
8
import i18n from "./i18n";

new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount("#app");