Add on-site translation for multilingual members

Floating translate button (bottom-left) on every member-facing page
lazy-loads the Google Translate element; language choice persists
across pages via the googtrans cookie. CSP extended for Google's
translate hosts only. Chatbot now replies in the member's language
and a canned answer points at the button.
This commit is contained in:
martbost
2026-08-21 07:23:55 -05:00
parent d60e8c6807
commit faf397f681
13 changed files with 61 additions and 11 deletions
+47
View File
@@ -0,0 +1,47 @@
// Floating language picker — lazy-loads the Google Translate element on first
// tap so pages pay zero cost until someone actually wants a translation. The
// googtrans cookie carries the chosen language across every page after that.
(function(){
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:14px;display:none;box-shadow:0 10px 34px rgba(0,0,0,.45)}'+
'#rmcTrPanel.on{display:block}'+
'#rmcTrPanel .t{color:#aebdca;font:600 12px/1.4 Inter,system-ui,sans-serif;margin:0 0 8px}'+
/* suppress Google's top banner + body shift */
'.goog-te-banner-frame,.skiptranslate iframe{display:none!important}'+
'body{top:0!important}'+
'#google_translate_element select{background:#071726;color:#f7f9fc;border:1px solid #24425d;border-radius:8px;padding:8px;font-size:14px;max-width:230px}'+
'#google_translate_element .goog-te-gadget{color:#aebdca;font-size:11px}'+
'#google_translate_element .goog-logo-link{color:#aebdca!important}';
var loaded=false;
function mount(){
var st=document.createElement('style');st.textContent=STYLE;document.head.appendChild(st);
var btn=document.createElement('button');btn.id='rmcTrBtn';btn.type='button';
btn.innerHTML='🌐 <span>Translate</span>';
btn.setAttribute('aria-label','Translate this page');
var panel=document.createElement('div');panel.id='rmcTrPanel';
panel.innerHTML='<p class="t">Choose your language — it sticks on every page.</p><div id="google_translate_element"></div>';
document.body.appendChild(btn);document.body.appendChild(panel);
btn.addEventListener('click',function(){
panel.classList.toggle('on');
if(!loaded){
loaded=true;
window.googleTranslateElementInit=function(){
new google.translate.TranslateElement({pageLanguage:'en',autoDisplay:false},'google_translate_element');
};
var s=document.createElement('script');
s.src='https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit';
s.onerror=function(){document.getElementById('google_translate_element').innerHTML='<p class="t">Translation is unavailable right now — your browser’s own “Translate page” option also works on this site.</p>';};
document.head.appendChild(s);
}
});
document.addEventListener('click',function(e){
if(panel.classList.contains('on')&&!panel.contains(e.target)&&e.target!==btn&&!btn.contains(e.target))panel.classList.remove('on');
});
}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',mount);else mount();
})();