@chaoswise/intl 1.0.0 → 1.2.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/bin/chaoswise-intl.js +5 -1
- package/bin/scripts/collect.js +38 -18
- package/bin/scripts/conf/default.js +40 -2
- package/bin/scripts/conf/getCustomConfig.js +8 -0
- package/bin/scripts/conf/index.js +2 -25
- package/bin/scripts/conf/initConfig.js +37 -0
- package/bin/scripts/initConfig.js +3 -0
- package/bin/scripts/service/index.js +2 -2
- package/bin/scripts/update.js +5 -5
- package/bin/scripts/util/FormPath/contexts.d.ts +10 -0
- package/bin/scripts/util/FormPath/contexts.js +23 -0
- package/bin/scripts/util/FormPath/destructor.d.ts +15 -0
- package/bin/scripts/util/FormPath/destructor.js +124 -0
- package/bin/scripts/util/FormPath/index.d.ts +49 -0
- package/bin/scripts/util/FormPath/index.js +536 -0
- package/bin/scripts/util/FormPath/lru.d.ts +1 -0
- package/bin/scripts/util/FormPath/lru.js +246 -0
- package/bin/scripts/util/FormPath/matcher.d.ts +33 -0
- package/bin/scripts/util/FormPath/matcher.js +216 -0
- package/bin/scripts/util/FormPath/parser.d.ts +28 -0
- package/bin/scripts/util/FormPath/parser.js +302 -0
- package/bin/scripts/util/FormPath/tokenizer.d.ts +26 -0
- package/bin/scripts/util/FormPath/tokenizer.js +280 -0
- package/bin/scripts/util/FormPath/tokens.d.ts +26 -0
- package/bin/scripts/util/FormPath/tokens.js +212 -0
- package/bin/scripts/util/FormPath/types.d.ts +76 -0
- package/bin/scripts/util/FormPath/types.js +17 -0
- package/bin/scripts/util/FormPath/utils.d.ts +10 -0
- package/bin/scripts/util/FormPath/utils.js +63 -0
- package/bin/scripts/util/downloadJson.js +10 -1
- package/bin/scripts/util/file.js +31 -0
- package/bin/scripts/util/getGroupName.js +15 -0
- package/bin/scripts/util/getWord.js +13 -0
- package/bin/scripts/util/log.js +25 -4
- package/bin/scripts/util/makeVisitorCollect.js +351 -46
- package/bin/scripts/util/makeVisitorUpdate.js +38 -1
- package/bin/scripts/util/specialMatch.js +14 -0
- package/bin/scripts/util/transformAst.js +30 -22
- package/bin/scripts/util/writeNewWordsFile.js +30 -0
- package/lib/index.js +2 -1
- package/package.json +7 -5
|
@@ -1,30 +1,179 @@
|
|
|
1
1
|
const log = require('./log');
|
|
2
2
|
const t = require('@babel/types');
|
|
3
|
+
const generate = require('@babel/generator').default;
|
|
4
|
+
const { getWord } = require('./getWord');
|
|
5
|
+
const specialMatch = require('./specialMatch');
|
|
6
|
+
const { Path: FormPath } = require('./FormPath');
|
|
3
7
|
|
|
4
|
-
|
|
8
|
+
const commentStr = ' @chaoswise/intl脚本替换失败 ';
|
|
9
|
+
|
|
10
|
+
module.exports = function (
|
|
5
11
|
{
|
|
6
12
|
primaryRegx,
|
|
7
13
|
i18nObject,
|
|
8
14
|
i18nMethod,
|
|
15
|
+
i18nDefaultFunctionKey,
|
|
9
16
|
importCode,
|
|
10
17
|
ignoreLines,
|
|
11
18
|
ignoreMethods,
|
|
12
19
|
ignoreComponents = [],
|
|
13
20
|
ignoreAttributes,
|
|
21
|
+
intlTag,
|
|
22
|
+
intlTagIdPath,
|
|
23
|
+
intlTagDefaultWordPath,
|
|
24
|
+
intlFunctionName,
|
|
25
|
+
intlFunctionIdPath,
|
|
26
|
+
intlFunctionDefaultWordPath,
|
|
27
|
+
removePkgName,
|
|
28
|
+
localWordPath,
|
|
29
|
+
removeFunctionName,
|
|
14
30
|
},
|
|
15
|
-
returns
|
|
31
|
+
returns,
|
|
32
|
+
{ filePath, special },
|
|
16
33
|
) {
|
|
34
|
+
|
|
35
|
+
// jsx默认 defaultMessage
|
|
36
|
+
intlTagDefaultWordPath = intlTagDefaultWordPath || 'defaultMessage';
|
|
37
|
+
|
|
17
38
|
const { replaceWords, allWords, downloadIds } = returns;
|
|
18
39
|
const hacked = {};
|
|
19
40
|
|
|
41
|
+
// 在没有replaceWords的情况下,不用log信息,这里统一处理
|
|
42
|
+
const properLog = {};
|
|
43
|
+
Object.keys(log).forEach(fnName => {
|
|
44
|
+
properLog[fnName] = (...args) => {
|
|
45
|
+
if (!Object.keys(replaceWords).length) return;
|
|
46
|
+
log[fnName](...args);
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// 获取完整路劲。例如:path='key',返回'0.key'
|
|
51
|
+
function getFullPath (path) {
|
|
52
|
+
if (!path) return path;
|
|
53
|
+
if (typeof path !== 'string') return path;
|
|
54
|
+
if (/^[0-9]/.test(path)) {
|
|
55
|
+
return path;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let preFixPath = '0';
|
|
59
|
+
if (!/^\./.test(path)) {
|
|
60
|
+
preFixPath = '0.';
|
|
61
|
+
}
|
|
62
|
+
return preFixPath + path;
|
|
63
|
+
}
|
|
64
|
+
// 插入注释
|
|
65
|
+
function insertFailCommon(node) {
|
|
66
|
+
const comment = node?.leadingComments?.value
|
|
67
|
+
if (comment && comment.trim() === commentStr) return;
|
|
68
|
+
t.addComment(node, 'leading', commentStr);
|
|
69
|
+
}
|
|
70
|
+
// 在jsx中插入注释
|
|
71
|
+
function insertFailCommonInJsx(path) {
|
|
72
|
+
const comment = path?.node?.leadingComments?.value
|
|
73
|
+
if (comment && comment.trim() === commentStr) return;
|
|
74
|
+
path.insertBefore(
|
|
75
|
+
t.jsxExpressionContainer(
|
|
76
|
+
{
|
|
77
|
+
"type": "JSXEmptyExpression",
|
|
78
|
+
"innerComments": [
|
|
79
|
+
{
|
|
80
|
+
"type": "CommentBlock",
|
|
81
|
+
"value": commentStr
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 获取国际化jsx标签中的id或者defaultMessage
|
|
90
|
+
function getJsxTagChaoswiseIntlValue(openingElement, intlTagValuePath) {
|
|
91
|
+
// <Tag id={{ x: ['id'] }} defaultMessage={{ x: ['中文'] }} />
|
|
92
|
+
// valueAst是{ x: ['id'] }的ast
|
|
93
|
+
let valueAst;
|
|
94
|
+
// intlTagValuePath 是 id.x.0
|
|
95
|
+
// valueKey 是 id
|
|
96
|
+
// valuePath 是 x.0
|
|
97
|
+
let valueKey = intlTagValuePath;
|
|
98
|
+
let valuePath = '';
|
|
99
|
+
|
|
100
|
+
const index = (intlTagValuePath || '').indexOf('.');
|
|
101
|
+
if (index !== -1) {
|
|
102
|
+
valueKey = intlTagValuePath.slice(0, index);
|
|
103
|
+
valuePath = intlTagValuePath.slice(index + 1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// <Tag {...props} />不能找到对应的值
|
|
107
|
+
valueAst = openingElement.attributes.find((item) => {
|
|
108
|
+
return item?.name?.name === valueKey;
|
|
109
|
+
})?.value;
|
|
110
|
+
// intlTagValuePath配置不正确就会找不到value
|
|
111
|
+
// 比如<Tag id2='id' /> 把intlTagValuePath配置为id就不行,因为这里应该是id2
|
|
112
|
+
if (!valueAst) return false;
|
|
113
|
+
|
|
114
|
+
// 如果是jsx容器,就 去掉jsx容器,拿里面的值
|
|
115
|
+
// 从{{ x: ['id'] }} 变为 { x: ['id'] }
|
|
116
|
+
if (valueAst.type === 'JSXExpressionContainer') {
|
|
117
|
+
valueAst = valueAst.expression;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 把ast转为js, 再用FormPath.getIn来取最终的值
|
|
121
|
+
const { code: valueCode } = generate(valueAst);
|
|
122
|
+
var chaoswiseIntlValue;
|
|
123
|
+
try {
|
|
124
|
+
eval('var chaoswiseIntlValue =' + valueCode);
|
|
125
|
+
chaoswiseIntlValue = FormPath.getIn(chaoswiseIntlValue, valuePath);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
// var a = 'id'; <Tag id={a} 这样会出错
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (typeof chaoswiseIntlValue !== 'string') {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return chaoswiseIntlValue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 获取函数名称 fn/object.fn/object.a.b.c/intl.get().d
|
|
138
|
+
function getFnName(node) {
|
|
139
|
+
let fnName = '';
|
|
140
|
+
while (['CallExpression', 'MemberExpression', 'Identifier'].includes(node?.type)) {
|
|
141
|
+
if (node.type === 'CallExpression') {
|
|
142
|
+
let name = getFnName(node.callee);
|
|
143
|
+
fnName = `${name}().` + fnName;
|
|
144
|
+
break;
|
|
145
|
+
} else if (node.type === 'MemberExpression') {
|
|
146
|
+
fnName = `${node.property.name}.` + fnName;
|
|
147
|
+
if (node.object.name) {
|
|
148
|
+
fnName = `${node.object.name}.` + fnName;
|
|
149
|
+
}
|
|
150
|
+
node = node.object;
|
|
151
|
+
} else if (node.type === 'Identifier') {
|
|
152
|
+
// 这里获取修饰器的函数名称
|
|
153
|
+
fnName = fnName || (node.name + '.')
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 把最后的 点. 取消
|
|
159
|
+
fnName = fnName.slice(0, -1);
|
|
160
|
+
return fnName;
|
|
161
|
+
}
|
|
162
|
+
|
|
20
163
|
// XXX: [TRICKY] 防止中文转码为 unicode
|
|
21
164
|
function hackValue(value, id) {
|
|
22
165
|
if (id) hacked[id] = true;
|
|
23
166
|
|
|
167
|
+
// 字符串默认是单引号,如果模板字符串中出现单引号,需要转义,把 ' 换成 \'
|
|
168
|
+
// 就算用户自定配置字符串为双引号,也没事,默认会转义双引号,但是默认不会处理单引号,所以自己手动处理
|
|
169
|
+
if (/\'/.test(id)) {
|
|
170
|
+
id = id.replace(/\'/g, '\\\'');
|
|
171
|
+
}
|
|
172
|
+
|
|
24
173
|
return Object.assign(t.StringLiteral(value), {
|
|
25
174
|
extra: {
|
|
26
175
|
raw: `'${id}'`, // id
|
|
27
|
-
rawValue: value, //
|
|
176
|
+
rawValue: value, // word
|
|
28
177
|
},
|
|
29
178
|
});
|
|
30
179
|
}
|
|
@@ -37,8 +186,12 @@ module.exports = function(
|
|
|
37
186
|
return false;
|
|
38
187
|
}
|
|
39
188
|
|
|
40
|
-
//
|
|
189
|
+
// 是否命中替换条件
|
|
41
190
|
function isPrimary(str) {
|
|
191
|
+
if (special) {
|
|
192
|
+
// 如果匹配到了替换过的,就返回false。为了防止多次执行collect,多次嵌套替换
|
|
193
|
+
if (specialMatch(str)) return false;
|
|
194
|
+
}
|
|
42
195
|
return primaryRegx.test(str);
|
|
43
196
|
}
|
|
44
197
|
|
|
@@ -58,28 +211,37 @@ module.exports = function(
|
|
|
58
211
|
function makeObjectExpression(obj) {
|
|
59
212
|
if (Object.prototype.toString.call(obj) !== '[object Object]') return null;
|
|
60
213
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
214
|
+
// 模板字符串中,转换后,如果第二项参数还有中文,或者更深层级有中文,这里处理好
|
|
215
|
+
// 模板字符串转换前`${f(`aa${f('中文')}中文`)}中文`
|
|
216
|
+
/* 转换后
|
|
217
|
+
intl
|
|
218
|
+
.get('id1', {
|
|
219
|
+
slot0: f(
|
|
220
|
+
intl
|
|
221
|
+
.get('id2', { slot0: f(intl.get('id3').d('中文')) })
|
|
222
|
+
.d('aa{slot0}中文')
|
|
223
|
+
),
|
|
224
|
+
})
|
|
225
|
+
.d('{slot0}中文');
|
|
226
|
+
*/
|
|
227
|
+
const keys = Object.keys(obj);
|
|
228
|
+
const datas = dealArgs(Object.values(obj).map(item => item.value || item));
|
|
229
|
+
|
|
230
|
+
return t.ObjectExpression(
|
|
231
|
+
keys.map((k, i) => {
|
|
232
|
+
const node = datas[i];
|
|
233
|
+
return t.ObjectProperty(
|
|
71
234
|
t.Identifier(k),
|
|
72
|
-
obj[k].isAstNode ?
|
|
235
|
+
obj[k].isAstNode ? node : t.Identifier(obj[k])
|
|
73
236
|
)
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
return t.ObjectExpression(ObjectPropertyArr);
|
|
237
|
+
})
|
|
238
|
+
);
|
|
77
239
|
}
|
|
78
240
|
|
|
79
241
|
// 更新allWords
|
|
80
|
-
function updateWordsInfo(
|
|
81
|
-
if (allWords.includes(
|
|
82
|
-
allWords.push(
|
|
242
|
+
function updateWordsInfo(word) {
|
|
243
|
+
if (allWords.includes(word)) return;
|
|
244
|
+
allWords.push(word);
|
|
83
245
|
}
|
|
84
246
|
|
|
85
247
|
// 处理函数的argments
|
|
@@ -87,7 +249,7 @@ module.exports = function(
|
|
|
87
249
|
if (!Array.isArray(args)) return args;
|
|
88
250
|
const resArgs = []; // 参数处理完,用resArgs保存
|
|
89
251
|
args.forEach(node => {
|
|
90
|
-
|
|
252
|
+
// 字符串变量
|
|
91
253
|
if (node.type === 'StringLiteral' && isPrimary(node.value)) {
|
|
92
254
|
resArgs.push(makeReplace(node.value));
|
|
93
255
|
}
|
|
@@ -141,6 +303,11 @@ module.exports = function(
|
|
|
141
303
|
// 将中文词条替换为国际化api:init.t(id/key)
|
|
142
304
|
const id = replaceWords[value];
|
|
143
305
|
|
|
306
|
+
// 特殊文件处理
|
|
307
|
+
if (special) {
|
|
308
|
+
const str = `${i18nObject ? `${i18nObject}.` : ''}${i18nMethod}("${id}").${i18nDefaultFunctionKey}("${value}")`;
|
|
309
|
+
return hackValue(str, str,);
|
|
310
|
+
}
|
|
144
311
|
// 生成新的ast节点
|
|
145
312
|
const v = hackValue(value, id);
|
|
146
313
|
const objExp = makeObjectExpression(variables);
|
|
@@ -157,7 +324,7 @@ module.exports = function(
|
|
|
157
324
|
: t.identifier(i18nMethod),
|
|
158
325
|
objExp ? [v, objExp] : [v]
|
|
159
326
|
)
|
|
160
|
-
, t.identifier(
|
|
327
|
+
, t.identifier(i18nDefaultFunctionKey)
|
|
161
328
|
),
|
|
162
329
|
[defaultV]
|
|
163
330
|
);
|
|
@@ -230,67 +397,119 @@ module.exports = function(
|
|
|
230
397
|
}
|
|
231
398
|
return { needReplace, value };
|
|
232
399
|
}
|
|
400
|
+
|
|
233
401
|
// 函数表达式
|
|
234
402
|
function dealCallExpressionNode(node) {
|
|
235
403
|
const res = {
|
|
236
404
|
needReplace: false,
|
|
237
405
|
value: null,
|
|
238
406
|
skip: false,
|
|
407
|
+
remove: false,
|
|
239
408
|
}
|
|
240
409
|
if (shouldIgnore(node)) {
|
|
241
410
|
res.skip = true;
|
|
242
411
|
return res;
|
|
243
412
|
}
|
|
244
413
|
|
|
414
|
+
const fnName = getFnName(node.callee);
|
|
415
|
+
|
|
245
416
|
// 处理 ignoreMethods
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
417
|
+
if ([
|
|
418
|
+
...(ignoreMethods || []),
|
|
419
|
+
`${i18nObject}.${i18nMethod}`, // intl.get
|
|
420
|
+
`${i18nObject}.${i18nMethod}().${i18nDefaultFunctionKey}`, // intl.get().d
|
|
421
|
+
].includes(fnName)) {
|
|
422
|
+
res.skip = true;
|
|
423
|
+
return res;
|
|
424
|
+
}
|
|
254
425
|
|
|
255
|
-
|
|
426
|
+
// 需要删除的函数
|
|
427
|
+
if (removeFunctionName.includes(fnName)) {
|
|
428
|
+
// 文件需要修改
|
|
429
|
+
returns.hasTouch = true;
|
|
430
|
+
res.remove = true;
|
|
431
|
+
return res;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 已经做过国际化的项目,替换国际化函数
|
|
435
|
+
if (fnName === intlFunctionName) {
|
|
436
|
+
res.skip = true;
|
|
256
437
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
438
|
+
const argsAst = node.arguments;
|
|
439
|
+
// 把ast转为js, 再用FormPath.getIn来取最终的值
|
|
440
|
+
const { code: argsCode } = generate(t.arrayExpression(argsAst));
|
|
441
|
+
let chaoswiseIntlId
|
|
442
|
+
var chaoswiseIntlIdData
|
|
443
|
+
try {
|
|
444
|
+
eval('var chaoswiseIntlIdData =' + argsCode);
|
|
445
|
+
chaoswiseIntlId = FormPath.getIn(chaoswiseIntlIdData, getFullPath(intlFunctionIdPath));
|
|
446
|
+
} catch (e) {
|
|
447
|
+
// var a = 'id'; f(a) 这样会出错
|
|
448
|
+
// TODO
|
|
260
449
|
}
|
|
261
|
-
}
|
|
262
450
|
|
|
263
|
-
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
451
|
+
let value = getWord(chaoswiseIntlId);
|
|
452
|
+
if (!value) {
|
|
453
|
+
let defautValue = FormPath.getIn(chaoswiseIntlIdData, getFullPath(intlFunctionDefaultWordPath));
|
|
454
|
+
if (typeof defautValue === 'string') {
|
|
455
|
+
value = defautValue;
|
|
456
|
+
} else {
|
|
457
|
+
if (intlFunctionIdPath && !chaoswiseIntlId) {
|
|
458
|
+
properLog.warn(`文件:${filePath} 替换的函数名intlFunctionName:${intlFunctionName} id路径intlFunctionIdPath:${intlFunctionIdPath} 未找到非空字符串`)
|
|
459
|
+
}
|
|
460
|
+
if (localWordPath && chaoswiseIntlId && !value) {
|
|
461
|
+
properLog.warn(`中文文件localWordPath:${localWordPath} 键:${chaoswiseIntlId} 未找到非空字符串`)
|
|
462
|
+
}
|
|
463
|
+
if (intlFunctionDefaultWordPath) {
|
|
464
|
+
properLog.warn(`文件:${filePath} 替换的函数名intlFunctionName:${intlFunctionName} 默认中文路径intlFunctionDefaultWordPath:${intlFunctionDefaultWordPath} 未找到非空字符串`)
|
|
465
|
+
}
|
|
466
|
+
insertFailCommon(node);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (value && isPrimary(value)) {
|
|
471
|
+
res.needReplace = true;
|
|
472
|
+
res.value = value;
|
|
267
473
|
}
|
|
268
474
|
}
|
|
269
475
|
|
|
270
476
|
return res;
|
|
271
477
|
}
|
|
272
478
|
|
|
479
|
+
// TODO
|
|
480
|
+
/*
|
|
481
|
+
this.props.intl = lang === 'zh'? '中文': 'en'
|
|
482
|
+
intl.get(id).d('中文')
|
|
483
|
+
this.props.intl.lang = 'zh' ==> intl.lang = 'zh'
|
|
484
|
+
replaceName: { ['this.props.intl.lang']: () => 'intl.lang' }
|
|
485
|
+
或者replaceName: { ['this.props.intl.lang']: 'intl.lang' }
|
|
486
|
+
*/
|
|
273
487
|
return {
|
|
274
488
|
// 导入声明,比如:import foo from "mod";
|
|
275
489
|
ImportDeclaration(path) {
|
|
276
490
|
// 是否已经导入过 intl 的依赖
|
|
277
491
|
const m = importCode.match(/from ["'](.*)["']/);
|
|
278
492
|
const pkgName = m ? m[1] : '';
|
|
279
|
-
|
|
493
|
+
const name = path.node.source.value;
|
|
494
|
+
if (name === pkgName) {
|
|
280
495
|
returns.hasImport = true;
|
|
281
496
|
}
|
|
497
|
+
if (removePkgName.includes(name)) {
|
|
498
|
+
path.remove();
|
|
499
|
+
returns.hasTouch = true;
|
|
500
|
+
}
|
|
282
501
|
path.skip();
|
|
283
502
|
},
|
|
284
503
|
|
|
285
|
-
// 字符串模版,比如:`我的${bar}${fun('哈哈')}中文` intl.
|
|
504
|
+
// 字符串模版,比如:`我的${bar}${fun('哈哈')}中文` intl.get(我的{bar}{slot1}中文,{bar:fdsafdsdf,slot1:fn()})
|
|
286
505
|
TemplateLiteral(path) {
|
|
287
506
|
const { node } = path;
|
|
288
507
|
|
|
289
508
|
const { needReplace, value, variable, } = dealTemplateLiteralNode(node);
|
|
290
509
|
if (needReplace) {
|
|
291
510
|
path.replaceWith(makeReplace(value, Object.keys(variable).length ? variable : null));
|
|
511
|
+
path.skip();
|
|
292
512
|
}
|
|
293
|
-
path.skip();
|
|
294
513
|
},
|
|
295
514
|
|
|
296
515
|
// 字符串变量
|
|
@@ -306,8 +525,17 @@ module.exports = function(
|
|
|
306
525
|
}
|
|
307
526
|
path.replaceWith(res);
|
|
308
527
|
path.skip();
|
|
309
|
-
}
|
|
310
|
-
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
|
|
531
|
+
// 修饰器
|
|
532
|
+
Decorator(path) {
|
|
533
|
+
const { node } = path;
|
|
534
|
+
const fnName = getFnName(node.expression);
|
|
535
|
+
if (removeFunctionName.includes(fnName)) {
|
|
536
|
+
returns.hasTouch = true;
|
|
537
|
+
path.remove();
|
|
538
|
+
path.skip();
|
|
311
539
|
}
|
|
312
540
|
},
|
|
313
541
|
|
|
@@ -315,13 +543,90 @@ module.exports = function(
|
|
|
315
543
|
CallExpression(path) {
|
|
316
544
|
const { node } = path;
|
|
317
545
|
|
|
318
|
-
const { needReplace, value, skip } = dealCallExpressionNode(node);
|
|
546
|
+
const { needReplace, value, skip, remove } = dealCallExpressionNode(node);
|
|
547
|
+
|
|
548
|
+
if (remove) {
|
|
549
|
+
if (node.arguments.length === 1) {
|
|
550
|
+
// 去掉外侧的包裹组件
|
|
551
|
+
path.replaceWith(node.arguments[0]);
|
|
552
|
+
} else {
|
|
553
|
+
// f( 1, 2)
|
|
554
|
+
// 1, 2
|
|
555
|
+
// 移除函数有问题,这里不处理
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
319
561
|
if (needReplace) {
|
|
320
562
|
path.replaceWith(makeReplace(value));
|
|
321
563
|
}
|
|
322
564
|
if (skip) path.skip();
|
|
323
565
|
},
|
|
324
566
|
|
|
567
|
+
// jsx标签
|
|
568
|
+
JSXElement(path) {
|
|
569
|
+
const { node } = path;
|
|
570
|
+
const { openingElement } = node;
|
|
571
|
+
const jsxName = openingElement.name.name;
|
|
572
|
+
|
|
573
|
+
// 不解析jsx中的style标签
|
|
574
|
+
if (ignoreComponents.includes(jsxName)) {
|
|
575
|
+
path.skip();
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const parentNodeType = path.parentPath?.node?.type;
|
|
580
|
+
|
|
581
|
+
// 如果是配置的国际化jsx标签
|
|
582
|
+
if (!shouldIgnore(node) && intlTag && jsxName === intlTag) {
|
|
583
|
+
|
|
584
|
+
let id = getJsxTagChaoswiseIntlValue(openingElement, intlTagIdPath || 'id');
|
|
585
|
+
|
|
586
|
+
let word = getWord(id);
|
|
587
|
+
|
|
588
|
+
if (!word) {
|
|
589
|
+
// 根据id找不到中文,就找jsx标签的默认中文
|
|
590
|
+
let defaultValue = getJsxTagChaoswiseIntlValue(openingElement, intlTagDefaultWordPath);
|
|
591
|
+
if (typeof defaultValue === 'string') {
|
|
592
|
+
word = defaultValue;
|
|
593
|
+
} else {
|
|
594
|
+
if (!intlTagIdPath) {
|
|
595
|
+
properLog.warn(`intlTagIdPath未配置`);
|
|
596
|
+
} else {
|
|
597
|
+
if (!id) {
|
|
598
|
+
properLog.warn(`文件:${filePath} id路径intlTagIdPath:${intlTagIdPath} 未找到非空字符串`);
|
|
599
|
+
} else {
|
|
600
|
+
// word找不到
|
|
601
|
+
localWordPath && properLog.warn(`中文文件localWordPath:${localWordPath} 键:${id} 未找到非空字符串`);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (defaultValue === false) {
|
|
605
|
+
properLog.warn(`文件:${filePath} 替换的标签intlTag:${intlTag} 默认中文路径intlTagDefaultWordPath:${intlTagDefaultWordPath} 未找到非空字符串`);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (['JSXFragment', 'JSXElement'].includes(parentNodeType)) {
|
|
609
|
+
insertFailCommonInJsx(path);
|
|
610
|
+
} else {
|
|
611
|
+
insertFailCommon(node);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (word && isPrimary(word)) {
|
|
617
|
+
// 替换国际化标签,<FormatMessage id='zhongwenid' defaultMessage="中文" /> 换成 {intl.get(id).d('中文')}
|
|
618
|
+
let res = makeReplace(word);
|
|
619
|
+
|
|
620
|
+
// 如果节点的父节点是JSXFragment或者JSXElement,那么就包一层JSXExpressionContainer
|
|
621
|
+
if (['JSXFragment', 'JSXElement'].includes(parentNodeType)) {
|
|
622
|
+
res = t.JSXExpressionContainer(res);
|
|
623
|
+
}
|
|
624
|
+
path.replaceWith(res);
|
|
625
|
+
}
|
|
626
|
+
path.skip();
|
|
627
|
+
}
|
|
628
|
+
},
|
|
629
|
+
|
|
325
630
|
// JSX文本节点
|
|
326
631
|
JSXText(path) {
|
|
327
632
|
const { node } = path;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
const t = require('@babel/types');
|
|
2
|
+
const specialMatch = require('./specialMatch');
|
|
2
3
|
|
|
3
4
|
module.exports = function f(
|
|
4
5
|
{
|
|
5
6
|
i18nObject,
|
|
6
7
|
i18nMethod,
|
|
7
8
|
importCode,
|
|
9
|
+
ignoreLines,
|
|
10
|
+
i18nDefaultFunctionKey,
|
|
8
11
|
},
|
|
9
|
-
returns
|
|
12
|
+
returns,
|
|
13
|
+
{ special },
|
|
10
14
|
) {
|
|
11
15
|
const { replaceWords, downloadIds } = returns;
|
|
12
16
|
|
|
@@ -33,6 +37,14 @@ module.exports = function f(
|
|
|
33
37
|
return str.trim().replace(/\s+/g, ' ');
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
// 是否忽略
|
|
41
|
+
function shouldIgnore(node) {
|
|
42
|
+
if (node?.loc) {
|
|
43
|
+
return ignoreLines.includes(node.loc.start.line);
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
// 处理模板字符串中的变量
|
|
37
49
|
function makeObjectExpression(obj) {
|
|
38
50
|
if (Object.prototype.toString.call(obj) !== '[object Object]') return null;
|
|
@@ -118,6 +130,31 @@ module.exports = function f(
|
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
return {
|
|
133
|
+
// 字符串变量 src/config/router.config.js中的id进行替换
|
|
134
|
+
StringLiteral(path) {
|
|
135
|
+
const { node } = path;
|
|
136
|
+
let { value } = node;
|
|
137
|
+
|
|
138
|
+
if (!shouldIgnore(node) && special) {
|
|
139
|
+
// intl.get('id').d(中文) 获取id和中文
|
|
140
|
+
const { id, defaultValue } = specialMatch(value) || {};
|
|
141
|
+
if (!id) return;
|
|
142
|
+
|
|
143
|
+
const finalyId = replaceWords[id];
|
|
144
|
+
if (finalyId) {
|
|
145
|
+
returns.hasTouch = true;
|
|
146
|
+
downloadIds.push(finalyId);
|
|
147
|
+
|
|
148
|
+
const str = `${i18nObject ? `${i18nObject}.` : ''}${i18nMethod}("${finalyId}").${i18nDefaultFunctionKey}("${defaultValue}")`;
|
|
149
|
+
const newStr = hackValue(str, str,);
|
|
150
|
+
path.replaceWith(newStr);
|
|
151
|
+
path.skip();
|
|
152
|
+
} else {
|
|
153
|
+
downloadIds.push(id);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
|
|
121
158
|
// 导入声明,比如:import foo from "mod";
|
|
122
159
|
ImportDeclaration(path) {
|
|
123
160
|
// 是否已经导入过 intl 的依赖
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const getConf = require('../conf');
|
|
2
|
+
|
|
3
|
+
let reg;
|
|
4
|
+
|
|
5
|
+
module.exports = function (str) {
|
|
6
|
+
if (!reg) {
|
|
7
|
+
const conf = getConf();
|
|
8
|
+
const { i18nObject, i18nMethod, i18nDefaultFunctionKey } = conf;
|
|
9
|
+
reg = new RegExp(`${i18nObject? `${i18nObject}\\.`: ''}${i18nMethod}\\([\\'\\"]([^\\)]*)[\\'\\"]\\)\\.${i18nDefaultFunctionKey}\\([\\'\\"]([^\\)]*)[\\'\\"]\\)`);
|
|
10
|
+
}
|
|
11
|
+
const res = str.match(reg);
|
|
12
|
+
if (!res) return;
|
|
13
|
+
return { id: res[1], defaultValue: res[2] };
|
|
14
|
+
}
|