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
|
@@ -0,0 +1,131 @@
|
|
|
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/eslint/react/i18n_easy_plugin.ts
|
|
20
|
+
var i18n_easy_plugin_exports = {};
|
|
21
|
+
__export(i18n_easy_plugin_exports, {
|
|
22
|
+
default: () => i18n_easy_plugin_default
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(i18n_easy_plugin_exports);
|
|
25
|
+
var import_report_and_fix = require("./report_and_fix.js");
|
|
26
|
+
var import_i18n_utils = require("./i18n_utils.js");
|
|
27
|
+
var ReactPlugin = {
|
|
28
|
+
rules: {
|
|
29
|
+
"i18n-transform": {
|
|
30
|
+
meta: {
|
|
31
|
+
type: "problem",
|
|
32
|
+
messages: { hasChinese: "当前文件存在中文字符‘{{ char }}’,可进行国际化替换" },
|
|
33
|
+
fixable: "code"
|
|
34
|
+
},
|
|
35
|
+
create(context) {
|
|
36
|
+
const customIgnore = context.settings.customIgnore;
|
|
37
|
+
let isIgnored;
|
|
38
|
+
const state = {
|
|
39
|
+
inComponent: [],
|
|
40
|
+
// 组件内中文
|
|
41
|
+
outComponent: []
|
|
42
|
+
// 组件外中文
|
|
43
|
+
};
|
|
44
|
+
let inComp = false;
|
|
45
|
+
let compNode = null;
|
|
46
|
+
const enterComp = () => inComp = true;
|
|
47
|
+
const exitComp = () => inComp = false;
|
|
48
|
+
const collectNodes = (textNode, programNode) => {
|
|
49
|
+
if (customIgnore == null ? void 0 : customIgnore(textNode, context)) return;
|
|
50
|
+
if (!(0, import_i18n_utils.canCollectOperateNodes)(textNode, isIgnored)) return;
|
|
51
|
+
const payload = { textNode, componentNode: inComp ? compNode : null, programNode: inComp ? null : programNode, inComp };
|
|
52
|
+
if (inComp) {
|
|
53
|
+
state.inComponent.push(payload);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
state.outComponent.push(payload);
|
|
57
|
+
};
|
|
58
|
+
const collectScriptOperateNodesVisitor = {
|
|
59
|
+
// 字面量节点
|
|
60
|
+
Literal(node) {
|
|
61
|
+
collectNodes(node, context.sourceCode.ast);
|
|
62
|
+
},
|
|
63
|
+
// 模版字符串节点
|
|
64
|
+
TemplateLiteral(node) {
|
|
65
|
+
collectNodes(node, context.sourceCode.ast);
|
|
66
|
+
},
|
|
67
|
+
// JSX文本节点
|
|
68
|
+
JSXText(node) {
|
|
69
|
+
collectNodes(node, context.sourceCode.ast);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const injectConfigCodeVisitor = {
|
|
73
|
+
/**
|
|
74
|
+
* 进入时 记录@i18n-ignore注释所在行号
|
|
75
|
+
*/
|
|
76
|
+
Program: function() {
|
|
77
|
+
isIgnored = (0, import_i18n_utils.createI18nIgnoreChecker)(context);
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* 退出时
|
|
81
|
+
* 1、替换中文为国际化写法
|
|
82
|
+
* 2、注入配置代码
|
|
83
|
+
*/
|
|
84
|
+
"Program:exit": function() {
|
|
85
|
+
(0, import_report_and_fix.batchFixAll)(context, state);
|
|
86
|
+
},
|
|
87
|
+
// 组件 function Component(){}
|
|
88
|
+
"FunctionDeclaration[id.name=/^[A-Z]/]": function(node) {
|
|
89
|
+
compNode = node;
|
|
90
|
+
enterComp();
|
|
91
|
+
},
|
|
92
|
+
"FunctionDeclaration[id.name=/^[A-Z]/]:exit": exitComp,
|
|
93
|
+
// 组件 const Component = () => {}
|
|
94
|
+
"VariableDeclarator[id.name=/^[A-Z]/] > ArrowFunctionExpression": function(node) {
|
|
95
|
+
compNode = node.parent;
|
|
96
|
+
enterComp();
|
|
97
|
+
},
|
|
98
|
+
"VariableDeclarator[id.name=/^[A-Z]/] > ArrowFunctionExpression:exit": exitComp,
|
|
99
|
+
// 组件 const Component = function(){}
|
|
100
|
+
"VariableDeclarator[id.name=/^[A-Z]/] > FunctionExpression": function(node) {
|
|
101
|
+
compNode = node.parent;
|
|
102
|
+
enterComp();
|
|
103
|
+
},
|
|
104
|
+
"VariableDeclarator[id.name=/^[A-Z]/] > FunctionExpression:exit": exitComp,
|
|
105
|
+
// 自定义hooks(同理)
|
|
106
|
+
"FunctionDeclaration[id.name=/^use[A-Z]/]": function(node) {
|
|
107
|
+
compNode = node;
|
|
108
|
+
enterComp();
|
|
109
|
+
},
|
|
110
|
+
"FunctionDeclaration[id.name=/^use[A-Z]/]:exit": exitComp,
|
|
111
|
+
"VariableDeclarator[id.name=/^use[A-Z]/] > ArrowFunctionExpression": function(node) {
|
|
112
|
+
compNode = node.parent;
|
|
113
|
+
enterComp();
|
|
114
|
+
},
|
|
115
|
+
"VariableDeclarator[id.name=/^use[A-Z]/] > ArrowFunctionExpression:exit": exitComp,
|
|
116
|
+
"VariableDeclarator[id.name=/^use[A-Z]/] > FunctionExpression": function(node) {
|
|
117
|
+
compNode = node.parent;
|
|
118
|
+
enterComp();
|
|
119
|
+
},
|
|
120
|
+
"VariableDeclarator[id.name=/^use[A-Z]/] > FunctionExpression:exit": exitComp
|
|
121
|
+
};
|
|
122
|
+
const replaceOperateNodesAndInjectVisitor = {
|
|
123
|
+
...collectScriptOperateNodesVisitor,
|
|
124
|
+
...injectConfigCodeVisitor
|
|
125
|
+
};
|
|
126
|
+
return replaceOperateNodesAndInjectVisitor;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var i18n_easy_plugin_default = ReactPlugin;
|
|
@@ -0,0 +1,145 @@
|
|
|
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/eslint/react/i18n_utils.ts
|
|
20
|
+
var i18n_utils_exports = {};
|
|
21
|
+
__export(i18n_utils_exports, {
|
|
22
|
+
canCollectOperateNodes: () => canCollectOperateNodes,
|
|
23
|
+
canInject: () => canInject,
|
|
24
|
+
createI18nIgnoreChecker: () => createI18nIgnoreChecker,
|
|
25
|
+
getI18nCallMethod: () => getI18nCallMethod,
|
|
26
|
+
getInjectNode: () => getInjectNode,
|
|
27
|
+
getLastImportOrFirstNotImportNode: () => getLastImportOrFirstNotImportNode,
|
|
28
|
+
getLeadingSpaces: () => getLeadingSpaces
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(i18n_utils_exports);
|
|
31
|
+
var import_utils = require("../../utils.js");
|
|
32
|
+
function createI18nIgnoreChecker(context) {
|
|
33
|
+
const ignoreLines = [];
|
|
34
|
+
const jsComments = context.sourceCode.getAllComments();
|
|
35
|
+
for (const comment of jsComments) {
|
|
36
|
+
if (["HTMLComment", "Line", "Block"].includes(comment.type) && comment.value.trim().includes("@i18n-ignore")) {
|
|
37
|
+
ignoreLines.push([comment.loc.start.line, comment.loc.end.line]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return function isIgnored(node) {
|
|
41
|
+
const nodeStartLine = node.loc.start.line;
|
|
42
|
+
const nodeEndLine = node.loc.end.line;
|
|
43
|
+
if (nodeStartLine !== nodeEndLine) return false;
|
|
44
|
+
return ignoreLines.some(([_start, end]) => end === nodeEndLine - 1);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function getScope(context, node) {
|
|
48
|
+
if (node.type === "Program") {
|
|
49
|
+
const programScope = context.sourceCode.getScope(node);
|
|
50
|
+
return programScope.type == "global" ? programScope.childScopes[0] : programScope;
|
|
51
|
+
}
|
|
52
|
+
if (["FunctionDeclaration", "VariableDeclarator"].includes(node.type)) {
|
|
53
|
+
return context.sourceCode.getScope(node);
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function canInject(context, node, codeType) {
|
|
58
|
+
if (!node) return false;
|
|
59
|
+
const { callMethodName } = context.settings.i18nInfo[codeType] || {};
|
|
60
|
+
if (!callMethodName) return false;
|
|
61
|
+
const scope = getScope(context, node);
|
|
62
|
+
if (!scope) return false;
|
|
63
|
+
return scope.variables.some((ref) => ref.name === callMethodName) === false;
|
|
64
|
+
}
|
|
65
|
+
function getLastImportOrFirstNotImportNode(context) {
|
|
66
|
+
const src = context.sourceCode;
|
|
67
|
+
const body = src.ast.body;
|
|
68
|
+
let lastImport = body.filter((n) => n.type === "ImportDeclaration").pop();
|
|
69
|
+
if (lastImport) {
|
|
70
|
+
return {
|
|
71
|
+
node: lastImport,
|
|
72
|
+
type: "lastImport"
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
let firstNonImport = null;
|
|
76
|
+
const allNodes = [...body];
|
|
77
|
+
const commentsAsNodes = src.getAllComments();
|
|
78
|
+
const sorted = [...allNodes, ...commentsAsNodes].sort((a, b) => {
|
|
79
|
+
if (a.range && b.range) {
|
|
80
|
+
return a.range[0] - b.range[0];
|
|
81
|
+
}
|
|
82
|
+
return 0;
|
|
83
|
+
});
|
|
84
|
+
firstNonImport = sorted.find((n) => n.type !== "ImportDeclaration");
|
|
85
|
+
if (firstNonImport) {
|
|
86
|
+
return {
|
|
87
|
+
node: firstNonImport,
|
|
88
|
+
type: "firstNonImport"
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
function getInjectNode(context, node) {
|
|
94
|
+
const commentNodes = context.sourceCode.getAllComments();
|
|
95
|
+
const comments = commentNodes.filter((item) => {
|
|
96
|
+
if (item.range && node.range) {
|
|
97
|
+
return item.range[0] >= node.range[0] && item.range[1] <= node.range[1];
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
});
|
|
101
|
+
const sorted = [...comments, ...node.body].sort((a, b) => {
|
|
102
|
+
if (a.range && b.range) {
|
|
103
|
+
return a.range[0] - b.range[0];
|
|
104
|
+
}
|
|
105
|
+
return 0;
|
|
106
|
+
});
|
|
107
|
+
return sorted[0];
|
|
108
|
+
}
|
|
109
|
+
function canCollectOperateNodes(node, isIgnored) {
|
|
110
|
+
if (isIgnored(node)) return false;
|
|
111
|
+
switch (node.type) {
|
|
112
|
+
case "TemplateLiteral":
|
|
113
|
+
if (!node.quasis.some((q) => (0, import_utils.hasChineseChar)(q.value.cooked))) return false;
|
|
114
|
+
return true;
|
|
115
|
+
case "Literal":
|
|
116
|
+
if (!(0, import_utils.hasChineseChar)(node.value)) return false;
|
|
117
|
+
return true;
|
|
118
|
+
case "JSXText":
|
|
119
|
+
if (!(0, import_utils.hasChineseChar)(node.value)) return false;
|
|
120
|
+
return true;
|
|
121
|
+
default:
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function getLeadingSpaces(context, node) {
|
|
126
|
+
if (!node.loc) return "";
|
|
127
|
+
const line = context.sourceCode.lines[node.loc.start.line - 1];
|
|
128
|
+
return line.slice(0, node.loc.start.column);
|
|
129
|
+
}
|
|
130
|
+
function getI18nCallMethod(callMethodName, key, value) {
|
|
131
|
+
if (value) {
|
|
132
|
+
return `${callMethodName}('${key}', { ${value} })`;
|
|
133
|
+
}
|
|
134
|
+
return `${callMethodName}('${key}')`;
|
|
135
|
+
}
|
|
136
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
137
|
+
0 && (module.exports = {
|
|
138
|
+
canCollectOperateNodes,
|
|
139
|
+
canInject,
|
|
140
|
+
createI18nIgnoreChecker,
|
|
141
|
+
getI18nCallMethod,
|
|
142
|
+
getInjectNode,
|
|
143
|
+
getLastImportOrFirstNotImportNode,
|
|
144
|
+
getLeadingSpaces
|
|
145
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
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/eslint/react/report_and_fix.ts
|
|
30
|
+
var report_and_fix_exports = {};
|
|
31
|
+
__export(report_and_fix_exports, {
|
|
32
|
+
batchFixAll: () => batchFixAll,
|
|
33
|
+
generateInjectCodeToTopLevelFixFun: () => generateInjectCodeToTopLevelFixFun,
|
|
34
|
+
generateInjectHooksCallFixFun: () => generateInjectHooksCallFixFun,
|
|
35
|
+
generateInjectImportFixFun: () => generateInjectImportFixFun,
|
|
36
|
+
generateReplaceKeyFixFun: () => generateReplaceKeyFixFun
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(report_and_fix_exports);
|
|
39
|
+
var import_i18n_utils = require("./i18n_utils.js");
|
|
40
|
+
var import_key_map = __toESM(require("../../key_map.js"));
|
|
41
|
+
var keyMapper = import_key_map.default.getInstance();
|
|
42
|
+
function generateReplaceKeyFixFun(context, node, codeType) {
|
|
43
|
+
const { callMethodName } = context.settings.i18nInfo[codeType] || {};
|
|
44
|
+
if (!callMethodName) return null;
|
|
45
|
+
switch (node.type) {
|
|
46
|
+
case "TemplateLiteral":
|
|
47
|
+
return (fixer) => {
|
|
48
|
+
const str = node.quasis.map((q, index) => q.tail ? q.value.cooked : `${q.value.cooked}{arg${index + 1}}`).join("");
|
|
49
|
+
const key = keyMapper.generateKey(str);
|
|
50
|
+
const expressionsArr = node.expressions;
|
|
51
|
+
if (expressionsArr.length) {
|
|
52
|
+
const paramsStr = expressionsArr.map((i, index) => `arg${index + 1}: ${context.sourceCode.getText(i)}`).join(", ");
|
|
53
|
+
const value = context.sourceCode.getText(node);
|
|
54
|
+
const afterReplaceKey = value.replace(value.trim(), key);
|
|
55
|
+
const replaceStr2 = `${(0, import_i18n_utils.getI18nCallMethod)(callMethodName, afterReplaceKey, paramsStr)}`;
|
|
56
|
+
return fixer.replaceTextRange(node.range, replaceStr2);
|
|
57
|
+
}
|
|
58
|
+
const replaceStr = `${(0, import_i18n_utils.getI18nCallMethod)(callMethodName, key)}`;
|
|
59
|
+
return fixer.replaceTextRange(node.range, replaceStr);
|
|
60
|
+
};
|
|
61
|
+
case "Literal":
|
|
62
|
+
return (fixer) => {
|
|
63
|
+
const value = node.value;
|
|
64
|
+
const key = keyMapper.generateKey(value);
|
|
65
|
+
const str = node.parent.type === "JSXAttribute" ? `{ ${(0, import_i18n_utils.getI18nCallMethod)(callMethodName, key)} }` : `${(0, import_i18n_utils.getI18nCallMethod)(callMethodName, key)}`;
|
|
66
|
+
const replaceStr = value.replace(value.trim(), str);
|
|
67
|
+
return fixer.replaceTextRange(node.range, replaceStr);
|
|
68
|
+
};
|
|
69
|
+
case "JSXText":
|
|
70
|
+
return (fixer) => {
|
|
71
|
+
const value = node.value;
|
|
72
|
+
const key = keyMapper.generateKey(value);
|
|
73
|
+
return fixer.replaceTextRange(node.range, `{ ${(0, import_i18n_utils.getI18nCallMethod)(callMethodName, key)} }`);
|
|
74
|
+
};
|
|
75
|
+
default:
|
|
76
|
+
return () => null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function generateInjectImportFixFun(context, codeType) {
|
|
80
|
+
const { injectImport } = context.settings.i18nInfo[codeType] || {};
|
|
81
|
+
if (!injectImport) return null;
|
|
82
|
+
return (fixer) => {
|
|
83
|
+
const res = (0, import_i18n_utils.getLastImportOrFirstNotImportNode)(context);
|
|
84
|
+
if (!res) return null;
|
|
85
|
+
const { node: injectNode, type } = res;
|
|
86
|
+
const indent = (0, import_i18n_utils.getLeadingSpaces)(context, injectNode);
|
|
87
|
+
if (type === "firstNonImport") {
|
|
88
|
+
return fixer.insertTextBeforeRange(injectNode.range, `${injectImport}
|
|
89
|
+
${indent}`);
|
|
90
|
+
}
|
|
91
|
+
return fixer.insertTextAfterRange(injectNode.range, `
|
|
92
|
+
${indent}${injectImport}`);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function generateInjectHooksCallFixFun(context, node) {
|
|
96
|
+
const { injectHooksCall } = context.settings.i18nInfo["jsx"] || {};
|
|
97
|
+
if (!injectHooksCall) return null;
|
|
98
|
+
return function(fixer) {
|
|
99
|
+
const blockStatementNode = node.type === "FunctionDeclaration" ? node.body : node.init.body;
|
|
100
|
+
const injectNode = (0, import_i18n_utils.getInjectNode)(context, blockStatementNode);
|
|
101
|
+
const indent = (0, import_i18n_utils.getLeadingSpaces)(context, injectNode);
|
|
102
|
+
return fixer.insertTextBeforeRange(injectNode.range, `${injectHooksCall}
|
|
103
|
+
${indent}`);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function generateInjectCodeToTopLevelFixFun(context, codeType) {
|
|
107
|
+
const { injectCodeToTopLevel } = context.settings.i18nInfo[codeType] || {};
|
|
108
|
+
if (!injectCodeToTopLevel) return null;
|
|
109
|
+
return (fixer) => {
|
|
110
|
+
const res = (0, import_i18n_utils.getLastImportOrFirstNotImportNode)(context);
|
|
111
|
+
if (!res) return null;
|
|
112
|
+
const { node: injectNode, type } = res;
|
|
113
|
+
const indent = (0, import_i18n_utils.getLeadingSpaces)(context, injectNode);
|
|
114
|
+
if (type === "firstNonImport") {
|
|
115
|
+
return fixer.insertTextBeforeRange(injectNode.range, `${injectCodeToTopLevel}
|
|
116
|
+
${indent}`);
|
|
117
|
+
}
|
|
118
|
+
return fixer.insertTextAfterRange(injectNode.range, `
|
|
119
|
+
${indent}${injectCodeToTopLevel}`);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function batchFixAll(context, state) {
|
|
123
|
+
if (!state.inComponent.length && !state.outComponent.length) return;
|
|
124
|
+
const injectHasInjectCompOrHooksMap = /* @__PURE__ */ new Map();
|
|
125
|
+
const fixArr = [...state.inComponent, ...state.outComponent].map((item) => generateReplaceKeyFixFun(context, item.textNode, item.inComp ? "jsx" : "js"));
|
|
126
|
+
if (state.outComponent.length && (0, import_i18n_utils.canInject)(context, context.sourceCode.ast, "js")) {
|
|
127
|
+
fixArr.unshift(generateInjectImportFixFun(context, "js"));
|
|
128
|
+
fixArr.push(generateInjectCodeToTopLevelFixFun(context, "js"));
|
|
129
|
+
}
|
|
130
|
+
for (const { componentNode } of state.inComponent) {
|
|
131
|
+
const name = componentNode.id.name;
|
|
132
|
+
if (!injectHasInjectCompOrHooksMap.has(name) && (0, import_i18n_utils.canInject)(context, componentNode, "jsx")) {
|
|
133
|
+
fixArr.push(generateInjectHooksCallFixFun(context, componentNode));
|
|
134
|
+
injectHasInjectCompOrHooksMap.set(name, componentNode);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (injectHasInjectCompOrHooksMap.size) {
|
|
138
|
+
fixArr.unshift(generateInjectImportFixFun(context, "jsx"));
|
|
139
|
+
fixArr.push(generateInjectCodeToTopLevelFixFun(context, "jsx"));
|
|
140
|
+
}
|
|
141
|
+
const fixes = fixArr.filter((f) => f !== null);
|
|
142
|
+
if (!fixes.length) return;
|
|
143
|
+
context.report({
|
|
144
|
+
loc: context.sourceCode.ast.loc,
|
|
145
|
+
message: "存在中文字符,可以进行国际化替换",
|
|
146
|
+
fix: (fixer) => fixes.map((f) => f(fixer)).filter(Boolean)
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
150
|
+
0 && (module.exports = {
|
|
151
|
+
batchFixAll,
|
|
152
|
+
generateInjectCodeToTopLevelFixFun,
|
|
153
|
+
generateInjectHooksCallFixFun,
|
|
154
|
+
generateInjectImportFixFun,
|
|
155
|
+
generateReplaceKeyFixFun
|
|
156
|
+
});
|
|
@@ -0,0 +1,161 @@
|
|
|
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/eslint/vue/i18n_easy_plugin.ts
|
|
20
|
+
var i18n_easy_plugin_exports = {};
|
|
21
|
+
__export(i18n_easy_plugin_exports, {
|
|
22
|
+
default: () => i18n_easy_plugin_default
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(i18n_easy_plugin_exports);
|
|
25
|
+
var import_report_and_fix = require("./report_and_fix.js");
|
|
26
|
+
var import_i18n_utils = require("./i18n_utils.js");
|
|
27
|
+
var DiFF_FILE_JS_CODE_MAP = {
|
|
28
|
+
vue: "script",
|
|
29
|
+
js: "js",
|
|
30
|
+
jsx: "jsx",
|
|
31
|
+
ts: "js",
|
|
32
|
+
tsx: "jsx"
|
|
33
|
+
};
|
|
34
|
+
var VuePlugin = {
|
|
35
|
+
rules: {
|
|
36
|
+
"i18n-transform": {
|
|
37
|
+
meta: {
|
|
38
|
+
type: "problem",
|
|
39
|
+
messages: { hasChinese: "当前文件存在中文字符,可进行国际化替换" },
|
|
40
|
+
fixable: "code"
|
|
41
|
+
},
|
|
42
|
+
create(context) {
|
|
43
|
+
const fileType = context.settings.fileType;
|
|
44
|
+
const customIgnore = context.settings.customIgnore;
|
|
45
|
+
const state = {
|
|
46
|
+
templateTextNodeList: [],
|
|
47
|
+
scriptTextNodeList: [],
|
|
48
|
+
jsTextNodeList: [],
|
|
49
|
+
jsxTextNodeList: []
|
|
50
|
+
};
|
|
51
|
+
let inSetup = false;
|
|
52
|
+
let setupNode = null;
|
|
53
|
+
let isIgnored;
|
|
54
|
+
const enterSetup = (node) => {
|
|
55
|
+
setupNode = node;
|
|
56
|
+
inSetup = true;
|
|
57
|
+
};
|
|
58
|
+
const leaveSetup = () => {
|
|
59
|
+
setupNode = null;
|
|
60
|
+
inSetup = false;
|
|
61
|
+
};
|
|
62
|
+
const collectNodes = (textNode, codeType) => {
|
|
63
|
+
if (customIgnore == null ? void 0 : customIgnore(textNode, context)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!(0, import_i18n_utils.canCollectOperateNodes)(textNode, isIgnored)) return;
|
|
67
|
+
switch (codeType) {
|
|
68
|
+
case "template":
|
|
69
|
+
state.templateTextNodeList.push({ textNode, setUpNode: null, inSetup: false, codeType });
|
|
70
|
+
break;
|
|
71
|
+
case "script":
|
|
72
|
+
state.scriptTextNodeList.push({ textNode, setUpNode: inSetup ? setupNode : null, inSetup, codeType });
|
|
73
|
+
break;
|
|
74
|
+
case "js":
|
|
75
|
+
state.jsTextNodeList.push({ textNode, setUpNode: null, inSetup: false, codeType });
|
|
76
|
+
break;
|
|
77
|
+
case "jsx":
|
|
78
|
+
state.jsxTextNodeList.push({ textNode, setUpNode: inSetup ? setupNode : null, inSetup, codeType });
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const collectTemplateChineseTextNodeVisitor = {
|
|
83
|
+
// 文本节点
|
|
84
|
+
VText(node) {
|
|
85
|
+
collectNodes(node, "template");
|
|
86
|
+
},
|
|
87
|
+
// 属性节点
|
|
88
|
+
VAttribute(node) {
|
|
89
|
+
collectNodes(node, "template");
|
|
90
|
+
},
|
|
91
|
+
// 模板字符串节点
|
|
92
|
+
TemplateLiteral(node) {
|
|
93
|
+
collectNodes(node, "template");
|
|
94
|
+
},
|
|
95
|
+
// 字面量节点
|
|
96
|
+
Literal(node) {
|
|
97
|
+
collectNodes(node, "template");
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const collectScriptChineseTextNodeVisitor = {
|
|
101
|
+
// 字面量节点
|
|
102
|
+
Literal(node) {
|
|
103
|
+
collectNodes(node, DiFF_FILE_JS_CODE_MAP[fileType]);
|
|
104
|
+
},
|
|
105
|
+
// 模版字符串节点
|
|
106
|
+
TemplateLiteral(node) {
|
|
107
|
+
collectNodes(node, DiFF_FILE_JS_CODE_MAP[fileType]);
|
|
108
|
+
},
|
|
109
|
+
// JSX文本节点
|
|
110
|
+
JSXText(node) {
|
|
111
|
+
collectNodes(node, DiFF_FILE_JS_CODE_MAP[fileType]);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const replaceNodeAndInjectCodeVisitor = {
|
|
115
|
+
/**
|
|
116
|
+
* 进入时
|
|
117
|
+
* 1、记录@i18n-ignore注释所在行号
|
|
118
|
+
* 2、如果是vue文件,判断是否是否存在setup函数(如果存在,记录setup函数节点)
|
|
119
|
+
*/
|
|
120
|
+
Program: function(node) {
|
|
121
|
+
isIgnored = (0, import_i18n_utils.createI18nIgnoreChecker)(context, node.templateBody);
|
|
122
|
+
if (fileType === "vue" && (0, import_i18n_utils.isScriptSetup)(context)) {
|
|
123
|
+
enterSetup(node);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
// 选择器匹配setup函数节点
|
|
127
|
+
'ExportDefaultDeclaration > ObjectExpression > Property[key.name="setup"] > :function': function(node) {
|
|
128
|
+
if (fileType === "vue" || fileType === "jsx") {
|
|
129
|
+
enterSetup(node);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
'ExportDefaultDeclaration > ObjectExpression > Property[key.name="setup"] > :function:exit': leaveSetup,
|
|
133
|
+
'ExportDefaultDeclaration > CallExpression[callee.name="defineComponent"] > ObjectExpression > Property[key.name="setup"] > :function': function(node) {
|
|
134
|
+
if (fileType === "vue" || fileType === "jsx") {
|
|
135
|
+
enterSetup(node);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
'ExportDefaultDeclaration > CallExpression[callee.name="defineComponent"] > ObjectExpression > Property[key.name="setup"] > :function:exit': leaveSetup,
|
|
139
|
+
/**
|
|
140
|
+
* 退出时,批量进行修复
|
|
141
|
+
*/
|
|
142
|
+
"Program:exit": async function() {
|
|
143
|
+
(0, import_report_and_fix.batchFixAll)(context, state);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor(
|
|
147
|
+
collectTemplateChineseTextNodeVisitor,
|
|
148
|
+
{
|
|
149
|
+
...collectScriptChineseTextNodeVisitor,
|
|
150
|
+
...replaceNodeAndInjectCodeVisitor
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
templateBodyTriggerSelector: "Program"
|
|
154
|
+
// 执行顺序 Program -> templateBodyVisitor -> scriptBodyVisitor -> Program:exit
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
var i18n_easy_plugin_default = VuePlugin;
|