Every .astro file here is a thin routing wrapper: imports a template, passes slug + locale. Zero user-facing text. Enforced by pnpm check:text.
pages/
├── index.astro # German homepage (/)
├── [locale]/index.astro # English homepage (/en/)
├── [slug].astro # CMS catch-all (pages + legal) — EXCEPTION
├── [locale]/[slug].astro # English CMS catch-all — EXCEPTION
├── preview/[...path].astro # SSR Directus preview — EXCEPTION (prerender = false)
├── robots.txt.ts # API route, non-prerendered
├── 404.astro 500.astro # Error pages
├── blog/ news/ podcast/ glossar/ webinare/ autoren/ bayern/ # German dynamic routes
├── [locale]/blog/ [locale]/news/ ... # English dynamic routes
└── *.astro # ~40 German static pages (platform, chatbot, faq, etc.)
/blog, /glossar, /preise/en/ prefix — /en/blog, /en/glossary, /en/pricing[locale]/[locale] pages call getStaticPaths() generating only non-default locales (LOCALES.filter(l => l !== DEFAULT_LOCALE) → ["en"])middleware.ts derives Astro.locals.locale from URL path; global components read it[slug].astro / [locale]/[slug].astro — CMS catch-all. Fetches Directus pages collection directly, renders through PageShell/PageMain. Not a thin wrapper.preview/[...path].astro — SSR preview route (prerender = false). Validates DIRECTUS_PREVIEW_TOKEN, resolves collection/locale from path, renders inline.robots.txt.ts — API route, non-prerendered, generates robots.txt based on hostname.| Task | Location |
|---|---|
| Add a static page (code-owned) | Create <slug>.astro + [locale]/<slug>.astro (thin wrappers) + template + .i18n.ts |
| Add a CMS page | Add row in Directus pages collection — catch-all resolves it automatically |
| Dynamic route static paths | src/utils/paths.ts — getStaticPathsDe / getStaticPathsEn / multi-collection variants |
| Change segment mapping | src/utils/i18n.ts PATH_SEGMENT_MAP (glossar→glossary, autoren→authors, etc.) |
src/components/templates/ and pass slug + locale.[locale]/), both thin wrappers.getStaticPathsDe() for German, getStaticPathsEn() for English — both fetch from Directus.bayern/, bavaria/): hard-coded slugs in getStaticPaths.// text-ok on a line allowlists a specific text exception (only for operational text like preview banners).