Design wechseln

Next.js Internationalisierung – Vollständiger Leitfaden: next-intl Best Practices

Easton editorial illustration: build pipeline conveyor

Letztes Jahr habe ich ein Next.js-Projekt übernommen, das Mehrsprachigkeit unterstützen musste. Beim Anblick der verschiedenen i18n-Einstellungen in der Konfiguration war ich zunächst etwas überfordert. Nach stundenlangem Durchforsten der Dokumentation wurde klar: App Router und Pages Router verfolgen bei der Internationalisierung völlig unterschiedliche Ansätze. Eine Woche später war next-intl eingerichtet – und unterwegs habe ich einige typische Fallen kennengelernt.

In diesem Artikel geht es um Internationalisierung in Next.js – insbesondere darum, wie Sie mit next-intl im App Router elegant Mehrsprachigkeit umsetzen.

Warum next-intl?

Vielleicht fragen Sie sich: Hat Next.js nicht eingebaute Internationalisierung? Tatsächlich bot der Pages Router früher native i18n-Routing-Unterstützung. Im App Router wurde diese Funktion entfernt.

Die offizielle Empfehlung lautet: Drittanbieter-Bibliotheken nutzen. next-intl ist dabei eine der beliebtesten Optionen.

Vorteile von next-intl:

  • Native App-Router-Unterstützung – speziell für den App Router entwickelt, sehr angenehm in der Handhabung
  • Typsicherheit – in Kombination mit TypeScript lassen sich Übersetzungstexte typprüfen
  • Flexible Routing-Strategien – Unterpfade, Domains, Cookies und weitere Sprachwechsel-Varianten
  • Umfangreiche Funktionen – Pluralisierung, Datums- und Zahlenformatierung, Rich Text und mehr
  • Gute Performance – Server-Component-freundlich, unterstützt statisches Rendering

Im Vergleich zu anderen Lösungen ist die Dokumentation von next-intl ebenfalls gut verständlich – der Einstieg fällt weniger schwer.

Grundkonfiguration: Von null an starten

1. Abhängigkeiten installieren

Zuerst installieren Sie next-intl:

npm install next-intl
# oder
pnpm add next-intl
# oder
yarn add next-intl

2. Übersetzungsdateien anlegen

Erstellen Sie im Projektroot einen Ordner messages (alternativ locales oder ein anderer Name) und legen Sie pro Sprache eine JSON-Datei an:

messages/
├── en.json
├── zh.json
└── ja.json

messages/zh.json:

{
  "HomePage": {
    "title": "欢迎来到我的网站",
    "description": "这是一个支持多语言的 Next.js 应用"
  },
  "Navigation": {
    "home": "首页",
    "about": "关于",
    "contact": "联系我们"
  }
}

messages/en.json:

{
  "HomePage": {
    "title": "Welcome to My Website",
    "description": "This is a multilingual Next.js application"
  },
  "Navigation": {
    "home": "Home",
    "about": "About",
    "contact": "Contact Us"
  }
}

Eine verschachtelte Struktur ist nicht zwingend – ich finde aber, dass die Gruppierung nach Seite oder Komponente die Verwaltung deutlich erleichtert.

3. i18n.ts konfigurieren

Erstellen Sie i18n.ts (oder i18n/config.ts) und definieren Sie die unterstützten Sprachen:

import { getRequestConfig } from 'next-intl/server';

export default getRequestConfig(async ({ locale }) => ({
  messages: (await import(`./messages/${locale}.json`)).default
}));

Diese Konfiguration teilt next-intl mit, wo die Übersetzungsdateien liegen. Der Parameter locale wird automatisch aus der URL extrahiert.

4. Middleware erstellen

Erstellen Sie im Projektroot middleware.ts – das ist der Schlüssel für mehrsprachiges Routing:

import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
  // Unterstützte Sprachen
  locales: ['en', 'zh', 'ja'],

  // Standardsprache
  defaultLocale: 'zh',

  // Standardsprache immer in der URL anzeigen?
  localePrefix: 'as-needed'
});

export const config = {
  // Alle Pfade außer api, _next/static, _next/image, favicon.ico
  matcher: ['/', '/(zh|en|ja)/:path*', '/((?!api|_next|_next/static|_next/image|favicon.ico).*)']
};

