import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const FR_DIR = path.join(__dirname, 'scripts'); const ENGLISH_TEXTS_FILE = path.join(__dirname, 'english-texts-found.json'); const FR_JSON_FILE = path.join(__dirname, 'fr.json'); // Charger les données const englishTexts = JSON.parse(fs.readFileSync(ENGLISH_TEXTS_FILE, 'utf8')); const frJson = JSON.parse(fs.readFileSync(FR_JSON_FILE, 'utf8')); // Créer un mapping de traductions basé sur fr.json et les patterns connus const translations = { // Patterns déjà traduits dans le système "Choose Training": "Choisir un Entraînement", "Lore (Magic)": "Savoir (Magie)", "Dark Magic (Necromancy)": "Magie Noire (Nécromancie)", "Lore (Theology)": "Savoir (Théologie)", "Lore (Runes)": "Savoir (Runes)", "Sail (Skycraft)": "Voile (Aéronavale)", "all forms": "toutes formes", // Messages utilisateur "Skipping Tests to apply the tattoos": "Tests ignorés pour appliquer les tatouages", "Apply Ward of Grimnir effect?": "Appliquer l'effet Rune de Grimnir ?", "No Lore (Theology) skill found, cannot pass.": "Compétence Savoir (Théologie) introuvable, impossible de continuer.", "No Lore (Runes) skill found, cannot pass.": "Compétence Savoir (Runes) introuvable, impossible de continuer.", "One or more Tests to apply the tattoos failed.": "Un ou plusieurs Tests pour appliquer les tatouages ont échoué.", "Must provide a Master Rune": "Doit fournir une Rune Maîtresse", "Must provide a Rune (non-Master)": "Doit fournir une Rune (non-Maîtresse)", // Effets et conditions "Removed Broken": "Condition Brisé supprimée", "Added Bleeding": "Saignement ajouté", "Applied after effects": "Effets secondaires appliqués", "Does not need to make Peur or Terror tests": "N'a pas besoin de faire de tests de Peur ou de Terreur", "Automatically passes any": "Réussit automatiquement tout", // Fragments de code courants (contextuels) "action-link critical": "action-link critical", // Classe CSS, ne pas traduire "> Critical": "> Critique", // Patterns génériques "|| this.item.getFlag(": "|| this.item.getFlag(", // Code JS, ne pas traduire ',"info")': ',"info")', // Code JS, ne pas traduire }; // Fonction pour obtenir la fréquence de chaque texte anglais function getTextFrequencies() { const frequencies = new Map(); englishTexts.forEach(({ strings }) => { strings.forEach(str => { frequencies.set(str, (frequencies.get(str) || 0) + 1); }); }); return frequencies; } // Fonction pour proposer des traductions automatiques function proposeTranslations(text) { // Si déjà dans le mapping, retourner if (translations[text]) { return translations[text]; } // Patterns de remplacement simples basés sur fr.json let translated = text; // Mots courants du vocabulaire WFRP const vocabulary = { "Choose": "Choisir", "Select": "Sélectionner", "Enter": "Entrer", "Critical": "Critique", "Wounds": "Blessures", "Bleeding": "Saignement", "Broken": "Brisé", "Removed": "Retiré", "Added": "Ajouté", "Applied": "Appliqué", "Failed": "Échoué", "Passed": "Réussi", "Cannot": "Impossible de", "Must": "Doit", "Need": "Besoin", "Automatically": "Automatiquement", "any": "tout", "all": "tout", "Test": "Test", "Tests": "Tests", "Skill": "Compétence", "effect": "effet", "after effects": "effets secondaires", }; // Appliquer les remplacements de vocabulaire for (const [en, fr] of Object.entries(vocabulary)) { const regex = new RegExp(`\\b${en}\\b`, 'gi'); translated = translated.replace(regex, (match) => { // Conserver la casse if (match[0] === match[0].toUpperCase()) { return fr.charAt(0).toUpperCase() + fr.slice(1); } return fr; }); } // Si rien n'a changé, ne pas proposer de traduction if (translated === text) { return null; } return translated; } // Analyser et créer le mapping complet console.log('Création du mapping de traductions...\n'); const frequencies = getTextFrequencies(); const autoTranslations = new Map(); // Trier par fréquence décroissante const sortedTexts = Array.from(frequencies.entries()) .sort((a, b) => b[1] - a[1]); let proposedCount = 0; let existingCount = 0; sortedTexts.forEach(([text, freq]) => { if (translations[text]) { autoTranslations.set(text, translations[text]); existingCount++; } else { const proposed = proposeTranslations(text); if (proposed && proposed !== text) { autoTranslations.set(text, proposed); proposedCount++; if (proposedCount <= 10) { console.log(`"${text}" → "${proposed}" (${freq}x)`); } } } }); console.log(`\n${existingCount} traductions existantes`); console.log(`${proposedCount} traductions proposées automatiquement`); console.log(`${sortedTexts.length - existingCount - proposedCount} textes ignorés (code/technique)`); // Appliquer les traductions console.log('\n' + '='.repeat(60)); console.log('Application des traductions...\n'); let stats = { filesProcessed: 0, filesModified: 0, replacementsMade: 0, errors: 0 }; englishTexts.forEach(({ file, strings }) => { const filePath = path.join(FR_DIR, file); stats.filesProcessed++; try { let content = fs.readFileSync(filePath, 'utf8'); let modified = false; let replacementsInFile = 0; strings.forEach(text => { const translation = autoTranslations.get(text); if (translation && content.includes(text)) { // Remplacement simple const newContent = content.split(text).join(translation); if (newContent !== content) { const count = content.split(text).length - 1; content = newContent; modified = true; replacementsInFile += count; stats.replacementsMade += count; } } }); if (modified) { fs.writeFileSync(filePath, content, 'utf8'); stats.filesModified++; console.log(`✓ ${file} : ${replacementsInFile} remplacement(s)`); } } catch (error) { stats.errors++; console.error(`✗ ${file} : ${error.message}`); } }); console.log('\n' + '='.repeat(60)); console.log('Traduction automatique terminée !'); console.log('='.repeat(60)); console.log(`Fichiers traités : ${stats.filesProcessed}`); console.log(`Fichiers modifiés : ${stats.filesModified}`); console.log(`Remplacements effectués : ${stats.replacementsMade}`); console.log(`Erreurs : ${stats.errors}`); console.log('='.repeat(60)); // Sauvegarder le mapping de traductions const mappingFile = path.join(__dirname, 'auto-translations-applied.json'); fs.writeFileSync( mappingFile, JSON.stringify(Object.fromEntries(autoTranslations), null, 2), 'utf8' ); console.log(`\nMapping de traductions sauvegardé dans : auto-translations-applied.json`);