Menu

Internationalisierung

Next.js ermöglicht es Ihnen, das Routing und die Darstellung von Inhalten zur Unterstützung mehrerer Sprachen zu konfigurieren. Die Anpassung Ihrer Website an verschiedene Gebietsschemas umfasst übersetzte Inhalte (Lokalisierung) und internationalisierte Routen.

Terminologie

  • Gebietsschema: Ein Identifikator für einen Satz von Sprach- und Formatierungseinstellungen. Dies umfasst in der Regel die bevorzugte Sprache des Benutzers und möglicherweise seine geografische Region.
    • en-US: Englisch wie in den Vereinigten Staaten gesprochen
    • nl-NL: Niederländisch wie in den Niederlanden gesprochen
    • nl: Niederländisch, keine spezifische Region

Routing-Übersicht

Es wird empfohlen, die Spracheinstellungen des Benutzers im Browser zu verwenden, um das zu verwendende Gebietsschema auszuwählen. Eine Änderung der bevorzugten Sprache ändert den eingehenden Accept-Language-Header Ihrer Anwendung.

Zum Beispiel können Sie mit folgenden Bibliotheken einen eingehenden Request untersuchen, um zu bestimmen, welches Gebietsschema basierend auf den Headers, den zu unterstützenden Gebietsschemen und dem Standardgebietsschema ausgewählt werden soll.

middleware.js
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
 
let headers = { 'accept-language': 'en-US,en;q=0.5' }
let languages = new Negotiator({ headers }).languages()
let locales = ['en-US', 'nl-NL', 'nl']
let defaultLocale = 'en-US'
 
match(languages, locales, defaultLocale) // -> 'en-US'

Das Routing kann entweder durch Unterpfad (/fr/products) oder Domäne (my-site.fr/products) internationalisiert werden. Mit diesen Informationen können Sie den Benutzer nun basierend auf dem Gebietsschema in der Middleware weiterleiten.

middleware.js
import { NextResponse } from "next/server";
 
let locales = ['en-US', 'nl-NL', 'nl']
 
// Bevorzugtes Gebietsschema abrufen, ähnlich wie oben oder mit einer Bibliothek
function getLocale(request) { ... }
 
export function middleware(request) {
  // Prüfen, ob ein unterstütztes Gebietsschema im Pfadnamen vorhanden ist
  const { pathname } = request.nextUrl
  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  )
 
  if (pathnameHasLocale) return
 
  // Weiterleiten, wenn kein Gebietsschema vorhanden ist
  const locale = getLocale(request)
  request.nextUrl.pathname = `/${locale}${pathname}`
  // z.B. eingehende Anfrage ist /products
  // Die neue URL ist jetzt /en-US/products
  return NextResponse.redirect(request.nextUrl)
}
 
export const config = {
  matcher: [
    // Alle internen Pfade (_next) überspringen
    '/((?!_next).*)',
    // Optional: nur auf Root (/) URL ausführen
    // '/'
  ],
}

Stellen Sie schließlich sicher, dass alle speziellen Dateien innerhalb von app/ unter app/[lang] verschachtelt sind. Dies ermöglicht es dem Next.js-Router, verschiedene Gebietsschemas in der Route dynamisch zu behandeln und den lang-Parameter an jedes Layout und jede Seite weiterzuleiten. Zum Beispiel:

app/[lang]/page.js
// Sie haben jetzt Zugriff auf das aktuelle Gebietsschema
// z.B. /en-US/products -> `lang` ist "en-US"
export default async function Page({ params: { lang } }) {
  return ...
}

Das Root-Layout kann ebenfalls in den neuen Ordner verschachtelt werden (z.B. app/[lang]/layout.js).

Lokalisierung

Das Ändern der angezeigten Inhalte basierend auf dem bevorzugten Gebietsschema oder Lokalisierung ist nichts Spezifisches für Next.js. Die beschriebenen Muster würden bei jeder Webanwendung gleich funktionieren.

Nehmen wir an, wir möchten sowohl englische als auch niederländische Inhalte in unserer Anwendung unterstützen. Wir könnten zwei verschiedene "Wörterbücher" pflegen, bei denen es sich um Objekte handelt, die uns eine Zuordnung von einem Schlüssel zu einer lokalisierten Zeichenfolge geben. Zum Beispiel:

dictionaries/en.json
{
  "products": {
    "cart": "Add to Cart"
  }
}
dictionaries/nl.json
{
  "products": {
    "cart": "Toevoegen aan Winkelwagen"
  }
}

Wir können dann eine getDictionary-Funktion erstellen, um die Übersetzungen für das angeforderte Gebietsschema zu laden:

app/[lang]/dictionaries.js
import 'server-only'
 
const dictionaries = {
  en: () => import('./dictionaries/en.json').then((module) => module.default),
  nl: () => import('./dictionaries/nl.json').then((module) => module.default),
}
 
export const getDictionary = async (locale) => dictionaries[locale]()

Basierend auf der aktuell ausgewählten Sprache können wir das Wörterbuch in einem Layout oder auf einer Seite abrufen.

app/[lang]/page.js
import { getDictionary } from './dictionaries'
 
export default async function Page({ params: { lang } }) {
  const dict = await getDictionary(lang) // en
  return <button>{dict.products.cart}</button> // Add to Cart
}

Da alle Layouts und Seiten im app/-Verzeichnis standardmäßig Server-Komponenten sind, müssen wir uns keine Sorgen über die Größe der Übersetzungsdateien machen, die unsere Client-seitige JavaScript-Bundle-Größe beeinflussen. Dieser Code wird nur auf dem Server ausgeführt, und nur das resultierende HTML wird an den Browser gesendet.

Statische Generierung

Um statische Routen für eine bestimmte Menge von Gebietsschemen zu generieren, können wir generateStaticParams mit einem beliebigen Layout oder Seite verwenden. Dies kann global sein, zum Beispiel im Root-Layout:

app/[lang]/layout.js
export async function generateStaticParams() {
  return [{ lang: 'en-US' }, { lang: 'de' }]
}
 
export default function Root({ children, params }) {
  return (
    <html lang={params.lang}>
      <body>{children}</body>
    </html>
  )
}

Ressourcen