i18ntk 4.5.2 → 4.5.4

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.
@@ -56,11 +56,14 @@ class I18nSummaryReporter {
56
56
  const uiLanguage = this.config.uiLanguage || 'en';
57
57
  loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
58
58
 
59
- this.sourceDir = this.config.sourceDir;
60
-
61
- // Validate source directory
62
- const { validateSourceDir } = require('../utils/config-helper');
63
- validateSourceDir(this.sourceDir, 'i18ntk-summary');
59
+ this.sourceDir = this.config.localesDir || this.config.i18nDir || this.config.sourceDir;
60
+ this.config.sourceDir = this.sourceDir;
61
+
62
+ if (!SecurityUtils.safeExistsSync(this.sourceDir, process.cwd())) {
63
+ const err = new Error(`Locale directory not found: ${this.sourceDir}`);
64
+ err.exitCode = 2;
65
+ throw err;
66
+ }
64
67
  } catch (error) {
65
68
  console.error(`Error initializing summary reporter: ${error.message}`);
66
69
  throw error;
@@ -523,7 +526,10 @@ class I18nSummaryReporter {
523
526
  report.push(t('summary.languagesCount', {count: this.stats.languages.length}));
524
527
  report.push(t('summary.totalFiles', {count: this.stats.totalFiles}));
525
528
  report.push(t('summary.totalKeys', {count: this.stats.totalKeys}));
526
- report.push(t('summary.avgKeysPerLanguage', {count: Math.round(this.stats.totalKeys / this.stats.languages.length)}));
529
+ const averageKeysPerLanguage = this.stats.languages.length > 0
530
+ ? Math.round(this.stats.totalKeys / this.stats.languages.length)
531
+ : 0;
532
+ report.push(t('summary.avgKeysPerLanguage', {count: averageKeysPerLanguage}));
527
533
 
528
534
  // Calculate total size
529
535
  const totalSize = Object.values(this.stats.folderSizes).reduce((sum, size) => sum + size, 0);
@@ -666,8 +672,13 @@ class I18nSummaryReporter {
666
672
  }
667
673
  report.push('');
668
674
  }
669
- } else {
670
- report.push(t('summary.noIssuesFound'));
675
+ } else if (this.stats.languages.length === 0) {
676
+ report.push('⚠️ NO LOCALE LANGUAGES FOUND');
677
+ report.push('='.repeat(30));
678
+ report.push('No locale language files or directories were found in the selected locale root.');
679
+ report.push('');
680
+ } else {
681
+ report.push(t('summary.noIssuesFound'));
671
682
  report.push('='.repeat(30));
672
683
  report.push(t('summary.allFilesConsistent'));
673
684
  report.push('');
@@ -795,13 +806,20 @@ class I18nSummaryReporter {
795
806
  const args = process.argv.slice(2);
796
807
  const parsed = {};
797
808
 
798
- args.forEach(arg => {
799
- if (arg.startsWith('--')) {
800
- const [key, value] = arg.substring(2).split('=');
801
- if (key === 'source-dir') {
802
- parsed.sourceDir = value;
803
- } else if (key === 'source-language') {
804
- parsed.sourceLanguage = value;
809
+ for (let i = 0; i < args.length; i++) {
810
+ const arg = args[i];
811
+ if (arg.startsWith('--')) {
812
+ const [key, rawValue] = arg.substring(2).split('=');
813
+ const value = rawValue !== undefined
814
+ ? rawValue
815
+ : (args[i + 1] && !args[i + 1].startsWith('--') ? args[++i] : true);
816
+ if (key === 'source-dir' || key === 'locales-dir' || key === 'i18n-dir') {
817
+ parsed.sourceDir = value;
818
+ parsed.i18nDir = value;
819
+ } else if (key === 'source-language' || key === 'source-locale') {
820
+ parsed.sourceLanguage = value;
821
+ } else if (key === 'code-dir' || key === 'source-code-dir') {
822
+ parsed.codeDir = value;
805
823
  } else if (key === 'output-file') {
806
824
  parsed.outputFile = value;
807
825
  } else if (key === 'verbose') {
@@ -813,10 +831,10 @@ class I18nSummaryReporter {
813
831
  } else if (key === 'no-prompt') {
814
832
  parsed.noPrompt = true;
815
833
  } else if (key === 'help') {
816
- parsed.help = true;
817
- }
818
- }
819
- });
834
+ parsed.help = true;
835
+ }
836
+ }
837
+ }
820
838
 
821
839
  return parsed;
822
840
  }
@@ -827,14 +845,16 @@ class I18nSummaryReporter {
827
845
  const { fromMenu = false, noPrompt = false } = options;
828
846
 
829
847
  // Always use unified configuration to respect settings
830
- const baseConfig = await getUnifiedConfig('summary', args);
831
- this.config = { ...this.config, ...baseConfig };
848
+ const baseConfig = await getUnifiedConfig('summary', args);
849
+ this.config = { ...this.config, ...baseConfig };
832
850
 
833
851
  const uiLanguage = this.config.uiLanguage || 'en';
834
852
  loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
835
- if (!this.config.sourceDir) {
836
- this.config.sourceDir = this.detectI18nDirectory();
837
- }
853
+ if (!this.config.sourceDir) {
854
+ this.config.sourceDir = this.detectI18nDirectory();
855
+ }
856
+ this.config.sourceDir = this.config.localesDir || this.config.i18nDir || this.config.sourceDir;
857
+ this.sourceDir = this.config.sourceDir;
838
858
 
839
859
  if (!fromMenu) {
840
860
  // Check admin authentication for sensitive operations (only when called directly)
@@ -866,10 +886,10 @@ class I18nSummaryReporter {
866
886
  }
867
887
 
868
888
  // Validate source directory exists
869
- if (!SecurityUtils.safeExistsSync(this.config.sourceDir, this.config.sourceDir)) {
870
- console.error(t('summary.sourceDirectoryDoesNotExist', { sourceDir: this.config.sourceDir }));
871
- process.exit(1);
872
- }
889
+ if (!SecurityUtils.safeExistsSync(this.config.sourceDir, process.cwd())) {
890
+ console.error(t('summary.sourceDirectoryDoesNotExist', { sourceDir: this.config.sourceDir }));
891
+ process.exit(2);
892
+ }
873
893
  }
874
894
 
875
895
  console.log(t('summary.i18nSummaryReportGenerator'));
@@ -992,17 +1012,19 @@ class I18nSummaryReporter {
992
1012
 
993
1013
  if (totalIssues > 0) {
994
1014
  console.log(t('summary.foundIssues', {count: totalIssues}));
995
- } else {
996
- console.log(t('summary.noIssuesConsole'));
997
- }
1015
+ } else if (this.stats.languages.length === 0) {
1016
+ console.log('⚠️ No locale languages found in the selected locale root.');
1017
+ } else {
1018
+ console.log(t('summary.noIssuesConsole'));
1019
+ }
998
1020
 
999
1021
  } catch (error) {
1000
1022
  console.error(t('summary.errorDuringAnalysis', { error: error.message }));
1001
1023
  if (args.verbose) {
1002
1024
  console.error(error.stack);
1003
1025
  }
1004
- process.exit(1);
1005
- }
1026
+ process.exit(error.exitCode || 1);
1027
+ }
1006
1028
  process.exit(0);
1007
1029
  }
