ztxkutils 10.0.8 → 20.0.1

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.
Files changed (63) hide show
  1. package/dist/businessTools.js +4 -3
  2. package/dist/dataModel-6c68c88f.js +26 -0
  3. package/dist/dataModel-914b6226.js +26 -0
  4. package/dist/dataModel.js +2 -1
  5. package/dist/fileOperation.d.ts +19 -0
  6. package/dist/fileOperation.js +74 -10
  7. package/dist/hooks.js +36 -22
  8. package/dist/i18next.js +21 -0
  9. package/dist/index.js +5 -4
  10. package/dist/myIndexDb.d.ts +1 -1
  11. package/dist/print.d.ts +4 -5
  12. package/dist/print.js +4 -3
  13. package/dist/reqUrl.js +1 -1
  14. package/dist/request-1e442d5d.js +2982 -0
  15. package/dist/request-986d7090.js +2923 -0
  16. package/dist/request-d8d72b87.js +2982 -0
  17. package/dist/request-f600ad7a.js +2992 -0
  18. package/dist/request.d.ts +13 -0
  19. package/dist/request.js +2 -1
  20. package/dist/stompClient.js +21 -8
  21. package/dist/useFileIdToBase64.js +2 -0
  22. package/dist/validate-21164759.js +260 -0
  23. package/dist/validate-2de5a28f.js +260 -0
  24. package/dist/validate.js +2 -1
  25. package/dist/workflow.js +3 -5
  26. package/locales/en-US.json +64 -0
  27. package/locales/zh-CN.json +64 -0
  28. package/package.json +41 -4
  29. package/zti18n-cli/bin/index.js +3 -0
  30. package/zti18n-cli/index.js +23 -0
  31. package/zti18n-cli/src/command/collect.js +353 -0
  32. package/zti18n-cli/src/command/convert.js +17 -0
  33. package/zti18n-cli/src/command/convert2.js +35 -0
  34. package/zti18n-cli/src/command/initFileConf.js +133 -0
  35. package/zti18n-cli/src/command/publish.js +24 -0
  36. package/zti18n-cli/src/conf/BaseConf.js +21 -0
  37. package/zti18n-cli/src/conf/FileConf.js +116 -0
  38. package/zti18n-cli/src/index.js +75 -0
  39. package/zti18n-cli/src/translate/google.js +87 -0
  40. package/zti18n-cli/src/utils/isChinese.js +3 -0
  41. package/zti18n-cli/src/utils/log.js +8 -0
  42. package/zti18n-cli/src/utils/mergeOptions.js +45 -0
  43. package/zti18n-cli/src/utils/reactOptions.js +73 -0
  44. package/zti18n-cli/src/utils/vueOptions.js +69 -0
  45. package/zti18n-core/index.js +1 -0
  46. package/zti18n-core/src/index.js +5 -0
  47. package/zti18n-core/src/plugin/reactIntlToReactIntlUniversal.js +224 -0
  48. package/zti18n-core/src/plugin/reactIntlUniversalToDi18n.js +64 -0
  49. package/zti18n-core/src/transform/defaultPkMap.js +79 -0
  50. package/zti18n-core/src/transform/transformHtml.js +271 -0
  51. package/zti18n-core/src/transform/transformJs.js +489 -0
  52. package/zti18n-core/src/transform/transformPug.js +272 -0
  53. package/zti18n-core/src/transform/transformReactIntlToReactIntlUniversal.js +96 -0
  54. package/zti18n-core/src/transform/transformReactIntlUniveralToDi18n.js +90 -0
  55. package/zti18n-core/src/transform/transformToDi18n.js +22 -0
  56. package/zti18n-core/src/transform/transformTs.js +41 -0
  57. package/zti18n-core/src/transform/transformVue.js +126 -0
  58. package/zti18n-core/src/transform/transformZeroToDi18n.js +105 -0
  59. package/zti18n-core/src/translate/google.js +6 -0
  60. package/zti18n-core/src/utils/constants.js +3 -0
  61. package/zti18n-core/src/utils/getIgnoreLines.js +14 -0
  62. package/zti18n-core/src/utils/isChinese.js +3 -0
  63. package/zti18n-core/src/utils/log.js +8 -0
