Skip to main content

De complete handleiding voor internationalisering in Next.js

Configureer next-intl met de App Router, stel locale-routering in en automatiseer vertalingen met AI.

1

next-intl installeren

next-intl is één pakket dat locale-routering, het laden van berichten en vertaalhooks voor de Next.js App Router afhandelt.

Terminal
npm install next-intl
Waarom next-intl in plaats van next-i18next? next-intl is ontwikkeld voor de App Router en servercomponenten. next-i18next is ontworpen voor de Pages Router en ondersteunt de App Router slechts beperkt.
2

De i18n-aanvraagconfiguratie maken

Maak twee bestanden: src/i18n/request.ts voor het laden van berichten en src/i18n/routing.ts voor locale-definities. Hiermee stel je in hoe next-intl berichten en routes bepaalt.

src/i18n/routing.ts
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';

export const routing = defineRouting({
  locales: ['en', 'de', 'ja', 'es'],
  defaultLocale: 'en',
  localePrefix: 'as-needed',  // /about for en, /de/about for de
});

export const { Link, redirect, usePathname, useRouter } =
  createNavigation(routing);
Turbopack (de standaardbundler in Next.js 15) vereist experimental.turbo.resolveAlias in je next.config.js. Zonder deze instelling krijg je de foutmelding "Couldn't find next-intl config file".
3

Middleware configureren

Voeg middleware.ts toe om localedetectie, het herschrijven van URL's en omleidingen af te handelen. De middleware onderschept elke aanvraag en zorgt dat de juiste locale wordt toegepast.

middleware.ts
// middleware.ts  <- Must be in project ROOT, not src/
import createMiddleware from 'next-intl/middleware';
import { routing } from './src/i18n/routing';

export default createMiddleware(routing);

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
};
middleware.ts MOET in de hoofdmap van je project staan, niet in src/. Dit is veruit de meest voorkomende configuratiefout met next-intl.
4

De mapstructuur [locale] instellen

Verplaats je app-routes naar app/[locale]/. Voeg generateStaticParams toe om tijdens het bouwen pagina's voor elke locale te genereren. Zo ontstaat de URL-structuur /en/about, /de/about enz.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx
import { routing } from '@/i18n/routing';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}
Je MOET setRequestLocale(locale) aanroepen in elk bestand page.tsx en layout.tsx dat vertalingen gebruikt. Anders valt Next.js terug op dynamische rendering en nemen de buildprestaties aanzienlijk af.
5

Je hoofdlay-out bijwerken

Laad berichten met getMessages() en geef ze in de hoofdlay-out voor locales door aan NextIntlClientProvider. Stel het html-attribuut lang in op basis van de locale-parameter.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing';
import { notFound } from 'next/navigation';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  const { locale } = await params;
  if (!routing.locales.includes(locale as any)) notFound();

  setRequestLocale(locale);
  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider locale={locale} messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}
NextIntlClientProvider vereist een expliciete locale-prop. Als je die weglaat, ontstaan er subtiele fouten in clientcomponenten die lastig te debuggen zijn.
6

Vertalingen in componenten gebruiken

Servercomponenten gebruiken getTranslations (async, await). Clientcomponenten gebruiken useTranslations (hook). Kies op basis van waar je component wordt gerenderd — met servercomponenten blijven vertalingen volledig buiten de JavaScript-bundel.

app/[locale]/page.tsx
// Server Component (default)
import { getTranslations, setRequestLocale } from 'next-intl/server';

export default async function AboutPage({
  params,
}: { params: { locale: string } }) {
  const { locale } = await params;
  setRequestLocale(locale);
  const t = await getTranslations('AboutPage');

  return <h1>{t('title')}</h1>;
}

// Client Component ('use client')
'use client';
import { useTranslations } from 'next-intl';

export default function SearchBar() {
  const t = useTranslations('SearchBar');
  return <input placeholder={t('placeholder')} />;
}
Geef voorrang aan servercomponenten voor vertaalde inhoud. Daarmee blijven vertaalteksten buiten de JavaScript-clientbundel en laden pagina's sneller voor gebruikers.
7