1008
1030
  }
@@ -1014,10 +1036,10 @@ if (require.main === module) {
1014
1036
  await reporter.initialize();
1015
1037
  await reporter.run();
1016
1038
  }
1017
- main().catch(error => {
1018
- console.error('Error in i18ntk-summary:', error.message);
1019
- process.exit(1);
1020
- });
1021
- }
1039
+ main().catch(error => {
1040
+ console.error('Error in i18ntk-summary:', error.message);
1041
+ process.exit(error.exitCode || 1);
1042
+ });
1043
+ }
1022
1044
 
1023
- module.exports = I18nSummaryReporter;
1045
+ module.exports = I18nSummaryReporter;
@@ -46,6 +46,7 @@ const JsonOutput = require('../utils/json-output');
46
46
  const SetupEnforcer = require('../utils/setup-enforcer');
47
47
  const { resolveUsageSourceDir } = require('../utils/usage-source');
48
48
  const { analyzeSourceForUsageInsights } = require('../utils/usage-insights');
49
+ const { isInteractive } = require('../utils/prompt-helper');
49
50
 
50
51
  // Ensure setup is complete before running
51
52
  (async () => {
@@ -195,7 +196,7 @@ class I18nUsageAnalyzer {
195
196
  this.config.excludeDirs = ['node_modules', '.git'];
196
197
  }
197
198
  if (!Array.isArray(this.config.includeExtensions) && !Array.isArray(this.config.supportedExtensions)) {
198
- this.config.includeExtensions = ['.js', '.jsx', '.ts', '.tsx', '.py', '.pyx', '.pyi'];
199
+ this.config.includeExtensions = ['.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte', '.py', '.pyx', '.pyi'];
199
200
  }
200
201
 
201
202
  await SecurityUtils.logSecurityEvent(t('usage.analyzerInitialized'), 'info', { component: 'i18ntk-usage' });
@@ -207,9 +208,10 @@ class I18nUsageAnalyzer {
207
208
 
208
209
  // Normalize CLI arguments to handle both camelCase and hyphenated flags
209
210
  normalizeArgs(a) {
210
- return {
211
- sourceDir: a.sourceDir ?? a['source-dir'],
212
- i18nDir: a.i18nDir ?? a['i18n-dir'],
211
+ return {
212
+ sourceDir: a.sourceDir ?? a['source-dir'] ?? a['code-dir'] ?? a['source-code-dir'],
213
+ i18nDir: a.i18nDir ?? a['i18n-dir'] ?? a['locales-dir'],
214
+ sourceLanguage: a.sourceLanguage ?? a['source-language'] ?? a['source-locale'],
213
215
  outputReport: a.outputReport ?? a['output-report'],
214
216
  outputDir: a.outputDir ?? a['output-dir'],
215
217
  uiLanguage: a.uiLanguage ?? a['ui-language'],
@@ -231,11 +233,18 @@ class I18nUsageAnalyzer {
231
233
  const args = process.argv.slice(2);
232
234
  const parsed = {};
233
235
 
234
- for (const arg of args) {
235
- if (arg.startsWith('--')) {
236
- const [key, value] = arg.substring(2).split('=');
237
- if (value !== undefined) {
238
- parsed[key] = value;
236
+ for (let i = 0; i < args.length; i++) {
237
+ const arg = args[i];
238
+ if (arg.startsWith('--')) {
239
+ let [key, value] = arg.substring(2).split('=');
240
+ if (value === undefined && args[i + 1] && !args[i + 1].startsWith('-')) {
241
+ value = args[++i];
242
+ }
243
+ if (key === 'code-dir' || key === 'source-code-dir') key = 'source-dir';
244
+ if (key === 'locales-dir') key = 'i18n-dir';
245
+ if (key === 'source-locale') key = 'source-language';
246
+ if (value !== undefined) {
247
+ parsed[key] = value;
239
248
  } else {
240
249
  parsed[key] = true;
241
250
  }
@@ -513,11 +522,15 @@ class I18nUsageAnalyzer {
513
522
  this.sourceDir = path.resolve(args.sourceDir);
514
523
  }
515
524
 
516
- if (args.i18nDir) {
517
- this.config.i18nDir = args.i18nDir;
518
- this.i18nDir = path.resolve(args.i18nDir);
519
- this.sourceLanguageDir = path.join(this.i18nDir, this.config.sourceLanguage);
520
- }
525
+ if (args.i18nDir) {
526
+ this.config.i18nDir = args.i18nDir;
527
+ this.i18nDir = path.resolve(args.i18nDir);
528
+ this.sourceLanguageDir = path.join(this.i18nDir, this.config.sourceLanguage);
529
+ }
530
+ if (args.sourceLanguage) {
531
+ this.config.sourceLanguage = args.sourceLanguage;
532
+ this.sourceLanguageDir = path.join(this.i18nDir, this.config.sourceLanguage);
533
+ }
521
534
 
522
535
  if (this.sourceDir || this.i18nDir) {
523
536
  await configManager.updateConfig({
@@ -722,9 +735,9 @@ class I18nUsageAnalyzer {
722
735
 
723
736
  console.log('\n' + t('usage.analysisCompletedSuccessfully'));
724
737
 
725
- if (require.main === module && !args.noPrompt) {
726
- await this.prompt('\nPress Enter to continue...');
727
- }
738
+ if (require.main === module && isInteractive(args)) {
739
+ await this.prompt('\nPress Enter to continue...');
740
+ }
728
741
  this.closeReadline();
729
742
 
730
743
  } catch (error) {
@@ -43,8 +43,9 @@ const configManager = require('../utils/config-manager');
43
43
  const SecurityUtils = require('../utils/security');
44
44
  const AdminCLI = require('../utils/admin-cli');
45
45
  const watchLocales = require('../utils/watch-locales');
46
- const { getGlobalReadline, closeGlobalReadline } = require('../utils/cli');
47
- const { getUnifiedConfig, parseCommonArgs, displayHelp, validateSourceDir, displayPaths } = require('../utils/config-helper');
46
+ const { getGlobalReadline, closeGlobalReadline } = require('../utils/cli');
47
+ const { getUnifiedConfig, parseCommonArgs, displayHelp, validateSourceDir, displayPaths } = require('../utils/config-helper');
48
+ const { isInteractive } = require('../utils/prompt-helper');
48
49
  const I18nInitializer = require('./i18ntk-init');
49
50
  const JsonOutput = require('../utils/json-output');
50
51
  const ExitCodes = require('../utils/exit-codes');
@@ -105,14 +106,21 @@ class I18nValidator {
105
106
  );
106
107
 
107
108
  // Use the i18n directory for language files
108
- this.sourceDir = this.config.i18nDir || this.config.sourceDir;
109
- this.i18nDir = this.config.i18nDir || this.config.sourceDir;
109
+ this.sourceDir = this.config.localesDir || this.config.i18nDir || this.config.sourceDir;
110
+ this.i18nDir = this.config.localesDir || this.config.i18nDir || this.config.sourceDir;
110
111
  this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
111
112
 
112
- try {
113
- validateSourceDir(this.sourceDir, 'i18ntk-validate');
114
- } catch (err) {
115
- console.log(t('init.requiredTitle'));
113
+ try {
114
+ if (!SecurityUtils.safeExistsSync(this.sourceDir, process.cwd())) {
115
+ const err = new Error(`Locale directory not found: ${this.sourceDir}`);
116
+ err.exitCode = 2;
117
+ throw err;
118
+ }
119
+ } catch (err) {
120
+ if (!isInteractive(args)) {
121
+ throw err;
122
+ }
123
+ console.log(t('init.requiredTitle'));
116
124
  console.log(t('init.requiredBody'));
117
125
  const answer = await this.prompt(t('init.promptRunNow'));
118
126
  if (answer.trim().toLowerCase() === 'y') {
@@ -827,11 +835,13 @@ class I18nValidator {
827
835
  if (args.uiLanguage) {
828
836
  loadTranslations(args.uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));}
829
837
 
830
- if (args.sourceDir) {
831
- this.config.sourceDir = args.sourceDir;
832
- this.sourceDir = path.resolve(this.config.sourceDir);
833
- this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
834
- }
838
+ const localeDirArg = args.i18nDir || (!args.i18nDir && args.sourceDir ? args.sourceDir : null);
839
+ if (localeDirArg) {
840
+ this.config.i18nDir = localeDirArg;
841
+ this.sourceDir = path.resolve(localeDirArg);
842
+ this.i18nDir = this.sourceDir;
843
+ this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
844
+ }
835
845
  if (args.strictMode) {
836
846
  this.config.strictMode = true;
837
847
  }
@@ -1131,14 +1141,18 @@ class I18nValidator {
1131
1141
  { message: 'Starting validation run' }
1132
1142
  );
1133
1143
 
1134
- const result = await this.validate();
1135
-
1136
- console.log(t('validate.validationProcessCompletedSuccessfully'));
1137
- SecurityUtils.logSecurityEvent(
1138
- t('validate.runCompleted'),
1139
- 'info',
1140
- { message: 'Validation run completed successfully' }
1141
- );
1144
+ const result = await this.validate();
1145
+
1146
+ if (result.success) {
1147
+ console.log(t('validate.validationProcessCompletedSuccessfully'));
1148
+ } else {
1149
+ console.log('❌ Validation failed.');
1150
+ }
1151
+ SecurityUtils.logSecurityEvent(
1152
+ result.success ? t('validate.runCompleted') : t('validate.runError'),
1153
+ result.success ? 'info' : 'error',
1154
+ { message: result.success ? 'Validation run completed successfully' : 'Validation run failed' }
1155
+ );
1142
1156
  return result;
1143
1157
  };
1144
1158
 
@@ -1234,8 +1248,8 @@ if (require.main === module) {
1234
1248
  timestamp: new Date().toISOString()
1235
1249
  });
1236
1250
 
1237
- process.exit(result.success ? ExitCodes.SUCCESS : ExitCodes.VALIDATION_FAILED);
1238
- }
1251
+ process.exit(result.success ? ExitCodes.SUCCESS : ExitCodes.VALIDATION_FAILED);
1252
+ }
1239
1253
  } catch (error) {
1240
1254
  console.error(t('validate.fatalValidationError', { error: error.message }));
1241
1255
  console.error(t('validate.stackTrace', { stack: error.stack }));
@@ -1245,7 +1259,7 @@ if (require.main === module) {
1245
1259
  timestamp: new Date().toISOString()
1246
1260
  });
1247
1261
 
1248
- process.exit(ExitCodes.CONFIG_ERROR);
1262
+ process.exit(error.exitCode || ExitCodes.CONFIG_ERROR);
1249
1263
  }
1250
1264
  })();
1251
1265
  }
@@ -80,10 +80,17 @@ class AnalyzeCommand {
80
80
  const uiLanguage = (this.config && this.config.uiLanguage) || 'en';
81
81
  loadTranslations(uiLanguage, path.resolve(__dirname, '../../../ui-locales'));
82
82
 
83
- this.sourceDir = this.config.sourceDir;
83
+ this.sourceDir = this.config.localesDir || this.config.i18nDir || this.config.sourceDir;
84
84
  this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
85
85
  this.outputDir = this.config.outputDir;
86
86
 
87
+ const explicitLocaleDir = args.i18nDir || (!args.i18nDir && args.sourceDir ? args.sourceDir : null);
88
+ if (explicitLocaleDir && !SecurityUtils.safeExistsSync(this.sourceDir, process.cwd())) {
89
+ const err = new Error(`Locale directory not found: ${this.sourceDir}`);
90
+ err.exitCode = 2;
91
+ throw err;
92
+ }
93
+
87
94
  // Validate source directory exists and is readable/writable
88
95
  this.validateSourceDirWithFallback(this.sourceDir);
89
96
 
@@ -766,12 +773,34 @@ class AnalyzeCommand {
766
773
  }
767
774
  }
768
775
 
769
- // Show help message
770
- showHelp() {
771
- console.log(t('analyze.help_message'));
772
- }
773
-
774
- // Main analyze method
776
+ // Show help message
777
+ showHelp() {
778
+ console.log(t('analyze.help_message'));
779
+ }
780
+
781
+ provideSetupGuidance() {
782
+ return [
783
+ 'Setup guidance:',
784
+ `- Ensure the locale root exists: ${this.sourceDir}`,
785
+ `- Ensure the source locale exists: ${path.join(this.sourceDir, this.config.sourceLanguage)}`,
786
+ '- Add at least one target locale, for example de/common.json or de.json.',
787
+ '- Prefer --locales-dir for locale files. Use --code-dir for application source files.'
788
+ ].join('\n');
789
+ }
790
+
791
+ detectStructureType() {
792
+ const sourceLocaleDir = path.join(this.sourceDir, this.config.sourceLanguage);
793
+ const sourceLocaleFile = path.join(this.sourceDir, `${this.config.sourceLanguage}.json`);
794
+ if (SecurityUtils.safeExistsSync(sourceLocaleFile, this.sourceDir)) {
795
+ return { type: 'monolith' };
796
+ }
797
+ if (SecurityUtils.safeExistsSync(sourceLocaleDir, this.sourceDir)) {
798
+ return { type: 'directory' };
799
+ }
800
+ return { type: 'unknown' };
801
+ }
802
+
803
+ // Main analyze method
775
804
  async analyze() {
776
805
  try {
777
806
  const results = [];
@@ -806,11 +835,11 @@ class AnalyzeCommand {
806
835
  });
807
836
  console.log(JSON.stringify(jsonOutput.data, null, args.indent || 2));
808
837
  return;
809
- }
810
- console.log(error);
811
- console.log('\n' + guidance);
812
- return;
813
- }
838
+ }
839
+ console.log(error);
840
+ console.log('\n' + guidance);
841
+ return { success: true, warnings: 1, message: error };
842
+ }
814
843
 
815
844
  if (!args.json) {
816
845
  console.log(t('analyze.foundLanguages', { count: languages.length, languages: languages.join(', ') }) || `📋 Found ${languages.length} languages to analyze: ${languages.join(', ')}`);
@@ -829,8 +858,11 @@ class AnalyzeCommand {
829
858
  const report = this.generateLanguageReport(analysis);
830
859
 
831
860
  // Save report
832
- const reportPath = await this.saveReport(language, report);
833
- const processedCount = results.length + 1;
861
+ const reportPath = await this.saveReport(language, report);
862
+ if (!reportPath) {
863
+ throw new Error(`Failed to save analysis report for ${language}`);
864
+ }
865
+ const processedCount = results.length + 1;
834
866
 
835
867
  if (!args.json) {
836
868
  console.log(t('analyze.completed', { language }) || `✅ Analysis completed for ${language}`);
@@ -898,9 +930,9 @@ class AnalyzeCommand {
898
930
  console.log(t('analyze.finished') || '\n✅ Analysis completed successfully!');
899
931
 
900
932
  // Only prompt for input if running standalone and not in no-prompt mode
901
- if (require.main === module && !this.noPrompt) {
902
- await this.prompt('\nPress Enter to continue...');
903
- }
933
+ if (require.main === module && !this.noPrompt && process.env.CI !== 'true' && process.stdin.isTTY && process.stdout.isTTY) {
934
+ await this.prompt('\nPress Enter to continue...');
935
+ }
904
936
  this.closeReadline();
905
937
 
906
938
  return results;
@@ -937,7 +969,7 @@ class AnalyzeCommand {
937
969
  const uiLanguage = this.config.uiLanguage || 'en';
938
970
  loadTranslations(uiLanguage, path.resolve(__dirname, '../../../ui-locales'));
939
971
 
940
- this.sourceDir = this.config.sourceDir;
972
+ this.sourceDir = this.config.localesDir || this.config.i18nDir || this.config.sourceDir;
941
973
  this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
942
974
  this.outputDir = this.config.outputDir;
943
975
  }
@@ -975,19 +1007,20 @@ class AnalyzeCommand {
975
1007
  loadTranslations(args.uiLanguage, path.resolve(__dirname, '../../../ui-locales'));}
976
1008
 
977
1009
  // Update config if source directory is provided
978
- if (args.sourceDir) {
979
- this.config.sourceDir = args.sourceDir;
980
- this.sourceDir = path.resolve(PROJECT_ROOT, this.config.sourceDir);
981
- this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
982
- }
1010
+ const localeDirArg = args.i18nDir || (!args.i18nDir && args.sourceDir ? args.sourceDir : null);
1011
+ if (localeDirArg) {
1012
+ this.config.i18nDir = localeDirArg;
1013
+ this.sourceDir = path.resolve(PROJECT_ROOT, localeDirArg);
1014
+ this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
1015
+ }
983
1016
 
984
1017
  if (args.outputDir) {
985
1018
  this.config.outputDir = args.outputDir;
986
1019
  this.outputDir = path.resolve(this.config.outputDir);
987
1020
  }
988
- const execute = async () => {
989
- await this.analyze();
990
- };
1021
+ const execute = async () => {
1022
+ return await this.analyze();
1023
+ };
991
1024
 
992
1025
  if (args.watch) {
993
1026
  await execute();
@@ -1003,19 +1036,21 @@ class AnalyzeCommand {
1003
1036
  });
1004
1037
  console.log('��� Watching for translation changes. Press Ctrl+C to exit.');
1005
1038
  } else {
1006
- await execute();
1007
- if (!fromMenu && require.main === module) {
1008
- process.exit(0);
1009
- }
1010
- }
1039
+ const result = await execute();
1040
+ if (!fromMenu && require.main === module) {
1041
+ process.exit(0);
1042
+ }
1043
+ return result;
1044
+ }
1011
1045
  } catch (error) {
1012
1046
  console.error(t('analyze.error') || '❌ Analysis failed:', error.message);
1013
1047
  this.closeReadline();
1014
- if (!fromMenu && require.main === module) {
1015
- process.exit(1);
1016
- }
1017
- }
1018
- }
1048
+ if (!fromMenu && require.main === module) {
1049
+ process.exit(1);
1050
+ }
1051
+ throw error;
1052
+ }
1053
+ }
1019
1054
 
1020
1055
  async runSetupWizard() {
1021
1056
  console.log('Translation Analysis Setup Wizard');
@@ -1132,14 +1167,14 @@ class AnalyzeCommand {
1132
1167
  /**
1133
1168
  * Execute the analyze command
1134
1169
  */
1135
- async execute(options = {}) {
1136
- try {
1137
- await this.initialize();
1138
- await this.run(options);
1139
- return { success: true, command: 'analyze' };
1140
- } catch (error) {
1141
- console.error(`Analyze command failed: ${error.message}`);
1142
- throw error;
1170
+ async execute(options = {}) {
1171
+ try {
1172
+ await this.initialize();
1173
+ const result = await this.run(options);
1174
+ return result && result.success === false ? result : { success: true, command: 'analyze', result };
1175
+ } catch (error) {
1176
+ console.error(`Analyze command failed: ${error.message}`);
1177
+ throw error;
1143
1178
  }
1144
1179
  }
1145
1180
 
@@ -122,9 +122,11 @@ class ScannerCommand {
122
122
  const value = valueParts.join('=');
123
123
 
124
124
  switch (key) {
125
- case 'source-dir':
126
- parsed.sourceDir = value || '';
127
- break;
125
+ case 'source-dir':
126
+ case 'code-dir':
127
+ case 'source-code-dir':
128
+ parsed.sourceDir = value || '';
129
+ break;
128
130
  case 'framework':
129
131
  parsed.framework = value || '';
130
132
  break;
@@ -146,9 +148,13 @@ class ScannerCommand {
146
148
  case 'output-report':
147
149
  parsed.outputReport = true;
148
150
  break;
149
- case 'include-tests':
150
- parsed.includeTests = true;
151
- break;
151
+ case 'include-tests':
152
+ parsed.includeTests = true;
153
+ break;
154
+ case 'source-language':
155
+ case 'source-locale':
156
+ parsed.sourceLanguage = value || '';
157
+ break;
152
158
  case 'help':
153
159
  case 'h':
154
160
  parsed.help = true;
@@ -669,4 +675,4 @@ class ScannerCommand {
669
675
  }
670
676
  }
671
677
 
672
- module.exports = ScannerCommand;
678
+ module.exports = ScannerCommand;