Spaces:
Running
Running
Please build a responsive web UI for a Self Hosted Translation App (single-page) with a clean, modern look.
ca78225 verified | /** | |
| * Application State & Logic | |
| */ | |
| // --- Language Data --- | |
| const LANGUAGES_M2M100 = [ | |
| { code: "af", label: "Afrikaans" }, { code: "am", label: "Amharic" }, { code: "ar", label: "Arabic" }, | |
| { code: "ast", label: "Asturian" }, { code: "az", label: "Azerbaijani" }, { code: "ba", label: "Bashkir" }, | |
| { code: "be", label: "Belarusian" }, { code: "bg", label: "Bulgarian" }, { code: "bn", label: "Bengali" }, | |
| { code: "br", label: "Breton" }, { code: "bs", label: "Bosnian" }, { code: "ca", label: "Catalan; Valencian" }, | |
| { code: "ceb", label: "Cebuano" }, { code: "cs", label: "Czech" }, { code: "cy", label: "Welsh" }, | |
| { code: "da", label: "Danish" }, { code: "de", label: "German" }, { code: "el", label: "Greek" }, | |
| { code: "en", label: "English" }, { code: "es", label: "Spanish" }, { code: "et", label: "Estonian" }, | |
| { code: "fa", label: "Persian" }, { code: "ff", label: "Fulah" }, { code: "fi", label: "Finnish" }, | |
| { code: "fr", label: "French" }, { code: "fy", label: "Western Frisian" }, { code: "ga", label: "Irish" }, | |
| { code: "gd", label: "Gaelic; Scottish Gaelic" }, { code: "gl", label: "Galician" }, { code: "gu", label: "Gujarati" }, | |
| { code: "ha", label: "Hausa" }, { code: "he", label: "Hebrew" }, { code: "hi", label: "Hindi" }, | |
| { code: "hr", label: "Croatian" }, { code: "ht", label: "Haitian; Haitian Creole" }, { code: "hu", label: "Hungarian" }, | |
| { code: "hy", label: "Armenian" }, { code: "id", label: "Indonesian" }, { code: "ig", label: "Igbo" }, | |
| { code: "ilo", label: "Iloko" }, { code: "is", label: "Icelandic" }, { code: "it", label: "Italian" }, | |
| { code: "ja", label: "Japanese" }, { code: "jv", label: "Javanese" }, { code: "ka", label: "Georgian" }, | |
| { code: "kk", label: "Kazakh" }, { code: "km", label: "Central Khmer" }, { code: "kn", label: "Kannada" }, | |
| { code: "ko", label: "Korean" }, { code: "lb", label: "Luxembourgish; Letzeburgesch" }, { code: "lg", label: "Ganda" }, | |
| { code: "ln", label: "Lingala" }, { code: "lo", label: "Lao" }, { code: "lt", label: "Lithuanian" }, | |
| { code: "lv", label: "Latvian" }, { code: "mg", label: "Malagasy" }, { code: "mk", label: "Macedonian" }, | |
| { code: "ml", label: "Malayalam" }, { code: "mn", label: "Mongolian" }, { code: "mr", label: "Marathi" }, | |
| { code: "ms", label: "Malay" }, { code: "my", label: "Burmese" }, { code: "ne", label: "Nepali" }, | |
| { code: "nl", label: "Dutch; Flemish" }, { code: "no", label: "Norwegian" }, { code: "ns", label: "Northern Sotho" }, | |
| { code: "oc", label: "Occitan (post 1500)" }, { code: "or", label: "Oriya" }, { code: "pa", label: "Panjabi; Punjabi" }, | |
| { code: "pl", label: "Polish" }, { code: "ps", label: "Pushto; Pashto" }, { code: "pt", label: "Portuguese" }, | |
| { code: "ro", label: "Romanian; Moldavian; Moldovan" }, { code: "ru", label: "Russian" }, { code: "sd", label: "Sindhi" }, | |
| { code: "si", label: "Sinhala; Sinhalese" }, { code: "sk", label: "Slovak" }, { code: "sl", label: "Slovenian" }, | |
| { code: "so", label: "Somali" }, { code: "sq", label: "Albanian" }, { code: "sr", label: "Serbian" }, | |
| { code: "ss", label: "Swati" }, { code: "su", label: "Sundanese" }, { code: "sv", label: "Swedish" }, | |
| { code: "sw", label: "Swahili" }, { code: "ta", label: "Tamil" }, { code: "th", label: "Thai" }, | |
| { code: "tl", label: "Tagalog" }, { code: "tn", label: "Tswana" }, { code: "tr", label: "Turkish" }, | |
| { code: "uk", label: "Ukrainian" }, { code: "ur", label: "Urdu" }, { code: "uz", label: "Uzbek" }, | |
| { code: "vi", label: "Vietnamese" }, { code: "wo", label: "Wolof" }, { code: "xh", label: "Xhosa" }, | |
| { code: "yi", label: "Yiddish" }, { code: "yo", label: "Yoruba" }, { code: "zh", label: "Chinese" }, | |
| { code: "zu", label: "Zulu" } | |
| ]; | |
| const LANGUAGES_INDIC = [ | |
| { code: "hin_Deva", label: "Hindi" }, | |
| { code: "guj_Gujr", label: "Gujarati" }, | |
| { code: "mar_Deva", label: "Marathi" }, | |
| { code: "san_Deva", label: "Sanskrit" } | |
| ]; | |
| // --- Global State --- | |
| window.appState = { | |
| model: 'indictrans2-en-indic-1B', // 'indictrans2-en-indic-1B' | 'm2m100-1.2b' | |
| sourceLang: 'en', | |
| targetLang: 'hin_Deva', | |
| inputText: '', | |
| outputText: '', | |
| isTranslating: false, | |
| file: null, | |
| fileStatus: 'idle' // idle, uploading, processing, done | |
| }; | |
| // --- Mock API --- | |
| const mockApi = { | |
| translateText: async (payload) => { | |
| return new Promise((resolve) => { | |
| setTimeout(() => { | |
| // Mock translation: Just repeat text or reverse it | |
| const mockResult = `[${payload.model}] ${payload.text} (Translated to ${payload.targetLang})`; | |
| resolve({ translation: mockResult }); | |
| }, 1000 + Math.random() * 1000); | |
| }); | |
| }, | |
| uploadFile: async (file) => { | |
| return new Promise((resolve) => { | |
| setTimeout(() => { | |
| resolve({ jobId: 'job_' + Date.now() }); | |
| }, 1500); | |
| }); | |
| }, | |
| checkFileStatus: async (jobId) => { | |
| return new Promise((resolve) => { | |
| setTimeout(() => { | |
| resolve({ status: 'completed', downloadUrl: '#' }); | |
| }, 2000); | |
| }); | |
| } | |
| }; | |
| // --- Event Bus --- | |
| window.dispatchEvent = new Proxy(window.dispatchEvent, { | |
| apply(target, thisArg, args) { | |
| // console.log("Event dispatched:", args[0].type); | |
| return target.apply(thisArg, args); | |
| } | |
| }); | |
| // --- Helper Functions --- | |
| window.showToast = (message, type = 'info') => { | |
| const container = document.getElementById('toast-container'); | |
| if (!container) return; | |
| const toast = document.createElement('div'); | |
| toast.className = ` | |
| flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800 | |
| toast-enter | |
| `; | |
| // Icon logic | |
| let iconHtml = ''; | |
| if(type === 'error') { | |
| iconHtml = `<div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-red-500 bg-red-100 rounded-lg dark:bg-red-800 dark:text-red-200"><i data-feather="x-circle"></i></div>`; | |
| toast.classList.add('border-l-4', 'border-red-500'); | |
| } else if (type === 'success') { | |
| iconHtml = `<div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200"><i data-feather="check-circle"></i></div>`; | |
| toast.classList.add('border-l-4', 'border-green-500'); | |
| } else { | |
| iconHtml = `<div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200"><i data-feather="info"></i></div>`; | |
| } | |
| toast.innerHTML = ` | |
| ${iconHtml} | |
| <div class="ml-3 text-sm font-normal">${message}</div> | |
| <button type="button" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" aria-label="Close"> | |
| <i data-feather="x" class="w-4 h-4"></i> | |
| </button> | |
| `; | |
| container.appendChild(toast); | |
| feather.replace(); | |
| // Close logic | |
| const closeBtn = toast.querySelector('button'); | |
| closeBtn.onclick = () => { | |
| toast.classList.remove('toast-enter-active'); | |
| toast.classList.add('toast-exit-active'); | |
| setTimeout(() => toast.remove(), 300); | |
| }; | |
| // Auto dismiss | |
| setTimeout(() => { | |
| if(toast.parentElement) { | |
| toast.classList.remove('toast-enter-active'); | |
| toast.classList.add('toast-exit-active'); | |
| setTimeout(() => toast.remove(), 300); | |
| } | |
| }, 3000); | |
| requestAnimationFrame(() => { | |
| toast.classList.remove('toast-enter'); | |
| toast.classList.add('toast-enter-active'); | |
| }); | |
| }; |