SEO toevoegen: metadata en hreflang

Gebruik generateMetadata om paginaspecifieke titels en beschrijvingen per locale te maken. Voeg alternates.languages toe voor hreflang-tags, zodat zoekmachines alle taalversies van elke pagina vinden.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx or any page.tsx
import { getTranslations } from 'next-intl/server';
import { routing } from '@/i18n/routing';

export async function generateMetadata({
  params,
}: { params: { locale: string } }) {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: 'Metadata' });

  return {
    title: t('title'),
    description: t('description'),
    alternates: {
      languages: Object.fromEntries(
        routing.locales.map((l) => [l, `/${l}`])
      ),
    },
  };
}
Op Vercel kunnen builds localhost als canonieke URL genereren als metadataBase niet is ingesteld. Stel metadataBase in je hoofdlay-out altijd in op je productiedomein.
8

Fout- en niet-gevondenpagina's afhandelen

error.tsx en not-found.tsx vereisen speciale verwerking, omdat ze buiten de normale locale-lay-out kunnen worden gerenderd. Het bestand not-found.tsx in de hoofdmap heeft een eigen configuratie van de i18n-provider nodig om gelokaliseerde foutmeldingen te tonen.

app/[locale]/error.tsx
// app/[locale]/error.tsx
'use client';
import { useTranslations } from 'next-intl';

export default function Error() {
  const t = useTranslations('Error');
  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}

// app/not-found.tsx (root level -- needs own provider)
import { routing } from '@/i18n/routing';

export default async function GlobalNotFound() {
  return (
    <html lang={routing.defaultLocale}>
      <body>
        <h1>404 - Page Not Found</h1>
      </body>
    </html>
  );
}
Next.js rendert je gelokaliseerde 404-pagina alleen wanneer notFound() expliciet in je code wordt aangeroepen. Onbekende routes zonder overeenkomende pagina tonen de standaard-404 van Next.js, niet je gelokaliseerde versie.
9

Vertalingen automatiseren

Zodra je i18n-configuratie klaar is, vertaal je berichtbestanden rechtstreeks vanuit je IDE met AI of gebruik je de i18n Agent CLI in je CI/CD-pipeline om bij elke implementatie automatisch te vertalen.

Terminal
# In your IDE, ask your AI assistant:
> Translate messages/en.json to German, Japanese, and Spanish

✓ messages/de.json created (1.1s)
✓ messages/ja.json created (1.4s)
✓ messages/es.json created (1.0s)
Gebruik next-intl-localechain voor intelligente locale-fallbacks — een gebruiker die pt-BR gebruikt, ziet dan vertalingen voor pt-PT in plaats van Engelse fallbackteksten als Braziliaans-Portugees niet beschikbaar is.

De vertaalkwaliteit automatisch bewaken

Spoor vóór de release ontbrekende sleutels en defecte placeholders op met i18n-validate. Test je gebruikersinterface met pseudovertaalde teksten uit i18n-pseudo voordat de echte vertalingen klaar zijn.

Opensourcetools voor i18n in Next.js

Deze opensourcepakketten lossen veelvoorkomende knelpunten in internationaliseringsworkflows voor Next.js op.

next-intl-localechain

Standaard valt next-intl bij een ontbrekende vertaling rechtstreeks terug op je standaardlocale. Een gebruiker die Braziliaans-Portugees gebruikt, ziet daardoor Engels in plaats van prima vertalingen voor pt-PT. next-intl-localechain voegt intelligente fallbackketens toe en voegt vertalingen uit verwante locales recursief samen, zodat regionale gebruikers altijd de best passende beschikbare vertaling zien.

src/i18n/request.ts
import { getRequestConfig } from 'next-intl/server';
import { withLocaleChain } from 'next-intl-localechain';

export default getRequestConfig(withLocaleChain({
  loadMessages: (locale) =>
    import(`../../messages/${locale}.json`).then(m => m.default),
  defaultLocale: 'en'
}));
Voegt vertalingen uit locale-ketens automatisch recursief samen
Ingebouwde ketens voor onder meer Portugees, Spaans, Frans en Duits
Slaat ontbrekende berichtbestanden zonder fouten over
Configuratie in één regel — verpakt je bestaande getRequestConfig
Bekijken op GitHub

