i18ntk 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +69 -2
  2. package/LICENSE +3 -1
  3. package/README.md +47 -46
  4. package/docs/README.md +40 -18
  5. package/docs/SCRIPT_DIRECTORY_GUIDE.md +224 -0
  6. package/docs/release-notes/v1.3.0.md +162 -0
  7. package/main/i18ntk-analyze.js +11 -6
  8. package/main/i18ntk-autorun.js +37 -36
  9. package/main/i18ntk-complete.js +9 -5
  10. package/main/i18ntk-init.js +19 -13
  11. package/main/i18ntk-manage.js +6 -4
  12. package/main/i18ntk-sizing.js +5 -1
  13. package/main/i18ntk-summary.js +6 -2
  14. package/main/i18ntk-usage.js +5 -5
  15. package/main/i18ntk-validate.js +9 -5
  16. package/package.json +12 -5
  17. package/scripts/copy-translations.js +90 -0
  18. package/settings/i18ntk-config.json +11 -1
  19. package/settings/settings-cli.js +136 -75
  20. package/settings/settings-manager.js +19 -0
  21. package/ui-locales/de/autorun.json +69 -64
  22. package/ui-locales/de/common.json +14 -1
  23. package/ui-locales/de/errors.json +11 -1
  24. package/ui-locales/de/menu.json +10 -1
  25. package/ui-locales/de/operations.json +11 -0
  26. package/ui-locales/de/security.json +2 -1
  27. package/ui-locales/de/settings.json +60 -9
  28. package/ui-locales/de/sizing.json +14 -1
  29. package/ui-locales/de/status.json +18 -1
  30. package/ui-locales/de/test-complete-system.json +13 -1
  31. package/ui-locales/en/autorun.json +68 -65
  32. package/ui-locales/en/common.json +15 -1
  33. package/ui-locales/en/init.json +20 -5
  34. package/ui-locales/en/menu.json +1 -0
  35. package/ui-locales/en/operations.json +11 -1
  36. package/ui-locales/en/settings.json +151 -34
  37. package/ui-locales/es/autorun.json +68 -65
  38. package/ui-locales/es/common.json +14 -1
  39. package/ui-locales/es/errors.json +11 -1
  40. package/ui-locales/es/menu.json +10 -1
  41. package/ui-locales/es/operations.json +11 -0
  42. package/ui-locales/es/security.json +2 -1
  43. package/ui-locales/es/settings.json +60 -9
  44. package/ui-locales/es/sizing.json +14 -1
  45. package/ui-locales/es/status.json +18 -1
  46. package/ui-locales/es/test-complete-system.json +13 -1
  47. package/ui-locales/fr/autorun.json +69 -64
  48. package/ui-locales/fr/common.json +14 -1
  49. package/ui-locales/fr/errors.json +11 -1
  50. package/ui-locales/fr/menu.json +10 -1
  51. package/ui-locales/fr/operations.json +11 -0
  52. package/ui-locales/fr/security.json +2 -1
  53. package/ui-locales/fr/settings.json +60 -9
  54. package/ui-locales/fr/sizing.json +14 -1
  55. package/ui-locales/fr/status.json +18 -1
  56. package/ui-locales/fr/test-complete-system.json +13 -1
  57. package/ui-locales/ja/autorun.json +69 -64
  58. package/ui-locales/ja/common.json +14 -1
  59. package/ui-locales/ja/errors.json +11 -1
  60. package/ui-locales/ja/menu.json +10 -1
  61. package/ui-locales/ja/operations.json +11 -0
  62. package/ui-locales/ja/security.json +2 -1
  63. package/ui-locales/ja/settings.json +60 -9
  64. package/ui-locales/ja/sizing.json +14 -1
  65. package/ui-locales/ja/status.json +18 -1
  66. package/ui-locales/ja/test-complete-system.json +13 -1
  67. package/ui-locales/pt/analyze.json +2 -1
  68. package/ui-locales/pt/autorun.json +69 -64
  69. package/ui-locales/pt/common.json +14 -1
  70. package/ui-locales/pt/errors.json +11 -1
  71. package/ui-locales/pt/init.json +5 -1
  72. package/ui-locales/pt/menu.json +10 -1
  73. package/ui-locales/pt/operations.json +11 -0
  74. package/ui-locales/pt/security.json +2 -1
  75. package/ui-locales/pt/settings.json +60 -9
  76. package/ui-locales/pt/sizing.json +14 -1
  77. package/ui-locales/pt/status.json +18 -1
  78. package/ui-locales/pt/test-complete-system.json +13 -1
  79. package/ui-locales/ru/autorun.json +69 -64
  80. package/ui-locales/ru/common.json +14 -1
  81. package/ui-locales/ru/errors.json +11 -1
  82. package/ui-locales/ru/menu.json +10 -1
  83. package/ui-locales/ru/operations.json +11 -0
  84. package/ui-locales/ru/security.json +2 -1
  85. package/ui-locales/ru/settings.json +60 -9
  86. package/ui-locales/ru/sizing.json +14 -1
  87. package/ui-locales/ru/status.json +18 -1
  88. package/ui-locales/ru/test-complete-system.json +13 -1
  89. package/ui-locales/zh/autorun.json +69 -64
  90. package/ui-locales/zh/common.json +14 -1
  91. package/ui-locales/zh/errors.json +11 -1
  92. package/ui-locales/zh/menu.json +10 -1
  93. package/ui-locales/zh/operations.json +11 -0
  94. package/ui-locales/zh/security.json +2 -1
  95. package/ui-locales/zh/settings.json +60 -9
  96. package/ui-locales/zh/sizing.json +13 -1
  97. package/ui-locales/zh/status.json +25 -8
  98. package/ui-locales/zh/test-complete-system.json +13 -1
  99. package/utils/test-complete-system.js +178 -162
  100. package/ui-locales/de-old.json +0 -705
  101. package/ui-locales/de.json +0 -15
  102. package/ui-locales/en-old.json +0 -709
  103. package/ui-locales/en.json +0 -15
  104. package/ui-locales/es-old.json +0 -654
  105. package/ui-locales/es.json +0 -15
  106. package/ui-locales/fr-old.json +0 -606
  107. package/ui-locales/fr.json +0 -15
  108. package/ui-locales/ja-old.json +0 -660
  109. package/ui-locales/ja.json +0 -15
  110. package/ui-locales/pt.json +0 -15
  111. package/ui-locales/ru-old.json +0 -655
  112. package/ui-locales/ru.json +0 -15
  113. package/ui-locales/zh-old.json +0 -647
  114. package/ui-locales/zh.json +0 -15
