StartseiteSandboxShowcaseAppDokumentBlog
    • EnglishEnglisch
      EN
    • русскийRussisch
      RU
    • 日本語Japanisch
      JA
    • françaisFranzösisch
      FR
    • 한국어Koreanisch
      KO
    • 中文Chinesisch
      ZH
    • españolSpanisch
      ES
    • DeutschDeutsch
      DE
    • العربيةArabisch
      AR
    • italianoItalienisch
      IT
    • British EnglishEnglisch (Vereinigtes Königreich)
      EN-GB
    • portuguêsPortugiesisch
      PT
    • हिन्दीHindi
      HI
    • TürkçeTürkisch
      TR
    • polskiPolnisch
      PL
    • IndonesiaIndonesisch
      ID
    • Tiếng ViệtVietnamesisch
      VI
    • українськаUkrainisch
      UK
    /
    Dokumentation nach Framework filtern
    Alt+←
    Warum Intlayer?
    Anfangen
    Konzept
    • Wie Intlayer funktioniert
    • Konfiguration
    • TestFillBuildWatchExtractLoginPushPullConfigurationListVersionEditorLiveDebugDoc ReviewDoc TranslateSDK
    • Visueller Editor
    • CMS
    • CI/CD-Integration
    • ÜbersetzungPluralAufzählungBedingungGeschlechtEinfügungDateiVerschachtelungMarkdownHTMLFunktionsabruf
    • Datei pro Locale
    • Compiler
    • Automatisches Ausfüllen
    • Testen
    • Bundle-Optimierung
    Umwelt
    • Next.js 14 und App Router
      Next.js 15
      Next.js ohne Locale URL
      Next.js und Page Router
      Compiler
    • Tanstack Start Solid
    • Astro und React
      Astro und Svelte
      Astro und Vue
      Astro und Solid
      Astro und Preact
      Astro und Lit
      Astro und Vanilla JS
    • React Router v7
      React Router v7 (fs-routes)
      Compiler
    • Nuxt und Vue
    • Vite und Solid
    • SvelteKit
    • Vite und Preact
    • Vite und Vanilla JS
    • Vite und Lit
    • Angular 19 (Webpack)
      Analog
    • React CRA
    • React Native und Expo
    • Express.js
      NestJS
      Fastify
      Hono
      Adonis
    • Lynx und React
    Plugins
    • JSON
    • gettext (.po)
    VS Code-Erweiterung
    Agent
    • MCP-Server
    • Agenten-Fähigkeiten
    Versionen
    • v8
    • v7
    • v6
    Benchmark
    • Next.js
    • TanStack
    • Vue
    • Solid
    • Svelte
    Blog
    Frage stellen
    1. Documentation
    2. Next intl
    Erstellung:2025-10-05Letzte Aktualisierung:2025-10-05
    Anwendungsvorlage auf GitHub ansehen

    Für diese Seite ist eine Anwendungsvorlage verfügbar.

    Referenzieren Sie diese Dokumentation mit Ihrem bevorzugten AI-Assistenten
    ChatGPT
    Claude
    DeepSeek
    Google AI mode
    Gemini
    Perplexity
    Mistral
    Grok

    Stellen Sie Ihre Frage und erhalten Sie einen Resümee des Dokuments, indem Sie diese Seite und den AI-Anbieter Ihrer Wahl referenzieren

    Der Inhalt dieser Seite wurde mit einer KI übersetzt.

    Den englischen Originaltext ansehen
    Diese Dokumentation bearbeiten

    Wenn Sie eine Idee haben, um diese Dokumentation zu verbessern, zögern Sie bitte nicht, durch das Einreichen eines Pull-Requests auf GitHub beizutragen.

    GitHub-Link zur Dokumentation
    Kopieren

    Markdown des Dokuments in die Zwischenablage kopieren

    Übersetzen Sie Ihre Next.js 15 Website mit next-intl unter Verwendung von Intlayer | Internationalisierung (i18n)

    Diese Anleitung führt Sie durch die Best Practices von next-intl in einer Next.js 15 (App Router) Anwendung und zeigt, wie Sie Intlayer darüber legen können für ein robustes Übersetzungsmanagement und Automatisierung.

    Sehen Sie den Vergleich in next-i18next vs next-intl vs Intlayer.

    • Für Einsteiger: Folgen Sie den Schritt-für-Schritt-Anleitungen, um eine funktionierende mehrsprachige App zu erstellen.
    • Für Entwickler mit mittlerem Erfahrungsniveau: Achten Sie auf Payload-Optimierung und die Trennung von Server- und Client-Komponenten.
    • Für erfahrene Entwickler: Beachten Sie statische Generierung, Middleware, SEO-Integration und Automatisierungshooks.

    Was wir behandeln werden:

    • Einrichtung und Dateistruktur
    • Optimierung des Ladens von Nachrichten
    • Verwendung von Client- und Server-Komponenten
    • Metadaten, Sitemap, Robots für SEO
    • Middleware für die Lokalisierungs-Routing
    • Hinzufügen von Intlayer obendrauf (CLI und Automatisierung)

    Richten Sie Ihre Anwendung mit next-intl ein

    Installieren Sie die next-intl Abhängigkeiten:

    bash
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    npm install next-intl
    bash
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    .├── locales│   ├── en│   │  ├── common.json│   │  └── about.json│   ├── fr│   │  ├── common.json│   │  └── about.json│   └── es│      ├── common.json│      └── about.json└── src    ├── i18n.ts    ├── middleware.ts    ├── app    │   └── [locale]    │       ├── layout.tsx    │       └── about    │           └── page.tsx    └── components        ├── ClientComponentExample.tsx        └── ServerComponent.tsx

    Einrichtung und Laden von Inhalten

    Laden Sie nur die Namespaces, die Ihre Routen benötigen, und validieren Sie die Locales frühzeitig. Halten Sie Server-Komponenten nach Möglichkeit synchron und senden Sie nur die benötigten Nachrichten an den Client.

    src/i18n.ts
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import { getRequestConfig } from "next-intl/server";import { notFound } from "next/navigation";export const locales = ["en", "fr", "es"] as const;export const defaultLocale = "en" as const;async function loadMessages(locale: string) {  // Lade nur die Namespaces, die dein Layout/deine Seiten benötigen  const [common, about] = await Promise.all([    import(`../locales/${locale}/common.json`).then((m) => m.default),    import(`../locales/${locale}/about.json`).then((m) => m.default),  ]);  return { common, about } as const;}export default getRequestConfig(async ({ locale }) => {  if (!locales.includes(locale)) notFound();  return {    messages: await loadMessages(locale),  };});
    src/app/[locale]/layout.tsx
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import type { ReactNode } from "react";import { locales } from "@/i18n";import {  getLocaleDirection,  unstable_setRequestLocale,} from "next-intl/server";export const dynamic = "force-static";export function generateStaticParams() {  return locales.map((locale) => ({ locale }));}export default async function LocaleLayout({  children,  params,}: {  children: ReactNode;  params: { locale: string };}) {  const { locale } = params;  // Setze die aktive Anfragelocale für dieses Server-Rendering (RSC)  unstable_setRequestLocale(locale);  const dir = getLocaleDirection(locale);  return (    <html lang={locale} dir={dir}>      <body>{children}</body>    </html>  );}
    src/app/[locale]/about/page.tsx
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import { getTranslations, getMessages, getFormatter } from "next-intl/server";import { NextIntlClientProvider } from "next-intl";import pick from "lodash/pick";import ServerComponent from "@/components/ServerComponent";import ClientComponentExample from "@/components/ClientComponentExample";export const dynamic = "force-static";export default async function AboutPage({  params,}: {  params: { locale: string };}) {  const { locale } = params;  // Nachrichten werden serverseitig geladen. Sende nur das Nötige an den Client.  const messages = await getMessages();  const clientMessages = pick(messages, ["common", "about"]);  // Ausschließlich serverseitige Übersetzungen/Formatierungen  const tAbout = await getTranslations("about");  const tCounter = await getTranslations("about.counter");  const format = await getFormatter();  const initialFormattedCount = format.number(0);  return (    <NextIntlClientProvider locale={locale} messages={clientMessages}>      <main>        <h1>{tAbout("title")}</h1>        <ClientComponentExample />        <ServerComponent          formattedCount={initialFormattedCount}          label={tCounter("label")}          increment={tCounter("increment")}        />      </main>    </NextIntlClientProvider>  );}

    Verwendung in einer Client-Komponente

    Nehmen wir ein Beispiel einer Client-Komponente, die einen Zähler rendert.

    Übersetzungen (Struktur wiederverwendet; laden Sie diese nach Belieben in die next-intl Nachrichten)

    locales/en/about.json
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    {  "counter": {    "label": "Counter",    "increment": "Increment"  }}
    locales/fr/about.json
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    {  "counter": {    "label": "Compteur",    "increment": "Incrémenter"  }}

    Client-Komponente

    src/components/ClientComponentExample.tsx
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    "use client";import React, { useState } from "react";import { useTranslations, useFormatter } from "next-intl";const ClientComponentExample = () => {  // Direkt auf das verschachtelte Objekt zugreifen  const t = useTranslations("about.counter");  const format = useFormatter();  const [count, setCount] = useState(0);  return (    <div>      <p>{format.number(count)}</p>      <button        aria-label={t("label")}        onClick={() => setCount((count) => count + 1)}      >        {t("increment")}      </button>    </div>  );};

    Vergiss nicht, die "about"-Nachricht in die Client-Nachrichten der Seite aufzunehmen (Fügen Sie nur die Namespaces hinzu, die Ihr Client tatsächlich benötigt).

    Verwendung in einer Server-Komponente

    Diese UI-Komponente ist eine Server-Komponente und kann unter einer Client-Komponente gerendert werden (Seite → Client → Server). Halten Sie sie synchron, indem Sie vorab berechnete Strings übergeben.

    src/components/ServerComponent.tsx
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    type ServerComponentProps = {  formattedCount: string;  label: string;  increment: string;};const ServerComponent = ({  formattedCount,  label,  increment,}: ServerComponentProps) => {  return (    <div>      <p>{formattedCount}</p>      <button aria-label={label}>{increment}</button>    </div>  );};

    Hinweise:

    • Berechnen Sie formattedCount serverseitig (z. B. const initialFormattedCount = format.number(0)).
    • Vermeiden Sie es, Funktionen oder nicht serialisierbare Objekte an Server-Komponenten zu übergeben.
    src/app/[locale]/about/layout.tsx
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import type { Metadata } from "next";import { locales, defaultLocale } from "@/i18n";import { getTranslations } from "next-intl/server";function localizedPath(locale: string, path: string) {  return locale === defaultLocale ? path : "/" + locale + path;}export async function generateMetadata({  params,}: {  params: { locale: string };}): Promise<Metadata> {  const { locale } = params;  const t = await getTranslations({ locale, namespace: "about" });  const url = "/about";  const languages = Object.fromEntries(    locales.map((locale) => [locale, localizedPath(locale, url)])  );  return {    title: t("title"),    description: t("description"),    alternates: {      canonical: localizedPath(locale, url),      languages: { ...languages, "x-default": url },    },  };}// ... Rest des Seiten-Codes
    src/app/sitemap.ts
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const formatterLocalizedPath = (locale: string, path: string) =>  locale === defaultLocale ? origin + path : origin + "/" + locale + path;export default function sitemap(): MetadataRoute.Sitemap {  const aboutLanguages = Object.fromEntries(    locales.map((l) => [l, formatterLocalizedPath(l, "/about")])  );  return [    {      url: formatterLocalizedPath(defaultLocale, "/about"),      lastModified: new Date(),      changeFrequency: "monatlich",      priority: 0.7,      alternates: { languages: aboutLanguages },    },  ];}
    src/app/robots.ts
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const withAllLocales = (path: string) => [  path,  ...locales    .filter((locale) => locale !== defaultLocale)    .map((locale) => "/" + locale + path),];export default function robots(): MetadataRoute.Robots {  const disallow = [    ...withAllLocales("/dashboard"),    ...withAllLocales("/admin"),  ];  return {    rules: { userAgent: "*", allow: ["/"], disallow },    host: origin,    sitemap: origin + "/sitemap.xml",  };}

    Middleware für Locale-Routing

    Fügen Sie eine Middleware hinzu, um die Lokalerkennung und das Routing zu verwalten:

    src/middleware.ts
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import createMiddleware from "next-intl/middleware";import { locales, defaultLocale } from "@/i18n";export default createMiddleware({  locales: [...locales],  defaultLocale,  localeDetection: true,});export const config = {  // API, Next-Interna und statische Assets überspringen  matcher: ["/((?!api|_next|.*\\..*).*)"],};

    Best Practices

    • Setzen Sie html lang und dir: Berechnen Sie in src/app/[locale]/layout.tsx dir über getLocaleDirection(locale) und setzen Sie <html lang={locale} dir={dir}>.
    • Teilen Sie Nachrichten nach Namespace auf: Organisieren Sie JSON-Dateien pro Locale und Namespace (z. B. common.json, about.json).
    • Minimieren Sie die Client-Last: Senden Sie auf Seiten nur die benötigten Namespaces an NextIntlClientProvider (z. B. pick(messages, ['common', 'about'])).
    • Bevorzugen Sie statische Seiten: Exportieren Sie export const dynamic = 'force-static' und generieren Sie statische Parameter für alle locales.
    • Synchronisierte Server-Komponenten: Übergeben Sie vorab berechnete Strings (übersetzte Labels, formatierte Zahlen) anstelle von asynchronen Aufrufen oder nicht serialisierbaren Funktionen.

    Implementieren Sie Intlayer auf Basis von next-intl

    Installieren Sie die Intlayer-Abhängigkeiten:

    bash
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    npm install intlayer @intlayer/sync-json-plugin --save-dev

    Erstellen Sie die Intlayer-Konfigurationsdatei:

    intlayer.config.ts
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    import { type IntlayerConfig, Locales } from "intlayer";import { syncJSON } from "@intlayer/sync-json-plugin";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH], // Verfügbare Sprachen    defaultLocale: Locales.ENGLISH, // Standardsprache  },  ai: {    apiKey: process.env.OPENAI_API_KEY, // API-Schlüssel für AI-Dienste  },  plugins: [    // Synchronisieren Sie Ihre Ordnerstruktur pro Namespace mit Intlayer    syncJSON({      format: "icu",      source: ({ key, locale }) => `./locales/${locale}/${key}.json`, // Pfad zu den JSON-Übersetzungsdateien    }),  ],};export default config;

    Fügen Sie package.json-Skripte hinzu:

    package.json
    Code kopieren

    Kopieren Sie den Code in die Zwischenablage

    {  "scripts": {    "i18n:fill": "intlayer fill", // Füllt fehlende Übersetzungen mit AI-Unterstützung    "i18n:test": "intlayer test" // Prüft auf fehlende oder ungültige Übersetzungen  }}

    Hinweise:

    • intlayer fill: Verwendet Ihren AI-Anbieter, um fehlende Übersetzungen basierend auf Ihren konfigurierten Sprachen zu ergänzen.
    • intlayer test: Überprüft fehlende oder ungültige Übersetzungen (ideal für den Einsatz in CI).

    Sie können Argumente und Anbieter konfigurieren; siehe Intlayer CLI.

    • intlayer fill: verwendet Ihren KI-Anbieter, um fehlende Übersetzungen basierend auf Ihren konfigurierten Sprachversionen zu ergänzen.
    • intlayer test: überprüft fehlende/ungültige Übersetzungen (verwenden Sie es im CI).

    Sie können Argumente und Anbieter konfigurieren; siehe Intlayer CLI.

    Warum Intlayer?
    Alt+→

    Auf dieser Seite

      Diskussionen sind anonym und werden regelmäßig überprüft, um häufige Probleme zu behandeln. Teilen Sie gerne Feature-Ideen, Feedback zur Dokumentation oder alles rund um Intlayer, wir nutzen diese Eingaben, um unsere Roadmap zu gestalten und das Produkt zu verbessern.

      npm install next-intl
      .├── locales│   ├── en│   │  ├── common.json│   │  └── about.json│   ├── fr│   │  ├── common.json│   │  └── about.json│   └── es│      ├── common.json│      └── about.json└── src    ├── i18n.ts    ├── middleware.ts    ├── app    │   └── [locale]    │       ├── layout.tsx    │       └── about    │           └── page.tsx    └── components        ├── ClientComponentExample.tsx        └── ServerComponent.tsx
      import { getRequestConfig } from "next-intl/server";import { notFound } from "next/navigation";export const locales = ["en", "fr", "es"] as const;export const defaultLocale = "en" as const;async function loadMessages(locale: string) {  // Lade nur die Namespaces, die dein Layout/deine Seiten benötigen  const [common, about] = await Promise.all([    import(`../locales/${locale}/common.json`).then((m) => m.default),    import(`../locales/${locale}/about.json`).then((m) => m.default),  ]);  return { common, about } as const;}export default getRequestConfig(async ({ locale }) => {  if (!locales.includes(locale)) notFound();  return {    messages: await loadMessages(locale),  };});
      import type { ReactNode } from "react";import { locales } from "@/i18n";import {  getLocaleDirection,  unstable_setRequestLocale,} from "next-intl/server";export const dynamic = "force-static";export function generateStaticParams() {  return locales.map((locale) => ({ locale }));}export default async function LocaleLayout({  children,  params,}: {  children: ReactNode;  params: { locale: string };}) {  const { locale } = params;  // Setze die aktive Anfragelocale für dieses Server-Rendering (RSC)  unstable_setRequestLocale(locale);  const dir = getLocaleDirection(locale);  return (    <html lang={locale} dir={dir}>      <body>{children}</body>    </html>  );}
      import { getTranslations, getMessages, getFormatter } from "next-intl/server";import { NextIntlClientProvider } from "next-intl";import pick from "lodash/pick";import ServerComponent from "@/components/ServerComponent";import ClientComponentExample from "@/components/ClientComponentExample";export const dynamic = "force-static";export default async function AboutPage({  params,}: {  params: { locale: string };}) {  const { locale } = params;  // Nachrichten werden serverseitig geladen. Sende nur das Nötige an den Client.  const messages = await getMessages();  const clientMessages = pick(messages, ["common", "about"]);  // Ausschließlich serverseitige Übersetzungen/Formatierungen  const tAbout = await getTranslations("about");  const tCounter = await getTranslations("about.counter");  const format = await getFormatter();  const initialFormattedCount = format.number(0);  return (    <NextIntlClientProvider locale={locale} messages={clientMessages}>      <main>        <h1>{tAbout("title")}</h1>        <ClientComponentExample />        <ServerComponent          formattedCount={initialFormattedCount}          label={tCounter("label")}          increment={tCounter("increment")}        />      </main>    </NextIntlClientProvider>  );}
      {  "counter": {    "label": "Counter",    "increment": "Increment"  }}
      {  "counter": {    "label": "Compteur",    "increment": "Incrémenter"  }}
      "use client";import React, { useState } from "react";import { useTranslations, useFormatter } from "next-intl";const ClientComponentExample = () => {  // Direkt auf das verschachtelte Objekt zugreifen  const t = useTranslations("about.counter");  const format = useFormatter();  const [count, setCount] = useState(0);  return (    <div>      <p>{format.number(count)}</p>      <button        aria-label={t("label")}        onClick={() => setCount((count) => count + 1)}      >        {t("increment")}      </button>    </div>  );};
      type ServerComponentProps = {  formattedCount: string;  label: string;  increment: string;};const ServerComponent = ({  formattedCount,  label,  increment,}: ServerComponentProps) => {  return (    <div>      <p>{formattedCount}</p>      <button aria-label={label}>{increment}</button>    </div>  );};
      import type { Metadata } from "next";import { locales, defaultLocale } from "@/i18n";import { getTranslations } from "next-intl/server";function localizedPath(locale: string, path: string) {  return locale === defaultLocale ? path : "/" + locale + path;}export async function generateMetadata({  params,}: {  params: { locale: string };}): Promise<Metadata> {  const { locale } = params;  const t = await getTranslations({ locale, namespace: "about" });  const url = "/about";  const languages = Object.fromEntries(    locales.map((locale) => [locale, localizedPath(locale, url)])  );  return {    title: t("title"),    description: t("description"),    alternates: {      canonical: localizedPath(locale, url),      languages: { ...languages, "x-default": url },    },  };}// ... Rest des Seiten-Codes
      import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const formatterLocalizedPath = (locale: string, path: string) =>  locale === defaultLocale ? origin + path : origin + "/" + locale + path;export default function sitemap(): MetadataRoute.Sitemap {  const aboutLanguages = Object.fromEntries(    locales.map((l) => [l, formatterLocalizedPath(l, "/about")])  );  return [    {      url: formatterLocalizedPath(defaultLocale, "/about"),      lastModified: new Date(),      changeFrequency: "monatlich",      priority: 0.7,      alternates: { languages: aboutLanguages },    },  ];}
      import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const withAllLocales = (path: string) => [  path,  ...locales    .filter((locale) => locale !== defaultLocale)    .map((locale) => "/" + locale + path),];export default function robots(): MetadataRoute.Robots {  const disallow = [    ...withAllLocales("/dashboard"),    ...withAllLocales("/admin"),  ];  return {    rules: { userAgent: "*", allow: ["/"], disallow },    host: origin,    sitemap: origin + "/sitemap.xml",  };}
      import createMiddleware from "next-intl/middleware";import { locales, defaultLocale } from "@/i18n";export default createMiddleware({  locales: [...locales],  defaultLocale,  localeDetection: true,});export const config = {  // API, Next-Interna und statische Assets überspringen  matcher: ["/((?!api|_next|.*\\..*).*)"],};
      npm install intlayer @intlayer/sync-json-plugin --save-dev
      import { type IntlayerConfig, Locales } from "intlayer";import { syncJSON } from "@intlayer/sync-json-plugin";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH], // Verfügbare Sprachen    defaultLocale: Locales.ENGLISH, // Standardsprache  },  ai: {    apiKey: process.env.OPENAI_API_KEY, // API-Schlüssel für AI-Dienste  },  plugins: [    // Synchronisieren Sie Ihre Ordnerstruktur pro Namespace mit Intlayer    syncJSON({      format: "icu",      source: ({ key, locale }) => `./locales/${locale}/${key}.json`, // Pfad zu den JSON-Übersetzungsdateien    }),  ],};export default config;
      {  "scripts": {    "i18n:fill": "intlayer fill", // Füllt fehlende Übersetzungen mit AI-Unterstützung    "i18n:test": "intlayer test" // Prüft auf fehlende oder ungültige Übersetzungen  }}