i18ntk 2.0.4 → 2.2.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 (57) hide show
  1. package/README.md +38 -60
  2. package/main/i18ntk-analyze.js +49 -44
  3. package/main/i18ntk-complete.js +75 -74
  4. package/main/i18ntk-fixer.js +3 -3
  5. package/main/i18ntk-init.js +5 -5
  6. package/main/i18ntk-scanner.js +2 -2
  7. package/main/i18ntk-sizing.js +35 -35
  8. package/main/i18ntk-summary.js +4 -4
  9. package/main/i18ntk-ui.js +54 -8
  10. package/main/i18ntk-usage.js +14 -14
  11. package/main/i18ntk-validate.js +6 -5
  12. package/main/manage/commands/AnalyzeCommand.js +40 -35
  13. package/main/manage/commands/FixerCommand.js +2 -2
  14. package/main/manage/commands/ScannerCommand.js +2 -2
  15. package/main/manage/commands/ValidateCommand.js +9 -9
  16. package/main/manage/index.js +147 -75
  17. package/main/manage/managers/LanguageMenu.js +7 -2
  18. package/main/manage/services/UsageService.js +7 -7
  19. package/package.json +269 -290
  20. package/settings/settings-cli.js +3 -3
  21. package/ui-locales/de.json +161 -166
  22. package/ui-locales/en.json +13 -18
  23. package/ui-locales/es.json +171 -184
  24. package/ui-locales/fr.json +155 -161
  25. package/ui-locales/ja.json +192 -243
  26. package/ui-locales/ru.json +145 -196
  27. package/ui-locales/zh.json +179 -185
  28. package/utils/cli-helper.js +26 -98
  29. package/utils/extractors/regex.js +39 -12
  30. package/utils/i18n-helper.js +88 -40
  31. package/{scripts → utils}/locale-optimizer.js +61 -60
  32. package/utils/security-check-improved.js +16 -13
  33. package/utils/security.js +6 -4
  34. package/main/i18ntk-go.js +0 -283
  35. package/main/i18ntk-java.js +0 -380
  36. package/main/i18ntk-js.js +0 -512
  37. package/main/i18ntk-manage.js +0 -1694
  38. package/main/i18ntk-php.js +0 -462
  39. package/main/i18ntk-py.js +0 -379
  40. package/main/i18ntk-settings.js +0 -23
  41. package/main/manage/index-fixed.js +0 -1447
  42. package/main/manage/services/ConfigurationService-fixed.js +0 -449
  43. package/scripts/build-lite.js +0 -279
  44. package/scripts/deprecate-versions.js +0 -317
  45. package/scripts/export-translations.js +0 -84
  46. package/scripts/fix-all-i18n.js +0 -215
  47. package/scripts/fix-and-purify-i18n.js +0 -213
  48. package/scripts/fix-locale-control-chars.js +0 -110
  49. package/scripts/lint-locales.js +0 -80
  50. package/scripts/prepublish.js +0 -348
  51. package/scripts/security-check.js +0 -117
  52. package/scripts/sync-translations.js +0 -151
  53. package/scripts/sync-ui-locales.js +0 -20
  54. package/scripts/validate-all-translations.js +0 -139
  55. package/scripts/verify-deprecations.js +0 -157
  56. package/scripts/verify-translations.js +0 -63
  57. package/utils/security-fixed.js +0 -607
@@ -41,8 +41,8 @@ class ScannerCommand {
41
41
  }
42
42
 