@@ -0,0 +1,90 @@
1
+ // This script copies English translation files to other language directories,
2
+ // prefixing the keys with the country code and using the English value as a fallback.
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const uiLocalesPath = path.join(__dirname, '..', 'ui-locales');
8
+ const englishLocalesPath = path.join(uiLocalesPath, 'en');
9
+
10
+ function copyTranslations() {
11
+ console.log('Starting translation copy process...');
12
+
13
+ // Read all English JSON files
14
+ const englishFiles = fs.readdirSync(englishLocalesPath).filter(file => file.endsWith('.json'));
15
+
16
+ // Get all language directories except 'en'
17
+ const languageDirs = fs.readdirSync(uiLocalesPath)
18
+ .filter(dir => fs.statSync(path.join(uiLocalesPath, dir)).isDirectory() && dir !== 'en');
19
+
20
+ for (const lang of languageDirs) {
21
+ console.log(`Processing language: ${lang}`);
22
+ const langPath = path.join(uiLocalesPath, lang);
23
+
24
+ for (const file of englishFiles) {
25
+ const englishFilePath = path.join(englishLocalesPath, file);
26
+ const langFilePath = path.join(langPath, file);
27
+
28
+ try {
29
+ const englishContent = JSON.parse(fs.readFileSync(englishFilePath, 'utf8'));
30
+ let langContent = {};
31
+
32
+ if (fs.existsSync(langFilePath)) {
33
+ langContent = JSON.parse(fs.readFileSync(langFilePath, 'utf8'));
34
+ }
35
+
36
+ let changesMade = false;
37
+
38
+ // Function to recursively synchronize keys
39
+ function synchronizeKeys(source, target, currentPath = '') {
40
+ let currentChanges = false;
41
+
42
+ // Add missing keys from source to target
43
+ for (const key in source) {
44
+ if (Object.hasOwnProperty.call(source, key)) {
45
+ const fullPath = currentPath ? `${currentPath}.${key}` : key;
46
+ if (typeof source[key] === 'object' && source[key] !== null) {
47
+ if (!Object.hasOwnProperty.call(target, key) || typeof target[key] !== 'object' || target[key] === null) {
48
+ target[key] = {};
49
+ currentChanges = true;
50
+ }
51
+ if (synchronizeKeys(source[key], target[key], fullPath)) {
52
+ currentChanges = true;
53
+ }
54
+ } else {
55
+ if (!Object.hasOwnProperty.call(target, key)) {
56
+ target[key] = `[${lang.toUpperCase()}] ${source[key]}`;
57
+ currentChanges = true;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ // Remove extra keys from target that are not in source
64
+ for (const key in target) {
65
+ if (Object.hasOwnProperty.call(target, key)) {
66
+ if (!Object.hasOwnProperty.call(source, key)) {
67
+ delete target[key];
68
+ currentChanges = true;
69
+ }
70
+ }
71
+ }
72
+ return currentChanges;
73
+ }
74
+
75
+ if (synchronizeKeys(englishContent, langContent)) {
76
+ fs.writeFileSync(langFilePath, JSON.stringify(langContent, null, 2), 'utf8');
77
+ console.log(` Updated ${file} for ${lang}`);
78
+ } else {
79
+ console.log(` No changes needed for ${file} in ${lang}`);
80
+ }
81
+
82
+ } catch (error) {
83
+ console.error(`Error processing ${file} for ${lang}: ${error.message}`);
84
+ }
85
+ }
86
+ }
87
+ console.log('Translation copy process completed.');
88
+ }
89
+
90
+ copyTranslations();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "language": "en",
3
3
  "sizeLimit": null,
4
- "sourceDir": "./locales",
4
+ "sourceDir": "./src/i18n/locales",
5
5
  "sourceLanguage": "en",
6
6
  "defaultLanguages": [
7
7
  "de",
@@ -10,6 +10,16 @@
10
10
  "ru"
11
11
  ],
12
12
  "outputDir": "./i18ntk-reports",
13
+ "scriptDirectories": {
14
+ "analyze": "/src/i18n/locales/test/",
15
+ "init": null,
16
+ "validate": null,
17
+ "complete": null,
18
+ "manage": null,
19
+ "summary": null,
20
+ "usage": null,
21
+ "sizing": null
22
+ },
13
23
  "reportLanguage": "auto",
14
24
  "theme": "light",
15
25
  "autoSave": true,
@@ -68,7 +68,7 @@ class SettingsCLI {
68
68
  this.schema = settingsManager.getSettingsSchema();
69
69
  return true;
70
70
  } catch (error) {
71
- this.error(`Failed to initialize settings: ${error.message}`);
71
+ this.error(this.t('settings.initFailed', { error: error.message }));
72
72
  return false;
73
73
  }
74
74
  }
@@ -113,7 +113,7 @@ class SettingsCLI {
113
113
  console.log(colors.reset);
114
114
 
115
115
  if (this.modified) {
116
- console.log(`${colors.yellow}⚠️ You have unsaved changes${colors.reset}\n`);
116
+ console.log(`${colors.yellow}${this.t('settings.mainMenu.unsavedChangesWarning')}${colors.reset}\n`);
117
117
  }
118
118
  }
119
119
 
@@ -124,12 +124,14 @@ class SettingsCLI {
124
124
  const options = [
125
125
  { key: '1', label: this.t('settings.mainMenu.uiSettings'), description: this.t('settings.mainMenu.uiSettingsDesc') },
126
126
  { key: '2', label: this.t('settings.mainMenu.directorySettings'), description: this.t('settings.mainMenu.directorySettingsDesc') },
127
- { key: '3', label: this.t('settings.mainMenu.processingSettings'), description: this.t('settings.mainMenu.processingSettingsDesc') },
128
- { key: '4', label: this.t('settings.mainMenu.advancedSettings'), description: this.t('settings.mainMenu.advancedSettingsDesc') },
129
- { key: '5', label: this.t('settings.mainMenu.viewAllSettings'), description: this.t('settings.mainMenu.viewAllSettingsDesc') },
130
- { key: '6', label: this.t('settings.mainMenu.importExport'), description: this.t('settings.mainMenu.importExportDesc') },
131
- { key: '7', label: this.t('settings.mainMenu.resetToDefaults'), description: this.t('settings.mainMenu.resetToDefaultsDesc') },
132
- { key: '8', label: this.t('settings.mainMenu.reportBug'), description: this.t('settings.mainMenu.reportBugDesc') },
127
+ { key: '3', label: this.t('settings.mainMenu.scriptDirectorySettings'), description: this.t('settings.mainMenu.scriptDirectorySettingsDesc') },
128
+ { key: '4', label: this.t('settings.mainMenu.processingSettings'), description: this.t('settings.mainMenu.processingSettingsDesc') },
129
+ { key: '5', label: this.t('settings.mainMenu.advancedSettings'), description: this.t('settings.mainMenu.advancedSettingsDesc') },
130
+ { key: '6', label: this.t('settings.mainMenu.viewAllSettings'), description: this.t('settings.mainMenu.viewAllSettingsDesc') },
131
+ { key: '7', label: this.t('settings.mainMenu.importExport'), description: this.t('settings.mainMenu.importExportDesc') },
132
+ { key: '8', label: this.t('settings.mainMenu.resetToDefaults'), description: this.t('settings.mainMenu.resetToDefaultsDesc') },
133
+ { key: '9', label: this.t('settings.mainMenu.reportBug'), description: this.t('settings.mainMenu.reportBugDesc') },
134
+ { key: '0', label: this.t('settings.mainMenu.updatePackage'), description: this.t('settings.mainMenu.updatePackageDesc') },
133
135
  { key: 's', label: this.t('settings.mainMenu.saveChanges'), description: this.t('settings.mainMenu.saveChangesDesc') },
134
136
  { key: 'h', label: this.t('settings.mainMenu.help'), description: this.t('settings.mainMenu.helpDesc') },
135
137
  { key: 'q', label: this.t('settings.mainMenu.quit'), description: this.t('settings.mainMenu.quitDesc') }
@@ -160,23 +162,29 @@ class SettingsCLI {
160
162
  await this.showDirectorySettings();
161
163
  break;
162
164
  case '3':
163
- await this.showProcessingSettings();
165
+ await this.showScriptDirectorySettings();
164
166
  break;
165
167
  case '4':
166
- await this.showAdvancedSettings();
168
+ await this.showProcessingSettings();
167
169
  break;
168
170
  case '5':
169
- await this.showAllSettings();
171
+ await this.showAdvancedSettings();
170
172
  break;
171
173
  case '6':
172
- await this.showImportExport();
174
+ await this.showAllSettings();
173
175
  break;
174
176
  case '7':
175
- await this.resetToDefaults();
177
+ await this.showImportExport();
176
178
  break;
177
179
  case '8':
180
+ await this.resetToDefaults();
181
+ break;
182
+ case '9':
178
183
  await this.reportBug();
179
184
  break;
185
+ case '0':
186
+ await this.updatePackage();
187
+ break;
180
188
  case 's':
181
189
  await this.saveSettings();
182
190
  break;
@@ -231,6 +239,30 @@ class SettingsCLI {
231
239
  await this.showSettingsCategory(dirSettings);
232
240
  }
233
241
 
242
+ /**
243
+ * Show script-specific directory settings menu
244
+ */
245
+ async showScriptDirectorySettings() {
246
+ this.clearScreen();
247
+ this.showHeader();
248
+ console.log(`${colors.bright}${this.t('settings.categories.scriptDirectorySettings')}${colors.reset}\n`);
249
+ console.log(`📁 ${colors.cyan}${this.t('settings.currentDirectory')}: ${process.cwd()}${colors.reset}`);
250
+ console.log(`💡 ${colors.dim}${this.t('settings.relativePathHint')}${colors.reset}\n`);
251
+
252
+ const scriptDirSettings = {
253
+ 'scriptDirectories.analyze': this.t('settings.fields.scriptDirectories.analyzeLabel'),
254
+ 'scriptDirectories.complete': this.t('settings.fields.scriptDirectories.completeLabel'),
255
+ 'scriptDirectories.init': this.t('settings.fields.scriptDirectories.initLabel'),
256
+ 'scriptDirectories.manage': this.t('settings.fields.scriptDirectories.manageLabel'),
257
+ 'scriptDirectories.sizing': this.t('settings.fields.scriptDirectories.sizingLabel'),
258
+ 'scriptDirectories.summary': this.t('settings.fields.scriptDirectories.summaryLabel'),
259
+ 'scriptDirectories.usage': this.t('settings.fields.scriptDirectories.usageLabel'),
260
+ 'scriptDirectories.validate': this.t('settings.fields.scriptDirectories.validateLabel')
261
+ };
262
+
263
+ await this.showSettingsCategory(scriptDirSettings);
264
+ }
265
+
234
266
  /**
235
267
  * Show processing settings menu
236
268
  */
@@ -402,7 +434,7 @@ class SettingsCLI {
402
434
 
403
435
  // Check if admin authentication is required
404
436
  if (this.requiresAdminAuth(key) && !this.adminAuthenticated) {
405
- console.log(`\n🔒 Admin authentication required for: ${label}`);
437
+ console.log(`\n${this.t('settings.admin.authRequired', { label: label })}`);
406
438
  const authenticated = await this.adminPin.verifyPin();
407
439
  if (!authenticated) {
408
440
  console.log(this.t('settings.admin.accessDenied'));
@@ -461,7 +493,7 @@ class SettingsCLI {
461
493
  // Convert the value
462
494
  const convertedValue = this.convertValue(newValue.trim(), schema);
463
495
  if (convertedValue === null) {
464
- this.error('Invalid value format.');
496
+ this.error(this.t('settings.invalidValueFormat'));
465
497
  await this.pause();
466
498
  return;
467
499
  }
@@ -499,7 +531,7 @@ class SettingsCLI {
499
531
  async handlePinSetup() {
500
532
  this.clearScreen();
501
533
  this.showHeader();
502
- console.log(`${colors.bright}Admin PIN Setup${colors.reset}\n`);
534
+ console.log(`${colors.bright}${this.t('settings.admin.pinSetupTitle')}${colors.reset}\n`);
503
535
 
504
536
  if (this.adminPin.isPinSet()) {
505
537
  console.log(this.t('settings.admin.pinConfigured'));
@@ -509,7 +541,7 @@ class SettingsCLI {
509
541
  console.log(' ' + this.t('settings.admin.cancel'));
510
542
  console.log();
511
543
 
512
- const choice = await this.prompt('Select option: ');
544
+ const choice = await this.prompt(this.t('settings.admin.selectOption'));
513
545
 
514
546
  switch (choice) {
515
547
  case '1':
@@ -542,7 +574,7 @@ class SettingsCLI {
542
574
  console.log(this.t('settings.admin.operationCancelled'));
543
575
  break;
544
576
  default:
545
- this.error('Invalid option.');
577
+ this.error(this.t('common.invalidOption'));
546
578
  }
547
579
  } else {
548
580
  console.log(this.t('settings.admin.noPinConfigured'));
@@ -553,7 +585,7 @@ class SettingsCLI {
553
585
  console.log(' ' + this.t('settings.admin.benefitReset'));
554
586
  console.log();
555
587
 
556
- const response = await this.prompt('Would you like to set up an admin PIN? (y/N): ');
588
+ const response = await this.prompt(this.t('settings.admin.setupPinPrompt'));
557
589
 
558
590
  if (response.toLowerCase() === 'y' || response.toLowerCase() === 'yes') {
559
591
  const success = await this.adminPin.setupPin();
@@ -640,7 +672,7 @@ class SettingsCLI {
640
672
  * Export settings to a file
641
673
  */
642
674
  async exportSettings() {
643
- const filename = await this.prompt('Enter filename (or press Enter for default): ');
675
+ const filename = await this.prompt(this.t('settings.importExport.exportFilenamePrompt'));
644
676
  const exportFile = filename.trim() || `i18n-settings-${new Date().toISOString().split('T')[0]}.json`;
645
677
 
646
678
  try {
@@ -657,7 +689,7 @@ class SettingsCLI {
657
689
  * Import settings from a file
658
690
  */
659
691
  async importSettings() {
660
- const filename = await this.prompt('Enter filename to import: ');
692
+ const filename = await this.prompt(this.t('settings.importExport.importFilenamePrompt'));
661
693
 
662
694
  if (!filename.trim()) {
663
695
  return;
@@ -679,7 +711,7 @@ class SettingsCLI {
679
711
  return;
680
712
  }
681
713
 
682
- const confirm = await this.prompt('This will replace all current settings. Continue? (y/N): ');
714
+ const confirm = await this.prompt(this.t('settings.importExport.importConfirm'));
683
715
  if (confirm.toLowerCase() === 'y') {
684
716
  this.settings = importedSettings;
685
717
  this.modified = true;
@@ -712,12 +744,11 @@ class SettingsCLI {
712
744
  async resetToDefaults() {
713
745
  this.clearScreen();
714
746
  this.showHeader();
715
- console.log(`${colors.bright}Reset to Defaults${colors.reset}\n`);
716
-
717
- console.log(`${colors.yellow}⚠️ This will reset ALL settings to their default values.${colors.reset}`);
718
- console.log(`${colors.yellow}⚠️ Any unsaved changes will be lost.${colors.reset}\n`);
747
+ console.log(`${colors.bright}${this.t('settings.resetToDefaultsTitle')}${colors.reset}\n`);
748
+ console.log(`${colors.yellow}${this.t('settings.resetWarning1')}${colors.reset}`);
749
+ console.log(`${colors.yellow}${this.t('settings.resetWarning2')}${colors.reset}\n`);
719
750
 
720
- const confirm = await this.prompt('Are you sure you want to continue? (y/N): ');
751
+ const confirm = await this.prompt(this.t('settings.resetConfirm'));
721
752
 
722
753
  if (confirm.toLowerCase() === 'y') {
723
754
  try {
@@ -758,31 +789,30 @@ class SettingsCLI {
758
789
  async showHelp() {
759
790
  this.clearScreen();
760
791
  this.showHeader();
761
- console.log(`${colors.bright}Help Information${colors.reset}\n`);
762
-
763
- console.log(`${colors.cyan}Navigation:${colors.reset}`);
764
- console.log(` • Use number keys to select menu options`);
765
- console.log(` • Use 'b' to go back to previous menu`);
766
- console.log(` • Use 'q' to quit (with save prompt if needed)`);
767
- console.log(` • Use 's' to save changes at any time\n`);
768
-
769
- console.log(`${colors.cyan}Settings Categories:${colors.reset}`);
770
- console.log(` • UI Settings: Interface language, theme, and display options`);
771
- console.log(` • Directory Settings: Paths for locales, reports, and backups`);
772
- console.log(` • Processing Settings: Performance and batch processing options`);
773
- console.log(` • Advanced Settings: Validation, logging, and expert features\n`);
774
-
775
- console.log(`${colors.cyan}Environment Variables:${colors.reset}`);
776
- console.log(` • I18N_CONFIG_FILE: Custom config file path`);
777
- console.log(` • I18N_LOCALE_DIR: Override locales directory`);
778
- console.log(` • I18N_REPORTS_DIR: Override reports directory\n`);
779
-
780
- console.log(`${colors.cyan}Command Line Usage:${colors.reset}`);
781
- console.log(` • i18ntk manage --command=settings`);
782
- console.log(` • node settings-cli.js (direct access)`);
783
- console.log(` • All scripts support --config flag for custom config files\n`);
784
-
785
- console.log(`Press Enter to continue...`);
792
+ console.log(`${colors.bright}${this.t('settings.help.title')}${colors.reset}\n`);
793
+ console.log(`${colors.cyan}${this.t('settings.help.navigationTitle')}${colors.reset}`);
794
+ console.log(`${this.t('settings.help.navigation1')}`);
795
+ console.log(`${this.t('settings.help.navigation2')}`);
796
+ console.log(`${this.t('settings.help.navigation3')}`);
797
+ console.log(`${this.t('settings.help.navigation4')}\n`);
798
+
799
+ console.log(`${colors.cyan}${this.t('settings.help.categoriesTitle')}${colors.reset}`);
800
+ console.log(`${this.t('settings.help.categoryUI')}`);
801
+ console.log(`${this.t('settings.help.categoryDirectory')}`);
802
+ console.log(`${this.t('settings.help.categoryProcessing')}`);
803
+ console.log(`${this.t('settings.help.categoryAdvanced')}\n`);
804
+
805
+ console.log(`${colors.cyan}${this.t('settings.help.envVarsTitle')}${colors.reset}`);
806
+ console.log(`${this.t('settings.help.envVar1')}`);
807
+ console.log(`${this.t('settings.help.envVar2')}`);
808
+ console.log(`${this.t('settings.help.envVar3')}\n`);
809
+
810
+ console.log(`${colors.cyan}${this.t('settings.help.cliUsageTitle')}${colors.reset}`);
811
+ console.log(`${this.t('settings.help.cliUsage1')}`);
812
+ console.log(`${this.t('settings.help.cliUsage2')}`);
813
+ console.log(`${this.t('settings.help.cliUsage3')}\n`);
814
+
815
+ console.log(`${this.t('settings.pressEnter')}\n`);
786
816
  await this.prompt('');
787
817
  }
788
818
 
@@ -792,19 +822,12 @@ class SettingsCLI {
792
822
  async reportBug() {
793
823
  this.clearScreen();
794
824
  this.showHeader();
795
- console.log(`${colors.bright}Report a Bug${colors.reset}\n`);
796
-
797
- console.log(`${colors.cyan}GitHub Issues Page:${colors.reset}`);
798
- console.log(`https://github.com/vladnoskv/i18n-management-toolkit-main/issues\n`);
799
-
800
- console.log(`${colors.yellow}Before reporting a bug, please:${colors.reset}`);
801
- console.log(` • Check if the issue already exists`);
802
- console.log(` • Include steps to reproduce the problem`);
803
- console.log(` • Provide error messages and logs`);
804
- console.log(` • Mention your operating system and Node.js version\n`);
805
-
806
- console.log(`${colors.cyan}Opening GitHub issues page...${colors.reset}`);
807
-
825
+ console.log(`${colors.bright}${this.t('settings.reportBug.title')}${colors.reset}\n`);
826
+ console.log(this.t('settings.reportBug.description'));
827
+ console.log(`
828
+ ${colors.dim}${this.t('settings.reportBug.link')}: https://github.com/vladnoskv/i18n-management-toolkit-main/issues${colors.reset}
829
+ `);
830
+
808
831
  try {
809
832
  const { exec } = require('child_process');
810
833
  const url = 'https://github.com/vladnoskv/i18n-management-toolkit-main/issues';
@@ -825,34 +848,72 @@ class SettingsCLI {
825
848
 
826
849
  exec(command, (error) => {
827
850
  if (error) {
828
- console.log(`${colors.yellow}Could not automatically open browser.${colors.reset}`);
829
- console.log(`Please manually visit: ${url}`);
851
+ console.log(`${colors.yellow}${this.t('settings.reportBug.browserOpenFailed')}${colors.reset}`);
852
+ console.log(`${this.t('settings.reportBug.manualVisit', { url: url })}`);
830
853
  } else {
831
- console.log(`${colors.green}✅ Browser opened successfully!${colors.reset}`);
854
+ console.log(`${colors.green}${this.t('settings.reportBug.browserOpened')}${colors.reset}`);
832
855
  }
833
856
  });
834
857
  } catch (error) {
835
- console.log(`${colors.yellow}Could not automatically open browser.${colors.reset}`);
836
- console.log(`Please manually visit: https://github.com/vladnoskv/i18n-management-toolkit-main/issues`);
858
+ console.log(`${colors.yellow}${this.t('settings.reportBug.browserOpenFailed')}${colors.reset}`);
859
+ console.log(`${this.t('settings.reportBug.manualVisit', { url: 'https://github.com/vladnoskv/i18n-management-toolkit-main/issues' })}`);
837
860
  }
838
861
 
839
862
  await this.pause();
840
863
  }
841
864
 
865
+ /**
866
+ * Update the i18n-toolkit package via npm
867
+ */
868
+ async updatePackage() {
869
+ this.clearScreen();
870
+ this.showHeader();
871
+ console.log(`${colors.bright}${this.t('settings.updatePackage.title')}${colors.reset}\n`);
872
+ console.log(this.t('settings.updatePackage.description'));
873
+ console.log(`
874
+ ${colors.dim}${this.t('settings.updatePackage.command')}: npm update i18ntk -g${colors.reset}
875
+ `);
876
+
877
+ const confirm = await this.prompt(this.t('settings.updatePackage.prompt'));
878
+
879
+ if (confirm.toLowerCase() === 'y') {
880
+ try {
881
+ const { exec } = require('child_process');
882
+ console.log(this.t('settings.updatePackage.updating'));
883
+ exec('npm update i18ntk -g', (error, stdout, stderr) => {
884
+ if (error) {
885
+ this.error(`${this.t('settings.updatePackage.error')}: ${error.message}`);
886
+ console.error(stderr);
887
+ } else {
888
+ this.success(this.t('settings.updatePackage.success'));
889
+ console.log(stdout);
890
+ }
891
+ this.pause();
892
+ });
893
+ } catch (error) {
894
+ this.error(`${this.t('settings.updatePackage.error')}: ${error.message}`);
895
+ this.pause();
896
+ }
897
+ } else {
898
+ this.warning(this.t('settings.updatePackage.cancelled'));
899
+ await this.pause();
900
+ }
901
+ }
902
+
842
903
  /**
843
904
  * Quit the application
844
905
  */
845
906
  async quit() {
846
907
  if (this.modified) {
847
- console.log(`\n${colors.yellow}⚠️ You have unsaved changes.${colors.reset}`);
848
- const save = await this.prompt('Save before quitting? (Y/n): ');
849
-
908
+ console.log(`\n${colors.yellow}${this.t('settings.mainMenu.unsavedChangesWarning')}${colors.reset}`);
909
+ const save = await this.prompt(this.t('settings.mainMenu.saveChangesBeforeQuit'));
910
+
850
911
  if (save.toLowerCase() !== 'n') {
851
912
  await this.saveSettings();
852
913
  }
853
914
  }
854
-
855
- console.log(`\n${colors.green}Thank you for using the i18n settings manager!${colors.reset}`);
915
+
916
+ console.log(`\n${colors.green}${this.t('settings.goodbyeMessage')}${colors.reset}`);
856
917
  this.rl.close();
857
918
  process.exit(0);
858
919
  }
@@ -22,6 +22,18 @@ class SettingsManager {
22
22
  defaultLanguages: ['de', 'es', 'fr', 'ru'], // Default target languages | Example: ['de', 'es', 'fr', 'ru', 'ja', 'zh']
23
23
  outputDir: './i18ntk-reports', // Default: './i18ntk-reports' | Example: './reports/i18n'
24
24
 
25
+ // Per-Script Directory Configuration (optional overrides)
26
+ scriptDirectories: {
27
+ analyze: null, // Custom sourceDir for i18ntk-analyze.js
28
+ init: null, // Custom sourceDir for i18ntk-init.js
29
+ validate: null, // Custom sourceDir for i18ntk-validate.js
30
+ complete: null, // Custom sourceDir for i18ntk-complete.js
31
+ manage: null, // Custom sourceDir for i18ntk-manage.js
32
+ summary: null, // Custom sourceDir for i18ntk-summary.js
33
+ usage: null, // Custom sourceDir for i18ntk-usage.js
34
+ sizing: null // Custom sourceDir for i18ntk-sizing.js
35
+ },
36
+
25
37
  // Report Settings
26
38
  reportLanguage: 'auto', // Default: 'auto' (matches UI language) | Options: 'auto', 'en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'
27
39
 
@@ -158,6 +170,13 @@ class SettingsManager {
158
170
  merged.advanced = { ...this.defaultConfig.advanced, ...loadedSettings.advanced };
159
171
  }
160
172
 
173
+ if (loadedSettings.scriptDirectories) {
174
+ merged.scriptDirectories = {
175
+ ...this.defaultConfig.scriptDirectories,
176
+ ...loadedSettings.scriptDirectories
177
+ };
178
+ }
179
+
161
180
  return merged;
162
181
  }
163
182