Menu

Internationalisierung (i18n) Routing

Beispiele

Next.js bietet seit Version v10.0.0 integrierte Unterstützung für internationalisiertes (i18n) Routing. Sie können eine Liste von Locales, das Standard-Locale und domänenspezifische Locales angeben, und Next.js wird das Routing automatisch verwalten.

Die i18n-Routing-Unterstützung soll bestehende i18n-Bibliothekslösungen wie react-intl, react-i18next, lingui, rosetta, next-intl, next-translate, next-multilingual, tolgee, paraglide-next und andere ergänzen, indem Routen und Locale-Parsing vereinfacht werden.

Erste Schritte

Fügen Sie zunächst die i18n-Konfiguration in Ihrer next.config.js-Datei hinzu.

Locales sind UTS-Locale-Bezeichner, ein standardisiertes Format zur Definition von Locales.

Ein Locale-Bezeichner besteht in der Regel aus Sprache, Region und Schrift, getrennt durch einen Bindestrich: Sprache-Region-Schrift. Region und Schrift sind optional. Ein Beispiel:

  • en-US - Englisch wie in den Vereinigten Staaten gesprochen
  • nl-NL - Niederländisch wie in den Niederlanden gesprochen
  • nl - Niederländisch, keine spezifische Region

Wenn das Benutzerlocale nl-BE ist und nicht in Ihrer Konfiguration aufgeführt ist, wird der Benutzer zu nl weitergeleitet, falls verfügbar, andernfalls zum Standard-Locale. Wenn Sie nicht alle Regionen eines Landes unterstützen möchten, ist es daher eine gute Praxis, Länder-Locales einzubeziehen, die als Fallback dienen.

next.config.js
module.exports = {
  i18n: {
    // Dies sind alle Locales, die Sie in
    // Ihrer Anwendung unterstützen möchten
    locales: ['en-US', 'fr', 'nl-NL'],
    // Dies ist das Standard-Locale, das verwendet werden soll,
    // wenn ein nicht-locale-präfixierter Pfad besucht wird, z.B. `/hello`
    defaultLocale: 'en-US',
    // Dies ist eine Liste von Locale-Domains und dem Standard-Locale,
    // das sie verarbeiten sollen (diese werden nur bei der Einrichtung von Domain-Routing benötigt)
    // Hinweis: Subdomains müssen im Domain-Wert enthalten sein, z.B. "fr.example.com".
    domains: [
      {
        domain: 'example.com',
        defaultLocale: 'en-US',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl-NL',
      },
      {
        domain: 'example.fr',
        defaultLocale: 'fr',
        // Es kann auch ein optionales http-Feld verwendet werden,
        // um Locale-Domains lokal mit http statt https zu testen
        http: true,
      },
    ],
  },
}

Locale-Strategien

Es gibt zwei Strategien zur Locale-Behandlung: Sub-Path-Routing und Domain-Routing.

Sub-Path-Routing

Sub-Path-Routing platziert das Locale im URL-Pfad.

next.config.js
module.exports = {
  i18n: {
    locales: ['en-US', 'fr', 'nl-NL'],
    defaultLocale: 'en-US',
  },
}

Mit dieser Konfiguration sind en-US, fr und nl-NL zum Routing verfügbar, und en-US ist das Standard-Locale. Bei einer pages/blog.js stehen folgende URLs zur Verfügung:

  • /blog
  • /fr/blog
  • /nl-nl/blog

Das Standard-Locale hat kein Präfix.

Domain-Routing

Beim Domain-Routing können Sie Locales so konfigurieren, dass sie von verschiedenen Domains bedient werden:

next.config.js
module.exports = {
  i18n: {
    locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
    defaultLocale: 'en-US',
 
    domains: [
      {
        // Hinweis: Subdomains müssen im Domain-Wert enthalten sein,
        // z.B. muss www.example.com verwendet werden, wenn dies der erwartete Hostname ist
        domain: 'example.com',
        defaultLocale: 'en-US',
      },
      {
        domain: 'example.fr',
        defaultLocale: 'fr',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl-NL',
        // Geben Sie andere Locales an, die zu dieser Domain
        // umgeleitet werden sollen
        locales: ['nl-BE'],
      },
    ],
  },
}

Bei einer pages/blog.js stehen z.B. folgende URLs zur Verfügung:

  • example.com/blog
  • www.example.com/blog
  • example.fr/blog
  • example.nl/blog
  • example.nl/nl-BE/blog

Automatische Locale-Erkennung

Wenn ein Benutzer die Anwendungswurzel (normalerweise /) besucht, versucht Next.js, das bevorzugte Locale des Benutzers basierend auf dem Accept-Language-Header und der aktuellen Domain automatisch zu erkennen.

Wird ein anderes Locale als das Standard-Locale erkannt, wird der Benutzer weitergeleitet zu:

  • Bei Sub-Path-Routing: Der locale-präfixierte Pfad
  • Bei Domain-Routing: Die Domain, für die dieses Locale als Standard festgelegt ist

