Which Router Are You Using?
Before proceeding, determine whether you’re using:
-
Pages Router (pages/) – Uses Next.js’ built-in i18n config for locale detection.
-
App Router (app/) – Requires middleware to determine locales based on domain.
For Pages Router (pages/)
If you’re using the Pages Router, Next.js automatically detects the locale based on the domain (no middleware required).
Update next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
i18n: {
locales: ['en-us', 'fr-fr'],
defaultLocale: 'en-us',
domains: [
{
domain: 'website.com',
defaultLocale: 'en-us',
},
{
domain: 'website.fr',
defaultLocale: 'fr-fr',
}
]
}
};
module.exports = nextConfig;
This automatically detects the locale from the domain and routes pages accordingly.
Fetching Content in pages/[uid].tsx
Next.js provides the locale in context.locale. You can pass it to Prismic when fetching content:
import { GetServerSideProps } from 'next';
import { createClient } from '@/prismicio';
import { SliceZone } from '@prismicio/react';
import { components } from '@/slices';
import { notFound } from 'next/navigation';
type PageProps = {
page: any;
};
export default function Page({ page }: PageProps) {
return (
<main>
<SliceZone slices={page.data.slices} components={components} />
</main>
);
}
// ✅ Fetch the correct locale content from Prismic
export const getServerSideProps: GetServerSideProps = async ({ params, locale }) => {
const client = createClient();
const page = await client.getByUID('page', params?.uid as string, { lang: locale }).catch(() => null);
if (!page) return { notFound: true };
return { props: { page } };
};
Why This Works
• getServerSideProps automatically gets the locale from the request.
• Fetches the correct localized content from Prismic.
• No need for manual locale detection.
Using Localized Links
When linking between pages, use the built-in locale system:
import Link from 'next/link';
import { useRouter } from 'next/router';
export default function Navigation() {
const { locale } = useRouter();
return (
<nav>
<Link href="/" locale="en-us">English</Link>
<Link href="/" locale="fr-fr">Français</Link>
</nav>
);
}
Next.js will automatically switch domains when clicking the links.
For App Router (app/)
If you’re using the App Router, you need middleware to handle locales based on domains since next.config.js won’t do it.
middleware.ts (Required)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const host = request.nextUrl.host;
let locale = 'en-us';
if (host.endsWith('website.fr')) {
locale = 'fr-fr';
}
request.headers.set('x-locale', locale);
return NextResponse.next();
}
export const config = {
matcher: '/((?!_next|static|favicon.ico).*)',
};
This ensures that every request gets the correct locale based on the domain.
Fetching Content in app/page.tsx
Since the params object doesn’t include lang, retrieve it from headers:
import { headers } from 'next/headers';
import { createClient } from '@/prismicio';
import { SliceZone } from '@prismicio/react';
import { components } from '@/slices';
import { notFound } from 'next/navigation';
export default async function Page({ params }: { params: { uid: string } }) {
const client = createClient();
// ✅ Retrieve the locale set by middleware
const locale = headers().get('x-locale') || 'en-us';
const page = await client.getByUID('page', params.uid, { lang: locale }).catch(() => notFound());
return (
<main>
<SliceZone slices={page.data.slices} components={components} />
</main>
);
}
The headers().get('x-locale') ensures the correct locale is used.