@chaoswise/intl 1.0.0 → 1.1.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 +28 -12
- package/bin/scripts/conf/default.js +37 -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/downloadJson.js +10 -1
- package/bin/scripts/util/getGroupName.js +15 -0
- package/bin/scripts/util/getWord.js +13 -0
- package/bin/scripts/util/makeVisitorCollect.js +326 -45
- 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/lib/index.js +2 -1
- package/package.json +5 -4
package/bin/chaoswise-intl.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const runCollect = require('./scripts/collect');
|
|
3
3
|
const runUpdate = require('./scripts/update');
|
|
4
|
+
const runInitConfig = require('./scripts/initConfig');
|
|
4
5
|
|
|
5
6
|
// 可执行的指令
|
|
6
|
-
const SCRIPTS = ['collect', 'update'];
|
|
7
|
+
const SCRIPTS = ['intl', 'collect', 'update'];
|
|
7
8
|
|
|
8
9
|
const args = process.argv.slice(2);
|
|
9
10
|
|
|
@@ -14,6 +15,9 @@ const scriptIndex = args.findIndex(arg => {
|
|
|
14
15
|
|
|
15
16
|
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
|
|
16
17
|
|
|
18
|
+
if(script === 'init') {
|
|
19
|
+
runInitConfig();
|
|
20
|
+
}
|
|
17
21
|
if(script === 'collect') {
|
|
18
22
|
runCollect();
|
|
19
23
|
}
|
package/bin/scripts/collect.js
CHANGED
|
@@ -5,11 +5,24 @@ const getTargetFiles = require('./util/getTargetFiles');
|
|
|
5
5
|
const transformAst = require('./util/transformAst');
|
|
6
6
|
const log = require('./util/log');
|
|
7
7
|
const file = require('./util/file');
|
|
8
|
+
const getGroupName = require('./util/getGroupName');
|
|
9
|
+
const { readWordJson } = require('./util/getWord');
|
|
8
10
|
|
|
9
11
|
const service = require('./service');
|
|
10
12
|
|
|
11
|
-
async function
|
|
13
|
+
async function collect() {
|
|
14
|
+
log.info('词条扫描中...')
|
|
12
15
|
const conf = getConf();
|
|
16
|
+
|
|
17
|
+
// 读取wordJson
|
|
18
|
+
if (conf.localWordPath && !readWordJson(conf.localWordPath)) {
|
|
19
|
+
log.error('localWordPath配置有误');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
// 读取groupName
|
|
23
|
+
const groupName = getGroupName();
|
|
24
|
+
|
|
25
|
+
// 获取需要遍历的文件
|
|
13
26
|
const files = getTargetFiles(conf);
|
|
14
27
|
|
|
15
28
|
// 遍历文件,并对代码进行ast处理的方法:transformAst(type, files, conf, replaceWords)
|
|
@@ -18,19 +31,25 @@ async function init() {
|
|
|
18
31
|
|
|
19
32
|
// 在国际化平台中获取所有已存在中文信息
|
|
20
33
|
const res = await service.searchByZh(info.allWords);
|
|
34
|
+
|
|
35
|
+
if (res.code !== 10000) {
|
|
36
|
+
log.error('请求数据出错:' + res.msg);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
const wordsMap = res.data;
|
|
22
41
|
|
|
23
42
|
const replaceWords = {}; // { zh: id } 需要在代码中替换的词条id
|
|
24
43
|
const newWords = {}; // { zh1: '待翻译', zh2: '请选择:中文1/中文2' }
|
|
25
|
-
Object.entries(wordsMap).forEach(([
|
|
44
|
+
Object.entries(wordsMap).forEach(([word, value]) => {
|
|
26
45
|
// 如果当前中文词条在平台中存在,且对应英文翻译有且只有一条,那么直接替换代码中的中文为当前id,否则生成临时key,让开发者手动确认
|
|
27
46
|
if (value.length === 1) {
|
|
28
|
-
replaceWords[
|
|
47
|
+
replaceWords[word] = value[0].key;
|
|
29
48
|
} else {
|
|
30
49
|
const id = uuidv4();
|
|
31
|
-
replaceWords[
|
|
50
|
+
replaceWords[word] = id;
|
|
32
51
|
newWords[id] = {
|
|
33
|
-
zh,
|
|
52
|
+
zh: word,
|
|
34
53
|
en:
|
|
35
54
|
value.length === 0
|
|
36
55
|
? '待翻译'
|
|
@@ -50,18 +69,15 @@ async function init() {
|
|
|
50
69
|
if (Object.keys(newWords).length) {
|
|
51
70
|
const newWordsJsonPath = 'newWords.json';
|
|
52
71
|
|
|
53
|
-
|
|
72
|
+
const oldNewWords = file.readJson(newWordsJsonPath) || {};
|
|
54
73
|
file.write(
|
|
55
74
|
newWordsJsonPath,
|
|
56
|
-
JSON.stringify({ ...oldNewWords, ...newWords }, null, 2)
|
|
75
|
+
JSON.stringify({ ...oldNewWords, ...newWords, groupName }, null, 2)
|
|
57
76
|
);
|
|
58
77
|
|
|
59
|
-
// 先注释掉,开始做指标时,会用到
|
|
60
|
-
// const package = file.read('package.json');
|
|
61
|
-
// file.write(newWordsJsonPath, JSON.stringify({ ...oldNewWords, ...newWords, projectName: package.name }, null, 2));
|
|
62
78
|
log.success(`需要翻译的文件在项目根目录的newWords.json中`);
|
|
63
79
|
}
|
|
64
80
|
}
|
|
65
81
|
|
|
66
|
-
//
|
|
67
|
-
module.exports =
|
|
82
|
+
// collect();
|
|
83
|
+
module.exports = collect;
|
|
@@ -8,7 +8,6 @@ module.exports = function (excludes = []) {
|
|
|
8
8
|
// exclude pattern, <string array>
|
|
9
9
|
// e.g. ['**/dist/**', '**/*.config.js', '**/*.data.js']
|
|
10
10
|
exclude: [
|
|
11
|
-
'**/router.config.js',
|
|
12
11
|
'**/src/public/**',
|
|
13
12
|
'**/_MOCK_/**'
|
|
14
13
|
],
|
|
@@ -19,7 +18,7 @@ module.exports = function (excludes = []) {
|
|
|
19
18
|
|
|
20
19
|
// ignored components, <string array>
|
|
21
20
|
// e.g. ['EventTracker']
|
|
22
|
-
ignoreComponents: [],
|
|
21
|
+
ignoreComponents: ['style', 'svg'],
|
|
23
22
|
|
|
24
23
|
// ignored methods, <string array>
|
|
25
24
|
// e.g. ['MirrorTrack']
|
|
@@ -41,6 +40,8 @@ module.exports = function (excludes = []) {
|
|
|
41
40
|
// e.g. 't'
|
|
42
41
|
i18nMethod: 'get',
|
|
43
42
|
|
|
43
|
+
i18nDefaultFunctionKey: 'd',
|
|
44
|
+
|
|
44
45
|
// babel配置项
|
|
45
46
|
babelPresets: [],
|
|
46
47
|
babelPlugins: [],
|
|
@@ -54,6 +55,40 @@ module.exports = function (excludes = []) {
|
|
|
54
55
|
endOfLine: 'lf',
|
|
55
56
|
},
|
|
56
57
|
|
|
58
|
+
// <Tag id={{ key: 'id' }} defaultMessage='中文' />
|
|
59
|
+
// intlTag 是 'Tag'
|
|
60
|
+
// intlTagIdPath 是 'id.key'
|
|
61
|
+
// intlTagDefaultWordPath 是 'defaultMessage',并且如果不配置,默认是'defaultMessage'
|
|
62
|
+
intlTag: '',
|
|
63
|
+
intlTagIdPath: '',
|
|
64
|
+
intlTagDefaultWordPath: '',
|
|
65
|
+
|
|
66
|
+
// intl.formatMessage({
|
|
67
|
+
// key: 'id',
|
|
68
|
+
// defaultMessage: '默认值',
|
|
69
|
+
// })
|
|
70
|
+
// intlFunctionName 是 intl.formatMessage
|
|
71
|
+
// intlFunctionIdPath 是 '0.key'。 如果 配置成 'key' 也行,intlFunctionIdPath如果不以数字开头,会在前面加上'0.' 'key' 就会变成 '0.key'
|
|
72
|
+
// intlFunctionDefaultWordPath 是 '0.defaultMessage',其他的说明同intlFunctionIdPath
|
|
73
|
+
intlFunctionName: '',
|
|
74
|
+
intlFunctionIdPath: '',
|
|
75
|
+
intlFunctionDefaultWordPath: '',
|
|
76
|
+
|
|
77
|
+
// 做过国际化的项目,中文config的路径。例如:'src/local/zh.json'
|
|
78
|
+
localWordPath: '',
|
|
79
|
+
|
|
80
|
+
// 配置 需要被脚本删除的依赖包的名字
|
|
81
|
+
removePkgName: [],
|
|
82
|
+
|
|
83
|
+
// 需要删除的函数和装饰器 的名称
|
|
84
|
+
removeFunctionName: ['injectIntl'],
|
|
85
|
+
|
|
86
|
+
// package.json中项目名称的key
|
|
87
|
+
groupNameKey: 'packageName',
|
|
88
|
+
|
|
89
|
+
// 特殊文件处理的正则 这里默认匹配router.config.js
|
|
90
|
+
specialFileReg: [/src\/config\/router\.config\.js/],
|
|
91
|
+
|
|
57
92
|
// 国际化平台地址
|
|
58
93
|
baseURL: 'http://10.0.1.133:18000',
|
|
59
94
|
};
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
const getDefaultConfig = require('./default');
|
|
2
|
-
const
|
|
3
|
-
const prettier = require('prettier');
|
|
4
|
-
|
|
5
|
-
function createCustomConfig() {
|
|
6
|
-
// 默认生成的配置文件,不需要给出全量可配置属性
|
|
7
|
-
const ignoreAttributes = [
|
|
8
|
-
'primaryRegx',
|
|
9
|
-
'importCode',
|
|
10
|
-
'i18nObject',
|
|
11
|
-
'i18nMethod',
|
|
12
|
-
'baseURL',
|
|
13
|
-
];
|
|
14
|
-
const defaultConfig = getDefaultConfig(ignoreAttributes);
|
|
15
|
-
|
|
16
|
-
const code = `module.exports = ${JSON.stringify(defaultConfig, null, 2)};`;
|
|
17
|
-
|
|
18
|
-
file.write(
|
|
19
|
-
'.intlconfig.js',
|
|
20
|
-
prettier.format(code, { ...defaultConfig.prettier, parser: 'babel' })
|
|
21
|
-
);
|
|
22
|
-
}
|
|
2
|
+
const getCustomConfig = require('./getCustomConfig');
|
|
23
3
|
|
|
24
4
|
// 内置一些,不需要被扫描的函数
|
|
25
5
|
const ignoreMethods = [
|
|
@@ -28,11 +8,8 @@ Object.keys(console).forEach(key => ignoreMethods.push(`console.${key}`))
|
|
|
28
8
|
|
|
29
9
|
module.exports = function () {
|
|
30
10
|
// 获取用户自定义配置文件
|
|
31
|
-
const customConfig =
|
|
11
|
+
const customConfig = getCustomConfig() || {};
|
|
32
12
|
|
|
33
|
-
if (!customConfig) {
|
|
34
|
-
createCustomConfig();
|
|
35
|
-
}
|
|
36
13
|
// 合并配置文件
|
|
37
14
|
const finalyConf = { ...getDefaultConfig(), ...customConfig };
|
|
38
15
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const getCustomConfig = require('./getCustomConfig');
|
|
2
|
+
const getDefaultConfig = require('./default');
|
|
3
|
+
const file = require('../util/file');
|
|
4
|
+
const prettier = require('prettier');
|
|
5
|
+
const log = require('../util/log');
|
|
6
|
+
|
|
7
|
+
module.exports = function initConfig() {
|
|
8
|
+
const customConfigName = '.intlconfig.js'
|
|
9
|
+
|
|
10
|
+
const customConfig = getCustomConfig();
|
|
11
|
+
|
|
12
|
+
if (customConfig) {
|
|
13
|
+
console.log(`${customConfigName}已存在,请手动删除本地已经有的配置文件再重新执行 npm run intl-init`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 默认生成的配置文件,不需要给出全量可配置属性
|
|
18
|
+
const ignoreAttributes = [
|
|
19
|
+
'primaryRegx',
|
|
20
|
+
'importCode',
|
|
21
|
+
'i18nObject',
|
|
22
|
+
'i18nMethod',
|
|
23
|
+
'i18nDefaultFunctionKey',
|
|
24
|
+
'specialFileReg',
|
|
25
|
+
'baseURL',
|
|
26
|
+
];
|
|
27
|
+
const defaultConfig = getDefaultConfig(ignoreAttributes);
|
|
28
|
+
|
|
29
|
+
const code = `module.exports = ${JSON.stringify(defaultConfig, null, 2)};`;
|
|
30
|
+
|
|
31
|
+
file.write(
|
|
32
|
+
customConfigName,
|
|
33
|
+
prettier.format(code, { ...defaultConfig.prettier, parser: 'babel' })
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
log.success(`初始化配置文件成功:.intlconfig.js`);
|
|
37
|
+
}
|
package/bin/scripts/update.js
CHANGED
|
@@ -5,7 +5,7 @@ const downloadJson = require('./util/downloadJson');
|
|
|
5
5
|
const log = require('./util/log');
|
|
6
6
|
const file = require('./util/file');
|
|
7
7
|
|
|
8
|
-
async function
|
|
8
|
+
async function update() {
|
|
9
9
|
const conf = getConf();
|
|
10
10
|
const files = getTargetFiles(conf);
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ async function replace() {
|
|
|
13
13
|
const relationKey = file.readJson('relationKey.json') || {};
|
|
14
14
|
|
|
15
15
|
const info = transformAst('update', files, conf, relationKey);
|
|
16
|
-
downloadJson(info.downloadIds);
|
|
16
|
+
await downloadJson(info.downloadIds);
|
|
17
17
|
|
|
18
18
|
const needDelete = Boolean(Object.keys(relationKey).length);
|
|
19
19
|
if (needDelete) {
|
|
@@ -23,10 +23,10 @@ async function replace() {
|
|
|
23
23
|
log.success('newWords.json和relationKey.json 已删除');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
log.success('脚本执行成功
|
|
26
|
+
log.success('脚本执行成功');
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
module.exports =
|
|
29
|
+
// update();
|
|
30
|
+
module.exports = update;
|
|
31
31
|
|
|
32
32
|
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
const service = require('../service');
|
|
2
2
|
const file = require('./file');
|
|
3
|
+
const log = require('./log');
|
|
4
|
+
const getGroupName = require('./getGroupName');
|
|
3
5
|
|
|
4
6
|
module.exports = async function downloadJson(downloadIds) {
|
|
5
|
-
|
|
7
|
+
// 读取groupName
|
|
8
|
+
const groupName = getGroupName();
|
|
9
|
+
|
|
10
|
+
const res = await service.getJson({ groupName, downloadIds });
|
|
11
|
+
if (res.code !== 10000) {
|
|
12
|
+
log.error(res.msg);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
6
15
|
const { zh, en } = res.data;
|
|
7
16
|
file.write('locales/zh-CN.json', JSON.stringify(zh, null, 2));
|
|
8
17
|
file.write('locales/en-US.json', JSON.stringify(en, null, 2));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const file = require('./file');
|
|
2
|
+
const log = require('./log');
|
|
3
|
+
const getConf = require('../conf');
|
|
4
|
+
|
|
5
|
+
module.exports = function getGroupName() {
|
|
6
|
+
const conf = getConf();
|
|
7
|
+
// 读取packageName
|
|
8
|
+
const package = file.readJson('package.json');
|
|
9
|
+
const groupName = package?.[conf.groupNameKey];
|
|
10
|
+
if (!groupName) {
|
|
11
|
+
log.error(`package.json中,groupName不能为空`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
return groupName;
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const file = require('./file');
|
|
2
|
+
|
|
3
|
+
let wordJson = null;
|
|
4
|
+
// 根据中文配置文件和id,来获取实际的中文
|
|
5
|
+
exports.readWordJson = function (localWordPath) {
|
|
6
|
+
wordJson = file.readJson(localWordPath);
|
|
7
|
+
return Boolean(wordJson);
|
|
8
|
+
}
|
|
9
|
+
// 根据中文配置文件和id,来获取实际的中文
|
|
10
|
+
exports.getWord = function (id) {
|
|
11
|
+
const word = (wordJson || {})[id];
|
|
12
|
+
return word;
|
|
13
|
+
}
|
|
@@ -1,30 +1,160 @@
|
|
|
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 { FormPath } = require('@formily/antd');
|
|
3
7
|
|
|
4
|
-
module.exports = function(
|
|
8
|
+
module.exports = function (
|
|
5
9
|
{
|
|
6
10
|
primaryRegx,
|
|
7
11
|
i18nObject,
|
|
8
12
|
i18nMethod,
|
|
13
|
+
i18nDefaultFunctionKey,
|
|
9
14
|
importCode,
|
|
10
15
|
ignoreLines,
|
|
11
16
|
ignoreMethods,
|
|
12
17
|
ignoreComponents = [],
|
|
13
18
|
ignoreAttributes,
|
|
19
|
+
intlTag,
|
|
20
|
+
intlTagIdPath,
|
|
21
|
+
intlTagDefaultWordPath,
|
|
22
|
+
intlFunctionName,
|
|
23
|
+
intlFunctionIdPath,
|
|
24
|
+
intlFunctionDefaultWordPath,
|
|
25
|
+
removePkgName,
|
|
26
|
+
localWordPath,
|
|
27
|
+
removeFunctionName,
|
|
14
28
|
},
|
|
15
|
-
returns
|
|
29
|
+
returns,
|
|
30
|
+
{ filePath, special },
|
|
16
31
|
) {
|
|
32
|
+
|
|
33
|
+
// jsx默认 defaultMessage
|
|
34
|
+
intlTagDefaultWordPath = intlTagDefaultWordPath || 'defaultMessage';
|
|
35
|
+
|
|
17
36
|
const { replaceWords, allWords, downloadIds } = returns;
|
|
18
37
|
const hacked = {};
|
|
19
38
|
|
|
39
|
+
// 在没有replaceWords的情况下,不用log信息,这里统一处理
|
|
40
|
+
const properLog = {};
|
|
41
|
+
Object.keys(log).forEach(fnName => {
|
|
42
|
+
properLog[fnName] = (...args) => {
|
|
43
|
+
if (!Object.keys(replaceWords).length) return;
|
|
44
|
+
log[fnName](...args);
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// 获取完整路劲。例如:path='key',返回'0.key'
|
|
49
|
+
function getFullPath (path) {
|
|
50
|
+
if (!path) return path;
|
|
51
|
+
if (typeof path !== 'string') return path;
|
|
52
|
+
if (/^[0-9]/.test(path)) {
|
|
53
|
+
return path;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let preFixPath = '0';
|
|
57
|
+
if (!/^\./.test(path)) {
|
|
58
|
+
preFixPath = '0.';
|
|
59
|
+
}
|
|
60
|
+
return preFixPath + path;
|
|
61
|
+
}
|
|
62
|
+
// 插入注释
|
|
63
|
+
function insertFailCommon(node) {
|
|
64
|
+
const commentStr = ' @chaoswise/intl脚本替换失败 ';
|
|
65
|
+
const comment = node?.leadingComments?.value
|
|
66
|
+
if (comment && comment.trim() === commentStr) return;
|
|
67
|
+
t.addComment(node, 'leading', commentStr);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 获取国际化jsx标签中的id或者defaultMessage
|
|
71
|
+
function getJsxTagChaoswiseIntlValue(openingElement, intlTagValuePath) {
|
|
72
|
+
// <Tag id={{ x: ['id'] }} defaultMessage={{ x: ['中文'] }} />
|
|
73
|
+
// valueAst是{ x: ['id'] }的ast
|
|
74
|
+
let valueAst;
|
|
75
|
+
// intlTagValuePath 是 id.x.0
|
|
76
|
+
// valueKey 是 id
|
|
77
|
+
// valuePath 是 x.0
|
|
78
|
+
let valueKey = intlTagValuePath;
|
|
79
|
+
let valuePath = '';
|
|
80
|
+
|
|
81
|
+
const index = (intlTagValuePath || '').indexOf('.');
|
|
82
|
+
if (index !== -1) {
|
|
83
|
+
valueKey = intlTagValuePath.slice(0, index);
|
|
84
|
+
valuePath = intlTagValuePath.slice(index + 1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// <Tag {...props} />不能找到对应的值
|
|
88
|
+
valueAst = openingElement.attributes.find((item) => {
|
|
89
|
+
return item?.name?.name === valueKey;
|
|
90
|
+
})?.value;
|
|
91
|
+
// intlTagValuePath配置不正确就会找不到value
|
|
92
|
+
// 比如<Tag id2='id' /> 把intlTagValuePath配置为id就不行,因为这里应该是id2
|
|
93
|
+
if (!valueAst) return false;
|
|
94
|
+
|
|
95
|
+
// 如果是jsx容器,就 去掉jsx容器,拿里面的值
|
|
96
|
+
// 从{{ x: ['id'] }} 变为 { x: ['id'] }
|
|
97
|
+
if (valueAst.type === 'JSXExpressionContainer') {
|
|
98
|
+
valueAst = valueAst.expression;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 把ast转为js, 再用FormPath.getIn来取最终的值
|
|
102
|
+
const { code: valueCode } = generate(valueAst);
|
|
103
|
+
var chaoswiseIntlValue;
|
|
104
|
+
try {
|
|
105
|
+
eval('var chaoswiseIntlValue =' + valueCode);
|
|
106
|
+
chaoswiseIntlValue = FormPath.getIn(chaoswiseIntlValue, valuePath);
|
|
107
|
+
} catch (e) {
|
|
108
|
+
// var a = 'id'; <Tag id={a} 这样会出错
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (typeof chaoswiseIntlValue !== 'string') {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return chaoswiseIntlValue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 获取函数名称 fn/object.fn/object.a.b.c/intl.get().d
|
|
119
|
+
function getFnName(node) {
|
|
120
|
+
let fnName = '';
|
|
121
|
+
while (['CallExpression', 'MemberExpression', 'Identifier'].includes(node?.type)) {
|
|
122
|
+
if (node.type === 'CallExpression') {
|
|
123
|
+
let name = getFnName(node.callee);
|
|
124
|
+
fnName = `${name}().` + fnName;
|
|
125
|
+
break;
|
|
126
|
+
} else if (node.type === 'MemberExpression') {
|
|
127
|
+
fnName = `${node.property.name}.` + fnName;
|
|
128
|
+
if (node.object.name) {
|
|
129
|
+
fnName = `${node.object.name}.` + fnName;
|
|
130
|
+
}
|
|
131
|
+
node = node.object;
|
|
132
|
+
} else if (node.type === 'Identifier') {
|
|
133
|
+
// 这里获取修饰器的函数名称
|
|
134
|
+
fnName = fnName || (node.name + '.')
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 把最后的 点. 取消
|
|
140
|
+
fnName = fnName.slice(0, -1);
|
|
141
|
+
return fnName;
|
|
142
|
+
}
|
|
143
|
+
|
|
20
144
|
// XXX: [TRICKY] 防止中文转码为 unicode
|
|
21
145
|
function hackValue(value, id) {
|
|
22
146
|
if (id) hacked[id] = true;
|
|
23
147
|
|
|
148
|
+
// 字符串默认是单引号,如果模板字符串中出现单引号,需要转义,把 ' 换成 \'
|
|
149
|
+
// 就算用户自定配置字符串为双引号,也没事,默认会转义双引号,但是默认不会处理单引号,所以自己手动处理
|
|
150
|
+
if (/\'/.test(id)) {
|
|
151
|
+
id = id.replace(/\'/g, '\\\'');
|
|
152
|
+
}
|
|
153
|
+
|
|
24
154
|
return Object.assign(t.StringLiteral(value), {
|
|
25
155
|
extra: {
|
|
26
156
|
raw: `'${id}'`, // id
|
|
27
|
-
rawValue: value, //
|
|
157
|
+
rawValue: value, // word
|
|
28
158
|
},
|
|
29
159
|
});
|
|
30
160
|
}
|
|
@@ -37,8 +167,12 @@ module.exports = function(
|
|
|
37
167
|
return false;
|
|
38
168
|
}
|
|
39
169
|
|
|
40
|
-
//
|
|
170
|
+
// 是否命中替换条件
|
|
41
171
|
function isPrimary(str) {
|
|
172
|
+
if (special) {
|
|
173
|
+
// 如果匹配到了替换过的,就返回false。为了防止多次执行collect,多次嵌套替换
|
|
174
|
+
if (specialMatch(str)) return false;
|
|
175
|
+
}
|
|
42
176
|
return primaryRegx.test(str);
|
|
43
177
|
}
|
|
44
178
|
|
|
@@ -58,28 +192,37 @@ module.exports = function(
|
|
|
58
192
|
function makeObjectExpression(obj) {
|
|
59
193
|
if (Object.prototype.toString.call(obj) !== '[object Object]') return null;
|
|
60
194
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
195
|
+
// 模板字符串中,转换后,如果第二项参数还有中文,或者更深层级有中文,这里处理好
|
|
196
|
+
// 模板字符串转换前`${f(`aa${f('中文')}中文`)}中文`
|
|
197
|
+
/* 转换后
|
|
198
|
+
intl
|
|
199
|
+
.get('id1', {
|
|
200
|
+
slot0: f(
|
|
201
|
+
intl
|
|
202
|
+
.get('id2', { slot0: f(intl.get('id3').d('中文')) })
|
|
203
|
+
.d('aa{slot0}中文')
|
|
204
|
+
),
|
|
205
|
+
})
|
|
206
|
+
.d('{slot0}中文');
|
|
207
|
+
*/
|
|
208
|
+
const keys = Object.keys(obj);
|
|
209
|
+
const datas = dealArgs(Object.values(obj).map(item => item.value || item));
|
|
210
|
+
|
|
211
|
+
return t.ObjectExpression(
|
|
212
|
+
keys.map((k, i) => {
|
|
213
|
+
const node = datas[i];
|
|
214
|
+
return t.ObjectProperty(
|
|
71
215
|
t.Identifier(k),
|
|
72
|
-
obj[k].isAstNode ?
|
|
216
|
+
obj[k].isAstNode ? node : t.Identifier(obj[k])
|
|
73
217
|
)
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
return t.ObjectExpression(ObjectPropertyArr);
|
|
218
|
+
})
|
|
219
|
+
);
|
|
77
220
|
}
|
|
78
221
|
|
|
79
222
|
// 更新allWords
|
|
80
|
-
function updateWordsInfo(
|
|
81
|
-
if (allWords.includes(
|
|
82
|
-
allWords.push(
|
|
223
|
+
function updateWordsInfo(word) {
|
|
224
|
+
if (allWords.includes(word)) return;
|
|
225
|
+
allWords.push(word);
|
|
83
226
|
}
|
|
84
227
|
|
|
85
228
|
// 处理函数的argments
|
|
@@ -87,7 +230,7 @@ module.exports = function(
|
|
|
87
230
|
if (!Array.isArray(args)) return args;
|
|
88
231
|
const resArgs = []; // 参数处理完,用resArgs保存
|
|
89
232
|
args.forEach(node => {
|
|
90
|
-
|
|
233
|
+
// 字符串变量
|
|
91
234
|
if (node.type === 'StringLiteral' && isPrimary(node.value)) {
|
|
92
235
|
resArgs.push(makeReplace(node.value));
|
|
93
236
|
}
|
|
@@ -141,6 +284,11 @@ module.exports = function(
|
|
|
141
284
|
// 将中文词条替换为国际化api:init.t(id/key)
|
|
142
285
|
const id = replaceWords[value];
|
|
143
286
|
|
|
287
|
+
// 特殊文件处理
|
|
288
|
+
if (special) {
|
|
289
|
+
const str = `${i18nObject ? `${i18nObject}.` : ''}${i18nMethod}("${id}").${i18nDefaultFunctionKey}("${value}")`;
|
|
290
|
+
return hackValue(str, str,);
|
|
291
|
+
}
|
|
144
292
|
// 生成新的ast节点
|
|
145
293
|
const v = hackValue(value, id);
|
|
146
294
|
const objExp = makeObjectExpression(variables);
|
|
@@ -157,7 +305,7 @@ module.exports = function(
|
|
|
157
305
|
: t.identifier(i18nMethod),
|
|
158
306
|
objExp ? [v, objExp] : [v]
|
|
159
307
|
)
|
|
160
|
-
, t.identifier(
|
|
308
|
+
, t.identifier(i18nDefaultFunctionKey)
|
|
161
309
|
),
|
|
162
310
|
[defaultV]
|
|
163
311
|
);
|
|
@@ -230,67 +378,119 @@ module.exports = function(
|
|
|
230
378
|
}
|
|
231
379
|
return { needReplace, value };
|
|
232
380
|
}
|
|
381
|
+
|
|
233
382
|
// 函数表达式
|
|
234
383
|
function dealCallExpressionNode(node) {
|
|
235
384
|
const res = {
|
|
236
385
|
needReplace: false,
|
|
237
386
|
value: null,
|
|
238
387
|
skip: false,
|
|
388
|
+
remove: false,
|
|
239
389
|
}
|
|
240
390
|
if (shouldIgnore(node)) {
|
|
241
391
|
res.skip = true;
|
|
242
392
|
return res;
|
|
243
393
|
}
|
|
244
394
|
|
|
395
|
+
const fnName = getFnName(node.callee);
|
|
396
|
+
|
|
245
397
|
// 处理 ignoreMethods
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
398
|
+
if ([
|
|
399
|
+
...(ignoreMethods || []),
|
|
400
|
+
`${i18nObject}.${i18nMethod}`, // intl.get
|
|
401
|
+
`${i18nObject}.${i18nMethod}().${i18nDefaultFunctionKey}`, // intl.get().d
|
|
402
|
+
].includes(fnName)) {
|
|
403
|
+
res.skip = true;
|
|
404
|
+
return res;
|
|
405
|
+
}
|
|
254
406
|
|
|
255
|
-
|
|
407
|
+
// 需要删除的函数
|
|
408
|
+
if (removeFunctionName.includes(fnName)) {
|
|
409
|
+
// 文件需要修改
|
|
410
|
+
returns.hasTouch = true;
|
|
411
|
+
res.remove = true;
|
|
412
|
+
return res;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// 已经做过国际化的项目,替换国际化函数
|
|
416
|
+
if (fnName === intlFunctionName) {
|
|
417
|
+
res.skip = true;
|
|
256
418
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
419
|
+
const argsAst = node.arguments;
|
|
420
|
+
// 把ast转为js, 再用FormPath.getIn来取最终的值
|
|
421
|
+
const { code: argsCode } = generate(t.arrayExpression(argsAst));
|
|
422
|
+
let chaoswiseIntlId
|
|
423
|
+
var chaoswiseIntlIdData
|
|
424
|
+
try {
|
|
425
|
+
eval('var chaoswiseIntlIdData =' + argsCode);
|
|
426
|
+
chaoswiseIntlId = FormPath.getIn(chaoswiseIntlIdData, getFullPath(intlFunctionIdPath));
|
|
427
|
+
} catch (e) {
|
|
428
|
+
// var a = 'id'; f(a) 这样会出错
|
|
429
|
+
// TODO
|
|
260
430
|
}
|
|
261
|
-
}
|
|
262
431
|
|
|
263
|
-
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
432
|
+
let value = getWord(chaoswiseIntlId);
|
|
433
|
+
if (!value) {
|
|
434
|
+
let defautValue = FormPath.getIn(chaoswiseIntlIdData, getFullPath(intlFunctionDefaultWordPath));
|
|
435
|
+
if (typeof defautValue === 'string') {
|
|
436
|
+
value = defautValue;
|
|
437
|
+
} else {
|
|
438
|
+
if (intlFunctionIdPath && !chaoswiseIntlId) {
|
|
439
|
+
properLog.warn(`intlFunctionIdPath配置有误,在文件${filePath}中函数为${intlFunctionName},按照intlFunctionIdPath(${intlFunctionIdPath})未找到对应的数据`)
|
|
440
|
+
}
|
|
441
|
+
if (localWordPath && chaoswiseIntlId && !value) {
|
|
442
|
+
properLog.warn(`在${localWordPath}中未找到id为${chaoswiseIntlId}的数据`)
|
|
443
|
+
}
|
|
444
|
+
if (intlFunctionDefaultWordPath) {
|
|
445
|
+
properLog.warn(`intlFunctionDefaultWordPath配置有误,在文件${filePath}中函数为${intlFunctionName},按照intlFunctionDefaultWordPath(${intlFunctionDefaultWordPath})未找到对应的数据`)
|
|
446
|
+
}
|
|
447
|
+
insertFailCommon(node);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (value && isPrimary(value)) {
|
|
452
|
+
res.needReplace = true;
|
|
453
|
+
res.value = value;
|
|
267
454
|
}
|
|
268
455
|
}
|
|
269
456
|
|
|
270
457
|
return res;
|
|
271
458
|
}
|
|
272
459
|
|
|
460
|
+
// TODO
|
|
461
|
+
/*
|
|
462
|
+
this.props.intl = lang === 'zh'? '中文': 'en'
|
|
463
|
+
intl.get(id).d('中文')
|
|
464
|
+
this.props.intl.lang = 'zh' ==> intl.lang = 'zh'
|
|
465
|
+
replaceName: { ['this.props.intl.lang']: () => 'intl.lang' }
|
|
466
|
+
或者replaceName: { ['this.props.intl.lang']: 'intl.lang' }
|
|
467
|
+
*/
|
|
273
468
|
return {
|
|
274
469
|
// 导入声明,比如:import foo from "mod";
|
|
275
470
|
ImportDeclaration(path) {
|
|
276
471
|
// 是否已经导入过 intl 的依赖
|
|
277
472
|
const m = importCode.match(/from ["'](.*)["']/);
|
|
278
473
|
const pkgName = m ? m[1] : '';
|
|
279
|
-
|
|
474
|
+
const name = path.node.source.value;
|
|
475
|
+
if (name === pkgName) {
|
|
280
476
|
returns.hasImport = true;
|
|
281
477
|
}
|
|
478
|
+
if (removePkgName.includes(name)) {
|
|
479
|
+
path.remove();
|
|
480
|
+
returns.hasTouch = true;
|
|
481
|
+
}
|
|
282
482
|
path.skip();
|
|
283
483
|
},
|
|
284
484
|
|
|
285
|
-
// 字符串模版,比如:`我的${bar}${fun('哈哈')}中文` intl.
|
|
485
|
+
// 字符串模版,比如:`我的${bar}${fun('哈哈')}中文` intl.get(我的{bar}{slot1}中文,{bar:fdsafdsdf,slot1:fn()})
|
|
286
486
|
TemplateLiteral(path) {
|
|
287
487
|
const { node } = path;
|
|
288
488
|
|
|
289
489
|
const { needReplace, value, variable, } = dealTemplateLiteralNode(node);
|
|
290
490
|
if (needReplace) {
|
|
291
491
|
path.replaceWith(makeReplace(value, Object.keys(variable).length ? variable : null));
|
|
492
|
+
path.skip();
|
|
292
493
|
}
|
|
293
|
-
path.skip();
|
|
294
494
|
},
|
|
295
495
|
|
|
296
496
|
// 字符串变量
|
|
@@ -307,7 +507,18 @@ module.exports = function(
|
|
|
307
507
|
path.replaceWith(res);
|
|
308
508
|
path.skip();
|
|
309
509
|
} else if (isPrimary(value)) {
|
|
310
|
-
|
|
510
|
+
properLog.warn('ignore 1!!!!!!', value);
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
|
|
514
|
+
// 修饰器
|
|
515
|
+
Decorator(path) {
|
|
516
|
+
const { node } = path;
|
|
517
|
+
const fnName = getFnName(node.expression);
|
|
518
|
+
if (removeFunctionName.includes(fnName)) {
|
|
519
|
+
returns.hasTouch = true;
|
|
520
|
+
path.remove();
|
|
521
|
+
path.skip();
|
|
311
522
|
}
|
|
312
523
|
},
|
|
313
524
|
|
|
@@ -315,13 +526,83 @@ module.exports = function(
|
|
|
315
526
|
CallExpression(path) {
|
|
316
527
|
const { node } = path;
|
|
317
528
|
|
|
318
|
-
const { needReplace, value, skip } = dealCallExpressionNode(node);
|
|
529
|
+
const { needReplace, value, skip, remove } = dealCallExpressionNode(node);
|
|
530
|
+
|
|
531
|
+
if (remove) {
|
|
532
|
+
if (node.arguments.length === 1) {
|
|
533
|
+
// 去掉外侧的包裹组件
|
|
534
|
+
path.replaceWith(node.arguments[0]);
|
|
535
|
+
} else {
|
|
536
|
+
// f( 1, 2)
|
|
537
|
+
// 1, 2
|
|
538
|
+
// 移除函数有问题,这里不处理
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
|
|
319
544
|
if (needReplace) {
|
|
320
545
|
path.replaceWith(makeReplace(value));
|
|
321
546
|
}
|
|
322
547
|
if (skip) path.skip();
|
|
323
548
|
},
|
|
324
549
|
|
|
550
|
+
// jsx标签
|
|
551
|
+
JSXElement(path) {
|
|
552
|
+
const { node } = path;
|
|
553
|
+
const { openingElement } = node;
|
|
554
|
+
const jsxName = openingElement.name.name;
|
|
555
|
+
|
|
556
|
+
// 不解析jsx中的style标签
|
|
557
|
+
if (ignoreComponents.includes(jsxName)) {
|
|
558
|
+
path.skip();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// 如果是配置的国际化jsx标签
|
|
563
|
+
if (!shouldIgnore(node) && intlTag && jsxName === intlTag) {
|
|
564
|
+
|
|
565
|
+
let id = getJsxTagChaoswiseIntlValue(openingElement, intlTagIdPath || 'id');
|
|
566
|
+
|
|
567
|
+
let word = getWord(id);
|
|
568
|
+
|
|
569
|
+
if (!word) {
|
|
570
|
+
// 根据id找不到中文,就找jsx标签的默认中文
|
|
571
|
+
let defaultValue = getJsxTagChaoswiseIntlValue(openingElement, intlTagDefaultWordPath);
|
|
572
|
+
if (typeof defaultValue === 'string') {
|
|
573
|
+
word = defaultValue;
|
|
574
|
+
} else {
|
|
575
|
+
if (!intlTagIdPath) {
|
|
576
|
+
properLog.warn(`intlTagIdPath未配置`);
|
|
577
|
+
} else {
|
|
578
|
+
if (!id) {
|
|
579
|
+
properLog.warn(`intlTagIdPath配置有误,文件${filePath}`);
|
|
580
|
+
} else {
|
|
581
|
+
// word找不到
|
|
582
|
+
localWordPath && properLog.warn(`在${localWordPath}中未找到id为${id}的中文`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (defaultValue === false) {
|
|
586
|
+
properLog.warn(`intlTagDefaultWordPath配置有误,文件${filePath}`);
|
|
587
|
+
}
|
|
588
|
+
insertFailCommon(node);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (word && isPrimary(word)) {
|
|
592
|
+
// 替换国际化标签,<FormatMessage id='zhongwenid' defaultMessage="中文" /> 换成 {intl.get(id).d('中文')}
|
|
593
|
+
const parentNodeType = path.parentPath?.node?.type;
|
|
594
|
+
let res = makeReplace(word);
|
|
595
|
+
|
|
596
|
+
// 如果节点的父节点是JSXFragment或者JSXElement,那么就包一层JSXExpressionContainer
|
|
597
|
+
if (['JSXFragment', 'JSXElement'].includes(parentNodeType)) {
|
|
598
|
+
res = t.JSXExpressionContainer(res);
|
|
599
|
+
}
|
|
600
|
+
path.replaceWith(res);
|
|
601
|
+
}
|
|
602
|
+
path.skip();
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
|
|
325
606
|
// JSX文本节点
|
|
326
607
|
JSXText(path) {
|
|
327
608
|
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
|
+
}
|
|
@@ -13,10 +13,12 @@ const pluginSyntaxAsyncGenerators = require('@babel/plugin-syntax-async-generato
|
|
|
13
13
|
const pluginSyntaxDoExpressions = require('@babel/plugin-syntax-do-expressions');
|
|
14
14
|
const pluginSyntaxDynamicImport = require('@babel/plugin-syntax-dynamic-import');
|
|
15
15
|
const pluginSyntaxFunctionBind = require('@babel/plugin-syntax-function-bind');
|
|
16
|
+
const pluginExportDefaultFrom = require('@babel/plugin-proposal-export-default-from');
|
|
16
17
|
const presetTypescript = require('@babel/preset-typescript').default;
|
|
17
18
|
|
|
18
19
|
const makeVisitorCollect = require('./makeVisitorCollect');
|
|
19
20
|
const makeVisitorUpdate = require('./makeVisitorUpdate');
|
|
21
|
+
const log = require('./log');
|
|
20
22
|
|
|
21
23
|
// 获取文件中需要忽略转化通用国际化API规范的所有行号
|
|
22
24
|
function getIgnoreLines(ast) {
|
|
@@ -69,16 +71,13 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
|
|
|
69
71
|
const {
|
|
70
72
|
entry,
|
|
71
73
|
output,
|
|
72
|
-
primaryRegx,
|
|
73
|
-
importCode,
|
|
74
|
-
i18nObject,
|
|
75
|
-
i18nMethod,
|
|
76
74
|
babelPresets = [],
|
|
77
75
|
babelPlugins = [],
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
specialFileReg,
|
|
77
|
+
|
|
78
|
+
...opts
|
|
81
79
|
} = conf;
|
|
80
|
+
const { importCode } = opts;
|
|
82
81
|
|
|
83
82
|
const allWords = []; // 收集到的所有词条
|
|
84
83
|
const downloadIds = []; // 需要从平台下载的词条id
|
|
@@ -105,24 +104,18 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
|
|
|
105
104
|
pluginSyntaxDoExpressions,
|
|
106
105
|
pluginSyntaxDynamicImport,
|
|
107
106
|
pluginSyntaxFunctionBind,
|
|
107
|
+
pluginExportDefaultFrom,
|
|
108
108
|
...babelPlugins,
|
|
109
109
|
],
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
-
const opts = {
|
|
113
|
-
primaryRegx,
|
|
114
|
-
i18nObject,
|
|
115
|
-
i18nMethod,
|
|
116
|
-
importCode,
|
|
117
|
-
ignoreLines: [],
|
|
118
|
-
ignoreMethods,
|
|
119
|
-
ignoreComponents,
|
|
120
|
-
ignoreAttributes,
|
|
121
|
-
};
|
|
122
|
-
|
|
123
112
|
// 处理所有文件
|
|
124
113
|
files.forEach((file) => {
|
|
125
114
|
const { filePath } = file;
|
|
115
|
+
|
|
116
|
+
if (specialFileReg.some(reg => reg.test(filePath))) {
|
|
117
|
+
file.special = true;
|
|
118
|
+
}
|
|
126
119
|
const isTSX = ['.ts', '.tsx'].includes(path.extname(filePath));
|
|
127
120
|
|
|
128
121
|
const r = {
|
|
@@ -133,7 +126,16 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
|
|
|
133
126
|
hasTouch: false, // 是否存在需要替换的词条
|
|
134
127
|
};
|
|
135
128
|
const sourceCode = fs.readFileSync(filePath, 'utf8');
|
|
136
|
-
|
|
129
|
+
|
|
130
|
+
let ast;
|
|
131
|
+
try {
|
|
132
|
+
ast = babel.parseSync(sourceCode, transformOptions);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
replaceWords && log.error(`文件解析出错:${file.filePath}
|
|
135
|
+
${e}`)
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
137
139
|
opts.ignoreLines = getIgnoreLines(ast);
|
|
138
140
|
|
|
139
141
|
let makeVisitor = makeVisitorCollect;
|
|
@@ -141,8 +143,14 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
|
|
|
141
143
|
makeVisitor = makeVisitorUpdate
|
|
142
144
|
}
|
|
143
145
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
try {
|
|
147
|
+
const visitor = makeVisitor(opts, r, file);
|
|
148
|
+
traverse(ast, visitor);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
replaceWords && log.error(`文件解析出错:${file.filePath}
|
|
151
|
+
${e}`)
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
146
154
|
|
|
147
155
|
// 不传入需要替换的文词条则不进行文件修改
|
|
148
156
|
// 在只需要提取中文词条的情况下不传入replaceWords
|
|
@@ -156,7 +164,7 @@ module.exports = function (type, files = [], conf = {}, replaceWords) {
|
|
|
156
164
|
|
|
157
165
|
if (!r.hasTouch) {
|
|
158
166
|
code = sourceCode;
|
|
159
|
-
} else if (!r.hasImport && importCode) {
|
|
167
|
+
} else if (!r.hasImport && !file.special && importCode && Object.keys(replaceWords).length) {
|
|
160
168
|
code = `${importCode}\n${code}`;
|
|
161
169
|
}
|
|
162
170
|
|
package/lib/index.js
CHANGED
|
@@ -25,4 +25,5 @@ _Object$defineProperty(exports, "useIntl", {
|
|
|
25
25
|
});
|
|
26
26
|
var _useIntl = _interopRequireDefault(require("./useIntl"));
|
|
27
27
|
var _context = _interopRequireDefault(require("./useIntl/context"));
|
|
28
|
-
var _reactIntlUniversal = _interopRequireDefault(require("react-intl-universal"));
|
|
28
|
+
var _reactIntlUniversal = _interopRequireDefault(require("react-intl-universal"));
|
|
29
|
+
_reactIntlUniversal["default"].options.escapeHtml = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaoswise/intl",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"author": "cloudwiser",
|
|
5
5
|
"description": "intl",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
"babel-plugin-macros": "^3.1.0",
|
|
68
68
|
"babel-plugin-polyfill-corejs3": "^0.5.2",
|
|
69
69
|
"chalk": "^2.4.1",
|
|
70
|
+
"glob": "^8.0.3",
|
|
70
71
|
"gulp": "^4.0.2",
|
|
71
72
|
"gulp-babel": "^8.0.0",
|
|
72
|
-
"gulp-typescript": "^5.0.1",
|
|
73
73
|
"gulp-connect": "^5.7.0",
|
|
74
74
|
"gulp-jsdoc3": "^3.0.0",
|
|
75
|
+
"gulp-typescript": "^5.0.1",
|
|
75
76
|
"prettier": "^2.8.1",
|
|
76
|
-
"glob": "^8.0.3",
|
|
77
77
|
"react-intl-universal": "^2.6.11",
|
|
78
78
|
"uuid": "^9.0.0"
|
|
79
79
|
},
|
|
@@ -81,5 +81,6 @@
|
|
|
81
81
|
"react": "^16.13.1",
|
|
82
82
|
"react-dom": "^16.13.1"
|
|
83
83
|
},
|
|
84
|
-
"license": "MIT"
|
|
84
|
+
"license": "MIT",
|
|
85
|
+
"gitHead": "6ed1475f01a4130625bbed5cf0a4daadde68d43e"
|
|
85
86
|
}
|