| name | next-intl-setRequestLocale-ssg-fix |
| description | Fix for next-intl v4 SSG pages showing wrong locale (typically English fallback)
despite correct build output. Use when: (1) next-intl pages build successfully with
generateStaticParams but render the default locale instead of the expected one,
(2) page metadata (from getTranslations with explicit locale) shows correct locale
but client components show wrong locale, (3) getMessages() returns default locale
messages in [locale] layout/pages. Root cause: missing setRequestLocale() call
before getMessages() in server components with static generation.
|
| author | Claude Code |
| version | 1.0.0 |
| date | "2026-02-15T00:00:00.000Z" |
| tags | next-intl, i18n, SSG, static-generation, Next.js, locale |
next-intl setRequestLocale SSG Fix
Problem
When using next-intl v4+ with Next.js App Router and static generation
(generateStaticParams), locale pages build successfully but render text in the
default locale (typically English) instead of the expected locale. The build
output shows no errors โ pages are generated for all locales โ but at runtime,
all locale variants show identical (default) content.
Context / Trigger Conditions
- Using
next-intl v4.x with Next.js 14/15 App Router
- Pages use
generateStaticParams() to pre-render locale variants
[locale] dynamic segment in the app directory
- Symptom 1: Build succeeds, locale pages are listed in build output (e.g.,
/zh-CN, /zh-TW)
- Symptom 2: Page
<title> may show correct locale (if generateMetadata passes locale explicitly via getTranslations({ locale }))
- Symptom 3: Client component text (from
useTranslations()) shows default locale
- Symptom 4:
getMessages() in layout returns default locale messages
- No error messages โ the fallback is silent
Especially likely when:
- Using a custom middleware (not
createMiddleware from next-intl/middleware)
- The middleware handles auth (e.g., Supabase) alongside locale detection
Root Cause
During static site generation (SSG), there is no HTTP request context. The
requestLocale parameter in getRequestConfig resolves to undefined because
no middleware sets the x-next-intl-locale header, and there's no live request
to extract the locale from.
When requestLocale is undefined, the getRequestConfig function typically
falls back to the default locale:
export default getRequestConfig(async ({ requestLocale }) => {
let locale = await requestLocale;
if (!locale || !locales.includes(locale)) {
locale = 'en';
}
});
This means getMessages() always returns default locale messages during SSG.
Solution
Call setRequestLocale(locale) in every server component (layout and page)
that uses next-intl server functions, before calling getMessages(),
getTranslations(), or any other next-intl/server function.
Fix the layout:
import { getMessages, setRequestLocale } from 'next-intl/server';
export default async function LocaleLayout({ children, params }) {
const { locale } = params;
setRequestLocale(locale);
const messages = await getMessages();
}
Fix every page:
import { setRequestLocale } from 'next-intl/server';
export default function LocalePage({ params }) {
setRequestLocale(params.locale);
return <PageClient />;
}
import { getTranslations, setRequestLocale } from 'next-intl/server';
export default async function LocaleAboutPage({ params }) {
const { locale } = params;
setRequestLocale(locale);
const t = await getTranslations({ locale, namespace: 'about.meta' });
}
Rules:
- Call
setRequestLocale() before any getMessages() or getTranslations() call
- Call it in every layout and page under
[locale]/, not just the layout
- The locale value comes from
params.locale (the route segment)
Verification
- Run
npm run build โ locale pages should still be listed with โ (SSG)
- Run
npm run dev and navigate to a locale page (e.g., /zh-CN)
- Verify client component text renders in the correct locale
- Verify
useTranslations() returns translated strings, not default locale
Why This Is Misleading
- Build succeeds with no warnings about wrong locale
generateMetadata works if it passes locale explicitly: getTranslations({ locale }) โ this bypasses the request context entirely
- Only
getMessages() (no locale param) is affected, because it reads from request context
- The
NextIntlClientProvider receives English messages but is told locale="zh-CN", creating a mismatch where the provider has the right locale but wrong messages
Notes
setRequestLocale is described by next-intl as a "stopgap" until Next.js natively
supports accessing route parameters in all Server Components
- This is especially important when NOT using
createMiddleware from next-intl/middleware
(e.g., when using custom Supabase auth middleware)
- Even when using next-intl's middleware,
setRequestLocale is still recommended for
static rendering support
- The function is synchronous โ no
await needed
References