i18ntk 3.1.0 → 3.1.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 CHANGED
@@ -3,9 +3,34 @@
3
3
  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
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [3.1.0] - 2026-05-07
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [3.1.2] - 2026-05-07
9
+
10
+ ### Fixed
11
+ - Auto Translate now resolves locale roots such as `./locales` to the selected source-language folder such as `./locales/en` when JSON files are stored under language folders.
12
+ - Public package staging now verifies root `package.json` and `package.public.json` release metadata are synchronized before pack or publish.
13
+ - Added a safe `publish:public:dry-run` path for validating the exact staged npm publish flow.
14
+
15
+ ### Changed
16
+ - Updated release docs, npm README metadata, and package manifests for v3.1.2.
17
+ - Kept generated backups, temporary benchmark datasets, local setup state, and debug repair files out of future public repo commits through `.gitignore`.
18
+
19
+ ## [3.1.1] - 2026-05-07
20
+
21
+ ### Added
22
+ - **Auto Translate protection file workflow**: Added user-editable `i18ntk-auto-translate.json` support for protected terms, key paths, exact values, and regex patterns.
23
+ - **Public package README guard**: Public package staging now verifies `README.md` is included and non-empty before publish.
24
+
25
+ ### Changed
26
+ - Updated README and release documentation for the current Auto Translate protection workflow and public package contents.
27
+ - Removed project-specific hardcoded validation examples so users configure their own brand and domain terms.
28
+
29
+ ### Fixed
30
+ - Removed provider-shaped fake secret fixtures from tests to avoid GitHub push protection false positives.
31
+ - Ensured public package metadata includes `readmeFilename: "README.md"` so npm can render the package README.
32
+
33
+ ## [3.1.0] - 2026-05-07
9
34
 
10
35
  ### Added
11
36
  - **Placeholder-preserve translation mode**: Translates text segments around dynamic placeholders and reinserts the original tokens exactly.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # i18ntk v3.1.0
1
+ # i18ntk v3.1.2
2
2
 
3
- Zero-dependency internationalization toolkit for setup, scanning, analysis, validation, usage tracking, translation completion, automatic locale translation, and runtime translation loading.
3
+ Zero-dependency internationalization toolkit for setup, scanning, analysis, validation, usage tracking, translation completion, automatic JSON locale translation, reporting, and runtime translation loading.
4
4
 
