vue-i18n-extract-plugin 1.0.47
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/.prettierrc +8 -0
- package/LICENSE +20 -0
- package/README.md +292 -0
- package/lib/babel-plugin-i18n.js +13 -0
- package/lib/babel-plugin-import-i18n.js +154 -0
- package/lib/cli.js +54 -0
- package/lib/extract.js +564 -0
- package/lib/import-i18n-transform.js +146 -0
- package/lib/index.js +74 -0
- package/lib/options.js +39 -0
- package/lib/translate.js +308 -0
- package/lib/translators/baidu.js +91 -0
- package/lib/translators/google.js +68 -0
- package/lib/translators/index.js +15 -0
- package/lib/translators/scan.js +24 -0
- package/lib/translators/translator/IntervalQueue.js +60 -0
- package/lib/translators/translator/Translator.js +62 -0
- package/lib/translators/translator/index.js +5 -0
- package/lib/translators/volcengine.js +131 -0
- package/lib/translators/youdao.js +89 -0
- package/lib/utils.js +234 -0
- package/lib/visitors.js +246 -0
- package/lib/vite-plugin-i18n.js +73 -0
- package/lib/vite-plugin-import-i18n.js +46 -0
- package/lib/vue-i18n-loader.js +54 -0
- package/lib/webpack-import-i18n-loader.js +69 -0
- package/lib/webpack-plugin-i18n.js +176 -0
- package/package.json +47 -0
package/.prettierrc
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020-present kazuya kawaguchi and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# vue-i18n-extract-plugin
|
|
2
|
+
|
|
3
|
+
- 针对vue/react项目,从js/jsx/ts/tsx/vue文件提取语言,生成语言包到json文件中,支持将生成的key重写入文件中(rewrite模式),并且支持自动翻译后生成翻译json文件.
|
|
4
|
+
- 包含了vite和webpack的插件.
|
|
5
|
+
|
|
6
|
+
# USAGE
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# npm
|
|
12
|
+
npm i vue-i18n-extract-plugin -D
|
|
13
|
+
# global
|
|
14
|
+
npm i vue-i18n-extract-plugin -g
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# yarn
|
|
19
|
+
yarn add vue-i18n-extract-plugin --dev
|
|
20
|
+
# global
|
|
21
|
+
yarn global add vue-i18n-extract-plugin
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## CLI
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
extract-i18n --includePath=demo --rewrite
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
这会提取demo目录下的所有`allowedExtensions`文件的`fromLang`,并生成一个对应的JSON文件,如果开启了自动翻译,则会自动翻译并生成对应的翻译JSON文件.
|
|
31
|
+
|
|
32
|
+
## Programming API
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const { extractI18n } = require("vue-i18n-extract-plugin");
|
|
36
|
+
|
|
37
|
+
extractI18n(options)
|
|
38
|
+
.then(() => {
|
|
39
|
+
console.log("extract done!");
|
|
40
|
+
})
|
|
41
|
+
.catch(err => {
|
|
42
|
+
console.error("extract error:", err);
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const defaultOptions = {
|
|
50
|
+
translateKey: "$t", // 提取的函数的名称
|
|
51
|
+
rewrite: true, // 是否将提取到的内容转换为id后重写入源文件
|
|
52
|
+
extractFromText: true, // 是否允许从纯文本节点中提取翻译内容
|
|
53
|
+
autoImportI18n: true, // 是否自动导入 i18n 模块
|
|
54
|
+
autoTranslate: true, // 提取完成后是否自动翻译
|
|
55
|
+
cleanTranslate: true, // 是否清理无用的翻译内容
|
|
56
|
+
enableExtractInPlugin: true, // 是否在插件中自动提取翻译内容
|
|
57
|
+
outputJsonFileInPlugin: true, // 是否在插件中输出 JSON 文件
|
|
58
|
+
outputJsonFileDebounceTimeInPlugin: 2000, // 输出 JSON 文件的防抖时间
|
|
59
|
+
translateInterval: 1000, // 自动翻译的间隔时间
|
|
60
|
+
excludedCall: [], // 排除的调用函数名称数组,目前已内置的函数请参阅:https://github.com/semdy/vue-i18n-extract-plugin/blob/main/lib/utils.js#L189
|
|
61
|
+
includePath: ['src/'], // 包含路径的数组
|
|
62
|
+
excludedPath: [], // 排除路径的数组 refer to https://github.com/mrmlnc/fast-glob?tab=readme-ov-file#how-to-exclude-directory-from-reading
|
|
63
|
+
allowedExtensions: [".vue", ".tsx", ".ts", ".jsx", ".js"], // 允许提取的文件扩展名
|
|
64
|
+
fromLang: 'zh-cn', // 源语言, 目前支持提取的语言有:zh-cn(zh-tw), en, ja, ko, ru
|
|
65
|
+
translateLangKeys: ["zh-tw", "en"], // 需要翻译为的语言键
|
|
66
|
+
i18nPkgImportPath: "@/i18n", // i18n语言包导入路径
|
|
67
|
+
outputPath: "src/i18n", // 提取的语言包输出文件路径
|
|
68
|
+
customGenLangFileName: langKey => langKey, // 自定义生成语言文件名
|
|
69
|
+
// 翻译后的文本处理函数,方便对翻译后的文本进行二次加工,如每个单词首字母大写, params: text: 翻译后的文本, toLang: 翻译后的目标语言,translateLangKeys的枚举成员
|
|
70
|
+
customTranslatedText: (text, toLang) => text,
|
|
71
|
+
/* 翻译器,默认使用GoogleTranslator,也可以自定义实现Translator接口 */
|
|
72
|
+
translator: new GoogleTranslator()
|
|
73
|
+
/** 如开启了端口代理,请配置port,如:7890 */
|
|
74
|
+
translator: new GoogleTranslator({
|
|
75
|
+
proxyOption: {
|
|
76
|
+
port: 7890,
|
|
77
|
+
host: '127.0.0.1',
|
|
78
|
+
headers: {
|
|
79
|
+
'User-Agent': 'Node'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Configuration file
|
|
87
|
+
|
|
88
|
+
在项目根目录创建extract-i18n.config.js,用于cli参数的配置.
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
import { YoudaoTranslator } from "vite-i18n-extract-plugin/translators";
|
|
92
|
+
|
|
93
|
+
export default {
|
|
94
|
+
rewrite: false,
|
|
95
|
+
translator: new YoudaoTranslator({
|
|
96
|
+
appId: "youdao appId",
|
|
97
|
+
appKey: "youdao appKey"
|
|
98
|
+
}),
|
|
99
|
+
...
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Vite plugin
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
import { defineConfig } from "vite";
|
|
107
|
+
import vue from "@vitejs/plugin-vue";
|
|
108
|
+
import { vitePluginImportI18n, vitePluginI18n } from "vue-i18n-extract-plugin";
|
|
109
|
+
|
|
110
|
+
export default defineConfig({
|
|
111
|
+
plugins: [
|
|
112
|
+
// 自动添加import { $t } from '@/i18n'导入语句,请在i18n文件导出一个$t的方法. 注意顺序,必放在vue插件之前
|
|
113
|
+
vitePluginImportI18n(options),
|
|
114
|
+
vue(),
|
|
115
|
+
// 用于运行时转换. 注意顺序,必放在vue插件之后
|
|
116
|
+
vitePluginI18n(options)
|
|
117
|
+
]
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Webpack plugin
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const { WebpackPluginI18n } = require("vue-i18n-extract-plugin");
|
|
125
|
+
|
|
126
|
+
module.exports = {
|
|
127
|
+
plugins: [
|
|
128
|
+
new VueLoaderPlugin(),
|
|
129
|
+
new HtmlWebpackPlugin({
|
|
130
|
+
template: "./public/index.html"
|
|
131
|
+
}),
|
|
132
|
+
new WebpackPluginI18n(options)
|
|
133
|
+
]
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## **重要说明**
|
|
138
|
+
|
|
139
|
+
在Vue3中,vue-i18n版本大于9.0.0时,legacy须设为false,否则在开发阶段会有`Uncaught TypeError: 'set' on proxy: trap returned falsish for property '$t'`的代理错误. 推荐写法如下:
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
import { createI18n } from "vue-i18n";
|
|
143
|
+
import zhMessages from "@/locales/zh-cn.json";
|
|
144
|
+
import enMessages from "@/locales/en.json";
|
|
145
|
+
|
|
146
|
+
const i18n = createI18n({
|
|
147
|
+
legacy: false,
|
|
148
|
+
fallbackLocale: "en",
|
|
149
|
+
locale: "zh",
|
|
150
|
+
messages: {
|
|
151
|
+
en: enMessages,
|
|
152
|
+
zh: zhMessages
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// 导出一个$t方法
|
|
157
|
+
export const $t = i18n.global.t.bind(i18n.global);
|
|
158
|
+
|
|
159
|
+
export default i18n;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
另外:如果不想使用vite/webpack插件,可以手动调用`extract-i18n --rewrite`,这会将转换后的代码重新写入源文件(uni-app X项目可用于此模式).
|
|
163
|
+
|
|
164
|
+
# Translators
|
|
165
|
+
|
|
166
|
+
插件默认使用谷歌翻译(默认配置代理端口7890)。在网络不支持访问谷歌的情况下,我们推荐使用 **有道翻译** ✨,其翻译效果优秀。目前插件已经内置谷歌、有道和百度翻译功能。如果需要自定义翻译器,可参考下方的示例。
|
|
167
|
+
|
|
168
|
+
## Google Translate (default)
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import { GoogleTranslator } from 'vue-i18n-extract-plugin/translators'
|
|
172
|
+
|
|
173
|
+
...
|
|
174
|
+
translator: new GoogleTranslator({
|
|
175
|
+
proxyOption: {
|
|
176
|
+
host: '127.0.0.1',
|
|
177
|
+
port: 7890,
|
|
178
|
+
headers: {
|
|
179
|
+
'User-Agent': 'Node'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
...
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 有道Translate
|
|
187
|
+
|
|
188
|
+
需要申请api,[api文档](https://ai.youdao.com/DOCSIRMA/html/trans/api/wbfy/index.html)。
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
import { YoudaoTranslator } from 'vue-i18n-extract-plugin/translators'
|
|
192
|
+
|
|
193
|
+
...
|
|
194
|
+
translator: new YoudaoTranslator({
|
|
195
|
+
appId: '你申请的appId',
|
|
196
|
+
appKey: '你申请的appKey'
|
|
197
|
+
})
|
|
198
|
+
...
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## 百度Translate
|
|
202
|
+
|
|
203
|
+
需要申请api,[api文档](https://api.fanyi.baidu.com/product/113)。
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
import { BaiduTranslator } from 'vue-i18n-extract-plugin/translators'
|
|
207
|
+
|
|
208
|
+
...
|
|
209
|
+
translator: new BaiduTranslator({
|
|
210
|
+
appId: '你申请的appId', // 百度翻译 AppId
|
|
211
|
+
appKey: '你申请的appKey' // 百度翻译 AppKey
|
|
212
|
+
})
|
|
213
|
+
...
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## 火山引擎AI Translate
|
|
217
|
+
|
|
218
|
+
支持调用 `doubao` 或 `deepseek` 进行翻译,AI大模型的翻译效果会比传统的API翻译更准确,但耗时较长。
|
|
219
|
+
火山引擎大模型介绍:https://www.volcengine.com/docs/82379/1099455。
|
|
220
|
+
需要开通大模型服务并申请API,[api文档](https://www.volcengine.com/docs/82379/1298454)。
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
import { VolcEngineTranslator } from 'vue-i18n-extract-plugin/translators'
|
|
224
|
+
|
|
225
|
+
...
|
|
226
|
+
translator: new VolcEngineTranslator({
|
|
227
|
+
apiKey: '你申请的apiKey',
|
|
228
|
+
model: '你要调用的模型,如:`doubao-1-5-pro-32k-250115`,请确保使用前已在控制台开通了对应模型'
|
|
229
|
+
})
|
|
230
|
+
...
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Empty Translate
|
|
234
|
+
|
|
235
|
+
如果只需要扫描目标语言,不进行翻译,该翻译器会生成 JSON 文件。
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
import { EmptyTranslator } from 'vue-i18n-extract-plugin/translators'
|
|
239
|
+
|
|
240
|
+
...
|
|
241
|
+
translator: new EmptyTranslator()
|
|
242
|
+
...
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Custom Translate
|
|
246
|
+
|
|
247
|
+
如果你有一个自用的翻译接口,可以通过以下方式自定义翻译器——
|
|
248
|
+
|
|
249
|
+
最简单的方式是使用 Translator 基类定义翻译器实例。
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
import { Translator } from 'vue-i18n-extract-plugin/translators'
|
|
253
|
+
import axios from 'axios'
|
|
254
|
+
|
|
255
|
+
...
|
|
256
|
+
translator: new Translator({
|
|
257
|
+
name: '我的翻译器',
|
|
258
|
+
// 翻译的方法
|
|
259
|
+
fetchMethod: (str, fromKey, toKey, _separator) => {
|
|
260
|
+
// 实际的接口调用可能比示例更复杂,具体可参考源码中YoudaoTranslator的实现,路径:src\translators\youdao.js
|
|
261
|
+
const myApi = 'https://www.my-i18n.cn/api/translate?from=${fromKey}&to=${toKey}&t={+new Date}'
|
|
262
|
+
return axios.post(myApi, { str })
|
|
263
|
+
.then(res => res.data)
|
|
264
|
+
},
|
|
265
|
+
// 接口触发间隔,有些接口频繁触发会被拉黑,请根据实际情况设置一个合理的接口触发间隔
|
|
266
|
+
interval: 1000
|
|
267
|
+
})
|
|
268
|
+
...
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
如果需要更高阶的功能,可以使用继承,不过目前无相关场景。
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
import { Translator } from 'vue-i18n-extract-plugin/translators'
|
|
275
|
+
|
|
276
|
+
class CustomTranslator extends Translator {
|
|
277
|
+
constructor () {
|
|
278
|
+
super({
|
|
279
|
+
name: '我的翻译器',
|
|
280
|
+
...
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
...
|
|
286
|
+
translator: new CustomTranslator()
|
|
287
|
+
...
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## :copyright: License
|
|
291
|
+
|
|
292
|
+
[MIT](http://opensource.org/licenses/MIT)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { declare } = require("@babel/helper-plugin-utils");
|
|
2
|
+
const { createI18nPlugin } = require("./visitors");
|
|
3
|
+
const { defaultOptions } = require("./options");
|
|
4
|
+
|
|
5
|
+
module.exports = declare((api, options) => {
|
|
6
|
+
api.assertVersion(7);
|
|
7
|
+
options = { ...defaultOptions, ...options };
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
name: "i18n-hash-replace",
|
|
11
|
+
...createI18nPlugin(options)()
|
|
12
|
+
};
|
|
13
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const t = require("@babel/types");
|
|
2
|
+
const { defaultOptions } = require("./options");
|
|
3
|
+
|
|
4
|
+
module.exports = function () {
|
|
5
|
+
return {
|
|
6
|
+
name: "auto-import-i18n",
|
|
7
|
+
visitor: {
|
|
8
|
+
Program(path, state) {
|
|
9
|
+
const { translateKey: importName, i18nPkgImportPath: importPath } = {
|
|
10
|
+
...defaultOptions,
|
|
11
|
+
...state.opts
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const localName = importName;
|
|
15
|
+
let hasI18nImport = false;
|
|
16
|
+
let lastImportPath = null;
|
|
17
|
+
let conflictTDefined = false;
|
|
18
|
+
|
|
19
|
+
path.traverse({
|
|
20
|
+
// ImportDeclaration(path) {
|
|
21
|
+
// lastImportPath = path;
|
|
22
|
+
// if (
|
|
23
|
+
// path.node.source.value === importPath &&
|
|
24
|
+
// path.node.specifiers.some(
|
|
25
|
+
// spec =>
|
|
26
|
+
// t.isImportSpecifier(spec) && spec.imported.name === importName
|
|
27
|
+
// )
|
|
28
|
+
// ) {
|
|
29
|
+
// hasI18nImport = true;
|
|
30
|
+
// }
|
|
31
|
+
// },
|
|
32
|
+
ImportDeclaration(path) {
|
|
33
|
+
lastImportPath = path;
|
|
34
|
+
|
|
35
|
+
const sourcePath = path.node.source.value;
|
|
36
|
+
|
|
37
|
+
// 判断是否是其它路径导入了 $t
|
|
38
|
+
const importedTElsewhere = path.node.specifiers.some(spec => {
|
|
39
|
+
return (
|
|
40
|
+
(t.isImportSpecifier(spec) ||
|
|
41
|
+
t.isImportDefaultSpecifier(spec)) &&
|
|
42
|
+
spec.local.name === importName &&
|
|
43
|
+
sourcePath !== importPath
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (importedTElsewhere) {
|
|
48
|
+
conflictTDefined = true;
|
|
49
|
+
path.stop();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 检查是否已经导入目标路径
|
|
54
|
+
if (sourcePath === importPath) {
|
|
55
|
+
hasI18nImport = true;
|
|
56
|
+
|
|
57
|
+
// 情况1:已有 import { $t } from '@/i18n'
|
|
58
|
+
const existingImport = path.node.specifiers.find(
|
|
59
|
+
spec =>
|
|
60
|
+
t.isImportSpecifier(spec) && spec.imported.name === importName
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (existingImport) return;
|
|
64
|
+
|
|
65
|
+
// if (
|
|
66
|
+
// existingImport &&
|
|
67
|
+
// !t.isImportSpecifier(existingImport, {
|
|
68
|
+
// local: { name: localName }
|
|
69
|
+
// })
|
|
70
|
+
// ) {
|
|
71
|
+
// // 将 $t 改为 _$t
|
|
72
|
+
// existingImport.local = t.identifier(localName);
|
|
73
|
+
// } else
|
|
74
|
+
// 情况2:已有 import i18n from '@/i18n'
|
|
75
|
+
|
|
76
|
+
// 添加 $t 到已有的 import
|
|
77
|
+
path.node.specifiers.push(
|
|
78
|
+
t.importSpecifier(
|
|
79
|
+
t.identifier(localName),
|
|
80
|
+
t.identifier(importName)
|
|
81
|
+
)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
VariableDeclarator(path) {
|
|
86
|
+
if (
|
|
87
|
+
t.isIdentifier(path.node.id) &&
|
|
88
|
+
path.node.id.name === importName
|
|
89
|
+
) {
|
|
90
|
+
conflictTDefined = true;
|
|
91
|
+
path.stop();
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
FunctionDeclaration(path) {
|
|
96
|
+
if (
|
|
97
|
+
t.isIdentifier(path.node.id) &&
|
|
98
|
+
path.node.id.name === importName
|
|
99
|
+
) {
|
|
100
|
+
conflictTDefined = true;
|
|
101
|
+
path.stop();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 跳过导入语句的生成
|
|
107
|
+
if (conflictTDefined) {
|
|
108
|
+
return {
|
|
109
|
+
ast,
|
|
110
|
+
needTransform: false
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 情况4:完全没有导入 @/i18n
|
|
115
|
+
if (!hasI18nImport) {
|
|
116
|
+
const importNode = t.importDeclaration(
|
|
117
|
+
[
|
|
118
|
+
// t.importDefaultSpecifier(t.identifier("i18n")),
|
|
119
|
+
t.importSpecifier(
|
|
120
|
+
t.identifier(localName),
|
|
121
|
+
t.identifier(importName)
|
|
122
|
+
)
|
|
123
|
+
],
|
|
124
|
+
t.stringLiteral(importPath)
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (lastImportPath) {
|
|
128
|
+
// 插入到最后一个 import 之后
|
|
129
|
+
lastImportPath.insertAfter(importNode);
|
|
130
|
+
} else {
|
|
131
|
+
// 插入到文件顶部
|
|
132
|
+
path.unshiftContainer("body", importNode);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* // babel.config.js
|
|
142
|
+
module.exports = {
|
|
143
|
+
presets: ['@vue/cli-plugin-babel/preset'],
|
|
144
|
+
plugins: [
|
|
145
|
+
[
|
|
146
|
+
'vue-i18n-extract-plugin/babel-plugin-import-i18n.js', // 插件路径
|
|
147
|
+
{
|
|
148
|
+
importName: '$t', // 可选,默认 '$t'
|
|
149
|
+
importPath: '@/i18n', // 可选,默认 '@/i18n'
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
*/
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { parseArg } = require("./utils");
|
|
4
|
+
const { extractI18n } = require("./extract");
|
|
5
|
+
const { autoTranslateFromFile, cleanTranslate } = require("./translate");
|
|
6
|
+
const { version, bin } = require("../package.json");
|
|
7
|
+
|
|
8
|
+
const cli = async function (args) {
|
|
9
|
+
let options = args.reduce((acc, arg) => {
|
|
10
|
+
const [key, value] = arg.split("=");
|
|
11
|
+
acc[key.replace(/\-\-|\-/, "")] = !value ? true : parseArg(value);
|
|
12
|
+
return acc;
|
|
13
|
+
}, {});
|
|
14
|
+
|
|
15
|
+
const hasVersion = options.version || options.V || options.v;
|
|
16
|
+
|
|
17
|
+
if (hasVersion) {
|
|
18
|
+
console.log("current version:", version);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (Object.keys(options).length === 1) {
|
|
22
|
+
if (hasVersion) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (options.translate || options.t) {
|
|
26
|
+
await autoTranslateFromFile();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (options.clean || options.c) {
|
|
30
|
+
await cleanTranslate();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { loadConfig } = await import("c12");
|
|
36
|
+
|
|
37
|
+
const { config: configFromFile } = await loadConfig({
|
|
38
|
+
name: Object.keys(bin)[0]
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
options = Object.assign({ rewrite: false }, configFromFile, options);
|
|
42
|
+
|
|
43
|
+
console.log("开始提取国际化内容...\n", options);
|
|
44
|
+
|
|
45
|
+
extractI18n(options)
|
|
46
|
+
.then(() => {
|
|
47
|
+
console.log("国际化提取完成!");
|
|
48
|
+
})
|
|
49
|
+
.catch(err => {
|
|
50
|
+
console.error("提取国际化失败:", err);
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
cli(process.argv.slice(2));
|