i18ntk 4.7.1 → 4.7.3

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 CHANGED
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
 
7
+ ## [4.7.3] - 2026-07-07
8
+
9
+ ### Fixed
10
+
11
+ - **PUBLISH INTEGRITY:** `utils/language-menu.js` and `utils/promptPin.js` were missing from the `files` array in `package.json`, causing `MODULE_NOT_FOUND` on install. Both added to `files` array in `package.json` and `package.public.json`.
12
+ - **4.7.2 deprecated** — published with the missing-module bug. All users should upgrade to 4.7.3.
13
+ - **Publish integrity test:** New `tests/publish-integrity.test.js` validates every production `require()` resolves to a file listed in the `files` array. Prevents future missing-module regressions.
14
+
15
+ ## [4.7.2] - 2026-07-07
16
+
17
+ ### FIXED
18
+
19
+ - **Dynamic CLI language selector** — Option 12 now derives available languages and native display names from `SettingsManager.getAvailableLanguages()` instead of stale hardcoded 7-language lists.
20
+ - **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.
21
+ - **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.
22
+
7
23
  ## [4.7.1] - 2026-07-07
8
24
 
9
25
  ### Added
@@ -58,7 +74,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
58
74
  - **supportedExtensions silently overridden:** `i18ntk-init.js` no longer unconditionally overrides `supportedExtensions` from config with the format adapter's single extension.
59
75
  - **allowedEnglishTerms in two places:** `validation-risk.js` now exports `resolveAllowedEnglishTerms()` which accepts both per-call options and project-level config terms as fallback sources.
60
76
 
61
- ## [4.6.0] - 2026-07-04
77
+ ## [4.6.0] - 2026-07-04
62
78
 
63
79
  ### Added
64
80
 
@@ -92,35 +108,35 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
92
108
  - **Hardcoded extension lists eliminated:** `SOURCE_EXTENSIONS` (report model), `SCANNER_EXTENSIONS` (scanner commands), `EXCLUDE_DIRS` (walk functions), and `SOURCE_DIRS` (usage resolver) are now defined once and imported everywhere.
93
109
  - **Framework-specific registration:** Adding a new framework now requires changes in only ONE file (`framework-detector.js`) instead of 6+ scattered locations.
94
110
 
95
- ## [4.5.4] - 2026-06-19
96
-
97
- ### Fixed
98
-
99
- - **Analyze:** Fixed `this.provideSetupGuidance is not a function` when no target locales are available. Analyze now prints setup guidance instead of crashing.
100
- - **Manager Route:** Manager-routed commands now propagate subcommand failures and no longer print `Operation completed successfully!` after a runtime failure.
101
- - **Complete:** Fixed `i18ntk-complete --help` by wiring the shared help renderer and keeping help output side-effect free.
102
- - **Validate:** Removed mixed failure/success output. Validation only prints successful completion when the validation result succeeds.
103
- - **Summary:** Guarded empty locale roots so `Average keys per language` prints `0` instead of `NaN`, and missing locale roots exit as invalid setup/argument failures.
104
- - **Analyze Reports:** Report write failures now fail analyze with a non-zero exit code instead of continuing with success wording.
105
-
106
- ### Changed
107
-
108
- - **CLI Flags:** Added canonical aliases: `--code-dir` / `--source-code-dir` for application source files, `--locales-dir` / `--i18n-dir` for locale files, and `--source-locale` for source language. Legacy `--source-dir`, `--i18n-dir`, and `--source-language` remain supported.
109
- - **Exit Codes:** Standardized automation behavior: `0` for success, `1` for validation/report/runtime failures, and `2` for invalid arguments or missing setup in non-interactive mode.
110
- - **CI Behavior:** Commands skip prompts when `--no-prompt` is passed, `CI=true`, stdin is not a TTY, or stdout is not a TTY.
111
- - **Complete Summary:** Completion output now distinguishes locales scanned, target locales changed, unique source keys added, total key insertions, files modified, files skipped, and dry-run status.
112
-
113
- ### Documentation
114
-
115
- - Updated README, API, configuration, scanner, and environment-variable docs with canonical CLI flags, legacy alias notes, and CI exit-code behavior.
116
-
117
- ### Tests
118
-
119
- - Added CLI reliability regression coverage for the analyze crash, manager failure propagation, complete help output, directory/source-locale aliases, summary `NaN`, non-interactive prompt suppression, validation wording, and completion summary labels.
120
-
121
- ## [4.5.3] - 2026-06-19
122
-
123
- ### Fixed
111
+ ## [4.5.4] - 2026-06-19
112
+
113
+ ### Fixed
114
+
115
+ - **Analyze:** Fixed `this.provideSetupGuidance is not a function` when no target locales are available. Analyze now prints setup guidance instead of crashing.
116
+ - **Manager Route:** Manager-routed commands now propagate subcommand failures and no longer print `Operation completed successfully!` after a runtime failure.
117
+ - **Complete:** Fixed `i18ntk-complete --help` by wiring the shared help renderer and keeping help output side-effect free.
118
+ - **Validate:** Removed mixed failure/success output. Validation only prints successful completion when the validation result succeeds.
119
+ - **Summary:** Guarded empty locale roots so `Average keys per language` prints `0` instead of `NaN`, and missing locale roots exit as invalid setup/argument failures.
120
+ - **Analyze Reports:** Report write failures now fail analyze with a non-zero exit code instead of continuing with success wording.
121
+
122
+ ### Changed
123
+
124
+ - **CLI Flags:** Added canonical aliases: `--code-dir` / `--source-code-dir` for application source files, `--locales-dir` / `--i18n-dir` for locale files, and `--source-locale` for source language. Legacy `--source-dir`, `--i18n-dir`, and `--source-language` remain supported.
125
+ - **Exit Codes:** Standardized automation behavior: `0` for success, `1` for validation/report/runtime failures, and `2` for invalid arguments or missing setup in non-interactive mode.
126
+ - **CI Behavior:** Commands skip prompts when `--no-prompt` is passed, `CI=true`, stdin is not a TTY, or stdout is not a TTY.
127
+ - **Complete Summary:** Completion output now distinguishes locales scanned, target locales changed, unique source keys added, total key insertions, files modified, files skipped, and dry-run status.
128
+
129
+ ### Documentation
130
+
131
+ - Updated README, API, configuration, scanner, and environment-variable docs with canonical CLI flags, legacy alias notes, and CI exit-code behavior.
132
+
133
+ ### Tests
134
+
135
+ - Added CLI reliability regression coverage for the analyze crash, manager failure propagation, complete help output, directory/source-locale aliases, summary `NaN`, non-interactive prompt suppression, validation wording, and completion summary labels.
136
+
137
+ ## [4.5.3] - 2026-06-19
138
+
139
+ ### Fixed
124
140
 
125
141
  - **Usage Scanner (Critical):** Fixed `supportedExtensions` default fallback in `config-helper.js` that excluded `.tsx` and `.jsx` files from source scanning. The default was `['.json', '.js', '.ts']` — missing `.jsx` and `.tsx`. In a Next.js project with 2704 keys across 1087 files, this caused the scanner to find only 57 keys (2.1%) instead of 2702 (99.9%) because all `.tsx` component files were silently ignored. The fix adds `.jsx` and `.tsx` to the default fallback: `['.json', '.js', '.jsx', '.ts', '.tsx']`.
126
142
  - **Usage Dead Code:** Cleaned up unreachable initializer in `i18ntk-usage.js` that was supposed to set default `includeExtensions` but never ran because `supportedExtensions` was always set by `config-helper.js`. Added `.vue` and `.svelte` to the fallback for completeness.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # i18ntk v4.7.1
