vue-i18n-extract-plugin 1.0.51 → 1.0.53
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 +18 -0
- package/lib/extract.js +8 -3
- package/lib/options.js +1 -0
- package/lib/visitors.js +38 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,7 @@ const defaultOptions = {
|
|
|
53
53
|
autoImportI18n: true, // 是否自动导入 i18n 模块
|
|
54
54
|
autoTranslate: true, // 提取完成后是否自动翻译
|
|
55
55
|
cleanTranslate: true, // 是否清理无用的翻译内容
|
|
56
|
+
keepRaw: false, // 开启后只做转换不生成hash值,即:"测试" -> $t("测试"), 开启rewrite时生效
|
|
56
57
|
enabled: true, // 是否启用插件
|
|
57
58
|
outputJsonFileInPlugin: true, // 是否在插件中输出 JSON 文件
|
|
58
59
|
outputJsonFileDebounceTimeInPlugin: 2000, // 输出 JSON 文件的防抖时间
|
|
@@ -98,6 +99,18 @@ export default {
|
|
|
98
99
|
}),
|
|
99
100
|
...
|
|
100
101
|
};
|
|
102
|
+
|
|
103
|
+
// ts支持
|
|
104
|
+
import { defineConfig } from "vite-i18n-extract-plugin";
|
|
105
|
+
|
|
106
|
+
export default defineConfig({
|
|
107
|
+
rewrite: false,
|
|
108
|
+
translator: new YoudaoTranslator({
|
|
109
|
+
appId: "youdao appId",
|
|
110
|
+
appKey: "youdao appKey"
|
|
111
|
+
}),
|
|
112
|
+
...
|
|
113
|
+
});
|
|
101
114
|
```
|
|
102
115
|
|
|
103
116
|
## Vite plugin
|
|
@@ -145,6 +158,8 @@ import enMessages from "@/locales/en.json";
|
|
|
145
158
|
|
|
146
159
|
const i18n = createI18n({
|
|
147
160
|
legacy: false,
|
|
161
|
+
globalInjection: true,
|
|
162
|
+
allowComposition: true,
|
|
148
163
|
fallbackLocale: "en",
|
|
149
164
|
locale: "zh",
|
|
150
165
|
messages: {
|
|
@@ -156,6 +171,9 @@ const i18n = createI18n({
|
|
|
156
171
|
// 导出一个$t方法
|
|
157
172
|
export const $t = i18n.global.t.bind(i18n.global);
|
|
158
173
|
|
|
174
|
+
// 建议在全局也挂载一个$t方法做兜底
|
|
175
|
+
globalThis.$t = $t;
|
|
176
|
+
|
|
159
177
|
export default i18n;
|
|
160
178
|
```
|
|
161
179
|
|
package/lib/extract.js
CHANGED
|
@@ -30,6 +30,11 @@ const { autoTranslate, cleanTranslate, cleanI18nMap } = require("./translate");
|
|
|
30
30
|
const { i18nImportAstTransform } = require("./import-i18n-transform");
|
|
31
31
|
|
|
32
32
|
let globalI18nMap = {};
|
|
33
|
+
const keepRawTextOptions = {
|
|
34
|
+
jsescOption: {
|
|
35
|
+
minimal: true // 保留原始字符串,不被转义成Unicode
|
|
36
|
+
}
|
|
37
|
+
};
|
|
33
38
|
|
|
34
39
|
function encodeToString(str) {
|
|
35
40
|
return str.indexOf("'") === -1 ? `'${str}'` : `"${str}"`;
|
|
@@ -68,7 +73,7 @@ function unwrapTransformedCode(ast) {
|
|
|
68
73
|
});
|
|
69
74
|
|
|
70
75
|
if (extractedNode) {
|
|
71
|
-
const { code: exprCode } = generate(extractedNode);
|
|
76
|
+
const { code: exprCode } = generate(extractedNode, keepRawTextOptions);
|
|
72
77
|
return exprCode;
|
|
73
78
|
} else {
|
|
74
79
|
console.warn("未能提取到 _expr 表达式");
|
|
@@ -118,7 +123,7 @@ function extractTCallsFromInterpolation(code, options, i18nMap) {
|
|
|
118
123
|
traverse(program, createI18nVisitor(options, i18nMap));
|
|
119
124
|
|
|
120
125
|
if (options.rewrite) {
|
|
121
|
-
return generate(ast, { compact: true }).code;
|
|
126
|
+
return generate(ast, { compact: true, ...keepRawTextOptions }).code;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
// return ast;
|
|
@@ -252,7 +257,7 @@ function transformScript(code, options, useAst, i18nMap) {
|
|
|
252
257
|
}
|
|
253
258
|
return {
|
|
254
259
|
changed: true,
|
|
255
|
-
code: generate(ast, { retainLines: true }).code
|
|
260
|
+
code: generate(ast, { retainLines: true, ...keepRawTextOptions }).code
|
|
256
261
|
};
|
|
257
262
|
}
|
|
258
263
|
|
package/lib/options.js
CHANGED
|
@@ -7,6 +7,7 @@ const defaultOptions = {
|
|
|
7
7
|
autoImportI18n: true, // 是否自动导入 i18n 模块
|
|
8
8
|
autoTranslate: true, // 提取完成后是否自动翻译
|
|
9
9
|
cleanTranslate: true, // 是否清理无用的翻译内容
|
|
10
|
+
keepRaw: false, // 开启后只做转换不生成hash值,即:"测试" -> $t("测试"), 开启rewrite时生效
|
|
10
11
|
enabled: true, // 是否启用插件
|
|
11
12
|
outputJsonFileInPlugin: true, // 是否在插件中输出 JSON 文件
|
|
12
13
|
outputJsonFileDebounceTimeInPlugin: 2000, // 输出 JSON 文件的防抖时间
|
package/lib/visitors.js
CHANGED
|
@@ -15,16 +15,16 @@ function isTFunction(node, option) {
|
|
|
15
15
|
);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function
|
|
18
|
+
function isVNodeCall(path, nodeName) {
|
|
19
19
|
const node = path.node;
|
|
20
20
|
if (!path.isCallExpression()) return false;
|
|
21
21
|
|
|
22
22
|
const callee = node.callee;
|
|
23
23
|
return (
|
|
24
|
-
(t.isIdentifier(callee) && callee.name ===
|
|
24
|
+
(t.isIdentifier(callee) && callee.name === nodeName) ||
|
|
25
25
|
(t.isMemberExpression(callee) &&
|
|
26
26
|
t.isIdentifier(callee.property) &&
|
|
27
|
-
callee.property.name ===
|
|
27
|
+
callee.property.name === nodeName)
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -106,6 +106,13 @@ function shouldTransform(path) {
|
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
function generateText(rawText, hashedText, options) {
|
|
110
|
+
if (options.keepRaw && options.rewrite) {
|
|
111
|
+
return rawText;
|
|
112
|
+
}
|
|
113
|
+
return hashedText;
|
|
114
|
+
}
|
|
115
|
+
|
|
109
116
|
function createI18nVisitor(option, i18nMap) {
|
|
110
117
|
const excludedCall = [...option.excludedCall, ...EXCLUDED_CALL];
|
|
111
118
|
|
|
@@ -130,15 +137,13 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
130
137
|
return;
|
|
131
138
|
}
|
|
132
139
|
|
|
133
|
-
// console.log("CallExpression", path.node.arguments);
|
|
134
|
-
|
|
135
140
|
const hashed = generateId(keyText);
|
|
136
141
|
|
|
137
142
|
if (i18nMap) {
|
|
138
143
|
i18nMap[hashed] = keyText;
|
|
139
144
|
}
|
|
140
145
|
|
|
141
|
-
const newArg = t.stringLiteral(hashed);
|
|
146
|
+
const newArg = t.stringLiteral(generateText(keyText, hashed, option));
|
|
142
147
|
path.node.arguments[0] = newArg;
|
|
143
148
|
},
|
|
144
149
|
|
|
@@ -182,46 +187,46 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
182
187
|
return;
|
|
183
188
|
}
|
|
184
189
|
|
|
185
|
-
// console.log("StringLiteral", value);
|
|
186
|
-
|
|
187
190
|
const hashed = generateId(value);
|
|
188
191
|
|
|
189
192
|
if (i18nMap) {
|
|
190
193
|
i18nMap[hashed] = value;
|
|
191
194
|
}
|
|
192
195
|
|
|
193
|
-
|
|
196
|
+
// 生成 _ctx.$t("hashed")
|
|
197
|
+
let callExpression = t.callExpression(
|
|
198
|
+
t.memberExpression(
|
|
199
|
+
t.identifier("_ctx"),
|
|
200
|
+
t.identifier(option.translateKey)
|
|
201
|
+
),
|
|
202
|
+
[t.stringLiteral(generateText(value, hashed, option))]
|
|
203
|
+
);
|
|
194
204
|
|
|
195
205
|
// 判断是否createTextVNode或MemberExpression(如 Vue.createTextVNode)
|
|
196
|
-
if (
|
|
197
|
-
// _ctx.$t("hashed")
|
|
198
|
-
callExpression = t.callExpression(
|
|
199
|
-
t.memberExpression(
|
|
200
|
-
t.identifier("_ctx"),
|
|
201
|
-
t.identifier(option.translateKey)
|
|
202
|
-
),
|
|
203
|
-
[t.stringLiteral(hashed)]
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
+
if (isVNodeCall(parentPath, "_createTextVNode")) {
|
|
206
207
|
// 如果 createTextVNode 参数只有一个,则补充第二个参数 1
|
|
207
208
|
const args = parentPath.node.arguments;
|
|
208
209
|
if (args.length === 1) {
|
|
209
210
|
parentPath.node.arguments = [callExpression, t.numericLiteral(1)];
|
|
210
211
|
}
|
|
212
|
+
// 是否 vue.createElementVNode(...),且该 StringLiteral 是第三个参数
|
|
213
|
+
} else if (isVNodeCall(parentPath, "_createElementVNode")) {
|
|
214
|
+
const callExpr = parentPath.node;
|
|
215
|
+
const args = callExpr.arguments;
|
|
216
|
+
|
|
217
|
+
// 当前是第三个参数,且参数数量为3
|
|
218
|
+
const argIndex = args.findIndex(arg => arg === path.node);
|
|
219
|
+
if (argIndex === 2 && args.length === 3) {
|
|
220
|
+
args[2] = callExpression; // 替换第3个参数
|
|
221
|
+
args.push(t.numericLiteral(1)); // 添加第4个参数
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
211
224
|
} else {
|
|
212
225
|
const hasCreateVNode = transformDirectiveIfNeeded(path, parentPath);
|
|
213
|
-
if (hasCreateVNode) {
|
|
214
|
-
|
|
215
|
-
t.memberExpression(
|
|
216
|
-
t.identifier("_ctx"),
|
|
217
|
-
t.identifier(option.translateKey)
|
|
218
|
-
),
|
|
219
|
-
[t.stringLiteral(hashed)]
|
|
220
|
-
);
|
|
221
|
-
} else {
|
|
222
|
-
// $t("hashed")
|
|
226
|
+
if (!hasCreateVNode) {
|
|
227
|
+
// 生成 $t("hashed")
|
|
223
228
|
callExpression = t.callExpression(t.identifier(option.translateKey), [
|
|
224
|
-
t.stringLiteral(hashed)
|
|
229
|
+
t.stringLiteral(generateText(value, hashed, option))
|
|
225
230
|
]);
|
|
226
231
|
}
|
|
227
232
|
}
|
|
@@ -262,8 +267,6 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
262
267
|
|
|
263
268
|
if (option.extractFromText === false) return;
|
|
264
269
|
|
|
265
|
-
// console.log("TemplateElement", value);
|
|
266
|
-
|
|
267
270
|
const hashed = generateId(value);
|
|
268
271
|
|
|
269
272
|
if (i18nMap) {
|
|
@@ -271,7 +274,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
271
274
|
}
|
|
272
275
|
|
|
273
276
|
// 替换为字符类型翻译节点
|
|
274
|
-
const tCallExpression = `${option.translateKey}('${hashed}')`;
|
|
277
|
+
const tCallExpression = `${option.translateKey}('${generateText(value, hashed, option)}')`;
|
|
275
278
|
node.value.raw = node.value.cooked = `\${${tCallExpression}}`;
|
|
276
279
|
},
|
|
277
280
|
JSXText(path) {
|
|
@@ -285,8 +288,6 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
285
288
|
return;
|
|
286
289
|
}
|
|
287
290
|
|
|
288
|
-
// console.log("JSXText", path.node.value);
|
|
289
|
-
|
|
290
291
|
const hashed = generateId(text);
|
|
291
292
|
|
|
292
293
|
if (i18nMap) {
|
|
@@ -297,7 +298,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
297
298
|
path.replaceWith(
|
|
298
299
|
t.jsxExpressionContainer(
|
|
299
300
|
t.callExpression(t.identifier(option.translateKey), [
|
|
300
|
-
t.stringLiteral(hashed)
|
|
301
|
+
t.stringLiteral(generateText(text, hashed, option))
|
|
301
302
|
])
|
|
302
303
|
)
|
|
303
304
|
);
|
|
@@ -315,8 +316,6 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
315
316
|
return;
|
|
316
317
|
}
|
|
317
318
|
|
|
318
|
-
// console.log("JSXExpressionContainer", path.node.expression.expr);
|
|
319
|
-
|
|
320
319
|
const hashed = generateId(value);
|
|
321
320
|
|
|
322
321
|
if (i18nMap) {
|
|
@@ -326,7 +325,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
326
325
|
path.replaceWith(
|
|
327
326
|
t.jsxExpressionContainer(
|
|
328
327
|
t.callExpression(t.identifier(option.translateKey), [
|
|
329
|
-
t.stringLiteral(hashed)
|
|
328
|
+
t.stringLiteral(generateText(value, hashed, option))
|
|
330
329
|
])
|
|
331
330
|
)
|
|
332
331
|
);
|