@i18n-agent/cli

Een opdrachtregeltool waarmee je berichtbestanden voor Next.js vertaalt zonder de terminal te verlaten. Vertaal bestanden rechtstreeks, controleer de taakstatus en download resultaten. Werkt in CI/CD-pipelines met authenticatie via een API-sleutel voor volledig geautomatiseerde lokalisatieworkflows.

Terminal
# Install the CLI
npm install -g @i18n-agent/cli

# Authenticate
i18nagent login

# Translate your message files
i18nagent translate ./messages/en.json --lang de,ja,es

# Or use in CI/CD with an API key
export I18N_AGENT_API_KEY=your-key-here
i18nagent translate ./messages/en.json --lang de,ja,es
Vertaal JSON, YAML, PO en andere i18n-bestandsindelingen vanuit de terminal
Klaar voor CI/CD — authenticatie via een omgevingsvariabele voor geautomatiseerde pipelines
Volg de taakstatus, hervat mislukte taken en download resultaten
Machineleesbare JSON-uitvoer voor scripts en automatisering
Bekijken op GitHub

Veelvoorkomende valkuilen

"Unable to find next-intl locale"

De middleware kwam niet overeen met de aanvraag. Controleer het volgende: staat middleware.ts in de hoofdmap van het project? Sluit het matcherpatroon statische bestanden correct uit? Is de locale opgenomen in je routeringsconfiguratie?

Onverwachte dynamische rendering

setRequestLocale(locale) ontbreekt op een pagina of in een lay-out. Zonder deze aanroep gebruikt next-intl headers of cookies om de locale te detecteren. Dit dwingt dynamische rendering af en verhindert statische generatie.

Parallelle routes werken niet met i18n

Parallelle routes (@modal) en onderscheppende routes ((.)photo) zijn niet volledig compatibel met het dynamische segment [locale]. Gebruik routering via middleware als tijdelijke oplossing voor deze geavanceerde routeringspatronen.

Bij het wisselen van taal gaat de huidige route verloren

Behoud bij het wisselen van locale het huidige pad met usePathname() en vervang alleen het locale-segment. Let op met dynamische routeparameters: die moeten voor de nieuwe locale opnieuw worden bepaald.

Aanbevolen bestandsstructuur

Project Structure
my-nextjs-app/
├── middleware.ts              # Locale routing (project root!)
├── next.config.mjs
├── messages/
│   ├── en.json                # Source messages
│   ├── de.json
│   └── ja.json
├── src/
│   ├── i18n/
│   │   ├── request.ts         # Message loading config
│   │   └── routing.ts         # Locale definitions
│   └── app/
│       └── [locale]/
│           ├── layout.tsx     # Root locale layout
│           ├── page.tsx       # Home page
│           ├── error.tsx      # Localized error page
│           ├── not-found.tsx  # Localized 404
│           └── about/
│               └── page.tsx
└── package.json

Probeer i18n Agent nu

Zet je vertaalbestand hier neer

JSON, YAML, PO, XML, CSV, Markdown, Properties

of klik om een bestand te selecteren

Doeltalen

Geen registratie nodigDirecte prijsindicatie

Locale-fallback met next-intl-localechain

Als een vertaalsleutel ontbreekt in een regionale locale zoals pt-BR, springt next-intl meteen naar de standaardlocale zonder eerst de bovenliggende locale pt te controleren.

Terminal
npm install next-intl-localechain
Configuration
import { withLocaleChain } from 'next-intl-localechain';

export default withLocaleChain({
  fallbacks: {
    'pt-BR': ['pt', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
  },
  defaultLocale: 'en',
  loadMessages: (locale) => import(`./messages/${locale}.json`),
});

Bekijk onze handleiding voor locale-fallbacks voor de volledige lijst met ondersteunde frameworks en 75 ingebouwde ketens. Learn more →

Veelgestelde vragen