@@ -0,0 +1,489 @@
1
+ const babel = require('@babel/core');
2
+ const generate = require('@babel/generator').default;
3
+ const traverse = require('@babel/traverse').default;
4
+ const t = require('@babel/types');
5
+ const pluginSyntaxJSX = require('@babel/plugin-syntax-jsx');
6
+ const pluginSyntaxProposalOptionalChaining = require('@babel/plugin-proposal-optional-chaining');
7
+ const pluginSyntaxClassProperties = require('@babel/plugin-syntax-class-properties');
8
+ const pluginSyntaxDecorators = require('@babel/plugin-syntax-decorators');
9
+ const pluginSyntaxObjectRestSpread = require('@babel/plugin-syntax-object-rest-spread');
10
+ const pluginSyntaxAsyncGenerators = require('@babel/plugin-syntax-async-generators');
11
+ const pluginSyntaxDoExpressions = require('@babel/plugin-syntax-do-expressions');
12
+ const pluginSyntaxDynamicImport = require('@babel/plugin-syntax-dynamic-import');
13
+ const pluginSyntaxFunctionBind = require('@babel/plugin-syntax-function-bind');
14
+
15
+ function getIgnoreLines(ast) {
16
+ const ignoreBlocks = [];
17
+ for (const comment of ast.comments) {
18
+ const { type, value, loc } = comment;
19
+ const last = ignoreBlocks.length - 1;
20
+
21
+ if (type === 'CommentLine' && value.trim() === 'zti18n-disable-line') {
22
+ ignoreBlocks.push({
23
+ start: loc.start.line,
24
+ end: loc.start.line,
25
+ });
26
+ } else if (type === 'CommentBlock' && value.trim() === 'zti18n-disable') {
27
+ if (last < 0 || ignoreBlocks[last].end) {
28
+ ignoreBlocks.push({
29
+ start: loc.start.line,
30
+ });
31
+ }
32
+ } else if (type === 'CommentBlock' && value.trim() === 'zti18n-enable') {
33
+ if (last >= 0 && !ignoreBlocks[last].end) {
34
+ ignoreBlocks[last].end = loc.start.line;
35
+ }
36
+ }
37
+ }
38
+
39
+ // 如果缺少 disable-enable,直接作用到最后一行
40
+ const len = ignoreBlocks.length;
41
+ if (len > 0 && !ignoreBlocks[len - 1].end) {
42
+ ignoreBlocks[len - 1].end = ast.loc.end.line;
43
+ }
44
+
45
+ // 转换成行号
46
+ const ignoreLines = [];
47
+ for (const block of ignoreBlocks) {
48
+ for (let i = block.start; i <= block.end; i++) {
49
+ ignoreLines.push(i);
50
+ }
51
+ }
52
+
53
+ return ignoreLines;
54
+ }
55
+
56
+ function makeVisitor(
57
+ {
58
+ primaryRegx,
59
+ i18nObject,
60
+ i18nMethod,
61
+ importCode,
62
+ ignoreLines,
63
+ ignoreMethods,
64
+ ignoreComponents,
65
+ ignoreAttributes,
66
+ },
67
+ returns
68
+ ) {
69
+ const { allTranslated, allUpdated, allUsedKeys } = returns;
70
+ const existValues = Object.keys(allTranslated);
71
+ const hacked = {};
72
+
73
+ // XXX: [TRICKY] 防止中文转码为 unicode
74
+ function hackValue(value, key) {
75
+ if (key) hacked[key] = true;
76
+
77
+ return Object.assign(t.StringLiteral(value), {
78
+ extra: {
79
+ raw: `'${value}'`,
80
+ rawValue: value,
81
+ },
82
+ });
83
+ }
84
+
85
+ function shouldIgnore(node) {
86
+ if (node.loc) {
87
+ // node may not have loc
88
+ return ignoreLines.includes(node.loc.start.line);
89
+ }
90
+ return false;
91
+ }
92
+
93
+ function isPrimary(str) {
94
+ return primaryRegx.test(str);
95
+ }
96
+
97
+ // 去掉首尾空白字符,中间的连续空白字符替换成一个空格
98
+ function formatWhitespace(str) {
99
+ return str.trim().replace(/\s+/g, ' ');
100
+ }
101
+
102
+ function makeObjectExpression(obj) {
103
+ if (Object.prototype.toString.call(obj) === '[object Object]') {
104
+ const ObjectPropertyArr = [];
105
+ Object.keys(obj).forEach((k) => {
106
+ ObjectPropertyArr.push(
107
+ t.ObjectProperty(
108
+ t.Identifier(k),
109
+ obj[k].isAstNode ? obj[k].value : t.Identifier(obj[k])
110
+ )
111
+ );
112
+ });
113
+ return t.ObjectExpression(ObjectPropertyArr);
114
+ }
115
+ return null;
116
+ }
117
+
118
+ // 更新2个 `all*` 数组
119
+ function updateLocaleInfo(key, value) {
120
+ if (!Array.isArray(allTranslated[value])) {
121
+ // 如果该文字没有存在于已翻译列表
122
+ allTranslated[value] = [key];
123
+ existValues.push(key);
124
+ } else if (allTranslated[value][0] === '') {
125
+ // 只有带有 context key 的情况
126
+ allTranslated[value][0] = key;
127
+ }
128
+ if (!allUsedKeys.includes(key)) {
129
+ allUsedKeys.push(key);
130
+ }
131
+ }
132
+
133
+ function makeReplace(value, variables) {
134
+ // 存在文案替换
135
+ returns.hasTouch = true;
136
+
137
+ value = formatWhitespace(value);
138
+
139
+ // 直接使用主语言(比如中文)做 key
140
+ const key = value;
141
+
142
+ updateLocaleInfo(key, value);
143
+
144
+ // 生成新节点
145
+ const v = hackValue(value);
146
+ const objExp = makeObjectExpression(variables);
147
+
148
+ if (i18nObject) {
149
+ return t.callExpression(
150
+ t.memberExpression(t.identifier(i18nObject), t.identifier(i18nMethod)),
151
+ objExp ? [v, objExp] : [v]
152
+ );
153
+ }
154
+
155
+ return t.callExpression(
156
+ t.identifier(i18nMethod),
157
+ objExp ? [v, objExp] : [v]
158
+ );
159
+ }
160
+
161
+ return {
162
+ ImportDeclaration(path) {
163
+ // 已经导入过 di18n-react 或 di18n-vue 包
164
+ const m = importCode.match(/from ["'](.*)["']/);
165
+ const pkgName = m ? m[1] : '';
166
+ if (path.node.source.value === pkgName) {
167
+ returns.hasImport = true;
168
+ }
169
+ path.skip();
170
+ },
171
+
172
+ TemplateLiteral(path) {
173
+ const { node } = path;
174
+
175
+ if (
176
+ !shouldIgnore(node) &&
177
+ node.quasis.some((word) => isPrimary(word.value.cooked))
178
+ ) {
179
+ const tempArr = [...node.quasis, ...node.expressions];
180
+ tempArr.sort((a, b) => a.start - b.start);
181
+
182
+ let value = '';
183
+ const variable = {};
184
+ let needReplace = false;
185
+ let slotIndex = 0;
186
+
187
+ tempArr.forEach(function (nd) {
188
+ if (nd.type === 'TemplateElement') {
189
+ value += nd.value.cooked;
190
+ if (isPrimary(nd.value.cooked)) {
191
+ needReplace = true;
192
+ }
193
+ } else if (nd.type === 'Identifier') {
194
+ value += `{{${nd.name}}}`;
195
+ variable[nd.name] = nd.name;
196
+ needReplace = true;
197
+ } else {
198
+ // 例如 CallExpression 等
199
+ const identifier = `slot${slotIndex++}`;
200
+ value += `{{${identifier}}}`;
201
+ variable[identifier] = { isAstNode: true, value: nd };
202
+ needReplace = true;
203
+ }
204
+ });
205
+
206
+ if (needReplace && value.trim()) {
207
+ path.replaceWith(makeReplace(value, variable));
208
+ }
209
+ }
210
+ path.skip();
211
+ },
212
+
213
+ StringLiteral(path) {
214
+ const { node } = path;
215
+ const { value } = node;
216
+
217
+ const isTsLiteralType =
218
+ node.type === 'StringLiteral' &&
219
+ ['TSLiteralType'].includes(path.parent.type);
220
+ if (!shouldIgnore(node) && isPrimary(node.value) && !isTsLiteralType) {
221
+ switch (path.parent.type) {
222
+ case 'ObjectProperty':
223
+ case 'AssignmentExpression':
224
+ path.replaceWith(makeReplace(value));
225
+ break;
226
+ case 'CallExpression':
227
+ let v = value;
228
+
229
+ if (allUpdated.hasOwnProperty(value)) {
230
+ // 如果对应的中文已经在远端被修改,则自动更新代码
231
+ v = allUpdated[value];
232
+ }
233
+
234
+ path.replaceWith(makeReplace(v));
235
+ break;
236
+ case 'NewExpression':
237
+ // XXX: 会出现吗?
238
+ path.replaceWith(makeReplace(value));
239
+ break;
240
+ case 'JSXAttribute':
241
+ if (ignoreComponents.includes(path.parentPath.parent.name.name)) {
242
+ // 过滤掉配置中 ignoreComponents 中指定的组件
243
+ // XXX: 以下应该是不需要的,先注释下个版本移除
244
+ // const key = value + node.start + node.end;
245
+ // if (!hacked[key]) {
246
+ // path.replaceWith(
247
+ // hackValue(value, key)
248
+ // );
249
+ // }
250
+ } else {
251
+ path.replaceWith(t.JSXExpressionContainer(makeReplace(value)));
252
+ }
253
+ break;
254
+ default:
255
+ path.replaceWith(makeReplace(value));
256
+ break;
257
+ }
258
+
259
+ path.skip();
260
+ } else if (isPrimary(value)) {
261
+ console.warn('ignore 1', value);
262
+ }
263
+ },
264
+
265
+ CallExpression(path) {
266
+ const { node } = path;
267
+
268
+ if (shouldIgnore(node)) {
269
+ path.skip();
270
+ return;
271
+ }
272
+
273
+ // 处理 ignoreMethods
274
+ if (node.callee.type === 'MemberExpression') {
275
+ let parentNode = '';
276
+ if (node.callee.object.name) {
277
+ parentNode = node.callee.object.name;
278
+ } else if (node.callee.object.property) {
279
+ // 处理忽略类似 Sdk.TaoTie.trackUserClickEvent 方法情况
280
+ parentNode = node.callee.object.property.name;
281
+ }
282
+
283
+ const callExpression = `${parentNode}.${node.callee.property.name}`;
284
+
285
+ if (ignoreMethods.includes(callExpression)) {
286
+ path.skip();
287
+ return;
288
+ }
289
+ }
290
+
291
+ if (node.callee.type === 'Identifier') {
292
+ if (ignoreMethods.includes(node.callee.name)) {
293
+ path.skip();
294
+ return;
295
+ }
296
+ }
297
+
298
+ // 可能需要更新 key
299
+ if (
300
+ (node.callee.type === 'MemberExpression' &&
301
+ node.callee.object.name === i18nObject &&
302
+ node.callee.property.name === i18nMethod) ||
303
+ (node.callee.type === 'Identifier' && node.callee.name === i18nMethod)
304
+ ) {
305
+ // 收集现有的 key
306
+ const args = node.arguments;
307
+ const hasContext = args[1] && typeof args[1].value === 'string';
308
+
309
+ let key = args[0].value;
310
+ let variable = null;
311
+
312
+ if (hasContext) {
313
+ // 附加上 context
314
+ key += `{context, ${args[1].value}}`;
315
+ variable = args[2];
316
+ } else {
317
+ variable = args[1];
318
+ }
319
+
320
+ if (allUpdated.hasOwnProperty(key)) {
321
+ // 如果对应的中文已经在远端被修改,则自动更新代码
322
+ path.replaceWith(makeReplace(allUpdated[key], variable));
323
+ } else {
324
+ if (Array.isArray(node.arguments) && node.arguments.length > 0) {
325
+ if (!allUsedKeys.includes(key)) {
326
+ allUsedKeys.push(key);
327
+ }
328
+
329
+ const { value } = node.arguments[0];
330
+
331
+ if (!existValues.includes(value)) {
332
+ if (hasContext) {
333
+ allTranslated[value] = ['', key];
334
+ } else {
335
+ allTranslated[value] = [key];
336
+ }
337
+ existValues.push(value);
338
+ } else if (!allTranslated[value].includes(key)) {
339
+ allTranslated[value].push(key);
340
+ }
341
+ }
342
+ }
343
+
344
+ path.skip();
345
+ }
346
+ },
347
+
348
+ JSXElement(path) {
349
+ const { node } = path;
350
+
351
+ if (!node.ignore && !shouldIgnore(node)) {
352
+ const { openingElement } = node;
353
+ if (openingElement.name.name === 'Di18nTrans') {
354
+ const keyAtr = openingElement.attributes.find(
355
+ (atr) => atr.name.name === 'i18nKey'
356
+ );
357
+ if (!keyAtr) return;
358
+
359
+ const key = keyAtr.value.value;
360
+
361
+ // Di18nTrans 的 key 和 value 肯定不一样
362
+ // 这里从 allUpdated 中移除 Di18nTrans 对应的 key
363
+ delete allUpdated[key];
364
+
365
+ const value = node.children.reduce((prev, cur, index) => {
366
+ if (cur.type === 'JSXText') {
367
+ // 内部的文案加上标记,不再检测
368
+ cur.ignore = true;
369
+ return prev + formatWhitespace(cur.value);
370
+ }
371
+
372
+ if (cur.type === 'JSXElement') {
373
+ // 内部的文案加上标记,不再检测
374
+ cur.children[0].ignore = true;
375
+ return (
376
+ prev +
377
+ formatWhitespace(
378
+ `<${index}>${cur.children[0].value}</${index}>`
379
+ )
380
+ );
381
+ }
382
+
383
+ console.error(`${cur.type} node are not supported in Di18nTrans`);
384
+ return '';
385
+ }, '');
386
+
387
+ updateLocaleInfo(key, value);
388
+ }
389
+ // 不能完全忽视该节点,内部的 JSX 属性照样需要检测
390
+ // path.skip();
391
+ }
392
+ },
393
+
394
+ JSXText(path) {
395
+ const { node } = path;
396
+
397
+ if (!node.ignore && !shouldIgnore(node) && isPrimary(node.value)) {
398
+ // 将中文替换为 JSX 表达式
399
+ path.replaceWith(t.JSXExpressionContainer(makeReplace(node.value)));
400
+ }
401
+
402
+ path.skip();
403
+ },
404
+
405
+ JSXAttribute(path) {
406
+ const { node } = path;
407
+
408
+ // 跳过被忽略的属性,比如 style、className 等
409
+ if (ignoreAttributes.includes(node.name.name)) {
410
+ path.skip();
411
+ }
412
+ },
413
+ };
414
+ }
415
+
416
+ module.exports = function transformJs(source, localeInfo = {}, options = {}) {
417
+ const { allTranslated = {}, allUpdated = {}, allUsedKeys = [] } = localeInfo;
418
+
419
+ const {
420
+ primaryRegx = /[\u4e00-\u9fa5]/,
421
+ i18nObject = 'intl',
422
+ i18nMethod = 't',
423
+ importCode = "import { intl } from 'di18n-react';",
424
+ babelPresets = [],
425
+ babelPlugins = [],
426
+ ignoreComponents = [],
427
+ ignoreMethods = [],
428
+ ignoreAttributes = ['style', 'className'],
429
+ } = options;
430
+
431
+ const transformOptions = {
432
+ sourceType: 'module',
433
+ ast: true,
434
+ configFile: false,
435
+ presets: babelPresets,
436
+ plugins: [
437
+ pluginSyntaxJSX,
438
+ pluginSyntaxProposalOptionalChaining,
439
+ pluginSyntaxClassProperties,
440
+ [pluginSyntaxDecorators, { decoratorsBeforeExport: true }],
441
+ pluginSyntaxObjectRestSpread,
442
+ pluginSyntaxAsyncGenerators,
443
+ pluginSyntaxDoExpressions,
444
+ pluginSyntaxDynamicImport,
445
+ pluginSyntaxFunctionBind,
446
+ ...babelPlugins,
447
+ ],
448
+ };
449
+
450
+ const opts = {
451
+ primaryRegx,
452
+ i18nObject,
453
+ i18nMethod,
454
+ importCode,
455
+ ignoreLines: [],
456
+ ignoreMethods,
457
+ ignoreComponents,
458
+ ignoreAttributes,
459
+ };
460
+
461
+ const r = {
462
+ allTranslated,
463
+ allUpdated,
464
+ allUsedKeys,
465
+ hasImport: false,
466
+ hasTouch: false,
467
+ };
468
+
469
+ const ast = babel.parseSync(source, transformOptions);
470
+ opts.ignoreLines = getIgnoreLines(ast);
471
+ const visitor = makeVisitor(opts, r);
472
+
473
+ traverse(ast, visitor);
474
+
475
+ // https://stackoverflow.com/a/55478641
476
+ let { code } = generate(
477
+ ast,
478
+ { retainLines: true, decoratorsBeforeExport: true },
479
+ source
480
+ );
481
+
482
+ if (!r.hasTouch) {
483
+ code = source;
484
+ } else if (!r.hasImport && importCode) {
485
+ code = `${importCode}\n${code}`;
486
+ }
487
+
488
+ return { source: code, hasTouch: r.hasTouch };
489
+ };