Routing
astro-intl provee un sistema de routing que te permite definir rutas URL traducidas para cada locale. Esto permite URLs localizadas como /es/sobre-nosotros en lugar de /es/about.
1. Define tus rutas
Agrega un mapa de routes a tu configuración de routing. Cada clave es un nombre de ruta, y cada valor mapea locales a sus templates de URL. Usa [param] para segmentos dinámicos.
export const routing = {
locales: ["en", "es"],
defaultLocale: "en",
routes: {
home: { en: "/", es: "/" },
about: { en: "/about", es: "/sobre-nosotros" },
blog: { en: "/blog/[slug]", es: "/blog/[slug]" },
shop: { en: "/shop/[category]/[id]", es: "/tienda/[category]/[id]" },
},
} as const;2a. Con Middleware (recomendado)
Cuando usas createIntlMiddleware, pasa tus rutas en la config. El middleware automáticamente reescribirá las URLs traducidas a sus rutas canónicas del filesystem — sin archivos de página extra.
Pasa las rutas al middleware:
import "@/i18n/request";
import { createIntlMiddleware } from "astro-intl/middleware";
import { routing } from "@/i18n/routing";
export const onRequest = createIntlMiddleware(routing);Tu filesystem solo necesita las rutas del locale por defecto:
src/pages/
└── [lang]/
├── index.astro ← /en/ and /es/
├── about.astro ← /en/about and /es/sobre-nosotros
├── blog/
│ └── [slug].astro ← /en/blog/my-post and /es/blog/mi-post
└── shop/
└── [category]/
└── [id].astro ← /en/shop/clothing/42 and /es/tienda/clothing/42/es/sobre-nosotros, el middleware lo matchea contra el mapa de routes, encuentra el template canónico (/about) y reescribe la petición a /es/about — que mapea a tu archivo [lang]/about.astro. Sin páginas duplicadas. 2b. Sin Middleware
Si prefieres no usar middleware, aún puedes usar path() y switchLocalePath() para generación de URLs. Configura las rutas via las opciones de la integración.
import { defineConfig } from "astro/config";
import astroIntl from "astro-intl";
export default defineConfig({
integrations: [
astroIntl({
defaultLocale: "en",
locales: ["en", "es"],
routes: {
about: { en: "/about", es: "/sobre-nosotros" },
blog: { en: "/blog/[slug]", es: "/blog/[slug]" },
},
}),
],
});Ejemplo: Routing nativo de Astro para rutas traducidas
Crea un archivo de página para cada URL traducida. Estas páginas "wrapper" simplemente re-exportan todo desde la página canónica (locale por defecto) — cero duplicación.
Tu página canónica (rutas del locale por defecto):
---
import Layout from "@/layouts/Layout.astro";
import { getTranslations } from "astro-intl";
const t = getTranslations("about");
export function getStaticPaths() {
return [
{ params: { lang: "en" } },
{ params: { lang: "es" } },
];
}
---
<Layout title={t("title")}>
<h1>{t("heading")}</h1>
<p>{t("description")}</p>
</Layout>Crea la ruta traducida como un wrapper ligero:
---
// Re-export everything from the canonical page
export { default } from "./about.astro";
export { getStaticPaths } from "./about.astro";
---Estructura de archivos resultante:
src/pages/[lang]/
├── about.astro ← Canonical page (all the logic)
├── sobre-nosotros.astro ← Wrapper (2 lines, re-exports about.astro)
├── blog/
│ └── [slug].astro ← Same URL structure, no wrapper needed
└── shop/
└── [category]/
└── [id].astro ← Canonical for /shop/:category/:id
src/pages/[lang]/tienda/
└── [category]/
└── [id].astro ← Wrapper (re-exports ../shop/[category]/[id].astro)/es/sobre-nosotros, renderiza el mismo componente que /es/about — la URL traducida funciona sin middleware. 3. Generando URLs con path()
Usa path(routeKey, options?) para generar URLs localizadas. Escoge el template correcto para el locale destino y sustituye cualquier param.
---
import { path } from "astro-intl/routing";
---
<!-- Simple route -->
<a href={path("about")}>About</a>
<!-- Current locale "en" → /en/about -->
<!-- Current locale "es" → /es/sobre-nosotros -->
<!-- Explicit locale -->
<a href={path("about", { locale: "es" })}>Sobre nosotros</a>
<!-- → /es/sobre-nosotros -->
<!-- With params -->
<a href={path("blog", { params: { slug: "hello-world" } })}>Read post</a>
<!-- → /en/blog/hello-world -->
<!-- Multiple params -->
<a href={path("shop", { locale: "es", params: { category: "ropa", id: "42" } })}>
Ver producto
</a>
<!-- → /es/tienda/ropa/42 -->4. Cambiando locale con switchLocalePath()
Usa switchLocalePath(currentPath, nextLocale) para convertir la URL actual a su equivalente en otro locale. Matchea la ruta contra los templates, extrae los params y reconstruye la URL con el template del locale destino.
---
import { switchLocalePath } from "astro-intl/routing";
const currentPath = Astro.url.pathname;
---
<nav>
<a href={switchLocalePath(currentPath, "en")}>English</a>
<a href={switchLocalePath(currentPath, "es")}>Español</a>
</nav>
<!-- On /en/about → switches to /es/sobre-nosotros -->
<!-- On /es/tienda/ropa/42 → switches to /en/shop/ropa/42 -->
<!-- On /en/unknown/page → falls back to /es/unknown/page -->switchLocalePath hace fallback a simplemente intercambiar el prefijo del locale. Parámetros Dinámicos
Los templates de rutas soportan segmentos dinámicos con sintaxis [param]. Puedes tener múltiples params por ruta — se extraen y sustituyen automáticamente.
import { path } from "astro-intl/routing";
// Route defined as:
// shop: { en: "/shop/[category]/[id]", es: "/tienda/[category]/[id]" }
const url = path("shop", {
locale: "es",
params: { category: "electronics", id: "123" },
});
// → /es/tienda/electronics/123Rutas Fallback (Astro 6.1+)
A partir de Astro 6.1, la integración detecta automáticamente las fallbackRoutes del hook astro:routes:resolved. Cuando configuras i18n.fallbackType: 'rewrite' en tu config de Astro, Astro genera rutas fallback para locales que no tienen su propio contenido. astro-intl las recopila y las hace disponibles via getFallbackRoutes().
Consulta las rutas fallback en tiempo de ejecución:
---
import { getFallbackRoutes } from "astro-intl";
const fallbacks = getFallbackRoutes();
// [
// { pattern: "/fr/about", pathname: "/fr/about/", locale: "fr" },
// { pattern: "/fr/blog/[...slug]", locale: "fr" },
// ]
// Example: check if the current page has a fallback for a locale
const hasFrenchFallback = fallbacks.some(fb => fb.locale === "fr");
---getFallbackRoutes() retorna un array vacío — sin errores, totalmente compatible hacia atrás.