Beim Domain-Routing wird ein Benutzer mit dem Accept-Language-Header fr;q=0.9, der example.com besucht, zu example.fr weitergeleitet, da diese Domain standardmäßig das fr-Locale verarbeitet.

Beim Sub-Path-Routing würde der Benutzer zu /fr weitergeleitet.

Präfixierung des Standard-Locales

Mit Next.js 12 und Middleware können wir dem Standard-Locale ein Präfix hinzufügen.

Beispielsweise ist hier eine next.config.js-Datei mit Unterstützung für einige Sprachen. Beachten Sie, dass das Locale "default" absichtlich hinzugefügt wurde.

next.config.js
module.exports = {
  i18n: {
    locales: ['default', 'en', 'de', 'fr'],
    defaultLocale: 'default',
    localeDetection: false,
  },
  trailingSlash: true,
}

Als Nächstes können wir Middleware verwenden, um benutzerdefinierte Routing-Regeln hinzuzufügen:

middleware.ts
import { NextRequest, NextResponse } from 'next/server'
 
const PUBLIC_FILE = /\.(.*)$/
 
export async function middleware(req: NextRequest) {
  if (
    req.nextUrl.pathname.startsWith('/_next') ||
    req.nextUrl.pathname.includes('/api/') ||
    PUBLIC_FILE.test(req.nextUrl.pathname)
  ) {
    return
  }
 
  if (req.nextUrl.locale === 'default') {
    const locale = req.cookies.get('NEXT_LOCALE')?.value || 'en'
 
    return NextResponse.redirect(
      new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url)
    )
  }
}

Diese Middleware überspringt das Hinzufügen des Standard-Präfixes zu API-Routen und öffentlichen Dateien wie Schriftarten oder Bildern. Wenn eine Anfrage an das Standard-Locale gesendet wird, leiten wir zu unserem Präfix /en um.

Deaktivierung der automatischen Locale-Erkennung

Die automatische Locale-Erkennung kann mit Folgendem deaktiviert werden:

next.config.js
module.exports = {
  i18n: {
    localeDetection: false,
  },
}

Wenn localeDetection auf false gesetzt ist, wird Next.js nicht mehr automatisch basierend auf dem bevorzugten Locale des Benutzers umleiten und nur Locale-Informationen bereitstellen, die vom locale-basierten Domain oder Locale-Pfad erkannt wurden.

Zugriff auf Locale-Informationen

Sie können auf Locale-Informationen über den Next.js-Router zugreifen. Beispielsweise sind beim Verwenden des useRouter()-Hooks folgende Eigenschaften verfügbar:

  • locale enthält das aktuell aktive Locale.
  • locales enthält alle konfigurierten Locales.
  • defaultLocale enthält das konfigurierte Standard-Locale.

Beim Pre-Rendering von Seiten mit getStaticProps oder getServerSideProps wird die Locale-Information in dem Kontext bereitgestellt, der der Funktion übergeben wird.

Bei Verwendung von getStaticPaths werden die konfigurierten Locales im Kontextparameter der Funktion unter locales und der konfigurierte Standardstandort unter defaultLocale bereitgestellt.

Wechsel zwischen Locales

Sie können next/link oder next/router verwenden, um zwischen Locales zu wechseln.

Bei next/link kann eine locale-Eigenschaft bereitgestellt werden, um zu einem anderen Locale als dem aktuellen zu wechseln. Wenn keine locale-Eigenschaft angegeben wird, wird der aktuell aktive locale während Clientübergängen verwendet. Beispiel:

import Link from 'next/link'
 
export default function IndexPage(props) {
  return (
    <Link href="/another" locale="fr">
      To /fr/another
    </Link>
  )
}

Bei der direkten Verwendung der next/router-Methoden können Sie den locale über die Übergabeoptionen angeben. Beispiel:

import { useRouter } from 'next/router'
 
export default function IndexPage(props) {
  const router = useRouter()
 
  return (
    <div
      onClick={() => {
        router.push('/another', '/another', { locale: 'fr' })
      }}
    >
      to /fr/another
    </div>
  )
}

Hinweis: Um nur den locale zu wechseln und gleichzeitig alle Routing-Informationen wie dynamische Routenwerte oder versteckte href-Abfragewerte zu erhalten, können Sie den href-Parameter als Objekt übergeben:

import { useRouter } from 'next/router'
const router = useRouter()
const { pathname, asPath, query } = router
// ändert nur den Locale und behält alle anderen Routeninformationen einschließlich href-Abfrage bei
router.push({ pathname, query }, asPath, { locale: nextLocale })

Weitere Informationen zur Objektstruktur von router.push finden Sie hier.

Wenn Ihre href bereits den Locale enthält, können Sie die automatische Locale-Präfixbehandlung deaktivieren:

import Link from 'next/link'
 
export default function IndexPage(props) {
  return (
    <Link href="/fr/another" locale={false}>
      To /fr/another
    </Link>
  )
}

Nutzung des NEXT_LOCALE-Cookies

Next.js ermöglicht das Setzen eines NEXT_LOCALE=the-locale-Cookies, der Vorrang vor dem Accept-Language-Header hat. Dieser Cookie kann mit einem Sprachschalter gesetzt werden und beim erneuten Seitenbesuch wird der im Cookie angegebene Locale bei der Weiterleitung von / zum korrekten Locale-Standort verwendet.

Beispiel: Wenn ein Benutzer den Locale fr in seinem Accept-Language-Header bevorzugt, aber ein NEXT_LOCALE=en-Cookie gesetzt ist, wird beim Besuch von / zum en-Locale weitergeleitet, bis der Cookie entfernt oder abgelaufen ist.

Suchmaschinenoptimierung

Da Next.js weiß, welche Sprache der Benutzer besucht, fügt es automatisch das lang-Attribut zum <html>-Tag hinzu.

Next.js kennt keine Varianten einer Seite, daher liegt es an Ihnen, die hreflang-Meta-Tags mit next/head hinzuzufügen. Mehr über hreflang erfahren Sie in der Google Webmasters-Dokumentation.

Wie funktioniert das mit Static Generation?

Hinweis: Internationalisiertes Routing ist nicht mit output: 'export' kompatibel, da es nicht die Next.js-Routing-Schicht nutzt. Hybride Next.js-Anwendungen, die output: 'export' nicht verwenden, werden vollständig unterstützt.

Dynamische Routen und getStaticProps-Seiten

Für Seiten mit getStaticProps bei dynamischen Routen müssen alle gewünschten Locale-Varianten der Seite von getStaticPaths zurückgegeben werden. Zusätzlich zum params-Objekt können Sie auch ein locale-Feld zurückgeben, das angibt, welchen Locale Sie rendern möchten. Beispiel:

pages/blog/[slug].js
export const getStaticPaths = ({ locales }) => {
  return {
    paths: [
      // wenn kein `locale` angegeben wird, wird nur der defaultLocale generiert
      { params: { slug: 'post-1' }, locale: 'en-US' },
      { params: { slug: 'post-1' }, locale: 'fr' },
    ],
    fallback: true,
  }
}

Für Automatisch statisch optimierte und nicht-dynamische getStaticProps-Seiten wird eine Version der Seite für jeden Locale generiert. Dies ist wichtig zu beachten, da es die Buildzeiten je nach Anzahl konfigurierter Locales erhöhen kann.

Beispiel: Bei 50 konfigurierten Locales mit 10 nicht-dynamischen Seiten mit getStaticProps bedeutet dies, dass getStaticProps 500 Mal aufgerufen wird. 50 Versionen der 10 Seiten werden während jedes Builds generiert.

Um die Buildzeit dynamischer Seiten mit getStaticProps zu reduzieren, verwenden Sie einen fallback-Modus. Dies ermöglicht es Ihnen, nur die beliebtesten Pfade und Locales von getStaticPaths für das Prerendering während des Builds zurückzugeben. Anschließend erstellt Next.js die restlichen Seiten zur Laufzeit, wenn sie angefordert werden.

Automatisch statisch optimierte Seiten

Für Seiten, die automatisch statisch optimiert sind, wird eine Version der Seite für jeden Locale generiert.

Nicht-dynamische getStaticProps-Seiten

Für nicht-dynamische getStaticProps-Seiten wird wie oben beschrieben eine Version für jeden Locale generiert. getStaticProps wird mit jedem zu rendernden locale aufgerufen. Wenn Sie bestimmte Locales vom Prerendering ausschließen möchten, können Sie notFound: true von getStaticProps zurückgeben, und diese Variante der Seite wird nicht generiert.

export async function getStaticProps({ locale }) {
  // Rufen Sie einen externen API-Endpunkt auf, um Beiträge zu erhalten
  // Sie können eine beliebige Datenfeching-Bibliothek verwenden
  const res = await fetch(`https://.../posts?locale=${locale}`)
  const posts = await res.json()
 
  if (posts.length === 0) {
    return {
      notFound: true,
    }
  }
 
  // Durch Zurückgeben von { props: posts } erhält die Blog-Komponente
  // `posts` als Prop zur Buildzeit
  return {
    props: {
      posts,
    },
  }
}

Grenzen für die i18n-Konfiguration

  • locales: 100 Locales insgesamt
  • domains: 100 Locale-Domain-Einträge insgesamt

Hinweis: Diese Grenzen wurden zunächst hinzugefügt, um potenzielle Leistungsprobleme zur Buildzeit zu verhindern. Sie können diese Grenzen mit benutzerdefiniertem Routing unter Verwendung von Middleware in Next.js 12 umgehen.