| <!DOCTYPE html> |
| <html lang="fr"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Traducteur Universel</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script> |
| tailwind.config = { |
| darkMode: 'class', |
| theme: { |
| extend: { |
| colors: { |
| dark: { |
| 100: '#E5E7EB', |
| 200: '#D1D5DB', |
| 300: '#9CA3AF', |
| 400: '#6B7280', |
| 500: '#4B5563', |
| 600: '#374151', |
| 700: '#1F2937', |
| 800: '#111827', |
| 900: '#0F172A', |
| } |
| } |
| } |
| } |
| } |
| </script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .language-flag { |
| width: 24px; |
| height: 16px; |
| margin-right: 8px; |
| border-radius: 2px; |
| } |
| .text-input { |
| min-height: 150px; |
| resize: none; |
| } |
| .swap-btn { |
| transition: all 0.3s ease; |
| } |
| .swap-btn:hover { |
| transform: rotate(180deg); |
| } |
| .pulse { |
| animation: pulse 1.5s infinite; |
| } |
| @keyframes pulse { |
| 0% { opacity: 1; } |
| 50% { opacity: 0.5; } |
| 100% { opacity: 1; } |
| } |
| body { |
| transition: background-color 0.3s ease; |
| } |
| </style> |
| </head> |
| <body class="bg-gradient-to-br from-dark-800 to-dark-900 min-h-screen text-dark-100"> |
| <div class="container mx-auto px-4 py-12 max-w-4xl"> |
| |
| <div class="flex justify-end mb-4"> |
| <button id="themeToggle" class="p-2 rounded-full bg-dark-700 hover:bg-dark-600 transition"> |
| <i class="fas fa-moon" id="themeIcon"></i> |
| </button> |
| </div> |
|
|
| <div class="text-center mb-10"> |
| <h1 class="text-4xl font-bold text-indigo-400 mb-2">Traducteur Universel</h1> |
| <p class="text-lg text-indigo-300">Traduisez instantanément entre toutes les langues</p> |
| </div> |
|
|
| <div class="bg-dark-700 rounded-xl shadow-xl overflow-hidden border border-dark-600"> |
| <div class="flex flex-col md:flex-row"> |
| |
| <div class="w-full md:w-1/2 p-6 border-b md:border-b-0 md:border-r border-dark-600"> |
| <div class="flex items-center justify-between mb-4"> |
| <div class="flex items-center"> |
| <div class="relative w-full"> |
| <select id="sourceLanguage" class="w-full p-3 border border-dark-500 rounded-lg appearance-none bg-dark-800 text-dark-100 pr-10 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| <option value="auto">Détection automatique</option> |
| <option value="fr">Français</option> |
| <option value="en">Anglais</option> |
| <option value="es">Espagnol</option> |
| <option value="de">Allemand</option> |
| <option value="it">Italien</option> |
| <option value="pt">Portugais</option> |
| <option value="ru">Russe</option> |
| <option value="zh">Chinois</option> |
| <option value="ja">Japonais</option> |
| <option value="ar">Arabe</option> |
| </select> |
| <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none"> |
| <i class="fas fa-chevron-down text-dark-400"></i> |
| </div> |
| </div> |
| </div> |
| </div> |
| <textarea id="sourceText" class="w-full text-input p-4 border border-dark-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 bg-dark-800 text-dark-100 placeholder-dark-400" placeholder="Entrez votre texte ici..."></textarea> |
| <div class="flex justify-between items-center mt-3"> |
| <div class="text-sm text-dark-400" id="sourceCharCount">0/5000</div> |
| <button id="clearSource" class="text-dark-400 hover:text-indigo-400"> |
| <i class="fas fa-times"></i> Effacer |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="w-full md:w-1/2 p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <div class="flex items-center"> |
| <div class="relative w-full"> |
| <select id="targetLanguage" class="w-full p-3 border border-dark-500 rounded-lg appearance-none bg-dark-800 text-dark-100 pr-10 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| <option value="fr">Français</option> |
| <option value="en" selected>Anglais</option> |
| <option value="es">Espagnol</option> |
| <option value="de">Allemand</option> |
| <option value="it">Italien</option> |
| <option value="pt">Portugais</option> |
| <option value="ru">Russe</option> |
| <option value="zh">Chinois</option> |
| <option value="ja">Japonais</option> |
| <option value="ar">Arabe</option> |
| </select> |
| <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none"> |
| <i class="fas fa-chevron-down text-dark-400"></i> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="targetText" class="w-full text-input p-4 border border-dark-600 rounded-lg bg-dark-800 min-h-[150px] text-dark-100"> |
| <div class="text-dark-400 italic">La traduction apparaîtra ici...</div> |
| </div> |
| <div class="flex justify-between items-center mt-3"> |
| <div class="text-sm text-dark-400" id="targetCharCount">0/5000</div> |
| <div class="flex space-x-2"> |
| <button id="copyTranslation" class="text-dark-400 hover:text-indigo-400" title="Copier"> |
| <i class="far fa-copy"></i> |
| </button> |
| <button id="speakTranslation" class="text-dark-400 hover:text-indigo-400" title="Écouter"> |
| <i class="fas fa-volume-up"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-dark-800 px-6 py-4 border-t border-dark-600 flex justify-between items-center"> |
| <div class="flex items-center space-x-2"> |
| <button id="swapLanguages" class="swap-btn bg-indigo-600 text-white p-3 rounded-full hover:bg-indigo-500"> |
| <i class="fas fa-exchange-alt"></i> |
| </button> |
| <span class="text-sm text-dark-300">Échanger les langues</span> |
| </div> |
| <button id="translateBtn" class="bg-indigo-600 hover:bg-indigo-500 text-white font-medium py-3 px-6 rounded-lg flex items-center"> |
| <i class="fas fa-language mr-2"></i> Traduire |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="mt-10 bg-dark-700 rounded-xl shadow-lg overflow-hidden border border-dark-600"> |
| <div class="p-6"> |
| <h2 class="text-xl font-semibold text-indigo-400 mb-4 flex items-center"> |
| <i class="fas fa-history mr-2"></i> Historique des traductions |
| </h2> |
| <div id="historyList" class="space-y-3 max-h-60 overflow-y-auto"> |
| |
| <div class="text-center text-dark-400 py-4 italic">Aucun historique pour le moment</div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| |
| const sourceText = document.getElementById('sourceText'); |
| const targetText = document.getElementById('targetText'); |
| const sourceLanguage = document.getElementById('sourceLanguage'); |
| const targetLanguage = document.getElementById('targetLanguage'); |
| const translateBtn = document.getElementById('translateBtn'); |
| const swapLanguages = document.getElementById('swapLanguages'); |
| const clearSource = document.getElementById('clearSource'); |
| const copyTranslation = document.getElementById('copyTranslation'); |
| const speakTranslation = document.getElementById('speakTranslation'); |
| const sourceCharCount = document.getElementById('sourceCharCount'); |
| const targetCharCount = document.getElementById('targetCharCount'); |
| const historyList = document.getElementById('historyList'); |
| const themeToggle = document.getElementById('themeToggle'); |
| const themeIcon = document.getElementById('themeIcon'); |
| let isDarkMode = true; |
| |
| |
| themeToggle.addEventListener('click', function() { |
| isDarkMode = !isDarkMode; |
| if (isDarkMode) { |
| document.documentElement.classList.add('dark'); |
| themeIcon.classList.remove('fa-sun'); |
| themeIcon.classList.add('fa-moon'); |
| } else { |
| document.documentElement.classList.remove('dark'); |
| themeIcon.classList.remove('fa-moon'); |
| themeIcon.classList.add('fa-sun'); |
| } |
| }); |
| |
| |
| sourceText.addEventListener('input', function() { |
| const count = sourceText.value.length; |
| sourceCharCount.textContent = `${count}/5000`; |
| if (count > 4500) { |
| sourceCharCount.classList.add('text-red-400'); |
| } else { |
| sourceCharCount.classList.remove('text-red-400'); |
| } |
| }); |
| |
| |
| clearSource.addEventListener('click', function() { |
| sourceText.value = ''; |
| sourceCharCount.textContent = '0/5000'; |
| targetText.innerHTML = '<div class="text-dark-400 italic">La traduction apparaîtra ici...</div>'; |
| targetCharCount.textContent = '0/5000'; |
| }); |
| |
| |
| swapLanguages.addEventListener('click', function() { |
| const tempLang = sourceLanguage.value; |
| sourceLanguage.value = targetLanguage.value; |
| targetLanguage.value = tempLang; |
| |
| |
| if (sourceText.value.trim()) { |
| translateText(); |
| } |
| }); |
| |
| |
| copyTranslation.addEventListener('click', function() { |
| if (targetText.textContent.trim() && !targetText.querySelector('.italic')) { |
| navigator.clipboard.writeText(targetText.textContent) |
| .then(() => { |
| const originalIcon = copyTranslation.innerHTML; |
| copyTranslation.innerHTML = '<i class="fas fa-check"></i>'; |
| setTimeout(() => { |
| copyTranslation.innerHTML = originalIcon; |
| }, 2000); |
| }); |
| } |
| }); |
| |
| |
| speakTranslation.addEventListener('click', function() { |
| if (targetText.textContent.trim() && !targetText.querySelector('.italic')) { |
| const utterance = new SpeechSynthesisUtterance(targetText.textContent); |
| utterance.lang = targetLanguage.value; |
| speechSynthesis.speak(utterance); |
| } |
| }); |
| |
| |
| let translateTimeout; |
| sourceText.addEventListener('input', function() { |
| clearTimeout(translateTimeout); |
| if (sourceText.value.trim()) { |
| translateTimeout = setTimeout(translateText, 1000); |
| } |
| }); |
| |
| |
| translateBtn.addEventListener('click', translateText); |
| |
| |
| function translateText() { |
| const text = sourceText.value.trim(); |
| if (!text) return; |
| |
| |
| targetText.innerHTML = '<div class="flex justify-center items-center h-full"><div class="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-indigo-500"></div></div>'; |
| translateBtn.disabled = true; |
| translateBtn.classList.add('opacity-75', 'cursor-not-allowed'); |
| |
| |
| setTimeout(() => { |
| |
| |
| const translatedText = `[Traduction simulée de ${sourceLanguage.value} vers ${targetLanguage.value}]\n${text.split('').reverse().join('')}`; |
| |
| targetText.innerHTML = translatedText; |
| targetCharCount.textContent = `${translatedText.length}/5000`; |
| |
| |
| addToHistory(text, translatedText, sourceLanguage.value, targetLanguage.value); |
| |
| translateBtn.disabled = false; |
| translateBtn.classList.remove('opacity-75', 'cursor-not-allowed'); |
| }, 1500); |
| } |
| |
| |
| function addToHistory(source, translation, fromLang, toLang) { |
| |
| if (historyList.querySelector('.italic')) { |
| historyList.innerHTML = ''; |
| } |
| |
| const historyItem = document.createElement('div'); |
| historyItem.className = 'bg-dark-800 p-3 rounded-lg border border-dark-600 hover:bg-dark-600 transition cursor-pointer'; |
| historyItem.innerHTML = ` |
| <div class="flex justify-between items-start"> |
| <div class="flex-1"> |
| <div class="text-sm font-medium text-dark-100 mb-1">${source.substring(0, 50)}${source.length > 50 ? '...' : ''}</div> |
| <div class="text-sm text-indigo-400">${translation.substring(0, 50)}${translation.length > 50 ? '...' : ''}</div> |
| </div> |
| <div class="text-xs text-dark-400 ml-2">${fromLang} → ${toLang}</div> |
| </div> |
| `; |
| |
| |
| historyList.insertBefore(historyItem, historyList.firstChild); |
| |
| |
| if (historyList.children.length > 10) { |
| historyList.removeChild(historyList.lastChild); |
| } |
| |
| |
| historyItem.addEventListener('click', function() { |
| sourceText.value = source; |
| sourceCharCount.textContent = `${source.length}/5000`; |
| targetText.innerHTML = translation; |
| targetCharCount.textContent = `${translation.length}/5000`; |
| sourceLanguage.value = fromLang; |
| targetLanguage.value = toLang; |
| }); |
| } |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Bruno2023/unitrad" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |