59bbff0ad9
Document the client-side, dual-rendered locale contract and dispatch a narrow language-change event for guide selector panels.\n\nDo not assemble the full-guide page or change its content collections; task 15d owns that integration.
69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
---
|
|
// LanguageToggle — idle-hydrated, full-guide-only locale control.
|
|
//
|
|
// The guide server-renders both locales. This leaf owns the persisted locale
|
|
// and announces changes so selector islands can rebuild their active panels
|
|
// from collection data without knowing about this control's markup.
|
|
---
|
|
|
|
<div class="lang-switch" aria-label="Language" data-language-toggle>
|
|
<button class="active" data-lang="en" aria-pressed="true">EN</button>
|
|
<span>/</span>
|
|
<button data-lang="pt" aria-pressed="false">PT</button>
|
|
</div>
|
|
|
|
<script>
|
|
type Language = 'en' | 'pt';
|
|
|
|
function setup(root: HTMLElement) {
|
|
const buttons = root.querySelectorAll<HTMLButtonElement>('[data-lang]');
|
|
|
|
function renderLanguage(next: Language) {
|
|
document.documentElement.lang = next === 'pt' ? 'pt-BR' : 'en';
|
|
buttons.forEach((button) => {
|
|
const isActive = button.dataset.lang === next;
|
|
button.classList.toggle('active', isActive);
|
|
button.setAttribute('aria-pressed', String(isActive));
|
|
});
|
|
document.querySelectorAll<HTMLElement>('[data-language-content]').forEach((node) => {
|
|
node.hidden = node.dataset.languageContent !== next;
|
|
});
|
|
window.dispatchEvent(
|
|
new CustomEvent('ai-for-dummies:languagechange', { detail: { language: next } }),
|
|
);
|
|
}
|
|
|
|
function selectLanguage(value: string | undefined): Language {
|
|
return value === 'pt' ? 'pt' : 'en';
|
|
}
|
|
|
|
buttons.forEach((button) => {
|
|
button.addEventListener('click', () => {
|
|
const language = selectLanguage(button.dataset.lang);
|
|
renderLanguage(language);
|
|
try {
|
|
localStorage.setItem('ai-for-dummies-language', language);
|
|
} catch {
|
|
// Preview environments can disable storage.
|
|
}
|
|
});
|
|
});
|
|
|
|
let savedLanguage = 'en';
|
|
try {
|
|
savedLanguage = localStorage.getItem('ai-for-dummies-language') || 'en';
|
|
} catch {
|
|
// Preview environments can disable storage.
|
|
}
|
|
renderLanguage(selectLanguage(savedLanguage));
|
|
}
|
|
|
|
document.querySelectorAll<HTMLElement>('[data-language-toggle]').forEach((root) => {
|
|
if ('requestIdleCallback' in window) {
|
|
window.requestIdleCallback(() => setup(root));
|
|
} else {
|
|
setTimeout(() => setup(root), 0);
|
|
}
|
|
});
|
|
</script>
|