i18ntk 1.0.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +401 -0
  2. package/LICENSE +21 -0
  3. package/README.md +507 -0
  4. package/dev/README.md +37 -0
  5. package/dev/debug/README.md +30 -0
  6. package/dev/debug/complete-console-translations.js +295 -0
  7. package/dev/debug/console-key-checker.js +408 -0
  8. package/dev/debug/console-translations.js +335 -0
  9. package/dev/debug/debugger.js +408 -0
  10. package/dev/debug/export-missing-keys.js +432 -0
  11. package/dev/debug/final-normalize.js +236 -0
  12. package/dev/debug/find-extra-keys.js +68 -0
  13. package/dev/debug/normalize-locales.js +153 -0
  14. package/dev/debug/refactor-locales.js +240 -0
  15. package/dev/debug/reorder-locales.js +85 -0
  16. package/dev/debug/replace-hardcoded-console.js +378 -0
  17. package/docs/INSTALLATION.md +449 -0
  18. package/docs/README.md +222 -0
  19. package/docs/TODO_ROADMAP.md +279 -0
  20. package/docs/api/API_REFERENCE.md +377 -0
  21. package/docs/api/COMPONENTS.md +492 -0
  22. package/docs/api/CONFIGURATION.md +651 -0
  23. package/docs/api/NPM_PUBLISHING_GUIDE.md +434 -0
  24. package/docs/debug/DEBUG_README.md +30 -0
  25. package/docs/debug/DEBUG_TOOLS.md +494 -0
  26. package/docs/development/AGENTS.md +351 -0
  27. package/docs/development/DEVELOPMENT_RULES.md +165 -0
  28. package/docs/development/DEV_README.md +37 -0
  29. package/docs/release-notes/RELEASE_NOTES_v1.0.0.md +173 -0
  30. package/docs/release-notes/RELEASE_NOTES_v1.6.0.md +141 -0
  31. package/docs/release-notes/RELEASE_NOTES_v1.6.1.md +185 -0
  32. package/docs/release-notes/RELEASE_NOTES_v1.6.3.md +199 -0
  33. package/docs/reports/ANALYSIS_README.md +17 -0
  34. package/docs/reports/CONSOLE_MISMATCH_BUG_REPORT_v1.5.0.md +181 -0
  35. package/docs/reports/SIZING_README.md +18 -0
  36. package/docs/reports/SUMMARY_README.md +18 -0
  37. package/docs/reports/TRANSLATION_BUG_REPORT_v1.5.0.md +129 -0
  38. package/docs/reports/USAGE_README.md +18 -0
  39. package/docs/reports/VALIDATION_README.md +18 -0
  40. package/locales/de/auth.json +3 -0
  41. package/locales/de/common.json +16 -0
  42. package/locales/de/pagination.json +6 -0
  43. package/locales/en/auth.json +3 -0
  44. package/locales/en/common.json +16 -0
  45. package/locales/en/pagination.json +6 -0
  46. package/locales/es/auth.json +3 -0
  47. package/locales/es/common.json +16 -0
  48. package/locales/es/pagination.json +6 -0
  49. package/locales/fr/auth.json +3 -0
  50. package/locales/fr/common.json +16 -0
  51. package/locales/fr/pagination.json +6 -0
  52. package/locales/ru/auth.json +3 -0
  53. package/locales/ru/common.json +16 -0
  54. package/locales/ru/pagination.json +6 -0
  55. package/main/i18ntk-analyze.js +625 -0
  56. package/main/i18ntk-autorun.js +461 -0
  57. package/main/i18ntk-complete.js +494 -0
  58. package/main/i18ntk-init.js +686 -0
  59. package/main/i18ntk-manage.js +848 -0
  60. package/main/i18ntk-sizing.js +557 -0
  61. package/main/i18ntk-summary.js +671 -0
  62. package/main/i18ntk-usage.js +1282 -0
  63. package/main/i18ntk-validate.js +762 -0
  64. package/main/ui-i18n.js +332 -0
  65. package/package.json +152 -0
  66. package/scripts/fix-missing-translation-keys.js +214 -0
  67. package/scripts/verify-package.js +168 -0
  68. package/ui-locales/de.json +637 -0
  69. package/ui-locales/en.json +688 -0
  70. package/ui-locales/es.json +637 -0
  71. package/ui-locales/fr.json +637 -0
  72. package/ui-locales/ja.json +637 -0
  73. package/ui-locales/ru.json +637 -0
  74. package/ui-locales/zh.json +637 -0
  75. package/utils/admin-auth.js +317 -0
  76. package/utils/admin-cli.js +353 -0
  77. package/utils/admin-pin.js +409 -0
  78. package/utils/detect-language-mismatches.js +454 -0
  79. package/utils/i18n-helper.js +128 -0
  80. package/utils/maintain-language-purity.js +433 -0
  81. package/utils/native-translations.js +478 -0
  82. package/utils/security.js +384 -0
  83. package/utils/test-complete-system.js +356 -0
  84. package/utils/test-console-i18n.js +402 -0
  85. package/utils/translate-mismatches.js +571 -0
  86. package/utils/validate-language-purity.js +531 -0
