document.addEventListener('DOMContentLoaded', function() { // DOM elements const sourceLanguage = document.getElementById('sourceLanguage'); const targetLanguage = document.getElementById('targetLanguage'); const swapButton = document.getElementById('swapLanguages'); const sourceText = document.getElementById('sourceText'); const translatedText = document.getElementById('translatedText'); const recordSourceButton = document.getElementById('recordSource'); const speakButton = document.getElementById('speak'); const clearSourceButton = document.getElementById('clearSource'); const copyTranslationButton = document.getElementById('copyTranslation'); const translateButton = document.getElementById('translateButton'); const statusMessage = document.getElementById('status'); // Audio recording variables let mediaRecorder; let audioChunks = []; let isRecording = false; // Speech recognition setup const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = SpeechRecognition ? new SpeechRecognition() : null; if (recognition) { recognition.continuous = false; recognition.interimResults = false; } // Event listeners swapButton.addEventListener('click', swapLanguages); translateButton.addEventListener('click', translateText); clearSourceButton.addEventListener('click', clearSource); copyTranslationButton.addEventListener('click', copyTranslation); if (recognition) { recordSourceButton.addEventListener('click', toggleRecording); } else { recordSourceButton.textContent = "Speech API not supported"; recordSourceButton.disabled = true; } speakButton.addEventListener('click', speakTranslation); // Functions (continued) function swapLanguages() { const tempLang = sourceLanguage.value; sourceLanguage.value = targetLanguage.value; targetLanguage.value = tempLang; // Also swap the text if both fields have content if (sourceText.value && translatedText.value) { const tempText = sourceText.value; sourceText.value = translatedText.value; translatedText.value = tempText; } } function clearSource() { sourceText.value = ''; updateStatus(''); } function copyTranslation() { if (!translatedText.value) { updateStatus('Nothing to copy', 'error'); return; } navigator.clipboard.writeText(translatedText.value) .then(() => { updateStatus('Copied to clipboard!', 'success'); setTimeout(() => updateStatus(''), 2000); }) .catch(err => { updateStatus('Failed to copy: ' + err, 'error'); }); } async function translateText() { const source = sourceText.value.trim(); if (!source) { updateStatus('Please enter or speak some text to translate', 'error'); return; } updateStatus('Translating...'); translatedText.value = ''; try { const response = await fetch('/translate', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ sourceLanguage: sourceLanguage.value, targetLanguage: targetLanguage.value, text: source }) }); const data = await response.json(); if (response.ok) { translatedText.value = data.translation; updateStatus('Translation complete', 'success'); setTimeout(() => updateStatus(''), 2000); } else { updateStatus(data.error || 'Translation failed', 'error'); } } catch (error) { updateStatus('Network error: ' + error.message, 'error'); } } function toggleRecording() { if (!recognition) { updateStatus('Speech recognition not supported in this browser', 'error'); return; } if (isRecording) { stopRecording(); } else { startRecording(); } } function startRecording() { sourceText.value = ''; updateStatus('Listening...'); recognition.lang = getLanguageCode(sourceLanguage.value); recognition.onresult = function(event) { const transcript = event.results[0][0].transcript; sourceText.value = transcript; updateStatus('Recording completed', 'success'); setTimeout(() => updateStatus(''), 2000); }; recognition.onerror = function(event) { updateStatus('Error in speech recognition: ' + event.error, 'error'); stopRecording(); }; recognition.onend = function() { stopRecording(); }; try { recognition.start(); isRecording = true; recordSourceButton.classList.add('recording'); recordSourceButton.querySelector('.button-text').textContent = 'Stop'; } catch (error) { updateStatus('Failed to start recording: ' + error.message, 'error'); } } function stopRecording() { if (isRecording) { try { recognition.stop(); } catch (error) { console.error('Error stopping recognition:', error); } isRecording = false; recordSourceButton.classList.remove('recording'); recordSourceButton.querySelector('.button-text').textContent = 'Record'; } } function speakTranslation() { const text = translatedText.value.trim(); if (!text) { updateStatus('No translation to speak', 'error'); return; } // Use the browser's speech synthesis API const speech = new SpeechSynthesisUtterance(text); speech.lang = getLanguageCode(targetLanguage.value); speech.volume = 1; speech.rate = 1; speech.pitch = 1; speech.onstart = function() { updateStatus('Speaking...'); speakButton.disabled = true; }; speech.onend = function() { updateStatus(''); speakButton.disabled = false; }; speech.onerror = function(event) { updateStatus('Speech synthesis error: ' + event.error, 'error'); speakButton.disabled = false; }; window.speechSynthesis.speak(speech); } function getLanguageCode(language) { // Map language names to BCP 47 language tags for speech recognition/synthesis const languageMap = { "arabic": "ar-SA", "armenian": "hy-AM", "azerbaijani": "az-AZ", "english": "en-US", "french": "fr-FR", "georgian": "ka-GE", "kazakh": "kk-KZ", "mandarin": "zh-CN", "persian": "fa-IR", "portuguese": "pt-PT", "russian": "ru-RU", "turkish": "tr-TR", "uzbek": "uz-UZ" }; return languageMap[language] || 'en-US'; } function updateStatus(message, type = '') { statusMessage.textContent = message; statusMessage.className = 'status-message'; if (type) { statusMessage.classList.add(type); } } // Check for microphone and speech support when page loads function checkSupportedFeatures() { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { updateStatus('Microphone access is not supported in this browser', 'error'); recordSourceButton.disabled = true; } if (!window.SpeechRecognition && !window.webkitSpeechRecognition) { updateStatus('Speech recognition is not supported in this browser', 'error'); recordSourceButton.disabled = true; } if (!window.speechSynthesis) { updateStatus('Speech synthesis is not supported in this browser', 'error'); speakButton.disabled = true; } } checkSupportedFeatures(); });