i18ntk 1.10.1 ā 2.0.2
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/LICENSE +1 -1
- package/README.md +141 -1185
- package/main/i18ntk-analyze.js +149 -133
- package/main/i18ntk-backup-class.js +420 -0
- package/main/i18ntk-backup.js +4 -4
- package/main/i18ntk-complete.js +90 -65
- package/main/i18ntk-doctor.js +123 -103
- package/main/i18ntk-fixer.js +61 -725
- package/main/i18ntk-go.js +14 -15
- package/main/i18ntk-init.js +76 -25
- package/main/i18ntk-java.js +27 -32
- package/main/i18ntk-js.js +70 -68
- package/main/i18ntk-manage.js +128 -29
- package/main/i18ntk-php.js +75 -75
- package/main/i18ntk-py.js +55 -56
- package/main/i18ntk-scanner.js +59 -57
- package/main/i18ntk-setup.js +10 -396
- package/main/i18ntk-sizing.js +46 -40
- package/main/i18ntk-summary.js +21 -18
- package/main/i18ntk-ui.js +11 -10
- package/main/i18ntk-usage.js +55 -19
- package/main/i18ntk-validate.js +13 -13
- package/main/manage/commands/AnalyzeCommand.js +1124 -0
- package/main/manage/commands/BackupCommand.js +62 -0
- package/main/manage/commands/CommandRouter.js +295 -0
- package/main/manage/commands/CompleteCommand.js +61 -0
- package/main/manage/commands/DoctorCommand.js +60 -0
- package/main/manage/commands/FixerCommand.js +624 -0
- package/main/manage/commands/InitCommand.js +62 -0
- package/main/manage/commands/ScannerCommand.js +654 -0
- package/main/manage/commands/SizingCommand.js +60 -0
- package/main/manage/commands/SummaryCommand.js +61 -0
- package/main/manage/commands/UsageCommand.js +60 -0
- package/main/manage/commands/ValidateCommand.js +978 -0
- package/main/manage/index-fixed.js +1447 -0
- package/main/manage/index.js +1462 -0
- package/main/manage/managers/DebugMenu.js +140 -0
- package/main/manage/managers/InteractiveMenu.js +177 -0
- package/main/manage/managers/LanguageMenu.js +62 -0
- package/main/manage/managers/SettingsMenu.js +53 -0
- package/main/manage/services/AuthenticationService.js +263 -0
- package/main/manage/services/ConfigurationService-fixed.js +449 -0
- package/main/manage/services/ConfigurationService.js +449 -0
- package/main/manage/services/FileManagementService.js +368 -0
- package/main/manage/services/FrameworkDetectionService.js +458 -0
- package/main/manage/services/InitService.js +1051 -0
- package/main/manage/services/SetupService.js +462 -0
- package/main/manage/services/SummaryService.js +450 -0
- package/main/manage/services/UsageService.js +1502 -0
- package/package.json +32 -30
- package/runtime/enhanced.d.ts +221 -221
- package/runtime/index.d.ts +29 -29
- package/runtime/index.full.d.ts +331 -331
- package/runtime/index.js +7 -6
- package/scripts/build-lite.js +17 -17
- package/scripts/deprecate-versions.js +23 -6
- package/scripts/export-translations.js +5 -5
- package/scripts/fix-all-i18n.js +3 -3
- package/scripts/fix-and-purify-i18n.js +3 -2
- package/scripts/fix-locale-control-chars.js +110 -0
- package/scripts/lint-locales.js +80 -0
- package/scripts/locale-optimizer.js +8 -8
- package/scripts/prepublish.js +21 -21
- package/scripts/security-check.js +13 -5
- package/scripts/sync-translations.js +4 -4
- package/scripts/sync-ui-locales.js +9 -8
- package/scripts/validate-all-translations.js +8 -7
- package/scripts/verify-deprecations.js +23 -15
- package/scripts/verify-translations.js +6 -5
- package/settings/i18ntk-config.json +282 -282
- package/settings/language-config.json +5 -5
- package/settings/settings-cli.js +9 -9
- package/settings/settings-manager.js +23 -20
- package/ui-locales/de.json +2417 -2348
- package/ui-locales/en.json +2415 -2352
- package/ui-locales/es.json +2425 -2353
- package/ui-locales/fr.json +2418 -2348
- package/ui-locales/ja.json +2463 -2361
- package/ui-locales/ru.json +2463 -2359
- package/ui-locales/zh.json +2418 -2351
- package/utils/admin-auth.js +2 -2
- package/utils/admin-cli.js +297 -297
- package/utils/admin-pin.js +9 -9
- package/utils/cli-helper.js +9 -9
- package/utils/config-helper.js +152 -103
- package/utils/config-manager.js +204 -164
- package/utils/config.js +5 -4
- package/utils/env-manager.js +256 -0
- package/utils/framework-detector.js +27 -24
- package/utils/i18n-helper.js +85 -41
- package/utils/init-helper.js +152 -94
- package/utils/json-output.js +98 -98
- package/utils/logger.js +6 -2
- package/utils/mini-commander.js +179 -0
- package/utils/missing-key-validator.js +5 -5
- package/utils/plugin-loader.js +29 -11
- package/utils/prompt.js +14 -44
- package/utils/safe-json.js +40 -0
- package/utils/secure-errors.js +3 -3
- package/utils/security-check-improved.js +390 -0
- package/utils/security-config.js +5 -5
- package/utils/security-fixed.js +607 -0
- package/utils/security.js +462 -248
- package/utils/setup-enforcer.js +136 -44
- package/utils/setup-validator.js +33 -32
- package/utils/terminal-icons.js +1 -1
- package/utils/ultra-performance-optimizer.js +11 -9
- package/utils/watch-locales.js +2 -1
- package/utils/prompt-fixed.js +0 -55
- package/utils/security-check.js +0 -450
package/main/i18ntk-analyze.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* I18NTK TRANSLATION ANALYSIS SCRIPT
|
|
4
4
|
*
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const fs = require('fs');
|
|
11
10
|
const path = require('path');
|
|
12
11
|
const cliHelper = require('../utils/cli-helper');
|
|
13
12
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
@@ -28,7 +27,7 @@ const SetupEnforcer = require('../utils/setup-enforcer');
|
|
|
28
27
|
}
|
|
29
28
|
})();
|
|
30
29
|
|
|
31
|
-
loadTranslations( 'en', path.resolve(__dirname, '..', 'ui-locales'));
|
|
30
|
+
loadTranslations( 'en', path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
|
|
32
31
|
|
|
33
32
|
const PROJECT_ROOT = process.cwd();
|
|
34
33
|
|
|
@@ -68,7 +67,7 @@ class I18nAnalyzer {
|
|
|
68
67
|
this.config = { ...baseConfig, ...(this.config || {}) };
|
|
69
68
|
|
|
70
69
|
const uiLanguage = (this.config && this.config.uiLanguage) || 'en';
|
|
71
|
-
loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
|
|
70
|
+
loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
|
|
72
71
|
|
|
73
72
|
this.sourceDir = this.config.sourceDir;
|
|
74
73
|
this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
|
|
@@ -146,7 +145,12 @@ class I18nAnalyzer {
|
|
|
146
145
|
// Get all available languages
|
|
147
146
|
getAvailableLanguages() {
|
|
148
147
|
try {
|
|
149
|
-
const items =
|
|
148
|
+
const items = SecurityUtils.safeReaddirSync(this.sourceDir, process.cwd(), { withFileTypes: true });
|
|
149
|
+
if (!items) {
|
|
150
|
+
console.error('Error reading source directory: Unable to access directory');
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
|
|
150
154
|
const languages = [];
|
|
151
155
|
|
|
152
156
|
// Check for directory-based structure
|
|
@@ -173,15 +177,17 @@ class I18nAnalyzer {
|
|
|
173
177
|
for (const dir of directories) {
|
|
174
178
|
const dirPath = path.join(this.sourceDir, dir);
|
|
175
179
|
try {
|
|
176
|
-
const dirItems =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
languages.
|
|
180
|
+
const dirItems = SecurityUtils.safeReaddirSync(dirPath, process.cwd(), { withFileTypes: true });
|
|
181
|
+
if (dirItems) {
|
|
182
|
+
const jsonFiles = dirItems
|
|
183
|
+
.filter(item => item.isFile() && item.name.endsWith('.json'))
|
|
184
|
+
.map(item => item.name.replace('.json', ''));
|
|
185
|
+
|
|
186
|
+
// If directory contains JSON files, it's likely a language directory
|
|
187
|
+
if (jsonFiles.length > 0) {
|
|
188
|
+
if (!languages.includes(dir)) {
|
|
189
|
+
languages.push(dir);
|
|
190
|
+
}
|
|
185
191
|
}
|
|
186
192
|
}
|
|
187
193
|
} catch (error) {
|
|
@@ -208,12 +214,14 @@ class I18nAnalyzer {
|
|
|
208
214
|
const files = [];
|
|
209
215
|
|
|
210
216
|
// Handle monolith file structure
|
|
211
|
-
|
|
217
|
+
const languageFileStat = SecurityUtils.safeStatSync(languageFile, this.sourceDir);
|
|
218
|
+
if (languageFileStat && languageFileStat.isFile()) {
|
|
212
219
|
return [path.basename(languageFile)];
|
|
213
220
|
}
|
|
214
221
|
|
|
215
222
|
// Handle directory-based structure
|
|
216
|
-
|
|
223
|
+
const languageDirStat = SecurityUtils.safeStatSync(languageDir, this.sourceDir);
|
|
224
|
+
if (languageDirStat && languageDirStat.isDirectory()) {
|
|
217
225
|
try {
|
|
218
226
|
// Ensure the path is within the source directory for security
|
|
219
227
|
const validatedPath = SecurityUtils.validatePath(languageDir, this.sourceDir);
|
|
@@ -224,7 +232,9 @@ class I18nAnalyzer {
|
|
|
224
232
|
|
|
225
233
|
const findJsonFiles = (dir) => {
|
|
226
234
|
const results = [];
|
|
227
|
-
const items =
|
|
235
|
+
const items = SecurityUtils.safeReaddirSync(dir, this.sourceDir, { withFileTypes: true });
|
|
236
|
+
|
|
237
|
+
if (!items) return results;
|
|
228
238
|
|
|
229
239
|
for (const item of items) {
|
|
230
240
|
const fullPath = path.join(dir, item.name);
|
|
@@ -267,16 +277,20 @@ class I18nAnalyzer {
|
|
|
267
277
|
const searchDir = this.sourceDir;
|
|
268
278
|
|
|
269
279
|
try {
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
const searchDirExists = SecurityUtils.safeExistsSync(searchDir, this.sourceDir);
|
|
281
|
+
if (searchDirExists) {
|
|
282
|
+
const items = SecurityUtils.safeReaddirSync(searchDir, this.sourceDir, { withFileTypes: true });
|
|
272
283
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
284
|
+
if (items) {
|
|
285
|
+
for (const item of items) {
|
|
286
|
+
if (item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules') {
|
|
287
|
+
const namespaceDir = path.join(searchDir, item.name);
|
|
288
|
+
const namespaceFile = path.join(namespaceDir, `${language}.json`);
|
|
289
|
+
|
|
290
|
+
const namespaceFileExists = SecurityUtils.safeExistsSync(namespaceFile, this.sourceDir);
|
|
291
|
+
if (namespaceFileExists) {
|
|
292
|
+
results.push(path.relative(path.join(this.sourceDir, item.name), namespaceFile));
|
|
293
|
+
}
|
|
280
294
|
}
|
|
281
295
|
}
|
|
282
296
|
}
|
|
@@ -468,15 +482,28 @@ class I18nAnalyzer {
|
|
|
468
482
|
const sourceFullPath = path.join(this.sourceDir, sourceFilePath);
|
|
469
483
|
const targetFullPath = path.join(this.sourceDir, targetFilePath);
|
|
470
484
|
|
|
471
|
-
|
|
485
|
+
const sourceExists = SecurityUtils.safeExistsSync(sourceFullPath, this.sourceDir);
|
|
486
|
+
if (!sourceExists) {
|
|
472
487
|
continue;
|
|
473
488
|
}
|
|
474
489
|
|
|
475
490
|
let sourceContent, targetContent;
|
|
476
491
|
|
|
477
492
|
try {
|
|
478
|
-
const sourceFileContent =
|
|
479
|
-
|
|
493
|
+
const sourceFileContent = SecurityUtils.safeReadFileSync(sourceFullPath, this.sourceDir, 'utf8');
|
|
494
|
+
if (!sourceFileContent) {
|
|
495
|
+
analysis.files[fileName] = {
|
|
496
|
+
error: `Failed to read source file: File not accessible or empty`
|
|
497
|
+
};
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
sourceContent = SecurityUtils.safeParseJSON(sourceFileContent);
|
|
501
|
+
if (!sourceContent) {
|
|
502
|
+
analysis.files[fileName] = {
|
|
503
|
+
error: `Failed to parse source file: Invalid JSON format`
|
|
504
|
+
};
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
480
507
|
} catch (error) {
|
|
481
508
|
analysis.files[fileName] = {
|
|
482
509
|
error: `Failed to parse source file: ${error.message}`
|
|
@@ -484,7 +511,8 @@ class I18nAnalyzer {
|
|
|
484
511
|
continue;
|
|
485
512
|
}
|
|
486
513
|
|
|
487
|
-
|
|
514
|
+
const targetExists = SecurityUtils.safeExistsSync(targetFullPath, this.sourceDir);
|
|
515
|
+
if (!targetExists) {
|
|
488
516
|
analysis.files[fileName] = {
|
|
489
517
|
status: 'missing',
|
|
490
518
|
sourceKeys: this.getAllKeys(sourceContent).size
|
|
@@ -493,9 +521,15 @@ class I18nAnalyzer {
|
|
|
493
521
|
}
|
|
494
522
|
|
|
495
523
|
try {
|
|
496
|
-
const targetFileContent =
|
|
497
|
-
|
|
498
|
-
|
|
524
|
+
const targetFileContent = SecurityUtils.safeReadFileSync(targetFullPath, this.sourceDir, 'utf8');
|
|
525
|
+
if (!targetFileContent) {
|
|
526
|
+
analysis.files[fileName] = {
|
|
527
|
+
error: `Failed to read target file: File not accessible or empty`
|
|
528
|
+
};
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const parsed = SecurityUtils.safeParseJSON(targetFileContent);
|
|
499
533
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
500
534
|
analysis.files[fileName] = {
|
|
501
535
|
error: `Invalid structure in target file: must be a plain object (not array/null/type)`
|
|
@@ -644,13 +678,10 @@ try {
|
|
|
644
678
|
}
|
|
645
679
|
|
|
646
680
|
// Ensure the output directory exists
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
console.error(`Failed to create output directory ${this.outputDir}:`, error.message);
|
|
652
|
-
return null;
|
|
653
|
-
}
|
|
681
|
+
const dirCreated = SecurityUtils.safeMkdirSync(this.outputDir, process.cwd(), { recursive: true });
|
|
682
|
+
if (!dirCreated) {
|
|
683
|
+
console.error(`Failed to create output directory ${this.outputDir}`);
|
|
684
|
+
return null;
|
|
654
685
|
}
|
|
655
686
|
|
|
656
687
|
// Validate the output directory is within the project
|
|
@@ -670,14 +701,10 @@ try {
|
|
|
670
701
|
return null;
|
|
671
702
|
}
|
|
672
703
|
|
|
673
|
-
// Use safeWriteFile
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
throw new Error(t('analyze.failedToWriteReportFile') || 'Failed to write report file securely');
|
|
678
|
-
}
|
|
679
|
-
} else {
|
|
680
|
-
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
|
|
704
|
+
// Use safeWriteFile for secure file writing
|
|
705
|
+
const success = await SecurityUtils.safeWriteFile(reportPath, JSON.stringify(report, null, 2), process.cwd(), 'utf8');
|
|
706
|
+
if (!success) {
|
|
707
|
+
throw new Error(t('analyze.failedToWriteReportFile') || 'Failed to write report file securely');
|
|
681
708
|
}
|
|
682
709
|
|
|
683
710
|
console.log(`Report saved to: ${reportPath}`);
|
|
@@ -709,8 +736,9 @@ try {
|
|
|
709
736
|
}
|
|
710
737
|
|
|
711
738
|
// Ensure output directory exists
|
|
712
|
-
|
|
713
|
-
|
|
739
|
+
const outputDirExists = SecurityUtils.safeExistsSync(this.outputDir, process.cwd());
|
|
740
|
+
if (!outputDirExists) {
|
|
741
|
+
SecurityUtils.safeMkdirSync(this.outputDir, process.cwd(), { recursive: true });
|
|
714
742
|
}
|
|
715
743
|
|
|
716
744
|
const languages = this.getAvailableLanguages();
|
|
@@ -856,7 +884,7 @@ try {
|
|
|
856
884
|
this.config = { ...baseConfig, ...this.config };
|
|
857
885
|
|
|
858
886
|
const uiLanguage = this.config.uiLanguage || 'en';
|
|
859
|
-
loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
|
|
887
|
+
loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
|
|
860
888
|
|
|
861
889
|
this.sourceDir = this.config.sourceDir;
|
|
862
890
|
this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
|
|
@@ -941,130 +969,110 @@ try {
|
|
|
941
969
|
}
|
|
942
970
|
|
|
943
971
|
async runSetupWizard() {
|
|
944
|
-
console.log('
|
|
972
|
+
console.log('Translation Analysis Setup Wizard');
|
|
945
973
|
console.log('='.repeat(50));
|
|
946
|
-
|
|
947
|
-
const prompts = require('prompts');
|
|
948
|
-
|
|
974
|
+
|
|
949
975
|
try {
|
|
950
|
-
// Detect current structure
|
|
951
976
|
const structure = this.detectStructureType();
|
|
952
977
|
console.log(`Current structure detected: ${structure.type}`);
|
|
953
|
-
|
|
954
|
-
const
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
initial: this.sourceDir,
|
|
972
|
-
validate: value => fs.existsSync(value) ? true : 'Directory does not exist'
|
|
973
|
-
},
|
|
974
|
-
{
|
|
975
|
-
type: 'text',
|
|
976
|
-
name: 'languages',
|
|
977
|
-
message: 'Enter languages to analyze (comma-separated, e.g., de,fr,es):',
|
|
978
|
-
initial: 'de,fr,es,ja,ru',
|
|
979
|
-
validate: value => value.trim() ? true : 'Please enter at least one language'
|
|
980
|
-
},
|
|
981
|
-
{
|
|
982
|
-
type: 'confirm',
|
|
983
|
-
name: 'outputReports',
|
|
984
|
-
message: 'Generate detailed reports for each language?',
|
|
985
|
-
initial: true
|
|
986
|
-
},
|
|
987
|
-
{
|
|
988
|
-
type: 'text',
|
|
989
|
-
name: 'outputDir',
|
|
990
|
-
message: 'Enter output directory for reports:',
|
|
991
|
-
initial: this.outputDir
|
|
992
|
-
}
|
|
993
|
-
];
|
|
994
|
-
|
|
995
|
-
const response = await prompts(questions);
|
|
996
|
-
|
|
997
|
-
if (!response.structureType) {
|
|
998
|
-
console.log('Setup cancelled.');
|
|
978
|
+
|
|
979
|
+
const structureOptions = ['monolith', 'directory', 'namespace', 'mixed'];
|
|
980
|
+
const defaultStructureIndex = structureOptions.indexOf(structure.type);
|
|
981
|
+
const defaultStructureChoice = defaultStructureIndex >= 0 ? String(defaultStructureIndex + 1) : '4';
|
|
982
|
+
|
|
983
|
+
console.log('Choose your translation file structure:');
|
|
984
|
+
console.log('1) Monolith files (en.json, de.json, etc.)');
|
|
985
|
+
console.log('2) Directory structure (en/common.json, de/common.json)');
|
|
986
|
+
console.log('3) Namespace structure (common/en.json, forms/en.json)');
|
|
987
|
+
console.log('4) Mixed structure (auto-detect)');
|
|
988
|
+
const structureChoiceInput = await this.prompt(`Select option [${defaultStructureChoice}]: `);
|
|
989
|
+
const structureChoice = structureChoiceInput.trim() || defaultStructureChoice;
|
|
990
|
+
const structureType = structureOptions[Number(structureChoice) - 1] || 'mixed';
|
|
991
|
+
|
|
992
|
+
const sourceDirInput = await this.prompt(`Enter source directory path [${this.sourceDir}]: `);
|
|
993
|
+
const sourceDir = sourceDirInput.trim() || this.sourceDir;
|
|
994
|
+
if (!SecurityUtils.safeExistsSync(sourceDir, process.cwd())) {
|
|
995
|
+
console.log('Setup cancelled: directory does not exist.');
|
|
999
996
|
return { success: false, cancelled: true };
|
|
1000
997
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
998
|
+
|
|
999
|
+
const languagesInput = await this.prompt('Enter languages to analyze (comma-separated) [de,fr,es,ja,ru]: ');
|
|
1000
|
+
const languagesValue = languagesInput.trim() || 'de,fr,es,ja,ru';
|
|
1001
|
+
const languages = languagesValue.split(',').map(lang => lang.trim()).filter(Boolean);
|
|
1002
|
+
if (languages.length === 0) {
|
|
1003
|
+
console.log('Setup cancelled: no languages provided.');
|
|
1004
|
+
return { success: false, cancelled: true };
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const outputReportsInput = await this.prompt('Generate detailed reports for each language? (Y/n): ');
|
|
1008
|
+
const outputReports = !['n', 'no'].includes(outputReportsInput.trim().toLowerCase());
|
|
1009
|
+
|
|
1010
|
+
const outputDirInput = await this.prompt(`Enter output directory for reports [${this.outputDir}]: `);
|
|
1011
|
+
const outputDir = outputDirInput.trim() || this.outputDir;
|
|
1012
|
+
|
|
1013
|
+
const response = {
|
|
1014
|
+
structureType,
|
|
1015
|
+
sourceDir,
|
|
1016
|
+
languages: languagesValue,
|
|
1017
|
+
outputReports,
|
|
1018
|
+
outputDir
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1003
1021
|
this.sourceDir = path.resolve(response.sourceDir);
|
|
1004
1022
|
this.outputDir = path.resolve(response.outputDir);
|
|
1005
1023
|
this.outputReports = response.outputReports;
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
console.log('\nš Configuration Summary:');
|
|
1024
|
+
|
|
1025
|
+
console.log('\nConfiguration Summary:');
|
|
1010
1026
|
console.log(`Source: ${this.sourceDir}`);
|
|
1011
1027
|
console.log(`Output: ${this.outputDir}`);
|
|
1012
|
-
console.log(`Languages: ${languages.join(
|
|
1028
|
+
console.log(`Languages: ${languages.join(", ")}`);
|
|
1013
1029
|
console.log(`Structure: ${response.structureType}`);
|
|
1014
|
-
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
message: 'Proceed with analysis?',
|
|
1019
|
-
initial: true
|
|
1020
|
-
});
|
|
1021
|
-
|
|
1022
|
-
if (!confirm.proceed) {
|
|
1030
|
+
|
|
1031
|
+
const proceedInput = await this.prompt('Proceed with analysis? (Y/n): ');
|
|
1032
|
+
const proceed = !['n', 'no'].includes(proceedInput.trim().toLowerCase());
|
|
1033
|
+
if (!proceed) {
|
|
1023
1034
|
console.log('Setup cancelled.');
|
|
1024
1035
|
return { success: false, cancelled: true };
|
|
1025
1036
|
}
|
|
1026
|
-
|
|
1027
|
-
// Run analysis with specified languages
|
|
1037
|
+
|
|
1028
1038
|
const results = [];
|
|
1029
1039
|
for (const language of languages) {
|
|
1030
1040
|
try {
|
|
1031
|
-
console.log(`\
|
|
1041
|
+
console.log(`\nAnalyzing ${language}...`);
|
|
1032
1042
|
const result = await this.analyzeLanguage(language);
|
|
1033
1043
|
results.push({ language, ...result });
|
|
1034
|
-
|
|
1044
|
+
|
|
1035
1045
|
if (this.outputReports) {
|
|
1036
1046
|
await this.saveReport(language, result);
|
|
1037
|
-
console.log(
|
|
1047
|
+
console.log(`Report saved: ${language}.json`);
|
|
1038
1048
|
}
|
|
1039
1049
|
} catch (error) {
|
|
1040
|
-
console.error(
|
|
1050
|
+
console.error(`Error analyzing ${language}:`, error.message);
|
|
1041
1051
|
results.push({ language, error: error.message });
|
|
1042
1052
|
}
|
|
1043
1053
|
}
|
|
1044
|
-
|
|
1045
|
-
// Generate summary
|
|
1054
|
+
|
|
1046
1055
|
const summary = {
|
|
1047
1056
|
totalLanguages: results.length,
|
|
1048
1057
|
successful: results.filter(r => !r.error).length,
|
|
1049
1058
|
failed: results.filter(r => r.error).length,
|
|
1050
1059
|
results
|
|
1051
1060
|
};
|
|
1052
|
-
|
|
1061
|
+
|
|
1053
1062
|
await this.saveReport('wizard-summary', {
|
|
1054
1063
|
summary,
|
|
1055
1064
|
configuration: response,
|
|
1056
1065
|
timestamp: new Date().toISOString()
|
|
1057
1066
|
});
|
|
1058
|
-
|
|
1059
|
-
console.log('\
|
|
1067
|
+
|
|
1068
|
+
console.log('\nSetup complete.');
|
|
1060
1069
|
console.log(`Analyzed ${summary.successful}/${summary.totalLanguages} languages successfully`);
|
|
1061
|
-
|
|
1070
|
+
|
|
1062
1071
|
return {
|
|
1063
1072
|
success: true,
|
|
1064
1073
|
summary,
|
|
1065
1074
|
configuration: response
|
|
1066
1075
|
};
|
|
1067
|
-
|
|
1068
1076
|
} catch (error) {
|
|
1069
1077
|
console.error('Setup wizard error:', error.message);
|
|
1070
1078
|
return { success: false, error: error.message };
|
|
@@ -1100,7 +1108,14 @@ async function analyzeTranslations(datasetPath) {
|
|
|
1100
1108
|
analyzer.outputDir = './reports';
|
|
1101
1109
|
|
|
1102
1110
|
// Load and analyze the dataset
|
|
1103
|
-
const
|
|
1111
|
+
const datasetContent = SecurityUtils.safeReadFileSync(datasetPath, process.cwd(), 'utf8');
|
|
1112
|
+
if (!datasetContent) {
|
|
1113
|
+
throw new Error('Failed to load dataset for benchmark');
|
|
1114
|
+
}
|
|
1115
|
+
const dataset = SecurityUtils.safeParseJSON(datasetContent);
|
|
1116
|
+
if (!dataset) {
|
|
1117
|
+
throw new Error('Failed to parse dataset JSON');
|
|
1118
|
+
}
|
|
1104
1119
|
|
|
1105
1120
|
// Simulate analysis processing
|
|
1106
1121
|
const languages = Object.keys(dataset).filter(lang => lang !== 'en');
|
|
@@ -1133,4 +1148,5 @@ async function analyzeTranslations(datasetPath) {
|
|
|
1133
1148
|
module.exports = {
|
|
1134
1149
|
I18nAnalyzer,
|
|
1135
1150
|
analyzeTranslations
|
|
1136
|
-
};
|
|
1151
|
+
};
|
|
1152
|
+
|