58 lines
1.8 KiB
JavaScript
58 lines
1.8 KiB
JavaScript
// Simple client-side i18n loader using JSON files in /locales/
|
|
(function(){
|
|
const defaultLang = localStorage.getItem('lang') || (navigator.language && navigator.language.startsWith && navigator.language.startsWith('en') ? 'en' : 'fr');
|
|
let current = defaultLang;
|
|
|
|
async function loadLocale(lang){
|
|
try{
|
|
const res = await fetch(`locales/${lang}.json`);
|
|
if(!res.ok) throw new Error('locale not found');
|
|
return await res.json();
|
|
}catch(e){
|
|
console.error('i18n load error', e);
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function applyTranslations(messages){
|
|
document.querySelectorAll('[data-i18n]').forEach(el => {
|
|
const key = el.getAttribute('data-i18n');
|
|
const txt = messages[key];
|
|
if(!txt) return;
|
|
if(el.placeholder !== undefined && el.tagName.toLowerCase()==='input'){
|
|
el.placeholder = txt;
|
|
} else if (el.hasAttribute('data-i18n-html')) {
|
|
el.innerHTML = txt;
|
|
} else {
|
|
el.textContent = txt;
|
|
}
|
|
});
|
|
}
|
|
|
|
async function setLang(lang){
|
|
const messages = await loadLocale(lang);
|
|
applyTranslations(messages);
|
|
localStorage.setItem('lang', lang);
|
|
current = lang;
|
|
try{ document.documentElement.lang = lang; }catch(e){}
|
|
document.querySelectorAll('.lang-toggle').forEach(btn => {
|
|
btn.classList.toggle('active', btn.getAttribute('data-lang')===lang);
|
|
});
|
|
}
|
|
|
|
// init on DOMContentLoaded
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// attach toggles
|
|
document.querySelectorAll('.lang-toggle').forEach(btn => {
|
|
btn.addEventListener('click', e => {
|
|
e.preventDefault();
|
|
const l = btn.getAttribute('data-lang');
|
|
setLang(l);
|
|
});
|
|
});
|
|
setLang(current);
|
|
});
|
|
|
|
// expose for debug
|
|
window.__i18n = { setLang };
|
|
})();
|