5.1 KiB
5.1 KiB
Localized SEO hreflang Strategy TODO
Goal
Establish a consistent canonical and hreflang setup for the marketing site so search engines can index German and English content without duplicate-content penalties.
Status (Stand 18.02.2026)
- Discovery: In progress (route audit complete).
- Implementation: In progress (canonical and locale-prefixed routing live).
- Validation: Not started.
Discovery
- Audit current route map and localized content coverage (marketing pages, blog, checkout flow).
- Marketing routes live in
routes/web.phpwithout locale prefixes. Locale handling is session-based viaLocaleController::set,HandleInertiaRequests, anduseLocalizedRoutes. - Slug coverage is mixed:
/contact(EN) and/kontakt(DE) coexist,/how-it-worksvs./so-funktionierts, while other key pages only exist once (e.g./packages,/demo,/blog, legal pages such as/impressumwith no EN variant). Occasion detail routes are German-only (/anlaesse/{type}withhochzeit,geburtstag, etc.). - Blog URLs are shared across locales (
/blog,/blog/{slug}), with translated content injected server-side. Checkout surfaces (/purchase-wizard/{package},/checkout/{package}) rely on shared slugs and localized copy but no alternate URLs. MarketingLayoutcurrently generates a single canonical URL per request and anx-defaultalternate, but no locale-specifichreflanglinks. Canonical calculation removes a/de|/enprefix even though paths are prefix-free, so both locales resolve to the same canonical if we later introduce prefixed URLs.- The sitemap at
public/sitemap.xmlalready lists/de/...and/en/...alternates that the app does not currently serve, causing mismatch risk.
- Marketing routes live in
- Decide on URL strategy (session-based locale vs. language-prefixed routes) and document migration implications.
- Decision: adopt path-prefixed locales (
/{locale}/{slug}) for all marketing and checkout-facing routes, matching the i18n PRP guidance. Default requests (/foo) will 301 to the locale-specific URL using the visitor’s persisted preference ordefallback. - Migration outline:
- Introduce a
SetLocaleFromPathmiddleware to extract the first segment and share it with Inertia; wire it into aRoute::groupwithprefix('{locale}')(constrained tode|en) inroutes/web.php. - Move existing marketing routes into the prefixed group, normalising slugs so EN and DE share identical structures where feasible (e.g.
/de/kontakt→/de/contactor/de/kontaktmirrored by/en/contact). Keep legacy German-only slugs (/so-funktionierts,/anlaesse/...) behind per-locale path maps. - Add legacy fallback routes (without prefix) that permanently redirect to the new prefixed URLs to preserve existing backlinks and sitemap entries.
- Ensure Inertia helpers (
useLocalizedRoutes) and navigation components build URLs with the active locale segment instead of relying on session posts to/set-locale.
- Introduce a
- Blog slugs remain language-agnostic identifiers under
/de/blog/{slug}and/en/blog/{slug}; content localization continues via translated fields.
- Decision: adopt path-prefixed locales (
- Identify required updates to
MarketingLayout, sitemap generation, and Inertia responses for localized alternates.MarketingLayoutneeds to accept structured SEO props (canonical URL, title, description, alternates) instead of deriving everything client-side. It should emit<link rel="alternate" hreflang="">entries for each supported locale plusx-default, setog:locale/og:locale:alternate, and keep canonical URLs locale-specific (no prefix stripping).- Server responses should standardise SEO data via a helper (e.g.
MarketingPage::make()or dedicated view model) so eachInertia::rendercall providesseoprops withcanonical,alternates, and translated meta.HandleInertiaRequestscan sharesupportedLocalesand the resolved host, while a newLocalizedUrlGeneratorservice maps routes/slugs per locale. - The static
public/sitemap.xmlmust be regenerated (or replaced with an automated generator/Artisan command) once prefixed URLs exist, ensuring each entry carries self-referential canonicals and pairedxhtml:linkelements. Include blog detail pages and legal pages for both locales.
Implementation
- Ensure canonical URLs and hreflang tags are generated per locale with reciprocal references.
- Expose locale-specific URLs in navigation, Open Graph tags, and any structured data.
- Update translation files and config to support the chosen URL strategy.
Validation
- Add automated checks (feature test or Playwright) verifying hreflang/canonical tags for both locales.
- Validate via Search Console-style inspection or lighthouse to confirm alternate links render correctly.
- Update docs (PRP + marketing playbooks) with the final hreflang strategy and operational guidance.
Open Questions
- How will we handle locale fallbacks for missing translations when hreflang is enforced?
- Do we need localized sitemap indexes per language or a unified sitemap with hreflang annotations?