i18ntk 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -1
- package/README.md +28 -15
- package/SECURITY.md +19 -5
- package/main/i18ntk-complete.js +120 -49
- package/main/i18ntk-translate.js +25 -1
- package/package.json +3 -3
- package/ui-locales/de.json +1389 -1359
- package/ui-locales/es.json +1503 -1473
- package/ui-locales/fr.json +1626 -1596
- package/ui-locales/ja.json +1595 -1565
- package/ui-locales/ru.json +1638 -1608
- package/ui-locales/zh.json +1613 -1583
- package/utils/translate/api.js +164 -41
- package/utils/translate/safe-network.js +280 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,40 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [3.
|
|
8
|
+
## [3.3.0] - 2026-05-20
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Auto Translate now supports `--provider google|deepl|libretranslate`; DeepL uses `DEEPL_API_KEY`, while LibreTranslate supports `LIBRETRANSLATE_URL` and optional `LIBRETRANSLATE_API_KEY`.
|
|
12
|
+
- Auto Translate provider networking now keeps HTTPS, host allowlist, response-size, private-network, and redacted security logging protections in place for additional providers.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- `i18ntk-complete` now fills missing target-language keys from the English source value with a language prefix such as `[DE] Home` instead of writing `NOT_TRANSLATED`; this works for both `locales/en/*.json` and monolith `locales/en.json` layouts.
|
|
16
|
+
|
|
17
|
+
### Security
|
|
18
|
+
- Eliminated all 21 dynamic `require()` calls flagged by Socket.dev: 20 `require(path.join(__dirname, ...))` patterns in `i18ntk-js.js`, `i18ntk-py.js`, `i18ntk-java.js`, `i18ntk-php.js`, and `i18ntk-go.js` converted to static string literal requires.
|
|
19
|
+
- Added `SecurityUtils.validatePath()` gate around the remaining dynamic `require()` in `i18ntk-translate.js` `loadCustomTranslateFn`.
|
|
20
|
+
- Created `utils/translate/safe-network.js` — a secure HTTPS wrapper with URL host/path allowlist validation, response size limits (100KB), suspicious query parameter detection, and security event logging. All outbound network access now flows through this validated layer.
|
|
21
|
+
- Replaced direct `https.get` call in `utils/translate/api.js` with `safeHttpGet` from the safe-network wrapper.
|
|
22
|
+
|
|
23
|
+
### Docs
|
|
24
|
+
- README.md updated for v3.3.0 Auto Translate providers and secure provider operations.
|
|
25
|
+
- SECURITY.md updated with Socket.dev analysis disclaimer and guidance on expected alerts for a CLI/i18n toolkit.
|
|
26
|
+
- CHANGELOG.md and `package.json` versionInfo updated for v3.3.0.
|
|
27
|
+
|
|
28
|
+
### Socket.dev Analysis Disclaimer
|
|
29
|
+
|
|
30
|
+
This package is a developer CLI and runtime helper that performs file I/O, network access (translation provider APIs on user request), and environment variable access. As such, Socket.dev will flag the following alerts that are **expected and by design**:
|
|
31
|
+
|
|
32
|
+
| Alert | Why it's expected |
|
|
33
|
+
|---|---|
|
|
34
|
+
| Network access | Only contacts configured translation providers via HTTPS when user invokes auto-translate. All outbound calls flow through `safe-network.js` with host/path allowlist validation, response size limits, private-network blocking, and redacted security event logging. No telemetry, no unexpected outbound calls. |
|
|
35
|
+
| Environment variable access | Centralized through `env-manager.js` with a strict allowlist. Blocks `SECRET`, `PASSWORD`, `KEY`, `TOKEN`, `AWS_*`, `NPM_*`, and 15+ other patterns. |
|
|
36
|
+
| Filesystem access | Reads/writes only project locale files and reports within validated paths. All FS operations gated by `SecurityUtils.validatePath`. |
|
|
37
|
+
| URL strings | Hardcoded default provider URLs for Google, DeepL, and LibreTranslate used only for auto-translation. No external resource loading. |
|
|
38
|
+
|
|
39
|
+
The v3.3.0 release resolves the actionable dynamic-require alert by eliminating all 21 instances.
|
|
40
|
+
|
|
41
|
+
## [3.2.0] - 2026-05-16
|
|
9
42
|
|
|
10
43
|
### Security
|
|
11
44
|
- **CRITICAL**: Fixed invalid `crypto.createCipherGCM`/`createDecipherGCM` API calls in `admin-pin.js` — replaced with `crypto.createCipheriv`/`createDecipheriv`.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# i18ntk v3.
|
|
1
|
+
# i18ntk v3.3.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A i18n toolkit - 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
|
|
|
5
5
|

|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ Zero-dependency internationalization toolkit for setup, scanning, analysis, vali
|
|
|
9
9
|
[](https://nodejs.org)
|
|
10
10
|
[](https://www.npmjs.com/package/i18ntk)
|
|
11
11
|
[](LICENSE)
|
|
12
|
-
[](https://socket.dev/npm/package/i18ntk/overview/3.3.0)
|
|
13
13
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
@@ -30,14 +30,14 @@ Requirements:
|
|
|
30
30
|
- npm `>=8.0.0`
|
|
31
31
|
- No runtime dependencies
|
|
32
32
|
|
|
33
|
-
## What's New in 3.
|
|
33
|
+
## What's New in 3.3.0
|
|
34
34
|
|
|
35
|
-
- **SECURITY**:
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
35
|
+
- **SECURITY**: Eliminated all 21 dynamic `require()` calls flagged by Socket.dev; 20 converted to static string literals, 1 gated with `SecurityUtils.validatePath`.
|
|
36
|
+
- **AUTO TRANSLATE**: Added provider selection for Google, DeepL, and LibreTranslate.
|
|
37
|
+
- **FIX**: `i18ntk-complete` now fills missing target-language keys from English values with language prefixes instead of `NOT_TRANSLATED`.
|
|
38
|
+
- **DOCS**: SECURITY.md updated with Socket.dev analysis disclaimer explaining expected alerts for a CLI/i18n toolkit.
|
|
39
39
|
|
|
40
|
-
See [CHANGELOG.md](./CHANGELOG.md)
|
|
40
|
+
See [CHANGELOG.md](./CHANGELOG.md) for more release details.
|
|
41
41
|
|
|
42
42
|
## Quick Start
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ Initialize a project:
|
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
i18ntk
|
|
48
|
-
# or
|
|
48
|
+
# or with explicit command
|
|
49
49
|
i18ntk --command=init
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -111,8 +111,8 @@ i18ntk-fixer
|
|
|
111
111
|
i18ntk-backup
|
|
112
112
|
i18ntk-translate
|
|
113
113
|
```
|
|
114
|
-
|
|
115
|
-
Note: manager route `i18ntk --command=backup` is disabled in current builds. Use `i18ntk-backup` directly for backup operations.
|
|
114
|
+
`n
|
|
115
|
+
Note: manager route `i18ntk --command=backup` is disabled in current builds. Use `i18ntk-backup` (or legacy `i18ntk-backup`) directly for backup operations.
|
|
116
116
|
|
|
117
117
|
## Common Options
|
|
118
118
|
|
|
@@ -150,6 +150,21 @@ i18ntk-translate locales/en/common.json fr --dry-run --report-stdout
|
|
|
150
150
|
i18ntk-translate locales/en es --source-dir locales/en --files "*.json" --no-confirm --preserve-placeholders
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
Provider examples:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
export DEEPL_API_KEY="your-deepl-api-key"
|
|
157
|
+
i18ntk-translate locales/en/common.json de --provider deepl --no-confirm --preserve-placeholders
|
|
158
|
+
|
|
159
|
+
export LIBRETRANSLATE_URL="https://libretranslate.com/translate"
|
|
160
|
+
export LIBRETRANSLATE_API_KEY="optional-api-key"
|
|
161
|
+
i18ntk-translate locales/en/common.json es --provider libretranslate --no-confirm --preserve-placeholders
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`google` remains the default provider. You can also set `I18NTK_TRANSLATE_PROVIDER=deepl` or `I18NTK_TRANSLATE_PROVIDER=libretranslate`.
|
|
165
|
+
|
|
166
|
+
Provider requests are HTTPS-only and response-size limited, and security logs redact provider query strings and response bodies. DeepL is pinned to official DeepL hosts by default; set `I18NTK_ALLOW_CUSTOM_TRANSLATE_HOSTS=1` only for a trusted DeepL-compatible proxy. Custom LibreTranslate URLs are blocked for localhost/private IP ranges unless `I18NTK_ALLOW_PRIVATE_TRANSLATE_URLS=1` is set for trusted local testing. Keep provider API keys in environment variables or a secret manager.
|
|
167
|
+
|
|
153
168
|
The manager flow asks for:
|
|
154
169
|
|
|
155
170
|
- source locale directory, either the folder with JSON files or a locale root such as `./locales`
|
|
@@ -289,7 +304,7 @@ Example:
|
|
|
289
304
|
|
|
290
305
|
```json
|
|
291
306
|
{
|
|
292
|
-
"version": "3.
|
|
307
|
+
"version": "3.3.0",
|
|
293
308
|
"sourceDir": "./locales",
|
|
294
309
|
"i18nDir": "./locales",
|
|
295
310
|
"outputDir": "./i18ntk-reports",
|
|
@@ -350,8 +365,6 @@ The public package manifest includes `readmeFilename: "README.md"`, and the rele
|
|
|
350
365
|
- [Migration Guide v3.2.0](./docs/migration-guide-v3.2.0.md)
|
|
351
366
|
- [Migration Guide v3.1.1](./docs/migration-guide-v3.1.1.md)
|
|
352
367
|
- [Migration Guide v3.0.0](./docs/migration-guide-v3.0.0.md)
|
|
353
|
-
- [Migration Guide v2.6.0](./docs/migration-guide-v2.6.0.md)
|
|
354
|
-
- [Migration Guide v2.5.1](./docs/migration-guide-v2.5.1.md)
|
|
355
368
|
|
|
356
369
|
## Security
|
|
357
370
|
|
package/SECURITY.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Supported Versions
|
|
4
4
|
|
|
5
|
-
The supported production line is `
|
|
5
|
+
The supported production line is `3.x`.
|
|
6
6
|
|
|
7
|
-
Versions earlier than `
|
|
7
|
+
Versions earlier than `3.3.0` are not recommended for production use because later releases include Auto Translate provider hardening, dynamic-require elimination, and path-validation hardening.
|
|
8
8
|
|
|
9
9
|
## Security Model
|
|
10
10
|
|
|
@@ -14,8 +14,8 @@ Security priorities:
|
|
|
14
14
|
|
|
15
15
|
- zero runtime dependencies
|
|
16
16
|
- no install-time lifecycle commands in the public package manifest
|
|
17
|
-
- no shipped local setup state, admin PINs,
|
|
18
|
-
- centralized environment-variable access through `utils/env-manager.js`
|
|
17
|
+
- no shipped local setup state, admin PINs, backup files, reports, logs, credentials, or generated artifacts
|
|
18
|
+
- centralized environment-variable access through `utils/env-manager.js` with a strict allowlist
|
|
19
19
|
- path containment checks based on resolved paths and `path.relative()`
|
|
20
20
|
- timing-safe comparison for authentication hashes or tokens
|
|
21
21
|
- silent-by-default logging for production-like contexts
|
|
@@ -24,6 +24,20 @@ Security priorities:
|
|
|
24
24
|
|
|
25
25
|
The npm package uses a stripped public manifest. It must not contain install-time lifecycle commands, dependency fields, local setup state, or development tooling.
|
|
26
26
|
|
|
27
|
+
## Socket.dev Analysis Disclaimer
|
|
28
|
+
|
|
29
|
+
Socket.dev scans the published npm package and may flag the following alerts. These are **expected behaviors** for a developer CLI/i18n toolkit and are mitigated as described:
|
|
30
|
+
|
|
31
|
+
| Alert | Design Rationale | Mitigation |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **Network access** | Contacts configured translation providers via HTTPS only when user explicitly invokes auto-translate. No telemetry, no beaconing, no background network activity. | `utils/translate/safe-network.js` enforces HTTPS, host/path allowlists, response-size limits, private-network blocking, and redacted security logging for Google, DeepL, and LibreTranslate provider requests. |
|
|
34
|
+
| **Environment variable access** | Reads env vars for logging level, output directory, UI language, and project paths. Required for CLI configuration. | `utils/env-manager.js` uses a fixed allowlist (28 vars). Blocks `SECRET`, `PASSWORD`, `KEY`, `TOKEN`, `AWS_*`, `GITHUB_*`, `NPM_*`, `NODE_*`, `PATH`, `HOME`, `USER`, `SHELL`, and 8 more patterns. |
|
|
35
|
+
| **Filesystem access** | Reads/writes locale JSON files, config files, and reports within the user's project. Core function of the toolkit. | All FS operations are gated by `SecurityUtils.validatePath()` with path-traversal detection, symlink resolution, and base-path containment checks. |
|
|
36
|
+
| **URL strings** | Contains hardcoded translation provider endpoint URLs for Google, DeepL, and LibreTranslate defaults. | Only used when user invokes `i18ntk-translate`. Custom provider URLs remain HTTPS-only and are validated before use. |
|
|
37
|
+
|
|
38
|
+
The v3.3.0 release **resolved** the previously actionable Socket.dev alert:
|
|
39
|
+
- **Dynamic require** — all 21 instances eliminated (20 converted to static string literals, 1 gated with `SecurityUtils.validatePath`).
|
|
40
|
+
|
|
27
41
|
## Reporting Vulnerabilities
|
|
28
42
|
|
|
29
43
|
Do not report security vulnerabilities in public GitHub issues.
|
|
@@ -46,7 +60,7 @@ Security reports are reviewed privately first. Confirmed issues should receive:
|
|
|
46
60
|
|
|
47
61
|
## User Guidance
|
|
48
62
|
|
|
49
|
-
- Keep i18ntk updated to `
|
|
63
|
+
- Keep i18ntk updated to `3.3.0` or newer.
|
|
50
64
|
- Do not commit `.i18ntk-config`, admin PIN files, backup directories, generated reports, logs, npm credentials, or secret material.
|
|
51
65
|
- Run i18ntk only in project directories you trust.
|
|
52
66
|
- Review generated translation changes before committing them.
|
package/main/i18ntk-complete.js
CHANGED
|
@@ -161,9 +161,14 @@ class I18nCompletionTool {
|
|
|
161
161
|
return lowered.startsWith('backup-') || lowered === 'backup' || lowered === 'reports' || lowered === 'i18ntk-reports';
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// Get all JSON files from a language directory
|
|
165
|
-
getLanguageFiles(language) {
|
|
166
|
-
const
|
|
164
|
+
// Get all JSON files from a language directory
|
|
165
|
+
getLanguageFiles(language) {
|
|
166
|
+
const monolithFile = path.join(this.sourceDir, `${language}.json`);
|
|
167
|
+
if (SecurityUtils.safeExistsSync(monolithFile, this.config.projectRoot)) {
|
|
168
|
+
return [`${language}.json`];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const languageDir = path.join(this.sourceDir, language);
|
|
167
172
|
|
|
168
173
|
if (!SecurityUtils.safeExistsSync(languageDir, this.config.projectRoot)) {
|
|
169
174
|
return [];
|
|
@@ -173,8 +178,20 @@ class I18nCompletionTool {
|
|
|
173
178
|
.filter(file => {
|
|
174
179
|
return file.endsWith('.json') &&
|
|
175
180
|
!this.config.excludeFiles.includes(file);
|
|
176
|
-
});
|
|
177
|
-
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getLanguageFilePath(language, fileName) {
|
|
185
|
+
if (fileName === `${language}.json`) {
|
|
186
|
+
return path.join(this.sourceDir, fileName);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return path.join(this.sourceDir, language, fileName);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
usesMonolithFile(language) {
|
|
193
|
+
return SecurityUtils.safeExistsSync(path.join(this.sourceDir, `${language}.json`), this.config.projectRoot);
|
|
194
|
+
}
|
|
178
195
|
|
|
179
196
|
// Parse key path and determine which file it belongs to
|
|
180
197
|
parseKeyPath(keyPath) {
|
|
@@ -238,25 +255,30 @@ class I18nCompletionTool {
|
|
|
238
255
|
}
|
|
239
256
|
|
|
240
257
|
// Add missing keys to a language
|
|
241
|
-
addMissingKeysToLanguage(language, missingKeys, dryRun = false) {
|
|
242
|
-
const languageDir = path.join(this.sourceDir, language);
|
|
243
|
-
const changes = [];
|
|
258
|
+
addMissingKeysToLanguage(language, missingKeys, dryRun = false) {
|
|
259
|
+
const languageDir = path.join(this.sourceDir, language);
|
|
260
|
+
const changes = [];
|
|
261
|
+
const usesMonolith = this.usesMonolithFile(language);
|
|
244
262
|
|
|
245
263
|
// Group keys by file
|
|
246
264
|
const keysByFile = {};
|
|
247
265
|
|
|
248
|
-
missingKeys.forEach(keyPath => {
|
|
249
|
-
const { file, key } =
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
266
|
+
missingKeys.forEach(keyPath => {
|
|
267
|
+
const { file, key } = usesMonolith
|
|
268
|
+
? { file: `${language}.json`, key: keyPath }
|
|
269
|
+
: this.parseKeyPath(keyPath);
|
|
270
|
+
if (!keysByFile[file]) {
|
|
271
|
+
keysByFile[file] = [];
|
|
272
|
+
}
|
|
253
273
|
keysByFile[file].push({ keyPath, key });
|
|
254
274
|
});
|
|
255
275
|
|
|
256
|
-
// Process each file
|
|
257
|
-
for (const [fileName, keys] of Object.entries(keysByFile)) {
|
|
258
|
-
const filePath =
|
|
259
|
-
|
|
276
|
+
// Process each file
|
|
277
|
+
for (const [fileName, keys] of Object.entries(keysByFile)) {
|
|
278
|
+
const filePath = usesMonolith
|
|
279
|
+
? path.join(this.sourceDir, fileName)
|
|
280
|
+
: path.join(languageDir, fileName);
|
|
281
|
+
let fileContent = {};
|
|
260
282
|
|
|
261
283
|
// Load existing file or create new
|
|
262
284
|
if (SecurityUtils.safeExistsSync(filePath, this.config.projectRoot)) {
|
|
@@ -266,12 +288,12 @@ class I18nCompletionTool {
|
|
|
266
288
|
console.warn(t("completeTranslations.warning_could_not_parse_filepa", { filePath })); ;
|
|
267
289
|
fileContent = {};
|
|
268
290
|
}
|
|
269
|
-
} else {
|
|
270
|
-
// Create directory if it doesn't exist
|
|
271
|
-
if (!SecurityUtils.safeExistsSync(languageDir, this.config.projectRoot)) {
|
|
272
|
-
if (!dryRun) {
|
|
273
|
-
SecurityUtils.safeMkdirSync(languageDir, this.config.projectRoot, { recursive: true });
|
|
274
|
-
}
|
|
291
|
+
} else {
|
|
292
|
+
// Create directory if it doesn't exist
|
|
293
|
+
if (!usesMonolith && !SecurityUtils.safeExistsSync(languageDir, this.config.projectRoot)) {
|
|
294
|
+
if (!dryRun) {
|
|
295
|
+
SecurityUtils.safeMkdirSync(languageDir, this.config.projectRoot, { recursive: true });
|
|
296
|
+
}
|
|
275
297
|
}
|
|
276
298
|
}
|
|
277
299
|
|
|
@@ -303,19 +325,66 @@ class I18nCompletionTool {
|
|
|
303
325
|
return changes;
|
|
304
326
|
}
|
|
305
327
|
|
|
306
|
-
// Generate appropriate translation value based on key and language
|
|
307
|
-
generateTranslationValue(keyPath, language) {
|
|
308
|
-
|
|
309
|
-
const baseValue =
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
328
|
+
// Generate appropriate translation value based on key and language
|
|
329
|
+
generateTranslationValue(keyPath, language) {
|
|
330
|
+
const sourceValue = this.getSourceValueForKeyPath(keyPath);
|
|
331
|
+
const baseValue = typeof sourceValue === 'string' && sourceValue.trim() !== ''
|
|
332
|
+
? sourceValue
|
|
333
|
+
: this.generateValueFromKey(keyPath);
|
|
334
|
+
|
|
335
|
+
// For source language, use the generated value
|
|
336
|
+
if (language === this.config.sourceLanguage) {
|
|
337
|
+
return baseValue;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return `[${language.toUpperCase()}] ${baseValue}`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
getNestedValue(obj, keyPath) {
|
|
344
|
+
const keys = String(keyPath || '').split('.');
|
|
345
|
+
let current = obj;
|
|
346
|
+
|
|
347
|
+
for (const key of keys) {
|
|
348
|
+
if (!current || typeof current !== 'object' || !(key in current)) {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
current = current[key];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return current;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
getSourceValueForKeyPath(keyPath) {
|
|
358
|
+
if (!this.sourceLanguageDir && !this.usesMonolithFile(this.config.sourceLanguage)) {
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const sourceFiles = this.getLanguageFiles(this.config.sourceLanguage);
|
|
363
|
+
const keyPathStr = String(keyPath || '');
|
|
364
|
+
const parsed = this.parseKeyPath(keyPathStr);
|
|
365
|
+
|
|
366
|
+
for (const fileName of sourceFiles) {
|
|
367
|
+
const sourceFilePath = this.getLanguageFilePath(this.config.sourceLanguage, fileName);
|
|
368
|
+
try {
|
|
369
|
+
const sourceContent = SecurityUtils.safeParseJSON(SecurityUtils.safeReadFileSync(sourceFilePath, this.config.projectRoot, 'utf8'));
|
|
370
|
+
if (!sourceContent || typeof sourceContent !== 'object') continue;
|
|
371
|
+
|
|
372
|
+
const candidates = [keyPathStr];
|
|
373
|
+
if (fileName === parsed.file) {
|
|
374
|
+
candidates.push(parsed.key);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
for (const candidate of candidates) {
|
|
378
|
+
const value = this.getNestedValue(sourceContent, candidate);
|
|
379
|
+
if (value !== undefined) return value;
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.warn(t("complete.couldNotParseSource", { file: sourceFilePath }));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
319
388
|
|
|
320
389
|
// Generate a readable value from a key path
|
|
321
390
|
generateValueFromKey(keyPath) {
|
|
@@ -351,18 +420,18 @@ class I18nCompletionTool {
|
|
|
351
420
|
}
|
|
352
421
|
|
|
353
422
|
// Get missing keys by comparing source language with target languages
|
|
354
|
-
getMissingKeysFromComparison() {
|
|
355
|
-
const sourceFiles = this.getLanguageFiles(this.config.sourceLanguage);
|
|
356
|
-
const missingKeys = [];
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
console.log(t("complete.sourceLanguageNotFound", { sourceLanguage: this.config.sourceLanguage }));
|
|
360
|
-
return [];
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Process each file in source language
|
|
364
|
-
for (const fileName of sourceFiles) {
|
|
365
|
-
const sourceFilePath =
|
|
423
|
+
getMissingKeysFromComparison() {
|
|
424
|
+
const sourceFiles = this.getLanguageFiles(this.config.sourceLanguage);
|
|
425
|
+
const missingKeys = [];
|
|
426
|
+
|
|
427
|
+
if (sourceFiles.length === 0) {
|
|
428
|
+
console.log(t("complete.sourceLanguageNotFound", { sourceLanguage: this.config.sourceLanguage }));
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Process each file in source language
|
|
433
|
+
for (const fileName of sourceFiles) {
|
|
434
|
+
const sourceFilePath = this.getLanguageFilePath(this.config.sourceLanguage, fileName);
|
|
366
435
|
|
|
367
436
|
try {
|
|
368
437
|
const sourceContent = SecurityUtils.safeParseJSON(SecurityUtils.safeReadFileSync(sourceFilePath, this.config.projectRoot, 'utf8'));
|
|
@@ -373,7 +442,9 @@ class I18nCompletionTool {
|
|
|
373
442
|
for (const language of languages) {
|
|
374
443
|
if (language === this.config.sourceLanguage) continue;
|
|
375
444
|
|
|
376
|
-
const targetFilePath =
|
|
445
|
+
const targetFilePath = fileName === `${this.config.sourceLanguage}.json` || this.usesMonolithFile(language)
|
|
446
|
+
? path.join(this.sourceDir, `${language}.json`)
|
|
447
|
+
: path.join(this.sourceDir, language, fileName);
|
|
377
448
|
let targetKeys = [];
|
|
378
449
|
|
|
379
450
|
if (SecurityUtils.safeExistsSync(targetFilePath, this.config.projectRoot)) {
|
package/main/i18ntk-translate.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* Options:
|
|
16
16
|
* --source-dir <dir> Source directory (default: ./locales/en)
|
|
17
17
|
* --output-dir <dir> Output directory (default: ./locales/<lang>)
|
|
18
|
+
* --provider <name> Translation provider: google, deepl, libretranslate
|
|
18
19
|
* --custom-regex <regex> Additional placeholder regex pattern
|
|
19
20
|
* --no-confirm Skip all confirmation dialogs
|
|
20
21
|
* --preserve-placeholders Translate text around placeholders and reinsert tokens
|
|
@@ -90,6 +91,7 @@ function printHelp() {
|
|
|
90
91
|
'Options:',
|
|
91
92
|
' --source-dir <dir> Source directory containing locale files',
|
|
92
93
|
' --output-dir <dir> Output directory for translated files',
|
|
94
|
+
' --provider <name> Provider: google (default), deepl, libretranslate',
|
|
93
95
|
' --source-lang <code> Source language code (default: en)',
|
|
94
96
|
' --custom-regex <regex> Additional placeholder regex pattern',
|
|
95
97
|
' --no-confirm Automate: skip confirmation dialogs',
|
|
@@ -110,6 +112,15 @@ function printHelp() {
|
|
|
110
112
|
' --retry-count <n> Max retries per failed request (default: 3)',
|
|
111
113
|
' --retry-delay <ms> Base backoff delay in ms (default: 1000)',
|
|
112
114
|
' --timeout <ms> HTTP request timeout in ms (default: 15000)',
|
|
115
|
+
'',
|
|
116
|
+
'Environment:',
|
|
117
|
+
' I18NTK_TRANSLATE_PROVIDER Default provider when --provider is omitted',
|
|
118
|
+
' DEEPL_API_KEY Required for --provider deepl',
|
|
119
|
+
' DEEPL_API_URL Optional, defaults to https://api-free.deepl.com/v2/translate',
|
|
120
|
+
' I18NTK_ALLOW_CUSTOM_TRANSLATE_HOSTS=1 Allow custom DeepL-compatible HTTPS hosts',
|
|
121
|
+
' LIBRETRANSLATE_URL Optional, defaults to https://libretranslate.com/translate',
|
|
122
|
+
' LIBRETRANSLATE_API_KEY Optional API key for LibreTranslate servers that require one',
|
|
123
|
+
' I18NTK_ALLOW_PRIVATE_TRANSLATE_URLS=1 Allow localhost/private provider URLs for trusted testing',
|
|
113
124
|
' -h, --help Show this help',
|
|
114
125
|
].join('\n'));
|
|
115
126
|
}
|
|
@@ -121,6 +132,7 @@ function parseArgs(argv) {
|
|
|
121
132
|
sourceDir: null,
|
|
122
133
|
outputDir: null,
|
|
123
134
|
sourceLang: 'en',
|
|
135
|
+
provider: process.env.I18NTK_TRANSLATE_PROVIDER || 'google',
|
|
124
136
|
customRegex: [],
|
|
125
137
|
noConfirm: false,
|
|
126
138
|
preservePlaceholders: false,
|
|
@@ -161,6 +173,7 @@ function parseArgs(argv) {
|
|
|
161
173
|
else if (arg === '--source-dir' && i + 1 < argv.length) { args.sourceDir = argv[++i]; }
|
|
162
174
|
else if (arg === '--output-dir' && i + 1 < argv.length) { args.outputDir = argv[++i]; }
|
|
163
175
|
else if (arg === '--source-lang' && i + 1 < argv.length) { args.sourceLang = argv[++i]; }
|
|
176
|
+
else if (arg === '--provider' && i + 1 < argv.length) { args.provider = argv[++i]; }
|
|
164
177
|
else if (arg === '--custom-regex' && i + 1 < argv.length) { args.customRegex.push(argv[++i]); }
|
|
165
178
|
else if (arg === '--protection-file' && i + 1 < argv.length) { args.protectionFile = argv[++i]; }
|
|
166
179
|
else if (arg === '--concurrency' && i + 1 < argv.length) { args.concurrency = parseInt(argv[++i], 10) || 3; }
|
|
@@ -206,7 +219,17 @@ function loadCustomTranslateFn(modulePath) {
|
|
|
206
219
|
if (!modulePath) return null;
|
|
207
220
|
try {
|
|
208
221
|
const resolved = path.isAbsolute(modulePath) ? modulePath : path.resolve(process.cwd(), modulePath);
|
|
209
|
-
const
|
|
222
|
+
const validated = SecurityUtils.validatePath(resolved);
|
|
223
|
+
if (!validated) {
|
|
224
|
+
SecurityUtils.logSecurityEvent('Blocked unsafe custom translate module path', 'warn', {
|
|
225
|
+
modulePath,
|
|
226
|
+
resolved,
|
|
227
|
+
source: 'user'
|
|
228
|
+
});
|
|
229
|
+
console.error(`Error: Custom translate module path "${modulePath}" failed security validation.`);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
const mod = require(validated);
|
|
210
233
|
if (typeof mod === 'function') return mod;
|
|
211
234
|
if (mod && typeof mod.translate === 'function') return mod.translate;
|
|
212
235
|
if (mod && typeof mod.default === 'function') return mod.default;
|
|
@@ -676,6 +699,7 @@ async function processFile(sourcePath, targetLang, args) {
|
|
|
676
699
|
|
|
677
700
|
const translateOptions = {
|
|
678
701
|
sourceLang: args.sourceLang,
|
|
702
|
+
provider: args.provider,
|
|
679
703
|
concurrency: args.concurrency,
|
|
680
704
|
batchSize: args.batchSize,
|
|
681
705
|
retryCount: args.retryCount,
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18ntk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
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": [
|
|
7
7
|
"i18ntk",
|
|
8
|
-
"i18n-toolkit",
|
|
9
8
|
"i18n",
|
|
10
9
|
"internationalization",
|
|
11
10
|
"localization",
|
|
@@ -123,6 +122,7 @@
|
|
|
123
122
|
"utils/formats/json.js",
|
|
124
123
|
"utils/translate/placeholder.js",
|
|
125
124
|
"utils/translate/api.js",
|
|
125
|
+
"utils/translate/safe-network.js",
|
|
126
126
|
"utils/translate/traverse.js",
|
|
127
127
|
"utils/translate/report.js",
|
|
128
128
|
"utils/translate/cli.js",
|
|
@@ -161,5 +161,5 @@
|
|
|
161
161
|
"access": "public"
|
|
162
162
|
},
|
|
163
163
|
"preferGlobal": true,
|
|
164
|
-
"readme": "# i18ntk v3.2.0\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\n\n[](https://www.npmjs.com/package/i18ntk)\n[](https://www.npmjs.com/package/i18ntk)\n[](https://nodejs.org)\n[](https://www.npmjs.com/package/i18ntk)\n[](LICENSE)\n[](https://socket.dev/npm/package/i18ntk/overview/3.2.0)\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.2.0\n\n- **SECURITY**: Fixed 4 critical runtime-crash bugs (invalid crypto APIs, missing imports) across admin-pin.js, security-config.js, and scripts/security-check.js.\n- **SECURITY**: Removed encryption key stored alongside ciphertext in admin-pin.js; encryption key is now derived via HKDF.\n- **SECURITY**: Enforced HTTPS-only for Google Translate API requests; fixed http.get timeout for Node.js <16.14 compatibility.\n- **SECURITY**: Added path validation to backup restore/verify operations; locked down FileManagementService PIN verification stubs.\n\nSee [CHANGELOG.md](./CHANGELOG.md) and [docs/migration-guide-v3.2.0.md](./docs/migration-guide-v3.2.0.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.2.0\",\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.2.0](./docs/migration-guide-v3.2.0.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"
|
|
164
|
+
"readme": "# i18ntk v3.3.0\n\nA i18n toolkit - A zero-dependency internationalization toolkit for setup, scanning, analysis, validation, usage tracking, translation completion, automatic JSON locale translation, reporting, and runtime translation loading.\n\n\n\n[](https://www.npmjs.com/package/i18ntk)\n[](https://www.npmjs.com/package/i18ntk)\n[](https://nodejs.org)\n[](https://www.npmjs.com/package/i18ntk)\n[](LICENSE)\n[](https://socket.dev/npm/package/i18ntk/overview/3.3.0)\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.3.0\n\n- **SECURITY**: Eliminated all 21 dynamic `require()` calls flagged by Socket.dev; 20 converted to static string literals, 1 gated with `SecurityUtils.validatePath`.\n- **AUTO TRANSLATE**: Added provider selection for Google, DeepL, and LibreTranslate.\n- **FIX**: `i18ntk-complete` now fills missing target-language keys from English values with language prefixes instead of `NOT_TRANSLATED`.\n- **DOCS**: SECURITY.md updated with Socket.dev analysis disclaimer explaining expected alerts for a CLI/i18n toolkit.\n\nSee [CHANGELOG.md](./CHANGELOG.md) for more release details.\n\n## Quick Start\n\nInitialize a project:\n\n```bash\ni18ntk\n# or with explicit command\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`n\nNote: manager route `i18ntk --command=backup` is disabled in current builds. Use `i18ntk-backup` (or legacy `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\nProvider examples:\n\n```bash\nexport DEEPL_API_KEY=\"your-deepl-api-key\"\ni18ntk-translate locales/en/common.json de --provider deepl --no-confirm --preserve-placeholders\n\nexport LIBRETRANSLATE_URL=\"https://libretranslate.com/translate\"\nexport LIBRETRANSLATE_API_KEY=\"optional-api-key\"\ni18ntk-translate locales/en/common.json es --provider libretranslate --no-confirm --preserve-placeholders\n```\n\n`google` remains the default provider. You can also set `I18NTK_TRANSLATE_PROVIDER=deepl` or `I18NTK_TRANSLATE_PROVIDER=libretranslate`.\n\nProvider requests are HTTPS-only and response-size limited, and security logs redact provider query strings and response bodies. DeepL is pinned to official DeepL hosts by default; set `I18NTK_ALLOW_CUSTOM_TRANSLATE_HOSTS=1` only for a trusted DeepL-compatible proxy. Custom LibreTranslate URLs are blocked for localhost/private IP ranges unless `I18NTK_ALLOW_PRIVATE_TRANSLATE_URLS=1` is set for trusted local testing. Keep provider API keys in environment variables or a secret manager.\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.3.0\",\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.2.0](./docs/migration-guide-v3.2.0.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\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"
|
|
165
165
|
}
|