43
43
  loadLocale() {
44
- const uiLocalesDir = path.join(__dirname, '../../../resources', 'i18n', 'ui-locales');
45
- const localeFile = path.join(uiLocalesDir, 'en.json');
44
+ const uiLocalesDir = path.join(__dirname, '../../../ui-locales');
45
+ const localeFile = path.join(uiLocalesDir, 'en.json');
46
46
 
47
47
  try {
48
48
  const localeContent = SecurityUtils.safeReadFileSync(localeFile, uiLocalesDir, 'utf8');
@@ -14,13 +14,13 @@ const configManager = require('../../../utils/config-manager');
14
14
  const SecurityUtils = require('../../../utils/security');
15
15
  const AdminCLI = require('../../../utils/admin-cli');
16
16
  const watchLocales = require('../../../utils/watch-locales');
17
- const { getGlobalReadline, closeGlobalReadline } = require('../../../utils/cli');
18
- const { getUnifiedConfig, parseCommonArgs, displayHelp, validateSourceDir, displayPaths } = require('../../../utils/config-helper');
19
- const I18nInitializer = require('../../i18ntk-init');
20
- const JsonOutput = require('../../../utils/json-output');
21
- const ExitCodes = require('../../../utils/exit-codes');
22
-
23
- loadTranslations('en', path.resolve(__dirname, '../../../resources', 'i18n', 'ui-locales'));
17
+ const { getGlobalReadline, closeGlobalReadline } = require('../../../utils/cli');
18
+ const { getUnifiedConfig, parseCommonArgs, displayHelp, validateSourceDir, displayPaths } = require('../../../utils/config-helper');
19
+ const I18nInitializer = require('../../i18ntk-init');
20
+ const JsonOutput = require('../../../utils/json-output');
21
+ const ExitCodes = require('../../../utils/exit-codes');
22
+
23
+ loadTranslations('en', path.resolve(__dirname, '../../../ui-locales'));
24
24
 
25
25
  class ValidateCommand {
26
26
  constructor(config = {}, ui = null) {
@@ -68,7 +68,7 @@ class ValidateCommand {
68
68
  this.config = { ...baseConfig, ...(this.config || {}) };
69
69
 
70
70
  const uiLanguage = (this.config && this.config.uiLanguage) || 'en';
71
- loadTranslations(uiLanguage, path.resolve(__dirname, '../../../resources', 'i18n', 'ui-locales'));
71
+ loadTranslations(uiLanguage, path.resolve(__dirname, '../../../ui-locales'));
72
72
 
73
73
  SecurityUtils.logSecurityEvent(
74
74
  'I18n validator initializing',
@@ -975,4 +975,4 @@ class ValidateCommand {
975
975
  }
976
976
  }
977
977
 
978
- module.exports = ValidateCommand;
978
+ module.exports = ValidateCommand;
@@ -151,13 +151,40 @@ class I18nManager {
151
151
  }
152
152
  }
153
153
 
154
- // Check if i18n framework is installed - configuration-based check without prompts
155
- async checkI18nDependencies() {
156
- const packageJsonPath = path.resolve('./package.json');
157
-
158
- if (!SecurityUtils.safeExistsSync(packageJsonPath)) {
159
- console.log(this.ui ? this.ui.t('errors.noPackageJson') : 'No package.json found');
160
- return false; // Treat as no framework detected
154
+ // Check if i18n framework is installed - configuration-based check without prompts
155
+ async checkI18nDependencies() {
156
+ const markInternalFrameworkDetected = () => {
157
+ const cfg = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
158
+ cfg.framework = cfg.framework || {};
159
+ cfg.framework.detected = true;
160
+ cfg.framework.preference = cfg.framework.preference || 'i18ntk';
161
+ const existing = Array.isArray(cfg.framework.installed) ? cfg.framework.installed : [];
162
+ if (!existing.includes('i18ntk')) {
163
+ cfg.framework.installed = [...existing, 'i18ntk'];
164
+ }
165
+ if (configManager.saveSettings) {
166
+ configManager.saveSettings(cfg);
167
+ } else if (configManager.saveConfig) {
168
+ configManager.saveConfig(cfg);
169
+ }
170
+ };
171
+
172
+ try {
173
+ const { checkInitialized } = require('../../utils/init-helper');
174
+ const initStatus = await checkInitialized();
175
+ if (initStatus?.initialized || initStatus?.config?.setup?.completed) {
176
+ markInternalFrameworkDetected();
177
+ return true;
178
+ }
179
+ } catch (_) {
180
+ // Continue with package.json detection.
181
+ }
182
+
183
+ const packageJsonPath = path.resolve('./package.json');
184
+
185
+ if (!SecurityUtils.safeExistsSync(packageJsonPath)) {
186
+ console.log(this.ui ? this.ui.t('errors.noPackageJson') : 'No package.json found');
187
+ return false; // Treat as no framework detected
161
188
  }
162
189
 
163
190
  try {
@@ -174,11 +201,12 @@ class I18nManager {
174
201
  'vue-i18n',
175
202
  'angular-i18n',
176
203
  'i18next',
177
- 'next-i18next',
178
- 'svelte-i18n',
179
- '@nuxtjs/i18n',
180
- 'i18ntk-runtime'
181
- ];
204
+ 'next-i18next',
205
+ 'svelte-i18n',
206
+ '@nuxtjs/i18n',
207
+ 'i18ntk-runtime',
208
+ 'i18ntk'
209
+ ];
182
210
 
183
211
  const installedFrameworks = i18nFrameworks.filter(framework => dependencies[framework]);
184
212
 
@@ -484,21 +512,39 @@ class I18nManager {
484
512
  const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
485
513
 
486
514
  // Ensure framework configuration exists with all required fields
487
- if (!settings.framework) {
488
- settings.framework = {
489
- detected: false,
490
- preference: null,
491
- prompt: 'always',
515
+ if (!settings.framework) {
516
+ settings.framework = {
517
+ detected: false,
518
+ preference: null,
519
+ prompt: 'always',
492
520
  lastPromptedVersion: null,
493
521
  installed: [],
494
- version: '1.0' // Schema version for future compatibility
495
- };
496
- }
497
-
498
- // Check if we need to prompt for framework detection
499
- if (!settings.framework.detected &&
500
- settings.framework.prompt !== 'suppress' &&
501
- settings.framework.lastPromptedVersion !== pkg.version) {
522
+ version: '1.0' // Schema version for future compatibility
523
+ };
524
+ }
525
+
526
+ const setupCompleted = Boolean(config?.setup?.completed || settings?.setup?.completed);
527
+ if (setupCompleted) {
528
+ settings.framework.detected = true;
529
+ settings.framework.preference = settings.framework.preference || 'i18ntk';
530
+ settings.framework.installed = Array.isArray(settings.framework.installed)
531
+ ? Array.from(new Set([...settings.framework.installed, 'i18ntk']))
532
+ : ['i18ntk'];
533
+ settings.framework.lastDetected = new Date().toISOString();
534
+
535
+ if (configManager.saveSettings) {
536
+ await configManager.saveSettings(settings);
537
+ } else if (configManager.saveConfig) {
538
+ await configManager.saveConfig(settings);
539
+ }
540
+
541
+ return { ...config, ...settings };
542
+ }
543
+
544
+ // Check if we need to prompt for framework detection
545
+ if (!settings.framework.detected &&
546
+ settings.framework.prompt !== 'suppress' &&
547
+ settings.framework.lastPromptedVersion !== pkg.version) {
502
548
 
503
549
  console.log('\nWe noticed you haven\'t set up an i18n framework yet.');
504
550
  console.log('Would you like to detect your i18n framework automatically?');
@@ -557,11 +603,11 @@ class I18nManager {
557
603
  return { ...config, ...settings };
558
604
  }
559
605
 
560
- async detectEnvironmentAndFramework() {
561
- // Defensive check to ensure SecurityUtils is available
562
- if (!SecurityUtils) {
563
- throw new Error('SecurityUtils is not available. This may indicate a module loading issue.');
564
- }
606
+ async detectEnvironmentAndFramework() {
607
+ // Defensive check to ensure SecurityUtils is available
608
+ if (!SecurityUtils) {
609
+ throw new Error('SecurityUtils is not available. This may indicate a module loading issue.');
610
+ }
565
611
  const fs = require('fs');
566
612
  const path = require('path');
567
613
 
@@ -572,13 +618,23 @@ class I18nManager {
572
618
  const pomPath = path.join(process.cwd(), 'pom.xml');
573
619
  const composerPath = path.join(process.cwd(), 'composer.json');
574
620
 
575
- let detectedLanguage = 'generic';
576
- let detectedFramework = 'generic';
577
-
578
- if (SecurityUtils.safeExistsSync(packageJsonPath)) {
579
- detectedLanguage = 'javascript';
580
- try {
581
- const packageJson = JSON.parse(SecurityUtils.safeReadFileSync(packageJsonPath, path.dirname(packageJsonPath), 'utf8'));
621
+ let detectedLanguage = 'generic';
622
+ let detectedFramework = 'generic';
623
+
624
+ try {
625
+ const { checkInitialized } = require('../../utils/init-helper');
626
+ const initStatus = await checkInitialized();
627
+ if (initStatus?.initialized || initStatus?.config?.setup?.completed) {
628
+ return { detectedLanguage: 'javascript', detectedFramework: 'i18ntk' };
629
+ }
630
+ } catch (_) {
631
+ // Continue with filesystem/package detection.
632
+ }
633
+
634
+ if (SecurityUtils.safeExistsSync(packageJsonPath)) {
635
+ detectedLanguage = 'javascript';
636
+ try {
637
+ const packageJson = JSON.parse(SecurityUtils.safeReadFileSync(packageJsonPath, path.dirname(packageJsonPath), 'utf8'));
582
638
  const deps = {
583
639
  ...(packageJson.dependencies || {}),
584
640
  ...(packageJson.devDependencies || {}),
@@ -586,13 +642,18 @@ class I18nManager {
586
642
  };
587
643
 
588
644
  // Check for i18ntk-runtime first (check both package names)
589
- const hasI18nTkRuntime = deps['i18ntk-runtime'] || deps['i18ntk/runtime'];
590
-
591
- // Check for common i18n patterns in source code if not found in package.json
592
- if (!hasI18nTkRuntime) {
593
- const i18nPatterns = [
594
- /i18n\.t\(['\"`]/,
595
- /useI18n\(/,
645
+ const hasI18nTkRuntime = deps['i18ntk-runtime'] || deps['i18ntk/runtime'];
646
+ const hasI18nTkToolkit = Boolean(deps['i18ntk']);
647
+
648
+ if (hasI18nTkToolkit) {
649
+ detectedFramework = 'i18ntk';
650
+ }
651
+
652
+ // Check for common i18n patterns in source code if not found in package.json
653
+ if (!hasI18nTkRuntime && detectedFramework !== 'i18ntk') {
654
+ const i18nPatterns = [
655
+ /i18n\.t\(['\"`]/,
656
+ /useI18n\(/,
596
657
  /from ['\"]i18ntk[\/\\]runtime['\"]/,
597
658
  /require\(['\"]i18ntk[\/\\]runtime['\"]\)/
598
659
  ];
@@ -614,9 +675,9 @@ class I18nManager {
614
675
  continue;
615
676
  }
616
677
  }
617
- } else {
618
- detectedFramework = 'i18ntk-runtime';
619
- }
678
+ } else if (hasI18nTkRuntime) {
679
+ detectedFramework = 'i18ntk-runtime';
680
+ }
620
681
 
621
682
  // Only check other frameworks if i18ntk-runtime wasn't detected
622
683
  if (detectedFramework !== 'i18ntk-runtime') {
@@ -850,27 +911,34 @@ class I18nManager {
850
911
  const choice = await this.prompt('\n' + t('menu.selectOptionPrompt'));
851
912
 
852
913
  switch (choice.trim()) {
853
- case '1':
854
- await this.executeCommand('init', {fromMenu: true});
855
- break;
856
- case '2':
857
- await this.executeCommand('analyze', {fromMenu: true});
858
- break;
859
- case '3':
860
- await this.executeCommand('validate', {fromMenu: true});
861
- break;
862
- case '4':
863
- await this.executeCommand('usage', {fromMenu: true});
864
- break;
865
- case '5':
866
- await this.executeCommand('complete', {fromMenu: true});
867
- break;
868
- case '6':
869
- await this.executeCommand('sizing', {fromMenu: true});
870
- break;
871
- case '7':
872
- await this.executeCommand('fix', {fromMenu: true});
873
- break;
914
+ case '1':
915
+ await this.executeCommand('init', {fromMenu: true});
916
+ await this.showInteractiveMenu();
917
+ return;
918
+ case '2':
919
+ await this.executeCommand('analyze', {fromMenu: true});
920
+ await this.showInteractiveMenu();
921
+ return;
922
+ case '3':
923
+ await this.executeCommand('validate', {fromMenu: true});
924
+ await this.showInteractiveMenu();
925
+ return;
926
+ case '4':
927
+ await this.executeCommand('usage', {fromMenu: true});
928
+ await this.showInteractiveMenu();
929
+ return;
930
+ case '5':
931
+ await this.executeCommand('complete', {fromMenu: true});
932
+ await this.showInteractiveMenu();
933
+ return;
934
+ case '6':
935
+ await this.executeCommand('sizing', {fromMenu: true});
936
+ await this.showInteractiveMenu();
937
+ return;
938
+ case '7':
939
+ await this.executeCommand('fix', {fromMenu: true});
940
+ await this.showInteractiveMenu();
941
+ return;
874
942
  case '8':
875
943
  // Check for PIN protection
876
944
  const authRequired = await this.adminAuth.isAuthRequiredForScript('summaryReports');
@@ -943,9 +1011,10 @@ class I18nManager {
943
1011
  case '12':
944
1012
  await this.showLanguageMenu();
945
1013
  break;
946
- case '13':
947
- await this.executeCommand('scanner', {fromMenu: true});
948
- break;
1014
+ case '13':
1015
+ await this.executeCommand('scanner', {fromMenu: true});
1016
+ await this.showInteractiveMenu();
1017
+ return;
949
1018
  case '0':
950
1019
  console.log(t('menu.goodbye'));
951
1020
  this.safeClose();
@@ -1435,10 +1504,13 @@ if (require.main === module) {
1435
1504
  console.log(`Version: ${packageJson.version}`);
1436
1505
  console.log(`Release Date: ${versionInfo.releaseDate || 'N/A'}`);
1437
1506
  console.log(`Maintainer: ${versionInfo.maintainer || packageJson.author}`);
1438
- console.log(`Node.js: ${versionInfo.supportedNodeVersions || packageJson.engines?.node || '>=16.0.0'}`);
1439
- console.log(`License: ${packageJson.license}`);
1440
-
1441
- if (versionInfo.majorChanges && versionInfo.majorChanges.length > 0) {
1507
+ console.log(`Node.js: ${versionInfo.supportedNodeVersions || packageJson.engines?.node || '>=16.0.0'}`);
1508
+ console.log(`License: ${packageJson.license}`);
1509
+ if (versionInfo.supportPolicy) {
1510
+ console.log(`\n⚠️ Support: ${versionInfo.supportPolicy}`);
1511
+ }
1512
+
1513
+ if (versionInfo.majorChanges && versionInfo.majorChanges.length > 0) {
1442
1514
  console.log(`\n✨ What's New in ${packageJson.version}:`);
1443
1515
  versionInfo.majorChanges.forEach(change => {
1444
1516
  console.log(` • ${change}`);
@@ -36,8 +36,13 @@ module.exports = class LanguageMenu {
36
36
  return;
37
37
  } else if (choiceNum >= 1 && choiceNum <= this.ui.availableLanguages.length) {
38
38
  const selectedLang = this.ui.availableLanguages[choiceNum - 1];
39
- await this.ui.changeLanguage(selectedLang);
40
- console.log(t('language.changed', { language: this.ui.getLanguageDisplayName(selectedLang) }));
39
+ try {
40
+ await this.ui.changeLanguage(selectedLang);
41
+ console.log(t('language.changed', { language: this.ui.getLanguageDisplayName(selectedLang) }));
42
+ } catch (error) {
43
+ console.error(t('language.changeFailed', { error: error.message }));
44
+ SecurityUtils.logSecurityEvent('Language change failed', 'error', { error: error.message, language: selectedLang });
45
+ }
41
46
 
42
47
  // Force reload translations for the entire system
43
48
  const { loadTranslations } = require('../../../utils/i18n-helper');
@@ -130,9 +130,9 @@ class UsageService {
130
130
  this.config.includeExtensions = ['.js', '.jsx', '.ts', '.tsx', '.py', '.pyx', '.pyi'];
131
131
  }
132
132
 
133
- await SecurityUtils.logSecurityEvent(t('usage.analyzerInitialized'), { component: 'i18ntk-usage' });
133
+ await SecurityUtils.logSecurityEvent(t('usage.analyzerInitialized'), 'info', { component: 'i18ntk-usage' });
134
134
  } catch (error) {
135
- await SecurityUtils.logSecurityEvent(t('usage.analyzerInitFailed'), { component: 'i18ntk-usage', error: error.message });
135
+ await SecurityUtils.logSecurityEvent(t('usage.analyzerInitFailed'), 'error', { component: 'i18ntk-usage', error: error.message });
136
136
  throw error;
137
137
  }
138
138
  }
@@ -237,7 +237,7 @@ class UsageService {
237
237
  }
238
238
  }
239
239
  } catch (error) {
240
- await SecurityUtils.logSecurityEvent(t('usage.translationDiscoveryError'), {
240
+ await SecurityUtils.logSecurityEvent(t('usage.translationDiscoveryError'), 'error', {
241
241
  component: 'i18ntk-usage',
242
242
  directory: currentDir,
243
243
  error: error.message
@@ -311,7 +311,7 @@ class UsageService {
311
311
  }
312
312
  }
313
313
  } catch (error) {
314
- await SecurityUtils.logSecurityEvent(t('usage.fileTraversalError'), {
314
+ await SecurityUtils.logSecurityEvent(t('usage.fileTraversalError'), 'error', {
315
315
  component: 'i18ntk-usage',
316
316
  directory: currentDir,
317
317
  error: error.message
@@ -466,7 +466,7 @@ class UsageService {
466
466
  if (isDebug) {
467
467
  console.error(error.stack);
468
468
  }
469
- await SecurityUtils.logSecurityEvent(t('usage.translationFileParseError'), {
469
+ await SecurityUtils.logSecurityEvent(t('usage.translationFileParseError'), 'error', {
470
470
  component: 'i18ntk-usage',
471
471
  file: fileInfo.filePath,
472
472
  error: error.message
@@ -474,7 +474,7 @@ class UsageService {
474
474
  }
475
475
  }
476
476
  } catch (error) {
477
- await SecurityUtils.logSecurityEvent(t('usage.translationKeysLoadError'), {
477
+ await SecurityUtils.logSecurityEvent(t('usage.translationKeysLoadError'), 'error', {
478
478
  component: 'i18ntk-usage',
479
479
  error: error.message
480
480
  });
@@ -1447,7 +1447,7 @@ class UsageService {
1447
1447
  } catch (error) {
1448
1448
  console.error(t('usage.analysisFailedError'), error.message);
1449
1449
  this.closeReadline();
1450
- SecurityUtils.logSecurityEvent(t('usage.usageAnalysisFailed'), {
1450
+ SecurityUtils.logSecurityEvent(t('usage.usageAnalysisFailed'), 'error', {
1451
1451
  component: 'i18ntk-usage',
1452
1452
  error: error.message
1453
1453
  });