i18ntk 1.7.1 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  ![i18ntk Logo](docs/screenshots/i18ntk-logo-public.PNG)
4
4
 
5
- **Version:** 1.7.1
5
+ **Version:** 1.7.2
6
6
  **Last Updated:** 2025-08-10
7
7
  **GitHub Repository:** [vladnoskv/i18ntk](https://github.com/vladnoskv/i18ntk)
8
8
 
9
9
  [![npm](https://img.shields.io/npm/dt/i18ntk.svg)](https://www.npmjs.com/package/i18ntk) [![npm version](https://badge.fury.io/js/i18ntk.svg)](https://badge.fury.io/js/i18ntk) [![Node.js Version](https://img.shields.io/badge/node-%3E%3D16.0.0-brightgreen.svg)](https://nodejs.org/) [![Downloads](https://img.shields.io/npm/dm/i18ntk.svg)](https://www.npmjs.com/package/i18ntk) [![GitHub stars](https://img.shields.io/github/stars/vladnoskv/i18ntk?style=social)](https://github.com/vladnoskv/i18ntk)
10
- [![Socket Badge](https://socket.dev/api/badge/npm/package/i18ntk/1.7.1)](https://socket.dev/npm/package/i18ntk/overview/1.7.1)
10
+ [![Socket Badge](https://socket.dev/api/badge/npm/package/i18ntk/1.7.1)](https://socket.dev/npm/package/i18ntk/overview/1.7.2)
11
11
 
12
12
  **🚀 The fastest way to manage translations across any framework or vanilla JavaScript projects**
13
13
 
14
14
  **Framework Support:** Auto-detects popular libraries (React i18next, Vue i18n, i18next, Nuxt i18n, Svelte i18n) or works without a framework. i18ntk manages translation files and validation—it does NOT implement translation logic like i18next or Vue i18n.
15
15
 
16
- > **v1.7.1** – Enhanced security logging, flexible 4-6 digit PIN authentication, configuration stability improvements, and CI/CD silent mode support; maintains 97% speed improvement (**15.38ms** for 200k keys up to 5/M keys per second).
16
+ > **v1.7.2** – Enhanced security logging, flexible 4-6 digit PIN authentication, configuration stability improvements, **fixed framework detection prompt**, and CI/CD silent mode support; maintains 97% speed improvement (**15.38ms** for 200k keys up to 5/M keys per second).
17
17
 
18
18
  ## 🚀 Quick Start
19
19
 
@@ -53,6 +53,7 @@ i18ntk validate --source ./locales
53
53
  - **Framework Support**: Auto-detects React i18next, Vue i18n, Angular, Next i18next, Nuxt i18next, Svelte i18n
54
54
  - **Memory Optimization**: 67% memory reduction with streaming processing
55
55
  - **Scalability**: Linear scaling up to 5M keys with ultra-extreme settings
56
+ - **Smart Framework Detection**: Automatically skips unnecessary prompts when i18n frameworks are detected
56
57
 
57
58
  ### 📸 Screenshots
58
59
 
@@ -87,7 +88,7 @@ Configuration is managed through the `settings/i18ntk-config.json` file:
87
88
 
88
89
  ```json
89
90
  {
90
- "version": "1.7.1",
91
+ "version": "1.7.2",
91
92
  "sourceDir": "./locales",
92
93
  "outputDir": "./i18ntk-reports",
93
94
  "defaultLanguage": "en",
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * I18N INITIALIZATION SCRIPT
4
4
  *
@@ -101,8 +101,26 @@ class I18nInitializer {
101
101
 
102
102
  if (installedFrameworks.length > 0) {
103
103
  console.log(t('init.detectedI18nFrameworks', { frameworks: installedFrameworks.join(', ') }));
104
+ const cfg = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
105
+ cfg.framework = cfg.framework || {};
106
+ cfg.framework.detected = true;
107
+ cfg.framework.installed = installedFrameworks;
108
+ if (configManager.saveSettings) {
109
+ configManager.saveSettings(cfg);
110
+ } else if (configManager.saveConfig) {
111
+ configManager.saveConfig(cfg);
112
+ }
104
113
  return true;
105
114
  } else {
115
+ const cfg = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
116
+ if (cfg.framework) {
117
+ cfg.framework.detected = false;
118
+ if (configManager.saveSettings) {
119
+ configManager.saveSettings(cfg);
120
+ } else if (configManager.saveConfig) {
121
+ configManager.saveConfig(cfg);
122
+ }
123
+ }
106
124
  // Framework detection is now handled by maybePromptFramework in i18ntk-manage.js
107
125
  // Skip prompting here to avoid double prompts
108
126
  return true;
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * I18N MANAGEMENT TOOLKIT - MAIN MANAGER
4
4
  *
@@ -69,13 +69,13 @@ async function ensureInitializedOrExit(rl) {
69
69
  };
70
70
 
71
71
  // Check if already initialized using new tracking system
72
- const initFilePath = path.join(process.cwd(), 'settings', 'initialization.json');
72
+ const initFilePath = path.join(settingsManager.configDir, 'initialization.json');
73
73
 
74
74
  let isInitialized = false;
75
75
  if (fs.existsSync(initFilePath)) {
76
76
  try {
77
77
  const initStatus = JSON.parse(fs.readFileSync(initFilePath, 'utf8'));
78
- isInitialized = initStatus.initialized && initStatus.version === '1.7.1';
78
+ isInitialized = initStatus.initialized && initStatus.version === '1.7.2';
79
79
  } catch (e) {
80
80
  // Invalid init file, proceed with check
81
81
  }
@@ -97,7 +97,7 @@ async function ensureInitializedOrExit(rl) {
97
97
  ensureDirectory(initDir);
98
98
  fs.writeFileSync(initFilePath, JSON.stringify({
99
99
  initialized: true,
100
- version: '1.7.1',
100
+ version: '1.7.2',
101
101
  timestamp: new Date().toISOString(),
102
102
  sourceDir: cfg.sourceDir,
103
103
  sourceLanguage: cfg.sourceLanguage
@@ -118,7 +118,7 @@ async function ensureInitializedOrExit(rl) {
118
118
  ensureDirectory(initDir);
119
119
  fs.writeFileSync(initFilePath, JSON.stringify({
120
120
  initialized: true,
121
- version: '1.7.1',
121
+ version: '1.7.2',
122
122
  timestamp: new Date().toISOString(),
123
123
  sourceDir: result.sourceDir || cfg.sourceDir,
124
124
  sourceLanguage: cfg.sourceLanguage
@@ -145,6 +145,12 @@ async function maybePromptFramework(rl, cfg, currentVersion) {
145
145
  };
146
146
  }
147
147
 
148
+ // Reload settings to ensure we have latest framework detection results
149
+ const freshSettings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
150
+ if (freshSettings.framework) {
151
+ settings.framework = freshSettings.framework;
152
+ }
153
+
148
154
  // Check if framework is already detected or preference is set to none
149
155
  if (settings.framework.detected || settings.framework.preference === 'none') {
150
156
  return cfg;
@@ -340,23 +346,38 @@ class I18nManager {
340
346
  ];
341
347
 
342
348
  const installedFrameworks = i18nFrameworks.filter(framework => dependencies[framework]);
343
-
349
+
344
350
  if (installedFrameworks.length > 0) {
345
351
  if (this.ui && this.ui.t) {
346
352
  console.log(this.ui.t('init.detectedFrameworks', { frameworks: installedFrameworks.join(', ') }));
347
353
  } else {
348
354
  console.log(`Detected frameworks: ${installedFrameworks.join(', ')}`);
349
355
  }
356
+ const cfg = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
357
+ cfg.framework = cfg.framework || {};
358
+ cfg.framework.detected = true;
359
+ cfg.framework.installed = installedFrameworks;
360
+ if (configManager.saveSettings) {
361
+ configManager.saveSettings(cfg);
362
+ } else if (configManager.saveConfig) {
363
+ configManager.saveConfig(cfg);
364
+ }
350
365
  return true;
351
366
  } else {
352
- // Check configuration for framework preference
353
367
  const cfg = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
354
-
368
+ if (cfg.framework) {
369
+ cfg.framework.detected = false;
370
+ if (configManager.saveSettings) {
371
+ configManager.saveSettings(cfg);
372
+ } else if (configManager.saveConfig) {
373
+ configManager.saveConfig(cfg);
374
+ }
375
+ }
355
376
  // If framework preference is already set to 'none', skip warning
356
377
  if (cfg.framework === 'none' || (cfg.framework && cfg.framework.preference === 'none')) {
357
378
  return true;
358
379
  }
359
-
380
+
360
381
  // Framework detection is handled by maybePromptFramework, so just return true here
361
382
  return true;
362
383
  }
@@ -435,6 +456,7 @@ class I18nManager {
435
456
 
436
457
  const rl = cliHelper.getInterface();
437
458
  const cfgAfterInitCheck = await ensureInitializedOrExit(rl);
459
+ await this.checkI18nDependencies();
438
460
  await maybePromptFramework(rl, cfgAfterInitCheck, pkg.version);
439
461
 
440
462
  // Update this.config with the configuration from ensureInitializedOrExit
@@ -1065,7 +1087,7 @@ class I18nManager {
1065
1087
  { path: path.join(process.cwd(), 'reports', 'backups'), name: 'Reports Backups', type: 'backups' },
1066
1088
  { path: path.join(process.cwd(), 'scripts', 'debug', 'logs'), name: 'Debug Logs', type: 'logs' },
1067
1089
  { path: path.join(process.cwd(), 'scripts', 'debug', 'reports'), name: 'Debug Reports', type: 'reports' },
1068
- { path: path.join(process.cwd(), 'settings', 'backups'), name: 'Settings Backups', type: 'backups' },
1090
+ { path: path.join(configManager.configDir, 'backups'), name: 'Settings Backups', type: 'backups' },
1069
1091
  { path: path.join(process.cwd(), 'utils', 'i18ntk-reports'), name: 'Utils Reports', type: 'reports' }
1070
1092
  ];
1071
1093
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "description": "i18ntk (i18n Toolkit) - Ultra-extreme performance enterprise-grade internationalization management toolkit with 97% performance improvement (15.38ms for 200k keys), advanced security with PIN protection, comprehensive backup & recovery, and edge case handling for JavaScript/TypeScript projects",
5
5
  "keywords": [
6
6
  "i18n",
@@ -144,7 +144,7 @@
144
144
  },
145
145
  "preferGlobal": true,
146
146
  "versionInfo": {
147
- "version": "1.7.1",
147
+ "version": "1.7.2",
148
148
  "releaseDate": "27/07/2025",
149
149
  "lastUpdated": "10/08/2025",
150
150
  "maintainer": "Vladimir Noskov",
@@ -4,7 +4,7 @@ const path = require('path');
4
4
  const AdminAuth = require('../utils/admin-auth');
5
5
 
6
6
  (async () => {
7
- const configPath = path.join(process.cwd(), 'settings', '.i18n-admin-config.json');
7
+ const configPath = path.join(require('../settings/settings-manager').configDir, '.i18n-admin-config.json');
8
8
  const auth = new AdminAuth();
9
9
 
10
10
  try {
@@ -316,7 +316,7 @@ class PrepublishCleaner {
316
316
  }
317
317
 
318
318
  async resetSecuritySettings() {
319
- const configPath = path.join(this.projectRoot, 'settings', '.i18n-admin-config.json');
319
+ const configPath = path.join(require('../settings/settings-manager').configDir, '.i18n-admin-config.json');
320
320
 
321
321
  if (fs.existsSync(configPath)) {
322
322
  const defaultConfig = {
@@ -9,8 +9,8 @@ const path = require('path');
9
9
 
10
10
  class SettingsManager {
11
11
  constructor() {
12
- const projectRoot = process.cwd();
13
- this.configDir = path.join(projectRoot, 'settings');
12
+ const packageDir = __dirname;
13
+ this.configDir = packageDir;
14
14
  this.configFile = path.join(this.configDir, 'i18ntk-config.json');
15
15
  this.lastBackupTime = 0;
16
16
  this.backupDebounceMs = 5000; // 5 seconds debounce
@@ -10,7 +10,8 @@ const configManager = require('./config-manager');
10
10
  */
11
11
  class AdminAuth {
12
12
  constructor() {
13
- this.configPath = path.join(process.cwd(), 'settings', '.i18n-admin-config.json');
13
+ const settingsDir = require('../settings/settings-manager').configDir;
14
+ this.configPath = path.join(settingsDir, '.i18n-admin-config.json');
14
15
 
15
16
  // Get settings from config manager
16
17
  const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
@@ -64,6 +64,7 @@ async function getUnifiedConfig(scriptName, cliArgs = {}) {
64
64
  outputDir: configManager.toRelative(cfg.outputDir),
65
65
  };
66
66
 
67
+ const settingsDir = settingsManager.configDir;
67
68
  const config = {
68
69
  ...cfg,
69
70
  sourceLanguage: cliArgs.sourceLanguage || cfg.sourceLanguage || 'en',
@@ -73,10 +74,10 @@ async function getUnifiedConfig(scriptName, cliArgs = {}) {
73
74
  excludeFiles: cfg.excludeFiles || cfg.processing?.excludeFiles || ['.DS_Store', 'Thumbs.db'],
74
75
  excludeDirs: cfg.excludeDirs || cfg.processing?.excludeDirs || ['node_modules', '.next', '.git', 'dist', 'build'],
75
76
  strictMode: cliArgs.strictMode || cfg.strictMode || false,
76
- backupDir: path.resolve(cfg.projectRoot, path.join('settings', 'backups')),
77
- tempDir: path.resolve(cfg.projectRoot, path.join('settings', 'temp')),
78
- cacheDir: path.resolve(cfg.projectRoot, path.join('settings', '.cache')),
79
- configDir: path.resolve(cfg.projectRoot, 'settings'),
77
+ backupDir: path.join(settingsDir, 'backups'),
78
+ tempDir: path.join(settingsDir, 'temp'),
79
+ cacheDir: path.join(settingsDir, '.cache'),
80
+ configDir: settingsDir,
80
81
  settings: {
81
82
  defaultLanguages: cfg.defaultLanguages || ['de', 'es', 'fr', 'ru'],
82
83
  processing: { ...cfg.processing },
@@ -268,14 +269,14 @@ function displayPaths(cfg = {}) {
268
269
  async function ensureInitialized(cfg) {
269
270
  try {
270
271
  // Check if initialization has been marked as complete
271
- const configPath = path.join(process.cwd(), 'settings', 'initialization.json');
272
+ const configPath = path.join(settingsManager.configDir, 'initialization.json');
272
273
  let initStatus = { initialized: false, version: null, timestamp: null };
273
274
 
274
275
  if (fs.existsSync(configPath)) {
275
276
  try {
276
277
  initStatus = JSON.parse(fs.readFileSync(configPath, 'utf8'));
277
278
  // If initialized and version matches current, skip further checks
278
- if (initStatus.initialized && initStatus.version === '1.7.1') {
279
+ if (initStatus.initialized && initStatus.version === '1.7.2') {
279
280
  return true;
280
281
  }
281
282
  } catch (e) {
@@ -296,7 +297,7 @@ async function ensureInitialized(cfg) {
296
297
  ensureDirectory(initDir);
297
298
  fs.writeFileSync(configPath, JSON.stringify({
298
299
  initialized: true,
299
- version: '1.7.1',
300
+ version: '1.7.2',
300
301
  timestamp: new Date().toISOString(),
301
302
  sourceDir: sourceDir,
302
303
  sourceLanguage: sourceLanguage
@@ -316,7 +317,7 @@ async function ensureInitialized(cfg) {
316
317
  ensureDirectory(initDir);
317
318
  fs.writeFileSync(configPath, JSON.stringify({
318
319
  initialized: true,
319
- version: '1.7.1',
320
+ version: '1.7.2',
320
321
  timestamp: new Date().toISOString(),
321
322
  sourceDir: sourceDir,
322
323
  sourceLanguage: sourceLanguage
@@ -337,7 +338,7 @@ async function ensureInitialized(cfg) {
337
338
  ensureDirectory(initDir);
338
339
  fs.writeFileSync(configPath, JSON.stringify({
339
340
  initialized: true,
340
- version: '1.7.1',
341
+ version: '1.7.2',
341
342
  timestamp: new Date().toISOString(),
342
343
  sourceDir: sourceDir,
343
344
  sourceLanguage: sourceLanguage
@@ -3,7 +3,8 @@ const path = require('path');
3
3
 
4
4
  // Project root is where commands are executed
5
5
  const projectRoot = process.cwd();
6
- const CONFIG_DIR = path.join(projectRoot, 'settings');
6
+ const settingsManager = require('../settings/settings-manager');
7
+ const CONFIG_DIR = settingsManager.configDir;
7
8
  const CONFIG_PATH = path.join(CONFIG_DIR, 'i18ntk-config.json');
8
9
 
9
10
  // Default configuration values - comprehensive configuration
package/utils/config.js CHANGED
@@ -1,14 +1,14 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
- const CONFIG_DIR = 'settings';
4
+ const settingsManager = require('../settings/settings-manager');
5
5
  const CONFIG_FILE = 'i18ntk-config.json';
6
6
 
7
- function getConfigPath(cwd = process.cwd()) {
8
- return path.join(cwd, CONFIG_DIR, CONFIG_FILE);
7
+ function getConfigPath(cwd = settingsManager.configDir) {
8
+ return path.join(cwd, CONFIG_FILE);
9
9
  }
10
10
 
11
- function loadConfig(cwd = process.cwd()) {
11
+ function loadConfig(cwd = settingsManager.configDir) {
12
12
  const p = getConfigPath(cwd);
13
13
  try {
14
14
  const raw = fs.readFileSync(p, 'utf8');
@@ -18,8 +18,8 @@ function loadConfig(cwd = process.cwd()) {
18
18
  }
19
19
  }
20
20
 
21
- function saveConfig(cfg, cwd = process.cwd()) {
22
- const dir = path.join(cwd, CONFIG_DIR);
21
+ function saveConfig(cfg, cwd = settingsManager.configDir) {
22
+ const dir = cwd;
23
23
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
24
24
  fs.writeFileSync(path.join(dir, CONFIG_FILE), JSON.stringify(cfg, null, 2), 'utf8');
25
25
  }
package/utils/security.js CHANGED
@@ -356,7 +356,7 @@ class SecurityUtils {
356
356
  static async saveEncryptedPin(pin) {
357
357
  try {
358
358
  const hash = crypto.createHash('sha256').update(pin).digest('hex');
359
- const settingsDir = path.join(process.cwd(), 'settings');
359
+ const settingsDir = require('../settings/settings-manager').configDir;
360
360
  const pinFile = path.join(settingsDir, 'admin-pin.hash');
361
361
  await fs.promises.mkdir(settingsDir, { recursive: true });
362
362
  await fs.promises.writeFile(pinFile, hash, 'utf8');