vue-i18n-extract-plugin 1.0.47 → 1.0.49
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 +4 -4
- package/lib/babel-plugin-i18n.js +7 -0
- package/lib/babel-plugin-import-i18n.js +7 -1
- package/lib/cli.js +1 -1
- package/lib/index.js +2 -2
- package/lib/options.js +2 -2
- package/lib/translate.js +0 -1
- package/lib/visitors.js +45 -50
- package/lib/vite-plugin-i18n.js +26 -2
- package/lib/vite-plugin-import-i18n.js +3 -2
- package/lib/webpack-plugin-i18n.js +16 -16
- package/package.json +2 -1
- package/types/babel-plugin-i18n.d.ts +6 -0
- package/types/babel-plugin-import-i18n.d.ts +6 -0
- package/types/common.d.ts +3 -0
- package/types/extract.d.ts +28 -0
- package/types/i18n.config.d.ts +7 -0
- package/types/import-i18n-transform.d.ts +21 -0
- package/types/index.d.ts +41 -0
- package/types/options.d.ts +33 -0
- package/types/translate.d.ts +18 -0
- package/types/translators/index.d.ts +186 -0
- package/types/utils.d.ts +21 -0
- package/types/visitors.d.ts +9 -0
- package/types/vite-plugin-i18n.d.ts +4 -0
- package/types/vite-plugin-import-i18n.d.ts +4 -0
- package/types/vue-i18n-loader.d.ts +2 -0
- package/types/webpack-import-i18n-loader.d.ts +2 -0
- package/types/webpack-plugin-i18n.d.ts +9 -0
package/README.md
CHANGED
|
@@ -48,12 +48,12 @@ extractI18n(options)
|
|
|
48
48
|
```javascript
|
|
49
49
|
const defaultOptions = {
|
|
50
50
|
translateKey: "$t", // 提取的函数的名称
|
|
51
|
-
rewrite:
|
|
51
|
+
rewrite: false, // 是否将提取到的内容转换为id后重写入源文件
|
|
52
52
|
extractFromText: true, // 是否允许从纯文本节点中提取翻译内容
|
|
53
53
|
autoImportI18n: true, // 是否自动导入 i18n 模块
|
|
54
54
|
autoTranslate: true, // 提取完成后是否自动翻译
|
|
55
55
|
cleanTranslate: true, // 是否清理无用的翻译内容
|
|
56
|
-
|
|
56
|
+
enabled: true, // 是否启用插件
|
|
57
57
|
outputJsonFileInPlugin: true, // 是否在插件中输出 JSON 文件
|
|
58
58
|
outputJsonFileDebounceTimeInPlugin: 2000, // 输出 JSON 文件的防抖时间
|
|
59
59
|
translateInterval: 1000, // 自动翻译的间隔时间
|
|
@@ -109,10 +109,10 @@ import { vitePluginImportI18n, vitePluginI18n } from "vue-i18n-extract-plugin";
|
|
|
109
109
|
|
|
110
110
|
export default defineConfig({
|
|
111
111
|
plugins: [
|
|
112
|
-
// 自动添加import { $t } from '@/i18n'导入语句,请在i18n文件导出一个$t的方法.
|
|
112
|
+
// 自动添加import { $t } from '@/i18n'导入语句,请在i18n文件导出一个$t的方法.
|
|
113
113
|
vitePluginImportI18n(options),
|
|
114
114
|
vue(),
|
|
115
|
-
//
|
|
115
|
+
// 用于运行时转换
|
|
116
116
|
vitePluginI18n(options)
|
|
117
117
|
]
|
|
118
118
|
});
|
package/lib/babel-plugin-i18n.js
CHANGED
|
@@ -6,6 +6,13 @@ module.exports = declare((api, options) => {
|
|
|
6
6
|
api.assertVersion(7);
|
|
7
7
|
options = { ...defaultOptions, ...options };
|
|
8
8
|
|
|
9
|
+
if (!options.enabled) {
|
|
10
|
+
return {
|
|
11
|
+
name: "i18n-hash-replace",
|
|
12
|
+
visitor: {}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
return {
|
|
10
17
|
name: "i18n-hash-replace",
|
|
11
18
|
...createI18nPlugin(options)()
|
|
@@ -6,11 +6,17 @@ module.exports = function () {
|
|
|
6
6
|
name: "auto-import-i18n",
|
|
7
7
|
visitor: {
|
|
8
8
|
Program(path, state) {
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
translateKey: importName,
|
|
11
|
+
i18nPkgImportPath: importPath,
|
|
12
|
+
enabled
|
|
13
|
+
} = {
|
|
10
14
|
...defaultOptions,
|
|
11
15
|
...state.opts
|
|
12
16
|
};
|
|
13
17
|
|
|
18
|
+
if (!enabled) return;
|
|
19
|
+
|
|
14
20
|
const localName = importName;
|
|
15
21
|
let hasI18nImport = false;
|
|
16
22
|
let lastImportPath = null;
|
package/lib/cli.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -4,8 +4,7 @@ const { defaultOptions } = require("./options");
|
|
|
4
4
|
const {
|
|
5
5
|
autoTranslate,
|
|
6
6
|
translateChunks,
|
|
7
|
-
createTextSplitter
|
|
8
|
-
getLangJsonPath
|
|
7
|
+
createTextSplitter
|
|
9
8
|
} = require("./translate");
|
|
10
9
|
const translators = require("./translators");
|
|
11
10
|
const {
|
|
@@ -15,6 +14,7 @@ const {
|
|
|
15
14
|
checkAgainstRegexArray,
|
|
16
15
|
extractFunctionName,
|
|
17
16
|
relativeCWDPath,
|
|
17
|
+
getLangJsonPath,
|
|
18
18
|
shouldExtract,
|
|
19
19
|
trimEmptyLine,
|
|
20
20
|
padEmptyLine,
|
package/lib/options.js
CHANGED
|
@@ -2,12 +2,12 @@ const { GoogleTranslator } = require("./translators");
|
|
|
2
2
|
|
|
3
3
|
const defaultOptions = {
|
|
4
4
|
translateKey: "$t", // 提取的函数的名称
|
|
5
|
-
rewrite:
|
|
5
|
+
rewrite: false, // 是否将提取到的内容转换为id后重写入源文件
|
|
6
6
|
extractFromText: true, // 是否允许从纯文本节点中提取翻译内容
|
|
7
7
|
autoImportI18n: true, // 是否自动导入 i18n 模块
|
|
8
8
|
autoTranslate: true, // 提取完成后是否自动翻译
|
|
9
9
|
cleanTranslate: true, // 是否清理无用的翻译内容
|
|
10
|
-
|
|
10
|
+
enabled: true, // 是否启用插件
|
|
11
11
|
outputJsonFileInPlugin: true, // 是否在插件中输出 JSON 文件
|
|
12
12
|
outputJsonFileDebounceTimeInPlugin: 2000, // 输出 JSON 文件的防抖时间
|
|
13
13
|
translateInterval: 1000, // 自动翻译的间隔时间
|
package/lib/translate.js
CHANGED
package/lib/visitors.js
CHANGED
|
@@ -44,6 +44,8 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
44
44
|
keyText = firstArg.quasis.map(q => q.value.cooked).join("${}");
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
keyText = keyText.trim();
|
|
48
|
+
|
|
47
49
|
if (!keyText) return;
|
|
48
50
|
|
|
49
51
|
if (!shouldExtract(keyText, option.fromLang)) {
|
|
@@ -58,10 +60,8 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
58
60
|
i18nMap[hashed] = keyText;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
path.node.arguments[0] = newArg;
|
|
64
|
-
}
|
|
63
|
+
const newArg = t.stringLiteral(hashed);
|
|
64
|
+
path.node.arguments[0] = newArg;
|
|
65
65
|
},
|
|
66
66
|
|
|
67
67
|
StringLiteral(path) {
|
|
@@ -91,7 +91,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
const value = path.node.value;
|
|
94
|
+
const value = path.node.value.trim();
|
|
95
95
|
|
|
96
96
|
// const callExpr = path.findParent((p) => p.isCallExpression());
|
|
97
97
|
|
|
@@ -100,8 +100,7 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
100
100
|
// return;
|
|
101
101
|
// }
|
|
102
102
|
|
|
103
|
-
if (value
|
|
104
|
-
if (!shouldExtract(value, option.fromLang)) {
|
|
103
|
+
if (!value || !shouldExtract(value, option.fromLang)) {
|
|
105
104
|
return;
|
|
106
105
|
}
|
|
107
106
|
|
|
@@ -113,29 +112,27 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
113
112
|
i18nMap[hashed] = value;
|
|
114
113
|
}
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
path.replaceWith(callExpression);
|
|
128
|
-
}
|
|
115
|
+
const callExpression = t.callExpression(
|
|
116
|
+
t.identifier(option.translateKey),
|
|
117
|
+
[t.stringLiteral(hashed)]
|
|
118
|
+
);
|
|
119
|
+
// 如果是 JSX 属性值,需要包裹在 JSXExpressionContainer 中
|
|
120
|
+
if (parentPath.isJSXAttribute()) {
|
|
121
|
+
const jsxExpression = t.jsxExpressionContainer(callExpression);
|
|
122
|
+
path.replaceWith(jsxExpression);
|
|
123
|
+
} else {
|
|
124
|
+
// 其他情况直接替换
|
|
125
|
+
path.replaceWith(callExpression);
|
|
129
126
|
}
|
|
130
127
|
},
|
|
131
128
|
|
|
132
129
|
TemplateElement(path) {
|
|
133
|
-
const { node
|
|
130
|
+
const { node } = path;
|
|
134
131
|
if (!node.value) return;
|
|
135
132
|
|
|
136
|
-
let value = node.value.raw || node.value.cooked;
|
|
133
|
+
let value = (node.value.raw || node.value.cooked).trim();
|
|
137
134
|
|
|
138
|
-
if (value
|
|
135
|
+
if (!value) return;
|
|
139
136
|
|
|
140
137
|
// 获取真实调用函数
|
|
141
138
|
const extractFnName = extractFunctionName(path);
|
|
@@ -163,11 +160,9 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
163
160
|
i18nMap[hashed] = value;
|
|
164
161
|
}
|
|
165
162
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
node.value.raw = node.value.cooked = `\${${tCallExpression}}`;
|
|
170
|
-
}
|
|
163
|
+
// 替换为字符类型翻译节点
|
|
164
|
+
const tCallExpression = `${option.translateKey}('${hashed}')`;
|
|
165
|
+
node.value.raw = node.value.cooked = `\${${tCallExpression}}`;
|
|
171
166
|
},
|
|
172
167
|
JSXText(path) {
|
|
173
168
|
// <div>Hello world</div>
|
|
@@ -188,43 +183,43 @@ function createI18nVisitor(option, i18nMap) {
|
|
|
188
183
|
i18nMap[hashed] = text;
|
|
189
184
|
}
|
|
190
185
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
t.
|
|
195
|
-
t.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
);
|
|
200
|
-
}
|
|
186
|
+
// 替换为表达式 {$t("hashed")}
|
|
187
|
+
path.replaceWith(
|
|
188
|
+
t.jsxExpressionContainer(
|
|
189
|
+
t.callExpression(t.identifier(option.translateKey), [
|
|
190
|
+
t.stringLiteral(hashed)
|
|
191
|
+
])
|
|
192
|
+
)
|
|
193
|
+
);
|
|
201
194
|
},
|
|
202
195
|
JSXExpressionContainer(path) {
|
|
203
196
|
// <div>{"Hi"}</div>
|
|
204
197
|
if (option.extractFromText === false) return;
|
|
205
198
|
const expr = path.node.expression;
|
|
199
|
+
|
|
206
200
|
if (t.isStringLiteral(expr)) {
|
|
207
|
-
|
|
201
|
+
const value = expr.value.trim();
|
|
202
|
+
|
|
203
|
+
if (!value) return;
|
|
204
|
+
if (!shouldExtract(value, option.fromLang)) {
|
|
208
205
|
return;
|
|
209
206
|
}
|
|
210
207
|
|
|
211
208
|
// console.log("JSXExpressionContainer", path.node.expression.expr);
|
|
212
209
|
|
|
213
|
-
const hashed = generateId(
|
|
210
|
+
const hashed = generateId(value);
|
|
214
211
|
|
|
215
212
|
if (i18nMap) {
|
|
216
|
-
i18nMap[hashed] =
|
|
213
|
+
i18nMap[hashed] = value;
|
|
217
214
|
}
|
|
218
215
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
t.
|
|
222
|
-
t.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
);
|
|
227
|
-
}
|
|
216
|
+
path.replaceWith(
|
|
217
|
+
t.jsxExpressionContainer(
|
|
218
|
+
t.callExpression(t.identifier(option.translateKey), [
|
|
219
|
+
t.stringLiteral(hashed)
|
|
220
|
+
])
|
|
221
|
+
)
|
|
222
|
+
);
|
|
228
223
|
}
|
|
229
224
|
}
|
|
230
225
|
};
|
package/lib/vite-plugin-i18n.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { transformAsync } = require("@babel/core");
|
|
2
2
|
const { createI18nPlugin } = require("./visitors");
|
|
3
|
-
const { checkAgainstRegexArray } = require("./utils");
|
|
3
|
+
const { relativeCWDPath, checkAgainstRegexArray } = require("./utils");
|
|
4
4
|
const { defaultOptions } = require("./options");
|
|
5
5
|
const { globalI18nMap, handleFinalI18nMap } = require("./extract");
|
|
6
6
|
|
|
@@ -12,12 +12,36 @@ function vitePluginI18n(option) {
|
|
|
12
12
|
|
|
13
13
|
return {
|
|
14
14
|
name: "vite-plugin-i18n-hash",
|
|
15
|
+
enforce: "post",
|
|
16
|
+
config(config, { command }) {
|
|
17
|
+
if (command !== "serve") return null;
|
|
18
|
+
const existingServerConfig = config.server || {};
|
|
19
|
+
const existingWatchConfig = existingServerConfig.watch || {};
|
|
20
|
+
const existingIgnored = existingWatchConfig.ignored || [];
|
|
21
|
+
const newIgnored = relativeCWDPath(option.outputPath) + "**";
|
|
15
22
|
|
|
23
|
+
const ignored = [
|
|
24
|
+
...(Array.isArray(existingIgnored)
|
|
25
|
+
? existingIgnored
|
|
26
|
+
: [existingIgnored]),
|
|
27
|
+
...(Array.isArray(newIgnored) ? newIgnored : [newIgnored])
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
server: {
|
|
32
|
+
...existingServerConfig,
|
|
33
|
+
watch: {
|
|
34
|
+
...existingWatchConfig,
|
|
35
|
+
ignored
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
},
|
|
16
40
|
configResolved(resolvedConfig) {
|
|
17
41
|
config = resolvedConfig;
|
|
18
42
|
},
|
|
19
43
|
async transform(code, path) {
|
|
20
|
-
if (!option.
|
|
44
|
+
if (!option.enabled) return;
|
|
21
45
|
|
|
22
46
|
if (option.allowedExtensions.some(ext => path.endsWith(ext))) {
|
|
23
47
|
if (
|
|
@@ -9,7 +9,8 @@ function vitePluginImportI18n(options) {
|
|
|
9
9
|
i18nPkgImportPath: importPath,
|
|
10
10
|
allowedExtensions: extensions,
|
|
11
11
|
includePath,
|
|
12
|
-
excludedPath
|
|
12
|
+
excludedPath,
|
|
13
|
+
enabled
|
|
13
14
|
} = { ...defaultOptions, ...options };
|
|
14
15
|
|
|
15
16
|
const filter = createFilter(
|
|
@@ -37,7 +38,7 @@ function vitePluginImportI18n(options) {
|
|
|
37
38
|
name: "vite-plugin-import-i18n",
|
|
38
39
|
enforce: "pre",
|
|
39
40
|
async transform(code, path) {
|
|
40
|
-
if (!filter(path)) return;
|
|
41
|
+
if (!enabled || !filter(path)) return;
|
|
41
42
|
return i18nImportTransform(code, path, importName, importPath);
|
|
42
43
|
}
|
|
43
44
|
};
|
|
@@ -27,6 +27,7 @@ class WebpackPluginI18n {
|
|
|
27
27
|
* @param compiler Webpack 编译器实例
|
|
28
28
|
*/
|
|
29
29
|
apply(compiler) {
|
|
30
|
+
if (!this.options.enabled) return;
|
|
30
31
|
/**
|
|
31
32
|
* 检查是否已经添加过这个自定义 Loader,避免重复添加
|
|
32
33
|
* @param rule Webpack 模块规则
|
|
@@ -49,22 +50,21 @@ class WebpackPluginI18n {
|
|
|
49
50
|
!compiler.options.module.rules.some(hasCustomLoader)
|
|
50
51
|
) {
|
|
51
52
|
const loaderRegex = generateAdvancedRegex(this.options);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
53
|
+
|
|
54
|
+
// 向 module.rules 中添加自定义 Loader
|
|
55
|
+
compiler.options.module?.rules.push({
|
|
56
|
+
// 生成高级正则表达式,用于匹配目标文件
|
|
57
|
+
test: loaderRegex,
|
|
58
|
+
// 设置 Loader 执行顺序为后置
|
|
59
|
+
enforce: "post",
|
|
60
|
+
use: [
|
|
61
|
+
{
|
|
62
|
+
// 指定自定义 Loader 的路径
|
|
63
|
+
loader: path.resolve(__dirname, "./vue-i18n-loader.js"),
|
|
64
|
+
options: this.options
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
68
|
|
|
69
69
|
if (this.options.autoImportI18n) {
|
|
70
70
|
compiler.options.module?.rules.push({
|
package/package.json
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Node } from '@babel/types';
|
|
2
|
+
import { I18nOptions as Options } from './options';
|
|
3
|
+
import { I18nMap } from './common';
|
|
4
|
+
|
|
5
|
+
export interface WriteResult {
|
|
6
|
+
hasDiff: boolean;
|
|
7
|
+
data: I18nMap;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function writeI18nMapToFile(
|
|
11
|
+
i18nMap: I18nMap,
|
|
12
|
+
options: Options,
|
|
13
|
+
checkDiffs?: boolean
|
|
14
|
+
): Promise<WriteResult>;
|
|
15
|
+
|
|
16
|
+
export function handleFinalI18nMap(
|
|
17
|
+
i18nMap: I18nMap,
|
|
18
|
+
options: Options,
|
|
19
|
+
checkDiffs?: boolean
|
|
20
|
+
): Promise<void>;
|
|
21
|
+
|
|
22
|
+
export function addI18nImportIfNeeded(ast: Node, options: Partial<Options>): Node
|
|
23
|
+
export function addI18nImportIfNeeded(ast: Node, options: Partial<Options>, generateCode: false): Node
|
|
24
|
+
export function addI18nImportIfNeeded(ast: Node, options: Partial<Options>, generateCode: true): string
|
|
25
|
+
|
|
26
|
+
export function extractI18n(options: Options): Promise<void>;
|
|
27
|
+
|
|
28
|
+
export let globalI18nMap: I18nMap;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Node } from '@babel/types';
|
|
2
|
+
|
|
3
|
+
export interface TransformResult {
|
|
4
|
+
ast: Node;
|
|
5
|
+
needTransform: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function i18nImportAstTransform(
|
|
9
|
+
ast: Node,
|
|
10
|
+
importName: string,
|
|
11
|
+
importPath: string
|
|
12
|
+
): TransformResult;
|
|
13
|
+
|
|
14
|
+
export function i18nImportTransform(
|
|
15
|
+
code: string,
|
|
16
|
+
path: string,
|
|
17
|
+
importName: string,
|
|
18
|
+
importPath: string
|
|
19
|
+
): Promise<string>;
|
|
20
|
+
|
|
21
|
+
export function extractScriptContent(code: string, path: string): string;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/// <reference path="./extract-i18n.config.d.ts" />
|
|
2
|
+
|
|
3
|
+
export { default as babelPluginI18n } from "./babel-plugin-i18n";
|
|
4
|
+
export { extractI18n, addI18nImportIfNeeded } from "./extract";
|
|
5
|
+
export { I18nOptions as defaultOptions } from "./options";
|
|
6
|
+
export {
|
|
7
|
+
autoTranslate,
|
|
8
|
+
translateChunks,
|
|
9
|
+
createTextSplitter
|
|
10
|
+
} from "./translate";
|
|
11
|
+
export * as translators from "./translators";
|
|
12
|
+
export {
|
|
13
|
+
hashKey,
|
|
14
|
+
generateId,
|
|
15
|
+
parseArg,
|
|
16
|
+
checkAgainstRegexArray,
|
|
17
|
+
extractFunctionName,
|
|
18
|
+
relativeCWDPath,
|
|
19
|
+
getLangJsonPath,
|
|
20
|
+
shouldExtract,
|
|
21
|
+
trimEmptyLine,
|
|
22
|
+
padEmptyLine,
|
|
23
|
+
excludeDirectives,
|
|
24
|
+
EXCLUDED_CALL
|
|
25
|
+
} from "./utils";
|
|
26
|
+
export {
|
|
27
|
+
shouldTransform,
|
|
28
|
+
isTFunction,
|
|
29
|
+
createI18nVisitor,
|
|
30
|
+
createI18nPlugin
|
|
31
|
+
} from "./visitors";
|
|
32
|
+
export { default as vitePluginI18n } from "./vite-plugin-i18n";
|
|
33
|
+
export { default as vitePluginImportI18n } from "./vite-plugin-import-i18n";
|
|
34
|
+
export { default as WebpackPluginI18n } from "./webpack-plugin-i18n";
|
|
35
|
+
export { default as vueI18nLoader } from "./vue-i18n-loader";
|
|
36
|
+
export { default as babelPluginImportI18n } from "./babel-plugin-import-i18n";
|
|
37
|
+
export {
|
|
38
|
+
i18nImportAstTransform,
|
|
39
|
+
i18nImportTransform,
|
|
40
|
+
extractScriptContent
|
|
41
|
+
} from "./import-i18n-transform";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type LangKey = "zh-cn" | 'zh-tw' | 'en' | 'ja' | 'ko' | 'ru' | string
|
|
2
|
+
|
|
3
|
+
export interface I18nOptions {
|
|
4
|
+
translateKey: string
|
|
5
|
+
rewrite: boolean
|
|
6
|
+
extractFromText: boolean
|
|
7
|
+
autoImportI18n: boolean
|
|
8
|
+
autoTranslate: boolean
|
|
9
|
+
cleanTranslate: boolean
|
|
10
|
+
enabled: boolean
|
|
11
|
+
outputJsonFileInPlugin: boolean
|
|
12
|
+
outputJsonFileDebounceTimeInPlugin: number
|
|
13
|
+
translateInterval: number
|
|
14
|
+
excludedCall: string[]
|
|
15
|
+
includePath: string[] | string
|
|
16
|
+
excludedPath: string[] | string
|
|
17
|
+
allowedExtensions: string[]
|
|
18
|
+
fromLang: LangKey
|
|
19
|
+
translateLangKeys: LangKey[]
|
|
20
|
+
i18nPkgImportPath: string
|
|
21
|
+
outputPath: string
|
|
22
|
+
customGenLangFileName: (langKey: LangKey) => LangKey
|
|
23
|
+
customTranslatedText: (text: string, toLang: LangKey) => string,
|
|
24
|
+
// translator: new GoogleTranslator({
|
|
25
|
+
// // proxyOption: {
|
|
26
|
+
// // port: 7890,
|
|
27
|
+
// // host: '127.0.0.1',
|
|
28
|
+
// // headers: {
|
|
29
|
+
// // 'User-Agent': 'Node'
|
|
30
|
+
// // }
|
|
31
|
+
// // }
|
|
32
|
+
// })
|
|
33
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { I18nOptions, LangKey } from './options';
|
|
2
|
+
import { I18nMap } from './common';
|
|
3
|
+
|
|
4
|
+
export function createTextSplitter(values: string[], maxChunkSize: number): string[];
|
|
5
|
+
|
|
6
|
+
export function cleanI18nMap(sourceObj: I18nMap, targetObj: I18nMap): I18nMap;
|
|
7
|
+
|
|
8
|
+
export function autoTranslateFromFile(): Promise<void>;
|
|
9
|
+
|
|
10
|
+
export function autoTranslate(i18nMap: I18nMap, option?: Partial<I18nOptions>): Promise<void>;
|
|
11
|
+
|
|
12
|
+
export function cleanTranslate(option?: Partial<I18nOptions>): Promise<void>;
|
|
13
|
+
|
|
14
|
+
export function translateChunks(
|
|
15
|
+
transLangObj: I18nMap,
|
|
16
|
+
toTranslateLang: LangKey,
|
|
17
|
+
option: Partial<I18nOptions>
|
|
18
|
+
): Promise<string[]>;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import tunnel from 'tunnel';
|
|
2
|
+
import { AxiosProxyConfig } from 'axios';
|
|
3
|
+
|
|
4
|
+
interface TranslatorOption {
|
|
5
|
+
/** Translator版本,用于做后续的功能迭代 */
|
|
6
|
+
version?: number;
|
|
7
|
+
/**
|
|
8
|
+
* 实际的请求方法
|
|
9
|
+
* @param text 被翻译的文本
|
|
10
|
+
* @param fromKey 源语言
|
|
11
|
+
* @param toKey 目标语言
|
|
12
|
+
* @param separator 分隔符
|
|
13
|
+
* @returns 翻译后的文本
|
|
14
|
+
*/
|
|
15
|
+
fetchMethod: (text: string, fromKey: string, toKey: string, separator: string) => Promise<string>;
|
|
16
|
+
name: string;
|
|
17
|
+
/** 单次最大翻译文本长度 */
|
|
18
|
+
maxChunkSize?: number;
|
|
19
|
+
/** 执行间隔(默认不开启) */
|
|
20
|
+
interval?: number;
|
|
21
|
+
/**
|
|
22
|
+
* 错误处理函数,主要是打印提示
|
|
23
|
+
* @param err 抛出的异常
|
|
24
|
+
* @param defaultErrorHandler 默认的错误处理函数
|
|
25
|
+
* @returns 如果在这里抛出异常会中断翻译
|
|
26
|
+
*/
|
|
27
|
+
onError?: (err: unknown, defaultErrorHandler: (error: unknown) => void) => void;
|
|
28
|
+
}
|
|
29
|
+
declare class Translator {
|
|
30
|
+
option: Required<TranslatorOption>;
|
|
31
|
+
constructor(option: TranslatorOption);
|
|
32
|
+
private defaultErrorHandler;
|
|
33
|
+
private getResultOption;
|
|
34
|
+
protected getErrorMessage(error: unknown): string;
|
|
35
|
+
translate(text: string, fromKey: string, toKey: string, separator: string): Promise<string>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface GoogleTranslatorOption {
|
|
39
|
+
proxyOption?: tunnel.ProxyOptions;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 谷歌翻译器
|
|
43
|
+
*
|
|
44
|
+
* 基于@vitalets/google-translate-api,需要翻墙,不稳定,但是免费
|
|
45
|
+
*
|
|
46
|
+
* 使用方式:
|
|
47
|
+
* ```ts
|
|
48
|
+
* vitePluginsAutoI18n({
|
|
49
|
+
...
|
|
50
|
+
translator: translator: new GoogleTranslator({
|
|
51
|
+
proxyOption: {
|
|
52
|
+
// 如果你本地的代理在127.0.0.0:8899
|
|
53
|
+
host: '127.0.0.1',
|
|
54
|
+
port: 8899,
|
|
55
|
+
headers: {
|
|
56
|
+
'User-Agent': 'Node'
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare class GoogleTranslator extends Translator {
|
|
64
|
+
constructor(option: GoogleTranslatorOption);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface YoudaoTranslatorOption {
|
|
68
|
+
appId: string;
|
|
69
|
+
appKey: string;
|
|
70
|
+
/** 网络代理配置 */
|
|
71
|
+
proxy?: AxiosProxyConfig;
|
|
72
|
+
/** 翻译api执行间隔,默认为1000 */
|
|
73
|
+
interval?: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 有道翻译器
|
|
77
|
+
*
|
|
78
|
+
* api文档:https://ai.youdao.com/DOCSIRMA/html/trans/api/wbfy/index.html
|
|
79
|
+
*
|
|
80
|
+
* 使用方式:
|
|
81
|
+
* ```ts
|
|
82
|
+
* vitePluginsAutoI18n({
|
|
83
|
+
...
|
|
84
|
+
translator: new YoudaoTranslator({
|
|
85
|
+
appId: '你申请的appId',
|
|
86
|
+
appKey: '你申请的appKey'
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare class YoudaoTranslator extends Translator {
|
|
92
|
+
/** 有道的语言类型映射不标准,需要手动控制 */
|
|
93
|
+
private readonly YOUDAO_TRANSLATE_KEY_CONVERT_MAP;
|
|
94
|
+
private truncate;
|
|
95
|
+
private getTranslateKey;
|
|
96
|
+
constructor(option: YoudaoTranslatorOption);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface BaiduTranslatorOption {
|
|
100
|
+
appId: string;
|
|
101
|
+
appKey: string;
|
|
102
|
+
/** 网络代理配置 */
|
|
103
|
+
proxy?: AxiosProxyConfig;
|
|
104
|
+
/** 翻译api执行间隔,默认为1000 */
|
|
105
|
+
interval?: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 百度翻译器
|
|
109
|
+
*
|
|
110
|
+
* api文档:https://api.fanyi.baidu.com/product/113
|
|
111
|
+
*
|
|
112
|
+
* 使用方式:
|
|
113
|
+
* ```ts
|
|
114
|
+
* vitePluginsAutoI18n({
|
|
115
|
+
...
|
|
116
|
+
translator: new BaiduTranslator({
|
|
117
|
+
appId: '你申请的appId',
|
|
118
|
+
appKey: '你申请的appKey'
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare class BaiduTranslator extends Translator {
|
|
124
|
+
/** 百度的语言类型映射不标准,需要手动控制 */
|
|
125
|
+
protected readonly BAIDU_TRANSLATE_KEY_CONVERT_MAP: Record<string, string>;
|
|
126
|
+
protected getTranslateKey(key: string): string;
|
|
127
|
+
constructor(option: BaiduTranslatorOption);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 空翻译器,不翻译文本,用于配合某些特殊的操作
|
|
132
|
+
*/
|
|
133
|
+
declare class EmptyTranslator extends Translator {
|
|
134
|
+
constructor(option?: Partial<TranslatorOption>);
|
|
135
|
+
}
|
|
136
|
+
/** @deprecated 别名导出,兼容旧版本 */
|
|
137
|
+
declare const ScanTranslator: typeof EmptyTranslator;
|
|
138
|
+
|
|
139
|
+
interface VolcengineTranslatorOption {
|
|
140
|
+
apiKey: string;
|
|
141
|
+
/** 使用的ai模型,可选值请参阅火山引擎控制台的模型列表,如`doubao-1-5-pro-32k-250115`,并请确保使用前已在控制台开通了对应模型 */
|
|
142
|
+
model: string;
|
|
143
|
+
/** 对本项目的简短描述,在有描述的情况下大模型的翻译结果可能会更加准确 */
|
|
144
|
+
desc?: string;
|
|
145
|
+
/** 网络代理配置 */
|
|
146
|
+
proxy?: AxiosProxyConfig;
|
|
147
|
+
/** 翻译api执行间隔,默认为1000 */
|
|
148
|
+
interval?: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 火山引擎翻译器,内置豆包、deepseek等模型
|
|
152
|
+
*
|
|
153
|
+
* 火山引擎大模型介绍:https://www.volcengine.com/docs/82379/1099455
|
|
154
|
+
*
|
|
155
|
+
* api文档:https://www.volcengine.com/docs/82379/1298454
|
|
156
|
+
*
|
|
157
|
+
* 使用方式:
|
|
158
|
+
* ```ts
|
|
159
|
+
* vitePluginsAutoI18n({
|
|
160
|
+
...
|
|
161
|
+
translator: new VolcengineTranslator({
|
|
162
|
+
apiKey: '你申请的apiKey',
|
|
163
|
+
model: '你要调用的模型,如:`doubao-1-5-pro-32k-250115`,请确保使用前已在控制台开通了对应模型'
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
declare class VolcengineTranslator extends Translator {
|
|
169
|
+
constructor(option: VolcengineTranslatorOption);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
export {
|
|
174
|
+
BaiduTranslator,
|
|
175
|
+
BaiduTranslatorOption,
|
|
176
|
+
EmptyTranslator,
|
|
177
|
+
GoogleTranslator,
|
|
178
|
+
GoogleTranslatorOption,
|
|
179
|
+
ScanTranslator,
|
|
180
|
+
Translator,
|
|
181
|
+
TranslatorOption,
|
|
182
|
+
VolcengineTranslator,
|
|
183
|
+
VolcengineTranslatorOption,
|
|
184
|
+
YoudaoTranslator,
|
|
185
|
+
YoudaoTranslatorOption
|
|
186
|
+
};
|
package/types/utils.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NodePath } from "@babel/traverse";
|
|
2
|
+
import { I18nOptions, LangKey } from './options';
|
|
3
|
+
|
|
4
|
+
export function hashKey(str: string): string;
|
|
5
|
+
export function generateId(text: string, length?: number): string;
|
|
6
|
+
export function parseArg(arg: string): any;
|
|
7
|
+
export function isEmptyObject(obj: Record<string, any>): boolean;
|
|
8
|
+
export function checkAgainstRegexArray(value: string, regexArray?: (string | RegExp)[]): boolean;
|
|
9
|
+
export function extractFunctionName(path: NodePath): string;
|
|
10
|
+
export function relativeCWDPath(subPath: string): string;
|
|
11
|
+
export function getLangJsonPath(langKey: LangKey, option: I18nOptions): string;
|
|
12
|
+
export function readJsonWithDefault(pathStr: string, defaultValue?: Record<string, any>): Record<string, any>;
|
|
13
|
+
export function resolveAliasPath(pathStr: string): string;
|
|
14
|
+
export function resolveFilterPath(pathStr: string): string;
|
|
15
|
+
export function fixFolderPath(pathStr: string | RegExp): string;
|
|
16
|
+
export function sleep(ms: number): Promise<void>;
|
|
17
|
+
export function shouldExtract(str: string, langKey: LangKey): boolean;
|
|
18
|
+
export function trimEmptyLine(str: string): string;
|
|
19
|
+
export function padEmptyLine(str: string): string;
|
|
20
|
+
export const excludeDirectives: string[];
|
|
21
|
+
export const EXCLUDED_CALL: string[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Node } from '@babel/types';
|
|
2
|
+
import { NodePath } from "@babel/traverse";
|
|
3
|
+
import { I18nOptions } from "./options";
|
|
4
|
+
import { I18nMap } from "./common";
|
|
5
|
+
|
|
6
|
+
export declare function shouldTransform(path: NodePath): boolean;
|
|
7
|
+
export declare function isTFunction(node: Node, option: I18nOptions): boolean;
|
|
8
|
+
export declare function createI18nVisitor(option: I18nOptions, i18nMap?: I18nMap): Record<string, (path: NodePath) => void>;
|
|
9
|
+
export declare function createI18nPlugin(option: I18nOptions, i18nMap?: I18nMap): () => { visitor: Record<string, (path: NodePath) => void> };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import webpack from 'webpack'
|
|
2
|
+
import { I18nOptions } from './options';
|
|
3
|
+
|
|
4
|
+
export declare class WebpackPluginI18n {
|
|
5
|
+
options: I18nOptions;
|
|
6
|
+
timer: NodeJS.Timeout | null;
|
|
7
|
+
constructor(optionInfo?: Partial<I18nOptions>);
|
|
8
|
+
apply(compiler: webpack.Compiler): void;
|
|
9
|
+
}
|