i18n-easy 1.0.0
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/README.md +527 -0
- package/esm/assets/const.js +7 -0
- package/esm/ast_transformer.d.ts +19 -0
- package/esm/ast_transformer.js +54 -0
- package/esm/eslint/react/i18n_easy_plugin.d.ts +3 -0
- package/esm/eslint/react/i18n_easy_plugin.js +111 -0
- package/esm/eslint/react/i18n_utils.d.ts +61 -0
- package/esm/eslint/react/i18n_utils.js +115 -0
- package/esm/eslint/react/report_and_fix.d.ts +67 -0
- package/esm/eslint/react/report_and_fix.js +118 -0
- package/esm/eslint/vue/i18n_easy_plugin.d.ts +5 -0
- package/esm/eslint/vue/i18n_easy_plugin.js +141 -0
- package/esm/eslint/vue/i18n_utils.d.ts +65 -0
- package/esm/eslint/vue/i18n_utils.js +133 -0
- package/esm/eslint/vue/report_and_fix.d.ts +8 -0
- package/esm/eslint/vue/report_and_fix.js +169 -0
- package/esm/file_processor_utils.d.ts +14 -0
- package/esm/file_processor_utils.js +68 -0
- package/esm/i18n_easy.d.ts +77 -0
- package/esm/i18n_easy.js +171 -0
- package/esm/index.d.ts +4 -0
- package/esm/index.js +9 -0
- package/esm/key_map.d.ts +14 -0
- package/esm/key_map.js +51 -0
- package/esm/patch.d.ts +5 -0
- package/esm/progressBus.d.ts +7 -0
- package/esm/progressBus.js +25 -0
- package/esm/translate.d.ts +34 -0
- package/esm/translate.js +107 -0
- package/esm/type.d.ts +94 -0
- package/esm/type.js +0 -0
- package/esm/utils.d.ts +54 -0
- package/esm/utils.js +102 -0
- package/lib/assets/const.js +32 -0
- package/lib/ast_transformer.js +88 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.js +5 -0
- package/lib/eslint/react/i18n_easy_plugin.js +131 -0
- package/lib/eslint/react/i18n_utils.js +145 -0
- package/lib/eslint/react/report_and_fix.js +156 -0
- package/lib/eslint/vue/i18n_easy_plugin.js +161 -0
- package/lib/eslint/vue/i18n_utils.js +164 -0
- package/lib/eslint/vue/report_and_fix.js +203 -0
- package/lib/file_processor_utils.js +109 -0
- package/lib/i18n_easy.js +205 -0
- package/lib/index.js +35 -0
- package/lib/key_map.js +71 -0
- package/lib/package.json +3 -0
- package/lib/patch.d.ts +5 -0
- package/lib/progressBus.js +50 -0
- package/lib/translate.js +127 -0
- package/lib/type.js +17 -0
- package/lib/utils.js +142 -0
- package/package.json +68 -0
- package/types/assets/const.d.ts +2 -0
- package/types/ast_transformer.d.ts +19 -0
- package/types/eslint/react/i18n_easy_plugin.d.ts +3 -0
- package/types/eslint/react/i18n_utils.d.ts +61 -0
- package/types/eslint/react/report_and_fix.d.ts +67 -0
- package/types/eslint/vue/i18n_easy_plugin.d.ts +5 -0
- package/types/eslint/vue/i18n_utils.d.ts +65 -0
- package/types/eslint/vue/report_and_fix.d.ts +8 -0
- package/types/file_processor_utils.d.ts +14 -0
- package/types/i18n_easy.d.ts +77 -0
- package/types/index.d.ts +4 -0
- package/types/key_map.d.ts +14 -0
- package/types/progressBus.d.ts +6 -0
- package/types/translate.d.ts +34 -0
- package/types/type.d.ts +94 -0
- package/types/utils.d.ts +54 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/index.ts
|
|
20
|
+
var src_exports = {};
|
|
21
|
+
__export(src_exports, {
|
|
22
|
+
I18nEasy: () => import_i18n_easy.I18nEasy,
|
|
23
|
+
defineConfig: () => import_utils.defineConfig,
|
|
24
|
+
progressBus: () => import_progressBus.progressBus
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(src_exports);
|
|
27
|
+
var import_i18n_easy = require("./i18n_easy.js");
|
|
28
|
+
var import_progressBus = require("./progressBus.js");
|
|
29
|
+
var import_utils = require("./utils.js");
|
|
30
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
31
|
+
0 && (module.exports = {
|
|
32
|
+
I18nEasy,
|
|
33
|
+
defineConfig,
|
|
34
|
+
progressBus
|
|
35
|
+
});
|
package/lib/key_map.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/key_map.ts
|
|
20
|
+
var key_map_exports = {};
|
|
21
|
+
__export(key_map_exports, {
|
|
22
|
+
default: () => KeyMap
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(key_map_exports);
|
|
25
|
+
var import_utils = require("./utils.js");
|
|
26
|
+
var KeyMap = class _KeyMap {
|
|
27
|
+
// 字符映射表
|
|
28
|
+
charMap = /* @__PURE__ */ new Map();
|
|
29
|
+
// 生成的国际化文件key类型
|
|
30
|
+
keyType = "pinyin";
|
|
31
|
+
static instance;
|
|
32
|
+
constructor() {
|
|
33
|
+
}
|
|
34
|
+
// 获取单例实例
|
|
35
|
+
static getInstance() {
|
|
36
|
+
if (!this.instance) {
|
|
37
|
+
this.instance = new _KeyMap();
|
|
38
|
+
}
|
|
39
|
+
return this.instance;
|
|
40
|
+
}
|
|
41
|
+
// 获取字符映射表
|
|
42
|
+
get charList() {
|
|
43
|
+
return this.charMap;
|
|
44
|
+
}
|
|
45
|
+
// 将中文转换成拼音
|
|
46
|
+
generateKey(str) {
|
|
47
|
+
const trimStr = str.trim();
|
|
48
|
+
const key = (0, import_utils.generateKeyByKeyType)(trimStr, this.keyType);
|
|
49
|
+
this.setCharMap(key, trimStr);
|
|
50
|
+
return key;
|
|
51
|
+
}
|
|
52
|
+
// 清空字符映射表
|
|
53
|
+
clearCharMap() {
|
|
54
|
+
this.charMap.clear();
|
|
55
|
+
}
|
|
56
|
+
// 设置字符映射表
|
|
57
|
+
setCharMap(key, value) {
|
|
58
|
+
if (this.charMap.has(key)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.charMap.set(key, value);
|
|
62
|
+
}
|
|
63
|
+
// 判断字符映射表是否为空
|
|
64
|
+
isEmpty() {
|
|
65
|
+
return this.charMap.size === 0;
|
|
66
|
+
}
|
|
67
|
+
// 设置映射表类型
|
|
68
|
+
setKeyType(type) {
|
|
69
|
+
this.keyType = type;
|
|
70
|
+
}
|
|
71
|
+
};
|
package/lib/package.json
ADDED
package/lib/patch.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/progressBus.ts
|
|
20
|
+
var progressBus_exports = {};
|
|
21
|
+
__export(progressBus_exports, {
|
|
22
|
+
log: () => log,
|
|
23
|
+
progressBus: () => progressBus
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(progressBus_exports);
|
|
26
|
+
var import_events = require("events");
|
|
27
|
+
var colors = {
|
|
28
|
+
reset: "\x1B[0m",
|
|
29
|
+
red: "\x1B[31m",
|
|
30
|
+
green: "\x1B[32m",
|
|
31
|
+
blue: "\x1B[34m"
|
|
32
|
+
};
|
|
33
|
+
var statusColorMap = {
|
|
34
|
+
fail: colors.red,
|
|
35
|
+
info: colors.blue,
|
|
36
|
+
success: colors.green
|
|
37
|
+
};
|
|
38
|
+
var progressBus = new import_events.EventEmitter();
|
|
39
|
+
function colorLog(msg, status) {
|
|
40
|
+
console.log(`${statusColorMap[status]}${msg}${colors.reset}`);
|
|
41
|
+
}
|
|
42
|
+
function log(msg, status) {
|
|
43
|
+
colorLog(msg, status);
|
|
44
|
+
progressBus.emit("log", msg, status);
|
|
45
|
+
}
|
|
46
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
47
|
+
0 && (module.exports = {
|
|
48
|
+
log,
|
|
49
|
+
progressBus
|
|
50
|
+
});
|
package/lib/translate.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/translate.ts
|
|
20
|
+
var translate_exports = {};
|
|
21
|
+
__export(translate_exports, {
|
|
22
|
+
default: () => Translate
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(translate_exports);
|
|
25
|
+
var import_uuid = require("uuid");
|
|
26
|
+
var import_utils = require("./utils.js");
|
|
27
|
+
var Translate = class _Translate {
|
|
28
|
+
// 微软翻译API
|
|
29
|
+
endpoint = "https://api.cognitive.microsofttranslator.com/translate";
|
|
30
|
+
// 微软翻译API密钥
|
|
31
|
+
apiKey;
|
|
32
|
+
// 单例实例
|
|
33
|
+
static instance;
|
|
34
|
+
constructor() {
|
|
35
|
+
}
|
|
36
|
+
// 获取单例实例
|
|
37
|
+
static getInstance() {
|
|
38
|
+
if (!this.instance) {
|
|
39
|
+
this.instance = new _Translate();
|
|
40
|
+
}
|
|
41
|
+
return this.instance;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 构建微软翻译API请求配置
|
|
45
|
+
* @param originalTextArr 原始文本数组,每个元素为{ text: string }
|
|
46
|
+
* @param lang 目标语言数组
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
buildRequestConfig(originalTextArr, lang) {
|
|
50
|
+
const url = new URL(this.endpoint);
|
|
51
|
+
url.searchParams.append("api-version", "3.0");
|
|
52
|
+
url.searchParams.append("from", "zh");
|
|
53
|
+
lang.forEach((toLang) => url.searchParams.append("to", toLang));
|
|
54
|
+
return {
|
|
55
|
+
url,
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: {
|
|
58
|
+
"Ocp-Apim-Subscription-Key": this.apiKey,
|
|
59
|
+
"Ocp-Apim-Subscription-Region": "global",
|
|
60
|
+
"Content-type": "application/json",
|
|
61
|
+
"X-ClientTraceId": (0, import_uuid.v4)().toString()
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(originalTextArr)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 处理微软翻译API响应数据
|
|
68
|
+
* @param responseData 翻译API响应数据,每个元素为{ translations: { text: string }[] }
|
|
69
|
+
* @param originalTextArr 原始文本数组,每个元素为[ key: string, text: string ]
|
|
70
|
+
* @param lang 目标语言数组
|
|
71
|
+
* @returns 翻译结果,格式为{ language: { key: text } }
|
|
72
|
+
*/
|
|
73
|
+
processResponse(responseData, originalTextArr, lang) {
|
|
74
|
+
const translationResult = {};
|
|
75
|
+
responseData.forEach((arrItem, i) => {
|
|
76
|
+
const key = originalTextArr[i][0];
|
|
77
|
+
arrItem.translations.forEach((item, j) => {
|
|
78
|
+
const language = lang[j];
|
|
79
|
+
translationResult[language] = translationResult[language] || {};
|
|
80
|
+
translationResult[language][key] = item.text;
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return translationResult;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 翻译中文为其他指定语言
|
|
87
|
+
* @param originalTextArr 原始文本数组,每个元素为[ key: string, text: string ]
|
|
88
|
+
* @param lang 目标语言数组
|
|
89
|
+
* @returns 翻译结果,格式为{ language: { key: text } }
|
|
90
|
+
*/
|
|
91
|
+
async translate(originalTextArr, lang) {
|
|
92
|
+
if (!this.apiKey) {
|
|
93
|
+
throw new Error("配置文件缺失配置项:微软翻译apiKey不能为空");
|
|
94
|
+
}
|
|
95
|
+
if (!lang.length) {
|
|
96
|
+
throw new Error("配置文件缺失配置项:目标语言lang不能为空");
|
|
97
|
+
}
|
|
98
|
+
if (!originalTextArr.length) {
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
const textArr = originalTextArr.map(([_, text]) => {
|
|
102
|
+
if (!text.includes("{") && !text.includes("}")) {
|
|
103
|
+
return { text };
|
|
104
|
+
}
|
|
105
|
+
const str = text.replace(/({\s*arg[0-9]\s*})/g, (str2) => (0, import_utils.customTranslation)(str2, str2));
|
|
106
|
+
return { text: str };
|
|
107
|
+
});
|
|
108
|
+
const { url, ...config } = this.buildRequestConfig(textArr, lang);
|
|
109
|
+
try {
|
|
110
|
+
const response = await fetch(url, config);
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw new Error(`翻译API请求失败,响应状态码:${response.status}`);
|
|
113
|
+
}
|
|
114
|
+
const data = await response.json();
|
|
115
|
+
return this.processResponse(data, originalTextArr, lang);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 设置微软翻译API密钥
|
|
122
|
+
* @param apiKey 微软翻译API密钥
|
|
123
|
+
*/
|
|
124
|
+
setApiKey(apiKey) {
|
|
125
|
+
this.apiKey = apiKey;
|
|
126
|
+
}
|
|
127
|
+
};
|
package/lib/type.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
10
|
+
}
|
|
11
|
+
return to;
|
|
12
|
+
};
|
|
13
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
14
|
+
|
|
15
|
+
// src/type.ts
|
|
16
|
+
var type_exports = {};
|
|
17
|
+
module.exports = __toCommonJS(type_exports);
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/utils.ts
|
|
30
|
+
var utils_exports = {};
|
|
31
|
+
__export(utils_exports, {
|
|
32
|
+
customTranslation: () => customTranslation,
|
|
33
|
+
defineConfig: () => defineConfig,
|
|
34
|
+
generateKeyByKeyType: () => generateKeyByKeyType,
|
|
35
|
+
hasChineseChar: () => hasChineseChar,
|
|
36
|
+
isSupportFileType: () => isSupportFileType,
|
|
37
|
+
isVueScriptSrcImport: () => isVueScriptSrcImport,
|
|
38
|
+
searchFileContent: () => searchFileContent
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(utils_exports);
|
|
41
|
+
var import_node_crypto = require("node:crypto");
|
|
42
|
+
var import_node_path = __toESM(require("node:path"));
|
|
43
|
+
var import_node_fs = require("node:fs");
|
|
44
|
+
var import_glob = require("glob");
|
|
45
|
+
var import_compiler_sfc = require("@vue/compiler-sfc");
|
|
46
|
+
var import_pinyin_pro = require("pinyin-pro");
|
|
47
|
+
var import_modern = __toESM(require("@pinyin-pro/data/modern"));
|
|
48
|
+
var import_cosmiconfig = require("cosmiconfig");
|
|
49
|
+
(0, import_pinyin_pro.addDict)(import_modern.default);
|
|
50
|
+
function hasChineseChar(str) {
|
|
51
|
+
if (!str) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return /[\u4e00-\u9fa5]/.test(str);
|
|
55
|
+
}
|
|
56
|
+
function generateHash(char) {
|
|
57
|
+
const hash = (0, import_node_crypto.createHash)("md5");
|
|
58
|
+
hash.update(char);
|
|
59
|
+
return hash.digest("hex").slice();
|
|
60
|
+
}
|
|
61
|
+
function generatePinYin(char, toneType) {
|
|
62
|
+
const filtered = char.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "");
|
|
63
|
+
return (0, import_pinyin_pro.pinyin)(filtered, {
|
|
64
|
+
separator: "_",
|
|
65
|
+
// 分隔符
|
|
66
|
+
toneType,
|
|
67
|
+
// 声调
|
|
68
|
+
nonZh: "consecutive",
|
|
69
|
+
// 非汉字在结果中紧凑输出
|
|
70
|
+
nonZhScope: /[a-zA-Z0-9]/
|
|
71
|
+
// 指定nonZh范围的正则
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function generateKeyByKeyType(char, keyType) {
|
|
75
|
+
if (keyType === "hash") {
|
|
76
|
+
return generateHash(char);
|
|
77
|
+
} else if (keyType === "pinyinWithNumber") {
|
|
78
|
+
return generatePinYin(char, "num");
|
|
79
|
+
} else {
|
|
80
|
+
return generatePinYin(char, "none");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function isVueScriptSrcImport(filePath, fileType) {
|
|
84
|
+
if (!["js", "ts"].includes(fileType)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const vueFiles = await (0, import_glob.glob)("*.vue", { cwd: import_node_path.default.dirname(filePath), absolute: true, nodir: true });
|
|
88
|
+
for (const file of vueFiles) {
|
|
89
|
+
const code = await import_node_fs.promises.readFile(file, "utf8");
|
|
90
|
+
const { descriptor } = (0, import_compiler_sfc.parse)(code);
|
|
91
|
+
const { script } = descriptor;
|
|
92
|
+
if ((script == null ? void 0 : script.src) && import_node_path.default.resolve(import_node_path.default.dirname(file), script.src) === filePath) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
function isSupportFileType(fileType, framework) {
|
|
99
|
+
const SUPPORT_FILE_TYPE_MAP = {
|
|
100
|
+
vue: /* @__PURE__ */ new Set(["vue", "js", "jsx", "ts", "tsx"]),
|
|
101
|
+
react: /* @__PURE__ */ new Set(["js", "jsx", "ts", "tsx"])
|
|
102
|
+
};
|
|
103
|
+
return SUPPORT_FILE_TYPE_MAP[framework].has(fileType);
|
|
104
|
+
}
|
|
105
|
+
async function searchFileContent(dirPath, searchPlaces) {
|
|
106
|
+
const explorer = (0, import_cosmiconfig.cosmiconfig)("", {
|
|
107
|
+
searchStrategy: "none",
|
|
108
|
+
searchPlaces,
|
|
109
|
+
loaders: {
|
|
110
|
+
".json": import_cosmiconfig.defaultLoaders[".json"],
|
|
111
|
+
// 保持默认 JSON 加载器
|
|
112
|
+
".js": import_cosmiconfig.defaultLoaders[".js"],
|
|
113
|
+
// 保持默认 JS 加载器
|
|
114
|
+
".mjs": import_cosmiconfig.defaultLoaders[".mjs"],
|
|
115
|
+
// 保持默认 MJS 加载器
|
|
116
|
+
".cjs": import_cosmiconfig.defaultLoaders[".cjs"],
|
|
117
|
+
// 保持默认 CJS 加载器
|
|
118
|
+
".ts": import_cosmiconfig.defaultLoaders[".ts"],
|
|
119
|
+
// 保持默认 TS 加载器'
|
|
120
|
+
noExt: import_cosmiconfig.defaultLoaders[".json"]
|
|
121
|
+
// 无扩展名文件作为 JSON 处理
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const result = await explorer.search(dirPath);
|
|
125
|
+
return result ? result.config : null;
|
|
126
|
+
}
|
|
127
|
+
function defineConfig(config) {
|
|
128
|
+
return config;
|
|
129
|
+
}
|
|
130
|
+
function customTranslation(source, translation) {
|
|
131
|
+
return `<mstrans:dictionary translation=${translation}>${source}</mstrans:dictionary>`;
|
|
132
|
+
}
|
|
133
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
134
|
+
0 && (module.exports = {
|
|
135
|
+
customTranslation,
|
|
136
|
+
defineConfig,
|
|
137
|
+
generateKeyByKeyType,
|
|
138
|
+
hasChineseChar,
|
|
139
|
+
isSupportFileType,
|
|
140
|
+
isVueScriptSrcImport,
|
|
141
|
+
searchFileContent
|
|
142
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "i18n-easy",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "一个一键国际化工具,用于将代码中的中文转换成国际化写法,并将翻译内容写入指定的语言文件中。提高开发效率,简化国际化流程。",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"i18n",
|
|
8
|
+
"国际化",
|
|
9
|
+
"中文国际化",
|
|
10
|
+
"翻译",
|
|
11
|
+
"国际化工具",
|
|
12
|
+
"代码转换",
|
|
13
|
+
"翻译管理",
|
|
14
|
+
"国际化文件生成"
|
|
15
|
+
],
|
|
16
|
+
"types": "./types/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./types/index.d.ts",
|
|
20
|
+
"default": "./esm/index.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./types/index.d.ts",
|
|
24
|
+
"default": "./lib/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"main": "./lib/index.js",
|
|
28
|
+
"bin": {
|
|
29
|
+
"i18n-easy": "./lib/cli.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"lib",
|
|
33
|
+
"esm",
|
|
34
|
+
"types",
|
|
35
|
+
"package.json",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"dev": "tsx src/cli.ts",
|
|
40
|
+
"build": "father build",
|
|
41
|
+
"build:types": "tsc --project tsconfig.types.json",
|
|
42
|
+
"build:all": "pnpm build && pnpm build:types",
|
|
43
|
+
"postbuild": "tsx post-build.ts"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/estree": "^1.0.6",
|
|
47
|
+
"@types/node": "^22.13.9",
|
|
48
|
+
"@typescript-eslint/utils": "^8.46.0",
|
|
49
|
+
"jiti": "^2.4.2",
|
|
50
|
+
"tsx": "^4.19.3",
|
|
51
|
+
"typescript": "~5.7.2"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@pinyin-pro/data": "^1.2.0",
|
|
55
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
56
|
+
"@vue/compiler-sfc": "^3.5.22",
|
|
57
|
+
"cosmiconfig": "^9.0.0",
|
|
58
|
+
"eslint": "^9.27.0",
|
|
59
|
+
"espree": "^10.3.0",
|
|
60
|
+
"father": "4.2.0",
|
|
61
|
+
"glob": "^11.0.3",
|
|
62
|
+
"json5": "^2.2.3",
|
|
63
|
+
"pinyin-pro": "^3.26.0",
|
|
64
|
+
"simple-git": "^3.28.0",
|
|
65
|
+
"uuid": "^11.1.0",
|
|
66
|
+
"vue-eslint-parser": "^10.1.3"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Framework, SupportFileMap, I18nInfoType, ReactI18nInfoType, TextNode, ReactCollectItemType } from './type.js';
|
|
2
|
+
import { type Rule } from 'eslint';
|
|
3
|
+
interface Props<T extends Framework> {
|
|
4
|
+
fileContent: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
fileType: SupportFileMap[T];
|
|
7
|
+
type: T;
|
|
8
|
+
i18nInfo: T extends 'vue' ? I18nInfoType : ReactI18nInfoType;
|
|
9
|
+
customIgnore?: (node: T extends 'vue' ? TextNode : ReactCollectItemType['textNode'], context: Rule.RuleContext) => boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare class AstTransformer {
|
|
12
|
+
private linter;
|
|
13
|
+
constructor();
|
|
14
|
+
convertFileContent<T extends Framework>(props: Props<T>): {
|
|
15
|
+
newFileContent: string;
|
|
16
|
+
fixed: boolean;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import * as ESTree from 'estree';
|
|
3
|
+
import { ReactCodeType, ReactCollectItemType, ReactInjectCodeType } from '../../type.js';
|
|
4
|
+
/**
|
|
5
|
+
* @description 创建忽略注释检查器
|
|
6
|
+
* @param context - 规则上下文
|
|
7
|
+
* @returns 忽略注释检查函数
|
|
8
|
+
*/
|
|
9
|
+
export declare function createI18nIgnoreChecker(context: Rule.RuleContext): (node: ReactCollectItemType["textNode"]) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* @description 判断能否注入
|
|
12
|
+
* @param context - 规则上下文
|
|
13
|
+
* @param node - 节点 (Program、组件、hooks节点)
|
|
14
|
+
* @param codeType - 代码类型
|
|
15
|
+
* @returns 是否能注入
|
|
16
|
+
*/
|
|
17
|
+
export declare function canInject(context: Rule.RuleContext, node: ReactInjectCodeType, codeType: ReactCodeType): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* @description 获取最后一个 import 或第一个非 import 节点
|
|
20
|
+
** 1、不存在节点返回null
|
|
21
|
+
** 2、存在import节点,返回最后一个import节点
|
|
22
|
+
** 3、不存在import节点,返回第一个非import节点
|
|
23
|
+
* @param context - 规则上下文
|
|
24
|
+
* @returns 节点信息
|
|
25
|
+
*/
|
|
26
|
+
export declare function getLastImportOrFirstNotImportNode(context: Rule.RuleContext): {
|
|
27
|
+
node: ESTree.Node;
|
|
28
|
+
type: string;
|
|
29
|
+
} | null;
|
|
30
|
+
/**
|
|
31
|
+
* @description 获取注入节点
|
|
32
|
+
* @param context - 规则上下文
|
|
33
|
+
* @param node - BlockStatement节点
|
|
34
|
+
* @returns 第一个子节点(包含注释节点)
|
|
35
|
+
*/
|
|
36
|
+
export declare function getInjectNode(context: Rule.RuleContext, node: ESTree.BlockStatement): ESTree.Comment | ESTree.Statement;
|
|
37
|
+
/**
|
|
38
|
+
* @description 判断能否收集操作节点
|
|
39
|
+
** 排除:
|
|
40
|
+
** 1、显示使用@i18n-ignore注释的节点
|
|
41
|
+
** 2、未使用中文的节点
|
|
42
|
+
* @param node - 节点 (TemplateLiteral、Literal、JSXText节点)
|
|
43
|
+
* @param isIgnored - 判断是否被忽略的函数
|
|
44
|
+
* @returns 是否能收集操作节点
|
|
45
|
+
*/
|
|
46
|
+
export declare function canCollectOperateNodes(node: ReactCollectItemType['textNode'], isIgnored: (n: ReactCollectItemType['textNode']) => boolean): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* @description 获取节点前的空格
|
|
49
|
+
* @param context - 规则上下文
|
|
50
|
+
* @param node - 节点
|
|
51
|
+
* @returns 节点前的空格
|
|
52
|
+
*/
|
|
53
|
+
export declare function getLeadingSpaces(context: Rule.RuleContext, node: ESTree.Node | ESTree.Comment): string;
|
|
54
|
+
/**
|
|
55
|
+
* @description 获取国际化调用方法
|
|
56
|
+
* @param callMethodName - 国际化调用方法
|
|
57
|
+
* @param key - 国际化键值
|
|
58
|
+
* @param value - 国际化参数
|
|
59
|
+
* @returns 国际化调用方法
|
|
60
|
+
*/
|
|
61
|
+
export declare function getI18nCallMethod(callMethodName: string, key: string, value?: string): string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import * as ESTree from 'estree';
|
|
3
|
+
import { ReactCollectItemType, ReactCollectListType, ReactCodeType } from '../../type.js';
|
|
4
|
+
type FixFunType = ((fixer: Rule.RuleFixer) => Rule.Fix | Iterable<Rule.Fix> | null) | null;
|
|
5
|
+
/**
|
|
6
|
+
* @description 生成替换中文为国际化写法修复函数
|
|
7
|
+
* @param context - 规则上下文
|
|
8
|
+
* @param node - 节点
|
|
9
|
+
* @param codeType - 代码类型
|
|
10
|
+
* @returns 修复函数
|
|
11
|
+
* @example 原始代码:<span>张三</span> 修复后代码:<span>{ formatMessage({ id: 'zhang_san'}) }</span>
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateReplaceKeyFixFun(context: Rule.RuleContext, node: ReactCollectItemType['textNode'], codeType: ReactCodeType): FixFunType;
|
|
14
|
+
/**
|
|
15
|
+
* @description 生成注入import语句的修复函数
|
|
16
|
+
* @param context - 规则上下文
|
|
17
|
+
* @param codeType - 代码类型
|
|
18
|
+
* @returns 修复函数
|
|
19
|
+
* @example
|
|
20
|
+
* 原始代码:
|
|
21
|
+
* const a = 1
|
|
22
|
+
* 修复后代码:
|
|
23
|
+
* import i18n from '@/i18n/i18n.js' // 注入导入语句
|
|
24
|
+
* const a = 1
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateInjectImportFixFun(context: Rule.RuleContext, codeType: ReactCodeType): FixFunType;
|
|
27
|
+
/**
|
|
28
|
+
* @description 生成注入hooks调用语句的修复函数
|
|
29
|
+
* @param context - 规则上下文
|
|
30
|
+
* @param node - 节点
|
|
31
|
+
* @returns 修复函数
|
|
32
|
+
* @example
|
|
33
|
+
* 原始代码:
|
|
34
|
+
* function Button() {
|
|
35
|
+
* return <span>按钮</span>
|
|
36
|
+
* }
|
|
37
|
+
* 修复后代码:
|
|
38
|
+
* function Button() {
|
|
39
|
+
* const { formatMessage } = useI18n() // 注入hooks调用语句
|
|
40
|
+
* return <span>按钮</span>
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateInjectHooksCallFixFun(context: Rule.RuleContext, node: ESTree.FunctionDeclaration | ESTree.VariableDeclarator): FixFunType;
|
|
44
|
+
/**
|
|
45
|
+
* @description 生成注入代码到顶部的修复函数
|
|
46
|
+
* @param context - 规则上下文
|
|
47
|
+
* @param codeType - 代码类型
|
|
48
|
+
* @returns 修复函数
|
|
49
|
+
* @example
|
|
50
|
+
* 原始代码:
|
|
51
|
+
* function Button() {
|
|
52
|
+
* return <span>{formatMessage('button')}</span>
|
|
53
|
+
* }
|
|
54
|
+
* 修复后代码:
|
|
55
|
+
* const { formatMessage } = getIntl(); // 注入代码到顶部
|
|
56
|
+
* function Button() {
|
|
57
|
+
* return <span>{formatMessage('button')}</span>
|
|
58
|
+
* }
|
|
59
|
+
*/
|
|
60
|
+
export declare function generateInjectCodeToTopLevelFixFun(context: Rule.RuleContext, codeType: ReactCodeType): FixFunType;
|
|
61
|
+
/**
|
|
62
|
+
* @description 批量执行修复函数 根据收集到节点生成修复函数并执行
|
|
63
|
+
* @param context - 规则上下文
|
|
64
|
+
* @param state - 收集到的节点列表
|
|
65
|
+
*/
|
|
66
|
+
export declare function batchFixAll(context: Rule.RuleContext, state: ReactCollectListType): void;
|
|
67
|
+
export {};
|