i18ntk 4.7.0 → 4.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/CHANGELOG.md +34 -1
- package/README.md +15 -4
- package/main/i18ntk-ui.js +35 -30
- package/main/i18ntk-usage.js +2 -2
- package/main/i18ntk-validate.js +1 -1
- package/main/manage/commands/ValidateCommand.js +1 -1
- package/main/manage/index.js +52 -47
- package/main/manage/managers/LanguageMenu.js +3 -1
- package/main/manage/services/ConfigurationService.js +1 -1
- package/main/manage/services/FrameworkDetectionService.js +1 -1
- package/main/manage/services/UsageService.js +2 -2
- package/package.json +11 -7
- package/settings/settings-manager.js +19 -3
- package/ui-locales/ar.json +2636 -0
- package/ui-locales/cs.json +2636 -0
- package/ui-locales/de.json +17 -1
- package/ui-locales/el.json +2636 -0
- package/ui-locales/en.json +17 -1
- package/ui-locales/es.json +17 -1
- package/ui-locales/fr.json +17 -1
- package/ui-locales/he.json +2636 -0
- package/ui-locales/hi.json +2636 -0
- package/ui-locales/hu.json +2636 -0
- package/ui-locales/it.json +2636 -0
- package/ui-locales/ja.json +17 -1
- package/ui-locales/ko.json +2636 -0
- package/ui-locales/nl.json +2636 -0
- package/ui-locales/pl.json +2636 -0
- package/ui-locales/pt.json +2636 -0
- package/ui-locales/ru.json +17 -1
- package/ui-locales/sv.json +2636 -0
- package/ui-locales/th.json +2636 -0
- package/ui-locales/tr.json +2636 -0
- package/ui-locales/uk.json +2636 -0
- package/ui-locales/vi.json +2636 -0
- package/ui-locales/zh.json +17 -1
- package/utils/config-helper.js +2 -2
- package/utils/config-manager.js +3 -4
- package/utils/env-manager.js +1 -1
- package/utils/locale-optimizer.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
|
|
7
|
+
## [4.7.2] - 2026-07-07
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Dynamic CLI language selector** — Option 12 now derives available languages and native display names from `SettingsManager.getAvailableLanguages()` instead of stale hardcoded 7-language lists.
|
|
12
|
+
- **Future-proof prompt range** — Language selection prompts now render the numeric upper bound from the current available language count, so future UI locale expansion does not leave stale `0-8` prompt text behind.
|
|
13
|
+
- **Fallback manager parity** — `main/manage/index.js` now instantiates `SettingsManager`, shows the real current UI language, persists `language` and `uiLanguage`, and uses the same 23-language registry as the rest of the CLI.
|
|
14
|
+
|
|
15
|
+
## [4.7.1] - 2026-07-07
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **23 UI locale languages** — Expanded from 7 to 23: Italian, Portuguese, Dutch, Polish, Swedish, Ukrainian, Czech, Turkish, Korean, Arabic, Hindi, Thai, Vietnamese, Hebrew, Greek, Hungarian. All 2,211 keys auto-translated with placeholder preservation via i18ntk's own pipeline. 95-98% translation completeness, 0 missing keys.
|
|
20
|
+
- **Native language names** — `settings.languages.{code}` entries added to all 23 locale files with names in native script (Italiano, 日本語, العربية, हिन्दी, etc.). `getAvailableLanguages()` returns all 23 with display names.
|
|
21
|
+
- **Settings schema expanded** — `language` and `uiLanguage` enum constraints expanded from 7 to 23 entries. Language selector in settings UI and CLI picks up all available languages.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **Framework detection centralized** — `manage/index.js` `detectEnvironmentAndFramework()` now calls `detectProjectFramework()` from the centralized detector instead of a 6-framework inline check. Detects all 30+ supported frameworks.
|
|
26
|
+
- **Hardcoded `framework.supported` removed** — Config templates (`config-manager.js`) and runtime config (`.i18ntk-config`) no longer ship a static framework list. Only actually-detected frameworks appear.
|
|
27
|
+
- **`checkI18nDependencies()` expanded** — Framework package lists unified across `manage/index.js`, `i18ntk-manage.js`, `InitService.js`, and `FrameworkDetectionService.js` (8→29 entries each).
|
|
28
|
+
- **Hardcoded 7-language lists expanded to 23** — Updated in 12 production files: `i18n-usage.js`, `i18n-validate.js`, `ValidateCommand.js`, `UsageService.js`, `FrameworkDetectionService.js`, `ConfigurationService.js`, `i18ntk-manage.js`, `locale-optimizer.js` ×2, `env-manager.js`, `i18ntk-ui.js`, `manage/index.js`.
|
|
29
|
+
- **Default config template expanded** — `config-helper.js` `supportedLanguages` and template skeleton files expanded from 8 to 23 languages.
|
|
30
|
+
- **Missing key validator** — Default constructor argument expanded from 7 to 23 languages.
|
|
31
|
+
- **Version bumped to 4.7.1** for language expansion and framework detection cleanup.
|
|
32
|
+
|
|
33
|
+
### Verified
|
|
34
|
+
|
|
35
|
+
- Language switching tested via `i18n-helper.loadTranslations()` across all 23 locales — all return non-English values.
|
|
36
|
+
- 69 core tests pass, 98 sandbox tests pass.
|
|
37
|
+
- Package JSON manifest sync test passes (version, versionInfo, nextVersion aligned).
|
|
38
|
+
- All 23 locale files have valid JSON syntax.
|
|
6
39
|
|
|
7
40
|
## [4.7.0] - 2026-07-07
|
|
8
41
|
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# i18ntk v4.7.
|
|
1
|
+
# i18ntk v4.7.2
|
|
2
2
|
|
|
3
3
|
A zero-dependency internationalization toolkit for setup, scanning, analysis, validation, usage tracking, translation completion, automatic JSON locale translation, reporting, and runtime translation loading.
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ A zero-dependency internationalization toolkit for setup, scanning, analysis, va
|
|
|
9
9
|
[](https://nodejs.org)
|
|
10
10
|
[](https://www.npmjs.com/package/i18ntk)
|
|
11
11
|
[](LICENSE)
|
|
12
|
-
[](https://socket.dev/npm/package/i18ntk/overview/4.7.2)
|
|
13
13
|
|
|
14
14
|
[](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-workbench)
|
|
15
15
|
[](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-lens)
|
|
@@ -27,6 +27,18 @@ npm install -g i18ntk
|
|
|
27
27
|
npx i18ntk --help
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
## What's New in 4.7.2
|
|
31
|
+
|
|
32
|
+
- **Dynamic Language Selector** — The interactive "Change UI Language" menu now derives its options and display names from the package language registry, including the fallback `manage/index.js` entrypoint.
|
|
33
|
+
- **Future-Proof Prompt Range** — The language selection prompt now renders `0-N` from the installed UI locale count instead of using a stale translated `0-8` range, so future locale expansion updates automatically.
|
|
34
|
+
|
|
35
|
+
## What's New in 4.7.1
|
|
36
|
+
|
|
37
|
+
- **23 UI Languages** — Expanded from 7 to 23: Italian, Portuguese, Dutch, Polish, Swedish, Ukrainian, Czech, Turkish, Korean, Arabic, Hindi, Thai, Vietnamese, Hebrew, Greek, Hungarian. All 2,211 keys auto-translated and verified.
|
|
38
|
+
- **Framework Detection Cleanup** — Removed hardcoded `framework.supported` lists from config templates. `manage/index.js` now uses centralized `detectProjectFramework()` covering all 30+ frameworks. Only detected frameworks appear in setup — no more static catalog.
|
|
39
|
+
- **Language Selector** — Settings UI, `getAvailableLanguages()`, and schema enums all expanded from 7 to 23 languages with native names.
|
|
40
|
+
- **12 Production Files Updated** — Hardcoded 7-language arrays expanded to 23: validators, locale optimizers, env manager, usage tracking, UI, and config helpers.
|
|
41
|
+
|
|
30
42
|
## What's New in 4.7.0
|
|
31
43
|
|
|
32
44
|
- **30+ framework detection patterns** — 13 new FRAMEWORK_PATTERNS: `i18ntk-runtime`, `nuxt`, `lingui`, `formatjs`, `ngx-translate`, `next-intl`, `svelte-i18n`, `solid-i18n`, `fastapi`, `ruby-on-rails`, `react-native-localize`, `ionic`. Each with framework-specific scan regexes for translation calls, JSX components, template directives, and pipes.
|
|
@@ -36,8 +48,7 @@ npx i18ntk --help
|
|
|
36
48
|
- **Expanded namespace helpers** — `useTranslate` (Qwik), `useSpeak` (Qwik), `withTranslation` (react-i18next) added.
|
|
37
49
|
- **Attribute key detection** — `i18nKey=`, `t-key=`, `data-i18n=` attributes detected in source scanning.
|
|
38
50
|
- **All frame works now have FRAMEWORK_COMPATIBILITY entries and FRAMEWORK_SUGGESTIONS** for consistent tooling.
|
|
39
|
-
|
|
40
|
-
[Full changelog →](./CHANGELOG.md)
|
|
51
|
+
[Full changelog →](./CHANGELOG.md)
|
|
41
52
|
|
|
42
53
|
## Quick Start
|
|
43
54
|
|
package/main/i18ntk-ui.js
CHANGED
|
@@ -5,11 +5,25 @@
|
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
-
const SettingsManager = require('../settings/settings-manager');
|
|
9
|
-
const SecurityUtils = require('../utils/security');
|
|
10
|
-
const legacyConfigManager = require('../utils/config-manager');
|
|
11
|
-
const { getIcon, isUnicodeSupported } = require('../utils/terminal-icons');
|
|
12
|
-
const
|
|
8
|
+
const SettingsManager = require('../settings/settings-manager');
|
|
9
|
+
const SecurityUtils = require('../utils/security');
|
|
10
|
+
const legacyConfigManager = require('../utils/config-manager');
|
|
11
|
+
const { getIcon, isUnicodeSupported } = require('../utils/terminal-icons');
|
|
12
|
+
const { formatLanguagePrompt } = require('../utils/language-menu');
|
|
13
|
+
const configManager = new SettingsManager();
|
|
14
|
+
|
|
15
|
+
function getSupportedUiLanguages() {
|
|
16
|
+
return configManager.getAvailableLanguages();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getSupportedUiLanguageCodes() {
|
|
20
|
+
return getSupportedUiLanguages().map(language => language.code);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getSupportedUiLanguageName(langCode) {
|
|
24
|
+
const language = getSupportedUiLanguages().find(item => item.code === langCode);
|
|
25
|
+
return language ? language.name : langCode;
|
|
26
|
+
}
|
|
13
27
|
|
|
14
28
|
class UIi18n {
|
|
15
29
|
constructor() {
|
|
@@ -99,12 +113,12 @@ this.translations = {};
|
|
|
99
113
|
* Detect which UI locales are currently installed
|
|
100
114
|
* @returns {string[]} Array of available language codes
|
|
101
115
|
*/
|
|
102
|
-
detectAvailableLanguages() {
|
|
103
|
-
const all =
|
|
104
|
-
return all.filter(lang => {
|
|
105
|
-
const filePath = path.join(this.uiLocalesDir, `${lang}.json`);
|
|
106
|
-
return SecurityUtils.safeExistsSync(filePath, this.getValidationBase(filePath));
|
|
107
|
-
});
|
|
116
|
+
detectAvailableLanguages() {
|
|
117
|
+
const all = getSupportedUiLanguageCodes();
|
|
118
|
+
return all.filter(lang => {
|
|
119
|
+
const filePath = path.join(this.uiLocalesDir, `${lang}.json`);
|
|
120
|
+
return SecurityUtils.safeExistsSync(filePath, this.getValidationBase(filePath));
|
|
121
|
+
});
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
/**
|
|
@@ -481,27 +495,17 @@ this.translations = {};
|
|
|
481
495
|
* @param {string} langCode - Language code
|
|
482
496
|
* @returns {string} Display name of the language
|
|
483
497
|
*/
|
|
484
|
-
getLanguageDisplayName(langCode) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
'es': 'Español (Spanish)',
|
|
489
|
-
'fr': 'Français (French)',
|
|
490
|
-
'ru': 'Русский (Russian)',
|
|
491
|
-
'ja': '日本語 (Japanese)',
|
|
492
|
-
'zh': '中文 (Chinese)'
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
// Hardcoded texts that are not part of the i18n system but need to be displayed
|
|
496
|
-
this.hardcodedTexts = {
|
|
497
|
-
autoDetectedI18nDirectory: this.t('ui.autoDetectedI18nDirectory'),
|
|
498
|
+
getLanguageDisplayName(langCode) {
|
|
499
|
+
// Hardcoded texts that are not part of the i18n system but need to be displayed
|
|
500
|
+
this.hardcodedTexts = {
|
|
501
|
+
autoDetectedI18nDirectory: this.t('ui.autoDetectedI18nDirectory'),
|
|
498
502
|
executingCommand: this.t('ui.executingCommand'),
|
|
499
503
|
unknownCommand: this.t('ui.unknownCommand'),
|
|
500
504
|
errorExecutingCommand: this.t('ui.errorExecutingCommand')
|
|
501
|
-
|
|
502
|
-
};
|
|
503
|
-
return
|
|
504
|
-
}
|
|
505
|
+
|
|
506
|
+
};
|
|
507
|
+
return getSupportedUiLanguageName(langCode);
|
|
508
|
+
}
|
|
505
509
|
|
|
506
510
|
/**
|
|
507
511
|
* Interactive language selection menu
|
|
@@ -528,7 +532,8 @@ this.translations = {};
|
|
|
528
532
|
console.log(this.t('language.languageOption', { index: index + 1, displayName, current }));
|
|
529
533
|
});
|
|
530
534
|
|
|
531
|
-
|
|
535
|
+
const languagePrompt = formatLanguagePrompt(this.t('language.prompt'), this.availableLanguages.length);
|
|
536
|
+
rl.question('\n' + languagePrompt, async (answer) => {
|
|
532
537
|
const choice = parseInt(answer);
|
|
533
538
|
|
|
534
539
|
if (choice === 0) {
|
package/main/i18ntk-usage.js
CHANGED
|
@@ -1208,7 +1208,7 @@ Analysis Features (v1.10.1):
|
|
|
1208
1208
|
});
|
|
1209
1209
|
|
|
1210
1210
|
for (const lang of allLanguageDirs) {
|
|
1211
|
-
if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(lang)) {
|
|
1211
|
+
if (['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(lang)) {
|
|
1212
1212
|
languages.add(lang);
|
|
1213
1213
|
}
|
|
1214
1214
|
}
|
|
@@ -1217,7 +1217,7 @@ Analysis Features (v1.10.1):
|
|
|
1217
1217
|
const directFiles = fs.readdirSync(this.i18nDir)
|
|
1218
1218
|
.filter(file => file.endsWith('.json'))
|
|
1219
1219
|
.map(file => path.basename(file, '.json'))
|
|
1220
|
-
.filter(lang => ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(lang));
|
|
1220
|
+
.filter(lang => ['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(lang));
|
|
1221
1221
|
|
|
1222
1222
|
directFiles.forEach(lang => languages.add(lang));
|
|
1223
1223
|
} catch (error) {
|
package/main/i18ntk-validate.js
CHANGED
|
@@ -186,7 +186,7 @@ class I18nValidator {
|
|
|
186
186
|
baseArgs.enforceKeyStyle = val === undefined ? true : val !== 'false';
|
|
187
187
|
} else if (sanitizedArg.startsWith('--') && !sanitizedArg.includes('=')) {
|
|
188
188
|
const key = sanitizedArg.substring(2);
|
|
189
|
-
if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(key)) {
|
|
189
|
+
if (['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(key)) {
|
|
190
190
|
baseArgs.uiLanguage = key;
|
|
191
191
|
}
|
|
192
192
|
}
|
|
@@ -163,7 +163,7 @@ class ValidateCommand {
|
|
|
163
163
|
const sanitizedArg = SecurityUtils.sanitizeInput(arg);
|
|
164
164
|
if (sanitizedArg.startsWith('--') && !sanitizedArg.includes('=')) {
|
|
165
165
|
const key = sanitizedArg.substring(2);
|
|
166
|
-
if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(key)) {
|
|
166
|
+
if (['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(key)) {
|
|
167
167
|
baseArgs.uiLanguage = key;
|
|
168
168
|
}
|
|
169
169
|
}
|
package/main/manage/index.js
CHANGED
|
@@ -17,21 +17,25 @@ const path = require('path');
|
|
|
17
17
|
const fs = require('fs');
|
|
18
18
|
const AdminAuth = require('../../utils/admin-auth');
|
|
19
19
|
const SecurityUtils = require('../../utils/security');
|
|
20
|
-
const
|
|
20
|
+
const SettingsManager = require('../../settings/settings-manager');
|
|
21
21
|
const { validateSourceDir } = require('../../utils/config-helper');
|
|
22
22
|
const { checkInitialized } = require('../../utils/init-helper');
|
|
23
23
|
const { showFrameworkWarningOnce } = require('../../utils/cli-helper');
|
|
24
24
|
const { createPrompt, isInteractive } = require('../../utils/prompt-helper');
|
|
25
25
|
const { loadTranslations, t, refreshLanguageFromSettings} = require('../../utils/i18n-helper');
|
|
26
|
+
const { formatLanguagePrompt } = require('../../utils/language-menu');
|
|
26
27
|
const cliHelper = require('../../utils/cli-helper');
|
|
27
28
|
const { printUpgradeWarningIfOutdated } = require('../../utils/npm-version-warning');
|
|
28
29
|
const { blue } = require('../../utils/colors-new');
|
|
29
30
|
const { loadConfig, saveConfig, ensureConfigDefaults } = require('../../utils/config');
|
|
30
31
|
const { buildMainMenuLines } = require('../../utils/menu-layout');
|
|
31
32
|
const SettingsCLI = require('../../settings/settings-cli');
|
|
32
|
-
const pkg = require('../../package.json');
|
|
33
|
+
const pkg = require('../../package.json');
|
|
33
34
|
const SetupEnforcer = require('../../utils/setup-enforcer');
|
|
34
35
|
const CommandRouter = require('./commands/CommandRouter');
|
|
36
|
+
const { detectProjectFramework } = require('../../utils/framework-detector');
|
|
37
|
+
|
|
38
|
+
const configManager = new SettingsManager();
|
|
35
39
|
|
|
36
40
|
// Import services to replace circular dependencies
|
|
37
41
|
const ConfigurationService = require('./services/ConfigurationService');
|
|
@@ -142,7 +146,7 @@ class I18nManager {
|
|
|
142
146
|
const hasLanguageDirs = items.some(item => {
|
|
143
147
|
const itemPath = path.join(resolvedPath, item);
|
|
144
148
|
return fs.statSync(itemPath).isDirectory() &&
|
|
145
|
-
['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(item);
|
|
149
|
+
['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(item);
|
|
146
150
|
});
|
|
147
151
|
|
|
148
152
|
if (hasLanguageDirs) {
|
|
@@ -201,15 +205,15 @@ class I18nManager {
|
|
|
201
205
|
};
|
|
202
206
|
|
|
203
207
|
const i18nFrameworks = [
|
|
204
|
-
'react-i18next',
|
|
205
|
-
'
|
|
206
|
-
'
|
|
207
|
-
'i18next',
|
|
208
|
-
'
|
|
209
|
-
'
|
|
210
|
-
'@
|
|
211
|
-
'i18ntk-runtime',
|
|
212
|
-
'i18ntk'
|
|
208
|
+
'react-i18next', 'vue-i18n', 'i18next', 'next-i18next',
|
|
209
|
+
'svelte-i18n', '@nuxtjs/i18n', 'next-intl', 'remix-i18next',
|
|
210
|
+
'i18next-remix', 'gatsby-plugin-react-i18next', 'gatsby-plugin-intl',
|
|
211
|
+
'sveltekit-i18n', 'astro-i18next', '@astrojs/i18n',
|
|
212
|
+
'qwik-speak', 'qwik-i18n', '@solid-primitives/i18n',
|
|
213
|
+
'ember-intl', 'react-native-localize', 'expo-localization',
|
|
214
|
+
'@ngx-translate/core', '@ionic/angular',
|
|
215
|
+
'formatjs', '@lingui/core', 'i18ntk-runtime', 'i18ntk/runtime',
|
|
216
|
+
'angular-i18n', '@angular/localize', 'i18ntk'
|
|
213
217
|
];
|
|
214
218
|
|
|
215
219
|
const installedFrameworks = i18nFrameworks.filter(framework => dependencies[framework]);
|
|
@@ -292,7 +296,7 @@ class I18nManager {
|
|
|
292
296
|
break;
|
|
293
297
|
default:
|
|
294
298
|
// Handle language shorthand flags like --de, --fr
|
|
295
|
-
if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(sanitizedKey)) {
|
|
299
|
+
if (['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(sanitizedKey)) {
|
|
296
300
|
parsed.uiLanguage = sanitizedKey;
|
|
297
301
|
}
|
|
298
302
|
break;
|
|
@@ -690,15 +694,10 @@ class I18nManager {
|
|
|
690
694
|
detectedFramework = 'i18ntk-runtime';
|
|
691
695
|
}
|
|
692
696
|
|
|
693
|
-
//
|
|
697
|
+
// Use centralized framework detector
|
|
694
698
|
if (detectedFramework !== 'i18ntk-runtime') {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
else if (deps['@angular/core']) detectedFramework = 'angular';
|
|
698
|
-
else if (deps.next) detectedFramework = 'nextjs';
|
|
699
|
-
else if (deps.nuxt) detectedFramework = 'nuxt';
|
|
700
|
-
else if (deps.svelte) detectedFramework = 'svelte';
|
|
701
|
-
else detectedFramework = 'generic';
|
|
699
|
+
const centralDetected = detectProjectFramework(process.cwd());
|
|
700
|
+
detectedFramework = (centralDetected && centralDetected !== 'vanilla') ? centralDetected : 'generic';
|
|
702
701
|
}
|
|
703
702
|
} catch (error) {
|
|
704
703
|
detectedFramework = 'generic';
|
|
@@ -1008,40 +1007,46 @@ class I18nManager {
|
|
|
1008
1007
|
|
|
1009
1008
|
// ... existing code for showLanguageMenu, showDebugMenu, deleteReports, showSettingsMenu, etc. ...
|
|
1010
1009
|
|
|
1011
|
-
async showLanguageMenu() {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
const current = 'en' === 'en' ? ' ✓' : '';
|
|
1029
|
-
console.log(t('language.languageOption', { index: index + 1, displayName: lang.name, current }));
|
|
1030
|
-
});
|
|
1010
|
+
async showLanguageMenu() {
|
|
1011
|
+
const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
1012
|
+
const currentLanguage = settings.uiLanguage || settings.language || this.config.uiLanguage || this.config.language || 'en';
|
|
1013
|
+
const languages = configManager.getAvailableLanguages ? configManager.getAvailableLanguages() : [
|
|
1014
|
+
{ code: 'en', name: 'English' }
|
|
1015
|
+
];
|
|
1016
|
+
const currentLanguageName = languages.find(lang => lang.code === currentLanguage)?.name || currentLanguage;
|
|
1017
|
+
|
|
1018
|
+
console.log(`\n${t('language.title')}`);
|
|
1019
|
+
console.log(t('language.separator'));
|
|
1020
|
+
console.log(t('language.current', { language: currentLanguageName }));
|
|
1021
|
+
console.log('\n' + t('language.available'));
|
|
1022
|
+
|
|
1023
|
+
languages.forEach((lang, index) => {
|
|
1024
|
+
const current = lang.code === currentLanguage ? ' ✓' : '';
|
|
1025
|
+
console.log(t('language.languageOption', { index: index + 1, displayName: lang.name, current }));
|
|
1026
|
+
});
|
|
1031
1027
|
|
|
1032
1028
|
console.log(`0. ${t('language.backToMainMenu')}`);
|
|
1033
1029
|
|
|
1034
|
-
const
|
|
1030
|
+
const languagePrompt = formatLanguagePrompt(t('language.prompt'), languages.length);
|
|
1031
|
+
const choice = await this.prompt('\n' + languagePrompt);
|
|
1035
1032
|
const choiceNum = parseInt(choice);
|
|
1036
1033
|
|
|
1037
1034
|
if (choiceNum === 0) {
|
|
1038
1035
|
await this.showInteractiveMenu();
|
|
1039
1036
|
return;
|
|
1040
|
-
} else if (choiceNum >= 1 && choiceNum <= languages.length) {
|
|
1041
|
-
const selectedLang = languages[choiceNum - 1];
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1037
|
+
} else if (choiceNum >= 1 && choiceNum <= languages.length) {
|
|
1038
|
+
const selectedLang = languages[choiceNum - 1];
|
|
1039
|
+
settings.language = selectedLang.code;
|
|
1040
|
+
settings.uiLanguage = selectedLang.code;
|
|
1041
|
+
if (configManager.saveSettings) {
|
|
1042
|
+
await configManager.saveSettings(settings);
|
|
1043
|
+
} else if (configManager.saveConfig) {
|
|
1044
|
+
await configManager.saveConfig(settings);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
console.log(t('language.changed', { language: selectedLang.name }));
|
|
1048
|
+
|
|
1049
|
+
// Force reload translations for the entire system
|
|
1045
1050
|
loadTranslations(selectedLang.code);
|
|
1046
1051
|
|
|
1047
1052
|
// Return to main menu with new language
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const { t } = require('../../../utils/i18n-helper');
|
|
7
7
|
const { loadTranslations } = require('../../../utils/i18n-helper');
|
|
8
8
|
const SecurityUtils = require('../../../utils/security');
|
|
9
|
+
const { formatLanguagePrompt } = require('../../../utils/language-menu');
|
|
9
10
|
|
|
10
11
|
module.exports = class LanguageMenu {
|
|
11
12
|
constructor(manager) {
|
|
@@ -30,7 +31,8 @@ module.exports = class LanguageMenu {
|
|
|
30
31
|
|
|
31
32
|
console.log(`0. ${t('language.backToMainMenu')}`);
|
|
32
33
|
|
|
33
|
-
const
|
|
34
|
+
const languagePrompt = formatLanguagePrompt(t('language.prompt'), this.ui.availableLanguages.length);
|
|
35
|
+
const choice = await this.manager.prompt('\n' + languagePrompt);
|
|
34
36
|
const choiceNum = parseInt(choice);
|
|
35
37
|
|
|
36
38
|
if (choiceNum === 0) {
|
|
@@ -311,7 +311,7 @@ module.exports = class ConfigurationService {
|
|
|
311
311
|
break;
|
|
312
312
|
default:
|
|
313
313
|
// Handle language shorthand flags like --de, --fr
|
|
314
|
-
if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(sanitizedKey)) {
|
|
314
|
+
if (['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(sanitizedKey)) {
|
|
315
315
|
parsed.uiLanguage = sanitizedKey;
|
|
316
316
|
}
|
|
317
317
|
break;
|
|
@@ -330,7 +330,7 @@ module.exports = class FrameworkDetectionService {
|
|
|
330
330
|
const hasLanguageDirs = items.some(item => {
|
|
331
331
|
const itemPath = path.join(resolvedPath, item);
|
|
332
332
|
return fs.statSync(itemPath).isDirectory() &&
|
|
333
|
-
['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(item);
|
|
333
|
+
['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(item);
|
|
334
334
|
});
|
|
335
335
|
|
|
336
336
|
if (hasLanguageDirs) {
|
|
@@ -674,7 +674,7 @@ class UsageService {
|
|
|
674
674
|
});
|
|
675
675
|
|
|
676
676
|
for (const lang of allLanguageDirs) {
|
|
677
|
-
if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(lang)) {
|
|
677
|
+
if (['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(lang)) {
|
|
678
678
|
languages.add(lang);
|
|
679
679
|
}
|
|
680
680
|
}
|
|
@@ -683,7 +683,7 @@ class UsageService {
|
|
|
683
683
|
const directFiles = fs.readdirSync(this.i18nDir)
|
|
684
684
|
.filter(file => file.endsWith('.json'))
|
|
685
685
|
.map(file => path.basename(file, '.json'))
|
|
686
|
-
.filter(lang => ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(lang));
|
|
686
|
+
.filter(lang => ['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'].includes(lang));
|
|
687
687
|
|
|
688
688
|
directFiles.forEach(lang => languages.add(lang));
|
|
689
689
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18ntk",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.2",
|
|
4
4
|
"description": "i18n Tool Kit - Zero-dependency internationalization toolkit for setup, scanning, analysis, validation, auto translation, fixing, reporting, and runtime translation loading.",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"keywords": [
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
},
|
|
180
180
|
"preferGlobal": true,
|
|
181
181
|
"versionInfo": {
|
|
182
|
-
"version": "4.7.
|
|
182
|
+
"version": "4.7.2",
|
|
183
183
|
"releaseDate": "07/07/2026",
|
|
184
184
|
"lastUpdated": "07/07/2026",
|
|
185
185
|
"maintainer": "Vlad Noskov",
|
|
@@ -197,10 +197,14 @@
|
|
|
197
197
|
"ICU/FLUENT PLACEHOLDER SUPPORT: Fluent $variable and ICU MessageFormat patterns added to placeholder detection and comparison.",
|
|
198
198
|
"JSX COMPONENT DETECTION: <Trans>, <FormattedMessage>, <Translate> JSX components detected in both VS Code extensions.",
|
|
199
199
|
"COMPREHENSIVE TESTING: All 384+ tests pass across CLI, Workbench, and Lens packages.",
|
|
200
|
-
"FRAMEWORK DETECTION v2: Added 13 additional FRAMEWORK_PATTERNS (i18ntk-runtime, nuxt, formatjs, lingui, ngx-translate, next-intl, svelte-i18n, solid-i18n, fastapi, ruby-on-rails, react-native-localize, ionic). Expanded detectFramework() to check Python/Rust/Go/Ruby project files. Added 20+ WRAPPER_SKIP_PATTERNS. Added 8 missing FRAMEWORK_COMPATIBILITY versions. Now supports 30+ frameworks across 15+ languages."
|
|
200
|
+
"FRAMEWORK DETECTION v2: Added 13 additional FRAMEWORK_PATTERNS (i18ntk-runtime, nuxt, formatjs, lingui, ngx-translate, next-intl, svelte-i18n, solid-i18n, fastapi, ruby-on-rails, react-native-localize, ionic). Expanded detectFramework() to check Python/Rust/Go/Ruby project files. Added 20+ WRAPPER_SKIP_PATTERNS. Added 8 missing FRAMEWORK_COMPATIBILITY versions. Now supports 30+ frameworks across 15+ languages.",
|
|
201
|
+
"UI LOCALE EXPANSION: Expanded from 7 to 23 languages (Italian, Portuguese, Dutch, Polish, Swedish, Ukrainian, Czech, Turkish, Korean, Arabic, Hindi, Thai, Vietnamese, Hebrew, Greek, Hungarian). All 2,211 keys auto-translated with placeholder preservation. Native language names in all locale files. getAvailableLanguages(), settings schema enums, and UI language picker expanded to 23. 95-98% translated per language, 0 missing keys.",
|
|
202
|
+
"FRAMEWORK DETECTION CLEANUP: manage/index.js now uses centralized detectProjectFramework() instead of 6-framework inline check. Removed hardcoded framework.supported from config templates — only detected frameworks appear. checkI18nDependencies() unified across 4 modules (8→29 entries). 12 production files updated — hardcoded 7-language arrays expanded to 23.",
|
|
203
|
+
"PATCH: CLI language selector now derives display names and options from SettingsManager.getAvailableLanguages(), including the fallback manage/index.js entrypoint.",
|
|
204
|
+
"PATCH: Language selection prompts now render their numeric range dynamically from the installed UI locale count, preventing stale bounds during future locale expansion."
|
|
201
205
|
],
|
|
202
206
|
"breakingChanges": [],
|
|
203
|
-
"nextVersion": "4.7.
|
|
207
|
+
"nextVersion": "4.7.3",
|
|
204
208
|
"supportedNodeVersions": ">=16.0.0",
|
|
205
209
|
"supportedFrameworks": {
|
|
206
210
|
"react-i18next": ">=11.0.0",
|
|
@@ -229,18 +233,18 @@
|
|
|
229
233
|
"fluent-rs": ">=0.16.0",
|
|
230
234
|
"gettext-rs": ">=0.7.0"
|
|
231
235
|
},
|
|
232
|
-
"supportPolicy": "Versions earlier than 4.7.0 may be unstable or insecure in CI automation. Upgrade to 4.7.
|
|
236
|
+
"supportPolicy": "Versions earlier than 4.7.0 may be unstable or insecure in CI automation. Upgrade to 4.7.2 or newer.",
|
|
233
237
|
"deprecations": [
|
|
234
238
|
"4.3.0",
|
|
235
239
|
"4.3.1",
|
|
236
240
|
"4.3.2",
|
|
237
241
|
"4.3.3"
|
|
238
242
|
],
|
|
239
|
-
"deprecationMessage": "i18ntk 4.3.x and earlier have known security vulnerabilities (path traversal, JSON DoS). Upgrade to i18ntk@4.7.
|
|
243
|
+
"deprecationMessage": "i18ntk 4.3.x and earlier have known security vulnerabilities (path traversal, JSON DoS). Upgrade to i18ntk@4.7.2 or newer: npm install -g i18ntk@latest",
|
|
240
244
|
"securityAdvisories": [
|
|
241
245
|
"GHSA-i18ntk-4.3.x-path-traversal: Backup command accepted arbitrary paths without validation (fixed in 4.4.1)",
|
|
242
246
|
"GHSA-i18ntk-4.3.x-json-dos: Deeply nested JSON files could cause denial of service (fixed in 4.4.1)"
|
|
243
247
|
]
|
|
244
248
|
},
|
|
245
|
-
"readme": "# i18ntk v4.7.0\n\nA zero-dependency internationalization toolkit for setup, scanning, analysis, validation, usage tracking, translation completion, automatic JSON locale translation, reporting, and runtime translation loading.\n\n\n\n[](https://www.npmjs.com/package/i18ntk)\n[](https://www.npmjs.com/package/i18ntk)\n[](https://nodejs.org)\n[](https://www.npmjs.com/package/i18ntk)\n[](LICENSE)\n[](https://socket.dev/npm/package/i18ntk/overview/4.7.0)\n\n[](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-workbench)\n[](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-lens)\n\n## Ecosystem\n\n- **i18ntk** — CLI toolkit and runtime (this package)\n- **i18ntk Workbench** — VS Code dashboard, reports, and key management\n- **i18ntk Lens** — inline hovers, CodeLens, and diagnostics\n\n## Install\n\n```bash\nnpm install -g i18ntk\nnpx i18ntk --help\n```\n\n## What's New in 4.7.0\n\n- **30+ framework detection patterns** — 13 new FRAMEWORK_PATTERNS: `i18ntk-runtime`, `nuxt`, `lingui`, `formatjs`, `ngx-translate`, `next-intl`, `svelte-i18n`, `solid-i18n`, `fastapi`, `ruby-on-rails`, `react-native-localize`, `ionic`. Each with framework-specific scan regexes for translation calls, JSX components, template directives, and pipes.\n- **Non-Node project detection** — Python (`requirements.txt`, `pyproject.toml`, `setup.py`), Rust (`Cargo.toml`), Go (`go.mod`), Ruby (`Gemfile`) now detected when no `package.json` exists. Detects Django, Flask, FastAPI, Rails, and generic i18n.\n- **20+ new WRAPPER_SKIP_PATTERNS** — Covers I18n.t(), useTranslate(), translateService.instant(), formatMessage(), bundle.get_message(), fluent!, ts! and more.\n- **Framework-aware report generation** — `report-model.js` accepts optional framework parameter and uses framework-specific patterns for key extraction.\n- **Expanded namespace helpers** — `useTranslate` (Qwik), `useSpeak` (Qwik), `withTranslation` (react-i18next) added.\n- **Attribute key detection** — `i18nKey=`, `t-key=`, `data-i18n=` attributes detected in source scanning.\n- **All frame works now have FRAMEWORK_COMPATIBILITY entries and FRAMEWORK_SUGGESTIONS** for consistent tooling.\n\n[Full changelog →](./CHANGELOG.md)\n\n## Quick Start\n\n```bash\ni18ntk # interactive menu\ni18ntk --command=analyze # coverage report\ni18ntk --command=validate # quality checks\ni18ntk --command=usage # key usage tracking\ni18ntk report --json --out ./reports # full report\ni18ntk --command=complete # fill missing keys\ni18ntk --command=translate # auto-translate\ni18ntk --command=summary # status overview\n```\n\nSee [docs/getting-started.md](./docs/getting-started.md) for the full onboarding guide.\n\n## Command Reference\n\n| Command | Purpose | Output |\n| ----------- | ------------------------------------------ | ----------------------------- |\n| `i18ntk` | Interactive management menu | — |\n| `init` | Setup locale folders and target files | Locale JSON, `.i18ntk-config` |\n| `analyze` | Translation coverage comparison | Reports |\n| `validate` | Structure, quality, and risk validation | Summary report |\n| `usage` | Map keys to source, find dead/missing keys | Usage report |\n| `report` | Stable schema report (JSON/MD/HTML) | stdout or file output |\n| `scanner` | Detect hardcoded text in source files | Scanner report |\n| `complete` | Fill missing keys in target files | Target locale JSON |\n| `translate` | Auto-translate via provider AI | Target locale JSON |\n| `sizing` | Expansion risk and layout analysis | Sizing report |\n| `summary` | Project translation status overview | Console output |\n| `fixer` | Fix placeholders and markers | Locale JSON |\n| `backup` | Create/verify/restore locale backups | Backup archives |\n\nEach is available as `i18ntk --command=<name>` or standalone `i18ntk-<name>`.\n\n## Common Options\n\n```\n--code-dir <path> Source code directory\n--locales-dir <path> Locale files directory\n--output-dir <path> Report output directory\n--source-locale <code> Source language code (e.g. en)\n--framework <name> Override framework detection\n--no-prompt Skip interactive prompts\n--help Show help\n```\n\n## Auto Translate\n\n```bash\ni18ntk-translate locales/en/common.json de\ni18ntk-translate locales/en/common.json fr --dry-run --preserve-placeholders\n```\n\n**Providers:** Google (default), DeepL, LibreTranslate\n\n```bash\nexport DEEPL_API_KEY=\"your-key\"\ni18ntk-translate locales/en/common.json de --provider deepl --no-confirm\n```\n\n**Placeholder-aware translation** detects `{name}`, `{{count}}`, `%s`, `:id`, `${value}`, `$t(key)`, and ICU pattern syntax. The default mode is `--only-missing` — existing translations are preserved.\n\nProtected terms and keys via `i18ntk-auto-translate.json`:\n\n```json\n{\n \"version\": 1,\n \"terms\": [\"BrandName\", \"PRODUCT_CODE\"],\n \"keys\": [\"app.brandName\", \"product.*.symbol\"],\n \"values\": [\"BrandName Ltd\"],\n \"patterns\": [\"[A-Z]{2,}-\\\\d+\"]\n}\n```\n\n[Auto Translate guide →](./docs/auto-translate.md)\n\n## Configuration\n\nExample `.i18ntk-config`:\n\n```json\n{\n \"version\": \"4.6.1\",\n \"sourceDir\": \"./locales\",\n \"i18nDir\": \"./locales\",\n \"sourceLanguage\": \"en\",\n \"defaultLanguages\": [\"en\", \"de\", \"es\", \"fr\", \"ru\"],\n \"keyStyle\": \"dot.notation\",\n \"englishContentThresholdPercent\": 10,\n \"allowedEnglishTerms\": [\"BrandName\"],\n \"autoTranslate\": {\n \"placeholderMode\": \"preserve\",\n \"concurrency\": 12,\n \"onlyMissingOrEnglish\": true\n },\n \"extensions\": {\n \"workbench\": { \"localeDirectory\": \"./locales\", \"sourceLocale\": \"en\" },\n \"lens\": { \"localeDirectory\": \"./locales\", \"sourceLocale\": \"en\", \"keyFormats\": [\"dot\", \"snake\"] }\n }\n}\n```\n\n[Configuration reference →](./docs/api/CONFIGURATION.md)\n\n## Scanner\n\nDetects hardcoded text in 12+ languages with language-specific character ranges and stopword filtering. Framework-specific patterns for React, Vue, Angular, Svelte, Astro, Django, Flask, Python, Rust, Go, and more.\n\n```bash\ni18ntk-scanner --code-dir ./src --source-locale de\ni18ntk-scanner --code-dir ./src --source-locale ja --output-report\n```\n\n## Usage Analysis\n\nTracks key references, detects dead keys with confidence scores, resolves dynamic patterns (templates, arrays, object maps), and recommends namespace alignment.\n\n```bash\ni18ntk-usage --code-dir ./src --locales-dir ./locales --cleanup --dry-run-delete\n```\n\n## Runtime\n\n```js\nconst runtime = require('i18ntk/runtime');\nconst i18n = runtime.initRuntime({\n baseDir: './locales',\n language: 'en',\n fallbackLanguage: 'en',\n});\n\nconsole.log(i18n.t('common.hello'));\ni18n.setLanguage('fr');\nconsole.log(i18n.getAvailableLanguages());\n```\n\n**Lazy loading** reduces memory on large locale folders:\n\n```js\nconst i18n = runtime.initRuntime({ baseDir: './locales', language: 'en', lazy: true });\n```\n\n**Per-call language overrides:**\n\n```js\ni18n.t('common.hello', {}, { language: 'de' });\n```\n\n**Batch translation:**\n\n```js\ni18n.translateBatch(['menu.home', 'menu.settings']);\n```\n\nProduction guidance:\n\n- Use the instance from `initRuntime()` — not module-level `runtime.t()` — in multi-tenant apps\n- Use `lazy: true` for large folders; `preload: true` for small sets\n- Call `refresh(language)` after deploying changed locale files\n- `i18ntk/runtime/enhanced` remains available for async/encryption compatibility\n\n[Runtime guide →](./docs/runtime.md)\n\n## Watch\n\n```js\nconst watchLocales = require('i18ntk/utils/watch-locales');\nconst watcher = watchLocales('./locales');\n\nwatcher.on('change', (filePath) => console.log('changed:', filePath));\nwatcher.on('add', (filePath) => console.log('added:', filePath));\nwatcher.stop();\n```\n\nFeatures: 300ms debounce, SHA-256 hash tracking, 50-directory cap. The callback form `watchLocales('./locales', onChange)` is still supported.\n\n## Documentation\n\n- [Getting Started](./docs/getting-started.md)\n- [Configuration](./docs/api/CONFIGURATION.md)\n- [API Reference](./docs/api/API_REFERENCE.md)\n- [Runtime API](./docs/runtime.md)\n- [Auto Translate](./docs/auto-translate.md)\n- [Scanner Guide](./docs/scanner-guide.md)\n- [Environment Variables](./docs/environment-variables.md)\n\n## Security\n\n- No API key required for default Auto Translate\n- Do not store secrets in locale files, `.i18ntk-config`, or protection files\n- Report issues via [SECURITY.md](./SECURITY.md)\n\n## Related\n\n| Tool | Purpose |\n| ---------------- | ------------------------------------------- |\n| i18ntk Workbench | VS Code localization health dashboard |\n| i18ntk Lens | Inline hovers, CodeLens, and diagnostics |\n| PublishGuard | Pre-publish safety scanner for npm packages |\n| ContextKit | AI coding context manager |\n\n## License\n\nSee [LICENSE](./LICENSE).\n"
|
|
249
|
+
"readme": "# i18ntk v4.7.2\n\nA zero-dependency internationalization toolkit for setup, scanning, analysis, validation, usage tracking, translation completion, automatic JSON locale translation, reporting, and runtime translation loading.\n\n\n\n[](https://www.npmjs.com/package/i18ntk)\n[](https://www.npmjs.com/package/i18ntk)\n[](https://nodejs.org)\n[](https://www.npmjs.com/package/i18ntk)\n[](LICENSE)\n[](https://socket.dev/npm/package/i18ntk/overview/4.7.2)\n\n[](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-workbench)\n[](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-lens)\n\n## Ecosystem\n\n- **i18ntk** — CLI toolkit and runtime (this package)\n- **i18ntk Workbench** — VS Code dashboard, reports, and key management\n- **i18ntk Lens** — inline hovers, CodeLens, and diagnostics\n\n## Install\n\n```bash\nnpm install -g i18ntk\nnpx i18ntk --help\n```\n\n## What's New in 4.7.2\n\n- **Dynamic Language Selector** — The interactive \"Change UI Language\" menu now derives its options and display names from the package language registry, including the fallback `manage/index.js` entrypoint.\n- **Future-Proof Prompt Range** — The language selection prompt now renders `0-N` from the installed UI locale count instead of using a stale translated `0-8` range, so future locale expansion updates automatically.\n\n## What's New in 4.7.1\n\n- **23 UI Languages** — Expanded from 7 to 23: Italian, Portuguese, Dutch, Polish, Swedish, Ukrainian, Czech, Turkish, Korean, Arabic, Hindi, Thai, Vietnamese, Hebrew, Greek, Hungarian. All 2,211 keys auto-translated and verified.\n- **Framework Detection Cleanup** — Removed hardcoded `framework.supported` lists from config templates. `manage/index.js` now uses centralized `detectProjectFramework()` covering all 30+ frameworks. Only detected frameworks appear in setup — no more static catalog.\n- **Language Selector** — Settings UI, `getAvailableLanguages()`, and schema enums all expanded from 7 to 23 languages with native names.\n- **12 Production Files Updated** — Hardcoded 7-language arrays expanded to 23: validators, locale optimizers, env manager, usage tracking, UI, and config helpers.\n\n## What's New in 4.7.0\n\n- **30+ framework detection patterns** — 13 new FRAMEWORK_PATTERNS: `i18ntk-runtime`, `nuxt`, `lingui`, `formatjs`, `ngx-translate`, `next-intl`, `svelte-i18n`, `solid-i18n`, `fastapi`, `ruby-on-rails`, `react-native-localize`, `ionic`. Each with framework-specific scan regexes for translation calls, JSX components, template directives, and pipes.\n- **Non-Node project detection** — Python (`requirements.txt`, `pyproject.toml`, `setup.py`), Rust (`Cargo.toml`), Go (`go.mod`), Ruby (`Gemfile`) now detected when no `package.json` exists. Detects Django, Flask, FastAPI, Rails, and generic i18n.\n- **20+ new WRAPPER_SKIP_PATTERNS** — Covers I18n.t(), useTranslate(), translateService.instant(), formatMessage(), bundle.get_message(), fluent!, ts! and more.\n- **Framework-aware report generation** — `report-model.js` accepts optional framework parameter and uses framework-specific patterns for key extraction.\n- **Expanded namespace helpers** — `useTranslate` (Qwik), `useSpeak` (Qwik), `withTranslation` (react-i18next) added.\n- **Attribute key detection** — `i18nKey=`, `t-key=`, `data-i18n=` attributes detected in source scanning.\n- **All frame works now have FRAMEWORK_COMPATIBILITY entries and FRAMEWORK_SUGGESTIONS** for consistent tooling.\n [Full changelog →](./CHANGELOG.md)\n\n## Quick Start\n\n```bash\ni18ntk # interactive menu\ni18ntk --command=analyze # coverage report\ni18ntk --command=validate # quality checks\ni18ntk --command=usage # key usage tracking\ni18ntk report --json --out ./reports # full report\ni18ntk --command=complete # fill missing keys\ni18ntk --command=translate # auto-translate\ni18ntk --command=summary # status overview\n```\n\nSee [docs/getting-started.md](./docs/getting-started.md) for the full onboarding guide.\n\n## Command Reference\n\n| Command | Purpose | Output |\n| ----------- | ------------------------------------------ | ----------------------------- |\n| `i18ntk` | Interactive management menu | — |\n| `init` | Setup locale folders and target files | Locale JSON, `.i18ntk-config` |\n| `analyze` | Translation coverage comparison | Reports |\n| `validate` | Structure, quality, and risk validation | Summary report |\n| `usage` | Map keys to source, find dead/missing keys | Usage report |\n| `report` | Stable schema report (JSON/MD/HTML) | stdout or file output |\n| `scanner` | Detect hardcoded text in source files | Scanner report |\n| `complete` | Fill missing keys in target files | Target locale JSON |\n| `translate` | Auto-translate via provider AI | Target locale JSON |\n| `sizing` | Expansion risk and layout analysis | Sizing report |\n| `summary` | Project translation status overview | Console output |\n| `fixer` | Fix placeholders and markers | Locale JSON |\n| `backup` | Create/verify/restore locale backups | Backup archives |\n\nEach is available as `i18ntk --command=<name>` or standalone `i18ntk-<name>`.\n\n## Common Options\n\n```\n--code-dir <path> Source code directory\n--locales-dir <path> Locale files directory\n--output-dir <path> Report output directory\n--source-locale <code> Source language code (e.g. en)\n--framework <name> Override framework detection\n--no-prompt Skip interactive prompts\n--help Show help\n```\n\n## Auto Translate\n\n```bash\ni18ntk-translate locales/en/common.json de\ni18ntk-translate locales/en/common.json fr --dry-run --preserve-placeholders\n```\n\n**Providers:** Google (default), DeepL, LibreTranslate\n\n```bash\nexport DEEPL_API_KEY=\"your-key\"\ni18ntk-translate locales/en/common.json de --provider deepl --no-confirm\n```\n\n**Placeholder-aware translation** detects `{name}`, `{{count}}`, `%s`, `:id`, `${value}`, `$t(key)`, and ICU pattern syntax. The default mode is `--only-missing` — existing translations are preserved.\n\nProtected terms and keys via `i18ntk-auto-translate.json`:\n\n```json\n{\n \"version\": 1,\n \"terms\": [\"BrandName\", \"PRODUCT_CODE\"],\n \"keys\": [\"app.brandName\", \"product.*.symbol\"],\n \"values\": [\"BrandName Ltd\"],\n \"patterns\": [\"[A-Z]{2,}-\\\\d+\"]\n}\n```\n\n[Auto Translate guide →](./docs/auto-translate.md)\n\n## Configuration\n\nExample `.i18ntk-config`:\n\n```json\n{\n \"version\": \"4.6.1\",\n \"sourceDir\": \"./locales\",\n \"i18nDir\": \"./locales\",\n \"sourceLanguage\": \"en\",\n \"defaultLanguages\": [\"en\", \"de\", \"es\", \"fr\", \"ru\"],\n \"keyStyle\": \"dot.notation\",\n \"englishContentThresholdPercent\": 10,\n \"allowedEnglishTerms\": [\"BrandName\"],\n \"autoTranslate\": {\n \"placeholderMode\": \"preserve\",\n \"concurrency\": 12,\n \"onlyMissingOrEnglish\": true\n },\n \"extensions\": {\n \"workbench\": { \"localeDirectory\": \"./locales\", \"sourceLocale\": \"en\" },\n \"lens\": { \"localeDirectory\": \"./locales\", \"sourceLocale\": \"en\", \"keyFormats\": [\"dot\", \"snake\"] }\n }\n}\n```\n\n[Configuration reference →](./docs/api/CONFIGURATION.md)\n\n## Scanner\n\nDetects hardcoded text in 12+ languages with language-specific character ranges and stopword filtering. Framework-specific patterns for React, Vue, Angular, Svelte, Astro, Django, Flask, Python, Rust, Go, and more.\n\n```bash\ni18ntk-scanner --code-dir ./src --source-locale de\ni18ntk-scanner --code-dir ./src --source-locale ja --output-report\n```\n\n## Usage Analysis\n\nTracks key references, detects dead keys with confidence scores, resolves dynamic patterns (templates, arrays, object maps), and recommends namespace alignment.\n\n```bash\ni18ntk-usage --code-dir ./src --locales-dir ./locales --cleanup --dry-run-delete\n```\n\n## Runtime\n\n```js\nconst runtime = require('i18ntk/runtime');\nconst i18n = runtime.initRuntime({\n baseDir: './locales',\n language: 'en',\n fallbackLanguage: 'en',\n});\n\nconsole.log(i18n.t('common.hello'));\ni18n.setLanguage('fr');\nconsole.log(i18n.getAvailableLanguages());\n```\n\n**Lazy loading** reduces memory on large locale folders:\n\n```js\nconst i18n = runtime.initRuntime({ baseDir: './locales', language: 'en', lazy: true });\n```\n\n**Per-call language overrides:**\n\n```js\ni18n.t('common.hello', {}, { language: 'de' });\n```\n\n**Batch translation:**\n\n```js\ni18n.translateBatch(['menu.home', 'menu.settings']);\n```\n\nProduction guidance:\n\n- Use the instance from `initRuntime()` — not module-level `runtime.t()` — in multi-tenant apps\n- Use `lazy: true` for large folders; `preload: true` for small sets\n- Call `refresh(language)` after deploying changed locale files\n- `i18ntk/runtime/enhanced` remains available for async/encryption compatibility\n\n[Runtime guide →](./docs/runtime.md)\n\n## Watch\n\n```js\nconst watchLocales = require('i18ntk/utils/watch-locales');\nconst watcher = watchLocales('./locales');\n\nwatcher.on('change', (filePath) => console.log('changed:', filePath));\nwatcher.on('add', (filePath) => console.log('added:', filePath));\nwatcher.stop();\n```\n\nFeatures: 300ms debounce, SHA-256 hash tracking, 50-directory cap. The callback form `watchLocales('./locales', onChange)` is still supported.\n\n## Documentation\n\n- [Getting Started](./docs/getting-started.md)\n- [Configuration](./docs/api/CONFIGURATION.md)\n- [API Reference](./docs/api/API_REFERENCE.md)\n- [Runtime API](./docs/runtime.md)\n- [Auto Translate](./docs/auto-translate.md)\n- [Scanner Guide](./docs/scanner-guide.md)\n- [Environment Variables](./docs/environment-variables.md)\n\n## Security\n\n- No API key required for default Auto Translate\n- Do not store secrets in locale files, `.i18ntk-config`, or protection files\n- Report issues via [SECURITY.md](./SECURITY.md)\n\n## Related\n\n| Tool | Purpose |\n| ---------------- | ------------------------------------------- |\n| i18ntk Workbench | VS Code localization health dashboard |\n| i18ntk Lens | Inline hovers, CodeLens, and diagnostics |\n| PublishGuard | Pre-publish safety scanner for npm packages |\n| ContextKit | AI coding context manager |\n\n## License\n\nSee [LICENSE](./LICENSE).\n"
|
|
246
250
|
}
|
|
@@ -780,13 +780,13 @@ class SettingsManager {
|
|
|
780
780
|
language: {
|
|
781
781
|
type: 'string',
|
|
782
782
|
description: 'Default language for translations',
|
|
783
|
-
enum: ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'],
|
|
783
|
+
enum: ['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'],
|
|
784
784
|
default: 'en'
|
|
785
785
|
},
|
|
786
786
|
uiLanguage: {
|
|
787
787
|
type: 'string',
|
|
788
788
|
description: 'UI language for toolkit interface',
|
|
789
|
-
enum: ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'],
|
|
789
|
+
enum: ['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'],
|
|
790
790
|
default: 'en'
|
|
791
791
|
},
|
|
792
792
|
theme: {
|
|
@@ -1129,9 +1129,25 @@ class SettingsManager {
|
|
|
1129
1129
|
{ code: 'de', name: 'Deutsch' },
|
|
1130
1130
|
{ code: 'es', name: 'Español' },
|
|
1131
1131
|
{ code: 'fr', name: 'Français' },
|
|
1132
|
+
{ code: 'it', name: 'Italiano' },
|
|
1133
|
+
{ code: 'pt', name: 'Português' },
|
|
1134
|
+
{ code: 'nl', name: 'Nederlands' },
|
|
1135
|
+
{ code: 'pl', name: 'Polski' },
|
|
1136
|
+
{ code: 'sv', name: 'Svenska' },
|
|
1137
|
+
{ code: 'uk', name: 'Українська' },
|
|
1138
|
+
{ code: 'cs', name: 'Čeština' },
|
|
1139
|
+
{ code: 'tr', name: 'Türkçe' },
|
|
1132
1140
|
{ code: 'ru', name: 'Русский' },
|
|
1133
1141
|
{ code: 'ja', name: '日本語' },
|
|
1134
|
-
{ code: '
|
|
1142
|
+
{ code: 'ko', name: '한국어' },
|
|
1143
|
+
{ code: 'zh', name: '中文' },
|
|
1144
|
+
{ code: 'ar', name: 'العربية' },
|
|
1145
|
+
{ code: 'hi', name: 'हिन्दी' },
|
|
1146
|
+
{ code: 'th', name: 'ไทย' },
|
|
1147
|
+
{ code: 'vi', name: 'Tiếng Việt' },
|
|
1148
|
+
{ code: 'he', name: 'עברית' },
|
|
1149
|
+
{ code: 'el', name: 'Ελληνικά' },
|
|
1150
|
+
{ code: 'hu', name: 'Magyar' }
|
|
1135
1151
|
];
|
|
1136
1152
|
}
|
|
1137
1153
|
}
|