vue-i18n-extract-plugin 1.0.78 → 1.0.80
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/.vscode/settings.json +20 -0
- package/README.md +3 -0
- package/lib/babel-plugin-import-i18n.js +8 -2
- package/lib/extract.js +9 -3
- package/lib/options.js +13 -1
- package/lib/translate.js +2 -1
- package/lib/translators/translator/Translator.js +8 -2
- package/lib/translators/volcengine.js +16 -2
- package/lib/visitors.js +145 -18
- package/lib/vite-plugin-import-i18n.js +5 -3
- package/lib/webpack-import-i18n-loader.js +8 -2
- package/package.json +1 -1
- package/types/options.d.ts +35 -29
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.formatOnSave": true,
|
|
3
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
4
|
+
"[javascript]": {
|
|
5
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
6
|
+
},
|
|
7
|
+
"[typescriptreact]": {
|
|
8
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
9
|
+
},
|
|
10
|
+
"[vue]": {
|
|
11
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
12
|
+
},
|
|
13
|
+
"editor.codeActionsOnSave": {
|
|
14
|
+
"source.fixAll": "explicit",
|
|
15
|
+
"source.fixAll.eslint": "explicit",
|
|
16
|
+
"source.fixAll.stylelint": "explicit",
|
|
17
|
+
"source.organizeImports": "never"
|
|
18
|
+
},
|
|
19
|
+
"cSpell.words": []
|
|
20
|
+
}
|
package/README.md
CHANGED
|
@@ -48,7 +48,9 @@ extractI18n(options)
|
|
|
48
48
|
```javascript
|
|
49
49
|
const defaultOptions = {
|
|
50
50
|
translateKey: "$t", // 提取的函数的名称
|
|
51
|
+
useTranslationIdentifier: "useTranslation", // 注入到组件的hook名称, 会注入const { $t } = useTranslation()
|
|
51
52
|
JSXElement: "Trans", // 提取的函数的 JSX 元素名称 默认为 Trans, 如:<Trans id="aaa" msg="xxx" />
|
|
53
|
+
injectUseTranslation: true, // 是否自动注入 useTranslation
|
|
52
54
|
jsx: false, // 是否启用 JSX 语法转换,开启后JSX里纯文件将转换为 <Trans id="aaa" msg="xxx" />而不是 $t("aaa")
|
|
53
55
|
rewrite: false, // 是否将提取到的内容转换为id后重写入源文件
|
|
54
56
|
extractFromText: true, // 是否允许从纯文本节点中提取翻译内容
|
|
@@ -70,6 +72,7 @@ const defaultOptions = {
|
|
|
70
72
|
i18nPkgImportPath: "@/i18n", // i18n语言包导入路径
|
|
71
73
|
outputPath: "src/i18n", // 提取的语言包输出文件路径
|
|
72
74
|
generateId: null, // 自定义生成 key 的函数
|
|
75
|
+
shouldExtract: null, // 自定义是否提取文件的函数
|
|
73
76
|
customGenLangFileName: langKey => langKey, // 自定义生成语言文件名
|
|
74
77
|
// 翻译后的文本处理函数,方便对翻译后的文本进行二次加工,如每个单词首字母大写, params: text: 翻译后的文本, toLang: 翻译后的目标语言,translateLangKeys的枚举成员
|
|
75
78
|
customTranslatedText: (text, toLang) => text,
|
|
@@ -12,7 +12,9 @@ module.exports = function () {
|
|
|
12
12
|
JSXElement,
|
|
13
13
|
jsx,
|
|
14
14
|
enabled,
|
|
15
|
-
autoImportI18n
|
|
15
|
+
autoImportI18n,
|
|
16
|
+
injectUseTranslation,
|
|
17
|
+
useTranslationIdentifier
|
|
16
18
|
} = {
|
|
17
19
|
...defaultOptions,
|
|
18
20
|
...state.opts
|
|
@@ -21,7 +23,11 @@ module.exports = function () {
|
|
|
21
23
|
if (!enabled || !autoImportI18n) return;
|
|
22
24
|
|
|
23
25
|
const ast = path.parentPath?.node || path.node;
|
|
24
|
-
const importNames = jsx
|
|
26
|
+
const importNames = jsx
|
|
27
|
+
? [importName, JSXElement]
|
|
28
|
+
: injectUseTranslation
|
|
29
|
+
? [importName, useTranslationIdentifier]
|
|
30
|
+
: [importName];
|
|
25
31
|
|
|
26
32
|
for (const importName of importNames) {
|
|
27
33
|
i18nImportAstTransform(ast, importName, importPath);
|
package/lib/extract.js
CHANGED
|
@@ -173,7 +173,9 @@ function createDirectiveFromProp(prop, content) {
|
|
|
173
173
|
function addI18nImportIfNeeded(ast, options, generateCode) {
|
|
174
174
|
const importNames = options.jsx
|
|
175
175
|
? [options.translateKey, options.JSXElement]
|
|
176
|
-
:
|
|
176
|
+
: options.injectUseTranslation
|
|
177
|
+
? [options.translateKey, options.useTranslationIdentifier]
|
|
178
|
+
: [options.translateKey];
|
|
177
179
|
|
|
178
180
|
for (const importName of importNames) {
|
|
179
181
|
i18nImportAstTransform(ast, importName, options.i18nPkgImportPath);
|
|
@@ -274,6 +276,10 @@ function transformScript(code, options, useAst, i18nMap) {
|
|
|
274
276
|
};
|
|
275
277
|
}
|
|
276
278
|
|
|
279
|
+
function _shouldExtract(text, options) {
|
|
280
|
+
return (options.shouldExtract || shouldExtract)(text, options.fromLang);
|
|
281
|
+
}
|
|
282
|
+
|
|
277
283
|
function transformTemplate(templateContent, options) {
|
|
278
284
|
const innerI18nMap = {};
|
|
279
285
|
let magicString;
|
|
@@ -363,7 +369,7 @@ function transformTemplate(templateContent, options) {
|
|
|
363
369
|
if (
|
|
364
370
|
text &&
|
|
365
371
|
typeof text === "string" &&
|
|
366
|
-
|
|
372
|
+
_shouldExtract(text, options)
|
|
367
373
|
) {
|
|
368
374
|
try {
|
|
369
375
|
const newValue = transformScriptExpression(
|
|
@@ -400,7 +406,7 @@ function transformTemplate(templateContent, options) {
|
|
|
400
406
|
if (
|
|
401
407
|
text &&
|
|
402
408
|
typeof text === "string" &&
|
|
403
|
-
|
|
409
|
+
_shouldExtract(text, options)
|
|
404
410
|
) {
|
|
405
411
|
try {
|
|
406
412
|
const newValue = extractTCallsFromInterpolation(
|
package/lib/options.js
CHANGED
|
@@ -2,7 +2,9 @@ const { GoogleTranslator } = require("./translators");
|
|
|
2
2
|
|
|
3
3
|
const defaultOptions = {
|
|
4
4
|
translateKey: "$t", // 提取的函数的名称
|
|
5
|
+
useTranslationIdentifier: "useTranslation", // 注入到组件的hook名称, 会注入const { $t } = useTranslation()
|
|
5
6
|
JSXElement: "Trans", // 提取的函数的 JSX 元素名称 默认为 Trans, 如:<Trans id="aaa" msg="xxx" />
|
|
7
|
+
injectUseTranslation: false, // 是否自动注入 useTranslation
|
|
6
8
|
jsx: false, // 是否启用 JSX 语法转换,开启后JSX里纯文件将转换为 <Trans id="aaa" msg="xxx" />而不是 $t("aaa")
|
|
7
9
|
rewrite: false, // 是否将提取到的内容转换为id后重写入源文件
|
|
8
10
|
extractFromText: true, // 是否允许从纯文本节点中提取翻译内容
|
|
@@ -18,12 +20,22 @@ const defaultOptions = {
|
|
|
18
20
|
excludedCall: [], // 排除的调用函数名称数组
|
|
19
21
|
includePath: ["src/"], // 包含路径的数组
|
|
20
22
|
excludedPath: [], // 排除路径的数组
|
|
21
|
-
allowedExtensions: [
|
|
23
|
+
allowedExtensions: [
|
|
24
|
+
".vue",
|
|
25
|
+
".nvue",
|
|
26
|
+
".uvue",
|
|
27
|
+
".tsx",
|
|
28
|
+
".ts",
|
|
29
|
+
".jsx",
|
|
30
|
+
".js",
|
|
31
|
+
".uts"
|
|
32
|
+
], // 允许提取的文件扩展名
|
|
22
33
|
fromLang: "zh-cn", // 源语言, 目前支持提取的语言有:zh-cn(zh-tw), en, ja, ko, ru
|
|
23
34
|
translateLangKeys: ["zh-tw", "en"], // 需要翻译为的语言键
|
|
24
35
|
i18nPkgImportPath: "@/i18n", // i18n语言包导入路径
|
|
25
36
|
outputPath: "src/i18n", // 提取的语言包输出文件路径
|
|
26
37
|
generateId: null, // 自定义生成 key 的函数
|
|
38
|
+
shouldExtract: null, // 自定义是否提取文件的函数
|
|
27
39
|
customGenLangFileName: langKey => langKey, // 自定义生成语言文件名
|
|
28
40
|
// 翻译后的文本处理函数,方便对翻译后的文本进行二次加工,如每个单词首字母大写, params: text: 翻译后的文本, toLang: 翻译后的目标语言,translateLangKeys的枚举成员
|
|
29
41
|
customTranslatedText: (text, toLang) => text,
|
package/lib/translate.js
CHANGED
|
@@ -46,10 +46,16 @@ class Translator {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
async translate(text, fromKey, toKey, separator) {
|
|
49
|
+
async translate(text, fromKey, toKey, separator, customGenerateId) {
|
|
50
50
|
let result = "";
|
|
51
51
|
try {
|
|
52
|
-
result = await this.option.fetchMethod(
|
|
52
|
+
result = await this.option.fetchMethod(
|
|
53
|
+
text,
|
|
54
|
+
fromKey,
|
|
55
|
+
toKey,
|
|
56
|
+
separator,
|
|
57
|
+
customGenerateId
|
|
58
|
+
);
|
|
53
59
|
} catch (error) {
|
|
54
60
|
this.option.onError(error, this.defaultErrorHandler);
|
|
55
61
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// 代码灵感来自https://github.com/dadidi9900/auto-plugins-json-translate/blob/main/src/services/translationService.ts
|
|
2
2
|
const axios = require("axios");
|
|
3
|
-
const { generateId } = require("../utils");
|
|
3
|
+
const { generateId: _generateId } = require("../utils");
|
|
4
4
|
const { Translator } = require("./translator");
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -25,9 +25,23 @@ class VolcEngineTranslator extends Translator {
|
|
|
25
25
|
constructor(option = {}) {
|
|
26
26
|
super({
|
|
27
27
|
name: "火山引擎ai翻译",
|
|
28
|
-
fetchMethod: async (
|
|
28
|
+
fetchMethod: async (
|
|
29
|
+
text,
|
|
30
|
+
fromKey,
|
|
31
|
+
toKey,
|
|
32
|
+
separator,
|
|
33
|
+
customGenerateId
|
|
34
|
+
) => {
|
|
29
35
|
let salt = new Date().getTime();
|
|
30
36
|
const textArr = text.split(separator);
|
|
37
|
+
|
|
38
|
+
const generateId = text => {
|
|
39
|
+
if (typeof customGenerateId === "function") {
|
|
40
|
+
return customGenerateId(text, _generateId);
|
|
41
|
+
}
|
|
42
|
+
return _generateId(text);
|
|
43
|
+
};
|
|
44
|
+
|
|
31
45
|
const sourceMap = Object.fromEntries(
|
|
32
46
|
textArr.map(text => [generateId(text), text])
|
|
33
47
|
);
|
package/lib/visitors.js
CHANGED
|
@@ -3,7 +3,7 @@ const {
|
|
|
3
3
|
generateId: _generateId,
|
|
4
4
|
extractFunctionName,
|
|
5
5
|
EXCLUDED_CALL,
|
|
6
|
-
shouldExtract
|
|
6
|
+
shouldExtract: _shouldExtract
|
|
7
7
|
} = require("./utils");
|
|
8
8
|
|
|
9
9
|
function isTFunction(node, option) {
|
|
@@ -18,10 +18,8 @@ function isTFunction(node, option) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function isVNodeCall(path, nodeName) {
|
|
21
|
-
const node = path.node;
|
|
22
21
|
if (!path.isCallExpression()) return false;
|
|
23
|
-
|
|
24
|
-
const callee = node.callee;
|
|
22
|
+
const callee = path.node.callee;
|
|
25
23
|
return (
|
|
26
24
|
(t.isIdentifier(callee) && callee.name === nodeName) ||
|
|
27
25
|
(t.isMemberExpression(callee) &&
|
|
@@ -56,7 +54,23 @@ function getPropKey(propNode) {
|
|
|
56
54
|
return null;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
|
|
57
|
+
/**
|
|
58
|
+
* 向 hoisted dynamicProps 数组中追加 propKey(若不存在)
|
|
59
|
+
* @returns 是否真的发生了修改
|
|
60
|
+
*/
|
|
61
|
+
function pushDynamicPropsIfMissing(arr, propKey) {
|
|
62
|
+
const hasKey = arr.elements.some(
|
|
63
|
+
el => t.isStringLiteral(el) && el.value === propKey
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (!hasKey) {
|
|
67
|
+
arr.elements.push(t.stringLiteral(propKey));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return !hasKey;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 自动补齐动态属性,如 createVNode(c, {message: dynamicValue}) => createVNode(c, {message: dynamicValue}, null, 8, ['message'])
|
|
60
74
|
function transformDirectiveIfNeeded(path, parentPath) {
|
|
61
75
|
let hasCreateVNode = false;
|
|
62
76
|
// 属性值情况,如 title: "xxx"
|
|
@@ -67,10 +81,7 @@ function transformDirectiveIfNeeded(path, parentPath) {
|
|
|
67
81
|
|
|
68
82
|
const vNodeCall = path.findParent(
|
|
69
83
|
p =>
|
|
70
|
-
p
|
|
71
|
-
(t.isIdentifier(p.node.callee, { name: "_createVNode" }) ||
|
|
72
|
-
(t.isMemberExpression(p.node.callee) &&
|
|
73
|
-
t.isIdentifier(p.node.callee.property, { name: "_createVNode" })))
|
|
84
|
+
isVNodeCall(p, "_createVNode") || isVNodeCall(p, "_createElementVNode")
|
|
74
85
|
);
|
|
75
86
|
|
|
76
87
|
if (vNodeCall) {
|
|
@@ -91,13 +102,23 @@ function transformDirectiveIfNeeded(path, parentPath) {
|
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
// 设置 patchFlag = 8
|
|
94
|
-
args[patchFlagIndex]
|
|
105
|
+
if (!args[patchFlagIndex]) {
|
|
106
|
+
args[patchFlagIndex] = t.numericLiteral(8);
|
|
107
|
+
}
|
|
95
108
|
|
|
96
109
|
// 设置 dynamicProps = ["propKey"]
|
|
97
110
|
const existingDynamicProps = args[dynamicPropsIndex];
|
|
98
|
-
|
|
111
|
+
|
|
112
|
+
if (t.isIdentifier(existingDynamicProps)) {
|
|
113
|
+
const arr = hoistedMap.get(existingDynamicProps.name);
|
|
114
|
+
if (arr) {
|
|
115
|
+
pushDynamicPropsIfMissing(arr, propKey);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!existingDynamicProps) {
|
|
99
120
|
args[dynamicPropsIndex] = t.arrayExpression([t.stringLiteral(propKey)]);
|
|
100
|
-
} else {
|
|
121
|
+
} else if (t.isArrayExpression(existingDynamicProps)) {
|
|
101
122
|
const existingKeys = new Set(
|
|
102
123
|
existingDynamicProps.elements
|
|
103
124
|
.filter(el => t.isStringLiteral(el))
|
|
@@ -134,7 +155,7 @@ function generateText(rawText, hashedText, options) {
|
|
|
134
155
|
|
|
135
156
|
function generateId(rawText, options) {
|
|
136
157
|
if (typeof options.generateId === "function") {
|
|
137
|
-
return options.generateId(rawText);
|
|
158
|
+
return options.generateId(rawText, _generateId);
|
|
138
159
|
}
|
|
139
160
|
return _generateId(rawText);
|
|
140
161
|
}
|
|
@@ -284,10 +305,95 @@ function isAnyVNodeCall(path) {
|
|
|
284
305
|
return false;
|
|
285
306
|
}
|
|
286
307
|
|
|
308
|
+
function markComponentUsesI18n(path) {
|
|
309
|
+
const fnPath = path.findParent(
|
|
310
|
+
p =>
|
|
311
|
+
p.isFunctionDeclaration() ||
|
|
312
|
+
p.isFunctionExpression() ||
|
|
313
|
+
p.isArrowFunctionExpression()
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
if (!fnPath) return;
|
|
317
|
+
|
|
318
|
+
fnPath.node.__usesI18n = true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function createUseTranslationDeclaration(options) {
|
|
322
|
+
return t.variableDeclaration("const", [
|
|
323
|
+
t.variableDeclarator(
|
|
324
|
+
t.objectPattern([
|
|
325
|
+
t.objectProperty(
|
|
326
|
+
t.identifier(options.translateKey),
|
|
327
|
+
t.identifier(options.translateKey),
|
|
328
|
+
false,
|
|
329
|
+
true
|
|
330
|
+
)
|
|
331
|
+
]),
|
|
332
|
+
t.callExpression(t.identifier(options.useTranslationIdentifier), [])
|
|
333
|
+
)
|
|
334
|
+
]);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function injectUseTranslation(fnPath, options) {
|
|
338
|
+
const body = fnPath.get("body");
|
|
339
|
+
|
|
340
|
+
if (!body.isBlockStatement()) {
|
|
341
|
+
// ArrowFunctionExpression 简写:() => <div />
|
|
342
|
+
body.replaceWith(
|
|
343
|
+
t.blockStatement([
|
|
344
|
+
createUseTranslationDeclaration(options),
|
|
345
|
+
t.returnStatement(body.node)
|
|
346
|
+
])
|
|
347
|
+
);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const statements = body.get("body");
|
|
352
|
+
|
|
353
|
+
// 已经存在 useTranslationss
|
|
354
|
+
if (
|
|
355
|
+
statements.some(
|
|
356
|
+
s =>
|
|
357
|
+
s.isVariableDeclaration() &&
|
|
358
|
+
s.node.declarations.some(
|
|
359
|
+
d =>
|
|
360
|
+
t.isCallExpression(d.init) &&
|
|
361
|
+
t.isIdentifier(d.init.callee, {
|
|
362
|
+
name: options.useTranslationIdentifier
|
|
363
|
+
})
|
|
364
|
+
)
|
|
365
|
+
)
|
|
366
|
+
) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
body.unshiftContainer("body", createUseTranslationDeclaration(options));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function shouldExtract(text, options) {
|
|
374
|
+
return (options.shouldExtract || _shouldExtract)(text, options.fromLang);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const hoistedMap = new Map();
|
|
378
|
+
|
|
287
379
|
function createI18nVisitor(option, i18nMap) {
|
|
288
380
|
const excludedCall = [...option.excludedCall, ...EXCLUDED_CALL];
|
|
289
381
|
|
|
290
382
|
return {
|
|
383
|
+
Program(path) {
|
|
384
|
+
path.traverse({
|
|
385
|
+
VariableDeclarator(p) {
|
|
386
|
+
const { id, init } = p.node;
|
|
387
|
+
if (
|
|
388
|
+
t.isIdentifier(id) &&
|
|
389
|
+
t.isArrayExpression(init) &&
|
|
390
|
+
id.name.startsWith("_hoisted_")
|
|
391
|
+
) {
|
|
392
|
+
hoistedMap.set(id.name, init);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
},
|
|
291
397
|
CallExpression(path) {
|
|
292
398
|
if (!isTFunction(path.node, option)) {
|
|
293
399
|
if (isVNodeCall(path, "_createTextVNode")) {
|
|
@@ -315,7 +421,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
315
421
|
|
|
316
422
|
if (!keyText) return;
|
|
317
423
|
|
|
318
|
-
if (!shouldExtract(keyText, option
|
|
424
|
+
if (!shouldExtract(keyText, option)) {
|
|
319
425
|
return;
|
|
320
426
|
}
|
|
321
427
|
|
|
@@ -373,7 +479,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
373
479
|
// return;
|
|
374
480
|
// }
|
|
375
481
|
|
|
376
|
-
if (!value || !shouldExtract(value, option
|
|
482
|
+
if (!value || !shouldExtract(value, option)) {
|
|
377
483
|
return;
|
|
378
484
|
}
|
|
379
485
|
|
|
@@ -463,7 +569,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
463
569
|
return;
|
|
464
570
|
}
|
|
465
571
|
|
|
466
|
-
if (!shouldExtract(value, option
|
|
572
|
+
if (!shouldExtract(value, option)) {
|
|
467
573
|
return;
|
|
468
574
|
}
|
|
469
575
|
|
|
@@ -489,7 +595,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
489
595
|
const text = path.node.value.trim();
|
|
490
596
|
if (!text) return; // 空白或换行等,跳过
|
|
491
597
|
|
|
492
|
-
if (!shouldExtract(text, option
|
|
598
|
+
if (!shouldExtract(text, option)) {
|
|
493
599
|
return;
|
|
494
600
|
}
|
|
495
601
|
|
|
@@ -499,6 +605,10 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
499
605
|
i18nMap[hashed] = text;
|
|
500
606
|
}
|
|
501
607
|
|
|
608
|
+
if (option.injectUseTranslation) {
|
|
609
|
+
markComponentUsesI18n(path);
|
|
610
|
+
}
|
|
611
|
+
|
|
502
612
|
if (option.jsx) {
|
|
503
613
|
const jsxElement = generateJSXElement(
|
|
504
614
|
option.JSXElement,
|
|
@@ -531,7 +641,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
531
641
|
const value = expr.value.trim();
|
|
532
642
|
|
|
533
643
|
if (!value) return;
|
|
534
|
-
if (!shouldExtract(value, option
|
|
644
|
+
if (!shouldExtract(value, option)) {
|
|
535
645
|
return;
|
|
536
646
|
}
|
|
537
647
|
|
|
@@ -541,6 +651,10 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
541
651
|
i18nMap[hashed] = value;
|
|
542
652
|
}
|
|
543
653
|
|
|
654
|
+
if (option.injectUseTranslation) {
|
|
655
|
+
markComponentUsesI18n(path);
|
|
656
|
+
}
|
|
657
|
+
|
|
544
658
|
if (
|
|
545
659
|
option.jsx &&
|
|
546
660
|
(path.parentPath.isJSXElement() || path.parentPath.isJSXFragment())
|
|
@@ -637,6 +751,19 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
637
751
|
)
|
|
638
752
|
);
|
|
639
753
|
}
|
|
754
|
+
},
|
|
755
|
+
// visitor:Function / ArrowFunction
|
|
756
|
+
Function: {
|
|
757
|
+
exit(path) {
|
|
758
|
+
if (!option.injectUseTranslation) return;
|
|
759
|
+
if (!path.node.__usesI18n) return;
|
|
760
|
+
|
|
761
|
+
// 防止重复注入
|
|
762
|
+
if (path.node.__i18nInjected) return;
|
|
763
|
+
path.node.__i18nInjected = true;
|
|
764
|
+
|
|
765
|
+
injectUseTranslation(path, option);
|
|
766
|
+
}
|
|
640
767
|
}
|
|
641
768
|
};
|
|
642
769
|
}
|
|
@@ -11,8 +11,8 @@ function vitePluginImportI18n(option) {
|
|
|
11
11
|
name: "vite-plugin-import-i18n",
|
|
12
12
|
enforce: "pre",
|
|
13
13
|
async transform(code, path) {
|
|
14
|
-
path = path.split(
|
|
15
|
-
|
|
14
|
+
path = path.split("?")[0];
|
|
15
|
+
|
|
16
16
|
if (!option.enabled || !option.autoImportI18n || !filter(path)) return;
|
|
17
17
|
|
|
18
18
|
return i18nImportTransform(
|
|
@@ -20,7 +20,9 @@ function vitePluginImportI18n(option) {
|
|
|
20
20
|
path,
|
|
21
21
|
option.jsx
|
|
22
22
|
? [option.translateKey, option.JSXElement]
|
|
23
|
-
:
|
|
23
|
+
: option.injectUseTranslation
|
|
24
|
+
? [option.translateKey, option.useTranslationIdentifier]
|
|
25
|
+
: [option.translateKey],
|
|
24
26
|
option.i18nPkgImportPath
|
|
25
27
|
);
|
|
26
28
|
}
|
|
@@ -11,7 +11,9 @@ module.exports = function (source) {
|
|
|
11
11
|
translateKey: importName,
|
|
12
12
|
JSXElement,
|
|
13
13
|
jsx,
|
|
14
|
-
i18nPkgImportPath: importPath
|
|
14
|
+
i18nPkgImportPath: importPath,
|
|
15
|
+
injectUseTranslation,
|
|
16
|
+
useTranslationIdentifier
|
|
15
17
|
} = { ...defaultOptions, ...global.getOptions() };
|
|
16
18
|
|
|
17
19
|
// // webpack 4.0
|
|
@@ -44,7 +46,11 @@ module.exports = function (source) {
|
|
|
44
46
|
return i18nImportTransform(
|
|
45
47
|
source,
|
|
46
48
|
global.resourcePath,
|
|
47
|
-
jsx
|
|
49
|
+
jsx
|
|
50
|
+
? [importName, JSXElement]
|
|
51
|
+
: injectUseTranslation
|
|
52
|
+
? [importName, useTranslationIdentifier]
|
|
53
|
+
: [importName],
|
|
48
54
|
importPath
|
|
49
55
|
);
|
|
50
56
|
};
|
package/package.json
CHANGED
package/types/options.d.ts
CHANGED
|
@@ -1,32 +1,38 @@
|
|
|
1
|
-
import { Translator } from
|
|
1
|
+
import { Translator } from "./translators";
|
|
2
2
|
|
|
3
|
-
export type LangKey = "zh-cn" |
|
|
3
|
+
export type LangKey = "zh-cn" | "zh-tw" | "en" | "ja" | "ko" | "ru" | string;
|
|
4
4
|
|
|
5
5
|
export interface I18nOptions {
|
|
6
|
-
translateKey: string
|
|
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
|
-
|
|
6
|
+
translateKey: string;
|
|
7
|
+
useTranslationIdentifier: string;
|
|
8
|
+
JSXElement: string;
|
|
9
|
+
injectUseTranslation: boolean;
|
|
10
|
+
jsx: boolean;
|
|
11
|
+
rewrite: boolean;
|
|
12
|
+
extractFromText: boolean;
|
|
13
|
+
autoImportI18n: boolean;
|
|
14
|
+
autoTranslate: boolean;
|
|
15
|
+
cleanTranslate: boolean;
|
|
16
|
+
keepRaw: boolean;
|
|
17
|
+
keepDefaultMsg: boolean;
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
outputJsonFileInPlugin: boolean;
|
|
20
|
+
outputJsonFileDebounceTimeInPlugin: number;
|
|
21
|
+
translateInterval: number;
|
|
22
|
+
excludedCall: string[];
|
|
23
|
+
includePath: string[] | string;
|
|
24
|
+
excludedPath: string[] | string;
|
|
25
|
+
allowedExtensions: string[];
|
|
26
|
+
fromLang: LangKey;
|
|
27
|
+
translateLangKeys: LangKey[];
|
|
28
|
+
i18nPkgImportPath: string;
|
|
29
|
+
outputPath: string;
|
|
30
|
+
generateId:
|
|
31
|
+
| ((text: string, rawGenerateIdFn?: (text: string) => string) => string)
|
|
32
|
+
| null
|
|
33
|
+
| undefined;
|
|
34
|
+
shouldExtract: (text: string, langKey: LangKey) => boolean;
|
|
35
|
+
customGenLangFileName: (langKey: LangKey) => LangKey;
|
|
36
|
+
customTranslatedText: (text: string, toLang: LangKey) => string;
|
|
37
|
+
translator: Translator;
|
|
38
|
+
}
|