5
5
  ![i18ntk Logo](https://raw.githubusercontent.com/vladnoskv/i18ntk/main/docs/screenshots/i18ntk-logo-public.PNG)
6
6
 
@@ -9,40 +9,7 @@ Zero-dependency internationalization toolkit for setup, scanning, analysis, vali
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/3.1.0)](https://socket.dev/npm/package/i18ntk/overview/3.1.0)
13
-
14
- ## Upgrade Notice
15
-
16
- Versions earlier than `3.1.0` may contain known stability and security issues.
17
- They are considered unsupported for production use. Upgrade to `3.1.0` or newer.
18
-
19
- ## v3.1.0 - Auto Translate Hardening and Validation Warning Tuning
20
-
21
- v3.1.0 improves automatic JSON locale translation through the management menu and the standalone `i18ntk-translate` command. It also reduces noisy validation warnings and added a dedicated settings module for the auto translator.
22
-
23
- For the full detailed changelog, see [CHANGELOG.md](./CHANGELOG.md). For migration notes, see [docs/migration-guide-v3.1.0.md](./docs/migration-guide-v3.1.0.md).
24
-
25
- ## What i18ntk Does
26
-
27
- - Zero runtime dependencies
28
- - Interactive and non-interactive project setup
29
- - Translation completeness analysis and usage tracking
30
- - Validation, sizing, and summary reporting
31
- - Missing-key completion and fixer workflows
32
- - Automatic translation of JSON locale files
33
- - Runtime translation helpers for application code
34
- - Support for JS/TS, React, Vue, Angular, and generic projects
35
-
36
- ## Getting Started
37
-
38
- 1. Install the package.
39
- 2. Run `i18ntk` or `i18ntk --command=init` to initialize the project.
40
- 3. Confirm the source language and locale directories.
41
- 4. Run `i18ntk --command=analyze` or `i18ntk --command=validate` to inspect translation coverage.
42
- 5. Use `i18ntk --command=complete` to fill missing keys when needed.
43
- 6. Use `i18ntk --command=translate` or menu option 14 to auto-translate source JSON files.
44
-
45
- The full onboarding flow is documented in [docs/getting-started.md](docs/getting-started.md).
12
+ [![socket](https://socket.dev/api/badge/npm/package/i18ntk/3.1.2)](https://socket.dev/npm/package/i18ntk/overview/3.1.2)
46
13
 
47
14
  ## Install
48
15
 
@@ -57,11 +24,31 @@ npm install --save-dev i18ntk
57
24
  npx i18ntk --help
58
25
  ```
59
26
 
60
- ## Setup
27
+ Requirements:
28
+
29
+ - Node.js `>=16.0.0`
30
+ - npm `>=8.0.0`
31
+ - No runtime dependencies
61
32
 
62
- The toolkit stores project configuration in `.i18ntk-config` at the project root.
33
+ ## What's New in 3.1.2
63
34
 
64
- Recommended setup flow:
35
+ - Auto Translate can translate strings that contain placeholders by translating text around the placeholders and reinserting the original tokens.
36
+ - Auto Translate supports user-editable protection rules in `i18ntk-auto-translate.json` for brand names, product terms, exact values, key paths, and regex patterns.
37
+ - The manager Auto Translate flow runs in-process, avoiding production `child_process` usage for that command.
38
+ - The target-language prompt supports `all` to translate into every configured target language while excluding the source language.
39
+ - Source-directory prompts are clearer and accept absolute paths or project-relative paths.
40
+ - Validation warnings now distinguish URLs, email addresses, secret-like values, and likely untranslated English content.
41
+ - Sizing reports now include per-language file counts, file-set mismatches, and per-file key/character statistics.
42
+ - Internal UI locale coverage is enforced against the English UI locale.
43
+ - Public package staging verifies `README.md` is present before publish.
44
+ - Auto Translate now resolves locale roots such as `./locales` to the selected source-language folder such as `./locales/en` when needed.
45
+ - Public package staging now fails when root `package.json` and `package.public.json` release metadata drift.
46
+
47
+ See [CHANGELOG.md](./CHANGELOG.md) and [docs/migration-guide-v3.1.2.md](./docs/migration-guide-v3.1.2.md) for release details.
48
+
49
+ ## Quick Start
50
+
51
+ Initialize a project:
65
52
 
66
53
  ```bash
67
54
  i18ntk
@@ -69,24 +56,41 @@ i18ntk
69
56
  i18ntk --command=init
70
57
  ```
71
58
 
72
- During setup, you can define:
59
+ Run common checks:
60
+
61
+ ```bash
62
+ i18ntk --command=analyze
63
+ i18ntk --command=validate
64
+ i18ntk --command=usage
65
+ i18ntk --command=sizing
66
+ i18ntk --command=summary
67
+ ```
68
+
69
+ Complete or fix translation files:
73
70
 
74
- - source directory
75
- - source language
76
- - UI language
77
- - framework preference
78
- - output directory
79
- - backup behavior
71
+ ```bash
72
+ i18ntk --command=complete
73
+ i18ntk-fixer --help
74
+ ```
80
75
 
81
- If you run in CI or a non-interactive shell, use:
76
+ Auto-translate locale JSON:
82
77
 
83
78
  ```bash
84
- i18ntk --command=init --no-prompt
79
+ i18ntk --command=translate
80
+ # or
81
+ i18ntk-translate locales/en/common.json de --report-stdout
85
82
  ```
86
83
 
87
- ## Daily Use
84
+ The full onboarding guide is in [docs/getting-started.md](./docs/getting-started.md).
85
+
86
+ ## Main Commands
87
+
88
+ Primary CLI:
88
89
 
89
90
  ```bash
91
+ i18ntk
92
+ i18ntk --help
93
+ i18ntk --command=init
90
94
  i18ntk --command=analyze
91
95
  i18ntk --command=validate
92
96
  i18ntk --command=usage
@@ -95,9 +99,10 @@ i18ntk --command=sizing
95
99
  i18ntk --command=complete
96
100
  i18ntk --command=translate
97
101
  i18ntk --command=summary
102
+ i18ntk --command=debug
98
103
  ```
99
104
 
100
- Standalone commands are also available:
105
+ Standalone executables:
101
106
 
102
107
  ```bash
103
108
  i18ntk-init
@@ -114,10 +119,11 @@ i18ntk-backup
114
119
  i18ntk-translate
115
120
  ```
116
121
 
117
- Note: `i18ntk --command=backup` in the manager flow is disabled in current builds.
118
- Use the standalone `i18ntk-backup` executable when backup operations are required.
122
+ Note: manager route `i18ntk --command=backup` is disabled in current builds. Use `i18ntk-backup` directly for backup operations.
123
+
124
+ ## Common Options
119
125
 
120
- ## Common Flags
126
+ Most commands support:
121
127
 
122
128
  - `--source-dir <path>`
123
129
  - `--i18n-dir <path>`
@@ -128,18 +134,6 @@ Use the standalone `i18ntk-backup` executable when backup operations are require
128
134
  - `--dry-run`
129
135
  - `--help`
130
136
 
131
- Auto Translate also supports:
132
-
133
- - `--source-lang <code>`
134
- - `--files <pattern>`
135
- - `--preserve-placeholders`
136
- - `--skip-placeholders`
137
- - `--send-placeholders`
138
- - `--batch-size <n>`
139
- - `--progress-interval <n>`
140
- - `--report-file <path>`
141
- - `--report-stdout`
142
-
143
137
  Example:
144
138
 
145
139
  ```bash
@@ -148,7 +142,7 @@ i18ntk --command=analyze --source-dir=./src --i18n-dir=./locales --output-dir=./
148
142
 
149
143
  ## Auto Translate
150
144
 
151
- Interactive menu flow:
145
+ Interactive manager flow:
152
146
 
153
147
  ```bash
154
148
  i18ntk
@@ -160,16 +154,119 @@ Direct CLI examples:
160
154
  ```bash
161
155
  i18ntk-translate locales/en/common.json de
162
156
  i18ntk-translate locales/en/common.json fr --dry-run --report-stdout
163
- i18ntk-translate locales/en es --files "*.json" --no-confirm --preserve-placeholders
157
+ i18ntk-translate locales/en es --source-dir locales/en --files "*.json" --no-confirm --preserve-placeholders
158
+ ```
159
+
160
+ The manager flow asks for:
161
+
162
+ - source locale directory, either the folder with JSON files or a locale root such as `./locales`
163
+ - source language code
164
+ - one or more target languages, or `all`
165
+ - one JSON file or all JSON files in the source directory
166
+
167
+ If you select a locale root such as `./locales` and choose source language `en`, the manager automatically uses `./locales/en` when that folder contains the source JSON files.
168
+
169
+ Before writing files, the manager can run a dry-run preview. After confirmation it writes translated files under sibling target-language folders, for example:
170
+
171
+ ```text
172
+ locales/en/common.json
173
+ locales/de/common.json
174
+ locales/fr/common.json
175
+ ```
176
+
177
+ ### Placeholder Handling
178
+
179
+ Auto Translate detects common placeholders such as:
180
+
181
+ - `{name}`
182
+ - `{{count}}`
183
+ - `%s`
184
+ - `%d`
185
+ - `:id`
186
+ - `%{name}`
187
+ - `${value}`
188
+
189
+ Useful flags:
190
+
191
+ - `--preserve-placeholders`: translate text around placeholders and reinsert original tokens
192
+ - `--skip-placeholders`: copy placeholder-bearing strings unchanged
193
+ - `--send-placeholders`: send placeholder-bearing strings through translation after masking
194
+ - `--custom-regex <regex>`: add project-specific placeholder detection
195
+
196
+ ### Protected Terms and Keys
197
+
198
+ Auto Translate can create and use a project-local protection file:
199
+
200
+ ```bash
201
+ i18ntk-translate locales/en/common.json de --create-protection-file --protection-file ./i18ntk-auto-translate.json
202
+ ```
203
+
204
+ Example `i18ntk-auto-translate.json`:
205
+
206
+ ```json
207
+ {
208
+ "version": 1,
209
+ "terms": ["BrandName", "PRODUCT_CODE", "API"],
210
+ "keys": ["app.brandName", "legal.companyName", "product.*.symbol"],
211
+ "values": ["BrandName Ltd", "support@example.com"],
212
+ "patterns": ["[A-Z]{2,}-\\d+"]
213
+ }
214
+ ```
215
+
216
+ - `terms` are masked before translation and restored exactly afterward.
217
+ - `keys` are exact key paths or `*` wildcard paths copied unchanged.
218
+ - `values` are exact source values copied unchanged.
219
+ - `patterns` are JavaScript regex strings for advanced protected substrings.
220
+
221
+ Useful flags:
222
+
223
+ - `--protection-file <path>`
224
+ - `--create-protection-file`
225
+ - `--no-protection`
226
+
227
+ Open Settings and choose `Auto Translate Beta` to edit defaults for placeholder mode, concurrency, batch size, retry settings, report output, BOM output, protection file path, first-run setup prompt, and update prompt.
228
+
229
+ See [docs/auto-translate.md](./docs/auto-translate.md) for the full Auto Translate guide.
230
+
231
+ ## Validation
232
+
233
+ Validation checks locale structure, completeness, placeholders, and content risks.
234
+
235
+ In 3.1.2, warning types are more specific:
236
+
237
+ - `Potential risky content`: URL, email address, or secret-like value
238
+ - `Possible untranslated English content`: target-language value appears to contain too much English
239
+
240
+ English-content warnings include:
241
+
242
+ - detected English percentage
243
+ - configured threshold
244
+ - matched word count
245
+ - sample matched words
246
+
247
+ Tune warnings in `.i18ntk-config`:
248
+
249
+ ```json
250
+ {
251
+ "englishContentThresholdPercent": 10,
252
+ "allowedEnglishTerms": ["BrandName", "PRODUCT_CODE"]
253
+ }
164
254
  ```
165
255
 
166
- The manager flow accepts comma- or space-separated target language codes, or `all` for every configured target language. It previews the first target language with a dry run when enabled, asks for confirmation, then writes translated files under matching target-language directories such as `locales/de/common.json`. By default it preserves placeholders while translating the surrounding text.
256
+ ## Sizing Analysis
257
+
258
+ `i18ntk-sizing` reports translation file sizes, key counts, average value length, and file-set mismatches across language folders.
259
+
260
+ ```bash
261
+ i18ntk-sizing --source-dir ./locales --format table
262
+ i18ntk-sizing --source-dir ./locales --detailed --output-dir ./i18ntk-reports
263
+ ```
167
264
 
168
- See [docs/auto-translate.md](docs/auto-translate.md) for full usage details.
265
+ Use `--detailed` to print per-file rows in the terminal.
169
266
 
170
267
  ## Runtime API
171
268
 
172
- Use `i18ntk/runtime` when your application needs to read locale JSON files at runtime.
269
+ Use `i18ntk/runtime` when an application needs to read locale JSON files at runtime.
173
270
 
174
271
  ```js
175
272
  const runtime = require('i18ntk/runtime');
@@ -189,15 +286,17 @@ console.log(runtime.getAvailableLanguages());
189
286
  runtime.refresh('fr');
190
287
  ```
191
288
 
192
- For a deeper walkthrough, see [docs/runtime.md](docs/runtime.md).
289
+ See [docs/runtime.md](./docs/runtime.md) for runtime details.
193
290
 
194
291
  ## Configuration
195
292
 
196
- Example `.i18ntk-config`:
293
+ i18ntk uses a project-local `.i18ntk-config` file.
294
+
295
+ Example:
197
296
 
198
297
  ```json
199
298
  {
200
- "version": "3.1.0",
299
+ "version": "3.1.2",
201
300
  "sourceDir": "./locales",
202
301
  "i18nDir": "./locales",
203
302
  "outputDir": "./i18ntk-reports",
@@ -206,8 +305,20 @@ Example `.i18ntk-config`:
206
305
  "englishContentThresholdPercent": 10,
207
306
  "allowedEnglishTerms": ["BrandName", "PRODUCT_CODE"],
208
307
  "autoTranslate": {
308
+ "placeholderMode": "preserve",
309
+ "concurrency": 6,
310
+ "batchSize": 100,
311
+ "progressInterval": 25,
312
+ "retryCount": 3,
313
+ "retryDelay": 1000,
314
+ "timeout": 15000,
315
+ "dryRunFirst": true,
316
+ "reportStdout": true,
317
+ "bom": false,
209
318
  "protectionEnabled": true,
210
- "protectionFile": "./i18ntk-auto-translate.json"
319
+ "protectionFile": "./i18ntk-auto-translate.json",
320
+ "promptProtectionSetup": true,
321
+ "promptProtectionUpdate": true
211
322
  },
212
323
  "setup": {
213
324
  "completed": true
@@ -215,34 +326,53 @@ Example `.i18ntk-config`:
215
326
  }
216
327
  ```
217
328
 
218
- See [docs/api/CONFIGURATION.md](docs/api/CONFIGURATION.md) for the full configuration model.
329
+ See [docs/api/CONFIGURATION.md](./docs/api/CONFIGURATION.md) for the full configuration model.
219
330
 
220
- ## Docs
331
+ ## Public Package Contents
221
332
 
222
- - [Documentation Index](https://github.com/vladnoskv/i18ntk/blob/main/docs/README.md)
223
- - [Getting Started](https://github.com/vladnoskv/i18ntk/blob/main/docs/getting-started.md)
224
- - [API Reference](https://github.com/vladnoskv/i18ntk/blob/main/docs/api/API_REFERENCE.md)
225
- - [Configuration Guide](https://github.com/vladnoskv/i18ntk/blob/main/docs/api/CONFIGURATION.md)
226
- - [Runtime API Guide](https://github.com/vladnoskv/i18ntk/blob/main/docs/runtime.md)
227
- - [Auto Translate Guide](https://github.com/vladnoskv/i18ntk/blob/main/docs/auto-translate.md)
228
- - [Scanner Guide](https://github.com/vladnoskv/i18ntk/blob/main/docs/scanner-guide.md)
229
- - [Environment Variables](https://github.com/vladnoskv/i18ntk/blob/main/docs/environment-variables.md)
230
- - [Migration Guide v3.1.0](https://github.com/vladnoskv/i18ntk/blob/main/docs/migration-guide-v3.1.0.md)
231
- - [Migration Guide v3.0.0](https://github.com/vladnoskv/i18ntk/blob/main/docs/migration-guide-v3.0.0.md)
232
- - [Migration Guide v2.6.0](https://github.com/vladnoskv/i18ntk/blob/main/docs/migration-guide-v2.6.0.md)
233
- - [Migration Guide v2.5.1](https://github.com/vladnoskv/i18ntk/blob/main/docs/migration-guide-v2.5.1.md)
333
+ The public package intentionally ships runtime and CLI files only. The publish staging script excludes development-only content such as tests, scripts, docs, release staging folders, local config files, and generated protection files.
234
334
 
235
- ## Community
335
+ The package includes:
336
+
337
+ - CLI entry points under `main/`
338
+ - manager commands and services
339
+ - runtime API files under `runtime/`
340
+ - settings UI files required at runtime
341
+ - bundled internal UI locales
342
+ - shared utilities required by the shipped commands
343
+ - `README.md`, `CHANGELOG.md`, `LICENSE`, and policy files
236
344
 
237
- - [Contributing](CONTRIBUTING.md)
238
- - [Code of Conduct](CODE_OF_CONDUCT.md)
239
- - [Security Policy](SECURITY.md)
240
- - [Funding](FUNDING.md)
345
+ The public package manifest includes `readmeFilename: "README.md"`, and the release staging script fails if `README.md` is missing or empty.
241
346
 
242
- ## Code of Conduct
347
+ ## Documentation
348
+
349
+ - [Documentation Index](./docs/README.md)
350
+ - [Getting Started](./docs/getting-started.md)
351
+ - [API Reference](./docs/api/API_REFERENCE.md)
352
+ - [Configuration Guide](./docs/api/CONFIGURATION.md)
353
+ - [Runtime API Guide](./docs/runtime.md)
354
+ - [Auto Translate Guide](./docs/auto-translate.md)
355
+ - [Scanner Guide](./docs/scanner-guide.md)
356
+ - [Environment Variables](./docs/environment-variables.md)
357
+ - [Migration Guide v3.1.2](./docs/migration-guide-v3.1.2.md)
358
+ - [Migration Guide v3.1.1](./docs/migration-guide-v3.1.1.md)
359
+ - [Migration Guide v3.0.0](./docs/migration-guide-v3.0.0.md)
360
+ - [Migration Guide v2.6.0](./docs/migration-guide-v2.6.0.md)
361
+ - [Migration Guide v2.5.1](./docs/migration-guide-v2.5.1.md)
362
+
363
+ ## Security
364
+
365
+ - No API key is required for the default Auto Translate flow.
366
+ - Do not store secrets in locale files, `.i18ntk-config`, or protection files.
367
+ - Project-specific brand/product terms should be configured by the user, not hardcoded into the package.
368
+ - Report security issues using [SECURITY.md](./SECURITY.md).
369
+
370
+ ## Community
243
371
 
244
- We are committed to providing a friendly, safe and welcoming environment for all. Please read and respect our [Code of Conduct](CODE_OF_CONDUCT.md).
372
+ - [Contributing](./CONTRIBUTING.md)
373
+ - [Code of Conduct](./CODE_OF_CONDUCT.md)
374
+ - [Funding](./FUNDING.md)
245
375
 
246
376
  ## License
247
377
 
248
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
378
+ MIT. See [LICENSE](./LICENSE).
@@ -71,7 +71,14 @@ class TranslateCommand {
71
71
  console.error(`Source locale directory not found: ${this.sourceDir}`);
72
72
  return { success: false, error: 'Source directory not found' };
73
73
  }
74
- const jsonFiles = SecurityUtils.safeReaddirSync(this.sourceDir, path.dirname(this.sourceDir)).filter(f => f.endsWith('.json')).sort();
74
+ const resolvedSource = this.resolveSourceDirectoryForLanguage(this.sourceDir, this.sourceLang);
75
+ if (!resolvedSource.ok) {
76
+ console.error(resolvedSource.message);
77
+ return { success: false, error: 'No source files found' };
78
+ }
79
+ this.sourceDir = resolvedSource.sourceDir;
80
+ this.configuredTargetLangs = this.getConfiguredTargetLanguages(unified, this.sourceDir);
81
+ const jsonFiles = resolvedSource.jsonFiles;
75
82
  return await this.nonInteractiveFlow(jsonFiles);
76
83
  }
77
84
 
@@ -84,18 +91,16 @@ class TranslateCommand {
84
91
  // Step 2: Choose source language
85
92
  this.sourceLang = await this.promptSourceLang(ask);
86
93
  if (!this.sourceLang) return { success: false, error: 'No source language selected' };
87
- this.configuredTargetLangs = this.getConfiguredTargetLanguages(unified, this.sourceDir);
88
-
89
- const jsonFiles = SecurityUtils.safeReaddirSync(this.sourceDir, path.dirname(this.sourceDir))
90
- .filter(f => f.endsWith('.json'))
91
- .sort();
92
94
 
93
- if (jsonFiles.length === 0) {
94
- console.error(`No JSON files found in: ${this.sourceDir}`);
95
+ const resolvedSource = this.resolveSourceDirectoryForLanguage(this.sourceDir, this.sourceLang);
96
+ if (!resolvedSource.ok) {
97
+ console.error(resolvedSource.message);
95
98
  return { success: false, error: 'No source files found' };
96
99
  }
100
+ this.sourceDir = resolvedSource.sourceDir;
101
+ this.configuredTargetLangs = this.getConfiguredTargetLanguages(unified, this.sourceDir);
97
102
 
98
- return await this.interactiveFlow(jsonFiles, ask);
103
+ return await this.interactiveFlow(resolvedSource.jsonFiles, ask);
99
104
  }
100
105
 
101
106
  async promptSourceDir(ask, defaultDir) {
@@ -106,8 +111,9 @@ class TranslateCommand {
106
111
  console.log(' Accepted: an absolute path, or a path relative to the current project.');
107
112
  console.log(' Examples:');
108
113
  console.log(' ./locales/en');
114
+ console.log(' ./locales (then choose source language: en)');
109
115
  console.log(` ${defaultDir}`);
110
- console.log(' The folder must contain the source JSON files to translate.');
116
+ console.log(' The folder can contain JSON files directly, or language folders such as ./locales/en.');
111
117
  console.log(' Press Enter to use the default.');
112
118
  const input = await ask(' > ');
113
119
 
@@ -251,6 +257,42 @@ class TranslateCommand {
251
257
  return { success: false, error: 'Non-interactive mode not supported from menu' };
252
258
  }
253
259
 
260
+ getJsonFiles(sourceDir) {
261
+ return SecurityUtils.safeReaddirSync(sourceDir, path.dirname(sourceDir))
262
+ .filter(f => f.endsWith('.json'))
263
+ .sort();
264
+ }
265
+
266
+ resolveSourceDirectoryForLanguage(selectedDir, sourceLang, options = {}) {
267
+ const shouldLog = options.log !== false;
268
+ const jsonFiles = this.getJsonFiles(selectedDir);
269
+ if (jsonFiles.length > 0) {
270
+ return { ok: true, sourceDir: selectedDir, jsonFiles };
271
+ }
272
+
273
+ const cleanLang = String(sourceLang || '').trim().toLowerCase();
274
+ if (cleanLang) {
275
+ const languageDir = path.join(selectedDir, cleanLang);
276
+ const languageStats = SecurityUtils.safeStatSync(languageDir, path.dirname(languageDir));
277
+ if (languageStats && languageStats.isDirectory()) {
278
+ const languageJsonFiles = this.getJsonFiles(languageDir);
279
+ if (languageJsonFiles.length > 0) {
280
+ if (shouldLog) {
281
+ console.log(` No JSON files found directly in: ${selectedDir}`);
282
+ console.log(` Using source language folder: ${languageDir}`);
283
+ }
284
+ return { ok: true, sourceDir: languageDir, jsonFiles: languageJsonFiles };
285
+ }
286
+ }
287
+ }
288
+
289
+ const checkedLanguageDir = cleanLang ? path.join(selectedDir, cleanLang) : null;
290
+ const message = checkedLanguageDir
291
+ ? `No JSON files found in: ${selectedDir}\nAlso checked source language folder: ${checkedLanguageDir}`
292
+ : `No JSON files found in: ${selectedDir}`;
293
+ return { ok: false, sourceDir: selectedDir, jsonFiles: [], message };
294
+ }
295
+
254
296
  getConfiguredTargetLanguages(config = {}, sourceDir = this.sourceDir) {
255
297
  const candidates = []
256
298
  .concat(config.defaultLanguages || [])
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Zero-dependency internationalization toolkit for setup, scanning, analysis, validation, auto translation, fixing, reporting, and runtime translation loading.",
5
+ "readmeFilename": "README.md",
5
6
  "keywords": [
6
7
  "i18n",
7
8
  "internationalization",
@@ -157,5 +158,6 @@
157
158
  "publishConfig": {
158
159
  "access": "public"
159
160
  },
160
- "preferGlobal": true
161
+ "preferGlobal": true,
162
+ "readme": "# i18ntk v3.1.2\n\nZero-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/3.1.2)](https://socket.dev/npm/package/i18ntk/overview/3.1.2)\n\n## Install\n\n```bash\n# global CLI use\nnpm install -g i18ntk\n\n# local project use\nnpm install --save-dev i18ntk\n\n# one-off execution\nnpx i18ntk --help\n```\n\nRequirements:\n\n- Node.js `>=16.0.0`\n- npm `>=8.0.0`\n- No runtime dependencies\n\n## What's New in 3.1.2\n\n- Auto Translate can translate strings that contain placeholders by translating text around the placeholders and reinserting the original tokens.\n- Auto Translate supports user-editable protection rules in `i18ntk-auto-translate.json` for brand names, product terms, exact values, key paths, and regex patterns.\n- The manager Auto Translate flow runs in-process, avoiding production `child_process` usage for that command.\n- The target-language prompt supports `all` to translate into every configured target language while excluding the source language.\n- Source-directory prompts are clearer and accept absolute paths or project-relative paths.\n- Validation warnings now distinguish URLs, email addresses, secret-like values, and likely untranslated English content.\n- Sizing reports now include per-language file counts, file-set mismatches, and per-file key/character statistics.\n- Internal UI locale coverage is enforced against the English UI locale.\n- Public package staging verifies `README.md` is present before publish.\n- Auto Translate now resolves locale roots such as `./locales` to the selected source-language folder such as `./locales/en` when needed.\n- Public package staging now fails when root `package.json` and `package.public.json` release metadata drift.\n\nSee [CHANGELOG.md](./CHANGELOG.md) and [docs/migration-guide-v3.1.2.md](./docs/migration-guide-v3.1.2.md) for release details.\n\n## Quick Start\n\nInitialize a project:\n\n```bash\ni18ntk\n# or\ni18ntk --command=init\n```\n\nRun common checks:\n\n```bash\ni18ntk --command=analyze\ni18ntk --command=validate\ni18ntk --command=usage\ni18ntk --command=sizing\ni18ntk --command=summary\n```\n\nComplete or fix translation files:\n\n```bash\ni18ntk --command=complete\ni18ntk-fixer --help\n```\n\nAuto-translate locale JSON:\n\n```bash\ni18ntk --command=translate\n# or\ni18ntk-translate locales/en/common.json de --report-stdout\n```\n\nThe full onboarding guide is in [docs/getting-started.md](./docs/getting-started.md).\n\n## Main Commands\n\nPrimary CLI:\n\n```bash\ni18ntk\ni18ntk --help\ni18ntk --command=init\ni18ntk --command=analyze\ni18ntk --command=validate\ni18ntk --command=usage\ni18ntk --command=scanner\ni18ntk --command=sizing\ni18ntk --command=complete\ni18ntk --command=translate\ni18ntk --command=summary\ni18ntk --command=debug\n```\n\nStandalone executables:\n\n```bash\ni18ntk-init\ni18ntk-analyze\ni18ntk-validate\ni18ntk-usage\ni18ntk-scanner\ni18ntk-sizing\ni18ntk-complete\ni18ntk-summary\ni18ntk-doctor\ni18ntk-fixer\ni18ntk-backup\ni18ntk-translate\n```\n\nNote: manager route `i18ntk --command=backup` is disabled in current builds. Use `i18ntk-backup` directly for backup operations.\n\n## Common Options\n\nMost commands support:\n\n- `--source-dir <path>`\n- `--i18n-dir <path>`\n- `--output-dir <path>`\n- `--source-language <code>`\n- `--ui-language <code>`\n- `--no-prompt`\n- `--dry-run`\n- `--help`\n\nExample:\n\n```bash\ni18ntk --command=analyze --source-dir=./src --i18n-dir=./locales --output-dir=./i18ntk-reports\n```\n\n## Auto Translate\n\nInteractive manager flow:\n\n```bash\ni18ntk\n# choose \"Auto Translate (Beta)\"\n```\n\nDirect CLI examples:\n\n```bash\ni18ntk-translate locales/en/common.json de\ni18ntk-translate locales/en/common.json fr --dry-run --report-stdout\ni18ntk-translate locales/en es --source-dir locales/en --files \"*.json\" --no-confirm --preserve-placeholders\n```\n\nThe manager flow asks for:\n\n- source locale directory, either the folder with JSON files or a locale root such as `./locales`\n- source language code\n- one or more target languages, or `all`\n- one JSON file or all JSON files in the source directory\n\nIf you select a locale root such as `./locales` and choose source language `en`, the manager automatically uses `./locales/en` when that folder contains the source JSON files.\n\nBefore writing files, the manager can run a dry-run preview. After confirmation it writes translated files under sibling target-language folders, for example:\n\n```text\nlocales/en/common.json\nlocales/de/common.json\nlocales/fr/common.json\n```\n\n### Placeholder Handling\n\nAuto Translate detects common placeholders such as:\n\n- `{name}`\n- `{{count}}`\n- `%s`\n- `%d`\n- `:id`\n- `%{name}`\n- `${value}`\n\nUseful flags:\n\n- `--preserve-placeholders`: translate text around placeholders and reinsert original tokens\n- `--skip-placeholders`: copy placeholder-bearing strings unchanged\n- `--send-placeholders`: send placeholder-bearing strings through translation after masking\n- `--custom-regex <regex>`: add project-specific placeholder detection\n\n### Protected Terms and Keys\n\nAuto Translate can create and use a project-local protection file:\n\n```bash\ni18ntk-translate locales/en/common.json de --create-protection-file --protection-file ./i18ntk-auto-translate.json\n```\n\nExample `i18ntk-auto-translate.json`:\n\n```json\n{\n \"version\": 1,\n \"terms\": [\"BrandName\", \"PRODUCT_CODE\", \"API\"],\n \"keys\": [\"app.brandName\", \"legal.companyName\", \"product.*.symbol\"],\n \"values\": [\"BrandName Ltd\", \"support@example.com\"],\n \"patterns\": [\"[A-Z]{2,}-\\\\d+\"]\n}\n```\n\n- `terms` are masked before translation and restored exactly afterward.\n- `keys` are exact key paths or `*` wildcard paths copied unchanged.\n- `values` are exact source values copied unchanged.\n- `patterns` are JavaScript regex strings for advanced protected substrings.\n\nUseful flags:\n\n- `--protection-file <path>`\n- `--create-protection-file`\n- `--no-protection`\n\nOpen Settings and choose `Auto Translate Beta` to edit defaults for placeholder mode, concurrency, batch size, retry settings, report output, BOM output, protection file path, first-run setup prompt, and update prompt.\n\nSee [docs/auto-translate.md](./docs/auto-translate.md) for the full Auto Translate guide.\n\n## Validation\n\nValidation checks locale structure, completeness, placeholders, and content risks.\n\nIn 3.1.2, warning types are more specific:\n\n- `Potential risky content`: URL, email address, or secret-like value\n- `Possible untranslated English content`: target-language value appears to contain too much English\n\nEnglish-content warnings include:\n\n- detected English percentage\n- configured threshold\n- matched word count\n- sample matched words\n\nTune warnings in `.i18ntk-config`:\n\n```json\n{\n \"englishContentThresholdPercent\": 10,\n \"allowedEnglishTerms\": [\"BrandName\", \"PRODUCT_CODE\"]\n}\n```\n\n## Sizing Analysis\n\n`i18ntk-sizing` reports translation file sizes, key counts, average value length, and file-set mismatches across language folders.\n\n```bash\ni18ntk-sizing --source-dir ./locales --format table\ni18ntk-sizing --source-dir ./locales --detailed --output-dir ./i18ntk-reports\n```\n\nUse `--detailed` to print per-file rows in the terminal.\n\n## Runtime API\n\nUse `i18ntk/runtime` when an application needs to read locale JSON files at runtime.\n\n```js\nconst runtime = require('i18ntk/runtime');\n\nruntime.initRuntime({\n baseDir: './locales',\n language: 'en',\n fallbackLanguage: 'en',\n keySeparator: '.',\n preload: true\n});\n\nconsole.log(runtime.t('common.hello'));\nruntime.setLanguage('fr');\nconsole.log(runtime.getLanguage());\nconsole.log(runtime.getAvailableLanguages());\nruntime.refresh('fr');\n```\n\nSee [docs/runtime.md](./docs/runtime.md) for runtime details.\n\n## Configuration\n\ni18ntk uses a project-local `.i18ntk-config` file.\n\nExample:\n\n```json\n{\n \"version\": \"3.1.2\",\n \"sourceDir\": \"./locales\",\n \"i18nDir\": \"./locales\",\n \"outputDir\": \"./i18ntk-reports\",\n \"sourceLanguage\": \"en\",\n \"defaultLanguages\": [\"de\", \"es\", \"fr\", \"ru\"],\n \"englishContentThresholdPercent\": 10,\n \"allowedEnglishTerms\": [\"BrandName\", \"PRODUCT_CODE\"],\n \"autoTranslate\": {\n \"placeholderMode\": \"preserve\",\n \"concurrency\": 6,\n \"batchSize\": 100,\n \"progressInterval\": 25,\n \"retryCount\": 3,\n \"retryDelay\": 1000,\n \"timeout\": 15000,\n \"dryRunFirst\": true,\n \"reportStdout\": true,\n \"bom\": false,\n \"protectionEnabled\": true,\n \"protectionFile\": \"./i18ntk-auto-translate.json\",\n \"promptProtectionSetup\": true,\n \"promptProtectionUpdate\": true\n },\n \"setup\": {\n \"completed\": true\n }\n}\n```\n\nSee [docs/api/CONFIGURATION.md](./docs/api/CONFIGURATION.md) for the full configuration model.\n\n## Public Package Contents\n\nThe public package intentionally ships runtime and CLI files only. The publish staging script excludes development-only content such as tests, scripts, docs, release staging folders, local config files, and generated protection files.\n\nThe package includes:\n\n- CLI entry points under `main/`\n- manager commands and services\n- runtime API files under `runtime/`\n- settings UI files required at runtime\n- bundled internal UI locales\n- shared utilities required by the shipped commands\n- `README.md`, `CHANGELOG.md`, `LICENSE`, and policy files\n\nThe public package manifest includes `readmeFilename: \"README.md\"`, and the release staging script fails if `README.md` is missing or empty.\n\n## Documentation\n\n- [Documentation Index](./docs/README.md)\n- [Getting Started](./docs/getting-started.md)\n- [API Reference](./docs/api/API_REFERENCE.md)\n- [Configuration Guide](./docs/api/CONFIGURATION.md)\n- [Runtime API Guide](./docs/runtime.md)\n- [Auto Translate Guide](./docs/auto-translate.md)\n- [Scanner Guide](./docs/scanner-guide.md)\n- [Environment Variables](./docs/environment-variables.md)\n- [Migration Guide v3.1.2](./docs/migration-guide-v3.1.2.md)\n- [Migration Guide v3.1.1](./docs/migration-guide-v3.1.1.md)\n- [Migration Guide v3.0.0](./docs/migration-guide-v3.0.0.md)\n- [Migration Guide v2.6.0](./docs/migration-guide-v2.6.0.md)\n- [Migration Guide v2.5.1](./docs/migration-guide-v2.5.1.md)\n\n## Security\n\n- No API key is required for the default Auto Translate flow.\n- Do not store secrets in locale files, `.i18ntk-config`, or protection files.\n- Project-specific brand/product terms should be configured by the user, not hardcoded into the package.\n- Report security issues using [SECURITY.md](./SECURITY.md).\n\n## Community\n\n- [Contributing](./CONTRIBUTING.md)\n- [Code of Conduct](./CODE_OF_CONDUCT.md)\n- [Funding](./FUNDING.md)\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n"
161
163
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "Fortfahren ohne erkanntes i18n-Framework."
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 Sprache ändern",
1109
- "separator": "============================================================",
1110
- "current": "Aktuelle Sprache: {language}",
1111
- "available": "Verfügbare Sprachen:",
1112
- "languageOption": "{index}. {displayName}{current}",
1113
- "backToMainMenu": "Zurück zum Hauptmenü",
1114
- "prompt": "Wähle eine Sprache (0–8):",
1115
- "cancelled": "Sprachwechsel abgebrochen.",
1116
- "invalid": "Ungültige Auswahl. Bitte erneut versuchen.",
1117
- "changed": "Sprache geändert zu: {language}",
1118
- "changeFailed": "Sprachwechsel fehlgeschlagen: {error}",
1119
- "pressEnterToContinue": "Drücke Enter, um fortzufahren..."
1108
+ "title": "🌍 Sprache ändern",
1109
+ "separator": "============================================================",
1110
+ "current": "Aktuelle Sprache: {language}",
1111
+ "available": "Verfügbare Sprachen:",
1112
+ "languageOption": "{index}. {displayName}{current}",
1113
+ "backToMainMenu": "Zurück zum Hauptmenü",
1114
+ "prompt": "Wähle eine Sprache (0–8):",
1115
+ "cancelled": "Sprachwechsel abgebrochen.",
1116
+ "invalid": "Ungültige Auswahl. Bitte erneut versuchen.",
1117
+ "changed": "Sprache geändert zu: {language}",
1118
+ "changeFailed": "Sprachwechsel fehlgeschlagen: {error}",
1119
+ "pressEnterToContinue": "Drücke Enter, um fortzufahren..."
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 Workflow zur Wahrung der Sprachreinheit",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "Proceeding without detected i18n framework."
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 Change Language",
1109
- "separator": "============================================================",
1110
- "current": "Current language: {language}",
1111
- "available": "Available Languages:",
1112
- "languageOption": "{index}. {displayName}{current}",
1113
- "backToMainMenu": "Back to Main Menu",
1114
- "prompt": "Select a language (0-8):",
1115
- "cancelled": "Language change cancelled.",
1116
- "invalid": "Invalid choice. Please try again.",
1117
- "changed": "Language changed to: {language}",
1118
- "changeFailed": "Failed to change language: {error}",
1119
- "pressEnterToContinue": "Press Enter to continue..."
1108
+ "title": "🌍 Change Language",
1109
+ "separator": "============================================================",
1110
+ "current": "Current language: {language}",
1111
+ "available": "Available Languages:",
1112
+ "languageOption": "{index}. {displayName}{current}",
1113
+ "backToMainMenu": "Back to Main Menu",
1114
+ "prompt": "Select a language (0-8):",
1115
+ "cancelled": "Language change cancelled.",
1116
+ "invalid": "Invalid choice. Please try again.",
1117
+ "changed": "Language changed to: {language}",
1118
+ "changeFailed": "Failed to change language: {error}",
1119
+ "pressEnterToContinue": "Press Enter to continue..."
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 Language Purity Maintenance Workflow",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "Procediendo sin marco i18n detectado."
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 Cambiar Idioma",
1109
- "separator": "============================================================",
1110
- "current": "Idioma actual: {language}",
1111
- "available": "Idiomas Disponibles:",
1112
- "languageOption": "{index}. {displayName}{current}",
1113
- "backToMainMenu": "Volver al Menú Principal",
1114
- "prompt": "Selecciona un idioma (0-8):",
1115
- "cancelled": "Cambio de idioma cancelado.",
1116
- "invalid": "Opción inválida. Por favor intenta de nuevo.",
1117
- "changed": "Idioma cambiado a: {language}",
1118
- "changeFailed": "Error al cambiar el idioma: {error}",
1119
- "pressEnterToContinue": "Presiona Enter para continuar..."
1108
+ "title": "🌍 Cambiar Idioma",
1109
+ "separator": "============================================================",
1110
+ "current": "Idioma actual: {language}",
1111
+ "available": "Idiomas Disponibles:",
1112
+ "languageOption": "{index}. {displayName}{current}",
1113
+ "backToMainMenu": "Volver al Menú Principal",
1114
+ "prompt": "Selecciona un idioma (0-8):",
1115
+ "cancelled": "Cambio de idioma cancelado.",
1116
+ "invalid": "Opción inválida. Por favor intenta de nuevo.",
1117
+ "changed": "Idioma cambiado a: {language}",
1118
+ "changeFailed": "Error al cambiar el idioma: {error}",
1119
+ "pressEnterToContinue": "Presiona Enter para continuar..."
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 Flujo de Trabajo de Mantenimiento de Pureza de Idioma",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "Poursuite sans framework i18n détecté."
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 Changer la langue",
1109
- "separator": "============================================================",
1110
- "current": "Langue actuelle : {language}",
1111
- "available": "Langues disponibles :",
1112
- "languageOption": "{index}. {displayName}{current}",
1113
- "backToMainMenu": "Retour au menu principal",
1114
- "prompt": "Sélectionnez une langue (0-8) :",
1115
- "cancelled": "Changement de langue annulé.",
1116
- "invalid": "Choix invalide. Veuillez réessayer.",
1117
- "changed": "Langue changée en : {language}",
1118
- "changeFailed": "Échec du changement de langue : {error}",
1119
- "pressEnterToContinue": "Appuyez sur Entrée pour continuer…"
1108
+ "title": "🌍 Changer la langue",
1109
+ "separator": "============================================================",
1110
+ "current": "Langue actuelle : {language}",
1111
+ "available": "Langues disponibles :",
1112
+ "languageOption": "{index}. {displayName}{current}",
1113
+ "backToMainMenu": "Retour au menu principal",
1114
+ "prompt": "Sélectionnez une langue (0-8) :",
1115
+ "cancelled": "Changement de langue annulé.",
1116
+ "invalid": "Choix invalide. Veuillez réessayer.",
1117
+ "changed": "Langue changée en : {language}",
1118
+ "changeFailed": "Échec du changement de langue : {error}",
1119
+ "pressEnterToContinue": "Appuyez sur Entrée pour continuer…"
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 Flux de maintenance de la pureté linguistique",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "i18n フレームワークが検出されないまま続行します。"
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 言語を変更",
1109
- "separator": "============================================================",
1110
- "current": "現在の言語: {language}",
1111
- "available": "利用可能な言語:",
1112
- "languageOption": "{index}。 {displayName}{current}",
1113
- "backToMainMenu": "メインメニューに戻る",
1114
- "prompt": "言語を選択してください (0-8):",
1115
- "cancelled": "言語変更がキャンセルされました。",
1116
- "invalid": "無効な選択です。もう一度お試しください。",
1117
- "changed": "言語が {language} に変更されました",
1118
- "changeFailed": "言語の変更に失敗しました: {error}",
1119
- "pressEnterToContinue": "続行するにはEnterキーを押してください…"
1108
+ "title": "🌍 言語を変更",
1109
+ "separator": "============================================================",
1110
+ "current": "現在の言語: {language}",
1111
+ "available": "利用可能な言語:",
1112
+ "languageOption": "{index}。 {displayName}{current}",
1113
+ "backToMainMenu": "メインメニューに戻る",
1114
+ "prompt": "言語を選択してください (0-8):",
1115
+ "cancelled": "言語変更がキャンセルされました。",
1116
+ "invalid": "無効な選択です。もう一度お試しください。",
1117
+ "changed": "言語が {language} に変更されました",
1118
+ "changeFailed": "言語の変更に失敗しました: {error}",
1119
+ "pressEnterToContinue": "続行するにはEnterキーを押してください…"
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 言語純度維持ワークフロー",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "Продолжаем без обнаружения платформы i18n."
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 Сменить язык",
1109
- "separator": "============================================================",
1110
- "current": "Текущий язык: {language}",
1111
- "available": "Доступные языки:",
1112
- "languageOption": "{index}. {displayName}{current}",
1113
- "backToMainMenu": "Вернуться в главное меню",
1114
- "prompt": "Выберите язык (0-8):",
1115
- "cancelled": "Смена языка отменена.",
1116
- "invalid": "Неверный выбор. Пожалуйста, попробуйте снова.",
1117
- "changed": "Язык изменён на: {language}",
1118
- "changeFailed": "Не удалось сменить язык: {error}",
1119
- "pressEnterToContinue": "Нажмите Enter для продолжения..."
1108
+ "title": "🌍 Сменить язык",
1109
+ "separator": "============================================================",
1110
+ "current": "Текущий язык: {language}",
1111
+ "available": "Доступные языки:",
1112
+ "languageOption": "{index}. {displayName}{current}",
1113
+ "backToMainMenu": "Вернуться в главное меню",
1114
+ "prompt": "Выберите язык (0-8):",
1115
+ "cancelled": "Смена языка отменена.",
1116
+ "invalid": "Неверный выбор. Пожалуйста, попробуйте снова.",
1117
+ "changed": "Язык изменён на: {language}",
1118
+ "changeFailed": "Не удалось сменить язык: {error}",
1119
+ "pressEnterToContinue": "Нажмите Enter для продолжения..."
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 Рабочий процесс поддержания чистоты языков",
@@ -2112,8 +2112,8 @@
2112
2112
  "sizingCommand": "Оценка команды",
2113
2113
  "completeCommand": "Завершение команды",
2114
2114
  "summaryCommand": "Сводка команды",
2115
- "scannerCommand": "scanner - 🔍 Сканирование проблем i18n",
2116
- "translateCommand": "translate - Автоперевод (Бета)",
2115
+ "scannerCommand": "scanner - 🔍 Сканирование проблем i18n",
2116
+ "translateCommand": "translate - Автоперевод (Бета)",
2117
2117
  "debugCommand": "Отладка команды"
2118
2118
  },
2119
2119
  "test_complete_system": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1105,18 +1105,18 @@
1105
1105
  "warningProceedingWithoutFramework": "未检测到 i18n 框架即可继续。"
1106
1106
  },
1107
1107
  "language": {
1108
- "title": "🌍 切换语言",
1109
- "separator": "============================================================",
1110
- "current": "当前语言:{language}",
1111
- "available": "可用语言:",
1112
- "languageOption": "{index}。 {displayName}{current}",
1113
- "backToMainMenu": "返回主菜单",
1114
- "prompt": "请选择语言(0-8):",
1115
- "cancelled": "已取消语言切换。",
1116
- "invalid": "无效选择,请重试。",
1117
- "changed": "语言已切换为:{language}",
1118
- "changeFailed": "切换语言失败:{error}",
1119
- "pressEnterToContinue": "按 Enter 继续..."
1108
+ "title": "🌍 切换语言",
1109
+ "separator": "============================================================",
1110
+ "current": "当前语言:{language}",
1111
+ "available": "可用语言:",
1112
+ "languageOption": "{index}。 {displayName}{current}",
1113
+ "backToMainMenu": "返回主菜单",
1114
+ "prompt": "请选择语言(0-8):",
1115
+ "cancelled": "已取消语言切换。",
1116
+ "invalid": "无效选择,请重试。",
1117
+ "changed": "语言已切换为:{language}",
1118
+ "changeFailed": "切换语言失败:{error}",
1119
+ "pressEnterToContinue": "按 Enter 继续..."
1120
1120
  },
1121
1121
  "maintainLanguagePurity": {
1122
1122
  "workflow_title": "🚀 语言纯洁度维护工作流",
@@ -380,9 +380,13 @@ async function acquireConfigLock(timeoutMs = CONFIG_LOCK_TIMEOUT_MS) {
380
380
  };
381
381
  }
382
382
 
383
- function isAutosaveDisabled() {
384
- return envManager.getBoolean('I18NTK_DISABLE_AUTOSAVE');
385
- }
383
+ function isAutosaveDisabled() {
384
+ const raw = process.env.I18NTK_DISABLE_AUTOSAVE;
385
+ if (raw !== undefined && raw !== null && raw !== '') {
386
+ return ['true', '1', 'yes'].includes(String(raw).trim().toLowerCase());
387
+ }
388
+ return envManager.getBoolean('I18NTK_DISABLE_AUTOSAVE');
389
+ }
386
390
 
387
391
  function clone(obj) {
388
392
  return JSON.parse(JSON.stringify(obj));