Middleware and SSR

Use this when multiple pages need translations before rendering or your application uses Node SSR. Complete the tutorial and understand [lang] routes first. Middleware can also run during prerendering.

Load messages in the runtime

For SSR, register messages in application code through this file, instead of relying on the process reading astro.config.mjs. Keep both tutorial JSON files. Remove messages and its imports from the configuration when switching to this approach.

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

const messages = { en, es };

export default defineRequestConfig(async (locale) => {
  if (locale !== "en" && locale !== "es") {
    throw new Error("Unsupported locale: " + locale);
  }
  return { locale, messages: messages[locale] };
});

Initialize before rendering

Create the middleware. If you already have one, combine handlers with sequence from astro:middleware; do not overwrite it. createIntlMiddleware prepares and isolates translations for the entire render of each request.

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

export const onRequest = createIntlMiddleware({
  locales: ["en", "es"],
  defaultLocale: "en",
});

Read translations in the page

With this middleware active, remove setRequestLocale from pages and call getTranslations directly. Keep getStaticPaths for static pages. For on-demand routes, use Astro’s SSR configuration and a compatible Node adapter, and do not export getStaticPaths. Isolation requires AsyncLocalStorage; an SSR runtime without it is unsupported.