xshell 0.0.16 → 0.0.21
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/chalk.browser.d.ts +2 -0
- package/chalk.browser.js +21 -0
- package/chalk.browser.js.map +1 -0
- package/file.js +1 -2
- package/file.js.map +1 -1
- package/i18n/README.md +275 -0
- package/i18n/dict.d.ts +30 -0
- package/i18n/dict.js +34 -0
- package/i18n/dict.js.map +1 -0
- package/i18n/i18n-scan.d.ts +2 -0
- package/i18n/i18n-scan.js +21 -0
- package/i18n/i18n-scan.js.map +1 -0
- package/i18n/i18n.ico +0 -0
- package/i18n/index.d.ts +65 -0
- package/i18n/index.js +118 -0
- package/i18n/index.js.map +1 -0
- package/i18n/rwdict.d.ts +42 -0
- package/i18n/rwdict.js +110 -0
- package/i18n/rwdict.js.map +1 -0
- package/i18n/scanner/checker.d.ts +5 -0
- package/i18n/scanner/checker.js +73 -0
- package/i18n/scanner/checker.js.map +1 -0
- package/i18n/scanner/index.d.ts +52 -0
- package/i18n/scanner/index.js +319 -0
- package/i18n/scanner/index.js.map +1 -0
- package/i18n/scanner/parser.d.ts +3 -0
- package/i18n/scanner/parser.js +154 -0
- package/i18n/scanner/parser.js.map +1 -0
- package/i18n/utils.d.ts +1 -0
- package/i18n/utils.js +14 -0
- package/i18n/utils.js.map +1 -0
- package/net.browser.d.ts +23 -0
- package/net.browser.js +70 -0
- package/net.browser.js.map +1 -0
- package/net.js +2 -4
- package/net.js.map +1 -1
- package/package.json +36 -7
- package/prototype.browser.d.ts +130 -0
- package/prototype.browser.js +421 -0
- package/prototype.browser.js.map +1 -0
- package/repl.js +4 -8
- package/repl.js.map +1 -1
- package/server.js +2 -3
- package/server.js.map +1 -1
- package/{toaster.d.ts → toaster.browser.d.ts} +0 -0
- package/toaster.browser.js +45 -0
- package/toaster.browser.js.map +1 -0
- package/ufs.js +3 -3
- package/ufs.js.map +1 -1
- package/utils.browser.d.ts +3 -0
- package/utils.browser.js +27 -0
- package/utils.browser.js.map +1 -0
- package/chalk.browser.ts +0 -41
- package/extension.d.ts +0 -3
- package/extension.js +0 -68
- package/extension.js.map +0 -1
- package/net.browser.ts +0 -141
- package/prototype.browser.ts +0 -728
- package/toaster.browser.ts +0 -50
- package/tsconfig.json +0 -73
- package/utils.browser.ts +0 -25
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scanner = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const i18next_scanner_1 = (0, tslib_1.__importDefault)(require("i18next-scanner"));
|
|
6
|
+
const upath_1 = (0, tslib_1.__importDefault)(require("upath"));
|
|
7
|
+
const ejs_1 = (0, tslib_1.__importDefault)(require("ejs"));
|
|
8
|
+
const vinyl_fs_1 = (0, tslib_1.__importDefault)(require("vinyl-fs"));
|
|
9
|
+
const map_stream_1 = (0, tslib_1.__importDefault)(require("map-stream"));
|
|
10
|
+
const gulp_sort_1 = (0, tslib_1.__importDefault)(require("gulp-sort"));
|
|
11
|
+
const ora_1 = (0, tslib_1.__importDefault)(require("ora"));
|
|
12
|
+
const cli_truncate_1 = (0, tslib_1.__importDefault)(require("cli-truncate"));
|
|
13
|
+
const vinyl_1 = (0, tslib_1.__importDefault)(require("vinyl"));
|
|
14
|
+
const through2_1 = (0, tslib_1.__importDefault)(require("through2"));
|
|
15
|
+
const cli_table3_1 = (0, tslib_1.__importDefault)(require("cli-table3"));
|
|
16
|
+
const index_1 = require("../index");
|
|
17
|
+
const rwdict_1 = (0, tslib_1.__importDefault)(require("../rwdict"));
|
|
18
|
+
const utils_1 = require("../utils");
|
|
19
|
+
require("../../prototype.js");
|
|
20
|
+
const parser_1 = require("./parser");
|
|
21
|
+
/** 默认 i18next 扫描配置 */
|
|
22
|
+
const DEFAULT_CONFIG = {
|
|
23
|
+
debug: false,
|
|
24
|
+
input: [
|
|
25
|
+
// 'src/**/*.{js,jsx,ts,tsx}',
|
|
26
|
+
'!i18n/**', // Use ! to filter out files or directories
|
|
27
|
+
],
|
|
28
|
+
// 相对于根目录
|
|
29
|
+
output: 'i18n/',
|
|
30
|
+
// 若是相对路径,则以 output 为基准进行解析
|
|
31
|
+
dict: ['dict.json', 'scanneds.json'],
|
|
32
|
+
lngs: ['zh', 'en', 'ja', 'ko'],
|
|
33
|
+
ns: ['translation'],
|
|
34
|
+
defaultLng: 'zh',
|
|
35
|
+
defaultNs: 'translation',
|
|
36
|
+
func: {
|
|
37
|
+
list: ['i18next.t', 'i18n.t', 'i18n.__', 't', '__'],
|
|
38
|
+
extensions: [], // 避免在 transform 中执行原生的 parseFuncFromString
|
|
39
|
+
},
|
|
40
|
+
trans: {
|
|
41
|
+
extensions: [],
|
|
42
|
+
fallbackKey: true,
|
|
43
|
+
babylon: {
|
|
44
|
+
sourceType: 'module',
|
|
45
|
+
allowAwaitOutsideFunction: true,
|
|
46
|
+
// https://babeljs.io/docs/en/babel-parser
|
|
47
|
+
plugins: [
|
|
48
|
+
// Language extensions
|
|
49
|
+
'jsx',
|
|
50
|
+
'typescript',
|
|
51
|
+
// ECMAScript proposals
|
|
52
|
+
'classProperties',
|
|
53
|
+
'classPrivateProperties',
|
|
54
|
+
'classPrivateMethods',
|
|
55
|
+
'classStaticBlock',
|
|
56
|
+
'decimal',
|
|
57
|
+
['decorators', { decoratorsBeforeExport: true }],
|
|
58
|
+
'doExpressions',
|
|
59
|
+
'exportDefaultFrom',
|
|
60
|
+
'functionBind',
|
|
61
|
+
'importAssertions',
|
|
62
|
+
'moduleBlocks',
|
|
63
|
+
'moduleStringNames',
|
|
64
|
+
'partialApplication',
|
|
65
|
+
['pipelineOperator', { proposal: 'smart' }],
|
|
66
|
+
'privateIn',
|
|
67
|
+
['recordAndTuple', { syntaxType: 'bar' }],
|
|
68
|
+
'throwExpressions',
|
|
69
|
+
'topLevelAwait',
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
// 实际并没有用到 acorn, 用了 babel
|
|
73
|
+
acorn: {
|
|
74
|
+
ecmaVersion: 'latest',
|
|
75
|
+
sourceType: 'module', // defaults to 'module'
|
|
76
|
+
// Check out https://github.com/acornjs/acorn/tree/master/acorn#interface for additional options
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
// 禁用 : 和 . 作为 seperator
|
|
80
|
+
keySeparator: false,
|
|
81
|
+
nsSeparator: false,
|
|
82
|
+
// Context Form
|
|
83
|
+
context: true,
|
|
84
|
+
contextFallback: true,
|
|
85
|
+
contextSeparator: '_',
|
|
86
|
+
// Plural
|
|
87
|
+
// whether to add plural form key
|
|
88
|
+
plural(language, ns, key, options /** Config */) {
|
|
89
|
+
return language === 'en';
|
|
90
|
+
},
|
|
91
|
+
pluralFallback: true,
|
|
92
|
+
pluralSeparator: '_',
|
|
93
|
+
// interpolation options
|
|
94
|
+
interpolation: {
|
|
95
|
+
prefix: '{{',
|
|
96
|
+
suffix: '}}' // suffix for interpolation
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const VALID_EXTENTIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.ejs']);
|
|
100
|
+
/** 扫描源码中的词条,以及收集未翻译的词条。生成 scanneds.json 和 untranslateds.json
|
|
101
|
+
* rootdir 要扫描根目录 [ process.cwd() ]
|
|
102
|
+
* config 配置信息
|
|
103
|
+
*/
|
|
104
|
+
function scanner(rootdir = upath_1.default.normalize(process.cwd()), config = {}) {
|
|
105
|
+
const output = upath_1.default.resolve(rootdir, config.output || DEFAULT_CONFIG.output);
|
|
106
|
+
const input = (config.input || DEFAULT_CONFIG.input).map(fp => upath_1.default.resolve(rootdir, fp));
|
|
107
|
+
config = {
|
|
108
|
+
...DEFAULT_CONFIG,
|
|
109
|
+
...config,
|
|
110
|
+
input,
|
|
111
|
+
output,
|
|
112
|
+
resource: {
|
|
113
|
+
loadPath: '',
|
|
114
|
+
savePath: upath_1.default.resolve(output, 'translation/{{lng}}.js'),
|
|
115
|
+
jsonIndent: 4,
|
|
116
|
+
lineEnding: '\n'
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
let dict = config.dict.reduce((dict, fp_dict) => dict.merge((0, utils_1.try_require)(upath_1.default.resolve(output, fp_dict)), { print: false, overwrite: true }), new rwdict_1.default());
|
|
120
|
+
let c_files = 0;
|
|
121
|
+
let c_scanneds = 0;
|
|
122
|
+
let errors = [];
|
|
123
|
+
// 扫描出的词条及已有的翻译
|
|
124
|
+
let scanneds = {};
|
|
125
|
+
// 所有语言的扫描统计信息
|
|
126
|
+
let stats = Object.fromEntries(index_1.LANGUAGES.map((language) => [language, { translateds: new Set(), untranslateds: new Set() }]));
|
|
127
|
+
let spinner = (0, ora_1.default)({ interval: 66 }).start('Scanning...');
|
|
128
|
+
function on_scanned(text, { language, key, defaultValue, count, context }) {
|
|
129
|
+
// console.log(text, { language, key, defaultValue, count, context })
|
|
130
|
+
text = text || defaultValue;
|
|
131
|
+
if (!key)
|
|
132
|
+
key = context ? `${text}_${context}` : text;
|
|
133
|
+
if (!language) {
|
|
134
|
+
for (const language of index_1.LANGUAGES)
|
|
135
|
+
on_scanned(text, { language, key, count, context });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// console.log(text, { language, key, defaultValue, count, context })
|
|
139
|
+
// debugger
|
|
140
|
+
const stat = stats[language];
|
|
141
|
+
// 获取已有翻译
|
|
142
|
+
const translation = dict.get(key, language) ||
|
|
143
|
+
language === 'zh' && text ||
|
|
144
|
+
'';
|
|
145
|
+
if (language === 'zh' && !context)
|
|
146
|
+
return;
|
|
147
|
+
scanneds[key] = {
|
|
148
|
+
...scanneds[key],
|
|
149
|
+
[language]: translation
|
|
150
|
+
};
|
|
151
|
+
if (translation)
|
|
152
|
+
stat.translateds.add(key);
|
|
153
|
+
else
|
|
154
|
+
stat.untranslateds.add(key);
|
|
155
|
+
if (language === 'en' && count !== undefined)
|
|
156
|
+
on_scanned(text, { language, key: `${key}_plural`, context });
|
|
157
|
+
}
|
|
158
|
+
function new_vinyl_file(_path, data) {
|
|
159
|
+
return new vinyl_1.default({
|
|
160
|
+
cwd: rootdir,
|
|
161
|
+
base: rootdir,
|
|
162
|
+
path: upath_1.default.resolve(config.output, _path),
|
|
163
|
+
contents: Buffer.from(typeof data === 'string' ? data : JSON.stringify(data, null, 4))
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// ------------ scan by file
|
|
167
|
+
vinyl_fs_1.default
|
|
168
|
+
.src(config.input, { cwd: rootdir, sync: false })
|
|
169
|
+
// 每个文件扫描前,统计文件数量
|
|
170
|
+
.pipe((0, map_stream_1.default)((file, cb, count) => {
|
|
171
|
+
// 支持 `// @i18n-noscan` 忽略扫描
|
|
172
|
+
if (/\/\/\s*@i18n-noscan\s/.test(file.contents.toString()))
|
|
173
|
+
return cb();
|
|
174
|
+
c_files++;
|
|
175
|
+
cb(null, file);
|
|
176
|
+
}))
|
|
177
|
+
// 对文件进行排序,保证词条有一定的顺序
|
|
178
|
+
.pipe((0, gulp_sort_1.default)())
|
|
179
|
+
// 分析代码提取词条
|
|
180
|
+
.pipe(i18next_scanner_1.default.createStream(config, function transform(file, encoding, callback) {
|
|
181
|
+
const { parser } = this;
|
|
182
|
+
const ext = upath_1.default.extname(file.path);
|
|
183
|
+
// 只扫描源码文件
|
|
184
|
+
if (!VALID_EXTENTIONS.has(ext)) {
|
|
185
|
+
callback();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
c_scanneds++;
|
|
189
|
+
const percent = Math.round((100 * c_scanneds) / c_files);
|
|
190
|
+
const text = `Scanning (${percent}%): ${file.path.green}`;
|
|
191
|
+
spinner.text = (0, cli_truncate_1.default)(text, process.stdout.columns - 5, { position: 'middle', });
|
|
192
|
+
let code = file.contents.toString();
|
|
193
|
+
if (ext === '.ejs')
|
|
194
|
+
code = ejs_1.default.compile(code, { filename: file.path, client: true, legacyInclude: true }).toString();
|
|
195
|
+
// --- 添加代码中扫描到的 i18n.t('key') 中的 key 到 parser
|
|
196
|
+
// parser.parseFuncFromString 使用 esprima 来解析代码,esprima 仍然不支持 optional chaining !!
|
|
197
|
+
parser.parseFuncFromString(code.replace(/\?\.\[/g, '[').replace(/\?\.\(/g, '(').replace(/\?\./g, '.'), on_scanned);
|
|
198
|
+
// --- 添加代码中扫描到的 Trans 组件中的 key 到 parser
|
|
199
|
+
if (ext === '.jsx' || ext === '.tsx') {
|
|
200
|
+
// parser.parseTransFromString 使用 acorn 解析代码,不支持 TypeScript,添加 parser.parseTransFromStringByBabel
|
|
201
|
+
(0, parser_1.mix_parse_trans_from_string_by_babel)(parser);
|
|
202
|
+
parser.parseTransFromStringByBabel(code, { filepath: file.path }, on_scanned, (error) => { errors.push(error); });
|
|
203
|
+
}
|
|
204
|
+
setTimeout(callback, 0);
|
|
205
|
+
}))
|
|
206
|
+
// 创建词条文件
|
|
207
|
+
.pipe(through2_1.default.obj(
|
|
208
|
+
/** i18n-scanner 会把扫描结果以每个语言一个文件的形式提供,这里解析扫描结果
|
|
209
|
+
* file: 翻译 resource 文件,其中 file.contents 包含翻译的扫描结果
|
|
210
|
+
*/
|
|
211
|
+
function write(file, encoding, cb) { cb(); },
|
|
212
|
+
/** 生成 stats.json, unmarkeds.md; 打印 untranslated / unmarkeds */
|
|
213
|
+
function flush(cb) {
|
|
214
|
+
// ------------ stats.json
|
|
215
|
+
this.push(new_vinyl_file('stats.json', Object.fromEntries(Object.entries(stats).map(([l, { translateds, untranslateds }]) => [l, { translateds: Array.from(translateds), untranslateds: Array.from(untranslateds) }]))));
|
|
216
|
+
// ------------ 打印 cli 统计表
|
|
217
|
+
const table = new cli_table3_1.default({
|
|
218
|
+
head: [
|
|
219
|
+
'Language',
|
|
220
|
+
'Untranslated'.red,
|
|
221
|
+
'Translated'.green,
|
|
222
|
+
],
|
|
223
|
+
colAligns: ['right', 'right', 'right', 'right'],
|
|
224
|
+
style: { head: [] },
|
|
225
|
+
chars: {
|
|
226
|
+
top: '',
|
|
227
|
+
'top-mid': '',
|
|
228
|
+
'top-left': '',
|
|
229
|
+
'top-right': '',
|
|
230
|
+
bottom: '',
|
|
231
|
+
'bottom-mid': '',
|
|
232
|
+
'bottom-left': '',
|
|
233
|
+
'bottom-right': '',
|
|
234
|
+
left: '',
|
|
235
|
+
'left-mid': '',
|
|
236
|
+
mid: '',
|
|
237
|
+
'mid-mid': '',
|
|
238
|
+
right: '',
|
|
239
|
+
'right-mid': '',
|
|
240
|
+
middle: ' ',
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
Object.entries(stats).forEach(([lang, stat]) => {
|
|
244
|
+
table.push([
|
|
245
|
+
lang,
|
|
246
|
+
String(stat.untranslateds.size).red,
|
|
247
|
+
String(stat.translateds.size).green
|
|
248
|
+
]);
|
|
249
|
+
});
|
|
250
|
+
spinner.stop();
|
|
251
|
+
console.log(`Scanned ${c_files} files. Occured ${errors.length} errors.`);
|
|
252
|
+
console.log(table.toString());
|
|
253
|
+
// ------------ 生成 unmarkeds.md 统计
|
|
254
|
+
/*
|
|
255
|
+
const fp_unmarked = path.resolve(config.output, 'unmarkeds.md')
|
|
256
|
+
|
|
257
|
+
if (fs.existsSync(fp_unmarked))
|
|
258
|
+
rimraf.sync(fp_unmarked)
|
|
259
|
+
|
|
260
|
+
if (unmarkeds.length) {
|
|
261
|
+
console.log(colors.yellow(`\n⚠️ 发现未标记的中文字符 ${unmarkeds.length} 处:\n`))
|
|
262
|
+
unmarkeds.forEach(({ value, filepath, loc: { start } }, index) => {
|
|
263
|
+
if (index >= 5) return
|
|
264
|
+
console.log( ` ${colors.white(`'${value}'`)}\t${colors.blue.underline(`${path.relative(rootdir, filepath)}:${start.line}:${start.column + 1}`)}` )
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.push( new_vinyl_file( fp_unmarked,
|
|
269
|
+
unmarkeds.map( ({ value, filepath, loc }) =>
|
|
270
|
+
'- [' + value.trim() + '](' + path.relative( config.output, path.resolve(rootdir, filepath || '') ) + '#L' + loc.start.line + ')'
|
|
271
|
+
).join('\n') + '\n'
|
|
272
|
+
))
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
if (unmarkeds.length > 5) {
|
|
276
|
+
console.log(' ...')
|
|
277
|
+
console.log(colors.yellow(`\n 完整未标记词条请查看 ${colors.blue.underline(path.relative(rootdir, fp_unmarked))}`))
|
|
278
|
+
}
|
|
279
|
+
*/
|
|
280
|
+
const en_untranslateds = stats.en.untranslateds;
|
|
281
|
+
if (en_untranslateds.size) {
|
|
282
|
+
console.log('\n未翻译的英文词条:'.yellow);
|
|
283
|
+
Array.from(en_untranslateds).slice(0, 10).forEach(untranslated => {
|
|
284
|
+
console.log(untranslated);
|
|
285
|
+
});
|
|
286
|
+
if (en_untranslateds.size > 10) {
|
|
287
|
+
console.log('...');
|
|
288
|
+
console.log(`--- 共 ${en_untranslateds.size} 个未翻译的英文词条 ---`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
else
|
|
292
|
+
console.log('\n所有词条都至少含有英文翻译.'.green);
|
|
293
|
+
// ------------ 生成 scanneds.json
|
|
294
|
+
const fp_scanneds = upath_1.default.resolve(config.output, 'scanneds.json');
|
|
295
|
+
this.push(new_vinyl_file(fp_scanneds, scanneds));
|
|
296
|
+
// ------------ 写入 dict.json
|
|
297
|
+
const fp_dict_new = upath_1.default.resolve(output, 'dict.json');
|
|
298
|
+
this.push(new_vinyl_file(fp_dict_new, dict.to_json(true) + '\n'));
|
|
299
|
+
console.log(`\n\n${'⚠️ 请检查扫描结果'.yellow} ${fp_scanneds.underline.blue} ${'和新生成的词典文件'.yellow} ${fp_dict_new.underline.blue}`);
|
|
300
|
+
console.log('\n请手动补全扫描结果 scanneds.json 中未翻译的词条'.yellow);
|
|
301
|
+
console.log('\n');
|
|
302
|
+
console.log('通过以上方法补充翻译后重新运行扫描,会根据 scanneds.json 更新 dict.json'.yellow);
|
|
303
|
+
console.log('最后 dict.json 所包含的词条会被打包进 js, 通过 new I18N(<dict.json>) 或 i18n.init(<dict.json>) 加载'.yellow);
|
|
304
|
+
console.log();
|
|
305
|
+
console.log(`${'详细文档请查看:'.yellow} ${'https://github.com/ShenHongFei/xshell/tree/master/i18n'.blue.underline}`);
|
|
306
|
+
cb();
|
|
307
|
+
}))
|
|
308
|
+
// 写入词条文件
|
|
309
|
+
.pipe(vinyl_fs_1.default.dest(rootdir))
|
|
310
|
+
.on('end', () => {
|
|
311
|
+
errors.forEach(errorHandler => errorHandler());
|
|
312
|
+
if (!errors.length)
|
|
313
|
+
return;
|
|
314
|
+
console.log('https://www.i18next.com/translation-function/essentials\n以上错误可能是由不规范的词条标记导致,标记规范可见:%s', ''.blue.underline);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
exports.scanner = scanner;
|
|
318
|
+
exports.default = scanner;
|
|
319
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import i18n_scanner from 'i18next-scanner'\nimport path from 'upath'\nimport ejs from 'ejs'\nimport vfs from 'vinyl-fs'\nimport map from 'map-stream'\nimport sort from 'gulp-sort'\nimport ora from 'ora'\nimport cli_truncate from 'cli-truncate'\nimport Vinyl from 'vinyl'\nimport through2 from 'through2'\nimport CliTable from 'cli-table3'\nimport type { Transform } from 'stream'\n\nimport { LANGUAGES } from '../index'\nimport type { Language } from '../index'\nimport Dict from '../rwdict'\nimport type { _Dict } from '../dict'\nimport { try_require } from '../utils'\n\nimport '../../prototype.js'\n\nimport { mix_parse_trans_from_string_by_babel } from './parser'\n\n\n\n/** 默认 i18next 扫描配置 */\nconst DEFAULT_CONFIG = {\n debug: false,\n \n input: [\n // 'src/**/*.{js,jsx,ts,tsx}',\n '!i18n/**', // Use ! to filter out files or directories\n ],\n \n // 相对于根目录\n output: 'i18n/',\n \n // 若是相对路径,则以 output 为基准进行解析\n dict: ['dict.json', 'scanneds.json'],\n \n lngs: ['zh', 'en', 'ja', 'ko'],\n ns: ['translation'],\n defaultLng: 'zh',\n defaultNs: 'translation',\n\n func: {\n list: [ 'i18next.t', 'i18n.t', 'i18n.__', 't', '__' ],\n extensions: [ ], // 避免在 transform 中执行原生的 parseFuncFromString\n },\n \n trans: {\n extensions: [ ], // 避免在 transform 中执行原生的 parseTransFromString\n fallbackKey: true,\n \n babylon: {\n sourceType: 'module',\n \n allowAwaitOutsideFunction: true,\n \n // https://babeljs.io/docs/en/babel-parser\n plugins: [\n // Language extensions\n 'jsx',\n 'typescript',\n \n // ECMAScript proposals\n 'classProperties',\n 'classPrivateProperties',\n 'classPrivateMethods',\n 'classStaticBlock',\n 'decimal',\n ['decorators', { decoratorsBeforeExport: true }],\n 'doExpressions',\n 'exportDefaultFrom',\n 'functionBind',\n 'importAssertions',\n 'moduleBlocks',\n 'moduleStringNames',\n 'partialApplication',\n ['pipelineOperator', { proposal: 'smart' }],\n 'privateIn',\n ['recordAndTuple', { syntaxType: 'bar' }],\n 'throwExpressions',\n 'topLevelAwait',\n ],\n } as import('@babel/parser').ParserOptions,\n \n // 实际并没有用到 acorn, 用了 babel\n acorn: {\n ecmaVersion: 'latest',\n sourceType: 'module', // defaults to 'module'\n // Check out https://github.com/acornjs/acorn/tree/master/acorn#interface for additional options\n }\n },\n \n // 禁用 : 和 . 作为 seperator\n keySeparator: false, // char to separate keys\n nsSeparator: false, // char to split namespace from key\n \n // Context Form\n context: true, // whether to add context form key\n contextFallback: true, // whether to add a fallback key as well as the context form key\n contextSeparator: '_', // char to split context from key\n\n // Plural\n // whether to add plural form key\n plural (language: string, ns: string, key: string, options: any /** Config */) {\n return language === 'en'\n }, \n pluralFallback: true, // whether to add a fallback key as well as the plural form key\n pluralSeparator: '_', // char to split plural from key\n \n // interpolation options\n interpolation: {\n prefix: '{{', // prefix for interpolation\n suffix: '}}' // suffix for interpolation\n }\n}\n\nconst VALID_EXTENTIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.ejs'])\n\nexport type Config = Partial<(typeof DEFAULT_CONFIG) & {\n defaultValue?: string\n resource?: { loadPath?: string, savePath?: string, jsonIndent?: number, lineEnding?: '\\n' }\n}>\n\n\n/** 扫描源码中的词条,以及收集未翻译的词条。生成 scanneds.json 和 untranslateds.json\n* rootdir 要扫描根目录 [ process.cwd() ]\n* config 配置信息\n*/\nexport function scanner (rootdir: string = path.normalize(process.cwd()), config: Config = { }) {\n const output = path.resolve(rootdir, config.output || DEFAULT_CONFIG.output)\n const input = (config.input || DEFAULT_CONFIG.input).map( fp => path.resolve(rootdir, fp) )\n \n config = {\n ...DEFAULT_CONFIG,\n ...config,\n input,\n output,\n resource: {\n loadPath: '',\n savePath: path.resolve(output, 'translation/{{lng}}.js'),\n jsonIndent: 4,\n lineEnding: '\\n'\n }\n }\n \n \n let dict = config.dict.reduce( (dict, fp_dict) => \n dict.merge( try_require( path.resolve(output, fp_dict)), { print: false, overwrite: true }),\n new Dict())\n \n let c_files = 0\n let c_scanneds = 0\n let errors = []\n \n // 扫描出的词条及已有的翻译\n let scanneds: _Dict = { }\n \n // 所有语言的扫描统计信息\n let stats = Object.fromEntries(\n LANGUAGES.map( (language) => [language, { translateds: new Set<string>(), untranslateds: new Set<string>() }])\n )\n \n let spinner = ora({ interval: 66 }).start('Scanning...')\n \n \n \n function on_scanned (text: string, { language, key, defaultValue, count, context }: { language?: Language, key?: string, defaultValue?: string, count?: number, context?: string }) {\n // console.log(text, { language, key, defaultValue, count, context })\n \n text = text || defaultValue\n \n if (!key)\n key = context ? `${text}_${context}` : text\n \n if (!language) {\n for (const language of LANGUAGES)\n on_scanned(text, { language, key, count, context })\n return\n }\n \n // console.log(text, { language, key, defaultValue, count, context })\n // debugger\n \n const stat = stats[language]\n \n // 获取已有翻译\n const translation = \n dict.get(key, language) || \n language === 'zh' && text || \n ''\n \n if (language === 'zh' && !context) return\n \n scanneds[key] = {\n ... scanneds[key],\n [language]: translation\n }\n \n if (translation)\n stat.translateds.add(key)\n else\n stat.untranslateds.add(key)\n \n if (language === 'en' && count !== undefined)\n on_scanned(text, { language, key: `${key}_plural`, context })\n }\n \n \n function new_vinyl_file (_path: string, data: string | object) {\n return new Vinyl({\n cwd: rootdir,\n base: rootdir,\n path: path.resolve(config.output, _path),\n contents: Buffer.from(typeof data === 'string' ? data : JSON.stringify(data, null, 4))\n })\n }\n \n \n // ------------ scan by file\n vfs\n .src(config.input, { cwd: rootdir, sync: false })\n \n // 每个文件扫描前,统计文件数量\n .pipe(\n map( (file: Vinyl, cb: Function, count: number) => {\n // 支持 `// @i18n-noscan` 忽略扫描\n if (/\\/\\/\\s*@i18n-noscan\\s/.test(file.contents.toString())) return cb()\n c_files++\n cb(null, file)\n })\n )\n \n // 对文件进行排序,保证词条有一定的顺序\n .pipe( sort() )\n \n // 分析代码提取词条\n .pipe(\n i18n_scanner.createStream( config, function transform (this: { parser: any }, file: Vinyl, encoding: string, callback: Function): void {\n const { parser } = this\n const ext = path.extname(file.path)\n \n // 只扫描源码文件\n if (!VALID_EXTENTIONS.has(ext)) {\n callback()\n return\n }\n \n c_scanneds++\n const percent = Math.round( (100 * c_scanneds) / c_files )\n const text = `Scanning (${percent}%): ${file.path.green}`\n spinner.text = cli_truncate(text, process.stdout.columns - 5, { position: 'middle', })\n \n let code = file.contents.toString()\n \n if (ext === '.ejs')\n code = ejs.compile( code, { filename: file.path, client: true, legacyInclude: true } as any ).toString()\n \n \n // --- 添加代码中扫描到的 i18n.t('key') 中的 key 到 parser\n // parser.parseFuncFromString 使用 esprima 来解析代码,esprima 仍然不支持 optional chaining !!\n parser.parseFuncFromString(code.replace(/\\?\\.\\[/g, '[').replace(/\\?\\.\\(/g, '(').replace(/\\?\\./g, '.'), on_scanned)\n \n // --- 添加代码中扫描到的 Trans 组件中的 key 到 parser\n if (ext === '.jsx' || ext === '.tsx') {\n // parser.parseTransFromString 使用 acorn 解析代码,不支持 TypeScript,添加 parser.parseTransFromStringByBabel\n mix_parse_trans_from_string_by_babel(parser)\n parser.parseTransFromStringByBabel(\n code,\n { filepath: file.path },\n on_scanned,\n (error: Error) => { errors.push(error) }\n )\n }\n \n setTimeout(callback, 0)\n })\n )\n \n // 创建词条文件\n .pipe(\n through2.obj(\n /** i18n-scanner 会把扫描结果以每个语言一个文件的形式提供,这里解析扫描结果\n * file: 翻译 resource 文件,其中 file.contents 包含翻译的扫描结果\n */\n function write (this: Transform, file: Vinyl, encoding: string, cb: Function) { cb() },\n \n /** 生成 stats.json, unmarkeds.md; 打印 untranslated / unmarkeds */\n function flush (this: Transform, cb: Function) {\n // ------------ stats.json\n this.push(new_vinyl_file('stats.json', \n Object.fromEntries(\n Object.entries(stats).map( ([l, { translateds, untranslateds }]) => \n [l, { translateds: Array.from(translateds), untranslateds: Array.from(untranslateds) }])\n )\n ))\n \n \n // ------------ 打印 cli 统计表\n const table = new CliTable({\n head: [\n 'Language',\n 'Untranslated'.red,\n 'Translated'.green,\n ],\n colAligns: ['right', 'right', 'right', 'right'],\n style: { head: [] },\n chars: {\n top: '',\n 'top-mid': '',\n 'top-left': '',\n 'top-right': '',\n bottom: '',\n 'bottom-mid': '',\n 'bottom-left': '',\n 'bottom-right': '',\n left: '',\n 'left-mid': '',\n mid: '',\n 'mid-mid': '',\n right: '',\n 'right-mid': '',\n middle: ' ',\n },\n })\n \n Object.entries(stats).forEach( ([lang, stat]) => {\n table.push([\n lang, \n String(stat.untranslateds.size).red, \n String(stat.translateds.size).green\n ] as any)\n })\n \n \n \n spinner.stop()\n console.log(`Scanned ${c_files} files. Occured ${errors.length} errors.`)\n console.log(table.toString())\n \n \n // ------------ 生成 unmarkeds.md 统计\n /*\n const fp_unmarked = path.resolve(config.output, 'unmarkeds.md')\n \n if (fs.existsSync(fp_unmarked))\n rimraf.sync(fp_unmarked)\n \n if (unmarkeds.length) {\n console.log(colors.yellow(`\\n⚠️ 发现未标记的中文字符 ${unmarkeds.length} 处:\\n`))\n unmarkeds.forEach(({ value, filepath, loc: { start } }, index) => {\n if (index >= 5) return\n console.log( ` ${colors.white(`'${value}'`)}\\t${colors.blue.underline(`${path.relative(rootdir, filepath)}:${start.line}:${start.column + 1}`)}` )\n })\n }\n \n this.push( new_vinyl_file( fp_unmarked, \n unmarkeds.map( ({ value, filepath, loc }) =>\n '- [' + value.trim() + '](' + path.relative( config.output, path.resolve(rootdir, filepath || '') ) + '#L' + loc.start.line + ')'\n ).join('\\n') + '\\n'\n ))\n \n \n if (unmarkeds.length > 5) {\n console.log(' ...')\n console.log(colors.yellow(`\\n 完整未标记词条请查看 ${colors.blue.underline(path.relative(rootdir, fp_unmarked))}`))\n }\n */\n \n const en_untranslateds = stats.en.untranslateds\n if (en_untranslateds.size) {\n console.log('\\n未翻译的英文词条:'.yellow)\n Array.from(en_untranslateds).slice(0, 10).forEach( untranslated => {\n console.log(untranslated)\n })\n if (en_untranslateds.size > 10) {\n console.log('...')\n console.log(`--- 共 ${en_untranslateds.size} 个未翻译的英文词条 ---`)\n }\n } else\n console.log('\\n所有词条都至少含有英文翻译.'.green)\n \n \n // ------------ 生成 scanneds.json\n const fp_scanneds = path.resolve(config.output, 'scanneds.json')\n this.push(\n new_vinyl_file(fp_scanneds, scanneds)\n )\n \n // ------------ 写入 dict.json\n const fp_dict_new = path.resolve(output, 'dict.json')\n this.push( new_vinyl_file( fp_dict_new, dict.to_json(true) + '\\n' ))\n \n console.log(`\\n\\n${'⚠️ 请检查扫描结果'.yellow} ${fp_scanneds.underline.blue} ${'和新生成的词典文件'.yellow} ${fp_dict_new.underline.blue}`)\n console.log('\\n请手动补全扫描结果 scanneds.json 中未翻译的词条'.yellow)\n console.log('\\n')\n console.log('通过以上方法补充翻译后重新运行扫描,会根据 scanneds.json 更新 dict.json'.yellow)\n console.log('最后 dict.json 所包含的词条会被打包进 js, 通过 new I18N(<dict.json>) 或 i18n.init(<dict.json>) 加载'.yellow)\n console.log()\n console.log(`${'详细文档请查看:'.yellow} ${'https://github.com/ShenHongFei/xshell/tree/master/i18n'.blue.underline}`)\n \n cb()\n }\n )\n )\n \n // 写入词条文件\n .pipe(\n vfs.dest(rootdir)\n )\n \n .on('end', () => {\n errors.forEach( errorHandler => errorHandler() )\n if (!errors.length) return\n console.log(\n 'https://www.i18next.com/translation-function/essentials\\n以上错误可能是由不规范的词条标记导致,标记规范可见:%s',\n ''.blue.underline\n )\n })\n}\n\nexport default scanner\n"]}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mix_parse_trans_from_string_by_babel = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
|
+
const traverse_1 = (0, tslib_1.__importDefault)(require("@babel/traverse"));
|
|
7
|
+
const parser_1 = require("@babel/parser");
|
|
8
|
+
const t = (0, tslib_1.__importStar)(require("@babel/types"));
|
|
9
|
+
require("../../prototype.js");
|
|
10
|
+
// import { Checker } from './checker'
|
|
11
|
+
/** file:///D:/0/i18next-scanner/src/parser.js */
|
|
12
|
+
function mix_parse_trans_from_string_by_babel(parser) {
|
|
13
|
+
parser.parseTransFromStringByBabel = function (code, options = {}, customHandler = null, onError = () => { }) {
|
|
14
|
+
if ((0, lodash_1.isFunction)(options)) {
|
|
15
|
+
customHandler = options;
|
|
16
|
+
options = {};
|
|
17
|
+
}
|
|
18
|
+
const { transformOptions = {}, // object
|
|
19
|
+
component = this.options.trans.component, // string
|
|
20
|
+
i18nKey = this.options.trans.i18nKey, // string
|
|
21
|
+
defaultsKey = this.options.trans.defaultsKey, // string
|
|
22
|
+
fallbackKey = this.options.trans.fallbackKey, // boolean|function
|
|
23
|
+
babylon: babylon_options = this.options.trans.babylon, // object
|
|
24
|
+
filepath, } = options;
|
|
25
|
+
const parseJSXElement = ({ node }) => {
|
|
26
|
+
if (!node)
|
|
27
|
+
return;
|
|
28
|
+
if (node.openingElement.name.name !== component)
|
|
29
|
+
return;
|
|
30
|
+
const getLiteralValue = literal => {
|
|
31
|
+
if (t.isTemplateLiteral(literal))
|
|
32
|
+
return literal.quasis.map(element => element.value.cooked).join("");
|
|
33
|
+
return literal.value;
|
|
34
|
+
};
|
|
35
|
+
const attr = (0, lodash_1.castArray)(node.openingElement.attributes).reduce((acc, attribute) => {
|
|
36
|
+
if (!t.isJSXAttribute(attribute) ||
|
|
37
|
+
!t.isJSXIdentifier(attribute.name))
|
|
38
|
+
return acc;
|
|
39
|
+
const { name } = attribute.name;
|
|
40
|
+
const value = attribute.value;
|
|
41
|
+
if (t.isLiteral(value))
|
|
42
|
+
acc[name] = getLiteralValue(value);
|
|
43
|
+
else if (t.isJSXExpressionContainer(value)) {
|
|
44
|
+
const expression = value.expression;
|
|
45
|
+
if (t.isIdentifier(expression))
|
|
46
|
+
acc[name] = expression.name;
|
|
47
|
+
else if (t.isLiteral(expression))
|
|
48
|
+
acc[name] = getLiteralValue(expression);
|
|
49
|
+
else if (t.isObjectExpression(expression)) {
|
|
50
|
+
const properties = (0, lodash_1.castArray)(expression.properties);
|
|
51
|
+
acc[name] = properties.reduce((obj, property) => {
|
|
52
|
+
if (!t.isObjectProperty(property))
|
|
53
|
+
return obj;
|
|
54
|
+
if (t.isLiteral(property.value))
|
|
55
|
+
obj[property.key.name] = getLiteralValue(property.value);
|
|
56
|
+
else // Unable to get value of the property
|
|
57
|
+
obj[property.key.name] = "";
|
|
58
|
+
return obj;
|
|
59
|
+
}, {});
|
|
60
|
+
/**
|
|
61
|
+
* 防止 count 被忽略,如
|
|
62
|
+
* ```jsx
|
|
63
|
+
* <Trans count={arr.length}>
|
|
64
|
+
* 一二三{{ count: arr.length }}
|
|
65
|
+
* </Trans>
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
}
|
|
69
|
+
else if (name === "count")
|
|
70
|
+
acc[name] = 0;
|
|
71
|
+
}
|
|
72
|
+
return acc;
|
|
73
|
+
}, {});
|
|
74
|
+
const transKey = (0, lodash_1.trim)(attr[i18nKey]);
|
|
75
|
+
const defaultsString = attr[defaultsKey] || "";
|
|
76
|
+
if (typeof defaultsString !== "string")
|
|
77
|
+
this.log(`defaults value must be a static string, saw ${defaultsString.yellow}`);
|
|
78
|
+
// https://www.i18next.com/translation-function/essentials#overview-options
|
|
79
|
+
const tOptions = attr.tOptions;
|
|
80
|
+
const options = {
|
|
81
|
+
...tOptions,
|
|
82
|
+
defaultValue: defaultsString || nodes_to_string(node.children, filepath, onError),
|
|
83
|
+
fallbackKey,
|
|
84
|
+
};
|
|
85
|
+
if (Object.prototype.hasOwnProperty.call(attr, "count"))
|
|
86
|
+
options.count = Number(attr.count) || 0;
|
|
87
|
+
if (Object.prototype.hasOwnProperty.call(attr, "ns")) {
|
|
88
|
+
if (typeof options.ns !== "string")
|
|
89
|
+
this.log(`The ns attribute must be a string, saw ${attr.ns?.yellow}`);
|
|
90
|
+
options.ns = attr.ns;
|
|
91
|
+
}
|
|
92
|
+
if (customHandler) {
|
|
93
|
+
customHandler(transKey, options);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.set(transKey, options);
|
|
97
|
+
};
|
|
98
|
+
try {
|
|
99
|
+
const ast = (0, parser_1.parse)(code, { ...babylon_options });
|
|
100
|
+
(0, traverse_1.default)(ast, { JSXElement: parseJSXElement, });
|
|
101
|
+
// traverse(ast, Checker({ filepath }))
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
onError(() => {
|
|
105
|
+
console.error('');
|
|
106
|
+
const { line, column } = (err && err.loc) || { line: 1, column: 1 };
|
|
107
|
+
console.error([filepath, line, column].join(":").yellow);
|
|
108
|
+
console.error(`Unable to parse ${component?.blue} component.\n`.red);
|
|
109
|
+
if (!filepath)
|
|
110
|
+
console.error(String(code).red);
|
|
111
|
+
console.error((" " + err.message).red);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return this;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
exports.mix_parse_trans_from_string_by_babel = mix_parse_trans_from_string_by_babel;
|
|
118
|
+
function nodes_to_string(nodes, filepath, onError) {
|
|
119
|
+
let memo = '';
|
|
120
|
+
let nodeIndex = 0;
|
|
121
|
+
nodes.forEach((node, i) => {
|
|
122
|
+
if (t.isJSXText(node) || t.isStringLiteral(node)) {
|
|
123
|
+
const value = node.value
|
|
124
|
+
.replace(/^[\r\n]+\s*/g, "") // remove leading spaces containing a leading newline character
|
|
125
|
+
.replace(/[\r\n]+\s*$/g, "") // remove trailing spaces containing a leading newline character
|
|
126
|
+
.replace(/[\r\n]+\s*/g, " "); // replace spaces containing a leading newline character with a single space character
|
|
127
|
+
if (!value)
|
|
128
|
+
return;
|
|
129
|
+
memo += value;
|
|
130
|
+
}
|
|
131
|
+
else if (t.isJSXExpressionContainer(node)) {
|
|
132
|
+
const { expression = {} } = node;
|
|
133
|
+
if (t.isNumericLiteral(expression)) // Numeric literal is ignored in react-i18next
|
|
134
|
+
memo += '';
|
|
135
|
+
if (t.isStringLiteral(expression))
|
|
136
|
+
memo += expression.value;
|
|
137
|
+
else if (t.isObjectExpression(expression) &&
|
|
138
|
+
t.isObjectProperty((0, lodash_1.get)(expression, 'properties[0]')))
|
|
139
|
+
memo += '{{' + expression.properties[0].key.name + '}}';
|
|
140
|
+
else
|
|
141
|
+
onError(() => {
|
|
142
|
+
const { line, column } = (node.expression && node.expression.loc.start) || { line: 1, column: 1 };
|
|
143
|
+
console.error('');
|
|
144
|
+
console.error([filepath, line, column].join(":").yellow);
|
|
145
|
+
console.error('Unsupported JSX expression. Only static values or {{interpolation}} blocks are supported.'.red);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else if (node.children)
|
|
149
|
+
memo += `<${nodeIndex}>${nodes_to_string(node.children, filepath, onError)}</${nodeIndex}>`;
|
|
150
|
+
nodeIndex++;
|
|
151
|
+
});
|
|
152
|
+
return memo;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { isFunction, castArray, trim, get as _get } from 'lodash'\nimport traverse from '@babel/traverse'\nimport { parse } from '@babel/parser'\nimport * as t from '@babel/types'\n\nimport '../../prototype.js'\n\n// import { Checker } from './checker'\n\n/** file:///D:/0/i18next-scanner/src/parser.js */\nexport function mix_parse_trans_from_string_by_babel (parser) {\n parser.parseTransFromStringByBabel = function(code: string, options = { }, customHandler = null, onError: (callback: Function) => void = () => { } ) {\n if (isFunction(options)) {\n customHandler = options\n options = { }\n }\n \n const {\n transformOptions = { }, // object\n component = this.options.trans.component, // string\n i18nKey = this.options.trans.i18nKey, // string\n defaultsKey = this.options.trans.defaultsKey, // string\n fallbackKey = this.options.trans.fallbackKey, // boolean|function\n babylon: babylon_options = this.options.trans.babylon, // object\n filepath,\n } = options as any\n \n const parseJSXElement = ({ node }) => {\n if (!node) return\n \n if (node.openingElement.name.name !== component) return\n \n \n const getLiteralValue = literal => {\n if (t.isTemplateLiteral(literal))\n return literal.quasis.map(element => element.value.cooked).join(\"\")\n \n return literal.value\n }\n \n const attr = castArray(node.openingElement.attributes).reduce(\n (acc, attribute) => {\n if (\n !t.isJSXAttribute(attribute) ||\n !t.isJSXIdentifier(attribute.name)\n ) return acc\n \n const { name } = attribute.name\n const value = attribute.value\n if (t.isLiteral(value))\n acc[name] = getLiteralValue(value)\n else if (t.isJSXExpressionContainer(value)) {\n const expression = value.expression\n if (t.isIdentifier(expression))\n acc[name] = expression.name\n else if (t.isLiteral(expression))\n acc[name] = getLiteralValue(expression)\n else if (t.isObjectExpression(expression)) {\n const properties = castArray(expression.properties)\n acc[name] = properties.reduce((obj, property) => {\n if (!t.isObjectProperty(property)) return obj\n if (t.isLiteral(property.value))\n obj[(property.key as any).name] = getLiteralValue(property.value)\n else // Unable to get value of the property\n obj[(property.key as any).name] = \"\"\n return obj\n }, { })\n /**\n * 防止 count 被忽略,如\n * ```jsx\n * <Trans count={arr.length}>\n * 一二三{{ count: arr.length }}\n * </Trans>\n * ```\n */\n } else if (name === \"count\")\n acc[name] = 0\n }\n return acc\n },\n { }\n )\n const transKey = trim(attr[i18nKey])\n \n const defaultsString = attr[defaultsKey] || \"\"\n if (typeof defaultsString !== \"string\")\n this.log(`defaults value must be a static string, saw ${defaultsString.yellow}`)\n \n \n // https://www.i18next.com/translation-function/essentials#overview-options\n const tOptions = attr.tOptions\n const options = {\n ...tOptions,\n defaultValue: defaultsString || nodes_to_string(node.children, filepath, onError),\n fallbackKey,\n }\n \n if (Object.prototype.hasOwnProperty.call(attr, \"count\"))\n options.count = Number(attr.count) || 0\n \n \n if (Object.prototype.hasOwnProperty.call(attr, \"ns\")) {\n if (typeof options.ns !== \"string\")\n this.log(`The ns attribute must be a string, saw ${attr.ns?.yellow}`)\n \n options.ns = attr.ns\n }\n \n if (customHandler) {\n customHandler(transKey, options)\n return\n }\n \n this.set(transKey, options)\n }\n \n try {\n const ast = parse(code, { ...babylon_options })\n traverse(ast, { JSXElement: parseJSXElement, })\n // traverse(ast, Checker({ filepath }))\n } catch (err) {\n onError(() => {\n console.error('')\n const { line, column } = (err && err.loc) || { line: 1, column: 1 }\n console.error([filepath, line, column].join(\":\").yellow)\n console.error(`Unable to parse ${component?.blue} component.\\n`.red)\n if (!filepath)\n console.error(String(code).red)\n console.error((\" \" + err.message).red)\n })\n }\n \n return this\n }\n}\n\n\nfunction nodes_to_string (nodes, filepath, onError) {\n let memo = ''\n let nodeIndex = 0\n nodes.forEach((node, i) => {\n if (t.isJSXText(node) || t.isStringLiteral(node)) {\n const value = node.value\n .replace(/^[\\r\\n]+\\s*/g, \"\") // remove leading spaces containing a leading newline character\n .replace(/[\\r\\n]+\\s*$/g, \"\") // remove trailing spaces containing a leading newline character\n .replace(/[\\r\\n]+\\s*/g, \" \") // replace spaces containing a leading newline character with a single space character\n \n if (!value) return\n \n memo += value\n } else if (t.isJSXExpressionContainer(node)) {\n const { expression = { } } = node\n \n if (t.isNumericLiteral(expression)) // Numeric literal is ignored in react-i18next\n memo += ''\n if (t.isStringLiteral(expression))\n memo += expression.value\n else if (\n t.isObjectExpression(expression) &&\n t.isObjectProperty(_get(expression, 'properties[0]'))\n )\n memo += '{{' + (expression.properties[0] as any).key.name + '}}'\n else\n onError(() => {\n const { line, column } = (node.expression && node.expression.loc.start) || { line: 1, column: 1 }\n console.error('')\n console.error([filepath, line, column].join(\":\").yellow)\n console.error('Unsupported JSX expression. Only static values or {{interpolation}} blocks are supported.'.red)\n })\n \n } else if (node.children)\n memo += `<${nodeIndex}>${nodes_to_string(node.children, filepath, onError)}</${nodeIndex}>`\n \n \n nodeIndex++\n })\n \n return memo\n}\n\n"]}
|
package/i18n/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function try_require(modpath: string): any;
|
package/i18n/utils.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.try_require = void 0;
|
|
4
|
+
function try_require(modpath) {
|
|
5
|
+
try {
|
|
6
|
+
return require(modpath);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
// console.error('未找到或解析错误,跳过加载:' + modpath)
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.try_require = try_require;
|
|
14
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":";;;AAAA,SAAgB,WAAW,CAAE,OAAe;IACxC,IAAI;QACA,OAAO,OAAO,CAAC,OAAO,CAAC,CAAA;KAC1B;IAAC,MAAM;QACJ,4CAA4C;QAC5C,OAAO,EAAG,CAAA;KACb;AACL,CAAC;AAPD,kCAOC","sourcesContent":["export function try_require (modpath: string) {\n try {\n return require(modpath)\n } catch {\n // console.error('未找到或解析错误,跳过加载:' + modpath)\n return { }\n }\n}\n"]}
|
package/net.browser.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface RequestOptions {
|
|
2
|
+
method?: 'get' | 'post' | 'put' | 'head' | 'delete' | 'patch';
|
|
3
|
+
queries?: Record<string, any>;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
body?: string | object | HTMLFormElement;
|
|
6
|
+
type?: 'application/json' | 'application/x-www-form-urlencoded' | 'multipart/form-data';
|
|
7
|
+
cors?: boolean;
|
|
8
|
+
by?: 'fetch' | 'GM_xmlhttpRequest';
|
|
9
|
+
}
|
|
10
|
+
export interface RequestRawOptions extends RequestOptions {
|
|
11
|
+
raw: true;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
- url: 可以只有 pathname 部分
|
|
15
|
+
- options:
|
|
16
|
+
- type: `'application/json'` 请求的 content-type 头 (如果有 body)
|
|
17
|
+
- by: `window.GM_xmlhttpRequest ? 'GM_xmlhttpRequest' : 'fetch'` 发起请求所使用的底层方法
|
|
18
|
+
*/
|
|
19
|
+
export declare function request(url: string | URL): Promise<string>;
|
|
20
|
+
export declare function request(url: string | URL, options: RequestRawOptions): Promise<Response>;
|
|
21
|
+
export declare function request(url: string | URL, options: RequestOptions): Promise<string>;
|
|
22
|
+
/** 发起 http 请求并将响应体作为 json 解析 */
|
|
23
|
+
export declare function request_json<T = any>(url: string, options?: RequestOptions): Promise<T>;
|