1
+ # i18ntk v4.7.3
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
  [![node](https://img.shields.io/badge/node-%3E%3D16-339933)](https://nodejs.org)
10
10
  [![dependencies](https://img.shields.io/badge/dependencies-0-success)](https://www.npmjs.com/package/i18ntk)
11
11
  [![license](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
12
- [![socket](https://socket.dev/api/badge/npm/package/i18ntk/4.7.1)](https://socket.dev/npm/package/i18ntk/overview/4.7.1)
12
+ [![socket](https://socket.dev/api/badge/npm/package/i18ntk/4.7.3)](https://socket.dev/npm/package/i18ntk/overview/4.7.3)
13
13
 
14
14
  [![i18ntk Workbench](https://img.shields.io/badge/VS_Code-Workbench-007ACC?logo=visualstudiocode&logoColor=white)](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-workbench)
15
15
  [![i18ntk Lens](https://img.shields.io/badge/VS_Code-Lens-007ACC?logo=visualstudiocode&logoColor=white)](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-lens)
@@ -27,6 +27,10 @@ npm install -g i18ntk
27
27
  npx i18ntk --help
28
28
  ```
29
29
 
30
+ ## What's New in 4.7.3
31
+
32
+ - **Publish integrity fix** — `language-menu.js` and `promptPin.js` now included in npm package. Fixes `MODULE_NOT_FOUND` crash on install. **4.7.2 is deprecated.**
33
+
30
34
  ## What's New in 4.7.1
31
35
 
32
36
  - **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.
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 configManager = new SettingsManager();
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 = ['en', 'de', 'es', 'fr', 'it', 'pt', 'nl', 'pl', 'sv', 'uk', 'cs', 'tr', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'th', 'vi', 'he', 'el', 'hu'];
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
- const displayNames = {
486
- 'en': 'English',
487
- 'de': 'Deutsch (German)',
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 displayNames[langCode] || langCode;
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
- rl.question('\n' + this.t('language.prompt'), async (answer) => {
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) {
@@ -17,12 +17,13 @@ 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 configManager = require('../../settings/settings-manager');
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');
@@ -33,6 +34,8 @@ const pkg = require('../../package.json');
33
34
  const SetupEnforcer = require('../../utils/setup-enforcer');
34
35
  const CommandRouter = require('./commands/CommandRouter');
35
36
  const { detectProjectFramework } = require('../../utils/framework-detector');
37
+
38
+ const configManager = new SettingsManager();
36
39
 
37
40
  // Import services to replace circular dependencies
38
41
  const ConfigurationService = require('./services/ConfigurationService');
@@ -1004,40 +1007,46 @@ class I18nManager {
1004
1007
 
1005
1008
  // ... existing code for showLanguageMenu, showDebugMenu, deleteReports, showSettingsMenu, etc. ...
1006
1009
 
1007
- async showLanguageMenu() {
1008
- console.log(`\n${t('language.title')}`);
1009
- console.log(t('language.separator'));
1010
- console.log(t('language.current', { language: 'English' })); // Simplified since we don't have UIi18n
1011
- console.log('\n' + t('language.available'));
1012
-
1013
- const languages = [
1014
- { code: 'en', name: 'English' },
1015
- { code: 'de', name: 'Deutsch' },
1016
- { code: 'es', name: 'Español' },
1017
- { code: 'fr', name: 'Français' },
1018
- { code: 'ru', name: 'Русский' },
1019
- { code: 'ja', name: '日本語' },
1020
- { code: 'zh', name: '中文' }
1021
- ];
1022
-
1023
- languages.forEach((lang, index) => {
1024
- const current = 'en' === 'en' ? ' ✓' : '';
1025
- console.log(t('language.languageOption', { index: index + 1, displayName: lang.name, current }));
1026
- });
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
+ });
1027
1027
 
1028
1028
  console.log(`0. ${t('language.backToMainMenu')}`);
1029
1029
 
1030
- const choice = await this.prompt('\n' + t('language.prompt'));
1030
+ const languagePrompt = formatLanguagePrompt(t('language.prompt'), languages.length);
1031
+ const choice = await this.prompt('\n' + languagePrompt);
1031
1032
  const choiceNum = parseInt(choice);
1032
1033
 
1033
1034
  if (choiceNum === 0) {
1034
1035
  await this.showInteractiveMenu();
1035
1036
  return;
1036
- } else if (choiceNum >= 1 && choiceNum <= languages.length) {
1037
- const selectedLang = languages[choiceNum - 1];
1038
- console.log(t('language.changed', { language: selectedLang.name }));
1039
-
1040
- // Force reload translations for the entire system
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
1041
1050
  loadTranslations(selectedLang.code);
1042
1051
 
1043
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 choice = await this.manager.prompt('\n' + t('language.prompt'));
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "4.7.1",
3
+ "version": "4.7.3",
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": [
@@ -144,12 +144,14 @@
144
144
  "utils/localized-confirm.js",
145
145
  "utils/mini-commander.js",
146
146
  "utils/locale-optimizer.js",
147
+ "utils/language-menu.js",
147
148
  "utils/logger.js",
148
149
  "utils/menu-layout.js",
149
150
  "utils/npm-version-warning.js",
150
151
  "utils/plugin-loader.js",
151
152
  "utils/prompt-helper.js",
152
153
  "utils/prompt.js",
154
+ "utils/promptPin.js",
153
155
  "utils/report-writer.js",
154
156
  "utils/report-model.js",
155
157
  "utils/secure-errors.js",
@@ -179,7 +181,7 @@
179
181
  },
180
182
  "preferGlobal": true,
181
183
  "versionInfo": {
182
- "version": "4.7.1",
184
+ "version": "4.7.3",
183
185
  "releaseDate": "07/07/2026",
184
186
  "lastUpdated": "07/07/2026",
185
187
  "maintainer": "Vlad Noskov",
@@ -199,10 +201,12 @@
199
201
  "COMPREHENSIVE TESTING: All 384+ tests pass across CLI, Workbench, and Lens packages.",
200
202
  "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
203
  "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."
204
+ "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.",
205
+ "PATCH: CLI language selector now derives display names and options from SettingsManager.getAvailableLanguages(), including the fallback manage/index.js entrypoint.",
206
+ "PATCH: Language selection prompts now render their numeric range dynamically from the installed UI locale count, preventing stale bounds during future locale expansion."
203
207
  ],
204
208
  "breakingChanges": [],
205
- "nextVersion": "4.7.2",
209
+ "nextVersion": "4.7.4",
206
210
  "supportedNodeVersions": ">=16.0.0",
207
211
  "supportedFrameworks": {
208
212
  "react-i18next": ">=11.0.0",
@@ -231,18 +235,19 @@
231
235
  "fluent-rs": ">=0.16.0",
232
236
  "gettext-rs": ">=0.7.0"
233
237
  },
234
- "supportPolicy": "Versions earlier than 4.7.0 may be unstable or insecure in CI automation. Upgrade to 4.7.1 or newer.",
238
+ "supportPolicy": "Versions earlier than 4.7.3 may be unstable or insecure in CI automation. Upgrade to 4.7.3 or newer.",
235
239
  "deprecations": [
236
240
  "4.3.0",
237
241
  "4.3.1",
238
242
  "4.3.2",
239
- "4.3.3"
243
+ "4.3.3",
244
+ "4.7.2"
240
245
  ],
241
- "deprecationMessage": "i18ntk 4.3.x and earlier have known security vulnerabilities (path traversal, JSON DoS). Upgrade to i18ntk@4.7.1 or newer: npm install -g i18ntk@latest",
246
+ "deprecationMessage": "i18ntk 4.3.x and earlier have known security vulnerabilities (path traversal, JSON DoS). i18ntk 4.7.2 has a missing-module bug. Upgrade to i18ntk@4.7.3 or newer: npm install -g i18ntk@latest",
242
247
  "securityAdvisories": [
243
248
  "GHSA-i18ntk-4.3.x-path-traversal: Backup command accepted arbitrary paths without validation (fixed in 4.4.1)",
244
249
  "GHSA-i18ntk-4.3.x-json-dos: Deeply nested JSON files could cause denial of service (fixed in 4.4.1)"
245
250
  ]
246
251
  },
247
- "readme": "# i18ntk v4.7.1\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![i18ntk Logo](https://raw.githubusercontent.com/vladnoskv/i18ntk/main/docs/screenshots/i18ntk-logo-public.PNG)\n\n[![npm version](https://img.shields.io/npm/v/i18ntk.svg?color=brightgreen)](https://www.npmjs.com/package/i18ntk)\n[![npm downloads](https://img.shields.io/npm/dt/i18ntk.svg)](https://www.npmjs.com/package/i18ntk)\n[![node](https://img.shields.io/badge/node-%3E%3D16-339933)](https://nodejs.org)\n[![dependencies](https://img.shields.io/badge/dependencies-0-success)](https://www.npmjs.com/package/i18ntk)\n[![license](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)\n[![socket](https://socket.dev/api/badge/npm/package/i18ntk/4.7.1)](https://socket.dev/npm/package/i18ntk/overview/4.7.1)\n\n[![i18ntk Workbench](https://img.shields.io/badge/VS_Code-Workbench-007ACC?logo=visualstudiocode&logoColor=white)](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-workbench)\n[![i18ntk Lens](https://img.shields.io/badge/VS_Code-Lens-007ACC?logo=visualstudiocode&logoColor=white)](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.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"
252
+ "readme": "# i18ntk v4.7.3\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![i18ntk Logo](https://raw.githubusercontent.com/vladnoskv/i18ntk/main/docs/screenshots/i18ntk-logo-public.PNG)\n\n[![npm version](https://img.shields.io/npm/v/i18ntk.svg?color=brightgreen)](https://www.npmjs.com/package/i18ntk)\n[![npm downloads](https://img.shields.io/npm/dt/i18ntk.svg)](https://www.npmjs.com/package/i18ntk)\n[![node](https://img.shields.io/badge/node-%3E%3D16-339933)](https://nodejs.org)\n[![dependencies](https://img.shields.io/badge/dependencies-0-success)](https://www.npmjs.com/package/i18ntk)\n[![license](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)\n[![socket](https://socket.dev/api/badge/npm/package/i18ntk/4.7.3)](https://socket.dev/npm/package/i18ntk/overview/4.7.3)\n\n[![i18ntk Workbench](https://img.shields.io/badge/VS_Code-Workbench-007ACC?logo=visualstudiocode&logoColor=white)](https://marketplace.visualstudio.com/items?itemName=VladNoskov.i18ntk-workbench)\n[![i18ntk Lens](https://img.shields.io/badge/VS_Code-Lens-007ACC?logo=visualstudiocode&logoColor=white)](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.3\n\n- **Publish integrity fix** — `language-menu.js` and `promptPin.js` now included in npm package. Fixes `MODULE_NOT_FOUND` crash on install. **4.7.2 is deprecated.**\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"
248
253
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Helpers for language selection menus.
3
+ */
4
+
5
+ function formatLanguagePrompt(prompt, maxOption) {
6
+ const max = String(maxOption);
7
+ const fallback = `Select a language (0-${max}):`;
8
+ const text = typeof prompt === 'string' && prompt.trim() ? prompt : fallback;
9
+
10
+ if (text.includes('{max}')) {
11
+ return text.replace(/\{max\}/g, max);
12
+ }
13
+
14
+ const updated = text.replace(/\(0\s*[-–—~~]\s*\d+\)/u, `(0-${max})`);
15
+ return updated === text ? `${text.replace(/\s*$/, '')} (0-${max}):` : updated;
16
+ }
17
+
18
+ module.exports = {
19
+ formatLanguagePrompt
20
+ };
@@ -0,0 +1,76 @@
1
+ const readline = require('readline');
2
+
3
+ async function promptPin({ rl, label = 'Enter 4-digit Admin PIN: ', length = 4, digitsOnly = true } = {}) {
4
+ return rawMaskedPrompt(rl, label, { length, digitsOnly });
5
+ }
6
+
7
+ async function promptPinConfirm(rl, label1 = 'Enter new 4-digit Admin PIN: ', label2 = 'Confirm PIN: ') {
8
+ const pin1 = await promptPin({ rl, label: label1 });
9
+ const pin2 = await promptPin({ rl, label: label2 });
10
+ if (pin1 !== pin2) throw new Error('PINs do not match');
11
+ return pin1;
12
+ }
13
+
14
+ function rawMaskedPrompt(rl, promptText, { length = 4, digitsOnly = true } = {}) {
15
+ return new Promise((resolve) => {
16
+ const input = rl.input;
17
+ const output = rl.output;
18
+
19
+ const isRaw = input.isRaw;
20
+ if (!isRaw) input.setRawMode && input.setRawMode(true);
21
+
22
+ let buf = '';
23
+
24
+ const onData = (chunk) => {
25
+ const s = chunk.toString('utf8');
26
+
27
+ if (s === '\r' || s === '\n') {
28
+ if (buf.length === length) {
29
+ output.write('\n');
30
+ cleanup();
31
+ return resolve(buf);
32
+ }
33
+ return;
34
+ }
35
+
36
+ if (s === '\u0003') {
37
+ output.write('\n');
38
+ cleanup();
39
+ process.exit(130);
40
+ }
41
+
42
+ if (s === '\u0008' || s === '\u007f') {
43
+ if (buf.length > 0) buf = buf.slice(0, -1);
44
+ repaint();
45
+ return;
46
+ }
47
+
48
+ const ch = s;
49
+ if (digitsOnly) {
50
+ if (/^\d$/.test(ch) && buf.length < length) {
51
+ buf += ch;
52
+ repaint();
53
+ }
54
+ } else if (buf.length < length) {
55
+ buf += ch;
56
+ repaint();
57
+ }
58
+ };
59
+
60
+ const repaint = () => {
61
+ output.cursorTo && output.cursorTo(0);
62
+ output.clearLine && output.clearLine(1);
63
+ output.write(promptText + '*'.repeat(buf.length));
64
+ };
65
+
66
+ const cleanup = () => {
67
+ input.removeListener('data', onData);
68
+ if (!isRaw) input.setRawMode && input.setRawMode(false);
69
+ };
70
+
71
+ output.write(promptText);
72
+ input.on('data', onData);
73
+ });
74
+ }
75
+
76
+ module.exports = { promptPin, promptPinConfirm };