i18ntk 1.7.5 → 1.8.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/README.md +45 -18
- package/main/i18ntk-fixer.js +126 -128
- package/main/i18ntk-manage.js +27 -59
- package/package.json +10 -9
- package/settings/.i18n-admin-config.json +2 -2
- package/settings/i18ntk-config.json +1 -8
- package/settings/settings-cli.js +8 -32
- package/ui-locales/de.json +10 -0
- package/ui-locales/en.json +10 -0
- package/ui-locales/es.json +11 -1
- package/ui-locales/fr.json +11 -1
- package/ui-locales/ja.json +11 -1
- package/ui-locales/ru.json +10 -0
- package/ui-locales/zh.json +10 -0
- package/main/i18ntk-autorun.js +0 -289
package/README.md
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
**Version:** 1.
|
|
5
|
+
**Version:** 1.8.0
|
|
6
6
|
**Last Updated:** 2025-08-11
|
|
7
7
|
**GitHub Repository:** [vladnoskv/i18ntk](https://github.com/vladnoskv/i18ntk)
|
|
8
8
|
|
|
9
|
-
[](https://www.npmjs.com/package/i18ntk) [](https://badge.fury.io/js/i18ntk) [](https://nodejs.org/) [](https://www.npmjs.com/package/i18ntk) [](https://www.npmjs.com/package/i18ntk) [](https://badge.fury.io/js/i18ntk) [](https://nodejs.org/) [](https://www.npmjs.com/package/i18ntk) [](https://socket.dev/npm/package/i18ntk/overview/1.8.0) [](https://github.com/vladnoskv/i18ntk)
|
|
10
10
|
|
|
11
11
|
**🚀 The fastest way to manage translations across any framework or vanilla JavaScript projects**
|
|
12
12
|
|
|
13
13
|
**Framework Support:** Auto-detects popular libraries (React i18next, Vue i18n, i18next, Nuxt i18n, Svelte i18n) or works without a framework. i18ntk manages translation files and validation—it does NOT implement translation logic like i18next or Vue i18n.
|
|
14
14
|
|
|
15
|
-
> **v1.
|
|
15
|
+
> **v1.8.0** – **SAFER WORKFLOW** - Autorun workflow removed for enhanced safety. Enhanced Interactive Translation Fixer Tool with improved automatic detection, selective language/file fixing, mass fix capabilities, and 7-language UI support; enhanced security logging, flexible 4-6 digit PIN authentication, configuration stability improvements, and CI/CD silent mode support; maintains 97% speed improvement.
|
|
16
16
|
|
|
17
17
|
## 🚀 Quick Start
|
|
18
18
|
|
|
@@ -46,8 +46,8 @@ i18ntk validate --source ./locales
|
|
|
46
46
|
|
|
47
47
|
## 🎯 Highlights
|
|
48
48
|
|
|
49
|
-
- **NEW in 1.
|
|
50
|
-
- **Interactive Translation Fixer:**
|
|
49
|
+
- **NEW in 1.8.0:** **SAFER WORKFLOW** - Autorun workflow removed for enhanced safety and configuration protection.
|
|
50
|
+
- **Enhanced Interactive Translation Fixer:** Improved automatic detection with guided flows, selective language/file fixing, mass fix capabilities, and 7-language UI support.
|
|
51
51
|
- **Ultra‑Extreme performance:** 97% speed improvement — **15.38ms** for 200k keys.
|
|
52
52
|
- **Security & Privacy:** PIN protection with AES‑256‑GCM; strict path and input validation.
|
|
53
53
|
- **Sizing tools:** Interactive locale optimizer (up to **86%** size reduction) and reports.
|
|
@@ -55,10 +55,11 @@ i18ntk validate --source ./locales
|
|
|
55
55
|
- **Watch helper:** Optional `--watch` keeps translations in sync.
|
|
56
56
|
- **Framework‑agnostic:** Works with React, Vue, Svelte, Nuxt, i18next, or plain JSON.
|
|
57
57
|
- **Scale:** Linear scaling up to 5M keys/second with ultra‑extreme settings.
|
|
58
|
+
- **Script-by-Script Safety:** Manual execution ensures proper setup before each operation.
|
|
58
59
|
|
|
59
60
|
---
|
|
60
61
|
|
|
61
|
-
## 🛡️ Security in 1.
|
|
62
|
+
## 🛡️ Security in 1.8.0
|
|
62
63
|
|
|
63
64
|
### Summary
|
|
64
65
|
|
|
@@ -71,7 +72,7 @@ i18ntk validate --source ./locales
|
|
|
71
72
|
|
|
72
73
|
### Before → After
|
|
73
74
|
|
|
74
|
-
| Area | Before (risk) | After (1.7.5)
|
|
75
|
+
| Area | Before (risk) | After (1.7.5+) |
|
|
75
76
|
| --------------------- | ---------------------------- | --------------------------------- |
|
|
76
77
|
| Shell execution | Possible via `child_process` | **Removed entirely** |
|
|
77
78
|
| File ops | Mixed shell + Node | **Node fs/path only** |
|
|
@@ -111,7 +112,25 @@ i18ntk validate --source ./locales
|
|
|
111
112
|
| `usage` | Analyze usage patterns | `i18ntk usage --format=json` |
|
|
112
113
|
| `doctor` | Diagnose configuration issues | `i18ntk doctor` |
|
|
113
114
|
| `sizing` | Optimize package size | `i18ntk sizing --interactive` |
|
|
114
|
-
| `fixer` | Fix broken translations/markers | `i18ntk fixer --interactive` |
|
|
115
|
+
| `fixer` | **Enhanced:** Fix broken translations/markers | `i18ntk fixer --interactive` |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 🔒 Safer Workflow (NEW in v1.8.0)
|
|
120
|
+
|
|
121
|
+
**Enhanced security through manual script execution:**
|
|
122
|
+
|
|
123
|
+
- **Autorun workflow removed** for enhanced safety and configuration protection
|
|
124
|
+
- **Script-by-script safety** - Each operation requires explicit user initiation
|
|
125
|
+
- **Enhanced validation** - All operations validated before execution
|
|
126
|
+
- **Improved security logging** - Comprehensive audit trail for all operations
|
|
127
|
+
- **Manual review encouraged** - Users maintain full control over each step
|
|
128
|
+
|
|
129
|
+
**Migration from previous versions:**
|
|
130
|
+
- The `workflow` command has been removed for security reasons
|
|
131
|
+
- Use individual commands (`analyze`, `validate`, `fixer`) for safer operations
|
|
132
|
+
- Enhanced fixer tool provides guided workflows for common tasks
|
|
133
|
+
- All previous functionality remains available through safer individual commands
|
|
115
134
|
|
|
116
135
|
---
|
|
117
136
|
|
|
@@ -121,7 +140,7 @@ Create `settings/i18ntk-config.json` (auto‑generated by `init`):
|
|
|
121
140
|
|
|
122
141
|
```json
|
|
123
142
|
{
|
|
124
|
-
"version": "1.
|
|
143
|
+
"version": "1.8.0",
|
|
125
144
|
"sourceDir": "./locales",
|
|
126
145
|
"outputDir": "./i18ntk-reports",
|
|
127
146
|
"defaultLanguage": "en",
|
|
@@ -162,14 +181,22 @@ You can override paths with environment variables:
|
|
|
162
181
|
|
|
163
182
|
---
|
|
164
183
|
|
|
165
|
-
## 🔧 Translation Fixer (
|
|
184
|
+
## 🔧 Enhanced Translation Fixer (v1.8.0)
|
|
185
|
+
|
|
186
|
+
Interactive tool with improved automatic detection to locate and repair placeholders such as `{{NOT_TRANSLATED}}`, `__UNTRANSLATED__`, or custom markers.
|
|
166
187
|
|
|
167
|
-
|
|
188
|
+
**Enhanced Features:**
|
|
189
|
+
- **Improved Auto-Detection:** Smarter detection of broken translations and markers
|
|
190
|
+
- **Selective Fixing:** Choose specific languages or files to fix
|
|
191
|
+
- **Mass Fix Capabilities:** Fix all broken translations at once
|
|
192
|
+
- **7-Language UI Support:** Complete interface in 7 languages
|
|
193
|
+
- **Script-by-Script Safety:** Manual execution ensures proper review
|
|
194
|
+
- **Enhanced Security:** Creates encrypted backups before any changes
|
|
168
195
|
|
|
169
196
|
**Examples:**
|
|
170
197
|
|
|
171
198
|
```bash
|
|
172
|
-
#
|
|
199
|
+
# Enhanced guided mode
|
|
173
200
|
i18ntk fixer --interactive
|
|
174
201
|
|
|
175
202
|
# Fix specific languages with custom markers
|
|
@@ -187,12 +214,12 @@ i18ntk fixer --languages all
|
|
|
187
214
|
|
|
188
215
|
**Interactive flow:**
|
|
189
216
|
|
|
190
|
-
- Welcome & help panel
|
|
191
|
-
-
|
|
192
|
-
- Language and directory selection
|
|
193
|
-
- Preview & confirmation
|
|
194
|
-
- Real‑time progress + stats
|
|
195
|
-
- Report generation (before/after, per‑file, per‑language)
|
|
217
|
+
- Welcome & help panel with 7-language support
|
|
218
|
+
- Enhanced marker configuration (built‑in + custom)
|
|
219
|
+
- Language and directory selection with smart filtering
|
|
220
|
+
- Preview & confirmation with detailed change overview
|
|
221
|
+
- Real‑time progress + comprehensive stats
|
|
222
|
+
- Report generation (before/after, per‑file, per‑language, security log)
|
|
196
223
|
|
|
197
224
|
---
|
|
198
225
|
|
package/main/i18ntk-fixer.js
CHANGED
|
@@ -123,86 +123,64 @@ class I18nFixer {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
async promptForMarkers() {
|
|
126
|
-
const
|
|
127
|
-
const rl = readline.createInterface({
|
|
128
|
-
input: process.stdin,
|
|
129
|
-
output: process.stdout
|
|
130
|
-
});
|
|
126
|
+
const { ask } = require('../utils/cli.js');
|
|
131
127
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
});
|
|
128
|
+
const defaultMarkers = ['__NOT_TRANSLATED__', 'NOT_TRANSLATED', 'TODO_TRANSLATE'];
|
|
129
|
+
console.log(`\n${this.t('fixer.markerPrompt.title')}`);
|
|
130
|
+
console.log(this.t('fixer.markerPrompt.description'));
|
|
131
|
+
console.log(this.t('fixer.markerPrompt.currentDefaults', { markers: defaultMarkers.join(', ') }));
|
|
132
|
+
|
|
133
|
+
const answer = await ask(this.t('fixer.markerPrompt.input'));
|
|
134
|
+
const cleanAnswer = answer.trim();
|
|
135
|
+
if (cleanAnswer) {
|
|
136
|
+
const markers = cleanAnswer.split(',').map(m => m.trim()).filter(Boolean);
|
|
137
|
+
return markers;
|
|
138
|
+
} else {
|
|
139
|
+
return defaultMarkers;
|
|
140
|
+
}
|
|
148
141
|
}
|
|
149
142
|
|
|
150
143
|
async promptForLanguages() {
|
|
151
|
-
const
|
|
152
|
-
const rl = readline.createInterface({
|
|
153
|
-
input: process.stdin,
|
|
154
|
-
output: process.stdout
|
|
155
|
-
});
|
|
144
|
+
const { ask } = require('../utils/cli.js');
|
|
156
145
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
146
|
+
const availableLanguages = this.getAvailableLanguages().filter(l => l !== this.config.sourceLanguage);
|
|
147
|
+
|
|
148
|
+
if (availableLanguages.length === 0) {
|
|
149
|
+
console.log(this.t('fixer.languagePrompt.noLanguages'));
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
165
152
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
});
|
|
181
|
-
});
|
|
153
|
+
console.log(`\n${this.t('fixer.languagePrompt.title')}`);
|
|
154
|
+
console.log(this.t('fixer.languagePrompt.available', { languages: availableLanguages.join(', ') }));
|
|
155
|
+
console.log(this.t('fixer.languagePrompt.description'));
|
|
156
|
+
|
|
157
|
+
const answer = await ask(this.t('fixer.languagePrompt.input'));
|
|
158
|
+
const cleanAnswer = answer.trim();
|
|
159
|
+
if (cleanAnswer) {
|
|
160
|
+
const languages = cleanAnswer.split(',').map(l => l.trim()).filter(Boolean);
|
|
161
|
+
// Validate languages exist
|
|
162
|
+
const validLanguages = languages.filter(l => availableLanguages.includes(l));
|
|
163
|
+
return validLanguages;
|
|
164
|
+
} else {
|
|
165
|
+
return availableLanguages;
|
|
166
|
+
}
|
|
182
167
|
}
|
|
183
168
|
|
|
184
169
|
async promptForDirectory() {
|
|
185
|
-
const
|
|
186
|
-
const rl = readline.createInterface({
|
|
187
|
-
input: process.stdin,
|
|
188
|
-
output: process.stdout
|
|
189
|
-
});
|
|
170
|
+
const { ask } = require('../utils/cli.js');
|
|
190
171
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
});
|
|
172
|
+
const defaultDir = this.config.sourceDir || './locales';
|
|
173
|
+
console.log(`\n${this.t('fixer.directoryPrompt.title')}`);
|
|
174
|
+
console.log(this.t('fixer.directoryPrompt.current', { dir: defaultDir }));
|
|
175
|
+
console.log(this.t('fixer.directoryPrompt.description'));
|
|
176
|
+
|
|
177
|
+
const answer = await ask(this.t('fixer.directoryPrompt.input'));
|
|
178
|
+
const cleanAnswer = answer.trim();
|
|
179
|
+
if (cleanAnswer) {
|
|
180
|
+
return cleanAnswer;
|
|
181
|
+
} else {
|
|
182
|
+
return defaultDir;
|
|
183
|
+
}
|
|
206
184
|
}
|
|
207
185
|
|
|
208
186
|
async initialize() {
|
|
@@ -487,24 +465,27 @@ class I18nFixer {
|
|
|
487
465
|
}
|
|
488
466
|
|
|
489
467
|
async getUserConfirmation() {
|
|
490
|
-
const
|
|
491
|
-
const rl = readline.createInterface({
|
|
492
|
-
input: process.stdin,
|
|
493
|
-
output: process.stdout
|
|
494
|
-
});
|
|
468
|
+
const { ask } = require('../utils/cli.js');
|
|
495
469
|
|
|
496
|
-
|
|
470
|
+
const askQuestion = async () => {
|
|
497
471
|
console.log(`\n${this.t('fixer.confirmationTitle')}`);
|
|
498
472
|
console.log(this.t('fixer.confirmationOptions'));
|
|
499
473
|
console.log(` ${this.t('fixer.optionYes')}`);
|
|
500
474
|
console.log(` ${this.t('fixer.optionNo')}`);
|
|
501
475
|
console.log(` ${this.t('fixer.optionShow')}`);
|
|
502
476
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
477
|
+
const answer = await ask(this.t('fixer.choicePrompt'));
|
|
478
|
+
const cleanAnswer = answer.toLowerCase().trim();
|
|
479
|
+
if (cleanAnswer === 's' || cleanAnswer === 'show') {
|
|
480
|
+
// Show detailed report and ask again
|
|
481
|
+
this.printDetailedReport();
|
|
482
|
+
return askQuestion();
|
|
483
|
+
} else {
|
|
484
|
+
return cleanAnswer;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
return askQuestion();
|
|
508
489
|
}
|
|
509
490
|
|
|
510
491
|
generateFixerReport(issues, report) {
|
|
@@ -581,72 +562,89 @@ class I18nFixer {
|
|
|
581
562
|
}
|
|
582
563
|
}
|
|
583
564
|
|
|
565
|
+
printDetailedReport() {
|
|
566
|
+
// This method is called when user selects 's' to show detailed issues
|
|
567
|
+
// Implementation can be added here if needed
|
|
568
|
+
console.log('\n📋 DETAILED REPORT - All issues shown above in the report file');
|
|
569
|
+
}
|
|
570
|
+
|
|
584
571
|
async run() {
|
|
585
|
-
|
|
572
|
+
const { closeGlobalReadline } = require('../utils/cli.js');
|
|
586
573
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
574
|
+
try {
|
|
575
|
+
await this.initialize();
|
|
576
|
+
|
|
577
|
+
if (this.languages.length === 0) {
|
|
578
|
+
console.log(this.t('fixer.noLanguages'));
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
591
581
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
582
|
+
console.log(`\n${this.t('fixer.starting', { languages: this.languages.join(', ') })}`);
|
|
583
|
+
console.log(this.t('fixer.sourceDirectory', { sourceDir: this.sourceDir }));
|
|
584
|
+
console.log(this.t('fixer.sourceLanguage', { sourceLanguage: this.config.sourceLanguage }));
|
|
585
|
+
console.log(this.t('fixer.markers', { markers: this.markers.join(', ') }));
|
|
596
586
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
587
|
+
const allIssues = [];
|
|
588
|
+
for (const lang of this.languages) {
|
|
589
|
+
console.log(this.t('fixer.scanningLanguage', { language: lang }));
|
|
590
|
+
const issues = this.scanForIssues(lang);
|
|
591
|
+
allIssues.push(...issues);
|
|
592
|
+
}
|
|
603
593
|
|
|
604
|
-
|
|
594
|
+
const report = this.generateReport(allIssues);
|
|
605
595
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
596
|
+
if (report.totalIssues === 0) {
|
|
597
|
+
console.log(`\n${this.t('fixer.allComplete')}`);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
610
600
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
601
|
+
// Generate and save report
|
|
602
|
+
const reportInfo = this.generateFixerReport(allIssues, report);
|
|
603
|
+
|
|
604
|
+
// Print limited report to console
|
|
605
|
+
this.printLimitedReport(allIssues, report);
|
|
606
|
+
|
|
607
|
+
// Non-interactive mode (for tests)
|
|
608
|
+
if (this.config.noBackup) {
|
|
609
|
+
console.log(`\n${this.t('fixer.nonInteractiveMode')}`);
|
|
610
|
+
this.languages.forEach(lang => this.processLanguage(lang));
|
|
611
|
+
console.log(this.t('fixer.fixingComplete'));
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
624
614
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const answer = await this.getUserConfirmation();
|
|
630
|
-
|
|
631
|
-
if (answer === 'y' || answer === 'yes') {
|
|
632
|
-
this.createBackup();
|
|
633
|
-
console.log(this.t('fixer.backupCreated'));
|
|
615
|
+
// Interactive mode
|
|
616
|
+
console.log(this.t('fixer.fullReportSaved', { reportPath: reportInfo.relativePath }));
|
|
617
|
+
console.log(this.t('fixer.reviewReport'));
|
|
634
618
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
619
|
+
const answer = await this.getUserConfirmation();
|
|
620
|
+
|
|
621
|
+
if (answer === 'y' || answer === 'yes') {
|
|
622
|
+
this.createBackup();
|
|
623
|
+
console.log(this.t('fixer.backupCreated'));
|
|
624
|
+
|
|
625
|
+
console.log(`\n${this.t('fixer.applyingFixes')}`);
|
|
626
|
+
this.languages.forEach(lang => this.processLanguage(lang));
|
|
627
|
+
console.log(this.t('fixer.fixingComplete'));
|
|
628
|
+
} else {
|
|
629
|
+
console.log(this.t('fixer.operationCancelled'));
|
|
630
|
+
}
|
|
631
|
+
} finally {
|
|
632
|
+
// Ensure readline is properly closed to prevent hanging
|
|
633
|
+
closeGlobalReadline();
|
|
640
634
|
}
|
|
641
635
|
}
|
|
642
636
|
}
|
|
643
637
|
|
|
644
638
|
// Run if executed directly
|
|
645
639
|
if (require.main === module) {
|
|
640
|
+
const { closeGlobalReadline } = require('../utils/cli.js');
|
|
646
641
|
const fixer = new I18nFixer();
|
|
647
642
|
fixer.run().catch(err => {
|
|
648
643
|
console.error(err.message);
|
|
649
644
|
process.exit(1);
|
|
645
|
+
}).finally(() => {
|
|
646
|
+
// Ensure readline is properly closed
|
|
647
|
+
closeGlobalReadline();
|
|
650
648
|
});
|
|
651
649
|
}
|
|
652
650
|
|
package/main/i18ntk-manage.js
CHANGED
|
@@ -649,34 +649,7 @@ class I18nManager {
|
|
|
649
649
|
const fixerTool = new I18nFixer();
|
|
650
650
|
await fixerTool.run({fromMenu: isManagerExecution});
|
|
651
651
|
break;
|
|
652
|
-
|
|
653
|
-
console.log(t('workflow.starting'));
|
|
654
|
-
const AutoRunner = require('./i18ntk-autorun');
|
|
655
|
-
const runner = new AutoRunner(this.config);
|
|
656
|
-
// Ensure autorun initializes its translations and config before running
|
|
657
|
-
await runner.init();
|
|
658
|
-
await runner.runAll(true); // Pass true for quiet mode
|
|
659
|
-
|
|
660
|
-
// Show workflow completion message and return to menu
|
|
661
|
-
console.log(t('workflow.completed'));
|
|
662
|
-
console.log(t('workflow.checkReports'));
|
|
663
|
-
|
|
664
|
-
// Check execution context for proper exit handling
|
|
665
|
-
if (isManagerExecution && !this.isNonInteractiveMode()) {
|
|
666
|
-
try {
|
|
667
|
-
await this.prompt(t('usage.pressEnterToReturnToMenu'));
|
|
668
|
-
await this.showInteractiveMenu();
|
|
669
|
-
} catch (error) {
|
|
670
|
-
// If readline fails, just exit gracefully
|
|
671
|
-
console.log(t('menu.returning'));
|
|
672
|
-
process.exit(0);
|
|
673
|
-
}
|
|
674
|
-
} else {
|
|
675
|
-
// For direct commands or workflow execution, exit gracefully
|
|
676
|
-
console.log(t('workflow.exitingCompleted'));
|
|
677
|
-
process.exit(0);
|
|
678
|
-
}
|
|
679
|
-
return;
|
|
652
|
+
|
|
680
653
|
case 'debug':
|
|
681
654
|
const debuggerTool = new I18nDebugger();
|
|
682
655
|
await debuggerTool.run();
|
|
@@ -760,20 +733,19 @@ class I18nManager {
|
|
|
760
733
|
console.log(`\n${t('menu.title')}`);
|
|
761
734
|
console.log(t('menu.separator'));
|
|
762
735
|
console.log(`1. ${t('menu.options.init')}`);
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
console.log(`0. ${t('menu.options.exit')}`);
|
|
736
|
+
console.log(`2. ${t('menu.options.analyze')}`);
|
|
737
|
+
console.log(`3. ${t('menu.options.validate')}`);
|
|
738
|
+
console.log(`4. ${t('menu.options.usage')}`);
|
|
739
|
+
console.log(`5. ${t('menu.options.complete')}`);
|
|
740
|
+
console.log(`6. ${t('menu.options.sizing')}`);
|
|
741
|
+
console.log(`7. ${t('menu.options.fix')}`);
|
|
742
|
+
console.log(`8. ${t('menu.options.status')}`);
|
|
743
|
+
console.log(`9. ${t('menu.options.delete')}`);
|
|
744
|
+
console.log(`10. ${t('menu.options.settings')}`);
|
|
745
|
+
console.log(`11. ${t('menu.options.help')}`);
|
|
746
|
+
console.log(`12. ${t('menu.options.debug')}`);
|
|
747
|
+
console.log(`13. ${t('menu.options.language')}`);
|
|
748
|
+
console.log(`0. ${t('menu.options.exit')}`);
|
|
777
749
|
console.log('\n' + t('menu.nonInteractiveModeWarning'));
|
|
778
750
|
console.log(t('menu.useDirectExecution'));
|
|
779
751
|
console.log(t('menu.useHelpForCommands'));
|
|
@@ -791,13 +763,12 @@ class I18nManager {
|
|
|
791
763
|
console.log(`5. ${t('menu.options.complete')}`);
|
|
792
764
|
console.log(`6. ${t('menu.options.sizing')}`);
|
|
793
765
|
console.log(`7. ${t('menu.options.fix')}`);
|
|
794
|
-
console.log(`8. ${t('menu.options.
|
|
795
|
-
console.log(`9. ${t('menu.options.
|
|
796
|
-
console.log(`10. ${t('menu.options.
|
|
797
|
-
console.log(`11. ${t('menu.options.
|
|
798
|
-
console.log(`12. ${t('menu.options.
|
|
799
|
-
console.log(`13. ${t('menu.options.
|
|
800
|
-
console.log(`14. ${t('menu.options.language')}`);
|
|
766
|
+
console.log(`8. ${t('menu.options.status')}`);
|
|
767
|
+
console.log(`9. ${t('menu.options.delete')}`);
|
|
768
|
+
console.log(`10. ${t('menu.options.settings')}`);
|
|
769
|
+
console.log(`11. ${t('menu.options.help')}`);
|
|
770
|
+
console.log(`12. ${t('menu.options.debug')}`);
|
|
771
|
+
console.log(`13. ${t('menu.options.language')}`);
|
|
801
772
|
console.log(`0. ${t('menu.options.exit')}`);
|
|
802
773
|
|
|
803
774
|
const choice = await this.prompt('\n' + t('menu.selectOptionPrompt'));
|
|
@@ -825,9 +796,6 @@ class I18nManager {
|
|
|
825
796
|
await this.executeCommand('fix', {fromMenu: true});
|
|
826
797
|
break;
|
|
827
798
|
case '8':
|
|
828
|
-
await this.executeCommand('workflow', {fromMenu: true});
|
|
829
|
-
break;
|
|
830
|
-
case '9':
|
|
831
799
|
// Check for PIN protection
|
|
832
800
|
const authRequired = await this.adminAuth.isAuthRequiredForScript('summaryReports');
|
|
833
801
|
if (authRequired) {
|
|
@@ -883,21 +851,21 @@ class I18nManager {
|
|
|
883
851
|
}
|
|
884
852
|
}
|
|
885
853
|
break;
|
|
886
|
-
case '
|
|
854
|
+
case '9':
|
|
887
855
|
await this.deleteReports();
|
|
888
856
|
break;
|
|
889
|
-
case '
|
|
857
|
+
case '10':
|
|
890
858
|
await this.showSettingsMenu();
|
|
891
859
|
break;
|
|
892
|
-
case '
|
|
860
|
+
case '11':
|
|
893
861
|
this.showHelp();
|
|
894
862
|
await this.prompt(t('menu.returnToMainMenu'));
|
|
895
863
|
await this.showInteractiveMenu();
|
|
896
864
|
break;
|
|
897
|
-
case '
|
|
865
|
+
case '12':
|
|
898
866
|
await this.showDebugMenu();
|
|
899
867
|
break;
|
|
900
|
-
case '
|
|
868
|
+
case '13':
|
|
901
869
|
await this.showLanguageMenu();
|
|
902
870
|
break;
|
|
903
871
|
case '0':
|
|
@@ -1367,8 +1335,8 @@ if (require.main === module) {
|
|
|
1367
1335
|
});
|
|
1368
1336
|
}
|
|
1369
1337
|
|
|
1370
|
-
console.log(`\n📖 Documentation: ${packageJson.homepage
|
|
1371
|
-
console.log(`🐛 Report Issues: ${packageJson.bugs?.url
|
|
1338
|
+
console.log(`\n📖 Documentation: ${packageJson.homepage}`);
|
|
1339
|
+
console.log(`🐛 Report Issues: ${packageJson.bugs?.url}`);
|
|
1372
1340
|
|
|
1373
1341
|
} catch (error) {
|
|
1374
1342
|
console.log(`\n❌ Version information unavailable`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18ntk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "i18ntk (i18n Toolkit) - Ultra-extreme performance enterprise-grade internationalization management toolkit with 97% performance improvement (15.38ms for 200k keys), NEW interactive translation fixer with custom placeholder markers, selective language/file fixing, mass fix capabilities, advanced security with PIN protection, comprehensive backup & recovery, **zero shell access security fixes**, and edge case handling for JavaScript/TypeScript projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"i18ntk-usage": "main/i18ntk-usage.js",
|
|
65
65
|
"i18ntk-complete": "main/i18ntk-complete.js",
|
|
66
66
|
"i18ntk-sizing": "main/i18ntk-sizing.js",
|
|
67
|
-
"i18ntk-autorun": "main/i18ntk-autorun.js",
|
|
68
67
|
"i18ntk-summary": "main/i18ntk-summary.js",
|
|
69
68
|
"i18ntk-doctor": "main/i18ntk-doctor.js",
|
|
70
69
|
"i18ntk-fixer": "main/i18ntk-fixer.js"
|
|
@@ -98,9 +97,6 @@
|
|
|
98
97
|
"i18ntk:doctor": "node main/i18ntk-doctor.js",
|
|
99
98
|
"i18ntk:summary": "node main/i18ntk-summary.js",
|
|
100
99
|
"i18ntk:manage": "node main/i18ntk-manage.js",
|
|
101
|
-
"i18n:autorun": "node main/i18ntk-autorun.js",
|
|
102
|
-
"i18ntk:autorun": "node main/i18ntk-autorun.js",
|
|
103
|
-
"workflow": "node main/i18ntk-autorun.js",
|
|
104
100
|
"init": "node main/i18ntk-init.js",
|
|
105
101
|
"analyze": "node main/i18ntk-analyze.js",
|
|
106
102
|
"validate": "node main/i18ntk-validate.js",
|
|
@@ -160,7 +156,7 @@
|
|
|
160
156
|
},
|
|
161
157
|
"preferGlobal": true,
|
|
162
158
|
"versionInfo": {
|
|
163
|
-
"version": "1.
|
|
159
|
+
"version": "1.8.0",
|
|
164
160
|
"releaseDate": "11/08/2025",
|
|
165
161
|
"lastUpdated": "11/08/2025",
|
|
166
162
|
"maintainer": "Vladimir Noskov",
|
|
@@ -168,9 +164,10 @@
|
|
|
168
164
|
"documentation": "./README.md",
|
|
169
165
|
"apiReference": "./docs/api/API_REFERENCE.md",
|
|
170
166
|
"majorChanges": [
|
|
167
|
+
"SAFER WORKFLOW: Autorun workflow removed for enhanced security and configuration protection",
|
|
171
168
|
"CRITICAL SECURITY FIXES: Zero shell access - eliminated all child_process.execSync() and spawnSync() calls",
|
|
172
169
|
"Enhanced security: Direct file system operations replacing shell commands",
|
|
173
|
-
"
|
|
170
|
+
"Enhanced Interactive Translation Fixer Tool with improved automatic detection",
|
|
174
171
|
"Mass fix capabilities for thousands of broken translations",
|
|
175
172
|
"7-language UI support for all interactive fixer operations",
|
|
176
173
|
"Ultra-extreme performance: 97% improvement - 15.38ms processing for 200k keys",
|
|
@@ -179,7 +176,9 @@
|
|
|
179
176
|
"Scalability: Linear scaling up to 5M keys with ultra-extreme settings",
|
|
180
177
|
"Fixed translation file inclusion - resolved ui-locales exclusion issue",
|
|
181
178
|
"Updated documentation - corrected package size claims and improved accuracy",
|
|
182
|
-
"Enhanced examples - added detailed use cases throughout documentation"
|
|
179
|
+
"Enhanced examples - added detailed use cases throughout documentation",
|
|
180
|
+
"FIXED: Translation fixer double enter and double readline issues",
|
|
181
|
+
"FIXED: Package URL strings - updated all repository URLs to use correct i18ntk naming"
|
|
183
182
|
],
|
|
184
183
|
"breakingChanges": [],
|
|
185
184
|
"deprecations": [
|
|
@@ -197,7 +196,9 @@
|
|
|
197
196
|
"1.7.1",
|
|
198
197
|
"1.7.2",
|
|
199
198
|
"1.7.3",
|
|
200
|
-
"1.7.4"
|
|
199
|
+
"1.7.4",
|
|
200
|
+
"1.7.5",
|
|
201
|
+
"1.7.6"
|
|
201
202
|
|
|
202
203
|
],
|
|
203
204
|
"nextVersion": "1.8.0",
|
|
@@ -193,12 +193,5 @@
|
|
|
193
193
|
"autoSave": true,
|
|
194
194
|
"dateFormat": "DD/MM/YYYY",
|
|
195
195
|
"timeFormat": "24h",
|
|
196
|
-
"timezone": "auto"
|
|
197
|
-
"sizeLimit": null,
|
|
198
|
-
"framework": {
|
|
199
|
-
"detected": false,
|
|
200
|
-
"preference": "none",
|
|
201
|
-
"prompt": "always",
|
|
202
|
-
"lastPromptedVersion": null
|
|
203
|
-
}
|
|
196
|
+
"timezone": "auto"
|
|
204
197
|
}
|
package/settings/settings-cli.js
CHANGED
|
@@ -1752,40 +1752,16 @@ class SettingsCLI {
|
|
|
1752
1752
|
console.log(`${colors.bright}${t('settings.reportBug.title')}${colors.reset}\n`);
|
|
1753
1753
|
console.log(t('settings.reportBug.description'));
|
|
1754
1754
|
console.log(`
|
|
1755
|
-
${colors.dim}${t('settings.reportBug.
|
|
1755
|
+
${colors.dim}${t('settings.reportBug.instructions')}${colors.reset}
|
|
1756
1756
|
`);
|
|
1757
|
-
|
|
1758
|
-
try {
|
|
1759
|
-
const { exec } = require('child_process');
|
|
1760
|
-
const url = 'https://github.com/vladnoskv/i18ntk/issues';
|
|
1761
|
-
|
|
1762
|
-
// Try to open the URL in the default browser
|
|
1763
|
-
let command;
|
|
1764
|
-
switch (process.platform) {
|
|
1765
|
-
case 'darwin': // macOS
|
|
1766
|
-
command = `open "${url}"`;
|
|
1767
|
-
break;
|
|
1768
|
-
case 'win32': // Windows
|
|
1769
|
-
command = `start "" "${url}"`;
|
|
1770
|
-
break;
|
|
1771
|
-
default: // Linux and others
|
|
1772
|
-
command = `xdg-open "${url}"`;
|
|
1773
|
-
break;
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
exec(command, (error) => {
|
|
1777
|
-
if (error) {
|
|
1778
|
-
console.log(`${colors.yellow}${t('settings.reportBug.browserOpenFailed')}${colors.reset}`);
|
|
1779
|
-
console.log(`${t('settings.reportBug.manualVisit', { url: url })}`);
|
|
1780
|
-
} else {
|
|
1781
|
-
console.log(`${colors.green}${t('settings.reportBug.browserOpened')}${colors.reset}`);
|
|
1782
|
-
}
|
|
1783
|
-
});
|
|
1784
|
-
} catch (error) {
|
|
1785
|
-
console.log(`${colors.yellow}${t('settings.reportBug.browserOpenFailed')}${colors.reset}`);
|
|
1786
|
-
console.log(`${t('settings.reportBug.manualVisit', { url: 'https://github.com/vladnoskv/i18ntk/issues' })}`);
|
|
1787
|
-
}
|
|
1788
1757
|
|
|
1758
|
+
// Generic bug reporting guidance without external URLs
|
|
1759
|
+
console.log(`${colors.cyan}💡 ${t('settings.reportBug.guidance')}${colors.reset}`);
|
|
1760
|
+
console.log(`${colors.dim}• ${t('settings.reportBug.checkLogs')}${colors.reset}`);
|
|
1761
|
+
console.log(`${colors.dim}• ${t('settings.reportBug.documentIssue')}${colors.reset}`);
|
|
1762
|
+
console.log(`${colors.dim}• ${t('settings.reportBug.contactSupport')}${colors.reset}`);
|
|
1763
|
+
|
|
1764
|
+
console.log(`\n${colors.green}${t('settings.reportBug.completed')}${colors.reset}`);
|
|
1789
1765
|
await this.pause();
|
|
1790
1766
|
}
|
|
1791
1767
|
|
package/ui-locales/de.json
CHANGED
|
@@ -1260,6 +1260,16 @@
|
|
|
1260
1260
|
"relativePathHint": "Verwende relative Pfade ab diesem Verzeichnis (z. B. ./locales)",
|
|
1261
1261
|
"currentDirectory": "Aktuelles Projektverzeichnis",
|
|
1262
1262
|
"pin": "PIN:",
|
|
1263
|
+
"reportBug": {
|
|
1264
|
+
"title": "Fehler melden",
|
|
1265
|
+
"description": "Melden Sie alle auftretenden Probleme oder Fehler",
|
|
1266
|
+
"guidance": "Um einen Fehler zu melden, folgen Sie bitte diesen Schritten:",
|
|
1267
|
+
"checkLogs": "1. Überprüfen Sie die letzten Debug-Logs auf Fehler",
|
|
1268
|
+
"documentIssue": "2. Dokumentieren Sie das Problem mit Reproduktionsschritten",
|
|
1269
|
+
"contactSupport": "3. Kontaktieren Sie den Support oder nutzen Sie den geeigneten Berichtskanal",
|
|
1270
|
+
"completed": "✅ Fehlerbericht-Prozess abgeschlossen",
|
|
1271
|
+
"instructions": "Folgen Sie den obigen Anweisungen, um den Fehler zu melden."
|
|
1272
|
+
},
|
|
1263
1273
|
"mainMenu": {
|
|
1264
1274
|
"title": "Hauptmenü:",
|
|
1265
1275
|
"uiSettings": "UI-Einstellungen",
|
package/ui-locales/en.json
CHANGED
|
@@ -1260,6 +1260,16 @@
|
|
|
1260
1260
|
"relativePathHint": "Use relative paths from this directory (e.g., ./src/i18n/locales)",
|
|
1261
1261
|
"currentDirectory": "Current project directory",
|
|
1262
1262
|
"pin": "PIN:",
|
|
1263
|
+
"reportBug": {
|
|
1264
|
+
"title": "Report Bug",
|
|
1265
|
+
"description": "Report any issues or bugs you encounter",
|
|
1266
|
+
"guidance": "To report issues effectively:",
|
|
1267
|
+
"checkLogs": "1. Check debug logs in your project directory",
|
|
1268
|
+
"documentIssue": "2. Document the issue with steps to reproduce",
|
|
1269
|
+
"contactSupport": "3. Contact your system administrator or support team",
|
|
1270
|
+
"completed": "Bug reporting guidance displayed",
|
|
1271
|
+
"instructions": "Follow the above instructions to report the bug."
|
|
1272
|
+
},
|
|
1263
1273
|
"mainMenu": {
|
|
1264
1274
|
"title": "Main Menu:",
|
|
1265
1275
|
"uiSettings": "UI Settings",
|
package/ui-locales/es.json
CHANGED
|
@@ -1260,6 +1260,16 @@
|
|
|
1260
1260
|
"relativePathHint": "Usa rutas relativas desde este directorio (por ejemplo, ./src/i18n/locales)",
|
|
1261
1261
|
"currentDirectory": "Directorio actual del proyecto",
|
|
1262
1262
|
"pin": "🔒 PIN:",
|
|
1263
|
+
"reportBug": {
|
|
1264
|
+
"title": "Reportar error",
|
|
1265
|
+
"description": "Reportar cualquier problema o error que encuentres",
|
|
1266
|
+
"guidance": "Para reportar problemas de forma efectiva:",
|
|
1267
|
+
"checkLogs": "1. Revisa los registros de depuración en tu directorio de proyecto",
|
|
1268
|
+
"documentIssue": "2. Documenta el problema con los pasos para reproducirlo",
|
|
1269
|
+
"contactSupport": "3. Contacta con tu administrador del sistema o equipo de soporte",
|
|
1270
|
+
"completed": "Guía de reporte de errores mostrada",
|
|
1271
|
+
"instructions": "Sigue las instrucciones para reportar el error."
|
|
1272
|
+
},
|
|
1263
1273
|
"mainMenu": {
|
|
1264
1274
|
"title": "Menú principal:",
|
|
1265
1275
|
"uiSettings": "Configuración de la interfaz",
|
|
@@ -1279,7 +1289,7 @@
|
|
|
1279
1289
|
"resetToDefaults": "Restablecer a valores predeterminados",
|
|
1280
1290
|
"resetToDefaultsDesc": "Restaurar la configuración de fábrica",
|
|
1281
1291
|
"reportBug": "Reportar error",
|
|
1282
|
-
"reportBugDesc": "Enviar
|
|
1292
|
+
"reportBugDesc": "Enviar informe de error en GitHub",
|
|
1283
1293
|
"saveChanges": "Guardar cambios",
|
|
1284
1294
|
"saveChangesDesc": "Guardar la configuración actual en un archivo",
|
|
1285
1295
|
"backupSettings": "Configuración de respaldo",
|
package/ui-locales/fr.json
CHANGED
|
@@ -1257,6 +1257,16 @@
|
|
|
1257
1257
|
"relativePathHint": "Utilisez des chemins relatifs depuis ce répertoire (ex. : ./src/i18n/locales)",
|
|
1258
1258
|
"currentDirectory": "Répertoire de projet actuel",
|
|
1259
1259
|
"pin": "PIN :",
|
|
1260
|
+
"reportBug": {
|
|
1261
|
+
"title": "Signaler un bug",
|
|
1262
|
+
"description": "Signaler tout problème ou bogue rencontré",
|
|
1263
|
+
"guidance": "Pour signaler un bogue, veuillez suivre ces étapes :",
|
|
1264
|
+
"checkLogs": "1. Vérifiez les journaux de débogage récents pour les erreurs",
|
|
1265
|
+
"documentIssue": "2. Documentez le problème avec des étapes de reproduction",
|
|
1266
|
+
"contactSupport": "3. Contactez le support ou utilisez le canal de rapport approprié",
|
|
1267
|
+
"completed": "✅ Processus de rapport de bogue terminé",
|
|
1268
|
+
"instructions": "Suivez les instructions ci-dessus pour signaler le bogue."
|
|
1269
|
+
},
|
|
1260
1270
|
"mainMenu": {
|
|
1261
1271
|
"title": "Menu principal :",
|
|
1262
1272
|
"uiSettings": "Paramètres UI",
|
|
@@ -1276,7 +1286,7 @@
|
|
|
1276
1286
|
"resetToDefaults": "Réinitialiser aux valeurs par défaut",
|
|
1277
1287
|
"resetToDefaultsDesc": "Restaurer les paramètres d’usine",
|
|
1278
1288
|
"reportBug": "Signaler un bug",
|
|
1279
|
-
"reportBugDesc": "
|
|
1289
|
+
"reportBugDesc": "Signaler tout problème ou bogue rencontré",
|
|
1280
1290
|
"backupSettings": "Paramètres de sauvegarde",
|
|
1281
1291
|
"backupSettingsDesc": "Configurer les paramètres de sauvegarde automatique pour vos fichiers de traduction",
|
|
1282
1292
|
"saveChanges": "Enregistrer les modifications",
|
package/ui-locales/ja.json
CHANGED
|
@@ -1260,6 +1260,16 @@
|
|
|
1260
1260
|
"relativePathHint": "このディレクトリからの相対パスを使用 (例: ./src/i18n/locales)",
|
|
1261
1261
|
"currentDirectory": "現在のプロジェクトディレクトリ",
|
|
1262
1262
|
"pin": "PIN:",
|
|
1263
|
+
"reportBug": {
|
|
1264
|
+
"title": "バグを報告",
|
|
1265
|
+
"description": "発生した問題やバグを報告する",
|
|
1266
|
+
"guidance": "バグを報告するには、以下の手順に従ってください:",
|
|
1267
|
+
"checkLogs": "1. 最近のデバッグログでエラーを確認する",
|
|
1268
|
+
"documentIssue": "2. 再現手順と共に問題を文書化する",
|
|
1269
|
+
"contactSupport": "3. サポートまたは適切な報告チャンネルに連絡する",
|
|
1270
|
+
"completed": "✅ バグ報告プロセスが完了しました",
|
|
1271
|
+
"instructions": "上記の手順に従ってバグを報告してください。"
|
|
1272
|
+
},
|
|
1263
1273
|
"mainMenu": {
|
|
1264
1274
|
"title": "メインメニュー:",
|
|
1265
1275
|
"uiSettings": "UI設定",
|
|
@@ -1279,7 +1289,7 @@
|
|
|
1279
1289
|
"resetToDefaults": "デフォルトにリセット",
|
|
1280
1290
|
"resetToDefaultsDesc": "工場出荷時設定に戻す",
|
|
1281
1291
|
"reportBug": "バグを報告",
|
|
1282
|
-
"reportBugDesc": "
|
|
1292
|
+
"reportBugDesc": "発生した問題やバグを報告する",
|
|
1283
1293
|
"saveChanges": "変更を保存",
|
|
1284
1294
|
"saveChangesDesc": "現在の設定をファイルに保存",
|
|
1285
1295
|
"help": "ヘルプ",
|
package/ui-locales/ru.json
CHANGED
|
@@ -1260,6 +1260,16 @@
|
|
|
1260
1260
|
"relativePathHint": "Используйте относительные пути от этой директории (например, ./src/i18n/locales)",
|
|
1261
1261
|
"currentDirectory": "Текущая директория проекта",
|
|
1262
1262
|
"pin": "PIN:",
|
|
1263
|
+
"reportBug": {
|
|
1264
|
+
"title": "Сообщить об ошибке",
|
|
1265
|
+
"description": "Сообщите о любых проблемах или ошибках, которые вы обнаружили",
|
|
1266
|
+
"guidance": "Чтобы сообщить об ошибке, выполните следующие шаги:",
|
|
1267
|
+
"checkLogs": "1. Проверьте последние журналы отладки на наличие ошибок",
|
|
1268
|
+
"documentIssue": "2. Задокументируйте проблему с шагами воспроизведения",
|
|
1269
|
+
"contactSupport": "3. Свяжитесь со службой поддержки или используйте соответствующий канал отчетности",
|
|
1270
|
+
"completed": "✅ Процесс отчета об ошибке завершен",
|
|
1271
|
+
"instructions": "Следуйте инструкциям выше, чтобы сообщить об ошибке."
|
|
1272
|
+
},
|
|
1263
1273
|
"mainMenu": {
|
|
1264
1274
|
"title": "Главное меню:",
|
|
1265
1275
|
"uiSettings": "Настройки интерфейса",
|
package/ui-locales/zh.json
CHANGED
|
@@ -1260,6 +1260,16 @@
|
|
|
1260
1260
|
"relativePathHint": "请使用相对路径(例如:./src/i18n/locales)",
|
|
1261
1261
|
"currentDirectory": "当前项目目录",
|
|
1262
1262
|
"pin": "PIN:",
|
|
1263
|
+
"reportBug": {
|
|
1264
|
+
"title": "报告错误",
|
|
1265
|
+
"description": "报告您在使用 i18n 工具包时遇到的任何问题",
|
|
1266
|
+
"guidance": "为帮助我们有效地解决问题,请提供:",
|
|
1267
|
+
"checkLogs": "• 检查最近的调试日志",
|
|
1268
|
+
"documentIssue": "• 记录问题详情和重现步骤",
|
|
1269
|
+
"contactSupport": "• 联系支持并提供相关信息",
|
|
1270
|
+
"completed": "✅ 错误报告流程已启动。请按照提供的指导操作。",
|
|
1271
|
+
"instructions": "按照上述步骤报告错误。"
|
|
1272
|
+
},
|
|
1263
1273
|
"mainMenu": {
|
|
1264
1274
|
"title": "主菜单:",
|
|
1265
1275
|
"uiSettings": "界面设置",
|
package/main/i18ntk-autorun.js
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* i18n Toolkit - Automated Workflow Runner (1.6.3-ready)
|
|
5
|
-
* Executes predefined workflow steps for i18n management.
|
|
6
|
-
* - Deterministic translation loading
|
|
7
|
-
* - Safe config precedence (defaults < constructor < unified/CLI)
|
|
8
|
-
* - Windows-safe child process execution via spawnSync
|
|
9
|
-
* - Optional step filtering via --steps=analyze,validate
|
|
10
|
-
* - Uses equals-style args (e.g., --output-dir=path) expected by sub-scripts
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const fs = require('fs');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
16
|
-
loadTranslations(process.env.I18NTK_LANG);
|
|
17
|
-
const { getUnifiedConfig, parseCommonArgs, displayHelp, ensureInitialized } = require('../utils/config-helper');
|
|
18
|
-
const SecurityUtils = require('../utils/security');
|
|
19
|
-
const configManager = require('../utils/config-manager');
|
|
20
|
-
|
|
21
|
-
// Default location for UI locale bundles (override via config.uiLocalesDir)
|
|
22
|
-
const UI_LOCALES_DIR = path.resolve(__dirname, '..', 'ui-locales');
|
|
23
|
-
|
|
24
|
-
class AutoRunner {
|
|
25
|
-
constructor(config = {}) {
|
|
26
|
-
this.CONFIG_FILE = configManager.CONFIG_PATH;
|
|
27
|
-
this.DEFAULT_CONFIG = {
|
|
28
|
-
steps: [
|
|
29
|
-
{ name: 'autorun.stepInitializeProject', script: 'i18ntk-init.js', description: 'autorun.stepInitializeProject' },
|
|
30
|
-
{ name: 'autorun.stepAnalyzeTranslations', script: 'i18ntk-analyze.js', description: 'autorun.stepAnalyzeTranslations' },
|
|
31
|
-
{ name: 'autorun.stepValidateTranslations', script: 'i18ntk-validate.js', description: 'autorun.stepValidateTranslations' },
|
|
32
|
-
{ name: 'autorun.stepCheckUsage', script: 'i18ntk-usage.js', description: 'autorun.stepCheckUsage' },
|
|
33
|
-
{ name: 'autorun.stepGenerateSummary', script: 'i18ntk-summary.js', description: 'autorun.stepGenerateSummary' }
|
|
34
|
-
]
|
|
35
|
-
};
|
|
36
|
-
// Ensure config is always initialized
|
|
37
|
-
this.config = { ...this.DEFAULT_CONFIG, ...(config || {}) };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Initialize config and translations BEFORE any output that calls t() */
|
|
41
|
-
async init(args = {}) {
|
|
42
|
-
const unified = await getUnifiedConfig('autorun', args);
|
|
43
|
-
// Precedence: defaults < constructor-provided < unified/CLI
|
|
44
|
-
this.config = { ...this.DEFAULT_CONFIG, ...this.config, ...unified };
|
|
45
|
-
|
|
46
|
-
// Support optional steps filter from CLI: --steps=analyze,validate
|
|
47
|
-
if (args && typeof args.steps === 'string') {
|
|
48
|
-
this.config.stepsFilter = args.steps
|
|
49
|
-
.split(',')
|
|
50
|
-
.map(s => s.trim())
|
|
51
|
-
.filter(Boolean);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Always use bundled UI locales directory
|
|
55
|
-
if (!fs.existsSync(UI_LOCALES_DIR)) {
|
|
56
|
-
console.warn(`[i18ntk] UI locales directory not found at: ${UI_LOCALES_DIR}`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const uiLanguage = (this.config && this.config.uiLanguage) || 'en';
|
|
60
|
-
try {
|
|
61
|
-
loadTranslations(uiLanguage);
|
|
62
|
-
} catch (e2) {
|
|
63
|
-
console.error('Error loading translations:', e2.message);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
loadConfig() {
|
|
68
|
-
try {
|
|
69
|
-
return configManager.getConfig();
|
|
70
|
-
} catch (error) {
|
|
71
|
-
console.error(this.t('autorun.configReadError', { file: this.CONFIG_FILE }) || `Failed to read config file: ${this.CONFIG_FILE}`, error.message);
|
|
72
|
-
return this.DEFAULT_CONFIG;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
t(key, params = {}) {
|
|
77
|
-
try { return t(key, params) || String(key); } catch { return String(key); }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
displayHelp() {
|
|
81
|
-
console.log(`\n${this.t('autorun.autoRunScriptTitle')}`);
|
|
82
|
-
console.log(this.t('autorun.separator'));
|
|
83
|
-
console.log(`\n${this.t('autorun.usageTitle')}:`);
|
|
84
|
-
console.log(` ${this.t('autorun.runAllSteps')}`);
|
|
85
|
-
console.log(` ${this.t('autorun.configureSettingsFirst')}`);
|
|
86
|
-
console.log(` ${this.t('autorun.runSpecificSteps')}`);
|
|
87
|
-
console.log(` ${this.t('autorun.showHelp')}`);
|
|
88
|
-
console.log(`\n${this.t('autorun.examplesTitle')}:`);
|
|
89
|
-
console.log(` ${this.t('autorun.configExample')}`);
|
|
90
|
-
console.log(` ${this.t('autorun.stepsExample1')}`);
|
|
91
|
-
console.log(` ${this.t('autorun.stepsExample2')}`);
|
|
92
|
-
console.log();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
displayConfig() {
|
|
96
|
-
console.log(`\n${this.t('autorun.customSettingsConfiguration')}`);
|
|
97
|
-
console.log(this.t('autorun.separator'));
|
|
98
|
-
const config = this.loadConfig();
|
|
99
|
-
console.log(JSON.stringify(config, null, 2));
|
|
100
|
-
console.log();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
runStep(step, stepNumber, totalSteps, commonArgs = []) {
|
|
104
|
-
const scriptPath = path.join(__dirname, step.script);
|
|
105
|
-
|
|
106
|
-
if (!fs.existsSync(scriptPath)) {
|
|
107
|
-
console.error(this.t('autorun.stepFailed', { stepName: this.t(step.description) }));
|
|
108
|
-
console.error(this.t('autorun.errorLabel', { error: this.t('autorun.missingRequiredFile', { file: step.script }) }));
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
console.log(this.t('autorun.stepRunning', { stepName: this.t(step.description), stepNumber, totalSteps }));
|
|
113
|
-
console.log(this.t('autorun.separator'));
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
// Build final argv. Use equals-style for value flags because sub-scripts expect it.
|
|
117
|
-
const argv = ['--no-prompt', ...commonArgs];
|
|
118
|
-
|
|
119
|
-
// Execute script directly as module (safe alternative to spawnSync)
|
|
120
|
-
const success = this.executeScriptAsModule(scriptPath, argv);
|
|
121
|
-
|
|
122
|
-
if (success) {
|
|
123
|
-
console.log(this.t('autorun.stepCompletedWithIcon', { stepName: this.t(step.description) }));
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
throw new Error('Script execution failed');
|
|
127
|
-
} catch (error) {
|
|
128
|
-
console.error(this.t('autorun.stepFailed', { stepName: this.t(step.description) }));
|
|
129
|
-
console.error(this.t('autorun.errorLabel', { error: error.message }));
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
_buildCommonArgs() {
|
|
135
|
-
const cfg = this.config;
|
|
136
|
-
const args = [];
|
|
137
|
-
if (cfg.sourceDir) {
|
|
138
|
-
args.push(`--source-dir=${cfg.sourceDir}`);
|
|
139
|
-
}
|
|
140
|
-
if (cfg.i18nDir) {
|
|
141
|
-
args.push(`--i18n-dir=${cfg.i18nDir}`);
|
|
142
|
-
}
|
|
143
|
-
if (cfg.outputDir) {
|
|
144
|
-
args.push(`--output-dir=${cfg.outputDir}`);
|
|
145
|
-
}
|
|
146
|
-
if (cfg.uiLanguage) {
|
|
147
|
-
args.push(`--ui-language=${cfg.uiLanguage}`);
|
|
148
|
-
}
|
|
149
|
-
return args;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
_selectStepsForRun() {
|
|
153
|
-
const all = this.config.steps || [];
|
|
154
|
-
const filter = this.config.stepsFilter;
|
|
155
|
-
if (!filter || !Array.isArray(filter) || filter.length === 0) return all;
|
|
156
|
-
|
|
157
|
-
const matchers = new Set(filter.map(s => s.toLowerCase()));
|
|
158
|
-
return all.filter(s => {
|
|
159
|
-
const tail = (s.name.split('.').pop() || '').toLowerCase();
|
|
160
|
-
return matchers.has(tail) || matchers.has(s.name.toLowerCase());
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Execute script as module (safe alternative to spawnSync)
|
|
166
|
-
*/
|
|
167
|
-
executeScriptAsModule(scriptPath, argv) {
|
|
168
|
-
try {
|
|
169
|
-
// Parse arguments to extract key-value pairs
|
|
170
|
-
const args = {};
|
|
171
|
-
for (const arg of argv) {
|
|
172
|
-
if (arg.startsWith('--')) {
|
|
173
|
-
const [key, value] = arg.substring(2).split('=');
|
|
174
|
-
if (key && value !== undefined) {
|
|
175
|
-
args[key] = value;
|
|
176
|
-
} else if (key) {
|
|
177
|
-
args[key] = true;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Map script names to their module exports
|
|
183
|
-
const scriptName = path.basename(scriptPath, '.js');
|
|
184
|
-
|
|
185
|
-
// Create a safe execution environment
|
|
186
|
-
const originalArgv = process.argv;
|
|
187
|
-
const originalExit = process.exit;
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
// Override process.argv for the script
|
|
191
|
-
process.argv = ['node', scriptPath, ...argv];
|
|
192
|
-
|
|
193
|
-
// Prevent actual exit
|
|
194
|
-
process.exit = (code = 0) => {
|
|
195
|
-
throw new Error(`Script attempted to exit with code ${code}`);
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
// Execute the script directly
|
|
199
|
-
const scriptModule = require(scriptPath);
|
|
200
|
-
|
|
201
|
-
// Check if it's a class or has a run method
|
|
202
|
-
if (scriptModule && typeof scriptModule.run === 'function') {
|
|
203
|
-
return scriptModule.run(args) !== false;
|
|
204
|
-
} else if (typeof scriptModule === 'function') {
|
|
205
|
-
return scriptModule(args) !== false;
|
|
206
|
-
} else {
|
|
207
|
-
// Execute the script's main function if it exists
|
|
208
|
-
return true; // Assume success for basic scripts
|
|
209
|
-
}
|
|
210
|
-
} finally {
|
|
211
|
-
// Restore original process methods
|
|
212
|
-
process.argv = originalArgv;
|
|
213
|
-
process.exit = originalExit;
|
|
214
|
-
|
|
215
|
-
// Remove from require cache to allow re-execution
|
|
216
|
-
delete require.cache[require.resolve(scriptPath)];
|
|
217
|
-
}
|
|
218
|
-
} catch (error) {
|
|
219
|
-
console.error(`Error executing ${path.basename(scriptPath)}: ${error.message}`);
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async runAll(quiet = false) {
|
|
225
|
-
const initialized = await ensureInitialized(this.config);
|
|
226
|
-
if (!initialized) return;
|
|
227
|
-
const stepsToRun = this._selectStepsForRun();
|
|
228
|
-
|
|
229
|
-
if (!quiet) {
|
|
230
|
-
console.log(`\n${this.t('autorun.startingAutoRunWorkflow')}`);
|
|
231
|
-
console.log(this.t('autorun.separator'));
|
|
232
|
-
console.log(`${this.t('autorun.workflowIncludesSteps', { count: stepsToRun.length })}`);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const commonArgs = this._buildCommonArgs();
|
|
236
|
-
|
|
237
|
-
let successCount = 0;
|
|
238
|
-
for (let i = 0; i < stepsToRun.length; i++) {
|
|
239
|
-
const step = stepsToRun[i];
|
|
240
|
-
const stepNumber = i + 1;
|
|
241
|
-
|
|
242
|
-
if (this.runStep(step, stepNumber, stepsToRun.length, commonArgs)) {
|
|
243
|
-
successCount++;
|
|
244
|
-
} else {
|
|
245
|
-
if (!quiet) console.error(`\n${this.t('autorun.workflowStopped')}`);
|
|
246
|
-
process.exit(1);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (!quiet) {
|
|
251
|
-
console.log(`\n${this.t('autorun.workflowCompleted')}`);
|
|
252
|
-
console.log(`${this.t('autorun.successfulSteps', { count: successCount })}`);
|
|
253
|
-
console.log(`${this.t('autorun.failedSteps', { count: stepsToRun.length - successCount })}`);
|
|
254
|
-
}
|
|
255
|
-
process.exit(0);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
async run() { await this.runAll(); }
|
|
259
|
-
|
|
260
|
-
listSteps() {
|
|
261
|
-
console.log(`\n${this.t('autorun.availableSteps')}`);
|
|
262
|
-
console.log(this.t('autorun.separator'));
|
|
263
|
-
(this.config.steps || []).forEach((step, index) => {
|
|
264
|
-
console.log(`${index + 1}. ${this.t(step.description)} (${step.script})`);
|
|
265
|
-
});
|
|
266
|
-
console.log();
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (require.main === module) {
|
|
271
|
-
(async function main() {
|
|
272
|
-
try {
|
|
273
|
-
const args = parseCommonArgs(process.argv.slice(2));
|
|
274
|
-
const runner = new AutoRunner();
|
|
275
|
-
await runner.init(args); // Initialize translations + config FIRST
|
|
276
|
-
|
|
277
|
-
if (args.help) { runner.displayHelp(); return; }
|
|
278
|
-
if (args.config) { runner.displayConfig(); return; }
|
|
279
|
-
if (args.list) { runner.listSteps(); return; }
|
|
280
|
-
|
|
281
|
-
await runner.runAll();
|
|
282
|
-
} catch (error) {
|
|
283
|
-
console.error('Error:', error.message);
|
|
284
|
-
process.exit(1);
|
|
285
|
-
}
|
|
286
|
-
})();
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
module.exports = AutoRunner;
|