scancscode 1.0.42 → 1.0.46

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.
@@ -1,261 +1,333 @@
1
- import * as crypto from "crypto";
2
- import * as https from "https";
3
- import { CSVUtils } from "./CSVUtils";
4
-
5
- interface NiuTransResponse {
6
- tgtList: Array<{
7
- from: string;
8
- to: string;
9
- tgtText: string;
10
- srcText?: string;
11
- errorCode?: string;
12
- errorMsg?: string;
13
- }>;
14
- resultCode: string;
15
- resultMsg: string;
16
- }
17
-
18
- export class CsvAutoTranslator {
19
- private apiKey: string;
20
- private appId: string;
21
- private apiUrl: string = "https://api.niutrans.com/v2/text/translate/array";
22
- private maxBatchSize: number = 5;
23
- private readonly MAX_BATCH_TEXT_COUNT: number = 50;
24
- private readonly MAX_BATCH_JSON_SIZE: number = 4900;
25
-
26
- constructor(apiKey: string, appId: string) {
27
- this.apiKey = apiKey;
28
- this.appId = appId;
29
- }
30
-
31
- private generateAuthStr(params: Record<string, string>): string {
32
- const sortedKeys = Object.keys(params).sort();
33
- const paramStr = sortedKeys
34
- .filter(key => params[key] !== "" && params[key] !== undefined && params[key] !== null)
35
- .map(key => `${key}=${params[key]}`)
36
- .join("&");
37
- const fullStr = `apikey=${this.apiKey}&${paramStr}`;
38
- return crypto.createHash("md5").update(fullStr).digest("hex");
39
- }
40
-
41
- private async requestTranslate(texts: string[], from: string, to: string): Promise<NiuTransResponse> {
42
- const timestamp = Date.now().toString();
43
- const params: Record<string, string> = {
44
- from: from,
45
- to: to,
46
- appId: this.appId,
47
- timestamp: timestamp
48
- };
49
- const authStr = this.generateAuthStr(params);
50
- const postData = JSON.stringify({
51
- ...params,
52
- srcText: texts,
53
- authStr: authStr
54
- });
55
- const url = new URL(this.apiUrl);
56
- const options: https.RequestOptions = {
57
- hostname: url.hostname,
58
- port: 443,
59
- path: url.pathname,
60
- method: "POST",
61
- headers: {
62
- "Content-Type": "application/json",
63
- "Content-Length": Buffer.byteLength(postData)
64
- }
65
- };
66
- return new Promise((resolve, reject) => {
67
- const req = https.request(options, (res) => {
68
- let data = "";
69
- res.on("data", (chunk) => {
70
- data += chunk;
71
- });
72
- res.on("end", async () => {
73
- try {
74
- let ret = JSON.parse(data);
75
- await res.destroy();
76
- resolve(ret);
77
- } catch (e) {
78
- reject(e);
79
- }
80
- });
81
- });
82
- req.on("error", reject);
83
- req.write(postData);
84
- req.end();
85
- });
86
- }
87
-
88
- private async translateBatch(texts: string[], from: string, to: string): Promise<string[]> {
89
- const response = await this.requestTranslate(texts, from, to);
90
- if (response.resultCode !== "200") {
91
- throw new Error(`翻译失败: ${response.resultMsg}`);
92
- }
93
- return response.tgtList.map(item => item.tgtText || "");
94
- }
95
-
96
- private estimateSingleTextJsonSize(text: string, isSingle: boolean): number {
97
- return Buffer.byteLength(JSON.stringify(text)) + (isSingle ? 0 : 1);
98
- }
99
-
100
- estimateJsonSize(texts: string[]): number {
101
- return Buffer.byteLength(JSON.stringify(texts));
102
- }
103
-
104
- smartBatch(texts: string[], batches?: string[][]): string[][] {
105
- const resultBatches = batches || [];
106
- let startIndex = 0;
107
- while (startIndex < texts.length) {
108
- let endIndexMax = Math.min(startIndex + this.MAX_BATCH_TEXT_COUNT, texts.length);
109
- let batchByteLength = 2;
110
- let currentBatchCount = 0;
111
- // let currentBatch = texts.slice(startIndex, endIndexMax);
112
- for (let i = startIndex; i < endIndexMax; i++) {
113
- const text = texts[i];
114
- const textSize = Buffer.byteLength(text) + (i >= 1 ? 1 : 0);
115
- currentBatchCount++;
116
- batchByteLength += textSize;
117
- if (batchByteLength + textSize > this.MAX_BATCH_JSON_SIZE) {
118
- break;
119
- }
120
- }
121
- let endIndex = startIndex + currentBatchCount;
122
- let currentBatch: string[] = texts.slice(startIndex, endIndex);
123
- let currentSize = this.estimateJsonSize(currentBatch);
124
- while (currentSize > this.MAX_BATCH_JSON_SIZE && currentBatch.length > 0) {
125
- endIndex--;
126
- let endText = texts[endIndex];
127
- let endTextSize = this.estimateSingleTextJsonSize(endText, endIndex > startIndex + 1);
128
- currentSize -= endTextSize;
129
- currentBatch.pop();
130
- }
131
- if (currentBatch.length == 0 && startIndex < endIndexMax) {
132
- console.error(`无法将文本分成合适的批次, 存在过长的文本, 起始索引: ${startIndex}, 结束索引: ${endIndex}`);
133
- currentBatch = ['']
134
- endIndex = startIndex + 1;
135
- }
136
- resultBatches.push(currentBatch);
137
- startIndex = endIndex;
138
- }
139
- return resultBatches;
140
- }
141
-
142
- private async translateAll(texts: string[], from: string, to: string): Promise<string[]> {
143
- const batches = this.smartBatch(texts);
144
- const results: string[][] = new Array(batches.length);
145
- const concurrencyLimit = this.maxBatchSize;
146
- let index = 0;
147
-
148
- let batchCount = 0;
149
- const processBatch = async (): Promise<void> => {
150
- while (index < batches.length) {
151
- const batchIndex = index++;
152
- const batch = batches[batchIndex];
153
- batchCount++;
154
- console.log(`batchCount++: ${batchCount}`)
155
- const batchResults = await this.translateBatch(batch, from, to);
156
- await new Promise(resolve => setTimeout(resolve, 1000));
157
- batchCount--;
158
- console.log(`batchCount--: ${batchCount}`)
159
- results[batchIndex] = batchResults;
160
- }
161
- };
162
-
163
- const workers: Promise<void>[] = [];
164
- for (let i = 0; i < concurrencyLimit && i < batches.length; i++) {
165
- workers.push(processBatch());
166
- }
167
- await Promise.all(workers);
168
- // await processBatch()
169
-
170
- return results.flat();
171
- }
172
-
173
- langMap: Map<string, string> = new Map([
174
- ["zh_cn", "zh"],
175
- ["zh_hk", "cht"],
176
- ["en_us", "en"],
177
- ])
178
- async translateCsvRows(rows: string[][], fromLang: string, toLangs?: string[]): Promise<number> {
179
- if (rows.length === 0) {
180
- console.log("CSV文件为空");
181
- return 0;
182
- }
183
- let header = rows[0];
184
- let fromLangIndex = header.indexOf(fromLang);
185
- if (fromLangIndex === -1) {
186
- console.error(`未找到 ${fromLang} 列`);
187
- return 0;
188
- }
189
- if (!this.langMap.has(fromLang)) {
190
- console.error(`未找到 ${fromLang} 的目标语言`);
191
- return 0;
192
- }
193
- let fromLang2 = this.langMap.get(fromLang);
194
- if (fromLang2 == null) {
195
- console.error(`未找到 ${fromLang} 的目标语言`);
196
- return 0;
197
- }
198
- const needTranslateIndices: number[] = [];
199
- const needTranslateTexts: string[] = [];
200
- for (let i = 1; i < rows.length; i++) {
201
- const row = rows[i];
202
- if (!row[0] || row[0].trim() === "") {
203
- continue;
204
- }
205
- if (row[fromLangIndex] && row[fromLangIndex].trim() !== "") {
206
- continue;
207
- }
208
- needTranslateIndices.push(i);
209
- let text = row[fromLangIndex]
210
- if (text == null || text == "") {
211
- text = row[0];
212
- }
213
- needTranslateTexts.push(text);
214
- }
215
- if (needTranslateTexts.length === 0) {
216
- console.log("没有需要翻译的内容");
217
- return 0;
218
- }
219
- console.log(`开始翻译 ${needTranslateTexts.length} 条内容...`);
220
- for (let curLangIndex = 0; curLangIndex < header.length; curLangIndex++) {
221
- let lang = header[curLangIndex];
222
- lang = lang.trim().toLowerCase();
223
- if (lang == "key") {
224
- continue;
225
- }
226
- if (toLangs != undefined && !toLangs.includes(lang)) {
227
- continue;
228
- }
229
- if (lang != fromLang && this.langMap.has(lang)) {
230
- const toLang = this.langMap.get(lang);
231
- if (toLang == null) {
232
- console.error(`未找到 ${lang} 的目标语言`);
233
- continue;
234
- }
235
- const translations = await this.translateAll(needTranslateTexts, fromLang2, toLang);
236
- for (let j = 0; j < needTranslateIndices.length; j++) {
237
- const rowIndex = needTranslateIndices[j];
238
- while (rows[rowIndex].length < header.length) {
239
- rows[rowIndex].push("");
240
- }
241
- rows[rowIndex][curLangIndex] = translations[j];
242
- }
243
- }
244
- }
245
- return needTranslateTexts.length;
246
- }
247
- async translateCsv(filePath: string, outFilePath: string, fromLang: string = "auto", toLangs?: string[]): Promise<void> {
248
- const csvUtils = new CSVUtils(filePath);
249
- const rows = await csvUtils.parseCsv();
250
- const translatedCount = await this.translateCsvRows(rows, fromLang, toLangs);
251
- if (translatedCount > 0) {
252
- await CSVUtils.writeCsv(outFilePath, rows);
253
- console.log(`翻译完成,已更新 ${translatedCount} 条内容到 ${outFilePath}`);
254
- }
255
- }
256
-
257
- public static async translateCsvWithLangs(filePath: string, outFilePath: string, fromLang: string, langs: string[], apiKey: string, appId: string) {
258
- const translator = new CsvAutoTranslator(apiKey, appId);
259
- await translator.translateCsv(filePath, outFilePath, fromLang, langs);
260
- }
261
- }
1
+ import * as crypto from "crypto";
2
+ import * as https from "https";
3
+ import { CSVUtils } from "./CSVUtils";
4
+
5
+ interface NiuTransResponse {
6
+ tgtList: Array<{
7
+ from: string;
8
+ to: string;
9
+ tgtText: string;
10
+ srcText?: string;
11
+ errorCode?: string;
12
+ errorMsg?: string;
13
+ }>;
14
+ resultCode: string;
15
+ resultMsg: string;
16
+ errorCode: string;
17
+ errorMsg: string;
18
+ }
19
+
20
+ class OnlineTranslateResult {
21
+ public errorCode: string = "";
22
+ public errorMsg: string = "";
23
+ public isOk: boolean = false;
24
+ public translatedTexts: string[];
25
+
26
+ public constructor(errorCode: string, errorMsg: string, isOk: boolean, translatedTexts: string[]) {
27
+ this.errorCode = errorCode;
28
+ this.errorMsg = errorMsg;
29
+ this.isOk = isOk;
30
+ this.translatedTexts = translatedTexts;
31
+ }
32
+ }
33
+
34
+ class TranslateCSVResult {
35
+ public translateCount: number = 0;
36
+ public isOk: boolean = false;
37
+ public firstErrorCode: string = "";
38
+ public firstErrorMsg: string = "";
39
+
40
+ public constructor(translateCount: number, isOk: boolean, firstErrorCode: string, firstErrorMsg: string) {
41
+ this.translateCount = translateCount;
42
+ this.isOk = isOk;
43
+ this.firstErrorCode = firstErrorCode;
44
+ this.firstErrorMsg = firstErrorMsg;
45
+ }
46
+
47
+ public static Empty: TranslateCSVResult = new TranslateCSVResult(0, false, "", "");
48
+ }
49
+
50
+ export class CsvAutoTranslator {
51
+ private apiKey: string;
52
+ private appId: string;
53
+ private apiUrl: string = "https://api.niutrans.com/v2/text/translate/array";
54
+ private maxBatchSize: number = 5;
55
+ private readonly MAX_BATCH_TEXT_COUNT: number = 50;
56
+ private readonly MAX_BATCH_JSON_SIZE: number = 4900;
57
+
58
+ constructor(appId: string, apiKey: string) {
59
+ this.apiKey = apiKey;
60
+ this.appId = appId;
61
+ }
62
+
63
+ private generateAuthStr(params: Record<string, string>): string {
64
+ const sortedKeys = Object.keys(params).sort();
65
+ const paramStr = sortedKeys
66
+ .filter(key => params[key] !== "" && params[key] !== undefined && params[key] !== null)
67
+ .map(key => `${key}=${params[key]}`)
68
+ .join("&");
69
+ const fullStr = `apikey=${this.apiKey}&${paramStr}`;
70
+ return crypto.createHash("md5").update(fullStr).digest("hex");
71
+ }
72
+
73
+ private async requestTranslate(texts: string[], from: string, to: string): Promise<NiuTransResponse> {
74
+ const timestamp = Date.now().toString();
75
+ const params: Record<string, string> = {
76
+ from: from,
77
+ to: to,
78
+ appId: this.appId,
79
+ timestamp: timestamp
80
+ };
81
+ const authStr = this.generateAuthStr(params);
82
+ const postData = JSON.stringify({
83
+ ...params,
84
+ srcText: texts,
85
+ authStr: authStr
86
+ });
87
+ const url = new URL(this.apiUrl);
88
+ const options: https.RequestOptions = {
89
+ hostname: url.hostname,
90
+ port: 443,
91
+ path: url.pathname,
92
+ method: "POST",
93
+ headers: {
94
+ "Content-Type": "application/json",
95
+ "Content-Length": Buffer.byteLength(postData)
96
+ }
97
+ };
98
+ return new Promise((resolve, reject) => {
99
+ const req = https.request(options, (res) => {
100
+ let data = "";
101
+ res.on("data", (chunk) => {
102
+ data += chunk;
103
+ });
104
+ res.on("end", async () => {
105
+ try {
106
+ let ret = JSON.parse(data);
107
+ await res.destroy();
108
+ resolve(ret);
109
+ } catch (e) {
110
+ reject(e);
111
+ }
112
+ });
113
+ });
114
+ req.on("error", reject);
115
+ req.write(postData);
116
+ req.end();
117
+ });
118
+ }
119
+
120
+ private async translateBatch(texts: string[], from: string, to: string): Promise<OnlineTranslateResult> {
121
+ const response = await this.requestTranslate(texts, from, to);
122
+ if (response.resultCode !== "200") {
123
+ let errTip = `翻译失败: ${response.errorCode}, ${response.errorMsg}, ${response.resultCode}, ${response.resultMsg}`;
124
+ console.error(errTip);
125
+ console.error("翻译失败内容:", texts);
126
+ let result = new OnlineTranslateResult(response.errorCode, response.errorMsg, false, new Array(texts.length).fill(""));
127
+ return result;
128
+ }
129
+ let result = new OnlineTranslateResult(response.resultCode, response.resultMsg, true, response.tgtList.map(item => item.tgtText || ""));
130
+ return result;
131
+ }
132
+
133
+ private estimateSingleTextJsonSize(text: string, isSingle: boolean): number {
134
+ return Buffer.byteLength(JSON.stringify(text)) + (isSingle ? 0 : 1);
135
+ }
136
+
137
+ estimateJsonSize(texts: string[]): number {
138
+ return Buffer.byteLength(JSON.stringify(texts));
139
+ }
140
+
141
+ smartBatch(texts: string[], batches?: string[][]): string[][] {
142
+ const resultBatches = batches || [];
143
+ let startIndex = 0;
144
+ while (startIndex < texts.length) {
145
+ let endIndexMax = Math.min(startIndex + this.MAX_BATCH_TEXT_COUNT, texts.length);
146
+ let batchByteLength = 2;
147
+ let currentBatchCount = 0;
148
+ // let currentBatch = texts.slice(startIndex, endIndexMax);
149
+ for (let i = startIndex; i < endIndexMax; i++) {
150
+ const text = texts[i];
151
+ const textSize = Buffer.byteLength(text) + (i >= 1 ? 1 : 0);
152
+ currentBatchCount++;
153
+ batchByteLength += textSize;
154
+ if (batchByteLength + textSize > this.MAX_BATCH_JSON_SIZE) {
155
+ break;
156
+ }
157
+ }
158
+ let endIndex = startIndex + currentBatchCount;
159
+ let currentBatch: string[] = texts.slice(startIndex, endIndex);
160
+ let currentSize = this.estimateJsonSize(currentBatch);
161
+ while (currentSize > this.MAX_BATCH_JSON_SIZE && currentBatch.length > 0) {
162
+ endIndex--;
163
+ let endText = texts[endIndex];
164
+ let endTextSize = this.estimateSingleTextJsonSize(endText, endIndex > startIndex + 1);
165
+ currentSize -= endTextSize;
166
+ currentBatch.pop();
167
+ }
168
+ if (currentBatch.length == 0 && startIndex < endIndexMax) {
169
+ console.error(`无法将文本分成合适的批次, 存在过长的文本, 起始索引: ${startIndex}, 结束索引: ${endIndex}`);
170
+ currentBatch = ['']
171
+ endIndex = startIndex + 1;
172
+ }
173
+ resultBatches.push(currentBatch);
174
+ startIndex = endIndex;
175
+ }
176
+ return resultBatches;
177
+ }
178
+
179
+ private async translateAll(texts: string[], from: string, to: string): Promise<OnlineTranslateResult> {
180
+ const batches = this.smartBatch(texts);
181
+ const results: string[][] = new Array(batches.length);
182
+ const concurrencyLimit = this.maxBatchSize;
183
+ let index = 0;
184
+ let isOk = true;
185
+ let batchCount = 0;
186
+ let firstErrorCode = "";
187
+ let firstErrorMsg = "";
188
+ const processBatch = async (): Promise<void> => {
189
+ while (index < batches.length) {
190
+ const batchIndex = index++;
191
+ const batch = batches[batchIndex];
192
+ batchCount++;
193
+ console.log(`batchCount++: ${batchCount}`)
194
+ const batchResult = await this.translateBatch(batch, from, to);
195
+ if (!batchResult.isOk) {
196
+ isOk = false;
197
+ if (firstErrorCode === "") {
198
+ firstErrorCode = batchResult.errorCode;
199
+ firstErrorMsg = batchResult.errorMsg;
200
+ }
201
+ }
202
+ await new Promise(resolve => setTimeout(resolve, 1000));
203
+ batchCount--;
204
+ console.log(`batchCount--: ${batchCount}`)
205
+ results[batchIndex] = batchResult.translatedTexts;
206
+ }
207
+ };
208
+
209
+ const workers: Promise<void>[] = [];
210
+ for (let i = 0; i < concurrencyLimit && i < batches.length; i++) {
211
+ workers.push(processBatch());
212
+ }
213
+ await Promise.all(workers);
214
+ // await processBatch()
215
+
216
+ let translatedTexts = results.flat();
217
+ let result = new OnlineTranslateResult(firstErrorCode, firstErrorMsg, isOk, translatedTexts);
218
+ return result;
219
+ }
220
+
221
+ langMap: Map<string, string> = new Map([
222
+ ["zh_cn", "zh"],
223
+ ["zh_hk", "cht"],
224
+ ["en_us", "en"],
225
+ ])
226
+ async translateCsvRows(rows: string[][], fromLang: string, toLangs?: string[]): Promise<TranslateCSVResult> {
227
+ if (rows.length === 0) {
228
+ console.log("CSV文件为空");
229
+ return TranslateCSVResult.Empty;
230
+ }
231
+ let header = rows[0];
232
+ let fromLangIndex = header.indexOf(fromLang);
233
+ if (fromLangIndex === -1) {
234
+ console.error(`未找到 ${fromLang} 列`);
235
+ return TranslateCSVResult.Empty;
236
+ }
237
+ if (!this.langMap.has(fromLang)) {
238
+ console.error(`未找到 ${fromLang} 的目标语言`);
239
+ return TranslateCSVResult.Empty;
240
+ }
241
+ let fromLang2 = this.langMap.get(fromLang);
242
+ if (fromLang2 == null) {
243
+ console.error(`未找到 ${fromLang} 的目标语言`);
244
+ return TranslateCSVResult.Empty;
245
+ }
246
+ let isOk = true;
247
+ let translateCount = 0;
248
+ let firstErrorCode = "";
249
+ let firstErrorMsg = "";
250
+ for (let curLangIndex = 0; curLangIndex < header.length; curLangIndex++) {
251
+ let lang = header[curLangIndex];
252
+ lang = lang.trim().toLowerCase();
253
+ if (lang == "key") {
254
+ continue;
255
+ }
256
+ if (toLangs != undefined && !toLangs.includes(lang)) {
257
+ continue;
258
+ }
259
+ if (!(lang != fromLang && this.langMap.has(lang))) {
260
+ continue;
261
+ }
262
+ const needTranslateIndices: number[] = [];
263
+ const needTranslateTexts: string[] = [];
264
+ for (let i = 1; i < rows.length; i++) {
265
+ const row = rows[i];
266
+ if (!row[0] || row[0].trim() === "") {
267
+ continue;
268
+ }
269
+ if (row[curLangIndex] && row[curLangIndex].trim() !== "") {
270
+ continue;
271
+ }
272
+ let text = row[fromLangIndex]
273
+ if (text == null || text == "") {
274
+ text = row[0];
275
+ }
276
+ if (text == null || text === "") {
277
+ continue;
278
+ }
279
+ needTranslateIndices.push(i);
280
+ needTranslateTexts.push(text);
281
+ }
282
+ if (needTranslateTexts.length === 0) {
283
+ console.log("没有需要翻译的内容");
284
+ return TranslateCSVResult.Empty;
285
+ }
286
+ console.log(`开始翻译 ${needTranslateTexts.length} 条内容...`);
287
+ const toLang = this.langMap.get(lang);
288
+ if (toLang == null) {
289
+ console.error(`未找到 ${lang} 的目标语言`);
290
+ continue;
291
+ }
292
+ const translateResult = await this.translateAll(needTranslateTexts, fromLang2, toLang);
293
+ isOk = isOk && translateResult.isOk;
294
+ if (!translateResult.isOk) {
295
+ if (firstErrorCode === "") {
296
+ firstErrorCode = translateResult.errorCode;
297
+ firstErrorMsg = translateResult.errorMsg;
298
+ }
299
+ console.error(`翻译 ${lang} 失败: ${translateResult.errorCode} ${translateResult.errorMsg}`);
300
+ continue;
301
+ }
302
+ let translations = translateResult.translatedTexts;
303
+ for (let j = 0; j < needTranslateIndices.length; j++) {
304
+ const rowIndex = needTranslateIndices[j];
305
+ while (rows[rowIndex].length < header.length) {
306
+ rows[rowIndex].push("");
307
+ }
308
+ rows[rowIndex][curLangIndex] = translations[j];
309
+ }
310
+ translateCount += needTranslateTexts.length;
311
+ }
312
+ let result = new TranslateCSVResult(translateCount, isOk, firstErrorCode, firstErrorMsg);
313
+ return result;
314
+ }
315
+ async translateCsv(filePath: string, outFilePath: string, fromLang: string = "auto", toLangs?: string[]): Promise<TranslateCSVResult> {
316
+ const csvUtils = new CSVUtils(filePath);
317
+ const rows = await csvUtils.parseCsv();
318
+ const translatedResult = await this.translateCsvRows(rows, fromLang, toLangs);
319
+ if (translatedResult.isOk && translatedResult.translateCount > 0) {
320
+ await CSVUtils.writeCsv(outFilePath, rows);
321
+ console.log(`翻译完成,已更新 ${translatedResult.translateCount} 条内容到 ${outFilePath}`);
322
+ } else {
323
+ console.log(`翻译完成,未更新任何内容到 ${outFilePath}`);
324
+ }
325
+ return translatedResult;
326
+ }
327
+
328
+ public static async translateCsvWithLangs(appId: string, apiKey: string, filePath: string, outFilePath: string, fromLang: string, langs?: string[]) {
329
+ const translator = new CsvAutoTranslator(appId, apiKey);
330
+ let result = await translator.translateCsv(filePath, outFilePath, fromLang, langs);
331
+ return result;
332
+ }
333
+ }
package/src/RunConvert.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { CmdExecutor } from "./CmdExecutor";
2
-
3
- CmdExecutor.runConvertWithCmdOptions()
1
+ import { CmdExecutor } from "./CmdExecutor";
2
+
3
+ CmdExecutor.runConvertWithCmdOptions()
@@ -1,3 +1,3 @@
1
- import { CmdExecutor } from "./CmdExecutor";
2
-
3
- CmdExecutor.runSlimCsvWithLangs()
1
+ import { CmdExecutor } from "./CmdExecutor";
2
+
3
+ CmdExecutor.runSlimCsvWithLangs()
@@ -1,3 +1,3 @@
1
- import { CmdExecutor } from "./CmdExecutor";
2
-
3
- CmdExecutor.runTranslateCsvWithCmdOptions()
1
+ import { CmdExecutor } from "./CmdExecutor";
2
+
3
+ CmdExecutor.runTranslateCsvWithCmdOptions()