Optionen für localePrefix:

  • 'always' – alle Sprachen mit Präfix, auch die Standardsprache (/zh/about, /en/about)
  • 'as-needed' – Standardsprache ohne Präfix (/about, /en/about)
  • 'never' – kein Sprachpräfix in der URL (Sprache wird anders erkannt, z. B. per Domain)

Ich nutze meist 'as-needed' – für chinesische Nutzer freundlich und die URL wirkt aufgeräumter.

5. app-Verzeichnisstruktur anpassen

Das ist der entscheidende Schritt: Alle Routen gehören unter die dynamische Route [locale].

Vorher:

app/
├── page.tsx
├── about/
│   └── page.tsx
└── layout.tsx

Nachher:

app/
├── [locale]/
│   ├── page.tsx
│   ├── about/
│   │   └── page.tsx
│   └── layout.tsx
└── layout.tsx (optional, für globale Konfiguration)

6. Root-Layout konfigurieren

In app/[locale]/layout.tsx richten Sie die Sprache ein:

import { NextIntlClientProvider } from 'next-intl';
import { getMessages } from 'next-intl/server';
import { notFound } from 'next/navigation';

const locales = ['en', 'zh', 'ja'];

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

export default async function LocaleLayout({
  children,
  params: { locale }
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  // Prüfen, ob die Sprache unterstützt wird
  if (!locales.includes(locale)) {
    notFound();
  }

  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

Beachten Sie generateStaticParams: Bei statischer Generierung teilt diese Funktion Next.js mit, für welche Sprachen Seiten erzeugt werden sollen.

Übersetzungen in Komponenten nutzen

Nach der Konfiguration können Sie in Komponenten Übersetzungen verwenden.

In Server Components

import { useTranslations } from 'next-intl';

export default function HomePage() {
  const t = useTranslations('HomePage');

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

Der Parameter von useTranslations ist der Namespace in der Übersetzungsdatei (der äußerste Key). Ohne Parameter können Sie den vollen Pfad nutzen, z. B. t('HomePage.title').

In Client Components

In Client Components funktioniert es genauso:

'use client';

import { useTranslations } from 'next-intl';

export default function Navigation() {
  const t = useTranslations('Navigation');

  return (
    <nav>
      <a href="/">{t('home')}</a>
      <a href="/about">{t('about')}</a>
      <a href="/contact">{t('contact')}</a>
    </nav>
  );
}

Das ist der elegante Teil an next-intl – Server und Client Components nutzen dieselbe API.

Mehrsprachiges Routing

Aktuelle Sprache ermitteln

import { useLocale } from 'next-intl';

export default function LanguageSwitcher() {
  const locale = useLocale();

  return <div>Current language: {locale}</div>;
}

Sprachumschalter erstellen

Jede mehrsprachige Website braucht das:

'use client';

import { useLocale } from 'next-intl';
import { usePathname, useRouter } from 'next/navigation';

export default function LanguageSwitcher() {
  const locale = useLocale();
  const router = useRouter();
  const pathname = usePathname();

  const switchLanguage = (newLocale: string) => {
    // Sprachsegment im Pfad ersetzen
    const newPath = pathname.replace(`/${locale}`, `/${newLocale}`);
    router.push(newPath);
  };

  return (
    <select value={locale} onChange={(e) => switchLanguage(e.target.value)}>
      <option value="zh">中文</option>
      <option value="en">English</option>
      <option value="ja">日本語</option>
    </select>
  );
}

Es gibt allerdings eine kleine Schwäche: Steht der Nutzer auf der Standardsprache (z. B. Chinesisch) unter /about, soll der Wechsel nach Englisch /en/about ergeben. Der obige Code braucht eine Anpassung:

const switchLanguage = (newLocale: string) => {
  // Aktuelles Sprachpräfix entfernen
  let path = pathname;
  if (pathname.startsWith(`/${locale}`)) {
    path = pathname.substring(locale.length + 1);
  }

  // Neues Sprachpräfix hinzufügen (außer Standardsprache bei as-needed)
  const newPath = newLocale === 'zh' ? path : `/${newLocale}${path}`;
  router.push(newPath);
};

next-intl bietet eine erweiterte Link-Komponente, die Sprachpräfixe automatisch handhabt:

import { Link } from '@/navigation'; // vorher konfigurieren

<Link href="/about">
  {t('about')}
</Link>

Konfiguration in navigation.ts:

import { createSharedPathnamesNavigation } from 'next-intl/navigation';

export const locales = ['en', 'zh', 'ja'] as const;
export const localePrefix = 'as-needed';

export const { Link, redirect, usePathname, useRouter } =
  createSharedPathnamesNavigation({ locales, localePrefix });

Die exportierten Link-, useRouter- und weiteren Hilfsmittel verarbeiten Sprachpfade automatisch.

Erweiterte Funktionen

1. Übersetzungen mit Parametern

Oft müssen Variablen in Übersetzungen eingefügt werden – next-intl unterstützt das so:

messages/zh.json:

{
  "welcome": "欢迎回来,{username}!",
  "items": "你有 {count} 个新消息"
}

Verwendung:

const t = useTranslations();

<p>{t('welcome', { username: 'John' })}</p>
<p>{t('items', { count: 5 })}</p>

2. Pluralisierung

Pluralregeln unterscheiden sich je nach Sprache – next-intl bietet dafür passende APIs:

messages/en.json:

{
  "messages": {
    "one": "You have {count} message",
    "other": "You have {count} messages"
  }
}

Verwendung:

t('messages', { count: 1 })  // "You have 1 message"
t('messages', { count: 5 })  // "You have 5 messages"

Chinesisch kennt keine Pluralform – Sie können es so schreiben:

messages/zh.json:

{
  "messages": "你有 {count} 条消息"
}

3. Datums- und Zahlenformatierung

next-intl stellt dedizierte Formatierungsfunktionen bereit:

import { useFormatter } from 'next-intl';

export default function DateExample() {
  const format = useFormatter();
  const now = new Date();

  return (
    <div>
      <p>{format.dateTime(now, { dateStyle: 'full' })}</p>
      {/* Chinesisch: 2025年12月25日星期三 */}
      {/* Englisch: Wednesday, December 25, 2025 */}

      <p>{format.number(1234567.89, { style: 'currency', currency: 'CNY' })}</p>
      {/* Chinesisch: ¥1,234,567.89 */}
      {/* Englisch: CN¥1,234,567.89 */}
    </div>
  );
}

4. Rich-Text-Übersetzungen

Manchmal enthalten Übersetzungen HTML-Tags oder React-Komponenten:

messages/zh.json:

{
  "richText": "我同意<terms>服务条款</terms>和<privacy>隐私政策</privacy>"
}

Verwendung:

import { useTranslations } from 'next-intl';

export default function Agreement() {
  const t = useTranslations();

  return (
    <p>
      {t.rich('richText', {
        terms: (chunks) => <a href="/terms">{chunks}</a>,
        privacy: (chunks) => <a href="/privacy">{chunks}</a>
      })}
    </p>
  );
}

Best Practices für Übersetzungsdateien

Mit wachsendem Projekt werden Übersetzungsdateien schwerer zu pflegen. Hier einige praktische Tipps:

1. Nach Funktionsmodulen aufteilen

Packen Sie nicht alles in eine große JSON-Datei – teilen Sie nach Seite oder Feature auf:

messages/
├── zh/
│   ├── common.json      # Allgemeine Texte (Buttons, Fehlermeldungen)
│   ├── home.json        # Startseite
│   ├── about.json       # Über-Seite
│   └── auth.json        # Authentifizierung
├── en/
│   ├── common.json
│   ├── home.json
│   ├── about.json
│   └── auth.json

In i18n.ts zusammenführen:

import { getRequestConfig } from 'next-intl/server';

export default getRequestConfig(async ({ locale }) => {
  const common = (await import(`./messages/${locale}/common.json`)).default;
  const home = (await import(`./messages/${locale}/home.json`)).default;
  const about = (await import(`./messages/${locale}/about.json`)).default;
  const auth = (await import(`./messages/${locale}/auth.json`)).default;

  return {
    messages: {
      common,
      home,
      about,
      auth
    }
  };
});

2. TypeScript-Typsicherheit

Besonders hilfreich: Typen für Übersetzungsdateien definieren, um Tippfehler zu vermeiden:

types/i18n.ts:

import zh from '@/messages/zh.json';

type Messages = typeof zh;

declare global {
  interface IntlMessages extends Messages {}
}

TypeScript konfigurieren (tsconfig.json):

{
  "compilerOptions": {
    "types": ["./types/i18n"]
  }
}

Bei t('xxx') meldet TypeScript fehlende Keys – sehr praktisch!

3. Gemeinsame Übersetzungen extrahieren

Texte wie „Speichern“, „Abbrechen“, „Löschen“ tauchen überall auf – besser zentral verwalten:

messages/zh/common.json:

{
  "actions": {
    "save": "保存",
    "cancel": "取消",
    "delete": "删除",
    "confirm": "确认",
    "edit": "编辑"
  },
  "status": {
    "success": "操作成功",
    "error": "操作失败",
    "loading": "加载中..."
  }
}

Verwendung:

const t = useTranslations('common.actions');
<button>{t('save')}</button>

4. Übersetzungs-Tools nutzen

Bei großen Projekten wird manuelles JSON-Pflegen mühsam. Mögliche Tools:

  • Tolgee – Open-Source-Übersetzungsplattform mit Live-Bearbeitung
  • Localazy – automatisierte Übersetzungs-Workflows
  • i18n Ally (VSCode-Erweiterung) – Übersetzungen direkt im Editor verwalten

Ich nutze vor allem i18n Ally – beim Codieren sehe ich Übersetzungen direkt und kann sie schnell anpassen.

5. Fehlende Übersetzungen behandeln

In der Entwicklung fehlen oft noch Übersetzungen für einzelne Sprachen. Fallback-Logik konfigurieren:

// i18n.ts
export default getRequestConfig(async ({ locale }) => {
  const messages = (await import(`./messages/${locale}.json`)).default;
  const fallback = locale !== 'zh'
    ? (await import(`./messages/zh.json`)).default
    : {};

  return {
    messages: {
      ...fallback,
      ...messages
    }
  };
});

Fehlt eine englische Übersetzung, greift automatisch Chinesisch als Fallback.

Performance-Optimierung

1. Code-Splitting

Bei großen Übersetzungsdateien lazy loading nutzen:

// Nur bei Bedarf laden
export default function AdminPage() {
  const t = useTranslations('admin'); // nur admin-Namespace
  // ...
}

2. Statische Generierung

Für selten ändernde Seiten verbessert statisches Rendering die Performance deutlich:

// app/[locale]/about/page.tsx
export const dynamic = 'force-static';

export function generateStaticParams() {
  return [
    { locale: 'zh' },
    { locale: 'en' },
    { locale: 'ja' }
  ];
}

3. Übersetzungen vorladen

Für Above-the-fold-Inhalte Übersetzungen serverseitig vorladen:

import { getTranslations } from 'next-intl/server';

// Serverseitig vorladen
export default async function Home() {
  const t = await getTranslations('HomePage');

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

Häufige Probleme und Lösungen

1. Sprachwechsel bei dynamischen Routen

Bei dynamischen Routen (z. B. /blog/[slug]) muss der Slug beim Sprachwechsel erhalten bleiben:

const switchLanguage = (newLocale: string) => {
  const segments = pathname.split('/').filter(Boolean);
  // Altes Sprachpräfix entfernen
  if (['zh', 'en', 'ja'].includes(segments[0])) {
    segments.shift();
  }
  // Neues Sprachpräfix hinzufügen (falls nötig)
  if (newLocale !== 'zh' || localePrefix === 'always') {
    segments.unshift(newLocale);
  }
  router.push('/' + segments.join('/'));
};

2. SEO-Optimierung

Bei mehrsprachigen Websites verdient SEO besondere Aufmerksamkeit:

// app/[locale]/layout.tsx
export async function generateMetadata({ params: { locale } }) {
  const t = await getTranslations({ locale, namespace: 'metadata' });

  return {
    title: t('title'),
    description: t('description'),
    alternates: {
      canonical: `https://example.com/${locale}`,
      languages: {
        'zh-CN': 'https://example.com/zh',
        'en-US': 'https://example.com/en',
        'ja-JP': 'https://example.com/ja'
      }
    }
  };
}

3. Spracherkennung

Beim ersten Besuch die Nutzersprache automatisch erkennen:

// middleware.ts
import createMiddleware from 'next-intl/middleware';
import { NextRequest } from 'next/server';

const intlMiddleware = createMiddleware({
  locales: ['en', 'zh', 'ja'],
  defaultLocale: 'zh',
  localeDetection: true // automatische Erkennung aktivieren
});

export default function middleware(request: NextRequest) {
  return intlMiddleware(request);
}

next-intl wählt die Sprache anhand des Accept-Language-Headers.

4. Sprachpräferenz speichern

Nach manueller Sprachwahl sollte die Wahl gemerkt werden:

// Per Cookie speichern
const switchLanguage = (newLocale: string) => {
  document.cookie = `NEXT_LOCALE=${newLocale}; path=/; max-age=31536000`;
  router.push(newPath);
};

Die next-intl-Middleware liest dieses Cookie automatisch aus.

Praxisbeispiel: vollständiges i18n-Projekt

Zum Abschluss die wichtigsten Codeausschnitte aus einem kleinen Projekt, das ich umgesetzt habe:

Projektstruktur:

├── app/
│   ├── [locale]/
│   │   ├── layout.tsx
│   │   ├── page.tsx
│   │   └── blog/
│   │       └── [slug]/
│   │           └── page.tsx
├── components/
│   ├── LanguageSwitcher.tsx
│   └── Navigation.tsx
├── messages/
│   ├── zh/
│   │   ├── common.json
│   │   └── blog.json
│   ├── en/
│   │   ├── common.json
│   │   └── blog.json
├── i18n.ts
├── middleware.ts
└── navigation.ts

navigation.ts (Routing-Konfiguration):

import { createSharedPathnamesNavigation } from 'next-intl/navigation';

export const locales = ['zh', 'en'] as const;
export const localePrefix = 'as-needed';

export const { Link, redirect, usePathname, useRouter } =
  createSharedPathnamesNavigation({ locales, localePrefix });

components/Navigation.tsx:

'use client';

import { Link } from '@/navigation';
import { useTranslations } from 'next-intl';
import LanguageSwitcher from './LanguageSwitcher';

export default function Navigation() {
  const t = useTranslations('common.navigation');

  return (
    <nav className="flex items-center justify-between p-4">
      <div className="flex gap-4">
        <Link href="/">{t('home')}</Link>
        <Link href="/blog">{t('blog')}</Link>
        <Link href="/about">{t('about')}</Link>
      </div>
      <LanguageSwitcher />
    </nav>
  );
}

Nach dem Go-live lief der Sprachwechsel sehr flüssig – ohne nennenswerte Probleme.

Fazit

Internationalisierung im Next.js App Router wirkt zunächst komplex – mit next-intl ist sie aber gut beherrschbar:

  1. Kernkonfiguration: Middleware + i18n.ts + [locale]-Verzeichnis
  2. Übersetzungen nutzen: useTranslations-Hook in Server- und Client Components
  3. Routing: Link und Router von next-intl verwenden
  4. Dateiverwaltung: modular aufteilen + TypeScript-Typsicherheit
  5. Performance: statische Generierung + Lazy Loading

Ehrlich gesagt wirkte das Setup anfangs verschachtelt – besonders Middleware und dynamische Routen. Nach ein paar Projekten ist es Routine; für i18n-Projekte nutze ich fast immer dieses Muster.

Wenn Sie ein mehrsprachiges Projekt planen oder bereits daran arbeiten, lohnt sich next-intl. Der Lernaufwand zahlt sich langfristig aus.

Referenzen

Ich hoffe, dieser Artikel hilft Ihnen bei der Next.js-Internationalisierung!

Next.js Internationalisierung – vollständiger Konfigurationsablauf

Vom Installieren von next-intl bis zur Konfiguration mehrsprachiger Routen und Übersetzungsdateien – Schritt für Schritt

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: next-intl installieren und Grundkonfiguration

    Installation:
    ```bash
    npm install next-intl
    ```

    Übersetzungsdateien anlegen:
    ```
    messages/
    zh.json
    en.json
    ```

    middleware.ts konfigurieren:
    ```ts
    import createMiddleware from 'next-intl/middleware'
    import { routing } from './i18n/routing'

    export default createMiddleware(routing)

    export const config = {
    matcher: ['/', '/(zh|en)/:path*']
    }
    ```

    app/[locale]/layout.tsx konfigurieren:
    ```tsx
    import { NextIntlClientProvider } from 'next-intl'
    import { getMessages } from 'next-intl/server'

    export default async function LocaleLayout({
    children,
    params: { locale }
    }) {
    const messages = await getMessages()

    return (
    <html lang={locale}>
    <body>
    <NextIntlClientProvider messages={messages}>
    {children}
    </NextIntlClientProvider>
    </body>
    </html>
    )
    }
    ```

    Wichtige Punkte:
    • [locale]-Dynamikroute verwenden
    • Übersetzungen im Layout bereitstellen
    • Middleware für Sprachwechsel konfigurieren
  2. 2

    Step 2: Mehrsprachige Routing-Strategie konfigurieren

    Strategie 1: Unterpfad (empfohlen)
    • URL-Format: /zh/about, /en/about
    • Einfache Konfiguration
    • SEO-freundlich

    Strategie 2: Domain
    • URL-Format: zh.example.com, en.example.com
    • Mehrere Domains nötig
    • Professioneller

    Strategie 3: Cookie
    • Sprache per Cookie umschalten
    • URL ohne Sprachpräfix
    • Für einsprachige Nutzer geeignet

    Unterpfad konfigurieren:
    ```ts
    // i18n/routing.ts
    export const routing = {
    locales: ['zh', 'en'],
    defaultLocale: 'zh'
    }
    ```

    Verwendung:
    ```tsx
    import { useTranslations } from 'next-intl'

    export function Page() {
    const t = useTranslations('common')
    return <h1>{t('title')}</h1>
    }
    ```

    Wichtiger Punkt: Wählen Sie die passende Routing-Strategie – für die meisten Projekte reicht der Unterpfad.
  3. 3

    Step 3: Übersetzungsdateien verwalten

    Übersetzungsdatei anlegen:
    ```json
    // messages/zh.json
    {
    "common": {
    "title": "欢迎",
    "description": "这是一个多语言网站"
    },
    "nav": {
    "home": "首页",
    "about": "关于"
    }
    }
    ```

    Übersetzung nutzen:
    ```tsx
    import { useTranslations } from 'next-intl'

    export function Page() {
    const t = useTranslations('common')
    return (
    <div>
    <h1>{t('title')}</h1>
    <p>{t('description')}</p>
    </div>
    )
    }
    ```

    Typsicherheit:
    ```ts
    // i18n/request.ts
    import { getRequestConfig } from 'next-intl/server'

    export default getRequestConfig(async ({ locale }) => ({
    messages: (await import(`../messages/${locale}.json`)).default
    }))
    ```

    Wichtige Punkte:
    • Verschachtelte Struktur für Übersetzungen
    • TypeScript für Typsicherheit
    • i18n-Ally-VSCode-Erweiterung für bessere Developer Experience

FAQ

Warum braucht der App Router next-intl?
Grund: Der App Router hat die eingebaute i18n-Funktion des Pages Router entfernt.

Pages Router:
• Eingebaute i18n-Routing-Unterstützung
• i18n-Feld in next.config.js konfigurieren
• Automatischer Sprachwechsel

App Router:
• Keine eingebaute i18n-Funktion mehr
• Drittanbieter-Bibliotheken erforderlich
• next-intl ist die beliebteste Wahl

next-intl-Vorteile:
• Native App-Router-Unterstützung
• Typsicherheit
• Flexible Routing-Strategien
• Umfangreiche Funktionen (Plural, Datumsformatierung usw.)
• Gute Performance

Empfehlung: Bei App Router next-intl bevorzugen.
Welche Routing-Strategien bietet next-intl?
Drei Routing-Strategien:

Strategie 1: Unterpfad (empfohlen)
• URL-Format: /zh/about, /en/about
• Einfache Konfiguration
• SEO-freundlich
• Für die meisten Projekte geeignet

Strategie 2: Domain
• URL-Format: zh.example.com, en.example.com
• Mehrere Domains nötig
• Professioneller
• Für große Projekte

Strategie 3: Cookie
• Sprache per Cookie umschalten
• URL ohne Sprachpräfix
• Für einsprachige Nutzer
• Komplexere Konfiguration

Auswahl:
• Die meisten Projekte → Unterpfad
• Große Projekte → Domain
• Spezielle Anforderungen → Cookie

Wichtiger Punkt: Für die meisten Projekte reicht der Unterpfad.
Wie konfiguriert man next-intl?
Installation:
```bash
npm install next-intl
```

Übersetzungsdateien anlegen:
```
messages/
zh.json
en.json
```

middleware.ts konfigurieren:
```ts
import createMiddleware from 'next-intl/middleware'
import { routing } from './i18n/routing'

export default createMiddleware(routing)

export const config = {
matcher: ['/', '/(zh|en)/:path*']
}
```

app/[locale]/layout.tsx konfigurieren:
```tsx
import { NextIntlClientProvider } from 'next-intl'
import { getMessages } from 'next-intl/server'

export default async function LocaleLayout({
children,
params: { locale }
}) {
const messages = await getMessages()

return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
)
}
```

Wichtige Punkte:
• [locale]-Dynamikroute verwenden
• Übersetzungen im Layout bereitstellen
• Middleware für Sprachwechsel konfigurieren
Wie verwaltet man Übersetzungsdateien?
Übersetzungsdatei anlegen:
```json
// messages/zh.json
{
"common": {
"title": "欢迎",
"description": "这是一个多语言网站"
},
"nav": {
"home": "首页",
"about": "关于"
}
}
```

Übersetzung nutzen:
```tsx
import { useTranslations } from 'next-intl'

export function Page() {
const t = useTranslations('common')
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</div>
)
}
```

Typsicherheit:
```ts
// i18n/request.ts
import { getRequestConfig } from 'next-intl/server'

export default getRequestConfig(async ({ locale }) => ({
messages: (await import(`../messages/${locale}.json`)).default
}))
```

Wichtige Punkte:
• Verschachtelte Struktur für Übersetzungen
• TypeScript für Typsicherheit
• i18n-Ally-VSCode-Erweiterung für bessere Developer Experience

Empfehlung: Übersetzungsdateien nach Funktionsmodulen organisieren, keine zu großen Einzeldateien.
Welche Funktionen unterstützt next-intl?
Kernfunktionen:
• Übersetzungstexte (t-Funktion)
• Pluralisierung
• Datumsformatierung
• Zahlenformatierung
• Rich-Text-Unterstützung

Beispiel:
```tsx
import { useTranslations, useFormatter } from 'next-intl'

export function Page() {
const t = useTranslations('common')
const format = useFormatter()

return (
<div>
<h1>{t('title')}</h1>
<p>{format.dateTime(new Date(), { dateStyle: 'long' })}</p>
<p>{format.number(1234.56, { style: 'currency', currency: 'USD' })}</p>
</div>
)
}
```

Vorteile:
• Umfangreiche Funktionen
• Typsicherheit
• Gute Performance
• Server-Component-freundlich

Empfehlung: next-intl-Funktionen voll nutzen, um die Nutzererfahrung zu verbessern.
Wie implementiert man den Sprachwechsel?
Link-Komponente nutzen:
```tsx
import { Link } from '@/i18n/navigation'

<Link href="/about" locale="en">
English
</Link>
<Link href="/about" locale="zh">
中文
</Link>
```

useRouter nutzen:
```tsx
'use client'
import { useRouter, usePathname } from '@/i18n/navigation'

export function LanguageSwitcher() {
const router = useRouter()
const pathname = usePathname()

const switchLanguage = (locale: string) => {
router.replace(pathname, { locale })
}

return (
<button onClick={() => switchLanguage('en')}>
English
</button>
)
}
```

Wichtige Punkte:
• Link und useRouter von next-intl verwenden
• Aktuellen Pfad beibehalten, nur Sprache wechseln
• Gute Nutzererfahrung

Empfehlung: Sprachumschalter in Navigation oder Footer platzieren.

11 Min. Lesezeit · Veröffentlicht am: 25. Dez. 2025 · Aktualisiert am: 14. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog