i18ntk 2.1.0 → 2.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 (73) hide show
  1. package/README.md +87 -50
  2. package/main/i18ntk-analyze.js +63 -63
  3. package/main/i18ntk-backup-class.js +37 -41
  4. package/main/i18ntk-backup.js +28 -30
  5. package/main/i18ntk-complete.js +75 -74
  6. package/main/i18ntk-doctor.js +7 -6
  7. package/main/i18ntk-fixer.js +3 -3
  8. package/main/i18ntk-init.js +49 -13
  9. package/main/i18ntk-scanner.js +2 -2
  10. package/main/i18ntk-sizing.js +36 -37
  11. package/main/i18ntk-summary.js +4 -4
  12. package/main/i18ntk-ui.js +95 -96
  13. package/main/i18ntk-usage.js +31 -19
  14. package/main/i18ntk-validate.js +78 -27
  15. package/main/manage/commands/AnalyzeCommand.js +71 -73
  16. package/main/manage/commands/CommandRouter.js +15 -12
  17. package/main/manage/commands/FixerCommand.js +94 -38
  18. package/main/manage/commands/ScannerCommand.js +2 -2
  19. package/main/manage/commands/ValidateCommand.js +87 -36
  20. package/main/manage/index.js +165 -152
  21. package/main/manage/managers/DebugMenu.js +6 -6
  22. package/main/manage/managers/InteractiveMenu.js +6 -6
  23. package/main/manage/managers/LanguageMenu.js +12 -6
  24. package/main/manage/managers/SettingsMenu.js +6 -6
  25. package/main/manage/services/AuthenticationService.js +5 -6
  26. package/main/manage/services/ConfigurationService.js +22 -34
  27. package/main/manage/services/FileManagementService.js +6 -6
  28. package/main/manage/services/InitService.js +44 -8
  29. package/main/manage/services/UsageService.js +24 -12
  30. package/package.json +21 -42
  31. package/settings/settings-cli.js +5 -5
  32. package/settings/settings-manager.js +984 -968
  33. package/ui-locales/de.json +12 -11
  34. package/ui-locales/en.json +12 -11
  35. package/ui-locales/es.json +12 -11
  36. package/ui-locales/fr.json +12 -11
  37. package/ui-locales/ja.json +12 -11
  38. package/ui-locales/ru.json +12 -11
  39. package/ui-locales/zh.json +12 -11
  40. package/utils/config-helper.js +27 -16
  41. package/utils/config-manager.js +8 -7
  42. package/utils/i18n-helper.js +161 -166
  43. package/utils/init-helper.js +3 -2
  44. package/utils/json-output.js +11 -10
  45. package/{scripts → utils}/locale-optimizer.js +61 -60
  46. package/utils/logger.js +4 -4
  47. package/utils/safe-json.js +3 -3
  48. package/utils/secure-backup.js +8 -7
  49. package/utils/setup-enforcer.js +63 -98
  50. package/main/i18ntk-go.js +0 -283
  51. package/main/i18ntk-java.js +0 -380
  52. package/main/i18ntk-js.js +0 -512
  53. package/main/i18ntk-manage.js +0 -1694
  54. package/main/i18ntk-php.js +0 -462
  55. package/main/i18ntk-py.js +0 -379
  56. package/main/i18ntk-settings.js +0 -23
  57. package/main/manage/index-fixed.js +0 -1447
  58. package/scripts/build-lite.js +0 -279
  59. package/scripts/deprecate-versions.js +0 -317
  60. package/scripts/export-translations.js +0 -84
  61. package/scripts/fix-all-i18n.js +0 -236
  62. package/scripts/fix-and-purify-i18n.js +0 -233
  63. package/scripts/fix-locale-control-chars.js +0 -110
  64. package/scripts/lint-locales.js +0 -80
  65. package/scripts/prepublish-dev.js +0 -221
  66. package/scripts/prepublish.js +0 -362
  67. package/scripts/security-check.js +0 -117
  68. package/scripts/sync-translations.js +0 -151
  69. package/scripts/sync-ui-locales.js +0 -20
  70. package/scripts/validate-all-translations.js +0 -195
  71. package/scripts/verify-deprecations.js +0 -157
  72. package/scripts/verify-translations.js +0 -63
  73. package/utils/security-fixed.js +0 -609
@@ -4,7 +4,8 @@
4
4
  * @module services/AuthenticationService
5
5
  */
6
6
 
7
- const AdminAuth = require('../../../utils/admin-auth');
7
+ const AdminAuth = require('../../../utils/admin-auth');
8
+ const cliHelper = require('../../../utils/cli-helper');
8
9
 
9
10
  module.exports = class AuthenticationService {
10
11
  constructor(config = {}) {
@@ -74,8 +75,7 @@ module.exports = class AuthenticationService {
74
75
  }
75
76
 
76
77
  console.log(ui ? ui.t('adminCli.authRequired') : 'Admin authentication required');
77
- const cliHelper = require('../../../utils/cli-helper');
78
- const pin = await cliHelper.promptPin(ui ? ui.t('adminCli.enterPin') : 'Enter PIN: ');
78
+ const pin = await cliHelper.promptPin(ui ? ui.t('adminCli.enterPin') : 'Enter PIN: ');
79
79
  const isValid = await this.verifyPin(pin);
80
80
 
81
81
  if (!isValid) {
@@ -131,8 +131,7 @@ module.exports = class AuthenticationService {
131
131
  * @returns {Promise<string>} User input or empty string
132
132
  */
133
133
  async prompt(question) {
134
- const cliHelper = require('../../../utils/cli-helper');
135
- // If interactive not available, return empty string to avoid hangs
134
+ // If interactive not available, return empty string to avoid hangs
136
135
  if (!process.stdin.isTTY || process.stdin.destroyed) {
137
136
  console.log('\n⚠️ Interactive input not available, using default response.');
138
137
  return Promise.resolve('');
@@ -260,4 +259,4 @@ module.exports = class AuthenticationService {
260
259
  process.exit(1);
261
260
  }
262
261
  }
263
- };
262
+ };
@@ -8,12 +8,14 @@ const path = require('path');
8
8
  const configManager = require('../../../settings/settings-manager');
9
9
  const { loadTranslations, t, refreshLanguageFromSettings } = require('../../../utils/i18n-helper');
10
10
 
11
- const { createPrompt, isInteractive } = require('../../../utils/prompt-helper');
12
- const { loadConfig, saveConfig, ensureConfigDefaults } = require('../../../utils/config');
13
- const { getUnifiedConfig, ensureInitialized, validateSourceDir } = require('../../../utils/config-helper');
14
- const cliHelper = require('../../../utils/cli-helper');
15
- const pkg = require('../../../package.json');
16
- const SetupEnforcer = require('../../../utils/setup-enforcer');
11
+ const { createPrompt, isInteractive } = require('../../../utils/prompt-helper');
12
+ const { loadConfig, saveConfig, ensureConfigDefaults } = require('../../../utils/config');
13
+ const { getUnifiedConfig, ensureInitialized, validateSourceDir } = require('../../../utils/config-helper');
14
+ const { checkInitialized } = require('../../../utils/init-helper');
15
+ const cliHelper = require('../../../utils/cli-helper');
16
+ const pkg = require('../../../package.json');
17
+ const SetupEnforcer = require('../../../utils/setup-enforcer');
18
+ const FrameworkDetectionService = require('./FrameworkDetectionService');
17
19
 
18
20
  module.exports = class ConfigurationService {
19
21
  constructor(config = {}) {
@@ -54,9 +56,8 @@ module.exports = class ConfigurationService {
54
56
  loadTranslations(uiLanguage);
55
57
 
56
58
  // Validate source directory exists
57
- const { validateSourceDir, displayPaths } = require('../../../utils/config-helper');
58
- try {
59
- validateSourceDir(this.config.sourceDir, 'i18ntk-manage');
59
+ try {
60
+ validateSourceDir(this.config.sourceDir, 'i18ntk-manage');
60
61
  } catch (err) {
61
62
  console.log(t('init.requiredTitle'));
62
63
  console.log(t('init.requiredBody'));
@@ -102,23 +103,18 @@ module.exports = class ConfigurationService {
102
103
  // Ensure setup is complete before running any operations
103
104
  await SetupEnforcer.checkSetupCompleteAsync();
104
105
 
105
- prompt = createPrompt({ noPrompt: args.noPrompt || Boolean(args.adminPin) });
106
- const interactive = isInteractive({ noPrompt: args.noPrompt || Boolean(args.adminPin) });
106
+ prompt = createPrompt({ noPrompt: args.noPrompt });
107
+ const interactive = isInteractive({ noPrompt: args.noPrompt });
107
108
 
108
109
  // Load settings and UI language
109
110
  const settings = this.settings || (this.configManager.loadSettings ? this.configManager.loadSettings() : (this.configManager.getConfig ? this.configManager.getConfig() : {}));
110
111
  const uiLanguage = args.uiLanguage || settings.uiLanguage || settings.language || this.config.uiLanguage || 'en';
111
112
  loadTranslations(uiLanguage);
112
113
 
113
- if (args.adminPin) {
114
- // Handle admin PIN mode
115
- this.prompt = async () => '';
116
- }
117
-
118
- if (args.help) {
119
- this.showHelp();
120
- return;
121
- }
114
+ if (args.help) {
115
+ this.showHelp();
116
+ return;
117
+ }
122
118
 
123
119
  let cfgAfterInitCheck = {};
124
120
  if (interactive) {
@@ -155,11 +151,7 @@ module.exports = class ConfigurationService {
155
151
  * @returns {Promise<Object>} Configuration object if initialized
156
152
  */
157
153
  async ensureInitializedOrExit(prompt) {
158
- const { checkInitialized } = require('../../../utils/init-helper');
159
- const cliHelper = require('../../../utils/cli-helper');
160
- const pkg = require('../../../package.json');
161
-
162
- const { initialized, config } = await checkInitialized();
154
+ const { initialized, config } = await checkInitialized();
163
155
 
164
156
  if (!initialized) {
165
157
  console.log('\nThis project is not yet initialized with i18ntk.');
@@ -224,8 +216,7 @@ module.exports = class ConfigurationService {
224
216
  console.log('Framework detection prompt will be suppressed for this version.');
225
217
  } else if (action === 'detect') {
226
218
  // Run framework detection
227
- const FrameworkDetectionService = require('./FrameworkDetectionService');
228
- const frameworkService = new FrameworkDetectionService();
219
+ const frameworkService = new FrameworkDetectionService();
229
220
  frameworkService.initialize(this.configManager);
230
221
 
231
222
  const { detectedLanguage, detectedFramework } = await frameworkService.detectEnvironmentAndFramework();
@@ -260,8 +251,7 @@ module.exports = class ConfigurationService {
260
251
  * @returns {Promise<boolean>} True if frameworks detected, false otherwise
261
252
  */
262
253
  async checkI18nDependencies() {
263
- const FrameworkDetectionService = require('./FrameworkDetectionService');
264
- const frameworkService = new FrameworkDetectionService();
254
+ const frameworkService = new FrameworkDetectionService();
265
255
  frameworkService.initialize(this.configManager);
266
256
  return await frameworkService.checkI18nDependencies(null);
267
257
  }
@@ -274,8 +264,7 @@ module.exports = class ConfigurationService {
274
264
  * @returns {Promise<Object>} Updated configuration
275
265
  */
276
266
  async maybePromptFramework(prompt, cfg, currentVersion) {
277
- const FrameworkDetectionService = require('./FrameworkDetectionService');
278
- const frameworkService = new FrameworkDetectionService();
267
+ const frameworkService = new FrameworkDetectionService();
279
268
  frameworkService.initialize(this.configManager);
280
269
  return await frameworkService.maybePromptFramework(prompt, cfg, currentVersion);
281
270
  }
@@ -392,8 +381,7 @@ module.exports = class ConfigurationService {
392
381
  * @returns {Promise<string>} User input or empty string
393
382
  */
394
383
  prompt(question) {
395
- const cliHelper = require('../../../utils/cli-helper');
396
- // If interactive not available, return empty string to avoid hangs
384
+ // If interactive not available, return empty string to avoid hangs
397
385
  if (!process.stdin.isTTY || process.stdin.destroyed) {
398
386
  console.log('\n⚠️ Interactive input not available, using default response.');
399
387
  return Promise.resolve('');
@@ -446,4 +434,4 @@ module.exports = class ConfigurationService {
446
434
  getUI() {
447
435
  return this.ui;
448
436
  }
449
- };
437
+ };
@@ -4,9 +4,10 @@
4
4
  * @module services/FileManagementService
5
5
  */
6
6
 
7
- const path = require('path');
8
- const fs = require('fs');
9
- const SecurityUtils = require('../../../utils/security');
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+ const SecurityUtils = require('../../../utils/security');
10
+ const cliHelper = require('../../../utils/cli-helper');
10
11
 
11
12
  module.exports = class FileManagementService {
12
13
  constructor(config = {}) {
@@ -108,8 +109,7 @@ module.exports = class FileManagementService {
108
109
  const authRequired = await this.isAuthRequiredForScript('deleteReports');
109
110
  if (authRequired) {
110
111
  console.log(`\n${ui ? ui.t('adminPin.protectedAccess') : 'Protected Access'}`);
111
- const cliHelper = require('../../../utils/cli-helper');
112
- const pin = await cliHelper.promptPin((ui ? ui.t('adminPin.enterPin') : 'Enter PIN: ') + ': ');
112
+ const pin = await cliHelper.promptPin((ui ? ui.t('adminPin.enterPin') : 'Enter PIN: ') + ': ');
113
113
  const isValid = await this.verifyPin(pin);
114
114
  if (!isValid) {
115
115
  console.log(ui ? ui.t('adminPin.invalidPin') : 'Invalid PIN');
@@ -365,4 +365,4 @@ module.exports = class FileManagementService {
365
365
  // For now, return true as a placeholder
366
366
  return true;
367
367
  }
368
- };
368
+ };
@@ -681,7 +681,7 @@ class InitService {
681
681
  }
682
682
 
683
683
  // Interactive admin PIN setup
684
- async promptAdminPinSetup() {
684
+ async promptAdminPinSetup() {
685
685
  const { ask, askHidden, flushStdout } = require('../../../utils/cli');
686
686
 
687
687
  console.log('\n' + t('init.adminPinSetupOptional'));
@@ -733,8 +733,31 @@ class InitService {
733
733
  }
734
734
  } else {
735
735
  console.log(t('init.skippingAdminPinSetup'));
736
- }
737
- }
736
+ }
737
+ }
738
+
739
+ async promptBackupConfiguration(skipPrompt = false) {
740
+ const defaultBackupConfig = { enabled: false, maxBackups: 1, location: './i18ntk-backups' };
741
+ if (skipPrompt || !process.stdin.isTTY) {
742
+ return null;
743
+ }
744
+
745
+ const { ask } = require('../../../utils/cli');
746
+ console.log('\nBackup Settings');
747
+ console.log('Backups are disabled by default to avoid backup recursion and repo pollution.');
748
+ const enableAnswer = await ask('Enable automatic backups? (y/N): ');
749
+ const enabled = ['y', 'yes'].includes(String(enableAnswer || '').trim().toLowerCase());
750
+
751
+ if (!enabled) {
752
+ return defaultBackupConfig;
753
+ }
754
+
755
+ const keepAnswer = await ask('How many backups should be kept automatically (1-3, default 1): ');
756
+ const parsedKeep = parseInt(String(keepAnswer || '').trim(), 10);
757
+ const maxBackups = Number.isInteger(parsedKeep) ? Math.min(Math.max(parsedKeep, 1), 3) : 1;
758
+
759
+ return { enabled: true, maxBackups, location: './i18ntk-backups' };
760
+ }
738
761
 
739
762
  // Interactive language selection
740
763
  async selectLanguages(skipPrompt = false) {
@@ -845,11 +868,24 @@ class InitService {
845
868
  // Prompt for admin PIN setup if not already configured
846
869
  const securitySettings = configManager.getConfig().security || {};
847
870
 
848
- if (!securitySettings.adminPinEnabled && securitySettings.adminPinPromptOnInit !== false && !args.noPrompt) {
849
- const { flushStdout } = require('../../../utils/cli');
850
- await flushStdout();
851
- await this.promptAdminPinSetup();
852
- }
871
+ if (!securitySettings.adminPinEnabled && securitySettings.adminPinPromptOnInit !== false && !args.noPrompt) {
872
+ const { flushStdout } = require('../../../utils/cli');
873
+ await flushStdout();
874
+ await this.promptAdminPinSetup();
875
+ }
876
+
877
+ const backupSettings = await this.promptBackupConfiguration(args.noPrompt);
878
+ if (backupSettings) {
879
+ await configManager.updateConfig({
880
+ backup: {
881
+ ...(this.config.backup || {}),
882
+ ...backupSettings
883
+ }
884
+ });
885
+ this.config.backup = { ...(this.config.backup || {}), ...backupSettings };
886
+ } else if (!this.config.backup) {
887
+ this.config.backup = { enabled: false, maxBackups: 1, location: './i18ntk-backups' };
888
+ }
853
889
 
854
890
  // Get target languages - use args.languages if provided
855
891
  let targetLanguages = args.languages || await this.selectLanguages(args.noPrompt);
@@ -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
  });
@@ -512,10 +512,22 @@ class UsageService {
512
512
  return keys;
513
513
  }
514
514
 
515
- collectPlaceholderKeys(obj, prefix = '', language) {
516
- const patterns = this.placeholderStyles[language] || [];
517
- const regexes = patterns.map(p => new RegExp(p));
518
- if (typeof obj !== 'object' || obj === null) return;
515
+ collectPlaceholderKeys(obj, prefix = '', language) {
516
+ const patterns = this.placeholderStyles[language] || [];
517
+ const regexes = patterns.reduce((compiled, pattern) => {
518
+ try {
519
+ compiled.push(new RegExp(pattern));
520
+ } catch (error) {
521
+ SecurityUtils.logSecurityEvent('Invalid placeholder regex pattern skipped', 'warn', {
522
+ component: 'i18ntk-usage',
523
+ language,
524
+ pattern,
525
+ error: error.message
526
+ });
527
+ }
528
+ return compiled;
529
+ }, []);
530
+ if (typeof obj !== 'object' || obj === null) return;
519
531
 
520
532
  for (const [key, value] of Object.entries(obj)) {
521
533
  const fullKey = prefix ? `${prefix}.${key}` : key;
@@ -1447,7 +1459,7 @@ class UsageService {
1447
1459
  } catch (error) {
1448
1460
  console.error(t('usage.analysisFailedError'), error.message);
1449
1461
  this.closeReadline();
1450
- SecurityUtils.logSecurityEvent(t('usage.usageAnalysisFailed'), {
1462
+ SecurityUtils.logSecurityEvent(t('usage.usageAnalysisFailed'), 'error', {
1451
1463
  component: 'i18ntk-usage',
1452
1464
  error: error.message
1453
1465
  });
@@ -1499,4 +1511,4 @@ Analysis Features (v1.8.3):
1499
1511
  }
1500
1512
  }
1501
1513
 
1502
- module.exports = UsageService;
1514
+ module.exports = UsageService;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "2.1.0",
4
- "description": "🚀 The fastest i18n toolkit with 97% performance boost! Zero-dependency, enterprise-grade internationalization for React, Vue, Angular, Python, Java, PHP & more. Features PIN protection, auto framework detection, 7+ UI languages, and comprehensive translation management. Perfect for startups to enterprises.",
3
+ "version": "2.3.0",
4
+ "description": "🚀 The fastest internationalization toolkit with 97% performance boost! Zero-dependency, enterprise-grade internationalization for React, Vue, Angular, Python, Java, PHP & more. Features PIN protection, auto framework detection, 7+ UI languages, and comprehensive translation management. Perfect for startups to enterprises.",
5
5
  "keywords": [
6
6
  "i18n",
7
7
  "internationalization",
@@ -134,7 +134,6 @@
134
134
  "./main/*": "./main/*",
135
135
  "./utils/*": "./utils/*",
136
136
  "./settings/*": "./settings/*",
137
- "./scripts/*": "./scripts/*",
138
137
  "./ui-locales/*": "./ui-locales/*",
139
138
  "./package.json": "./package.json"
140
139
  },
@@ -162,9 +161,17 @@
162
161
  "main/",
163
162
  "runtime/",
164
163
  "utils/",
165
- "scripts/",
166
164
  "settings/",
167
165
  "ui-locales/",
166
+ "!main/manage/index-fixed.js",
167
+ "!main/i18ntk-manage.js",
168
+ "!main/i18ntk-py.js",
169
+ "!main/i18ntk-js.js",
170
+ "!main/i18ntk-java.js",
171
+ "!main/i18ntk-php.js",
172
+ "!main/i18ntk-go.js",
173
+ "!main/i18ntk-settings.js",
174
+ "!utils/security-fixed.js",
168
175
  "LICENSE",
169
176
  "package.json",
170
177
  "README.md"
@@ -220,50 +227,21 @@
220
227
  },
221
228
  "preferGlobal": true,
222
229
  "versionInfo": {
223
- "version": "2.1.0",
224
- "releaseDate": "11/04/2026",
225
- "lastUpdated": "11/04/2026",
230
+ "version": "2.3.0",
231
+ "releaseDate": "12/04/2026",
232
+ "lastUpdated": "12/04/2026",
226
233
  "maintainer": "Vladimir Noskov",
227
234
  "changelog": "./CHANGELOG.md",
228
235
  "documentation": "./README.md",
229
236
  "apiReference": "./docs/api/API_REFERENCE.md",
230
237
  "majorChanges": [
231
- "UX: Interactive menu command flow now returns reliably to Main Menu after command completion",
232
- "I18N: UI locale keysets synchronized and normalized across resources/ui-locales and ui-locales",
233
- "ANALYZE: Fixed progress counter and removed duplicate report-save output lines",
234
- "RELIABILITY: Backup/report directories are excluded from language discovery in analyze/complete flows",
235
- "FRAMEWORK: Setup-complete projects are recognized as internal i18ntk framework to avoid repeated detection prompts",
236
- "SECURITY: Reduced false-positive config sanitization warnings for valid date/time report settings"
238
+ "CRITICAL FIX: Resolved sizing and usage-analysis regressions in v2 command flow.",
239
+ "PACKAGING: Reduced publish footprint by removing internal development scripts and legacy fixed-file artifacts.",
240
+ "SECURITY: Hardened release checks and added explicit support guidance to update from pre-2.3.0 versions.",
241
+ "I18N: Completed internal UI locale parity and actionable untranslated-key cleanup across supported languages."
237
242
  ],
238
243
  "breakingChanges": [],
239
- "deprecations": [
240
- "1.0.x",
241
- "1.1.x",
242
- "1.2.x",
243
- "1.3.x",
244
- "1.4.x",
245
- "1.5.x",
246
- "1.6.0",
247
- "1.6.1",
248
- "1.6.2",
249
- "1.6.3",
250
- "1.7.0",
251
- "1.7.1",
252
- "1.7.2",
253
- "1.7.3",
254
- "1.7.4",
255
- "1.7.5",
256
- "1.7.6",
257
- "1.8.0",
258
- "1.8.1",
259
- "1.8.2",
260
- "1.8.3",
261
- "1.9.0",
262
- "1.10.1",
263
- "1.10.2",
264
- "1.10.3"
265
- ],
266
- "nextVersion": "2.2.0",
244
+ "nextVersion": "2.4.0",
267
245
  "supportedNodeVersions": ">=16.0.0",
268
246
  "supportedFrameworks": {
269
247
  "react-i18next": ">=11.0.0",
@@ -284,7 +262,8 @@
284
262
  "fastapi": ">=0.70.0",
285
263
  "spring-boot": ">=2.5.0",
286
264
  "laravel": ">=8.0.0"
287
- }
265
+ },
266
+ "supportPolicy": "Versions earlier than 2.3.0 may be unstable or insecure. Upgrade to 2.3.0 or newer."
288
267
  },
289
268
  "_comment": "This package is zero-dependency and uses only native Node.js modules"
290
269
  }
@@ -12,7 +12,7 @@ const settingsManager = new SettingsManager();
12
12
  const UIi18n = require('../main/i18ntk-ui');
13
13
  const configManager = require('../utils/config-manager');
14
14
  const { loadTranslations, t } = require('../utils/i18n-helper');
15
- loadTranslations(null, path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
15
+ loadTranslations(null, path.resolve(__dirname, '..', 'ui-locales'));
16
16
 
17
17
  const AdminAuth = require('../utils/admin-auth');
18
18
  const uiI18n = new UIi18n();
@@ -567,8 +567,8 @@ class SettingsCLI {
567
567
  'backupRetention': { min: 1, max: 30, type: 'int', unit: 'days' },
568
568
  'logRetention': { min: 1, max: 90, type: 'int', unit: 'days' },
569
569
  'retentionDays': { min: 1, max: 365, type: 'int', unit: 'days' },
570
- 'maxBackups': { min: 1, max: 1000, type: 'int' }
571
- };
570
+ 'maxBackups': { min: 1, max: 3, type: 'int' }
571
+ };
572
572
 
573
573
  for (const [field, rules] of Object.entries(validations)) {
574
574
  if (key.includes(field)) {
@@ -610,7 +610,7 @@ class SettingsCLI {
610
610
  }
611
611
  if (key === 'removeUiLanguages') {
612
612
  if (this.rl && this.rl.pause) this.rl.pause();
613
- const LocaleOptimizer = require('../scripts/locale-optimizer.js');
613
+ const LocaleOptimizer = require('../utils/locale-optimizer.js');
614
614
  const optimizer = new LocaleOptimizer();
615
615
  await optimizer.interactiveSelect();
616
616
  // Re-initialize readline if it was closed by locale optimizer
@@ -2135,4 +2135,4 @@ Note: Use arrow keys and Enter to navigate the interactive menu.
2135
2135
  console.error('Stack trace:', error.stack);
2136
2136
  process.exit(1);
2137
2137
  });
2138
- }
2138
+ }