i18ntk 1.7.2 → 1.7.4

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.
@@ -31,6 +31,7 @@ const { I18nAnalyzer } = require('./i18ntk-analyze');
31
31
  const I18nValidator = require('./i18ntk-validate');
32
32
  const I18nUsageAnalyzer = require('./i18ntk-usage');
33
33
  const I18nSizingAnalyzer = require('./i18ntk-sizing');
34
+ const I18nFixer = require('./i18ntk-fixer');
34
35
  const SettingsCLI = require('../settings/settings-cli');
35
36
  const I18nDebugger = require('../scripts/debug/debugger');
36
37
 
@@ -323,7 +324,7 @@ class I18nManager {
323
324
 
324
325
  if (!fs.existsSync(packageJsonPath)) {
325
326
  console.log(this.ui ? this.ui.t('init.noPackageJson') : 'No package.json found');
326
- return true; // Allow to continue without framework
327
+ return false; // Treat as no framework detected
327
328
  }
328
329
 
329
330
  try {
@@ -373,17 +374,12 @@ class I18nManager {
373
374
  configManager.saveConfig(cfg);
374
375
  }
375
376
  }
376
- // If framework preference is already set to 'none', skip warning
377
- if (cfg.framework === 'none' || (cfg.framework && cfg.framework.preference === 'none')) {
378
- return true;
379
- }
380
-
381
- // Framework detection is handled by maybePromptFramework, so just return true here
382
- return true;
377
+ // Always signal that frameworks were not detected
378
+ return false;
383
379
  }
384
380
  } catch (error) {
385
381
  console.log(t('init.errors.packageJsonRead'));
386
- return true; // Allow to continue on error
382
+ return false; // Treat as no framework detected on error
387
383
  }
388
384
  }
389
385
 
