i18n URL Routing
The frontend supports translated URL path segments per market language, with automatic middleware rewrites, 301 redirects, and hreflang tag generation.
How It Works
Section titled “How It Works”- File routes use English segment names (e.g.,
pages/[market]/destinations/[country].astro) - Middleware rewrites translated URLs to the English file route (URL bar stays translated)
- 301 redirects English URLs to translated versions for markets that have translations
- hreflang tags are generated automatically for all markets via
SeoHead.astro
Translation Map
Section titled “Translation Map”Source of truth: frontend/src/shared/config/i18n.ts (SEGMENT_TRANSLATIONS)
| English (file route) | ES |
|---|---|
destinations | destinos |
regions | regiones |
about-us | sobre-nosotros |
terms | terminos-condiciones |
privacy-policy | politica-privacidad |
collections | colecciones |
Markets without a translation entry (DE, US, UK, CA) use the English segment as-is. Only the first path segment (the page type) is translated — slugs like country names stay the same across all markets.
Middleware Behavior
Section titled “Middleware Behavior”Source: frontend/src/middleware.ts
For a request like /es/destinos/argentina:
- Middleware identifies the market (
es) and first content segment (destinos) - Reverse-translates
destinostodestinationsusingREVERSE_TRANSLATIONS - Stashes original path in
context.locals.originalPath(used bySeoHead.astrofor hreflang) - Rewrites to
/es/destinations/argentina(Astro file route)
For a request like /es/destinations/argentina (English segment on a translated market):
- Middleware detects that
destinationshas a Spanish translationdestinos - Issues a 301 redirect to
/es/destinos/argentina
This ensures each page has one canonical URL per market.
Building Links with localizedPath()
Section titled “Building Links with localizedPath()”Always use localizedPath() for internal links. Never hardcode translated segments.
Parameters:
market— Market code (es,de,us,uk,ca)englishPath— Path with English segments, without market prefix (e.g.,/destinations/argentina)
Examples:
localizedPath("es", "/destinations/argentina")returns/es/destinos/argentinalocalizedPath("us", "/destinations/argentina")returns/us/destinations/argentinalocalizedPath("es", "/about-us")returns/es/sobre-nosotros
Source: frontend/src/shared/config/i18n.ts
When NOT to Use localizedPath()
Section titled “When NOT to Use localizedPath()”- Product pages (PDP): URLs come from the backend API via
tour_path_slugs. The catch-all route[...path].astrohandles these. - Checkout pages:
/{market}/checkout/{offerId}/...— not translated. - Auth/account pages:
/login,/my-account— not market-scoped.
hreflang and Canonical Tags
Section titled “hreflang and Canonical Tags”The SeoHead.astro component generates hreflang and canonical tags automatically. It is included in PublicLayout and MainLayout.
For every page, it outputs:
<link rel="canonical">for the current market’s translated URL<link rel="alternate" hreflang="es-ES">pointing to the ES translated URL<link rel="alternate" hreflang="de-DE">pointing to the DE URL<link rel="alternate" hreflang="en-US">pointing to the US URL<link rel="alternate" hreflang="en-GB">pointing to the UK URL<link rel="alternate" hreflang="en-CA">pointing to the CA URL<link rel="alternate" hreflang="x-default">pointing to the ES URL (international fallback)
All URLs use the production domain https://byvolare.com.
Source: frontend/src/shared/ui/SeoHead.astro
Supported Markets
Section titled “Supported Markets”| Market | HTML lang | API lang | URL segment behavior |
|---|---|---|---|
es | es-ES | es | Translated (Spanish segments) |
de | de-DE | de | English fallback |
us | en-US | en | English |
uk | en-GB | en | English |
ca | en-CA | en | English |
Source: frontend/src/shared/config/markets.ts
Adding a New Page
Section titled “Adding a New Page”- Create the file route in English:
pages/[market]/new-page.astro - Add a translation to
SEGMENT_TRANSLATIONSinfrontend/src/shared/config/i18n.tsif the page needs translated URLs - Middleware automatically handles rewrites and 301 redirects
- Use
localizedPath()in all links to the new page - hreflang tags generate automatically via
SeoHead.astro
Adding a New Market
Section titled “Adding a New Market”Adding a new market requires more than updating SEGMENT_TRANSLATIONS.
Required steps:
- Add the market code to
SUPPORTED_MARKETSinfrontend/src/shared/config/markets.ts - Add its API language to
MARKET_API_LANG - Add its HTML hreflang value to
MARKET_HTML_LANG - Add translated first-segment entries to
SEGMENT_TRANSLATIONSif the market should not use English fallback segments - Search for page-level market allowlists or assumptions outside shared config before finishing
The translation reverse-lookup map builds automatically from SEGMENT_TRANSLATIONS, so no extra middleware code is needed for first-segment rewrites once the market and translation config are in place.
Related
Section titled “Related”- Frontend Overview — full frontend architecture
- Market config:
frontend/src/shared/config/markets.ts - i18n config:
frontend/src/shared/config/i18n.ts - Middleware:
frontend/src/middleware.ts - SEO component:
frontend/src/shared/ui/SeoHead.astro