@chaoswise/intl 1.2.0 → 1.2.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.
@@ -7,12 +7,16 @@ const log = require('./util/log');
7
7
  const file = require('./util/file');
8
8
  const writeNewWordsFile = require('./util/writeNewWordsFile');
9
9
  const { readWordJson } = require('./util/getWord');
10
+ const getGroupName = require('./util/getGroupName');
10
11
 
11
12
  const service = require('./service');
12
13
 
13
14
  async function collect() {
14
- log.info('词条扫描中...')
15
+
16
+ log.info('工程扫描中...')
17
+
15
18
  const conf = getConf();
19
+ const groupName = getGroupName();
16
20
  const newWordsFileType = conf.newWordsFileType || 'excel';
17
21
 
18
22
  // 检查newWordsFileType
@@ -36,6 +40,8 @@ async function collect() {
36
40
 
37
41
  // 在国际化平台中获取所有已存在中文信息
38
42
  const res = await service.searchByZh(info.allWords);
43
+ // 在国际化平台记录特殊方法
44
+ await service.saveMethod({ groupName, specialMethod: info.specialMethod });
39
45
 
40
46
  if (res.code !== 10000) {
41
47
  log.error('请求数据出错:' + res.msg);
@@ -46,10 +52,13 @@ async function collect() {
46
52
 
47
53
  const replaceWords = {}; // { zh: id } 需要在代码中替换的词条id
48
54
  const newWords = {}; // { zh1: '待翻译', zh2: '请选择:中文1/中文2' }
55
+ const exist = {}; // 根据中文只查出一条数据的已有词条
49
56
  Object.entries(wordsMap).forEach(([word, value]) => {
50
57
  // 如果当前中文词条在平台中存在,且对应英文翻译有且只有一条,那么直接替换代码中的中文为当前id,否则生成临时key,让开发者手动确认
51
58
  if (value.length === 1) {
52
- replaceWords[word] = value[0].key;
59
+ const { id, key, zh, en } = value[0];
60
+ replaceWords[word] = key;
61
+ exist[id] = { id, key, zh, en };
53
62
  } else {
54
63
  const id = uuidv4();
55
64
  replaceWords[word] = id;
@@ -65,11 +74,15 @@ async function collect() {
65
74
  }
66
75
  });
67
76
 
77
+
78
+ // 在国际化平台中保存所有已存在词条
79
+ await service.saveExist({groupName, exist});
80
+
68
81
  // 第二次遍历,传入replaceWords,对代码进行国际化通用API转化,把词条替换成数据库的id,或者脚本临时生成的uuid
69
82
  transformAst('collect', files, conf, replaceWords);
70
83
 
71
- log.success('脚本执行成功');
72
- log.success('自定义配置文件在项目根目录的.intlconfig.js');
84
+ log.success('★★★ 脚本执行成功 ★★★');
85
+ log.info('国际化配置文件: .intlconfig.js,可根据需求自定义修改');
73
86
  // 本次扫描出新的待翻译词条,写入到newWords中
74
87
  if (Object.keys(newWords).length) {
75
88
  writeNewWordsFile(newWordsFileType, newWords);
@@ -79,7 +92,7 @@ async function collect() {
79
92
  if (warnLogs.length) {
80
93
  const fileName = `intl.logs.warn.${(new Date).toLocaleString().replace(/[\/ ]/g, '_')}.txt`;
81
94
  file.write(fileName, JSON.stringify(warnLogs, null, 2));
82
- log.warnToLog(`警告日志文件:${fileName}`);
95
+ log.warn(`存在脚本无法处理的情况,具体查看 ${fileName} 手动处理`);
83
96
  }
84
97
  }
85
98
 
@@ -55,30 +55,30 @@ module.exports = function (excludes = []) {
55
55
  endOfLine: 'lf',
56
56
  },
57
57
 
58
- // <Tag id={{ key: 'id' }} defaultMessage='中文' />
59
- // intlTag 是 'Tag'
60
- // intlTagIdPath 是 'id.key'
58
+ // <FormattedMessage id='id' defaultMessage='中文' />
59
+ // intlTag 是 'FormattedMessage'
60
+ // intlTagIdPath 是 'id'
61
61
  // intlTagDefaultWordPath 是 'defaultMessage',并且如果不配置,默认是'defaultMessage'
62
- intlTag: '',
63
- intlTagIdPath: '',
64
- intlTagDefaultWordPath: '',
62
+ intlTag: 'FormattedMessage',
63
+ intlTagIdPath: 'id',
64
+ intlTagDefaultWordPath: 'defaultMessage',
65
65
 
66
66
  // intl.formatMessage({
67
- // key: 'id',
67
+ // id: 'id',
68
68
  // defaultMessage: '默认值',
69
69
  // })
70
70
  // intlFunctionName 是 intl.formatMessage
71
- // intlFunctionIdPath 是 '0.key'。 如果 配置成 'key' 也行,intlFunctionIdPath如果不以数字开头,会在前面加上'0.' 'key' 就会变成 '0.key'
71
+ // intlFunctionIdPath 是 '0.id'。 如果 配置成 'id' 也行,intlFunctionIdPath如果不以数字开头,会在前面加上'0.' 'id' 就会变成 '0.id'
72
72
  // intlFunctionDefaultWordPath 是 '0.defaultMessage',其他的说明同intlFunctionIdPath
73
- intlFunctionName: '',
74
- intlFunctionIdPath: '',
75
- intlFunctionDefaultWordPath: '',
73
+ intlFunctionName: 'intl.formatMessage',
74
+ intlFunctionIdPath: 'id',
75
+ intlFunctionDefaultWordPath: 'defaultMessage',
76
76
 
77
77
  // 做过国际化的项目,中文config的路径。例如:'src/local/zh.json'
78
78
  localWordPath: '',
79
79
 
80
80
  // 配置 需要被脚本删除的依赖包的名字
81
- removePkgName: [],
81
+ removePkgName: ['react-intl'],
82
82
 
83
83
  // 需要删除的函数和装饰器 的名称
84
84
  removeFunctionName: ['injectIntl'],
@@ -86,8 +86,8 @@ module.exports = function (excludes = []) {
86
86
  // package.json中项目名称的key
87
87
  groupNameKey: 'packageName',
88
88
 
89
- // 特殊文件处理的正则 这里默认匹配router.config.js
90
- specialFileReg: [/src\/config\/router\.config\.js/],
89
+ // 特殊文件处理数组的每一项为正则或者字符串 这里默认匹配router.config.js
90
+ specialFileReg: ['src/config/router.config.js'],
91
91
 
92
92
  // newWords文件的类型 json或者excel
93
93
  newWordsFileType: 'excel',
@@ -10,7 +10,7 @@ module.exports = function initConfig() {
10
10
  const customConfig = getCustomConfig();
11
11
 
12
12
  if (customConfig) {
13
- console.log(`${customConfigName}已存在,请手动删除本地已经有的配置文件再重新执行 npm run intl-init`);
13
+ log.error(`${customConfigName}已存在,请删除后重新执行`);
14
14
  return;
15
15
  }
16
16
 
@@ -33,5 +33,5 @@ module.exports = function initConfig() {
33
33
  prettier.format(code, { ...defaultConfig.prettier, parser: 'babel' })
34
34
  );
35
35
 
36
- log.success(`初始化配置文件成功:.intlconfig.js`);
36
+ log.success(`★★★ 初始化配置文件成功:.intlconfig.js ★★★`);
37
37
  }
@@ -3,7 +3,7 @@ const getConf = require('../conf');
3
3
 
4
4
  const conf = getConf();
5
5
 
6
- axios.defaults.baseURL = (conf.baseURL || '') + '/api/i18n/dictionary';
6
+ axios.defaults.baseURL = (conf.baseURL || '') + '/api/i18n';
7
7
 
8
8
  axios.interceptors.response.use(
9
9
  function (response) {
@@ -20,10 +20,20 @@ axios.interceptors.response.use(
20
20
 
21
21
  // 在国际化平台中获取所有已存在中文信息
22
22
  exports.searchByZh = (zhs) => {
23
- return axios.post('/searchByZh', zhs);
23
+ return axios.post('/dictionary/searchByZh', zhs);
24
24
  };
25
25
 
26
26
  // 根据词条id获取所有数据库词条信息
27
27
  exports.getJson = ({ groupName, downloadIds }) => {
28
- return axios.post('/getJson', { groupName, downloadIds });
28
+ return axios.post('/dictionary/getJson', { groupName, downloadIds });
29
+ };
30
+
31
+ // 保存替换的特殊方法
32
+ exports.saveMethod = (data) => {
33
+ return axios.post('/history/method/save', data);
34
+ };
35
+
36
+ // 保存已有词条
37
+ exports.saveExist = (data) => {
38
+ return axios.post('/history/exist/save', data);
29
39
  };
@@ -6,6 +6,7 @@ const log = require('./util/log');
6
6
  const file = require('./util/file');
7
7
 
8
8
  async function update() {
9
+ log.info('词条更新中...')
9
10
  const conf = getConf();
10
11
  const files = getTargetFiles(conf);
11
12
 
@@ -13,17 +14,17 @@ async function update() {
13
14
  const relationKey = file.readJson('relationKey.json') || {};
14
15
 
15
16
  const info = transformAst('update', files, conf, relationKey);
16
- await downloadJson(info.downloadIds);
17
+ await downloadJson(info.downloadIds.filter(Boolean));
17
18
 
18
19
  const needDelete = Boolean(Object.keys(relationKey).length);
19
20
  if (needDelete) {
20
21
  file.delete('newWords.json');
21
22
  file.delete('relationKey.json');
22
23
 
23
- log.success('newWords.json和relationKey.json 已删除');
24
+ // log.success('newWords.json和relationKey.json 已删除');
24
25
  }
25
26
 
26
- log.success('脚本执行成功');
27
+ log.success('★★★ 脚本执行成功 ★★★');
27
28
  }
28
29
 
29
30
  // update();
@@ -32,10 +32,7 @@ module.exports = function (
32
32
  { filePath, special },
33
33
  ) {
34
34
 
35
- // jsx默认 defaultMessage
36
- intlTagDefaultWordPath = intlTagDefaultWordPath || 'defaultMessage';
37
-
38
- const { replaceWords, allWords, downloadIds } = returns;
35
+ const { replaceWords, allWords, downloadIds, specialMethod } = returns;
39
36
  const hacked = {};
40
37
 
41
38
  // 在没有replaceWords的情况下,不用log信息,这里统一处理
@@ -62,15 +59,17 @@ module.exports = function (
62
59
  return preFixPath + path;
63
60
  }
64
61
  // 插入注释
65
- function insertFailCommon(node) {
62
+ function insertFailCommon(node, errorMsg) {
66
63
  const comment = node?.leadingComments?.value
67
- if (comment && comment.trim() === commentStr) return;
68
- t.addComment(node, 'leading', commentStr);
64
+ const errMsg = `${commentStr} ${errorMsg}`;
65
+ if (comment && comment.trim() === errMsg.trim()) return;
66
+ t.addComment(node, 'leading', errMsg);
69
67
  }
70
68
  // 在jsx中插入注释
71
- function insertFailCommonInJsx(path) {
69
+ function insertFailCommonInJsx(path, errorMsg) {
72
70
  const comment = path?.node?.leadingComments?.value
73
- if (comment && comment.trim() === commentStr) return;
71
+ const errMsg = `${commentStr} ${errorMsg}`;
72
+ if (comment && comment.trim() === errMsg.trim()) return;
74
73
  path.insertBefore(
75
74
  t.jsxExpressionContainer(
76
75
  {
@@ -78,7 +77,7 @@ module.exports = function (
78
77
  "innerComments": [
79
78
  {
80
79
  "type": "CommentBlock",
81
- "value": commentStr
80
+ "value": errMsg
82
81
  }
83
82
  ]
84
83
  }
@@ -450,24 +449,43 @@ module.exports = function (
450
449
 
451
450
  let value = getWord(chaoswiseIntlId);
452
451
  if (!value) {
453
- let defautValue = FormPath.getIn(chaoswiseIntlIdData, getFullPath(intlFunctionDefaultWordPath));
454
- if (typeof defautValue === 'string') {
455
- value = defautValue;
452
+ let defaultValue = FormPath.getIn(chaoswiseIntlIdData, getFullPath(intlFunctionDefaultWordPath));
453
+ if (typeof defaultValue === 'string' && defaultValue) {
454
+ value = defaultValue;
456
455
  } 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} 未找到非空字符串`)
456
+ let errorMsg = '';
457
+
458
+ if (!intlFunctionIdPath) {
459
+ errorMsg = `intlFunctionIdPath未配置`;
460
+ properLog.warn(errorMsg);
461
+ } else {
462
+ if (!chaoswiseIntlId) {
463
+ errorMsg = `在 ${intlFunctionName}() 中未找到 ${intlFunctionIdPath} 对应的值`;
464
+ properLog.warn(`文件 ${filePath} 中,在 ${intlFunctionName}() 中未找到 ${intlFunctionIdPath} 对应的值`);
465
+ } else if(!localWordPath) {
466
+ // 中文json文件未配置
467
+ errorMsg = `国际化中文文件路径 localWordPath 未配置`;
468
+ properLog.warn(errorMsg);
469
+ } else {
470
+ // word找不到
471
+ errorMsg = `国际化中文文件 ${localWordPath} 未找到 ${chaoswiseIntlId} 对应的值`;
472
+ properLog.warn(errorMsg);
473
+ }
462
474
  }
463
- if (intlFunctionDefaultWordPath) {
464
- properLog.warn(`文件:${filePath} 替换的函数名intlFunctionName:${intlFunctionName} 默认中文路径intlFunctionDefaultWordPath:${intlFunctionDefaultWordPath} 未找到非空字符串`)
475
+ if (intlFunctionDefaultWordPath && !defaultValue) {
476
+ errorMsg = `在 ${intlFunctionName}() 中未找到 ${intlFunctionDefaultWordPath} 对应的值`;
477
+ properLog.warn(`文件 ${filePath} 中,在 ${intlFunctionName} 中未找到 ${intlFunctionDefaultWordPath} 对应的值`);
465
478
  }
466
- insertFailCommon(node);
479
+
480
+ insertFailCommon(node, errorMsg);
467
481
  }
468
482
  }
469
483
 
470
484
  if (value && isPrimary(value)) {
485
+ if (!specialMethod.includes(fnName)) {
486
+ specialMethod.push(fnName);
487
+ }
488
+
471
489
  res.needReplace = true;
472
490
  res.value = value;
473
491
  }
@@ -591,29 +609,42 @@ module.exports = function (
591
609
  if (typeof defaultValue === 'string') {
592
610
  word = defaultValue;
593
611
  } else {
612
+ let errorMsg = '';
594
613
  if (!intlTagIdPath) {
595
- properLog.warn(`intlTagIdPath未配置`);
614
+ errorMsg = `intlTagIdPath未配置`;
615
+ properLog.warn(errorMsg);
596
616
  } else {
597
617
  if (!id) {
598
- properLog.warn(`文件:${filePath} id路径intlTagIdPath:${intlTagIdPath} 未找到非空字符串`);
618
+ errorMsg = `文件 ${filePath} 中,在<${intlTag} /> 中未找到 ${intlTagIdPath} 对应的值`;
619
+ properLog.warn(`在<${intlTag} /> 中未找到 ${intlTagIdPath} 对应的值`);
620
+ } else if(!localWordPath) {
621
+ // 中文json文件未配置
622
+ errorMsg = `国际化中文文件路径 localWordPath 未配置`;
623
+ properLog.warn(errorMsg);
599
624
  } else {
600
625
  // word找不到
601
- localWordPath && properLog.warn(`中文文件localWordPath:${localWordPath} 键:${id} 未找到非空字符串`);
626
+ errorMsg = `国际化中文文件 ${localWordPath} 未找到 ${id} 对应的值`;
627
+ properLog.warn(errorMsg);
602
628
  }
603
629
  }
604
- if (defaultValue === false) {
605
- properLog.warn(`文件:${filePath} 替换的标签intlTag:${intlTag} 默认中文路径intlTagDefaultWordPath:${intlTagDefaultWordPath} 未找到非空字符串`);
630
+ if (intlTagDefaultWordPath && defaultValue === false) {
631
+ errorMsg = `在<${intlTag} /> 中未找到 ${intlTagDefaultWordPath} 对应的值`;
632
+ properLog.warn(`文件 ${filePath} 在 <${intlTag} /> 中未找到 ${intlTagDefaultWordPath} 对应的值`);
606
633
  }
607
634
 
608
635
  if (['JSXFragment', 'JSXElement'].includes(parentNodeType)) {
609
- insertFailCommonInJsx(path);
636
+ insertFailCommonInJsx(path, errorMsg);
610
637
  } else {
611
- insertFailCommon(node);
638
+ insertFailCommon(node, errorMsg);
612
639
  }
613
640
 
614
641
  }
615
642
  }
616
643
  if (word && isPrimary(word)) {
644
+ if (!specialMethod.includes(jsxName)) {
645
+ specialMethod.push(jsxName);
646
+ }
647
+
617
648
  // 替换国际化标签,<FormatMessage id='zhongwenid' defaultMessage="中文" /> 换成 {intl.get(id).d('中文')}
618
649
  let res = makeReplace(word);
619
650
 
@@ -100,7 +100,7 @@ module.exports = function f(
100
100
  (node.callee.type === 'MemberExpression' &&
101
101
  node.callee.object.name === i18nObject &&
102
102
  node.callee.property.name === i18nMethod) ||
103
- (node.callee.type === 'Identifier' && node.callee.name === i18nMethod)
103
+ (!i18nObject && node.callee.type === 'Identifier' && node.callee.name === i18nMethod)
104
104
  ) {
105
105
  // 收集现有的 key
106
106
  const args = node.arguments;
@@ -81,6 +81,7 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
81
81
 
82
82
  const allWords = []; // 收集到的所有词条
83
83
  const downloadIds = []; // 需要从平台下载的词条id
84
+ const specialMethod = []; // 替换的国际化特殊方法
84
85
 
85
86
  // babel配置
86
87
  const transformOptions = {
@@ -113,7 +114,15 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
113
114
  files.forEach((file) => {
114
115
  const { filePath } = file;
115
116
 
116
- if (specialFileReg.some(reg => reg.test(filePath))) {
117
+ if (
118
+ specialFileReg.some(item => {
119
+ if (typeof item === 'string') {
120
+ return item === filePath;
121
+ } else {
122
+ return item.test(filePath);
123
+ }
124
+ })
125
+ ) {
117
126
  file.special = true;
118
127
  }
119
128
  const isTSX = ['.ts', '.tsx'].includes(path.extname(filePath));
@@ -122,6 +131,7 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
122
131
  allWords,
123
132
  replaceWords: replaceWords || {},
124
133
  downloadIds,
134
+ specialMethod,
125
135
  hasImport: false, // 是否已经引入通用国际化API,import {init} from ...;
126
136
  hasTouch: false, // 是否存在需要替换的词条
127
137
  };
@@ -183,5 +193,6 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
183
193
  return {
184
194
  allWords,
185
195
  downloadIds,
196
+ specialMethod,
186
197
  };
187
198
  };
@@ -26,5 +26,5 @@ module.exports = async function writeNewWordsFile(type, newWords) {
26
26
  file.writeXlsx(fileName, { Sheet1: [...oldNewWords, ...newWordsArr ] });
27
27
  }
28
28
 
29
- log.success(`需要翻译的文件在项目根目录的${fileName}中`);
29
+ log.info(`待翻译词条请查看: ${fileName}中`);
30
30
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chaoswise/intl",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "author": "cloudwiser",
5
5
  "description": "intl",
6
6
  "main": "lib/index.js",
@@ -83,5 +83,5 @@
83
83
  "react-dom": "^16.13.1"
84
84
  },
85
85
  "license": "MIT",
86
- "gitHead": "e56a7289b5085c5d38813e85776dbd5f789606b0"
86
+ "gitHead": "e90f035c659bef6d8cfe7ae08cfbc6117f8b5a79"
87
87
  }