@@ -456,8 +452,10 @@ class I18nManager {
456
452
 
457
453
  const rl = cliHelper.getInterface();
458
454
  const cfgAfterInitCheck = await ensureInitializedOrExit(rl);
459
- await this.checkI18nDependencies();
460
- await maybePromptFramework(rl, cfgAfterInitCheck, pkg.version);
455
+ const frameworksDetected = await this.checkI18nDependencies();
456
+ if (!frameworksDetected) {
457
+ await maybePromptFramework(rl, cfgAfterInitCheck, pkg.version);
458
+ }
461
459
 
462
460
  // Update this.config with the configuration from ensureInitializedOrExit
463
461
  this.config = { ...this.config, ...cfgAfterInitCheck };
@@ -470,7 +468,7 @@ class I18nManager {
470
468
 
471
469
  // Define valid direct commands
472
470
  const directCommands = [
473
- 'init', 'analyze', 'validate', 'usage', 'sizing', 'complete', 'summary', 'debug', 'workflow'
471
+ 'init', 'analyze', 'validate', 'usage', 'sizing', 'complete', 'fix', 'summary', 'debug', 'workflow'
474
472
  ];
475
473
 
476
474
  // Handle help immediately without dependency checks
@@ -608,7 +606,7 @@ class I18nManager {
608
606
  }
609
607
 
610
608
  // Check admin authentication for all commands when PIN protection is enabled
611
- const authRequiredCommands = ['init', 'analyze', 'validate', 'usage', 'complete', 'sizing', 'workflow', 'status', 'delete', 'settings', 'debug'];
609
+ const authRequiredCommands = ['init', 'analyze', 'validate', 'usage', 'complete', 'fix', 'sizing', 'workflow', 'status', 'delete', 'settings', 'debug'];
612
610
  if (authRequiredCommands.includes(command)) {
613
611
  const authPassed = await this.checkAdminAuth();
614
612
  if (!authPassed) {
@@ -647,6 +645,10 @@ class I18nManager {
647
645
  const tool = new completeTool();
648
646
  await tool.run({fromMenu: isManagerExecution});
649
647
  break;
648
+ case 'fix':
649
+ const fixerTool = new I18nFixer();
650
+ await fixerTool.run({fromMenu: isManagerExecution});
651
+ break;
650
652
  case 'workflow':
651
653
  console.log(t('workflow.starting'));
652
654
  const AutoRunner = require('./i18ntk-autorun');
@@ -763,13 +765,14 @@ class I18nManager {
763
765
  console.log(`4. ${t('menu.options.usage')}`);
764
766
  console.log(`5. ${t('menu.options.complete')}`);
765
767
  console.log(`6. ${t('menu.options.sizing')}`);
766
- console.log(`7. ${t('menu.options.workflow')}`);
767
- console.log(`8. ${t('menu.options.status')}`);
768
- console.log(`9. ${t('menu.options.delete')}`);
769
- console.log(`10. ${t('menu.options.settings')}`);
770
- console.log(`11. ${t('menu.options.help')}`);
771
- console.log(`12. ${t('menu.options.debug')}`);
772
- console.log(`13. ${t('menu.options.language')}`);
768
+ console.log(`7. ${t('menu.options.fix')}`);
769
+ console.log(`8. ${t('menu.options.workflow')}`);
770
+ console.log(`9. ${t('menu.options.status')}`);
771
+ console.log(`10. ${t('menu.options.delete')}`);
772
+ console.log(`11. ${t('menu.options.settings')}`);
773
+ console.log(`12. ${t('menu.options.help')}`);
774
+ console.log(`13. ${t('menu.options.debug')}`);
775
+ console.log(`14. ${t('menu.options.language')}`);
773
776
  console.log(`0. ${t('menu.options.exit')}`);
774
777
  console.log('\n' + t('menu.nonInteractiveModeWarning'));
775
778
  console.log(t('menu.useDirectExecution'));
@@ -787,13 +790,14 @@ class I18nManager {
787
790
  console.log(`4. ${t('menu.options.usage')}`);
788
791
  console.log(`5. ${t('menu.options.complete')}`);
789
792
  console.log(`6. ${t('menu.options.sizing')}`);
790
- console.log(`7. ${t('menu.options.workflow')}`);
791
- console.log(`8. ${t('menu.options.status')}`);
792
- console.log(`9. ${t('menu.options.delete')}`);
793
- console.log(`10. ${t('menu.options.settings')}`);
794
- console.log(`11. ${t('menu.options.help')}`);
795
- console.log(`12. ${t('menu.options.debug')}`);
796
- console.log(`13. ${t('menu.options.language')}`);
793
+ console.log(`7. ${t('menu.options.fix')}`);
794
+ console.log(`8. ${t('menu.options.workflow')}`);
795
+ console.log(`9. ${t('menu.options.status')}`);
796
+ console.log(`10. ${t('menu.options.delete')}`);
797
+ console.log(`11. ${t('menu.options.settings')}`);
798
+ console.log(`12. ${t('menu.options.help')}`);
799
+ console.log(`13. ${t('menu.options.debug')}`);
800
+ console.log(`14. ${t('menu.options.language')}`);
797
801
  console.log(`0. ${t('menu.options.exit')}`);
798
802
 
799
803
  const choice = await this.prompt('\n' + t('menu.selectOptionPrompt'));
@@ -818,9 +822,12 @@ class I18nManager {
818
822
  await this.executeCommand('sizing', {fromMenu: true});
819
823
  break;
820
824
  case '7':
821
- await this.executeCommand('workflow', {fromMenu: true});
825
+ await this.executeCommand('fix', {fromMenu: true});
822
826
  break;
823
827
  case '8':
828
+ await this.executeCommand('workflow', {fromMenu: true});
829
+ break;
830
+ case '9':
824
831
  // Check for PIN protection
825
832
  const authRequired = await this.adminAuth.isAuthRequiredForScript('summaryReports');
826
833
  if (authRequired) {
@@ -876,21 +883,21 @@ class I18nManager {
876
883
  }
877
884
  }
878
885
  break;
879
- case '9':
886
+ case '10':
880
887
  await this.deleteReports();
881
888
  break;
882
- case '10':
889
+ case '11':
883
890
  await this.showSettingsMenu();
884
891
  break;
885
- case '11':
892
+ case '12':
886
893
  this.showHelp();
887
894
  await this.prompt(t('menu.returnToMainMenu'));
888
895
  await this.showInteractiveMenu();
889
896
  break;
890
- case '12':
897
+ case '13':
891
898
  await this.showDebugMenu();
892
899
  break;
893
- case '13':
900
+ case '14':
894
901
  await this.showLanguageMenu();
895
902
  break;
896
903
  case '0':
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  // Check for uppercase command usage and provide helpful error
4
4
  const commandLine = process.argv.join(' ');
@@ -322,7 +322,8 @@ class I18nValidator {
322
322
  } else if (typeof value === 'string') {
323
323
  totalKeys++;
324
324
 
325
- if (value === this.config.notTranslatedMarker) {
325
+ const markers = this.config.notTranslatedMarkers || [this.config.notTranslatedMarker];
326
+ if (markers.some(m => value === m)) {
326
327
  issues.push({
327
328
  type: 'not_translated',
328
329
  key: fullKey,
@@ -338,7 +339,7 @@ class I18nValidator {
338
339
  language,
339
340
  fileName
340
341
  });
341
- } else if (value.includes(this.config.notTranslatedMarker)) {
342
+ } else if (markers.some(m => value.includes(m))) {
342
343
  issues.push({
343
344
  type: 'partial_translation',
344
345
  key: fullKey,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "1.7.2",
4
- "description": "i18ntk (i18n Toolkit) - Ultra-extreme performance enterprise-grade internationalization management toolkit with 97% performance improvement (15.38ms for 200k keys), advanced security with PIN protection, comprehensive backup & recovery, and edge case handling for JavaScript/TypeScript projects",
3
+ "version": "1.7.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, and edge case handling for JavaScript/TypeScript projects",
5
5
  "keywords": [
6
6
  "i18n",
7
7
  "internationalization",
@@ -62,7 +62,8 @@
62
62
  "i18ntk-sizing": "main/i18ntk-sizing.js",
63
63
  "i18ntk-autorun": "main/i18ntk-autorun.js",
64
64
  "i18ntk-summary": "main/i18ntk-summary.js",
65
- "i18ntk-doctor": "main/i18ntk-doctor.js"
65
+ "i18ntk-doctor": "main/i18ntk-doctor.js",
66
+ "i18ntk-fixer": "main/i18ntk-fixer.js"
66
67
  },
67
68
  "directories": {
68
69
  "doc": "docs",
@@ -86,6 +87,7 @@
86
87
  "i18ntk:validate": "main/i18ntk-validate.js",
87
88
  "i18ntk:usage": "node main/i18ntk-usage.js",
88
89
  "i18ntk:complete": "node main/i18ntk-complete.js",
90
+ "i18ntk:fix": "node main/i18ntk-fixer.js",
89
91
  "i18ntk-sizing": "main/i18ntk-sizing.js",
90
92
  "start": "node main/i18ntk-manage.js",
91
93
  "settings": "node settings/settings-cli.js",
@@ -100,6 +102,7 @@
100
102
  "validate": "node main/i18ntk-validate.js",
101
103
  "usage": "node main/i18ntk-usage.js",
102
104
  "complete": "node main/i18ntk-complete.js",
105
+ "fix": "node main/i18ntk-fixer.js",
103
106
  "sizing": "node main/i18ntk-sizing.js",
104
107
  "summary": "node main/i18ntk-summary.js",
105
108
  "full-coverage": "npm run complete && npm run analyze",
@@ -144,14 +147,18 @@
144
147
  },
145
148
  "preferGlobal": true,
146
149
  "versionInfo": {
147
- "version": "1.7.2",
148
- "releaseDate": "27/07/2025",
149
- "lastUpdated": "10/08/2025",
150
+ "version": "1.7.4",
151
+ "releaseDate": "12/08/2025",
152
+ "lastUpdated": "12/08/2025",
150
153
  "maintainer": "Vladimir Noskov",
151
154
  "changelog": "./CHANGELOG.md",
152
155
  "documentation": "./README.md",
153
156
  "apiReference": "./docs/api/API_REFERENCE.md",
154
157
  "majorChanges": [
158
+ "NEW Interactive Translation Fixer Tool with custom placeholder markers and selective language/file fixing",
159
+ "Mass fix capabilities for thousands of broken translations",
160
+ "8-language UI support for all interactive fixer operations",
161
+ "Ultra-extreme performance: 97% improvement - 15.38ms processing for 200k keys",
155
162
  "Ultra-extreme performance: 97% improvement - 15.38ms processing for 200k keys",
156
163
  "Enhanced security: Advanced PIN protection with exponential backoff",
157
164
  "Edge case handling: Robust handling of corrupt files, encoding issues, and network failures",
@@ -0,0 +1,90 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const assert = require('assert');
5
+ const I18nFixer = require('../main/i18ntk-fixer.js');
6
+
7
+ async function testEnhancedFixer() {
8
+ // Create temporary directory for test
9
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'i18ntk-test-'));
10
+ const locales = path.join(tmp, 'locales');
11
+
12
+ fs.mkdirSync(path.join(locales, 'en'), { recursive: true });
13
+ fs.mkdirSync(path.join(locales, 'fr'), { recursive: true });
14
+
15
+ // Create source files
16
+ fs.writeFileSync(path.join(locales, 'en', 'common.json'), JSON.stringify({
17
+ admin: 'Admin',
18
+ prev: 'Previous',
19
+ page: 'Page',
20
+ next: 'Next',
21
+ missing: 'Missing'
22
+ }, null, 2));
23
+
24
+ fs.writeFileSync(path.join(locales, 'fr', 'common.json'), JSON.stringify({
25
+ admin: 'Administrateur',
26
+ prev: '__NOT_TRANSLATED__',
27
+ page: '[FR] Old',
28
+ next: '__NOT_TRANSLATED__'
29
+ }, null, 2));
30
+
31
+ console.log('Test setup complete. Files:');
32
+ console.log('EN:', fs.readFileSync(path.join(locales, 'en', 'common.json'), 'utf8'));
33
+ console.log('FR:', fs.readFileSync(path.join(locales, 'fr', 'common.json'), 'utf8'));
34
+
35
+ // Create fixer instance and configure directly
36
+ const fixer = new I18nFixer();
37
+
38
+ // Configure the fixer with proper absolute paths
39
+ await fixer.initialize();
40
+ fixer.sourceDir = locales;
41
+ fixer.sourceLanguageDir = path.join(locales, 'en');
42
+ fixer.languages = ['fr'];
43
+ fixer.markers = ['__NOT_TRANSLATED__', '[FR]'];
44
+ fixer.config = {
45
+ ...fixer.config,
46
+ sourceLanguage: 'en',
47
+ noBackup: true,
48
+ languages: ['fr']
49
+ };
50
+
51
+ // Test scanning functionality
52
+ console.log('\n🔍 Testing scanning functionality...');
53
+ const issues = fixer.scanForIssues('fr');
54
+ console.log(`Found ${issues.length} issues:`);
55
+ issues.forEach(issue => {
56
+ console.log(`- ${issue.type}: ${issue.path} = "${issue.targetValue}" → "${issue.newValue}"`);
57
+ });
58
+
59
+ // Apply fixes directly without calling run() which would re-initialize
60
+ console.log('\n🚀 Applying fixes directly...');
61
+ fixer.languages.forEach(lang => fixer.processLanguage(lang));
62
+ console.log('✅ Fixes applied successfully!');
63
+
64
+ console.log('After fix:');
65
+ console.log('FR:', fs.readFileSync(path.join(locales, 'fr', 'common.json'), 'utf8'));
66
+
67
+ // Verify the fixes
68
+ const frContent = JSON.parse(fs.readFileSync(path.join(locales, 'fr', 'common.json'), 'utf8'));
69
+
70
+ assert.strictEqual(frContent.prev, '[FR] Previous', 'prev should be fixed');
71
+ assert.strictEqual(frContent.page, '[FR] Page', 'page should be fixed');
72
+ assert.strictEqual(frContent.next, '[FR] Next', 'next should be fixed');
73
+
74
+ console.log('✅ All assertions passed!');
75
+
76
+ // Test backup functionality
77
+ console.log('\n📁 Testing backup functionality...');
78
+ fixer.config.noBackup = false;
79
+ await fixer.run();
80
+
81
+ // Clean up
82
+ fs.rmSync(tmp, { recursive: true, force: true });
83
+ console.log('🧹 Test completed successfully!');
84
+ }
85
+
86
+ if (require.main === module) {
87
+ testEnhancedFixer().catch(console.error);
88
+ }
89
+
90
+ module.exports = testEnhancedFixer;
@@ -18,7 +18,8 @@ class TestRunner {
18
18
  { name: 'System Tests', script: 'dev/tests/test-complete-system.js' },
19
19
  { name: 'Console i18n Tests', script: 'dev/tests/test-console-i18n.js' },
20
20
  { name: 'Security i18n Tests', script: 'dev/tests/test-security-i18n.js' },
21
- { name: 'Translation Validation', script: 'scripts/validate-all-translations.js' }
21
+ { name: 'Translation Validation', script: 'scripts/validate-all-translations.js' },
22
+ { name: 'Translation Fixer Tests', script: 'scripts/fixer.test.js' }
22
23
  ];
23
24
  this.results = [];
24
25
  this.startTime = new Date();
@@ -193,5 +193,12 @@
193
193
  "autoSave": true,
194
194
  "dateFormat": "DD/MM/YYYY",
195
195
  "timeFormat": "24h",
196
- "timezone": "auto"
196
+ "timezone": "auto",
197
+ "sizeLimit": null,
198
+ "framework": {
199
+ "detected": false,
200
+ "preference": "none",
201
+ "prompt": "always",
202
+ "lastPromptedVersion": null
203
+ }
197
204
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "initialized": true,
3
- "version": "1.7.1",
4
- "timestamp": "2024-12-19T10:30:00.000Z",
5
- "sourceDir": "./locales",
3
+ "version": "1.7.2",
4
+ "timestamp": "2025-08-10T23:59:22.694Z",
5
+ "sourceDir": "E:\\i18n-management-toolkit-main\\i18ntk-1.7.0\\locales",
6
6
  "sourceLanguage": "en"
7
7
  }
@@ -94,6 +94,71 @@
94
94
  "settings": "Einstellungen",
95
95
  "confirm": "Bestätigen"
96
96
  },
97
+ "fixer": {
98
+ "help_message": "\nI18n Übersetzungs-Fixer\n\nVerwendung: node i18ntk-fixer.js [optionen]\n\nOptionen:\n --source-dir <dir> Quellverzeichnis zu analysieren (Standard: ./locales)\n --languages <langs> Komma-getrennte Liste der zu korrigierenden Sprachen\n --markers <markers> Komma-getrennte Liste der als nicht übersetzt zu behandelnden Markierungen\n --no-backup Automatische Backup-Erstellung überspringen\n --help Diese Hilfe anzeigen\n\nBeispiele:\n node i18ntk-fixer.js --languages de,fr\n node i18ntk-fixer.js --source-dir=./locales --markers NOT_TRANSLATED\n node i18ntk-fixer.js --no-backup\n",
99
+ "starting": "🚀 Starte Übersetzungskorrektur für Sprachen: {languages}",
100
+ "sourceDirectory": "📁 Quellverzeichnis: {sourceDir}",
101
+ "sourceLanguage": "🔤 Quellsprache: {sourceLanguage}",
102
+ "markers": "🏷️ Zu korrigierende Markierungen: {markers}",
103
+ "scanningLanguage": "📊 Analysiere {language}...",
104
+ "noLanguages": "❌ Keine Sprachen für Korrektur angegeben.",
105
+ "allComplete": "🎉 Alle Übersetzungen sind bereits vollständig!",
106
+ "fullReportSaved": "📊 Vollständiger Bericht gespeichert in: {reportPath}",
107
+ "reviewReport": "Bitte überprüfen Sie den Bericht, bevor Sie fortfahren.",
108
+ "backupCreated": "💾 Backup erfolgreich erstellt.",
109
+ "applyingFixes": "🔄 Wende Korrekturen an...",
110
+ "fixingComplete": "✅ Übersetzungskorrektur abgeschlossen!",
111
+ "operationCancelled": "❌ Vorgang vom Benutzer abgebrochen.",
112
+ "analysisTitle": "🔍 ÜBERSETZUNGSKORREKTUR-ANALYSE",
113
+ "analysisSeparator": "==================================================",
114
+ "totalIssues": "Gefundene Probleme gesamt: {totalIssues}",
115
+ "missingTranslations": "Fehlende Übersetzungen: {missing}",
116
+ "placeholderTranslations": "Übersetzungen mit Markierungen: {placeholder}",
117
+ "noIssues": "✅ Keine Probleme gefunden. Alle Übersetzungen sind vollständig.",
118
+ "detailedIssues": "📋 DETAillierte PROBLEME:",
119
+ "detailedSeparator": "--------------------------------------------------",
120
+ "filePath": "📄 {file} → {path}",
121
+ "missingKey": "❌ FEHLT: {source} → {new}",
122
+ "placeholderKey": "⚠️ MARKIERUNG: \"{target}\" → \"{new}\"",
123
+ "moreIssues": "... und {count} weitere Probleme. Siehe Berichtsdatei für vollständige Details.",
124
+ "confirmationTitle": "🤔 Möchten Sie mit diesen Korrekturen fortfahren?",
125
+ "confirmationOptions": "Optionen:",
126
+ "optionYes": "j - Ja, alle Korrekturen anwenden",
127
+ "optionNo": "n - Nein, Vorgang abbrechen",
128
+ "optionShow": "d - Detaillierte Probleme anzeigen",
129
+ "choicePrompt": "Ihre Wahl (j/n/d): ",
130
+ "nonInteractiveMode": "⚡ Nicht-interaktiver Modus erkannt - wende Korrekturen automatisch an...",
131
+ "reportGenerated": "📊 Korrekturbericht generiert: {path}",
132
+ "summary": {
133
+ "totalIssues": "Gesamtprobleme: {total}",
134
+ "missingKeys": "Fehlende Schlüssel: {missing}",
135
+ "placeholderKeys": "Schlüssel mit Markern: {placeholder}",
136
+ "languages": "Sprachen: {languages}"
137
+ },
138
+ "welcome": {
139
+ "title": "🎯 Willkommen beim Übersetzungs-Fixer!",
140
+ "description": "Dieses Tool hilft Ihnen, beschädigte Übersetzungen und Markierungen in Ihren Sprachdateien zu reparieren."
141
+ },
142
+ "markerPrompt": {
143
+ "title": "🏷️ Platzhalter-Markierungen konfigurieren",
144
+ "description": "Geben Sie die Markierungen ein, die nicht übersetzten Text anzeigen (durch Kommas getrennt):",
145
+ "currentDefaults": "Standardmarkierungen: {markers}",
146
+ "input": "Markierungen (oder Enter für Standardwerte): "
147
+ },
148
+ "languagePrompt": {
149
+ "title": "🌍 Sprachen zur Reparatur auswählen",
150
+ "available": "Verfügbare Sprachen: {languages}",
151
+ "description": "Geben Sie die zu reparierenden Sprachen ein (durch Kommas getrennt) oder Enter für alle:",
152
+ "input": "Sprachen: ",
153
+ "noLanguages": "Keine Sprachen zur Reparatur gefunden."
154
+ },
155
+ "directoryPrompt": {
156
+ "title": "📁 Verzeichnis auswählen",
157
+ "current": "Aktuelles Verzeichnis: {dir}",
158
+ "description": "Geben Sie das Verzeichnis mit Ihren Sprachdateien ein (oder Enter für aktuelles Verzeichnis):",
159
+ "input": "Verzeichnis: "
160
+ }
161
+ },
97
162
  "autorun": {
98
163
  "stepAnalyzeTranslations": "Übersetzungen analysieren",
99
164
  "stepCompletedWithIcon": "✅ Schritt '{stepName}' abgeschlossen.",
@@ -950,6 +1015,7 @@
950
1015
  "usage": "📊 Schlüsselverwendung prüfen",
951
1016
  "complete": "🎯 Übersetzungen vervollständigen (100% Abdeckung)",
952
1017
  "sizing": "📏 Größenanalyse",
1018
+ "fix": "🛠️ Platzhalterübersetzungen reparieren",
953
1019
  "workflow": "🔄 Gesamten Workflow ausführen",
954
1020
  "status": "📋 Projektstatus anzeigen",
955
1021
  "delete": "🗑️ Alle Berichte löschen",
@@ -961,7 +1027,7 @@
961
1027
  },
962
1028
  "update": "📦 Paket aktualisieren",
963
1029
  "goodbye": "👋 Auf Wiedersehen!",
964
- "invalidChoice": "❌ Ungültige Auswahl. Bitte wähle 0–13.",
1030
+ "invalidChoice": "❌ Ungültige Auswahl. Bitte wähle 0–14.",
965
1031
  "returning": "🔄 Zurück zum Hauptmenü...",
966
1032
  "invalidOption": "❌ Ungültige Option. Bitte erneut versuchen.",
967
1033
  "nonInteractiveModeWarning": "⚠️ Nicht-interaktiver Modus erkannt. Menü dient nur zur Referenz.",
@@ -94,6 +94,71 @@
94
94
  "settings": "Settings",
95
95
  "confirm": "Confirm"
96
96
  },
97
+ "fixer": {
98
+ "help_message": "\nI18n Translation Fixer\n\nUsage: node i18ntk-fixer.js [options]\n\nOptions:\n --source-dir <dir> Source directory to scan (default: ./locales)\n --languages <langs> Comma separated list of languages to fix\n --markers <markers> Comma separated markers to treat as untranslated\n --no-backup Skip automatic backup creation\n --help Show this help\n\nExamples:\n node i18ntk-fixer.js --languages de,fr\n node i18ntk-fixer.js --source-dir=./locales --markers NOT_TRANSLATED\n node i18ntk-fixer.js --no-backup\n",
99
+ "starting": "🚀 Starting translation fixing for languages: {languages}",
100
+ "sourceDirectory": "📁 Source directory: {sourceDir}",
101
+ "sourceLanguage": "🔤 Source language: {sourceLanguage}",
102
+ "markers": "🏷️ Markers to fix: {markers}",
103
+ "scanningLanguage": "📊 Scanning {language}...",
104
+ "noLanguages": "❌ No languages specified for fixing.",
105
+ "allComplete": "🎉 All translations are already complete!",
106
+ "fullReportSaved": "📊 Full report saved to: {reportPath}",
107
+ "reviewReport": "Please review the report before proceeding.",
108
+ "backupCreated": "💾 Backup created successfully.",
109
+ "applyingFixes": "🔄 Applying fixes...",
110
+ "fixingComplete": "✅ Translation fixing complete!",
111
+ "operationCancelled": "❌ Operation cancelled by user.",
112
+ "analysisTitle": "🔍 TRANSLATION FIXING ANALYSIS",
113
+ "analysisSeparator": "==================================================",
114
+ "totalIssues": "Total issues found: {totalIssues}",
115
+ "missingTranslations": "Missing translations: {missing}",
116
+ "placeholderTranslations": "Placeholder translations: {placeholder}",
117
+ "noIssues": "✅ No issues found. All translations are complete.",
118
+ "detailedIssues": "📋 DETAILED ISSUES:",
119
+ "detailedSeparator": "--------------------------------------------------",
120
+ "filePath": "📄 {file} → {path}",
121
+ "missingKey": "❌ MISSING: {source} → {new}",
122
+ "placeholderKey": "⚠️ PLACEHOLDER: \"{target}\" → \"{new}\"",
123
+ "moreIssues": "... and {count} more issues. Check the report file for complete details.",
124
+ "confirmationTitle": "🤔 Do you want to proceed with these fixes?",
125
+ "confirmationOptions": "Options:",
126
+ "optionYes": "y - Yes, apply all fixes",
127
+ "optionNo": "n - No, cancel operation",
128
+ "optionShow": "s - Show detailed issues",
129
+ "choicePrompt": "Your choice (y/n/s): ",
130
+ "nonInteractiveMode": "⚡ Non-interactive mode detected - applying fixes automatically...",
131
+ "reportGenerated": "📊 Fixer report generated: {path}",
132
+ "summary": {
133
+ "totalIssues": "Total issues: {total}",
134
+ "missingKeys": "Missing keys: {missing}",
135
+ "placeholderKeys": "Placeholder keys: {placeholder}",
136
+ "languages": "Languages: {languages}"
137
+ },
138
+ "welcome": {
139
+ "title": "🎯 Welcome to the Translation Fixer!",
140
+ "description": "This tool will help you fix broken translations and placeholders across your locale files."
141
+ },
142
+ "markerPrompt": {
143
+ "title": "🏷️ Configure Placeholder Markers",
144
+ "description": "Enter the markers that indicate untranslated text (comma-separated):",
145
+ "currentDefaults": "Default markers: {markers}",
146
+ "input": "Markers (or press Enter for defaults): "
147
+ },
148
+ "languagePrompt": {
149
+ "title": "🌍 Select Languages to Fix",
150
+ "available": "Available languages: {languages}",
151
+ "description": "Enter languages to fix (comma-separated) or press Enter for all:",
152
+ "input": "Languages: ",
153
+ "noLanguages": "No languages found to fix."
154
+ },
155
+ "directoryPrompt": {
156
+ "title": "📁 Select Directory",
157
+ "current": "Current directory: {dir}",
158
+ "description": "Enter the directory containing your locale files (or press Enter for current):",
159
+ "input": "Directory: "
160
+ }
161
+ },
97
162
  "autorun": {
98
163
  "stepAnalyzeTranslations": "Analyze translations",
99
164
  "stepCompletedWithIcon": "✅ Completed: {stepName}",
@@ -950,6 +1015,7 @@
950
1015
  "usage": "📊 Check key usage",
951
1016
  "complete": "🎯 Complete translations (100% coverage)",
952
1017
  "sizing": "📏 Analyze sizing",
1018
+ "fix": "🛠️ Fix placeholder translations",
953
1019
  "workflow": "🔄 Run full workflow",
954
1020
  "status": "📋 Show project status",
955
1021
  "delete": "🗑️ Delete all reports",
@@ -961,7 +1027,7 @@
961
1027
  },
962
1028
  "update": "📦 Update Package",
963
1029
  "goodbye": "👋 Goodbye!",
964
- "invalidChoice": "❌ Invalid choice. Please select 0-13.",
1030
+ "invalidChoice": "❌ Invalid choice. Please select 0-14.",
965
1031
  "returning": "🔄 Returning to main menu...",
966
1032
  "invalidOption": "❌ Invalid option. Please try again.",
967
1033
  "nonInteractiveModeWarning": "⚠️ Non-interactive mode detected. Menu displayed for reference only.",
@@ -94,6 +94,71 @@
94
94
  "settings": "Configuración",
95
95
  "confirm": "Confirmar"
96
96
  },
97
+ "fixer": {
98
+ "help_message": "\nCorrector de Traducción I18n\n\nUso: node i18ntk-fixer.js [opciones]\n\nOpciones:\n --source-dir <dir> Directorio fuente para escanear (predeterminado: ./locales)\n --languages <langs> Lista separada por comas de idiomas a corregir\n --markers <markers> Lista separada por comas de marcadores a tratar como sin traducir\n --no-backup Omitir creación de respaldo automático\n --help Mostrar esta ayuda\n\nEjemplos:\n node i18ntk-fixer.js --languages de,fr\n node i18ntk-fixer.js --source-dir=./locales --markers NOT_TRANSLATED\n node i18ntk-fixer.js --no-backup\n",
99
+ "starting": "🚀 Iniciando corrección de traducción para idiomas: {languages}",
100
+ "sourceDirectory": "📁 Directorio fuente: {sourceDir}",
101
+ "sourceLanguage": "🔤 Idioma fuente: {sourceLanguage}",
102
+ "markers": "🏷️ Marcadores a corregir: {markers}",
103
+ "scanningLanguage": "📊 Escaneando {language}...",
104
+ "noLanguages": "❌ No se especificaron idiomas para corregir.",
105
+ "allComplete": "🎉 ¡Todas las traducciones ya están completas!",
106
+ "fullReportSaved": "📊 Informe completo guardado en: {reportPath}",
107
+ "reviewReport": "Por favor revise el informe antes de proceder.",
108
+ "backupCreated": "💾 Respaldo creado exitosamente.",
109
+ "applyingFixes": "🔄 Aplicando correcciones...",
110
+ "fixingComplete": "✅ ¡Corrección de traducción completada!",
111
+ "operationCancelled": "❌ Operación cancelada por el usuario.",
112
+ "analysisTitle": "🔍 ANÁLISIS DE CORRECCIÓN DE TRADUCCIÓN",
113
+ "analysisSeparator": "==================================================",
114
+ "totalIssues": "Total de problemas encontrados: {totalIssues}",
115
+ "missingTranslations": "Traducciones faltantes: {missing}",
116
+ "placeholderTranslations": "Traducciones con marcadores: {placeholder}",
117
+ "noIssues": "✅ No se encontraron problemas. Todas las traducciones están completas.",
118
+ "detailedIssues": "📋 PROBLEMAS DETALLADOS:",
119
+ "detailedSeparator": "--------------------------------------------------",
120
+ "filePath": "📄 {file} → {path}",
121
+ "missingKey": "❌ FALTANTE: {source} → {new}",
122
+ "placeholderKey": "⚠️ MARCADOR: \"{target}\" → \"{new}\"",
123
+ "moreIssues": "... y {count} problemas más. Consulte el archivo de informe para detalles completos.",
124
+ "confirmationTitle": "🤔 ¿Desea proceder con estas correcciones?",
125
+ "confirmationOptions": "Opciones:",
126
+ "optionYes": "s - Sí, aplicar todas las correcciones",
127
+ "optionNo": "n - No, cancelar operación",
128
+ "optionShow": "m - Mostrar problemas detallados",
129
+ "choicePrompt": "Su elección (s/n/m): ",
130
+ "nonInteractiveMode": "⚡ Modo no interactivo detectado - aplicando correcciones automáticamente...",
131
+ "reportGenerated": "📊 Informe de corrección generado: {path}",
132
+ "summary": {
133
+ "totalIssues": "Total de problemas: {total}",
134
+ "missingKeys": "Claves faltantes: {missing}",
135
+ "placeholderKeys": "Claves con marcadores: {placeholder}",
136
+ "languages": "Idiomas: {languages}"
137
+ },
138
+ "welcome": {
139
+ "title": "🎯 ¡Bienvenido al Arreglador de Traducciones!",
140
+ "description": "Esta herramienta te ayudará a corregir traducciones rotas y marcadores en tus archivos de idiomas."
141
+ },
142
+ "markerPrompt": {
143
+ "title": "🏷️ Configurar Marcadores de Placeholder",
144
+ "description": "Ingresa los marcadores que indican texto sin traducir (separados por comas):",
145
+ "currentDefaults": "Marcadores predeterminados: {markers}",
146
+ "input": "Marcadores (o presiona Enter para usar predeterminados): "
147
+ },
148
+ "languagePrompt": {
149
+ "title": "🌍 Seleccionar Idiomas para Corregir",
150
+ "available": "Idiomas disponibles: {languages}",
151
+ "description": "Ingresa los idiomas a corregir (separados por comas) o presiona Enter para todos:",
152
+ "input": "Idiomas: ",
153
+ "noLanguages": "No se encontraron idiomas para corregir."
154
+ },
155
+ "directoryPrompt": {
156
+ "title": "📁 Seleccionar Directorio",
157
+ "current": "Directorio actual: {dir}",
158
+ "description": "Ingresa el directorio que contiene tus archivos de idiomas (o presiona Enter para el actual):",
159
+ "input": "Directorio: "
160
+ }
161
+ },
97
162
  "autorun": {
98
163
  "stepAnalyzeTranslations": "Analizar archivos de traducción",
99
164
  "stepCompletedWithIcon": "{icon} Paso '{stepName}' completado.",
@@ -950,6 +1015,7 @@
950
1015
  "usage": "📊 Comprobar uso de claves",
951
1016
  "complete": "🎯 Completar traducciones (100% cobertura)",
952
1017
  "sizing": "📏 Analizar tamaños",
1018
+ "fix": "🛠️ Corregir traducciones de marcador",
953
1019
  "workflow": "🔄 Ejecutar flujo completo",
954
1020
  "status": "📋 Mostrar estado del proyecto",
955
1021
  "delete": "🗑️ Eliminar todos los informes",
@@ -961,7 +1027,7 @@
961
1027
  },
962
1028
  "update": "📦 Actualizar paquete",
963
1029
  "goodbye": "👋 ¡Hasta luego!",
964
- "invalidChoice": "❌ Opción inválida. Por favor selecciona entre 0-13.",
1030
+ "invalidChoice": "❌ Opción inválida. Por favor selecciona entre 0-14.",
965
1031
  "returning": "🔄 Volviendo al menú principal...",
966
1032
  "invalidOption": "❌ Opción inválida. Inténtalo de nuevo.",
967
1033
  "nonInteractiveModeWarning": "⚠️ Modo no interactivo detectado. Menú mostrado solo como referencia.",