i18ntk 1.7.0 → 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 +18 -55
- package/main/i18ntk-analyze.js +2 -2
- package/main/i18ntk-autorun.js +1 -1
- package/main/i18ntk-complete.js +1 -1
- package/main/i18ntk-init.js +42 -9
- package/main/i18ntk-manage.js +236 -40
- package/main/i18ntk-sizing.js +2 -2
- package/main/i18ntk-summary.js +2 -2
- package/main/i18ntk-ui.js +6 -0
- package/main/i18ntk-usage.js +2 -2
- package/main/i18ntk-validate.js +47 -11
- package/package.json +7 -8
- package/scripts/admin-auth.test.js +21 -0
- package/scripts/prepublish.js +1 -1
- package/settings/.i18n-admin-config.json +2 -2
- package/settings/i18ntk-config.json +0 -1
- package/settings/initialization.json +7 -0
- package/settings/settings-cli.js +1 -1
- package/settings/settings-manager.js +2 -2
- package/ui-locales/de.json +2 -0
- package/ui-locales/en.json +2 -0
- package/ui-locales/es.json +2 -0
- package/ui-locales/fr.json +2 -0
- package/ui-locales/ja.json +2 -0
- package/ui-locales/ru.json +35 -33
- package/ui-locales/zh.json +2 -0
- package/utils/admin-auth.js +88 -19
- package/utils/admin-cli.js +15 -3
- package/utils/admin-pin.js +519 -526
- package/utils/cli-helper.js +84 -11
- package/utils/config-helper.js +60 -6
- package/utils/config-manager.js +2 -1
- package/utils/config.js +41 -0
- package/utils/i18n-helper.js +2 -1
- package/utils/promptPin.js +76 -0
- package/utils/security-check.js +6 -2
- package/utils/security.js +1 -1
package/README.md
CHANGED
|
@@ -2,19 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
**Version:** 1.7.
|
|
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
|
-
[](https://www.npmjs.com/package/i18ntk) [](https://badge.fury.io/js/i18ntk) [](https://nodejs.org/) [](https://www.npmjs.com/package/i18ntk) [](https://github.com/vladnoskv/i18ntk)
|
|
9
|
+
[](https://www.npmjs.com/package/i18ntk) [](https://badge.fury.io/js/i18ntk) [](https://nodejs.org/) [](https://www.npmjs.com/package/i18ntk) [](https://github.com/vladnoskv/i18ntk)
|
|
10
|
+
[](https://socket.dev/npm/package/i18ntk/overview/1.7.2)
|
|
10
11
|
|
|
11
12
|
**🚀 The fastest way to manage translations across any framework or vanilla JavaScript projects**
|
|
12
13
|
|
|
13
|
-
**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
|
|
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.
|
|
14
15
|
|
|
15
|
-
> **
|
|
16
|
-
|
|
17
|
-
> **v1.7.0** – 97% speed improvement (**15.38ms** for 200k keys), new watch helper, and a lite English-only UI locale framework; up to 86% package size reduction, zero runtime dependencies, enhanced security with PIN protection, and comprehensive edge case handling.
|
|
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).
|
|
18
17
|
|
|
19
18
|
## 🚀 Quick Start
|
|
20
19
|
|
|
@@ -54,6 +53,7 @@ i18ntk validate --source ./locales
|
|
|
54
53
|
- **Framework Support**: Auto-detects React i18next, Vue i18n, Angular, Next i18next, Nuxt i18next, Svelte i18n
|
|
55
54
|
- **Memory Optimization**: 67% memory reduction with streaming processing
|
|
56
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
|
|
57
57
|
|
|
58
58
|
### 📸 Screenshots
|
|
59
59
|
|
|
@@ -88,7 +88,7 @@ Configuration is managed through the `settings/i18ntk-config.json` file:
|
|
|
88
88
|
|
|
89
89
|
```json
|
|
90
90
|
{
|
|
91
|
-
"version": "1.7.
|
|
91
|
+
"version": "1.7.2",
|
|
92
92
|
"sourceDir": "./locales",
|
|
93
93
|
"outputDir": "./i18ntk-reports",
|
|
94
94
|
"defaultLanguage": "en",
|
|
@@ -176,6 +176,7 @@ const i18n = createI18n({ locale: 'en', messages: translations });
|
|
|
176
176
|
- **Encrypted Backups**: AES-256 encrypted backup storage
|
|
177
177
|
|
|
178
178
|
### 🎯 **NEW INTERACTIVE LOCALE OPTIMIZER** - up to 86% Package Size Reduction
|
|
179
|
+
|
|
179
180
|
- **Package Size**: 830.4KB → 115.3KB (86% reduction for English only)
|
|
180
181
|
- **Smart Management**: Interactive selection with automatic backups
|
|
181
182
|
- **Zero Breaking Changes**: Safe restoration from backups
|
|
@@ -199,51 +200,10 @@ your-project/
|
|
|
199
200
|
|
|
200
201
|
- **Locale files are backed up automatically** before optimization
|
|
201
202
|
- **Use interactive optimizer** for safe locale management
|
|
202
|
-
- **Zero breaking changes** from v1.6.x to v1.7.
|
|
203
|
-
- **All versions prior to 1.7.
|
|
203
|
+
- **Zero breaking changes** from v1.6.x to v1.7.1
|
|
204
|
+
- **All versions prior to 1.7.1 are deprecated**
|
|
204
205
|
- **All improvements applied automatically** on update
|
|
205
206
|
|
|
206
|
-
## 📞 Support
|
|
207
|
-
|
|
208
|
-
- **Issues**: [GitHub Issues](https://github.com/vladnoskv/i18ntk/issues)
|
|
209
|
-
- **Documentation**: [Complete docs](./docs)
|
|
210
|
-
- **Performance**: [Benchmark results](./benchmarks/results)
|
|
211
|
-
- **Version**: `i18ntk --version`
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
**Made for the global development community** ❤️
|
|
216
|
-
|
|
217
|
-
## Migration Guide
|
|
218
|
-
|
|
219
|
-
### Upgrading from Deprecated Versions
|
|
220
|
-
|
|
221
|
-
#### From any version < 1.7.0 (DEPRECATED - use latest version)
|
|
222
|
-
1. **Backup your current configuration**:
|
|
223
|
-
```bash
|
|
224
|
-
cp -r ./.i18ntk ./.i18ntk-backup-$(date +%Y%m%d)
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
2. **Install the latest version**:
|
|
228
|
-
```bash
|
|
229
|
-
npm install i18ntk@1.7.0
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
3. **Verify installation**:
|
|
233
|
-
```bash
|
|
234
|
-
i18ntk --version
|
|
235
|
-
i18ntk doctor
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
3. **Run configuration migration**:
|
|
239
|
-
```bash
|
|
240
|
-
npx i18ntk@1.6.3 --migrate
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
4. **Verify installation**:
|
|
244
|
-
```bash
|
|
245
|
-
npx i18ntk@1.6.3--validate
|
|
246
|
-
```
|
|
247
207
|
|
|
248
208
|
#### Preserved Features from 1.6.3
|
|
249
209
|
- ✅ Ultra-extreme performance improvements
|
|
@@ -256,9 +216,12 @@ your-project/
|
|
|
256
216
|
#### Breaking Changes
|
|
257
217
|
- **None** - 1.6.3 is fully backward compatible
|
|
258
218
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
219
|
+
## 📞 Support
|
|
220
|
+
|
|
221
|
+
- **Issues**: [GitHub Issues](https://github.com/vladnoskv/i18ntk/issues)
|
|
222
|
+
- **Documentation**: [Complete docs](./docs)
|
|
223
|
+
- **Performance**: [Benchmark results](./benchmarks/results)
|
|
224
|
+
- **Version**: `i18ntk --version`
|
|
225
|
+
---
|
|
264
226
|
|
|
227
|
+
**Made for the global development community** ❤️
|
package/main/i18ntk-analyze.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* I18N TRANSLATION ANALYSIS SCRIPT
|
|
4
4
|
*
|
|
@@ -11,7 +11,7 @@ const fs = require('fs');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const cliHelper = require('../utils/cli-helper');
|
|
13
13
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
14
|
-
loadTranslations(process.env.I18NTK_LANG
|
|
14
|
+
loadTranslations(process.env.I18NTK_LANG);
|
|
15
15
|
const { getUnifiedConfig, parseCommonArgs, displayHelp } = require('../utils/config-helper');
|
|
16
16
|
const SecurityUtils = require('../utils/security');
|
|
17
17
|
const AdminCLI = require('../utils/admin-cli');
|
package/main/i18ntk-autorun.js
CHANGED
|
@@ -14,7 +14,7 @@ const fs = require('fs');
|
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const { spawnSync } = require('child_process');
|
|
16
16
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
17
|
-
loadTranslations(process.env.I18NTK_LANG
|
|
17
|
+
loadTranslations(process.env.I18NTK_LANG);
|
|
18
18
|
const { getUnifiedConfig, parseCommonArgs, displayHelp, ensureInitialized } = require('../utils/config-helper');
|
|
19
19
|
const SecurityUtils = require('../utils/security');
|
|
20
20
|
const configManager = require('../utils/config-manager');
|
package/main/i18ntk-complete.js
CHANGED
|
@@ -17,7 +17,7 @@ const { execSync } = require('child_process');
|
|
|
17
17
|
const SecurityUtils = require('../utils/security');
|
|
18
18
|
const { getUnifiedConfig, parseCommonArgs, displayHelp } = require('../utils/config-helper');
|
|
19
19
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
20
|
-
loadTranslations(process.env.I18NTK_LANG
|
|
20
|
+
loadTranslations(process.env.I18NTK_LANG);
|
|
21
21
|
const { getGlobalReadline, closeGlobalReadline } = require('../utils/cli');
|
|
22
22
|
|
|
23
23
|
|
package/main/i18ntk-init.js
CHANGED
|
@@ -20,7 +20,7 @@ const AdminAuth = require('../utils/admin-auth');
|
|
|
20
20
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
21
21
|
// Ensure UIi18n is available for this initializer class
|
|
22
22
|
const UIi18n = require('./i18ntk-ui');
|
|
23
|
-
loadTranslations(process.env.I18NTK_LANG
|
|
23
|
+
loadTranslations(process.env.I18NTK_LANG);
|
|
24
24
|
const { getUnifiedConfig, parseCommonArgs, displayHelp } = require('../utils/config-helper');
|
|
25
25
|
const { showFrameworkWarningOnce } = require('../utils/cli-helper');
|
|
26
26
|
|
|
@@ -66,15 +66,16 @@ class I18nInitializer {
|
|
|
66
66
|
// No longer create readline interface here - use CLI helpers
|
|
67
67
|
this.rl = null;
|
|
68
68
|
this.shouldCloseRL = false;
|
|
69
|
+
this.announcedExistingDir = false;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
//
|
|
72
|
+
// Updated checkI18nDependencies method that uses configuration
|
|
72
73
|
async checkI18nDependencies(noPrompt = false) {
|
|
73
74
|
const packageJsonPath = path.resolve('./package.json');
|
|
74
75
|
|
|
75
76
|
if (!fs.existsSync(packageJsonPath)) {
|
|
76
77
|
console.log(t('init.noPackageJson'));
|
|
77
|
-
return
|
|
78
|
+
return true; // Allow to continue without framework
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
try {
|
|
@@ -100,14 +101,33 @@ class I18nInitializer {
|
|
|
100
101
|
|
|
101
102
|
if (installedFrameworks.length > 0) {
|
|
102
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
|
+
}
|
|
103
113
|
return true;
|
|
104
114
|
} else {
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
}
|
|
124
|
+
// Framework detection is now handled by maybePromptFramework in i18ntk-manage.js
|
|
125
|
+
// Skip prompting here to avoid double prompts
|
|
126
|
+
return true;
|
|
107
127
|
}
|
|
108
128
|
} catch (error) {
|
|
109
129
|
console.log(t('init.errors.packageJsonRead'));
|
|
110
|
-
return
|
|
130
|
+
return true; // Allow to continue on error
|
|
111
131
|
}
|
|
112
132
|
}
|
|
113
133
|
|
|
@@ -239,7 +259,10 @@ class I18nInitializer {
|
|
|
239
259
|
|
|
240
260
|
if (selectedIndex >= 0 && selectedIndex < existingLocations.length) {
|
|
241
261
|
const selectedDir = existingLocations[selectedIndex];
|
|
242
|
-
|
|
262
|
+
if (!this.announcedExistingDir) {
|
|
263
|
+
console.log(t('init.usingExistingDirectory', { dir: selectedDir }));
|
|
264
|
+
this.announcedExistingDir = true;
|
|
265
|
+
}
|
|
243
266
|
|
|
244
267
|
this.config.sourceDir = selectedDir;
|
|
245
268
|
this.sourceDir = path.resolve(selectedDir);
|
|
@@ -733,7 +756,10 @@ class I18nInitializer {
|
|
|
733
756
|
this.config.sourceDir = selectedDir;
|
|
734
757
|
this.sourceDir = path.resolve(selectedDir);
|
|
735
758
|
this.sourceLanguageDir = path.join(this.sourceDir, this.config.sourceLanguage);
|
|
736
|
-
|
|
759
|
+
if (!this.announcedExistingDir) {
|
|
760
|
+
console.log(t('init.usingExistingDirectory', { dir: selectedDir }));
|
|
761
|
+
this.announcedExistingDir = true;
|
|
762
|
+
}
|
|
737
763
|
} else {
|
|
738
764
|
await this.setupInitialStructure(args.noPrompt);
|
|
739
765
|
}
|
|
@@ -907,7 +933,14 @@ class I18nInitializer {
|
|
|
907
933
|
try {
|
|
908
934
|
// Parse command line arguments
|
|
909
935
|
const args = this.parseArgs();
|
|
910
|
-
|
|
936
|
+
|
|
937
|
+
// On first run, prompt user for preferred UI language
|
|
938
|
+
if (!fs.existsSync(configManager.CONFIG_PATH)) {
|
|
939
|
+
const { getGlobalReadline } = require('../utils/cli');
|
|
940
|
+
getGlobalReadline();
|
|
941
|
+
const selectedLang = await this.ui.selectLanguage();
|
|
942
|
+
loadTranslations(selectedLang);
|
|
943
|
+
}
|
|
911
944
|
// Initialize configuration properly when called from menu
|
|
912
945
|
if (fromMenu && !this.sourceDir) {
|
|
913
946
|
const baseConfig = await getUnifiedConfig('init', args);
|
package/main/i18ntk-manage.js
CHANGED
|
@@ -34,9 +34,174 @@ const I18nSizingAnalyzer = require('./i18ntk-sizing');
|
|
|
34
34
|
const SettingsCLI = require('../settings/settings-cli');
|
|
35
35
|
const I18nDebugger = require('../scripts/debug/debugger');
|
|
36
36
|
|
|
37
|
-
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
38
|
-
loadTranslations(process.env.I18NTK_LANG || 'en');
|
|
37
|
+
const { loadTranslations, t, refreshLanguageFromSettings} = require('../utils/i18n-helper');
|
|
39
38
|
const cliHelper = require('../utils/cli-helper');
|
|
39
|
+
const { loadConfig, saveConfig, ensureConfigDefaults } = require('../utils/config');
|
|
40
|
+
const pkg = require('../package.json');
|
|
41
|
+
|
|
42
|
+
async function runInitFlow(rl) {
|
|
43
|
+
const initializer = new I18nInitializer();
|
|
44
|
+
await initializer.run({ fromMenu: true });
|
|
45
|
+
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
46
|
+
return { i18nDir: settings.i18nDir, sourceDir: settings.sourceDir };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function askYesNo(rl, prompt) {
|
|
50
|
+
return new Promise(res => {
|
|
51
|
+
rl.question(prompt, a => res(/^y(es)?$/i.test(a.trim())));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function ensureInitializedOrExit(rl) {
|
|
56
|
+
const path = require('path');
|
|
57
|
+
const fs = require('fs');
|
|
58
|
+
const { ensureDirectory } = require('../utils/config-helper');
|
|
59
|
+
const settingsManager = require('../settings/settings-manager');
|
|
60
|
+
|
|
61
|
+
// Get configuration from settings manager
|
|
62
|
+
const settings = settingsManager.getAllSettings();
|
|
63
|
+
|
|
64
|
+
const cfg = {
|
|
65
|
+
sourceDir: path.resolve(settings.sourceDir || './locales'),
|
|
66
|
+
sourceLanguage: settings.sourceLanguage || 'en',
|
|
67
|
+
projectRoot: path.resolve('.'),
|
|
68
|
+
framework: settings.framework || { detected: false, prompt: 'always' }
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Check if already initialized using new tracking system
|
|
72
|
+
const initFilePath = path.join(settingsManager.configDir, 'initialization.json');
|
|
73
|
+
|
|
74
|
+
let isInitialized = false;
|
|
75
|
+
if (fs.existsSync(initFilePath)) {
|
|
76
|
+
try {
|
|
77
|
+
const initStatus = JSON.parse(fs.readFileSync(initFilePath, 'utf8'));
|
|
78
|
+
isInitialized = initStatus.initialized && initStatus.version === '1.7.2';
|
|
79
|
+
} catch (e) {
|
|
80
|
+
// Invalid init file, proceed with check
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isInitialized) {
|
|
85
|
+
return cfg;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check if source language files exist
|
|
89
|
+
const langDir = path.join(cfg.sourceDir, cfg.sourceLanguage);
|
|
90
|
+
|
|
91
|
+
const hasLanguageFiles = fs.existsSync(langDir) &&
|
|
92
|
+
fs.readdirSync(langDir).some(f => f.endsWith('.json'));
|
|
93
|
+
|
|
94
|
+
// If language files exist, mark as initialized
|
|
95
|
+
if (hasLanguageFiles) {
|
|
96
|
+
const initDir = path.dirname(initFilePath);
|
|
97
|
+
ensureDirectory(initDir);
|
|
98
|
+
fs.writeFileSync(initFilePath, JSON.stringify({
|
|
99
|
+
initialized: true,
|
|
100
|
+
version: '1.7.2',
|
|
101
|
+
timestamp: new Date().toISOString(),
|
|
102
|
+
sourceDir: cfg.sourceDir,
|
|
103
|
+
sourceLanguage: cfg.sourceLanguage
|
|
104
|
+
}, null, 2));
|
|
105
|
+
return cfg;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const answer = await askYesNo(rl, 'Initialization Required\nThis project must be initialized before running this command.\nWould you like to run initialization now? (y/N): ');
|
|
109
|
+
if (!answer) {
|
|
110
|
+
console.log('Operation cancelled.');
|
|
111
|
+
process.exit(0);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const result = await runInitFlow(rl);
|
|
115
|
+
|
|
116
|
+
// Mark as initialized after successful init
|
|
117
|
+
const initDir = path.dirname(initFilePath);
|
|
118
|
+
ensureDirectory(initDir);
|
|
119
|
+
fs.writeFileSync(initFilePath, JSON.stringify({
|
|
120
|
+
initialized: true,
|
|
121
|
+
version: '1.7.2',
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
sourceDir: result.sourceDir || cfg.sourceDir,
|
|
124
|
+
sourceLanguage: cfg.sourceLanguage
|
|
125
|
+
}, null, 2));
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
...cfg,
|
|
129
|
+
sourceDir: result.sourceDir || cfg.sourceDir,
|
|
130
|
+
i18nDir: result.i18nDir || cfg.i18nDir
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function maybePromptFramework(rl, cfg, currentVersion) {
|
|
135
|
+
// Load current settings to check framework configuration
|
|
136
|
+
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
137
|
+
|
|
138
|
+
// Ensure framework configuration exists
|
|
139
|
+
if (!settings.framework) {
|
|
140
|
+
settings.framework = {
|
|
141
|
+
detected: false,
|
|
142
|
+
preference: null,
|
|
143
|
+
prompt: 'always',
|
|
144
|
+
lastPromptedVersion: null
|
|
145
|
+
};
|
|
146
|
+
}
|
|
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
|
+
|
|
154
|
+
// Check if framework is already detected or preference is set to none
|
|
155
|
+
if (settings.framework.detected || settings.framework.preference === 'none') {
|
|
156
|
+
return cfg;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check if dnr (do not remind) is active for this version
|
|
160
|
+
if (settings.framework.prompt === 'suppress' && settings.framework.lastPromptedVersion === currentVersion) {
|
|
161
|
+
return cfg;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Reset suppress if version changed
|
|
165
|
+
if (settings.framework.prompt === 'suppress' && settings.framework.lastPromptedVersion !== currentVersion) {
|
|
166
|
+
settings.framework.prompt = 'always';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (settings.framework.prompt === 'always') {
|
|
170
|
+
const ans = await new Promise(res =>
|
|
171
|
+
rl.question([
|
|
172
|
+
t('init.suggestions.noFramework'),
|
|
173
|
+
t('init.frameworks.react'),
|
|
174
|
+
t('init.frameworks.vue'),
|
|
175
|
+
t('init.frameworks.i18next'),
|
|
176
|
+
t('init.frameworks.nuxt'),
|
|
177
|
+
t('init.frameworks.svelte'),
|
|
178
|
+
'',
|
|
179
|
+
t('init.continueWithoutI18nPrompt') + ' (y/N/dnr = do not remind until next update): '
|
|
180
|
+
].join('\n'), a => res(a.trim().toLowerCase()))
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (ans === 'y' || ans === 'yes') {
|
|
184
|
+
settings.framework.preference = 'none';
|
|
185
|
+
settings.framework.prompt = 'always'; // Keep asking until explicitly suppressed
|
|
186
|
+
} else if (ans === 'dnr') {
|
|
187
|
+
settings.framework.preference = 'none';
|
|
188
|
+
settings.framework.prompt = 'suppress';
|
|
189
|
+
settings.framework.lastPromptedVersion = currentVersion;
|
|
190
|
+
} else {
|
|
191
|
+
console.log('Operation cancelled.');
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Save configuration using settings manager
|
|
196
|
+
if (configManager.saveSettings) {
|
|
197
|
+
configManager.saveSettings(settings);
|
|
198
|
+
} else if (configManager.saveConfig) {
|
|
199
|
+
configManager.saveConfig(settings);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return cfg;
|
|
204
|
+
}
|
|
40
205
|
|
|
41
206
|
// Use unified configuration system
|
|
42
207
|
const { getUnifiedConfig, ensureInitialized, validateSourceDir } = require('../utils/config-helper');
|
|
@@ -48,7 +213,7 @@ class I18nManager {
|
|
|
48
213
|
this.isReadlineClosed = false;
|
|
49
214
|
this.isAuthenticated = false;
|
|
50
215
|
this.ui = null;
|
|
51
|
-
this.adminAuth =
|
|
216
|
+
this.adminAuth = new AdminAuth();
|
|
52
217
|
|
|
53
218
|
// No longer create readline interface here - use CLI helpers
|
|
54
219
|
}
|
|
@@ -62,34 +227,29 @@ class I18nManager {
|
|
|
62
227
|
// Initialize configuration using unified system
|
|
63
228
|
async initialize() {
|
|
64
229
|
try {
|
|
230
|
+
// Parse args here for other initialization needs (but language is already loaded)
|
|
65
231
|
const args = this.parseArgs();
|
|
66
232
|
if (args.help) {
|
|
67
233
|
this.showHelp();
|
|
68
234
|
process.exit(0);
|
|
69
235
|
}
|
|
70
236
|
|
|
71
|
-
|
|
72
|
-
this.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.adminAuth = new AdminAuth();
|
|
79
|
-
|
|
80
|
-
// Load language from saved configuration, not just CLI args
|
|
81
|
-
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
82
|
-
const uiLanguage = settings.uiLanguage || settings.language || this.config.uiLanguage || 'en';
|
|
83
|
-
this.ui.loadLanguage(uiLanguage);
|
|
237
|
+
// Ensure UI is initialized (it should already be loaded in run())
|
|
238
|
+
if (!this.ui) {
|
|
239
|
+
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
240
|
+
const uiLanguage = args.uiLanguage || settings.uiLanguage || settings.language || this.config.uiLanguage || 'en';
|
|
241
|
+
this.ui.loadLanguage(uiLanguage);
|
|
242
|
+
loadTranslations(uiLanguage);
|
|
243
|
+
}
|
|
84
244
|
|
|
85
245
|
// Validate source directory exists
|
|
86
246
|
const {validateSourceDir, displayPaths} = require('../utils/config-helper');
|
|
87
247
|
try {
|
|
88
248
|
validateSourceDir(this.config.sourceDir, 'i18ntk-manage');
|
|
89
249
|
} catch (err) {
|
|
90
|
-
console.log(t('init.requiredTitle'));
|
|
91
|
-
console.log(t('init.requiredBody'));
|
|
92
|
-
const answer = await cliHelper.prompt(t('init.promptRunNow'));
|
|
250
|
+
console.log(this.ui.t('init.requiredTitle'));
|
|
251
|
+
console.log(this.ui.t('init.requiredBody'));
|
|
252
|
+
const answer = await cliHelper.prompt(this.ui.t('init.promptRunNow'));
|
|
93
253
|
if (answer.trim().toLowerCase() === 'y') {
|
|
94
254
|
const initializer = new I18nInitializer(this.config);
|
|
95
255
|
await initializer.run({ fromMenu: true });
|
|
@@ -99,13 +259,14 @@ class I18nManager {
|
|
|
99
259
|
}
|
|
100
260
|
|
|
101
261
|
} catch (error) {
|
|
102
|
-
|
|
262
|
+
|
|
103
263
|
throw error;
|
|
104
264
|
}
|
|
105
265
|
}
|
|
106
266
|
|
|
107
267
|
// Auto-detect i18n directory from common locations only if not configured in settings
|
|
108
268
|
detectI18nDirectory() {
|
|
269
|
+
|
|
109
270
|
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
110
271
|
const projectRoot = path.resolve(settings.projectRoot || this.config.projectRoot || '.');
|
|
111
272
|
|
|
@@ -156,13 +317,13 @@ class I18nManager {
|
|
|
156
317
|
}
|
|
157
318
|
}
|
|
158
319
|
|
|
159
|
-
// Check if i18n framework is installed
|
|
320
|
+
// Check if i18n framework is installed - configuration-based check without prompts
|
|
160
321
|
async checkI18nDependencies() {
|
|
161
322
|
const packageJsonPath = path.resolve('./package.json');
|
|
162
323
|
|
|
163
324
|
if (!fs.existsSync(packageJsonPath)) {
|
|
164
|
-
console.log(t('init.noPackageJson'));
|
|
165
|
-
return
|
|
325
|
+
console.log(this.ui ? this.ui.t('init.noPackageJson') : 'No package.json found');
|
|
326
|
+
return true; // Allow to continue without framework
|
|
166
327
|
}
|
|
167
328
|
|
|
168
329
|
try {
|
|
@@ -185,22 +346,44 @@ class I18nManager {
|
|
|
185
346
|
];
|
|
186
347
|
|
|
187
348
|
const installedFrameworks = i18nFrameworks.filter(framework => dependencies[framework]);
|
|
188
|
-
|
|
349
|
+
|
|
189
350
|
if (installedFrameworks.length > 0) {
|
|
190
|
-
|
|
351
|
+
if (this.ui && this.ui.t) {
|
|
352
|
+
console.log(this.ui.t('init.detectedFrameworks', { frameworks: installedFrameworks.join(', ') }));
|
|
353
|
+
} else {
|
|
354
|
+
console.log(`Detected frameworks: ${installedFrameworks.join(', ')}`);
|
|
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
|
+
}
|
|
191
365
|
return true;
|
|
192
366
|
} else {
|
|
193
367
|
const cfg = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
194
|
-
if (cfg.framework
|
|
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
|
+
}
|
|
376
|
+
// If framework preference is already set to 'none', skip warning
|
|
377
|
+
if (cfg.framework === 'none' || (cfg.framework && cfg.framework.preference === 'none')) {
|
|
195
378
|
return true;
|
|
196
379
|
}
|
|
197
|
-
showFrameworkWarningOnce(this.ui);
|
|
198
380
|
|
|
199
|
-
return
|
|
381
|
+
// Framework detection is handled by maybePromptFramework, so just return true here
|
|
382
|
+
return true;
|
|
200
383
|
}
|
|
201
384
|
} catch (error) {
|
|
202
385
|
console.log(t('init.errors.packageJsonRead'));
|
|
203
|
-
return
|
|
386
|
+
return true; // Allow to continue on error
|
|
204
387
|
}
|
|
205
388
|
}
|
|
206
389
|
|
|
@@ -208,7 +391,8 @@ class I18nManager {
|
|
|
208
391
|
* Prompt user to continue without i18n framework
|
|
209
392
|
*/
|
|
210
393
|
async promptContinueWithoutI18n() {
|
|
211
|
-
const
|
|
394
|
+
const promptText = this.ui && this.ui.t ? this.ui.t('init.continueWithoutI18nPrompt') : 'Do you want to continue without one? (y/N)';
|
|
395
|
+
const answer = await this.prompt('\n' + promptText);
|
|
212
396
|
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
213
397
|
}
|
|
214
398
|
|
|
@@ -259,11 +443,28 @@ class I18nManager {
|
|
|
259
443
|
// Add this run method after the checkI18nDependencies method
|
|
260
444
|
async run() {
|
|
261
445
|
try {
|
|
446
|
+
// Parse command line arguments first
|
|
447
|
+
const args = this.parseArgs();
|
|
448
|
+
|
|
449
|
+
// Load settings to get language preference BEFORE any messages
|
|
450
|
+
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
451
|
+
|
|
452
|
+
// Initialize UI localization system with language from settings
|
|
453
|
+
this.ui = new UIi18n();
|
|
454
|
+
const uiLanguage = args.uiLanguage || settings.uiLanguage || settings.language || this.config.uiLanguage || 'en';
|
|
455
|
+
this.ui.loadLanguage(uiLanguage);
|
|
456
|
+
|
|
457
|
+
const rl = cliHelper.getInterface();
|
|
458
|
+
const cfgAfterInitCheck = await ensureInitializedOrExit(rl);
|
|
459
|
+
await this.checkI18nDependencies();
|
|
460
|
+
await maybePromptFramework(rl, cfgAfterInitCheck, pkg.version);
|
|
461
|
+
|
|
462
|
+
// Update this.config with the configuration from ensureInitializedOrExit
|
|
463
|
+
this.config = { ...this.config, ...cfgAfterInitCheck };
|
|
464
|
+
|
|
262
465
|
// Initialize configuration using unified system
|
|
263
466
|
await this.initialize();
|
|
264
467
|
|
|
265
|
-
// Parse command line arguments
|
|
266
|
-
const args = this.parseArgs();
|
|
267
468
|
const rawArgs = process.argv.slice(2); // Preserve original CLI args array for positional checks
|
|
268
469
|
let commandToExecute = null;
|
|
269
470
|
|
|
@@ -301,13 +502,8 @@ class I18nManager {
|
|
|
301
502
|
return;
|
|
302
503
|
}
|
|
303
504
|
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
if (!shouldContinue) {
|
|
307
|
-
console.log(t('init.errorsNoFramework'));
|
|
308
|
-
console.log(t('init.suggestions.installFramework'));
|
|
309
|
-
process.exit(0);
|
|
310
|
-
}
|
|
505
|
+
// Framework detection is now handled by maybePromptFramework above
|
|
506
|
+
// Skip the redundant checkI18nDependencies prompt
|
|
311
507
|
|
|
312
508
|
// Interactive mode - showInteractiveMenu will handle the title
|
|
313
509
|
await this.showInteractiveMenu();
|
|
@@ -891,7 +1087,7 @@ class I18nManager {
|
|
|
891
1087
|
{ path: path.join(process.cwd(), 'reports', 'backups'), name: 'Reports Backups', type: 'backups' },
|
|
892
1088
|
{ path: path.join(process.cwd(), 'scripts', 'debug', 'logs'), name: 'Debug Logs', type: 'logs' },
|
|
893
1089
|
{ path: path.join(process.cwd(), 'scripts', 'debug', 'reports'), name: 'Debug Reports', type: 'reports' },
|
|
894
|
-
{ path: path.join(
|
|
1090
|
+
{ path: path.join(configManager.configDir, 'backups'), name: 'Settings Backups', type: 'backups' },
|
|
895
1091
|
{ path: path.join(process.cwd(), 'utils', 'i18ntk-reports'), name: 'Utils Reports', type: 'reports' }
|
|
896
1092
|
];
|
|
897
1093
|
|
package/main/i18ntk-sizing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* I18n Sizing Analyzer
|
|
@@ -35,7 +35,7 @@ const fs = require('fs');
|
|
|
35
35
|
const path = require('path');
|
|
36
36
|
const { performance } = require('perf_hooks');
|
|
37
37
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
38
|
-
loadTranslations(process.env.I18NTK_LANG
|
|
38
|
+
loadTranslations(process.env.I18NTK_LANG);
|
|
39
39
|
const configManager = require('../settings/settings-manager');
|
|
40
40
|
const SecurityUtils = require('../utils/security');
|
|
41
41
|
const { getUnifiedConfig } = require('../utils/config-helper');
|
package/main/i18ntk-summary.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
6
|
-
loadTranslations(process.env.I18NTK_LANG
|
|
6
|
+
loadTranslations(process.env.I18NTK_LANG);
|
|
7
7
|
const { getUnifiedConfig, parseCommonArgs, displayHelp } = require('../utils/config-helper');
|
|
8
8
|
const SecurityUtils = require('../utils/security');
|
|
9
9
|
const AdminCLI = require('../utils/admin-cli');
|