Configuración

1. Crear archivos de mensajes

Crea un archivo JSON por locale dentro de src/i18n/messages/. Puedes organizar las claves en namespaces (objetos anidados).

src/i18n/messages/en.json
{
  "nav": {
    "home": "Home",
    "docs": "Documentation"
  },
  "hero": {
    "title": "Hello, World!",
    "description": "Welcome to <bold>astro-intl</bold>"
  }
}

2. Elige tu enfoque

astro-intl ofrece tres formas de cargar mensajes. Elige la que mejor se adapte a tu proyecto.

Si no estás usando createIntlMiddleware, debes pasar defaultLocale y locales directamente en astro.config.mjs para que funciones como getLocales(), getDefaultLocale() e isValidLocale() funcionen correctamente.

Opción A — Messages en config (recomendado)

Pasa tus imports de mensajes junto con defaultLocale y locales directamente en astro.config.mjs. No se necesitan archivos extra.

astro.config.mjs
import { defineConfig } from "astro/config";
import astroIntl from "astro-intl";

export default defineConfig({
  integrations: [
    astroIntl({
      defaultLocale: "en",
      locales: ["en", "es"],
      messages: {
        en: () => import("./src/i18n/messages/en.json"),
        es: () => import("./src/i18n/messages/es.json"),
      },
    }),
  ],
});

Opción B — Custom request.ts (avanzado)

Para control total, usa defineRequestConfig para crear un archivo de request — similar a next-intl. Esto te permite agregar lógica personalizada como obtener mensajes desde un CMS. Todavía necesitas pasar defaultLocale y locales en astro.config.mjs.

src/i18n/request.ts
import { defineRequestConfig } from "astro-intl";

export default defineRequestConfig(async (locale) => {
  return {
    locale,
    messages: (await import(`./messages/${locale}.json`)).default,
  };
});

astro.config.mjs con locales:

astro.config.mjs
import { defineConfig } from "astro/config";
import astroIntl from "astro-intl";

export default defineConfig({
  integrations: [
    astroIntl({
      defaultLocale: "en",
      locales: ["en", "es"],
    }),
  ],
});

Opción C — messagesDir (JSON simplificado)

Configura messagesDir con una ruta de directorio y la integración cargará automáticamente los archivos {locale}.json. No necesitas imports manuales — perfecto para flujos de trabajo basados en JSON.

astro.config.mjs
import { defineConfig } from "astro/config";
import astroIntl from "astro-intl";

export default defineConfig({
  integrations: [
    astroIntl({
      defaultLocale: "en",
      locales: ["en", "es"],
      messagesDir: "./src/i18n/messages",
    }),
  ],
});

3. Configurar tu Layout

Mejor práctica: Llama a setRequestLocale una sola vez en un layout compartido (ej: src/layouts/Layout.astro) en lugar de repetirlo en cada página. Esto inicializa el contexto global de i18n antes de que cualquier componente lea traducciones.

Con Opción A (messages en config):

src/layouts/Layout.astro
---
import { setRequestLocale } from "astro-intl";

// No need to import anything — messages come from astro.config
await setRequestLocale(Astro.url);
---

<!DOCTYPE html>
<html>
  <head>
    <title>My Site</title>
  </head>
  <body>
    <slot />
  </body>
</html>

Con Opción B (defineRequestConfig):

src/layouts/Layout.astro
---
import { setRequestLocale } from "astro-intl";
import "../i18n/request"; // registers defineRequestConfig

await setRequestLocale(Astro.url);
---

<!DOCTYPE html>
<html>
  <head>
    <title>My Site</title>
  </head>
  <body>
    <slot />
  </body>
</html>

3b. Enfoque con Middleware (alternativa)

En lugar de llamar a setRequestLocale en cada layout, puedes usar createIntlMiddleware para manejarlo automáticamente en todas las rutas. Esto también establece locales y defaultLocale en el store, por lo que no necesitas pasarlos en astro.config.mjs.

Crea un archivo de routing:

src/i18n/routing.ts
export const routing = {
  locales: ["en", "es"],
  defaultLocale: "en",
} as const;

Crea el middleware:

src/middleware.ts
import "@/i18n/request";
import { createIntlMiddleware } from "astro-intl/middleware";
import { routing } from "@/i18n/routing";

export const onRequest = createIntlMiddleware(routing);

Tu astro.config.mjs se mantiene simple:

astro.config.mjs
import { defineConfig } from "astro/config";
import astroIntl from "astro-intl";

export default defineConfig({
  integrations: [astroIntl()],
});

4. Exportar getStaticPaths

En cada página [lang], exporta getStaticPaths retornando todos los locales soportados para que Astro pueda pre-renderizarlos.

src/pages/[lang]/index.astro
export function getStaticPaths() {
  return [
    { params: { lang: "en" } },
    { params: { lang: "es" } },
  ];
}