// The complete, versioned catalog is embedded before this script by the server. // Only textContent/Alpine x-text is used: parameters are never interpreted as HTML. const I18n = (() => { const supported=['en','ru','fr']; const detect=(languages)=>{for(const raw of languages || []){const base=String(raw).toLowerCase().split(/[-_]/)[0];if(supported.includes(base))return base;}return 'en';}; const browser=detect(navigator.languages?.length?navigator.languages:[navigator.language]); const locale=()=>globalThis.Alpine?.store('locale')?.language || browser; const translate=(key,params={},language=locale())=>{ const entry=MEGURI_MESSAGES[key]; if(!entry)throw new Error('Missing localization key: '+key); const pattern=entry[language] || entry.en; return pattern.replace(/\{([\w]+)\}/g,(match,name)=>Object.hasOwn(params,name)?String(params[name]):match); }; const exact=new Map(); for(const [key,entry]of Object.entries(MEGURI_MESSAGES))for(const text of Object.values(entry))if(text)exact.set(text,key); const patterns=[]; for(const [key,entry]of Object.entries(MEGURI_MESSAGES)){ if(!entry.en.includes('{'))continue; const names=[];let from=0,expression='^'; for(const match of entry.en.matchAll(/\{(\w+)\}/g)){expression+=entry.en.slice(from,match.index).replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'([\\s\\S]*?)';names.push(match[1]);from=match.index+match[0].length;} if(names.length){expression+=entry.en.slice(from).replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'$';patterns.push({key,names,re:new RegExp(expression)});} } const diagnostic=(text)=>{ if(text==null)return ''; text=String(text);const key=exact.get(text);if(key)return translate(key); for(const item of patterns){const match=item.re.exec(text);if(match)return translate(item.key,Object.fromEntries(item.names.map((name,i)=>[name,match[i+1]])));} return text; // User values and third-party diagnostics are opaque, never guessed or rewritten. }; document.addEventListener('alpine:init',()=>{ Alpine.store('locale',{language:browser}); Alpine.effect(()=>{const language=locale();document.documentElement.lang=language;const title=document.querySelector('[data-title-key]');if(title)document.title=translate(title.dataset.titleKey);}); }); return Object.freeze({supported,browser,detect,locale,translate,diagnostic}); })(); function tr(key,params){return I18n.translate(key,params);}