@@ -0,0 +1,571 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Translation Helper Tool
5
+ *
6
+ * This script helps translate English content in foreign language files
7
+ * by providing translation suggestions and batch processing capabilities.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ class TranslationHelper {
14
+ constructor() {
15
+ this.localesDir = path.join(__dirname, 'ui-locales');
16
+ this.translationMappings = {
17
+ de: {
18
+ // Common UI terms
19
+ 'Debug Tools': 'Debug-Tools',
20
+ 'Settings': 'Einstellungen',
21
+ 'Configuration': 'Konfiguration',
22
+ 'Options': 'Optionen',
23
+ 'Menu': 'Menü',
24
+ 'Back': 'Zurück',
25
+ 'Main Menu': 'Hauptmenü',
26
+ 'Back to Main Menu': 'Zurück zum Hauptmenü',
27
+ 'Invalid choice': 'Ungültige Auswahl',
28
+ 'Please select': 'Bitte wählen Sie',
29
+ 'Error': 'Fehler',
30
+ 'Warning': 'Warnung',
31
+ 'Success': 'Erfolg',
32
+ 'Failed': 'Fehlgeschlagen',
33
+ 'Loading': 'Laden',
34
+ 'Saving': 'Speichern',
35
+ 'Delete': 'Löschen',
36
+ 'Create': 'Erstellen',
37
+ 'Update': 'Aktualisieren',
38
+ 'Add': 'Hinzufügen',
39
+ 'Remove': 'Entfernen',
40
+ 'Edit': 'Bearbeiten',
41
+ 'View': 'Anzeigen',
42
+ 'Show': 'Zeigen',
43
+ 'Hide': 'Verstecken',
44
+ 'Open': 'Öffnen',
45
+ 'Close': 'Schließen',
46
+ 'Start': 'Starten',
47
+ 'Stop': 'Stoppen',
48
+ 'Run': 'Ausführen',
49
+ 'Execute': 'Ausführen',
50
+ 'Process': 'Verarbeiten',
51
+ 'Generate': 'Generieren',
52
+ 'Analysis': 'Analyse',
53
+ 'Report': 'Bericht',
54
+ 'Summary': 'Zusammenfassung',
55
+ 'Details': 'Details',
56
+ 'Tools': 'Werkzeuge',
57
+ 'Debug': 'Debug',
58
+ 'Test': 'Test',
59
+ 'Validate': 'Validieren',
60
+ 'Check': 'Prüfen',
61
+ 'Verify': 'Überprüfen',
62
+ 'Confirm': 'Bestätigen',
63
+ 'Cancel': 'Abbrechen',
64
+ 'Continue': 'Fortfahren',
65
+ 'Finish': 'Beenden',
66
+ 'Complete': 'Vollständig',
67
+ 'File': 'Datei',
68
+ 'Files': 'Dateien',
69
+ 'Found': 'Gefunden',
70
+ 'Not found': 'Nicht gefunden',
71
+ 'Available': 'Verfügbar',
72
+ 'Not available': 'Nicht verfügbar',
73
+ 'Issues found': 'Probleme gefunden',
74
+ 'No issues found': 'Keine Probleme gefunden',
75
+ 'Warnings found': 'Warnungen gefunden',
76
+
77
+ // Debug-specific terms
78
+ 'Full System Debug': 'Vollständiges System-Debug',
79
+ 'Configuration Debug': 'Konfigurations-Debug',
80
+ 'Translation Debug': 'Übersetzungs-Debug',
81
+ 'Performance Debug': 'Leistungs-Debug',
82
+
83
+ // Operations
84
+ 'INITIALIZING I18N': 'I18N INITIALISIEREN',
85
+ 'ANALYZING TRANSLATIONS': 'ÜBERSETZUNGEN ANALYSIEREN',
86
+ 'VALIDATING TRANSLATIONS': 'ÜBERSETZUNGEN VALIDIEREN',
87
+ 'ANALYZING KEY USAGE': 'SCHLÜSSEL-VERWENDUNG ANALYSIEREN',
88
+ 'COMPLETING TRANSLATIONS': 'ÜBERSETZUNGEN VERVOLLSTÄNDIGEN',
89
+ 'ANALYZING TRANSLATION SIZES': 'ÜBERSETZUNGSGRÖSSEN ANALYSIEREN',
90
+ 'RUNNING COMPREHENSIVE I18N WORKFLOW': 'UMFASSENDEN I18N-WORKFLOW AUSFÜHREN',
91
+
92
+ // Admin terms
93
+ 'Admin PIN Setup': 'Admin-PIN-Einrichtung',
94
+ 'Enter Admin PIN': 'Admin-PIN eingeben',
95
+ 'Confirm Admin PIN': 'Admin-PIN bestätigen',
96
+ 'PINs do not match': 'PINs stimmen nicht überein',
97
+ 'Authentication failed': 'Authentifizierung fehlgeschlagen',
98
+ 'Access denied': 'Zugriff verweigert',
99
+ 'Session authenticated': 'Sitzung authentifiziert',
100
+ 'Security log': 'Sicherheitsprotokoll',
101
+
102
+ // Common phrases
103
+ 'Please try again': 'Bitte versuchen Sie es erneut',
104
+ 'Would you like': 'Möchten Sie',
105
+ 'Select option': 'Option auswählen',
106
+ 'try again': 'erneut versuchen',
107
+ 'choice': 'Auswahl',
108
+ 'option': 'Option',
109
+ 'issue(s)': 'Problem(e)',
110
+ 'warning(s)': 'Warnung(en)',
111
+ 'found': 'gefunden',
112
+ 'not': 'nicht'
113
+ },
114
+
115
+ fr: {
116
+ // Common UI terms
117
+ 'Debug Tools': 'Outils de débogage',
118
+ 'Settings': 'Paramètres',
119
+ 'Configuration': 'Configuration',
120
+ 'Options': 'Options',
121
+ 'Menu': 'Menu',
122
+ 'Back': 'Retour',
123
+ 'Main Menu': 'Menu principal',
124
+ 'Back to Main Menu': 'Retour au menu principal',
125
+ 'Invalid choice': 'Choix invalide',
126
+ 'Please select': 'Veuillez sélectionner',
127
+ 'Error': 'Erreur',
128
+ 'Warning': 'Avertissement',
129
+ 'Success': 'Succès',
130
+ 'Failed': 'Échec',
131
+ 'Loading': 'Chargement',
132
+ 'Saving': 'Sauvegarde',
133
+ 'Delete': 'Supprimer',
134
+ 'Create': 'Créer',
135
+ 'Update': 'Mettre à jour',
136
+ 'Add': 'Ajouter',
137
+ 'Remove': 'Supprimer',
138
+ 'Edit': 'Modifier',
139
+ 'View': 'Voir',
140
+ 'Show': 'Afficher',
141
+ 'Hide': 'Masquer',
142
+ 'Open': 'Ouvrir',
143
+ 'Close': 'Fermer',
144
+ 'Start': 'Démarrer',
145
+ 'Stop': 'Arrêter',
146
+ 'Run': 'Exécuter',
147
+ 'Execute': 'Exécuter',
148
+ 'Process': 'Traiter',
149
+ 'Generate': 'Générer',
150
+ 'Analysis': 'Analyse',
151
+ 'Report': 'Rapport',
152
+ 'Summary': 'Résumé',
153
+ 'Details': 'Détails',
154
+ 'Tools': 'Outils',
155
+ 'Debug': 'Débogage',
156
+ 'Test': 'Test',
157
+ 'Validate': 'Valider',
158
+ 'Check': 'Vérifier',
159
+ 'Verify': 'Vérifier',
160
+ 'Confirm': 'Confirmer',
161
+ 'Cancel': 'Annuler',
162
+ 'Continue': 'Continuer',
163
+ 'Finish': 'Terminer',
164
+ 'Complete': 'Complet',
165
+ 'File': 'Fichier',
166
+ 'Files': 'Fichiers',
167
+ 'Found': 'Trouvé',
168
+ 'Not found': 'Non trouvé',
169
+ 'Available': 'Disponible',
170
+ 'Not available': 'Non disponible',
171
+ 'Issues found': 'Problèmes trouvés',
172
+ 'No issues found': 'Aucun problème trouvé',
173
+ 'Warnings found': 'Avertissements trouvés',
174
+
175
+ // Debug-specific terms
176
+ 'Full System Debug': 'Débogage système complet',
177
+ 'Configuration Debug': 'Débogage de configuration',
178
+ 'Translation Debug': 'Débogage de traduction',
179
+ 'Performance Debug': 'Débogage de performance',
180
+
181
+ // Operations
182
+ 'INITIALIZING I18N': 'INITIALISATION I18N',
183
+ 'ANALYZING TRANSLATIONS': 'ANALYSE DES TRADUCTIONS',
184
+ 'VALIDATING TRANSLATIONS': 'VALIDATION DES TRADUCTIONS',
185
+ 'ANALYZING KEY USAGE': 'ANALYSE DE L\'UTILISATION DES CLÉS',
186
+ 'COMPLETING TRANSLATIONS': 'FINALISATION DES TRADUCTIONS',
187
+ 'ANALYZING TRANSLATION SIZES': 'ANALYSE DES TAILLES DE TRADUCTION',
188
+ 'RUNNING COMPREHENSIVE I18N WORKFLOW': 'EXÉCUTION DU WORKFLOW I18N COMPLET',
189
+
190
+ // Admin terms
191
+ 'Admin PIN Setup': 'Configuration du PIN administrateur',
192
+ 'Enter Admin PIN': 'Entrer le PIN administrateur',
193
+ 'Confirm Admin PIN': 'Confirmer le PIN administrateur',
194
+ 'PINs do not match': 'Les PINs ne correspondent pas',
195
+ 'Authentication failed': 'Échec de l\'authentification',
196
+ 'Access denied': 'Accès refusé',
197
+ 'Session authenticated': 'Session authentifiée',
198
+ 'Security log': 'Journal de sécurité',
199
+
200
+ // Common phrases
201
+ 'Please try again': 'Veuillez réessayer',
202
+ 'Would you like': 'Souhaitez-vous',
203
+ 'Select option': 'Sélectionner une option',
204
+ 'try again': 'réessayer',
205
+ 'choice': 'choix',
206
+ 'option': 'option',
207
+ 'issue(s)': 'problème(s)',
208
+ 'warning(s)': 'avertissement(s)',
209
+ 'found': 'trouvé',
210
+ 'not': 'ne pas'
211
+ },
212
+
213
+ es: {
214
+ // Common UI terms
215
+ 'Debug Tools': 'Herramientas de depuración',
216
+ 'Settings': 'Configuración',
217
+ 'Configuration': 'Configuración',
218
+ 'Options': 'Opciones',
219
+ 'Menu': 'Menú',
220
+ 'Back': 'Atrás',
221
+ 'Main Menu': 'Menú principal',
222
+ 'Back to Main Menu': 'Volver al menú principal',
223
+ 'Invalid choice': 'Opción inválida',
224
+ 'Please select': 'Por favor seleccione',
225
+ 'Error': 'Error',
226
+ 'Warning': 'Advertencia',
227
+ 'Success': 'Éxito',
228
+ 'Failed': 'Falló',
229
+ 'Loading': 'Cargando',
230
+ 'Saving': 'Guardando',
231
+ 'Delete': 'Eliminar',
232
+ 'Create': 'Crear',
233
+ 'Update': 'Actualizar',
234
+ 'Add': 'Agregar',
235
+ 'Remove': 'Quitar',
236
+ 'Edit': 'Editar',
237
+ 'View': 'Ver',
238
+ 'Show': 'Mostrar',
239
+ 'Hide': 'Ocultar',
240
+ 'Open': 'Abrir',
241
+ 'Close': 'Cerrar',
242
+ 'Start': 'Iniciar',
243
+ 'Stop': 'Detener',
244
+ 'Run': 'Ejecutar',
245
+ 'Execute': 'Ejecutar',
246
+ 'Process': 'Procesar',
247
+ 'Generate': 'Generar',
248
+ 'Analysis': 'Análisis',
249
+ 'Report': 'Informe',
250
+ 'Summary': 'Resumen',
251
+ 'Details': 'Detalles',
252
+ 'Tools': 'Herramientas',
253
+ 'Debug': 'Depurar',
254
+ 'Test': 'Prueba',
255
+ 'Validate': 'Validar',
256
+ 'Check': 'Verificar',
257
+ 'Verify': 'Verificar',
258
+ 'Confirm': 'Confirmar',
259
+ 'Cancel': 'Cancelar',
260
+ 'Continue': 'Continuar',
261
+ 'Finish': 'Finalizar',
262
+ 'Complete': 'Completo',
263
+ 'File': 'Archivo',
264
+ 'Files': 'Archivos',
265
+ 'Found': 'Encontrado',
266
+ 'Not found': 'No encontrado',
267
+ 'Available': 'Disponible',
268
+ 'Not available': 'No disponible',
269
+ 'Issues found': 'Problemas encontrados',
270
+ 'No issues found': 'No se encontraron problemas',
271
+ 'Warnings found': 'Advertencias encontradas',
272
+
273
+ // Debug-specific terms
274
+ 'Full System Debug': 'Depuración completa del sistema',
275
+ 'Configuration Debug': 'Depuración de configuración',
276
+ 'Translation Debug': 'Depuración de traducción',
277
+ 'Performance Debug': 'Depuración de rendimiento',
278
+
279
+ // Operations
280
+ 'INITIALIZING I18N': 'INICIALIZANDO I18N',
281
+ 'ANALYZING TRANSLATIONS': 'ANALIZANDO TRADUCCIONES',
282
+ 'VALIDATING TRANSLATIONS': 'VALIDANDO TRADUCCIONES',
283
+ 'ANALYZING KEY USAGE': 'ANALIZANDO USO DE CLAVES',
284
+ 'COMPLETING TRANSLATIONS': 'COMPLETANDO TRADUCCIONES',
285
+ 'ANALYZING TRANSLATION SIZES': 'ANALIZANDO TAMAÑOS DE TRADUCCIÓN',
286
+ 'RUNNING COMPREHENSIVE I18N WORKFLOW': 'EJECUTANDO FLUJO DE TRABAJO I18N INTEGRAL',
287
+
288
+ // Admin terms
289
+ 'Admin PIN Setup': 'Configuración de PIN de administrador',
290
+ 'Enter Admin PIN': 'Ingrese PIN de administrador',
291
+ 'Confirm Admin PIN': 'Confirme PIN de administrador',
292
+ 'PINs do not match': 'Los PINs no coinciden',
293
+ 'Authentication failed': 'Falló la autenticación',
294
+ 'Access denied': 'Acceso denegado',
295
+ 'Session authenticated': 'Sesión autenticada',
296
+ 'Security log': 'Registro de seguridad',
297
+
298
+ // Common phrases
299
+ 'Please try again': 'Por favor intente de nuevo',
300
+ 'Would you like': '¿Le gustaría',
301
+ 'Select option': 'Seleccionar opción',
302
+ 'try again': 'intentar de nuevo',
303
+ 'choice': 'opción',
304
+ 'option': 'opción',
305
+ 'issue(s)': 'problema(s)',
306
+ 'warning(s)': 'advertencia(s)',
307
+ 'found': 'encontrado',
308
+ 'not': 'no'
309
+ }
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Translate English content in all locale files
315
+ */
316
+ async translateAll(dryRun = true) {
317
+ console.log(`🌐 Translation Helper ${dryRun ? '(DRY RUN)' : '(LIVE)'}`);
318
+ console.log('=====================================\n');
319
+
320
+ const localeFiles = this.getLocaleFiles();
321
+ let totalTranslations = 0;
322
+
323
+ for (const file of localeFiles) {
324
+ if (file.language === 'en') {
325
+ continue; // Skip source language
326
+ }
327
+
328
+ console.log(`📄 Processing ${file.language}.json...`);
329
+ const translations = await this.translateFile(file, dryRun);
330
+ totalTranslations += translations;
331
+ }
332
+
333
+ console.log(`\n📊 Translation Summary:`);
334
+ console.log(` Total translations applied: ${totalTranslations}`);
335
+
336
+ if (dryRun && totalTranslations > 0) {
337
+ console.log('\n💡 Run with --apply to apply these translations\n');
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Get all locale files
343
+ */
344
+ getLocaleFiles() {
345
+ return fs.readdirSync(this.localesDir)
346
+ .filter(file => file.endsWith('.json'))
347
+ .map(file => ({
348
+ filename: file,
349
+ language: path.basename(file, '.json'),
350
+ path: path.join(this.localesDir, file)
351
+ }));
352
+ }
353
+
354
+ /**
355
+ * Translate a single file
356
+ */
357
+ async translateFile(file, dryRun = true) {
358
+ try {
359
+ const content = fs.readFileSync(file.path, 'utf8');
360
+ let translations = JSON.parse(content);
361
+ let translationCount = 0;
362
+
363
+ const mappings = this.translationMappings[file.language];
364
+ if (!mappings) {
365
+ console.log(` ⚠️ No translation mappings available for ${file.language}`);
366
+ return 0;
367
+ }
368
+
369
+ // Apply translations
370
+ this.translateObject(translations, '', mappings, (key, oldValue, newValue) => {
371
+ if (!dryRun) {
372
+ console.log(` ✅ ${key}: "${oldValue}" → "${newValue}"`);
373
+ }
374
+ translationCount++;
375
+ });
376
+
377
+ if (translationCount > 0 && !dryRun) {
378
+ fs.writeFileSync(file.path, JSON.stringify(translations, null, 2));
379
+ console.log(` 💾 Saved ${translationCount} translations to ${file.filename}`);
380
+ } else if (translationCount > 0) {
381
+ console.log(` 🔍 Found ${translationCount} translatable items`);
382
+ } else {
383
+ console.log(` ✨ No automatic translations available`);
384
+ }
385
+
386
+ return translationCount;
387
+
388
+ } catch (error) {
389
+ console.error(` ❌ Error processing ${file.filename}: ${error.message}`);
390
+ return 0;
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Recursively translate object properties
396
+ */
397
+ translateObject(obj, keyPath, mappings, callback) {
398
+ for (const [key, value] of Object.entries(obj)) {
399
+ const currentPath = keyPath ? `${keyPath}.${key}` : key;
400
+
401
+ if (typeof value === 'string') {
402
+ const translated = this.translateString(value, mappings);
403
+ if (translated !== value) {
404
+ obj[key] = translated;
405
+ callback(currentPath, value, translated);
406
+ }
407
+ } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
408
+ this.translateObject(value, currentPath, mappings, callback);
409
+ } else if (Array.isArray(value)) {
410
+ value.forEach((item, index) => {
411
+ if (typeof item === 'string') {
412
+ const translated = this.translateString(item, mappings);
413
+ if (translated !== item) {
414
+ value[index] = translated;
415
+ callback(`${currentPath}[${index}]`, item, translated);
416
+ }
417
+ }
418
+ });
419
+ }
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Translate a single string
425
+ */
426
+ translateString(text, mappings) {
427
+ let translated = text;
428
+
429
+ // Remove [NOT TRANSLATED] markers
430
+ translated = translated.replace(/\[NOT TRANSLATED\]\s*/g, '');
431
+
432
+ // Apply direct mappings
433
+ for (const [english, foreign] of Object.entries(mappings)) {
434
+ // Case-insensitive replacement
435
+ const regex = new RegExp(english.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
436
+ translated = translated.replace(regex, foreign);
437
+ }
438
+
439
+ return translated;
440
+ }
441
+
442
+ /**
443
+ * Generate translation report
444
+ */
445
+ async generateReport() {
446
+ console.log('📊 Translation Coverage Report');
447
+ console.log('===============================\n');
448
+
449
+ const localeFiles = this.getLocaleFiles();
450
+
451
+ for (const file of localeFiles) {
452
+ if (file.language === 'en') continue;
453
+
454
+ console.log(`📄 ${file.filename}:`);
455
+
456
+ const content = fs.readFileSync(file.path, 'utf8');
457
+ const translations = JSON.parse(content);
458
+
459
+ const stats = {
460
+ total: 0,
461
+ translated: 0,
462
+ untranslated: 0,
463
+ hasEnglish: 0
464
+ };
465
+
466
+ this.analyzeTranslations(translations, stats);
467
+
468
+ const coverage = ((stats.translated / stats.total) * 100).toFixed(1);
469
+
470
+ console.log(` Total keys: ${stats.total}`);
471
+ console.log(` Translated: ${stats.translated}`);
472
+ console.log(` Untranslated markers: ${stats.untranslated}`);
473
+ console.log(` Contains English: ${stats.hasEnglish}`);
474
+ console.log(` Coverage: ${coverage}%\n`);
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Analyze translation statistics
480
+ */
481
+ analyzeTranslations(obj, stats) {
482
+ for (const [key, value] of Object.entries(obj)) {
483
+ if (typeof value === 'string') {
484
+ stats.total++;
485
+
486
+ if (value.includes('[TRANSLATE]') || value.includes('[NOT TRANSLATED]')) {
487
+ stats.untranslated++;
488
+ } else if (this.containsEnglish(value)) {
489
+ stats.hasEnglish++;
490
+ } else {
491
+ stats.translated++;
492
+ }
493
+ } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
494
+ this.analyzeTranslations(value, stats);
495
+ } else if (Array.isArray(value)) {
496
+ value.forEach(item => {
497
+ if (typeof item === 'string') {
498
+ stats.total++;
499
+
500
+ if (item.includes('[TRANSLATE]') || item.includes('[NOT TRANSLATED]')) {
501
+ stats.untranslated++;
502
+ } else if (this.containsEnglish(item)) {
503
+ stats.hasEnglish++;
504
+ } else {
505
+ stats.translated++;
506
+ }
507
+ }
508
+ });
509
+ }
510
+ }
511
+ }
512
+
513
+ /**
514
+ * Check if text contains English
515
+ */
516
+ containsEnglish(text) {
517
+ const englishWords = [
518
+ 'error', 'warning', 'success', 'failed', 'loading', 'saving',
519
+ 'debug', 'tools', 'settings', 'configuration', 'options',
520
+ 'menu', 'back', 'main', 'invalid', 'choice', 'select',
521
+ 'please', 'try', 'again', 'found', 'not', 'available'
522
+ ];
523
+
524
+ const lowerText = text.toLowerCase();
525
+ return englishWords.some(word => lowerText.includes(word));
526
+ }
527
+ }
528
+
529
+ // CLI Interface
530
+ if (require.main === module) {
531
+ const args = process.argv.slice(2);
532
+ const helper = new TranslationHelper();
533
+
534
+ if (args.includes('--help') || args.includes('-h')) {
535
+ console.log(`
536
+ Translation Helper Tool
537
+
538
+ Usage:
539
+ node translate-mismatches.js [options]
540
+
541
+ Options:
542
+ --translate Show translation preview (dry run)
543
+ --apply Apply translations (live mode)
544
+ --report Generate translation coverage report
545
+ --help, -h Show this help message
546
+
547
+ Examples:
548
+ node translate-mismatches.js --report # Show coverage report
549
+ node translate-mismatches.js --translate # Preview translations
550
+ node translate-mismatches.js --apply # Apply translations
551
+ `);
552
+ process.exit(0);
553
+ }
554
+
555
+ if (args.includes('--report')) {
556
+ helper.generateReport().catch(error => {
557
+ console.error('❌ Error:', error.message);
558
+ process.exit(1);
559
+ });
560
+ } else if (args.includes('--translate') || args.includes('--apply')) {
561
+ const dryRun = !args.includes('--apply');
562
+ helper.translateAll(dryRun).catch(error => {
563
+ console.error('❌ Error:', error.message);
564
+ process.exit(1);
565
+ });
566
+ } else {
567
+ console.log('Use --help for usage information');
568
+ }
569
+ }
570
+
571
+ module.exports = TranslationHelper;