// Floating language picker — self-hosted translation. Text nodes are collected, // translated through /api/public/translate (server-cached forever per string), // and swapped in place. A MutationObserver keeps late-rendered dashboard panels // translated too. No third-party scripts touch the page. (function(){ var LANGS=[['es','Español'],['pt','Português'],['fr','Français'],['de','Deutsch'],['it','Italiano'], ['nl','Nederlands'],['pl','Polski'],['ro','Română'],['ru','Русский'],['uk','Українська'], ['tr','Türkçe'],['ar','العربية'],['hi','हिन्दी'],['fil','Filipino'],['vi','Tiếng Việt'], ['id','Bahasa Indonesia'],['th','ไทย'],['zh','中文'],['ja','日本語'],['ko','한국어'],['sw','Kiswahili']]; var STYLE=''+ '#rmcTrBtn{position:fixed;bottom:18px;left:18px;z-index:9998;display:flex;align-items:center;gap:7px;'+ 'background:#0d2236;border:1px solid #24425d;color:#f7f9fc;border-radius:999px;padding:9px 14px;'+ 'font:700 13px/1 Inter,system-ui,sans-serif;cursor:pointer;box-shadow:0 6px 24px rgba(0,0,0,.35)}'+ '#rmcTrBtn:hover{border-color:#4ed6cb}'+ '#rmcTrPanel{position:fixed;bottom:64px;left:18px;z-index:9999;background:#0d2236;border:1px solid #24425d;'+ 'border-radius:14px;padding:12px;display:none;box-shadow:0 10px 34px rgba(0,0,0,.45);max-height:60vh;overflow:auto;width:230px}'+ '#rmcTrPanel.on{display:block}'+ '#rmcTrPanel .t{color:#aebdca;font:600 12px/1.4 Inter,system-ui,sans-serif;margin:0 0 8px}'+ '#rmcTrPanel button{display:block;width:100%;text-align:left;background:none;border:none;color:#f7f9fc;'+ 'padding:8px 10px;border-radius:8px;font:600 14px/1 Inter,system-ui,sans-serif;cursor:pointer}'+ '#rmcTrPanel button:hover{background:#123049}'+ '#rmcTrPanel button.on{background:#123049;color:#4ed6cb}'+ '@media print{#rmcTrBtn,#rmcTrPanel,.chat-fab,.chat-panel{display:none!important}}'; var lang=null; try{ lang=localStorage.getItem('rmc.lang')||null; }catch(e){} var cacheKey=function(){ return 'rmc.tr.'+lang; }; var memo={}; function loadMemo(){ memo={}; try{ memo=JSON.parse(sessionStorage.getItem(cacheKey())||'{}'); }catch(e){} } function saveMemo(){ try{ var k=Object.keys(memo); if(k.length>900){memo={};} sessionStorage.setItem(cacheKey(),JSON.stringify(memo)); }catch(e){} } var SKIP={SCRIPT:1,STYLE:1,NOSCRIPT:1,CODE:1,TEXTAREA:1,SELECT:1}; function collect(root){ var nodes=[],w=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,{acceptNode:function(n){ var p=n.parentNode; if(!p||SKIP[p.nodeName])return NodeFilter.FILTER_REJECT; if(p.closest&&p.closest('#rmcTrPanel,#rmcTrBtn'))return NodeFilter.FILTER_REJECT; var t=n.nodeValue; if(!t||!t.trim()||t.trim().length<2)return NodeFilter.FILTER_REJECT; if(!/[A-Za-z]{2}/.test(t))return NodeFilter.FILTER_REJECT; if(n.__rmcTr===lang)return NodeFilter.FILTER_REJECT; return NodeFilter.FILTER_ACCEPT; }}); var n; while((n=w.nextNode()))nodes.push(n); return nodes; } var busy=false,queued=false; function translatePage(root){ if(!lang)return; if(busy){queued=true;return} busy=true; var nodes=collect(root||document.body); var uniq=[],idx={}; nodes.forEach(function(n){ var t=n.nodeValue.trim(); if(!(t in idx)&&memo[t]==null){ idx[t]=uniq.length; uniq.push(t);} }); var chunks=[]; for(var i=0;iChoose your language — it sticks on every page.

', '']; LANGS.forEach(function(L){ htmlBits.push(''); }); panel.innerHTML=htmlBits.join(''); document.body.appendChild(btn);document.body.appendChild(panel); btn.addEventListener('click',function(){ panel.classList.toggle('on'); }); panel.addEventListener('click',function(e){ var b=e.target.closest('button[data-l]'); if(!b)return; panel.querySelectorAll('button').forEach(function(x){x.classList.remove('on')}); if(b.dataset.l)b.classList.add('on'); panel.classList.remove('on'); setLang(b.dataset.l||null); }); document.addEventListener('click',function(e){ if(panel.classList.contains('on')&&!panel.contains(e.target)&&!btn.contains(e.target))panel.classList.remove('on'); }); mo.observe(document.body,{childList:true,subtree:true}); if(lang){ loadMemo(); translatePage(); } } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',mount);else mount(); })();