From 59bbff0ad9c0cfd2a91164dd0c70ea61d5978674 Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sat, 5 Sep 2026 17:44:20 +0000 Subject: [PATCH 1/3] feat: add full-guide language toggle 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. --- .agents/context/content-i18n.md | 40 ++++++++++++ src/components/islands/LanguageToggle.astro | 68 +++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 .agents/context/content-i18n.md create mode 100644 src/components/islands/LanguageToggle.astro diff --git a/.agents/context/content-i18n.md b/.agents/context/content-i18n.md new file mode 100644 index 0000000..746be5d --- /dev/null +++ b/.agents/context/content-i18n.md @@ -0,0 +1,40 @@ +# Context: full-guide language switching + +## Decision + +The Astro full guide keeps the current client-side language switch on its +existing `/full-guide/` URL. It server-renders both locale variants and the +language-toggle island shows the selected variant after `client:idle` hydration. + +This deliberately preserves the current no-URL-change contract, including links +shared without a locale segment, and avoids a route/redirect and publishing +change. The cost is duplicated localized HTML and both locales in the response. +That is acceptable for this small guide and avoids sending duplicated string +data through every interactive island. + +## Markup and island contract for task 15d + +- Render each static localized fragment twice. Put `data-language-content="en"` + or `data-language-content="pt"` on its outer element. English is visible in + server HTML; the toggle uses the native `hidden` attribute for the inactive + locale. +- Add `` to the guide top bar. Astro's `client:idle` directive + is only valid for framework components; this `.astro` island defers its + browser setup with `requestIdleCallback` (and a timeout fallback) instead. Do + not hydrate the page or use `client:load`; the control is deliberately + idle-priority. +- The island owns the `ai-for-dummies-language` localStorage key. Every read and + write remains inside `try`/`catch`, because previews may disable storage. +- On each selection the island sets `` to `en` or `pt-BR`, updates + its `[data-lang]` buttons' `.active` class and `aria-pressed` state, updates + `[data-language-content]`, then dispatches `ai-for-dummies:languagechange` on + `window`. The event detail is `{ language: 'en' | 'pt' }`. +- The guide selector island (15a) must read `document.documentElement.lang` when + it hydrates and listen for that event. On receipt it must re-render the + currently active phase and all active selector panels from their collection + data. This preserves today’s `applyLanguage` behaviour without coupling the + toggle to page selectors. + +This is a page-local contract: the existing `/rules/` toggle continues using its +own `rules-language` key and must not be changed as part of full-guide +migration. diff --git a/src/components/islands/LanguageToggle.astro b/src/components/islands/LanguageToggle.astro new file mode 100644 index 0000000..f44f7fa --- /dev/null +++ b/src/components/islands/LanguageToggle.astro @@ -0,0 +1,68 @@ +--- +// 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. +--- + +
+ + / + +
+ + From 6ec1e31ec529cad14e9543e904b6e735ee6edbbe Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sat, 5 Sep 2026 17:44:20 +0000 Subject: [PATCH 2/3] feat(guide): add shared selector island Add one client-visible controller for the nine full-guide selectors. Keep static shells and page migration out of scope. --- src/components/islands/GuideSelector.astro | 283 +++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 src/components/islands/GuideSelector.astro diff --git a/src/components/islands/GuideSelector.astro b/src/components/islands/GuideSelector.astro new file mode 100644 index 0000000..42e4528 --- /dev/null +++ b/src/components/islands/GuideSelector.astro @@ -0,0 +1,283 @@ +--- +// GuideSelector — one client:visible controller for the nine independent +// selectors on /full-guide/. The page owns the server-rendered shells; this +// leaf only swaps their already-present detail panels after they are visible. + +interface Localized { + en: string; + pt: string; +} +interface GuideSelectorData { + phases: Record; + workers: Record; + trees: Record; + routes: Record; + providers: Record< + string, + { + label: string; + source: string; + title: Localized; + copy: Localized; + tiers: [string, string, Localized][]; + config: string; + } + >; + efforts: Record; + skillFiles: Record; + skillWorkflow: Record< + string, + { + number: string; + title: Localized; + question: Localized; + action: Localized; + output: Localized; + proof: Localized; + } + >; + commonSkills: Record< + string, + { + number: string; + kind: Localized; + title: string; + rule: Localized; + use: Localized; + example: Localized; + caution: Localized; + source: string; + } + >; + labels: { + context: Localized; + owner: Localized; + reasoningLoad: Localized; + officialSource: Localized; + skillFileHint: Localized; + workflow: { question: Localized; action: Localized; artifact: Localized; proof: Localized }; + commonSkill: { + whenToUse: Localized; + example: Localized; + watchOut: Localized; + source: Localized; + }; + }; +} +interface Props { + /** The page root that contains the nine static selector shells. */ + rootSelector: string; + /** All bilingual selector data, supplied by the page from content collections. */ + data: GuideSelectorData; +} +const { rootSelector, data } = Astro.props; +--- + + + + + + + From 7a1211ac5f9db98bfe25866cb3e35b0cc7e29254 Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sat, 5 Sep 2026 17:50:48 +0000 Subject: [PATCH 3/3] fix(guide): match 15c event name and the legacy focus ring The island listened for `ai-for-dummies:language-change` on `document`, but task 15c dispatches `ai-for-dummies:languagechange` on `window`. Window events do not reach a document listener, so that path was dead; only the `` MutationObserver was firing. The focus ring was `3px solid var(--red)` at `outline-offset: 2px`, applied globally to every button on the page. `responsive.css` uses gold at offset -3px for exactly these nine groups. Restored, and scoped to them. --- src/components/islands/GuideSelector.astro | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/islands/GuideSelector.astro b/src/components/islands/GuideSelector.astro index 42e4528..1c2dc67 100644 --- a/src/components/islands/GuideSelector.astro +++ b/src/components/islands/GuideSelector.astro @@ -260,7 +260,7 @@ const { rootSelector, data } = Astro.props; new MutationObserver((changes) => { if (changes.some((change) => change.attributeName === 'lang')) renderAll(); }).observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] }); - document.addEventListener('ai-for-dummies:language-change', renderAll); + window.addEventListener('ai-for-dummies:languagechange', renderAll); renderAll(); } if ('IntersectionObserver' in window) { @@ -276,8 +276,19 @@ const { rootSelector, data } = Astro.props;