# 多语言翻译方案
- 如果需要本地进行多语言翻译, 可以使用这个方法进行多语言初始化配置
# 测试用例
import { intlUtil } from "./intl.util";
const commonLangConfig = {
ok: {
zh_CN: "确定",
en_US: "ok"
},
cancel: {
zh_CN: "取消",
en_US: "cancel"
}
};
describe("intl util", () => {
test("代理多语言配置", () => {
const commonLang = intlUtil.proxy(commonLangConfig);
expect(commonLang.ok("zh_CN")).toBe("确定");
});
test("获取多语言配置项", () => {
const commonLang = intlUtil.proxy(commonLangConfig);
expect(commonLang.ok()).toEqual(commonLangConfig.ok);
});
test("继承配置", () => {
const commonLang = intlUtil.proxy(commonLangConfig);
const pageLevelLang = intlUtil.proxy({
ok: commonLang.ok,
specialContent: {
zh_CN: "特殊内容",
en_US: "special content"
}
});
expect(pageLevelLang.ok("zh_CN")).toBe("确定");
});
test("配置嵌套", () => {
const nestedLang = intlUtil.proxy({
footer: {
zh_CN: "底部",
en_US: "footer"
left: {
zh_CN: "页底左",
en_US: "footer left"
}
}
});
expect(function() {
nestedLang.footer("zh_CN");
}).toThrowError(new Error("无此多语言配置:footer"));
expect(nestedLang.footer("en_US")).toBe("footer");
expect(nestedLang.footer.left("zh_CN")).toBe("页底左");
});
test("支持变量", () => {
const includeVarLang = intlUtil.proxy({
welcome: {
zh_CN: "你好 {name} 欢迎你来到{address}",
en_US: "Hi, Welcome to {address}, {name}"
},
fake: {
zh_CN: "你好 {{name}} 欢迎你来到{{address}}",
en_US: "Hi, Welcome to {{address}}, {{name}}"
}
});
expect(
includeVarLang.welcome("zh_CN", {
name: "小明",
address: "中国"
})
).toBe("你好 {name} 欢迎你来到{address}");
expect(
includeVarLang.fake("zh_CN", {
name: "小明",
address: "中国"
})
).toBe("你好 小明 欢迎你来到中国");
});
});
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 实现代码
使用了 es6 里的 Proxy 的特性去实现
# 功能点
- 支持多语言
- 支持继承
- 支持嵌套, 支持链式调用
- 支持模板字符串, 传入变量进行替换
import _ from "lodash";
const handler = {
set: function(obj, prop, value) {
if (_.isFunction(obj[prop])) {
Object.keys(value).forEach(valueKey => {
obj[prop][valueKey] = value[valueKey];
});
} else {
obj[prop] = value;
}
return true;
},
get: function(target, propKey) {
if (_.isFunction(target[propKey])) {
return target[propKey];
}
return target[propKey];
}
};
const intlUtil = {
/**
* 代理多语言配置
* @param {object} langs
*/
proxy(langs) {
if (!_.isPlainObject(langs)) {
throw new Error("params of lang must be object");
}
const langProxy = new Proxy({}, handler);
Object.keys(langs).forEach(langKey => {
let langValue = langs[langKey];
if (_.isFunction(langValue)) {
langValue = langValue();
}
if (_.isPlainObject(langValue)) {
// if (_.has(langValue, 'zh_CN') && _.has(langValue, 'en_US')) {
// 判断如果有zh_CN, en_US 表示符合规范
langProxy[langKey] = (language, params) => {
if (language) {
if (!_.isString(language)) {
throw new Error("params of language must be string");
}
if (langValue[language]) {
if (_.isPlainObject(params)) {
return templateTranslate(langValue[language], params);
}
return langValue[language];
} else {
throw new Error("无此多语言配置:" + langKey);
}
}
return langValue;
};
const copyLangValue = _.cloneDeep(langValue);
delete copyLangValue.zh_CN;
delete copyLangValue.en_US;
if (Object.keys(copyLangValue).length > 0) {
const childFuncObj = this.proxy(copyLangValue);
langProxy[langKey] = childFuncObj;
}
} else {
throw new Error(
"The first parameter of proxy is not in the correct format, expect function or object"
);
}
});
return langProxy;
}
};
/**
* 模板转换
* @param {string} template 带有 {param}格式的字符串 就是需要转换的模板
* @param {object} params 替换模板的参数
*/
function templateTranslate(template, params) {
const reg = /\{\{(.*?)\}\}/g;
const paramsList = template.match(reg);
if (paramsList) {
// eslint-disable-next-line no-useless-escape
const paramsKeyList = paramsList.map(v => v.replace(/[\{, \}]/g, ""));
if (Array.isArray(paramsKeyList)) {
paramsKeyList.forEach((paramsKey, paramsIndex) => {
if (_.has(params, paramsKey)) {
template = template.replace(
paramsList[paramsIndex],
params[paramsKey]
);
}
});
}
}
return template;
}
export { intlUtil };
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116