vue-i18n-extract-plugin 1.0.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +8 -0
- package/LICENSE +20 -0
- package/README.md +292 -0
- package/lib/babel-plugin-i18n.js +13 -0
- package/lib/babel-plugin-import-i18n.js +154 -0
- package/lib/cli.js +54 -0
- package/lib/extract.js +564 -0
- package/lib/import-i18n-transform.js +146 -0
- package/lib/index.js +74 -0
- package/lib/options.js +39 -0
- package/lib/translate.js +308 -0
- package/lib/translators/baidu.js +91 -0
- package/lib/translators/google.js +68 -0
- package/lib/translators/index.js +15 -0
- package/lib/translators/scan.js +24 -0
- package/lib/translators/translator/IntervalQueue.js +60 -0
- package/lib/translators/translator/Translator.js +62 -0
- package/lib/translators/translator/index.js +5 -0
- package/lib/translators/volcengine.js +131 -0
- package/lib/translators/youdao.js +89 -0
- package/lib/utils.js +234 -0
- package/lib/visitors.js +246 -0
- package/lib/vite-plugin-i18n.js +73 -0
- package/lib/vite-plugin-import-i18n.js +46 -0
- package/lib/vue-i18n-loader.js +54 -0
- package/lib/webpack-import-i18n-loader.js +69 -0
- package/lib/webpack-plugin-i18n.js +176 -0
- package/package.json +47 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const { IntervalQueue } = require("./IntervalQueue");
|
|
2
|
+
|
|
3
|
+
class Translator {
|
|
4
|
+
option = {};
|
|
5
|
+
|
|
6
|
+
constructor(option) {
|
|
7
|
+
this.option = this.getResultOption(option);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
defaultErrorHandler = error => {
|
|
11
|
+
const name = this.option.name;
|
|
12
|
+
console.error(error);
|
|
13
|
+
console.error(
|
|
14
|
+
`翻译api${name ? `【${name}】` : ""}请求异常:${this.getErrorMessage(error)}`
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
getResultOption(option) {
|
|
19
|
+
const resultOption = {
|
|
20
|
+
version: 1,
|
|
21
|
+
maxChunkSize: 4500, // 目前默认是4500
|
|
22
|
+
interval: 0,
|
|
23
|
+
onError: this.defaultErrorHandler,
|
|
24
|
+
...option
|
|
25
|
+
};
|
|
26
|
+
if (resultOption.interval) {
|
|
27
|
+
const getIntervalFn = (fn, delay) => {
|
|
28
|
+
const queue = new IntervalQueue(fn.bind(null), delay);
|
|
29
|
+
return (...args) => {
|
|
30
|
+
return queue.execute(...args);
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
resultOption.fetchMethod = getIntervalFn(
|
|
34
|
+
resultOption.fetchMethod,
|
|
35
|
+
resultOption.interval
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return resultOption;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getErrorMessage(error) {
|
|
42
|
+
if (error instanceof Error) {
|
|
43
|
+
return error.message;
|
|
44
|
+
} else {
|
|
45
|
+
return String(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async translate(text, fromKey, toKey, separator) {
|
|
50
|
+
let result = "";
|
|
51
|
+
try {
|
|
52
|
+
result = await this.option.fetchMethod(text, fromKey, toKey, separator);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
this.option.onError(error, this.defaultErrorHandler);
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
Translator
|
|
62
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// 代码灵感来自https://github.com/dadidi9900/auto-plugins-json-translate/blob/main/src/services/translationService.ts
|
|
2
|
+
const axios = require("axios");
|
|
3
|
+
const { generateId } = require("../utils");
|
|
4
|
+
const { Translator } = require("./translator");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 火山引擎翻译器,内置豆包、deepseek等模型
|
|
8
|
+
*
|
|
9
|
+
* 火山引擎大模型介绍:https://www.volcengine.com/docs/82379/1099455
|
|
10
|
+
*
|
|
11
|
+
* api文档:https://www.volcengine.com/docs/82379/1298454
|
|
12
|
+
*
|
|
13
|
+
* 使用方式:
|
|
14
|
+
* ```ts
|
|
15
|
+
* vitePluginI18n({
|
|
16
|
+
...
|
|
17
|
+
translator: new VolcEngineTranslator({
|
|
18
|
+
apiKey: '你申请的apiKey',
|
|
19
|
+
model: '你要调用的模型,如:`doubao-1-5-pro-32k-250115`,请确保使用前已在控制台开通了对应模型'
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
class VolcEngineTranslator extends Translator {
|
|
25
|
+
constructor(option = {}) {
|
|
26
|
+
super({
|
|
27
|
+
name: "火山引擎ai翻译",
|
|
28
|
+
fetchMethod: async (text, fromKey, toKey, separator) => {
|
|
29
|
+
let salt = new Date().getTime();
|
|
30
|
+
const textArr = text.split(separator);
|
|
31
|
+
const sourceMap = Object.fromEntries(
|
|
32
|
+
textArr.map(text => [generateId(text), text])
|
|
33
|
+
);
|
|
34
|
+
const data = {
|
|
35
|
+
model: option.model,
|
|
36
|
+
messages: [
|
|
37
|
+
{
|
|
38
|
+
role: "system",
|
|
39
|
+
content: `
|
|
40
|
+
###
|
|
41
|
+
假如你是一个专业的翻译助手,你将根据一个${option.desc ? option.desc + "的" : ""}web项目中使用的文本组成的JSON对象,来解决将数组每个成员从源语言A翻译成目标语言B并返回翻译后的JSON对象的任务。根据以下规则一步步执行:
|
|
42
|
+
1. 明确源语言A和目标语言B。
|
|
43
|
+
2. 对JSON对象中数组的每个成员进行从源语言A到目标语言B的翻译。
|
|
44
|
+
3. 将翻译后的内容以JSON对象格式返回。
|
|
45
|
+
|
|
46
|
+
参考例子:
|
|
47
|
+
示例1:
|
|
48
|
+
输入:zh-cn -> en { "awfgx": "你好", "qwfga": "世界" }
|
|
49
|
+
输出:{ "awfgx": "Hello", "qwfga": "World" }
|
|
50
|
+
说明:输出的英文句子如果较短,则每个单词的首字母大写,如果是长句子则保持原样。
|
|
51
|
+
示例: "查看详情" 翻译为 "View Details","优惠券发放时间" 翻译为 "Coupon Award Time"。
|
|
52
|
+
建议:句子单词数不超过3个时每个单词首字母大写,超过3个单词时保持原样。
|
|
53
|
+
|
|
54
|
+
示例2:
|
|
55
|
+
输入:de -> fr { "gweaq": "Hallo", "wtrts": "Welt" }
|
|
56
|
+
输出:{ "gweaq": "Bonjour", "wtrts": "Monde" }
|
|
57
|
+
|
|
58
|
+
请回答问题:
|
|
59
|
+
输入:源语言A -> 目标语言B { "wghhj": "XXX" }
|
|
60
|
+
输出:
|
|
61
|
+
|
|
62
|
+
要求:
|
|
63
|
+
1 以JSON对象格式输出
|
|
64
|
+
2 JSON对象中每个成员为翻译后的内容
|
|
65
|
+
3 翻译后的内容尽可能本土化、精准、自然、不丢失原意
|
|
66
|
+
4 保持JSON对象的键不变
|
|
67
|
+
5 如果无法翻译,请返回原内容
|
|
68
|
+
###
|
|
69
|
+
`
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
role: "user",
|
|
73
|
+
content: `${fromKey} -> ${toKey} ${JSON.stringify(sourceMap)}`
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
const response = await axios.post(
|
|
78
|
+
`https://ark.cn-beijing.volces.com/api/v3/chat/completions?t=${salt}`,
|
|
79
|
+
data,
|
|
80
|
+
{
|
|
81
|
+
headers: {
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
Authorization: `Bearer ${option.apiKey}`
|
|
84
|
+
},
|
|
85
|
+
proxy: option.proxy
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
let resultTextArr = Array.from(textArr).fill("");
|
|
90
|
+
const content = response.data.choices[0].message.content;
|
|
91
|
+
try {
|
|
92
|
+
let resultMap;
|
|
93
|
+
try {
|
|
94
|
+
resultMap = JSON.parse(content);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw new Error("大模型返回文本解析失败");
|
|
97
|
+
}
|
|
98
|
+
if (typeof resultMap !== "object" || !resultMap) {
|
|
99
|
+
throw new Error("大模型返回文本解析后类型不正确");
|
|
100
|
+
}
|
|
101
|
+
const isMiss = Object.keys(resultMap).some(
|
|
102
|
+
key => !(key in sourceMap)
|
|
103
|
+
);
|
|
104
|
+
if (isMiss) {
|
|
105
|
+
throw new Error("大模型返回文本内容不完整");
|
|
106
|
+
}
|
|
107
|
+
resultTextArr = textArr.map(text => resultMap[generateId(text)]); // 用textArr遍历,保证顺序
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const message = error instanceof Error ? error.message : "未知错误";
|
|
110
|
+
console.warn("⚠", message);
|
|
111
|
+
console.warn("⚠ 返回的文本内容:", content);
|
|
112
|
+
console.warn("⚠ 原文本内容:", JSON.stringify(sourceMap));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return resultTextArr.join(separator);
|
|
116
|
+
},
|
|
117
|
+
onError: (error, cb) => {
|
|
118
|
+
cb(error);
|
|
119
|
+
console.error(
|
|
120
|
+
"请确保在火山引擎控制台开通了对应模型,且有足够的token余额。控制台地址:https://console.volcengine.com/ark/"
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
maxChunkSize: 1000, // 太长可能会导致返回文本不完整
|
|
124
|
+
interval: option.interval ?? 1000
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = {
|
|
130
|
+
VolcEngineTranslator
|
|
131
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
const { Translator } = require("./translator");
|
|
3
|
+
const CryptoJS = require("crypto-js");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 有道翻译器
|
|
7
|
+
*
|
|
8
|
+
* api文档:https://ai.youdao.com/DOCSIRMA/html/trans/api/wbfy/index.html
|
|
9
|
+
*
|
|
10
|
+
* 使用方式:
|
|
11
|
+
* ```ts
|
|
12
|
+
* vitePluginI18n({
|
|
13
|
+
...
|
|
14
|
+
translator: new YoudaoTranslator({
|
|
15
|
+
appId: '你申请的appId',
|
|
16
|
+
appKey: '你申请的appKey'
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
class YoudaoTranslator extends Translator {
|
|
22
|
+
/** 有道的语言类型映射不标准,需要手动控制 */
|
|
23
|
+
YOUDAO_TRANSLATE_KEY_CONVERT_MAP = {
|
|
24
|
+
"zh-cn": "zh-CHS",
|
|
25
|
+
"zh-tw": "zh-CHT"
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
truncate(q) {
|
|
29
|
+
// 检查输入字符串的长度
|
|
30
|
+
if (q.length <= 20) {
|
|
31
|
+
// 如果长度小于等于20,直接返回原字符串
|
|
32
|
+
return q;
|
|
33
|
+
} else {
|
|
34
|
+
// 如果长度大于20,截取前10个字符和后10个字符,并在中间插入长度信息
|
|
35
|
+
const len = q.length;
|
|
36
|
+
return q.substring(0, 10) + len + q.substring(len - 10);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getTranslateKey(key) {
|
|
41
|
+
return this.YOUDAO_TRANSLATE_KEY_CONVERT_MAP[key] || key;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
constructor(option = {}) {
|
|
45
|
+
super({
|
|
46
|
+
name: "有道翻译",
|
|
47
|
+
fetchMethod: async (text, fromKey, toKey) => {
|
|
48
|
+
let salt = new Date().getTime();
|
|
49
|
+
let curTime = Math.round(new Date().getTime() / 1000);
|
|
50
|
+
let str =
|
|
51
|
+
option.appId + this.truncate(text) + salt + curTime + option.appKey;
|
|
52
|
+
let sign = CryptoJS.SHA256(str).toString(CryptoJS.enc.Hex);
|
|
53
|
+
const data = {
|
|
54
|
+
q: text,
|
|
55
|
+
appKey: option.appId,
|
|
56
|
+
salt,
|
|
57
|
+
from: this.getTranslateKey(fromKey),
|
|
58
|
+
to: this.getTranslateKey(toKey),
|
|
59
|
+
sign,
|
|
60
|
+
signType: "v3",
|
|
61
|
+
curtime: curTime
|
|
62
|
+
};
|
|
63
|
+
const response = await axios.post(
|
|
64
|
+
"https://openapi.youdao.com/api",
|
|
65
|
+
data,
|
|
66
|
+
{
|
|
67
|
+
headers: {
|
|
68
|
+
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
|
|
69
|
+
},
|
|
70
|
+
proxy: option.proxy
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
// 请求成功,返回响应数据
|
|
74
|
+
return response.data.translation?.[0] || "";
|
|
75
|
+
},
|
|
76
|
+
onError: (error, cb) => {
|
|
77
|
+
cb(error);
|
|
78
|
+
console.error(
|
|
79
|
+
"请前往有道翻译官方申请翻译key,默认会有50的额度,并请检查额度是否充足。"
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
interval: option.interval ?? 1000
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = {
|
|
88
|
+
YoudaoTranslator
|
|
89
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs-extra");
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const types = require("@babel/types");
|
|
5
|
+
|
|
6
|
+
function hashKey(str) {
|
|
7
|
+
return crypto.createHash("sha512").update(str).digest("base64").slice(0, 6);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function generateId(text, length = 6) {
|
|
11
|
+
let hash = 5381; // 初始哈希值(素数基数)
|
|
12
|
+
|
|
13
|
+
// 1. 计算稳定哈希值
|
|
14
|
+
for (let i = 0; i < text.length; i++) {
|
|
15
|
+
hash = (hash * 33) ^ text.charCodeAt(i); // DJB2哈希变种
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 2. 生成6位字母数字组合(Base36编码)
|
|
19
|
+
return Math.abs(hash)
|
|
20
|
+
.toString(36) // 转为36进制(0-9a-z)
|
|
21
|
+
.padStart(length, "0")
|
|
22
|
+
.slice(-length);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseArg(arg) {
|
|
26
|
+
try {
|
|
27
|
+
if (
|
|
28
|
+
arg === "true" ||
|
|
29
|
+
arg === "false" ||
|
|
30
|
+
arg === "null" ||
|
|
31
|
+
arg.startsWith("[") ||
|
|
32
|
+
arg.startsWith("{")
|
|
33
|
+
) {
|
|
34
|
+
return JSON.parse(arg);
|
|
35
|
+
}
|
|
36
|
+
return arg;
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.warn(`解析参数失败: ${arg}`, err);
|
|
39
|
+
// 可能是因为参数不是有效的 JSON 格式,直接返回原始字符串
|
|
40
|
+
return arg;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isEmptyObject(obj) {
|
|
45
|
+
return Object.keys(obj).length === 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function checkAgainstRegexArray(value, regexArray = []) {
|
|
49
|
+
for (let i = 0; i < regexArray.length; i++) {
|
|
50
|
+
const regex =
|
|
51
|
+
typeof regexArray[i] === "string"
|
|
52
|
+
? new RegExp(regexArray[i].replace(/\*/g, ""))
|
|
53
|
+
: regexArray[i];
|
|
54
|
+
if (regex.test(value)) {
|
|
55
|
+
return true; // 如果符合任何一个规则,返回 true
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false; // 如果所有规则都不符合,返回 false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @description: 用于解析抽象语法树中的调用表达式,并提取出调用的名称,如a.b.c() 取 c。
|
|
63
|
+
* @param {any} path
|
|
64
|
+
* @return {*}
|
|
65
|
+
*/
|
|
66
|
+
function extractFunctionName(path) {
|
|
67
|
+
const callPath = path.findParent(p => p.isCallExpression());
|
|
68
|
+
if (!callPath) return "";
|
|
69
|
+
|
|
70
|
+
const callee = callPath.node.callee;
|
|
71
|
+
|
|
72
|
+
let callName = "";
|
|
73
|
+
function callObjName(callObj, name) {
|
|
74
|
+
name = "." + callObj.property.name + name;
|
|
75
|
+
if (types.isMemberExpression(callObj.object)) {
|
|
76
|
+
return callObjName(callObj.object, name);
|
|
77
|
+
}
|
|
78
|
+
return callObj.object.name + name;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (types.isMemberExpression(callee)) {
|
|
82
|
+
callName = callObjName(callee, "");
|
|
83
|
+
} else if (types.isIdentifier(callee)) {
|
|
84
|
+
callName = callee.name;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return callName;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function relativeCWDPath(subPath) {
|
|
91
|
+
const rPath = path.resolve(
|
|
92
|
+
fs.realpathSync(process.cwd()),
|
|
93
|
+
subPath.replace(/^\//, "").replace(/^@\//, "")
|
|
94
|
+
);
|
|
95
|
+
if (path.extname(rPath) !== "") {
|
|
96
|
+
return rPath;
|
|
97
|
+
}
|
|
98
|
+
return rPath.replace(/\/$/, "") + "/";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getLangJsonPath(langKey, option) {
|
|
102
|
+
return (
|
|
103
|
+
relativeCWDPath(option.outputPath) +
|
|
104
|
+
option.customGenLangFileName(langKey) +
|
|
105
|
+
".json"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function readJsonWithDefault(pathStr, defaultValue = {}) {
|
|
110
|
+
try {
|
|
111
|
+
if (!fs.existsSync(pathStr)) {
|
|
112
|
+
return defaultValue;
|
|
113
|
+
}
|
|
114
|
+
return fs.readJSONSync(pathStr) || defaultValue;
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.warn(`读取 JSON 文件失败: ${pathStr}`, err);
|
|
117
|
+
// 如果读取失败,返回默认值
|
|
118
|
+
return defaultValue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function resolveAliasPath(pathStr) {
|
|
123
|
+
if (pathStr.startsWith("@/")) {
|
|
124
|
+
return "src" + pathStr.slice(1);
|
|
125
|
+
}
|
|
126
|
+
return pathStr;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function resolveFilterPath(pathStr) {
|
|
130
|
+
if (/\*/.test(pathStr)) {
|
|
131
|
+
// 如果包含通配符,直接返回原始路径
|
|
132
|
+
return pathStr;
|
|
133
|
+
}
|
|
134
|
+
pathStr = resolveAliasPath(pathStr);
|
|
135
|
+
if (path.extname(pathStr) !== "") {
|
|
136
|
+
return pathStr;
|
|
137
|
+
}
|
|
138
|
+
if (pathStr.endsWith("/")) {
|
|
139
|
+
return pathStr + "**";
|
|
140
|
+
}
|
|
141
|
+
return pathStr + "/**";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function fixFolderPath(pathStr) {
|
|
145
|
+
if (pathStr instanceof RegExp) {
|
|
146
|
+
pathStr = pathStr.source.replace(/\\/g, "").replace(/\/\//, "/");
|
|
147
|
+
}
|
|
148
|
+
pathStr = resolveAliasPath(pathStr);
|
|
149
|
+
if (pathStr.endsWith("/")) {
|
|
150
|
+
return pathStr;
|
|
151
|
+
}
|
|
152
|
+
return pathStr + "/";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function sleep(ms) {
|
|
156
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function shouldExtract(str, langKey) {
|
|
160
|
+
if (REGEX_MAP[langKey]) {
|
|
161
|
+
return REGEX_MAP[langKey].test(str);
|
|
162
|
+
}
|
|
163
|
+
return REGEX_MAP[translateLangKeyEnum.ZH].test(str);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function trimEmptyLine(str) {
|
|
167
|
+
return str.replace(/^\n+|\n+$/g, "");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function padEmptyLine(str) {
|
|
171
|
+
return "\n" + str + "\n";
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const translateLangKeyEnum = {
|
|
175
|
+
ZH: "zh-cn",
|
|
176
|
+
EN: "en",
|
|
177
|
+
JA: "ja",
|
|
178
|
+
KO: "ko",
|
|
179
|
+
RU: "ru"
|
|
180
|
+
};
|
|
181
|
+
const REGEX_MAP = {
|
|
182
|
+
[translateLangKeyEnum.ZH]: /[\u4e00-\u9fff]/,
|
|
183
|
+
[translateLangKeyEnum.EN]: /[a-zA-Z]/,
|
|
184
|
+
[translateLangKeyEnum.JA]: /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]/, // 日语假名和汉字
|
|
185
|
+
[translateLangKeyEnum.KO]: /[\uAC00-\uD7A3]/, // 韩语字母
|
|
186
|
+
[translateLangKeyEnum.RU]: /[йцукенгшщзхъфывапролджэячсмитьбюё .-]{1,}/ // 俄语字母
|
|
187
|
+
};
|
|
188
|
+
const excludeDirectives = [
|
|
189
|
+
"model",
|
|
190
|
+
"slot",
|
|
191
|
+
"if",
|
|
192
|
+
"show",
|
|
193
|
+
"for",
|
|
194
|
+
"on",
|
|
195
|
+
"once",
|
|
196
|
+
"memo"
|
|
197
|
+
];
|
|
198
|
+
const EXCLUDED_CALL = [
|
|
199
|
+
"$deepScan",
|
|
200
|
+
"console.log",
|
|
201
|
+
"console.info",
|
|
202
|
+
"console.warn",
|
|
203
|
+
"console.error",
|
|
204
|
+
"$i8n",
|
|
205
|
+
"$t",
|
|
206
|
+
"require",
|
|
207
|
+
"$$i8n",
|
|
208
|
+
"$$t",
|
|
209
|
+
"$emit",
|
|
210
|
+
"$emits",
|
|
211
|
+
"emits",
|
|
212
|
+
"_createCommentVNode"
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
module.exports = {
|
|
216
|
+
hashKey,
|
|
217
|
+
generateId,
|
|
218
|
+
parseArg,
|
|
219
|
+
isEmptyObject,
|
|
220
|
+
checkAgainstRegexArray,
|
|
221
|
+
extractFunctionName,
|
|
222
|
+
relativeCWDPath,
|
|
223
|
+
getLangJsonPath,
|
|
224
|
+
readJsonWithDefault,
|
|
225
|
+
resolveAliasPath,
|
|
226
|
+
resolveFilterPath,
|
|
227
|
+
fixFolderPath,
|
|
228
|
+
sleep,
|
|
229
|
+
shouldExtract,
|
|
230
|
+
trimEmptyLine,
|
|
231
|
+
padEmptyLine,
|
|
232
|
+
excludeDirectives,
|
|
233
|
+
EXCLUDED_CALL
|
|
234
|
+
};
|