i18ntk 3.1.1 → 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,8 +3,19 @@
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
-
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
+
8
19
  ## [3.1.1] - 2026-05-07
9
20
 
10
21
  ### Added
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # i18ntk v3.1.1
1
+ # i18ntk v3.1.2
2
2
 
3
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
 
@@ -9,7 +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.1)](https://socket.dev/npm/package/i18ntk/overview/3.1.1)
12
+ [![socket](https://socket.dev/api/badge/npm/package/i18ntk/3.1.2)](https://socket.dev/npm/package/i18ntk/overview/3.1.2)
13
13
 
14
14
  ## Install
15
15
 
@@ -30,7 +30,7 @@ Requirements:
30
30
  - npm `>=8.0.0`
31
31
  - No runtime dependencies
32
32
 
33
- ## What's New in 3.1.1
33
+ ## What's New in 3.1.2
34
34
 
35
35
  - Auto Translate can translate strings that contain placeholders by translating text around the placeholders and reinserting the original tokens.
36
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.
@@ -41,8 +41,10 @@ Requirements:
41
41
  - Sizing reports now include per-language file counts, file-set mismatches, and per-file key/character statistics.
42
42
  - Internal UI locale coverage is enforced against the English UI locale.
43
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.
44
46
 
45
- See [CHANGELOG.md](./CHANGELOG.md) and [docs/migration-guide-v3.1.1.md](./docs/migration-guide-v3.1.1.md) for release details.
47
+ See [CHANGELOG.md](./CHANGELOG.md) and [docs/migration-guide-v3.1.2.md](./docs/migration-guide-v3.1.2.md) for release details.
46
48
 
47
49
  ## Quick Start
48
50
 
@@ -157,11 +159,13 @@ i18ntk-translate locales/en es --source-dir locales/en --files "*.json" --no-con
157
159
 
158
160
  The manager flow asks for:
159
161
 
160
- - source locale directory
162
+ - source locale directory, either the folder with JSON files or a locale root such as `./locales`
161
163
  - source language code
162
164
  - one or more target languages, or `all`
163
165
  - one JSON file or all JSON files in the source directory
164
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
+
165
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:
166
170
 
167
171
  ```text
@@ -228,7 +232,7 @@ See [docs/auto-translate.md](./docs/auto-translate.md) for the full Auto Transla
228
232
 
229
233
  Validation checks locale structure, completeness, placeholders, and content risks.
230
234
 
231
- In 3.1.1, warning types are more specific:
235
+ In 3.1.2, warning types are more specific:
232
236
 
233
237
  - `Potential risky content`: URL, email address, or secret-like value
234
238
  - `Possible untranslated English content`: target-language value appears to contain too much English
@@ -292,7 +296,7 @@ Example:
292
296
 
293
297
  ```json
294
298
  {
295
- "version": "3.1.1",
299
+ "version": "3.1.2",
296
300
  "sourceDir": "./locales",
297
301
  "i18nDir": "./locales",
298
302
  "outputDir": "./i18ntk-reports",
@@ -350,6 +354,7 @@ The public package manifest includes `readmeFilename: "README.md"`, and the rele
350
354
  - [Auto Translate Guide](./docs/auto-translate.md)
351
355
  - [Scanner Guide](./docs/scanner-guide.md)
352
356
  - [Environment Variables](./docs/environment-variables.md)
357
+ - [Migration Guide v3.1.2](./docs/migration-guide-v3.1.2.md)
353
358
  - [Migration Guide v3.1.1](./docs/migration-guide-v3.1.1.md)
354
359
  - [Migration Guide v3.0.0](./docs/migration-guide-v3.0.0.md)
355
360
  - [Migration Guide v2.6.0](./docs/migration-guide-v2.6.0.md)
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "3.1.1",
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
5
  "readmeFilename": "README.md",
6
6
  "keywords": [
@@ -158,5 +158,6 @@
158
158
  "publishConfig": {
159
159
  "access": "public"
160
160
  },
161
- "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"
162
163
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "updated": "2026-05-07"
5
5
  },
6
6
  "common": {
@@ -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));