@intlayer/docs 6.1.4 → 6.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +1135 -75
  2. package/blog/ar/nextjs-multilingual-seo-comparison.md +364 -0
  3. package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +1139 -72
  4. package/blog/de/nextjs-multilingual-seo-comparison.md +362 -0
  5. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +224 -240
  6. package/blog/en/nextjs-multilingual-seo-comparison.md +360 -0
  7. package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1134 -37
  8. package/blog/en-GB/nextjs-multilingual-seo-comparison.md +360 -0
  9. package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +1122 -64
  10. package/blog/es/nextjs-multilingual-seo-comparison.md +363 -0
  11. package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1132 -75
  12. package/blog/fr/nextjs-multilingual-seo-comparison.md +362 -0
  13. package/blog/hi/nextjs-multilingual-seo-comparison.md +363 -0
  14. package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1120 -55
  15. package/blog/it/nextjs-multilingual-seo-comparison.md +363 -0
  16. package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1140 -76
  17. package/blog/ja/nextjs-multilingual-seo-comparison.md +362 -0
  18. package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1129 -73
  19. package/blog/ko/nextjs-multilingual-seo-comparison.md +362 -0
  20. package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1133 -76
  21. package/blog/pt/nextjs-multilingual-seo-comparison.md +362 -0
  22. package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1142 -74
  23. package/blog/ru/nextjs-multilingual-seo-comparison.md +370 -0
  24. package/blog/tr/nextjs-multilingual-seo-comparison.md +362 -0
  25. package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1142 -75
  26. package/blog/zh/nextjs-multilingual-seo-comparison.md +394 -0
  27. package/dist/cjs/generated/blog.entry.cjs +16 -0
  28. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  29. package/dist/esm/generated/blog.entry.mjs +16 -0
  30. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  31. package/dist/types/generated/blog.entry.d.ts +1 -0
  32. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  33. package/docs/en/interest_of_intlayer.md +2 -2
  34. package/package.json +10 -10
  35. package/src/generated/blog.entry.ts +16 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2025-08-23
3
- updatedAt: 2025-08-23
3
+ updatedAt: 2025-09-29
4
4
  title: next-i18next vs next-intl vs Intlayer
5
5
  description: Vergleich von next-i18next mit next-intl und Intlayer für die Internationalisierung (i18n) einer Next.js-App
6
6
  keywords:
@@ -19,144 +19,1211 @@ slugs:
19
19
 
20
20
  # next-i18next VS next-intl VS intlayer | Next.js Internationalisierung (i18n)
21
21
 
22
- Dieser Leitfaden vergleicht drei weit verbreitete i18n-Optionen für **Next.js**: **next-intl**, **next-i18next** und **Intlayer**.
22
+ Werfen wir einen Blick auf die Gemeinsamkeiten und Unterschiede zwischen drei i18n-Optionen für Next.js: next-i18next, next-intl und Intlayer.
23
+
24
+ Dies ist kein vollständiges Tutorial. Es ist ein Vergleich, der Ihnen bei der Auswahl helfen soll.
25
+
23
26
  Wir konzentrieren uns auf den **Next.js 13+ App Router** (mit **React Server Components**) und bewerten:
24
27
 
25
28
  1. **Architektur & Inhaltsorganisation**
26
29
  2. **TypeScript & Sicherheit**
27
30
  3. **Umgang mit fehlenden Übersetzungen**
28
31
  4. **Routing & Middleware**
29
- 5. **Leistung & Ladeverhalten**
30
- 6. **Entwicklererfahrung (DX), Werkzeuge & Wartung**
32
+ 5. **Performance & Ladeverhalten**
33
+ 6. **Entwicklererfahrung (DX), Tools & Wartung**
31
34
  7. **SEO & Skalierbarkeit bei großen Projekten**
32
35
 
33
36
  > **Kurzfassung**: Alle drei können eine Next.js-App lokalisieren. Wenn Sie **komponentenbezogenen Inhalt**, **strenge TypeScript-Typen**, **Build-Zeit-Prüfungen fehlender Schlüssel**, **tree-shakbare Wörterbücher** und **erstklassige App Router- und SEO-Hilfen** wünschen, ist **Intlayer** die vollständigste und modernste Wahl.
34
37
 
38
+ > Eine häufige Verwirrung bei Entwicklern ist die Annahme, dass `next-intl` die Next.js-Version von `react-intl` sei. Das ist nicht der Fall – `next-intl` wird von [Amann](https://github.com/amannn) gepflegt, während `react-intl` von [FormatJS](https://github.com/formatjs/formatjs) betreut wird.
39
+
40
+ ---
41
+
42
+ ## Kurz gesagt
43
+
44
+ - **next-intl** – Leichtgewichtiges, unkompliziertes Nachrichtenformat mit solider Next.js-Unterstützung. Zentralisierte Kataloge sind üblich; die Entwicklererfahrung (DX) ist einfach, aber Sicherheit und großflächige Wartung bleiben größtenteils Ihre Verantwortung.
45
+ - **next-i18next** – i18next im Next.js-Gewand. Ausgereiftes Ökosystem und Funktionen über Plugins (z. B. ICU), aber die Konfiguration kann umfangreich sein und Kataloge neigen dazu, mit wachsendem Projekt zentralisiert zu werden.
46
+ - **Intlayer** – Komponentenorientiertes Inhaltsmodell für Next.js, **strikte TS-Typisierung**, **Build-Zeit-Prüfungen**, **Tree-Shaking**, **eingebaute Middleware- & SEO-Hilfen**, optionaler **Visueller Editor/CMS** und **KI-unterstützte Übersetzungen**.
47
+
48
+ ---
49
+
50
+ | Library | GitHub Stars | Total Commits | Last Commit | First Version | NPM Version | NPM Downloads |
51
+ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
52
+ | `aymericzip/intlayer` | [![GitHub Repo stars](https://img.shields.io/github/stars/aymericzip/intlayer?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/aymericzip/intlayer/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/aymericzip/intlayer?style=for-the-badge&label=commits)](https://github.com/aymericzip/intlayer/commits) | [![Last Commit](https://img.shields.io/github/last-commit/aymericzip/intlayer?style=for-the-badge)](https://github.com/aymericzip/intlayer/commits) | April 2024 | [![npm](https://img.shields.io/npm/v/intlayer?style=for-the-badge)](https://www.npmjs.com/package/intlayer) | [![npm downloads](https://img.shields.io/npm/dm/intlayer?style=for-the-badge)](https://www.npmjs.com/package/intlayer) |
53
+ | `amannn/next-intl` | [![GitHub Repo stars](https://img.shields.io/github/stars/amannn/next-intl?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/amannn/next-intl/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/amannn/next-intl?style=for-the-badge&label=commits)](https://github.com/amannn/next-intl/commits) | [![Last Commit](https://img.shields.io/github/last-commit/amannn/next-intl?style=for-the-badge)](https://github.com/amannn/next-intl/commits) | Nov 2020 | [![npm](https://img.shields.io/npm/v/next-intl?style=for-the-badge)](https://www.npmjs.com/package/next-intl) | [![npm downloads](https://img.shields.io/npm/dm/next-intl?style=for-the-badge)](https://www.npmjs.com/package/next-intl) |
54
+ | `i18next/i18next` | [![GitHub Repo stars](https://img.shields.io/github/stars/i18next/i18next?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/i18next/i18next/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/i18next/i18next?style=for-the-badge&label=commits)](https://github.com/i18next/i18next/commits) | [![Last Commit](https://img.shields.io/github/last-commit/i18next/i18next?style=for-the-badge)](https://github.com/i18next/i18next/commits) | Jan 2012 | [![npm](https://img.shields.io/npm/v/i18next?style=for-the-badge)](https://www.npmjs.com/package/i18next) | [![npm downloads](https://img.shields.io/npm/dm/i18next?style=for-the-badge)](https://www.npmjs.com/package/i18next) |
55
+ | `i18next/next-i18next` | [![GitHub Repo stars](https://img.shields.io/github/stars/i18next/next-i18next?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/i18next/next-i18next/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/i18next/next-i18next?style=for-the-badge&label=commits)](https://github.com/i18next/next-i18next/commits) | [![Last Commit](https://img.shields.io/github/last-commit/i18next/next-i18next?style=for-the-badge)](https://github.com/i18next/next-i18next/commits) | Nov 2018 | [![npm](https://img.shields.io/npm/v/next-i18next?style=for-the-badge)](https://www.npmjs.com/package/next-i18next) | [![npm downloads](https://img.shields.io/npm/dm/next-i18next?style=for-the-badge)](https://www.npmjs.com/package/next-i18next) |
56
+
57
+ > Abzeichen werden automatisch aktualisiert. Schnappschüsse können sich im Laufe der Zeit ändern.
58
+
35
59
  ---
36
60
 
37
- ## Übergeordnete Positionierung
61
+ ## Gegenüberstellung der Funktionen (Fokus auf Next.js)
62
+
63
+ | Funktion | `next-intlayer` (Intlayer) | `next-intl` | `next-i18next` |
38
64
 
39
- - **next-intl** - Leichtgewichtiges, unkompliziertes Nachrichtenformat mit solider Next.js-Unterstützung. Zentralisierte Kataloge sind üblich; die Entwicklererfahrung ist einfach, aber Sicherheit und großflächige Wartung liegen größtenteils in Ihrer Verantwortung.
40
- - **next-i18next** - i18next im Next.js-Gewand. Ausgereiftes Ökosystem und Funktionen über Plugins (z. B. ICU), aber die Konfiguration kann umfangreich sein und Kataloge neigen dazu, mit wachsendem Projektumfang zentralisiert zu werden.
41
- - **Intlayer** - Komponentenorientiertes Inhaltsmodell für Next.js, **strenge TS-Typisierung**, **Build-Zeit-Prüfungen**, **Tree-Shaking**, **eingebaute Middleware- und SEO-Hilfen**, optionaler **Visueller Editor/CMS** und **KI-unterstützte Übersetzungen**.
65
+ > Abzeichen werden automatisch aktualisiert. Screenshots können sich im Laufe der Zeit ändern.
42
66
 
43
67
  ---
44
68
 
45
- ## Vergleich der Funktionen im Überblick (Fokus auf Next.js)
69
+ ## Gegenüberstellung der Funktionen (Fokus auf Next.js)
46
70
 
47
- | Funktion | `next-intlayer` (Intlayer) | `next-intl` | `next-i18next` |
48
- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
49
- | **Übersetzungen in der Nähe der Komponenten** | ✅ Ja, Inhalt ist mit jeder Komponente zusammengefasst | ❌ Nein | ❌ Nein |
50
- | **TypeScript-Integration** | ✅ Fortgeschritten, automatisch generierte strenge Typen | ✅ Gut | ⚠️ Grundlegend |
51
- | **Fehlende Übersetzungserkennung** | ✅ TypeScript-Fehlerhervorhebung und Fehler-/Warnmeldung zur Build-Zeit | ⚠️ Laufzeit-Fallback | ⚠️ Laufzeit-Fallback |
52
- | **Reicher Inhalt (JSX/Markdown/Komponenten)** | ✅ Direkte Unterstützung | ❌ Nicht für komplexe Knoten ausgelegt | ⚠️ Eingeschränkt |
53
- | **KI-gestützte Übersetzung** | ✅ Ja, unterstützt mehrere KI-Anbieter. Nutzbar mit eigenen API-Schlüsseln. Berücksichtigt den Kontext Ihrer Anwendung und den Umfang des Inhalts | ❌ Nein | ❌ Nein |
54
- | **Visueller Editor** | ✅ Ja, lokaler visueller Editor + optionales CMS; kann Codebasis-Inhalte auslagern; einbettbar | ❌ Nein / verfügbar über externe Lokalisierungsplattformen | ❌ Nein / verfügbar über externe Lokalisierungsplattformen |
55
- | **Lokalisierte Routenführung** | ✅ Ja, unterstützt lokalisierte Pfade direkt (funktioniert mit Next.js & Vite) | ✅ Integriert, App Router unterstützt `[locale]` Segment | ✅ Integriert |
56
- | **Dynamische Routen-Generierung** | ✅ Ja | ✅ Ja | ✅ Ja |
57
- | **Pluralisierung** | ✅ Aufzählungsbasierte Muster | ✅ Gut | ✅ Gut |
58
- | **Formatierung (Daten, Zahlen, Währungen)** | ✅ Optimierte Formatierer (Intl im Hintergrund) | ✅ Gut (Intl-Hilfsmittel) | ✅ Gut (Intl-Hilfsmittel) |
59
- | **Inhaltsformat** | ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml in Arbeit) | ✅ .json, .js, .ts | ⚠️ .json |
60
- | **ICU-Unterstützung** | ⚠️ In Arbeit | ✅ Ja | ⚠️ Über Plugin (`i18next-icu`) |
61
- | **SEO-Helfer (hreflang, Sitemap)** | ✅ Eingebaute Werkzeuge: Helfer für Sitemap, robots.txt, Metadaten | ✅ Gut | ✅ Gut |
62
- | **Ökosystem / Community** | ⚠️ Kleinere, aber schnell wachsende und reaktive Community | ✅ Mittelgroß, Next.js-fokussiert | ✅ Mittelgroß, Next.js-fokussiert |
63
- | **Server-seitiges Rendering & Server-Komponenten** | ✅ Ja, optimiert für SSR / React Server-Komponenten | ⚠️ Unterstützt auf Seitenebene, aber t-Funktionen müssen im Komponentenbaum für untergeordnete Server-Komponenten übergeben werden | ⚠️ Unterstützt auf Seitenebene, aber t-Funktionen müssen im Komponentenbaum für untergeordnete Server-Komponenten übergeben werden |
64
- | **Tree-shaking (nur genutzte Inhalte laden)** | ✅ Ja, pro Komponente zur Build-Zeit über Babel/SWC-Plugins | ⚠️ Teilweise | ⚠️ Teilweise |
65
- | **Lazy Loading** | ✅ Ja, pro Locale / pro Wörterbuch | ✅ Ja (pro Route/pro Locale), benötigt Namespace-Verwaltung | ✅ Ja (pro Route/pro Locale), benötigt Namespace-Verwaltung |
66
- | **Bereinigung ungenutzter Inhalte** | ✅ Ja, pro Wörterbuch zur Build-Zeit | ❌ Nein, kann manuell mit Namespace-Verwaltung gehandhabt werden | ❌ Nein, kann manuell mit Namespace-Verwaltung gehandhabt werden |
67
- | **Management großer Projekte** | ✅ Fördert Modularität, geeignet für Design-Systeme | ✅ Modular mit Setup | ✅ Modular mit Setup |
71
+ | Funktion | `next-intlayer` (Intlayer) | `next-intl` | `next-i18next` |
72
+ | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
73
+ | **Übersetzungen in der Nähe der Komponenten** | ✅ Ja, Inhalt ist mit jeder Komponente zusammengefasst | ❌ Nein | ❌ Nein |
74
+ | **TypeScript-Integration** | ✅ Fortgeschritten, automatisch generierte strenge Typen | ✅ Gut | ⚠️ Grundlegend |
75
+ | **Erkennung fehlender Übersetzungen** | ✅ TypeScript-Fehlerhervorhebung und Fehler-/Warnmeldung zur Build-Zeit | ⚠️ Laufzeit-Fallback | ⚠️ Laufzeit-Fallback |
76
+ | **Reicher Inhalt (JSX/Markdown/Komponenten)** | ✅ Direkte Unterstützung | ❌ Nicht für komplexe Knoten ausgelegt | ⚠️ Eingeschränkt |
77
+ | **KI-gestützte Übersetzung** | ✅ Ja, unterstützt mehrere KI-Anbieter. Nutzbar mit eigenen API-Schlüsseln. Berücksichtigt den Kontext Ihrer Anwendung und den Umfang des Inhalts | ❌ Nein | ❌ Nein |
78
+ | **Visueller Editor** | ✅ Ja, lokaler visueller Editor + optionales CMS; kann Codebasis-Inhalte auslagern; einbettbar | ❌ Nein / verfügbar über externe Lokalisierungsplattformen | ❌ Nein / verfügbar über externe Lokalisierungsplattformen |
79
+ | **Lokalisierte Routenführung** | ✅ Ja, unterstützt lokalisierte Pfade direkt (funktioniert mit Next.js & Vite) | ✅ Eingebaut, App Router unterstützt `[locale]` Segment | ✅ Eingebaut |
80
+ | **Dynamische Routen-Generierung** | ✅ Ja | ✅ Ja | ✅ Ja |
81
+ | **Pluralisierung** | ✅ Aufzählungsbasierte Muster | ✅ Gut | ✅ Gut |
82
+ | **Formatierung (Daten, Zahlen, Währungen)** | ✅ Optimierte Formatierer (Intl im Hintergrund) | ✅ Gut (Intl-Helfer) | ✅ Gut (Intl-Helfer) |
83
+ | **Inhaltsformat** | ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml in Arbeit) | ✅ .json, .js, .ts | ⚠️ .json |
84
+ | **ICU-Unterstützung** | ⚠️ In Arbeit | ✅ Ja | ⚠️ Über Plugin (`i18next-icu`) |
85
+ | **SEO-Helfer (hreflang, Sitemap)** | ✅ Eingebaute Werkzeuge: Helfer für Sitemap, robots.txt, Metadaten | ✅ Gut | ✅ Gut |
86
+ | **Ökosystem / Community** | ⚠️ Kleiner, wächst aber schnell und ist reaktiv | ✅ Gut | ✅ Gut |
87
+ | **Server-seitiges Rendering & Server-Komponenten** | ✅ Ja, optimiert für SSR / React Server-Komponenten | ⚠️ Auf Seitenebene unterstützt, aber t-Funktionen müssen im Komponentenbaum an untergeordnete Server-Komponenten weitergegeben werden | ⚠️ Auf Seitenebene unterstützt, aber t-Funktionen müssen im Komponentenbaum an untergeordnete Server-Komponenten weitergegeben werden |
88
+ | **Tree-shaking (nur verwendeten Inhalt laden)** | ✅ Ja, pro Komponente zur Build-Zeit über Babel/SWC-Plugins | ⚠️ Teilweise | ⚠️ Teilweise |
89
+ | **Lazy Loading** | ✅ Ja, pro Sprache / pro Wörterbuch | ✅ Ja (pro Route/pro Sprache), benötigt Namespace-Verwaltung | ✅ Ja (pro Route/pro Sprache), benötigt Namespace-Verwaltung |
90
+ | **Bereinigung ungenutzter Inhalte** | ✅ Ja, pro Wörterbuch zur Build-Zeit | ❌ Nein, kann manuell mit Namespace-Verwaltung gehandhabt werden | ❌ Nein, kann manuell mit Namespace-Verwaltung gehandhabt werden |
91
+ | **Verwaltung großer Projekte** | ✅ Fördert Modularität, geeignet für Design-Systeme | ✅ Modular mit Setup | ✅ Modular mit Setup |
92
+ | **Testen fehlender Übersetzungen (CLI/CI)** | ✅ CLI: `npx intlayer content test` (CI-freundliches Audit) | ⚠️ Nicht eingebaut; Dokumentation empfiehlt `npx @lingual/i18n-check` | ⚠️ Nicht eingebaut; verlässt sich auf i18next-Tools / Laufzeit `saveMissing` |
68
93
 
69
94
  ---
70
95
 
71
- ## Tiefgehender Vergleich
96
+ ## Einführung
72
97
 
73
- ### 1) Architektur & Skalierbarkeit
98
+ Next.js bietet integrierte Unterstützung für internationalisierte Routen (z.B. Lokalisierungssegmente). Diese Funktion übernimmt jedoch nicht automatisch die Übersetzungen. Sie benötigen weiterhin eine Bibliothek, um lokalisierten Inhalt für Ihre Nutzer darzustellen.
74
99
 
75
- - **next-intl / next-i18next**: Standardmäßig **zentralisierte Kataloge** pro Locale (plus **Namespaces** in i18next). Funktioniert anfangs gut, wird aber oft zu einer großen gemeinsamen Oberfläche mit zunehmender Kopplung und Schlüsseländerungen.
76
- - **Intlayer**: Fördert **pro Komponente** (oder pro Funktion) **lokalisierte Wörterbücher**, die **direkt am Code** liegen, den sie bedienen. Dies reduziert die kognitive Belastung, erleichtert die Duplizierung/Migration von UI-Elementen und verringert Konflikte zwischen Teams. Unbenutzte Inhalte sind so leichter zu erkennen und zu entfernen.
100
+ Es gibt viele i18n-Bibliotheken, aber in der Next.js-Welt gewinnen heute drei an Bedeutung: next-i18next, next-intl und Intlayer.
101
+
102
+ ---
103
+
104
+ ## Architektur & Skalierbarkeit
105
+
106
+ - **next-intl / next-i18next**: Standardmäßig **zentralisierte Kataloge** pro Locale (plus **Namespaces** in i18next). Funktioniert anfangs gut, wird aber oft zu einer großen gemeinsamen Oberfläche mit zunehmender Kopplung und Schlüsselwechsel.
107
+ - **Intlayer**: Fördert **pro-Komponenten** (oder pro-Feature) Wörterbücher, die **am selben Ort** wie der zugehörige Code liegen. Dies reduziert die kognitive Belastung, erleichtert die Duplizierung/Migration von UI-Teilen und verringert Konflikte zwischen Teams. Unbenutzter Inhalt ist so natürlicherweise leichter zu erkennen und zu entfernen.
77
108
 
78
109
  **Warum das wichtig ist:** In großen Codebasen oder Design-System-Setups skaliert **modularer Inhalt** besser als monolithische Kataloge.
79
110
 
80
111
  ---
81
112
 
82
- ### 2) TypeScript & Sicherheit
113
+ ## Bundle-Größen & Abhängigkeiten
83
114
 
84
- - **next-intl**: Solide TypeScript-Unterstützung, aber **Schlüssel sind standardmäßig nicht strikt typisiert**; Sicherheitsmuster müssen manuell gepflegt werden.
85
- - **next-i18next**: Basis-Typen für Hooks; **strikte Schlüsseltypisierung erfordert zusätzliche Tools/Konfiguration**.
86
- - **Intlayer**: **Erzeugt strenge Typen** aus Ihren Inhalten. **IDE-Autovervollständigung** und **Kompilierzeitfehler** erkennen Tippfehler und fehlende Schlüssel vor der Bereitstellung.
115
+ Nach dem Erstellen der Anwendung ist das Bundle das JavaScript, das der Browser zum Rendern der Seite lädt. Die Bundle-Größe ist daher wichtig für die Anwendungsleistung.
87
116
 
88
- **Warum das wichtig ist:** Starke Typisierung verschiebt Fehler **nach links** (CI/Build) statt **nach rechts** (Laufzeit).
117
+ Zwei Komponenten sind im Kontext eines mehrsprachigen Anwendungs-Bundles wichtig:
118
+
119
+ - Der Anwendungscode
120
+ - Der vom Browser geladene Inhalt
121
+
122
+ ## Anwendungscode
123
+
124
+ Die Bedeutung des Anwendungscodes ist in diesem Fall minimal. Alle drei Lösungen sind tree-shakable, was bedeutet, dass ungenutzte Teile des Codes nicht im Bundle enthalten sind.
125
+
126
+ Hier ist ein Vergleich der JavaScript-Bundle-Größe, die der Browser für eine mehrsprachige Anwendung mit den drei Lösungen lädt.
127
+
128
+ Wenn wir keinen Formatter in der Anwendung benötigen, ist die Liste der exportierten Funktionen nach dem Tree-Shaking wie folgt:
129
+
130
+ - **next-intlayer**: `useIntlayer`, `useLocale`, `NextIntlClientProvider`, (Paketgröße ist 180,6 kB -> 78,6 kB (gzip))
131
+ - **next-intl**: `useTranslations`, `useLocale`, `NextIntlClientProvider`, (Paketgröße ist 101,3 kB -> 31,4 kB (gzip))
132
+ - **next-i18next**: `useTranslation`, `useI18n`, `I18nextProvider`, (Paketgröße ist 80,7 kB -> 25,5 kB (gzip))
133
+
134
+ Diese Funktionen sind nur Wrapper um den React-Kontext/-Status, daher ist der Gesamteinfluss der i18n-Bibliothek auf die Paketgröße minimal.
135
+
136
+ > Intlayer ist etwas größer als `next-intl` und `next-i18next`, da es mehr Logik in der Funktion `useIntlayer` enthält. Dies hängt mit der Integration von Markdown und `intlayer-editor` zusammen.
137
+
138
+ ## Inhalt und Übersetzungen
139
+
140
+ Dieser Teil wird von Entwicklern oft ignoriert, aber betrachten wir den Fall einer Anwendung, die aus 10 Seiten in 10 Sprachen besteht. Nehmen wir zur Vereinfachung der Berechnung an, dass jede Seite zu 100 % einzigartigen Inhalt enthält (in Wirklichkeit ist viel Inhalt zwischen den Seiten redundant, z. B. Seitentitel, Kopfzeile, Fußzeile usw.).
141
+
142
+ Ein Benutzer, der die Seite `/fr/about` besuchen möchte, lädt den Inhalt einer Seite in einer bestimmten Sprache. Das Ignorieren der Inhaltsoptimierung würde bedeuten, dass unnötigerweise 8.200 % `((1 + (((10 Seiten - 1) × (10 Sprachen - 1)))) × 100)` des Anwendungsinhalts geladen werden. Sehen Sie das Problem? Selbst wenn dieser Inhalt nur Text ist und Sie wahrscheinlich eher daran denken, die Bilder Ihrer Website zu optimieren, senden Sie unnötigen Inhalt über den Globus und lassen die Computer der Benutzer ihn umsonst verarbeiten.
143
+
144
+ Zwei wichtige Probleme:
145
+
146
+ - **Aufteilung nach Route:**
147
+
148
+ > Wenn ich mich auf der Seite `/about` befinde, möchte ich nicht den Inhalt der Seite `/home` laden.
149
+
150
+ - **Aufteilung nach Sprache:**
151
+
152
+ > Wenn ich mich auf der Seite `/fr/about` befinde, möchte ich nicht den Inhalt der Seite `/en/about` laden.
153
+
154
+ Alle drei Lösungen sind sich dieser Probleme bewusst und ermöglichen die Verwaltung dieser Optimierungen. Der Unterschied zwischen den drei Lösungen liegt in der DX (Developer Experience).
155
+
156
+ `next-intl` und `next-i18next` verwenden einen zentralisierten Ansatz zur Verwaltung von Übersetzungen, der es erlaubt, JSON-Dateien nach Sprache und Unterdateien aufzuteilen. In `next-i18next` nennen wir die JSON-Dateien „Namespaces“; `next-intl` erlaubt das Deklarieren von Nachrichten. In `intlayer` nennen wir die JSON-Dateien „Dictionaries“.
157
+
158
+ - Im Fall von `next-intl`, ähnlich wie bei `next-i18next`, wird der Inhalt auf Seiten-/Layout-Ebene geladen, und dieser Inhalt wird dann in einen Context-Provider geladen. Das bedeutet, dass der Entwickler die JSON-Dateien, die für jede Seite geladen werden sollen, manuell verwalten muss.
159
+
160
+ > In der Praxis bedeutet dies, dass Entwickler diese Optimierung oft überspringen und es vorziehen, aus Einfachheitsgründen den gesamten Inhalt im Context-Provider der Seite zu laden.
161
+
162
+ - Im Fall von `intlayer` wird der gesamte Inhalt in der Anwendung geladen. Anschließend kümmert sich ein Plugin (`@intlayer/babel` / `@intlayer/swc`) darum, das Bundle zu optimieren, indem nur der auf der Seite verwendete Inhalt geladen wird. Der Entwickler muss daher die zu ladenden Wörterbücher nicht manuell verwalten. Dies ermöglicht eine bessere Optimierung, bessere Wartbarkeit und reduziert die Entwicklungszeit.
163
+
164
+ Da die Anwendung wächst (insbesondere wenn mehrere Entwickler an der Anwendung arbeiten), ist es üblich, dass vergessen wird, nicht mehr verwendete Inhalte aus den JSON-Dateien zu entfernen.
165
+
166
+ > Beachten Sie, dass in allen Fällen (next-intl, next-i18next, intlayer) alle JSON-Dateien geladen werden.
167
+
168
+ Deshalb ist der Ansatz von Intlayer leistungsfähiger: Wenn eine Komponente nicht mehr verwendet wird, wird ihr Wörterbuch nicht im Bundle geladen.
169
+
170
+ Wie die Bibliothek mit Fallbacks umgeht, ist ebenfalls wichtig. Nehmen wir an, die Anwendung ist standardmäßig auf Englisch eingestellt und der Benutzer besucht die Seite `/fr/about`. Wenn Übersetzungen auf Französisch fehlen, wird der englische Fallback berücksichtigt.
171
+
172
+ Im Fall von `next-intl` und `next-i18next` erfordert die Bibliothek das Laden der JSON-Dateien, die sowohl zur aktuellen Locale als auch zur Fallback-Locale gehören. Somit lädt jede Seite, vorausgesetzt alle Inhalte sind übersetzt, 100 % unnötigen Inhalt. **Im Vergleich dazu verarbeitet `intlayer` das Fallback bereits zur Build-Zeit des Wörterbuchs. Dadurch lädt jede Seite nur den tatsächlich genutzten Inhalt.**
173
+
174
+ Hier ein Beispiel für die Auswirkung der Bundle-Größenoptimierung mit `intlayer` in einer vite + react Anwendung:
175
+
176
+ | Optimiertes Bundle | Nicht optimiertes Bundle |
177
+ | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
178
+ | ![optimiertes Bundle](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png) | ![nicht optimiertes Bundle](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle_no_optimization.png) |
89
179
 
90
180
  ---
91
181
 
92
- ### 3) Umgang mit fehlenden Übersetzungen
182
+ ## TypeScript & Sicherheit
183
+
184
+ <Columns>
185
+ <Column>
186
+
187
+ **next-intl**
188
+
189
+ - Solide TypeScript-Unterstützung, aber **Schlüssel sind standardmäßig nicht strikt typisiert**; Sicherheitsmuster müssen manuell gepflegt werden.
190
+
191
+ </Column>
192
+ <Column>
193
+
194
+ **next-i18next**
195
+
196
+ - Basis-Typen für Hooks; **strikte Schlüsseltypisierung erfordert zusätzliche Werkzeuge/Konfiguration**.
197
+
198
+ </Column>
199
+ <Column>
93
200
 
94
- - **next-intl / next-i18next**: Verlassen sich auf **Laufzeit-Fallbacks** (z.B. Anzeige des Schlüssels oder der Standardsprache). Der Build schlägt nicht fehl.
95
- - **Intlayer**: **Erkennung zur Build-Zeit** mit **Warnungen/Fehlern** bei fehlenden Sprachen oder Schlüsseln.
201
+ **intlayer**
96
202
 
97
- **Warum das wichtig ist:** Das Erkennen von Lücken während des Builds verhindert „mysteriöse Strings“ in der Produktion und entspricht strengen Release-Richtlinien.
203
+ - **Erzeugt strenge Typen** aus Ihrem Inhalt. **IDE-Autovervollständigung** und **Kompilierzeit-Fehler** erkennen Tippfehler und fehlende Schlüssel vor der Bereitstellung.
204
+
205
+ </Column>
206
+ </Columns>
207
+
208
+ **Warum das wichtig ist:** Starke Typisierung verschiebt Fehler **nach links** (CI/Build) statt **nach rechts** (Laufzeit).
98
209
 
99
210
  ---
100
211
 
101
- ### 4) Routing, Middleware & URL-Strategie
212
+ ## Umgang mit fehlenden Übersetzungen
213
+
214
+ **next-intl**
215
+
216
+ - Verwendet **Fallbacks zur Laufzeit** (z. B. Anzeige des Schlüssels oder der Standardsprache). Der Build schlägt nicht fehl.
102
217
 
103
- - Alle drei arbeiten mit **Next.js lokalisiertem Routing** im App Router.
104
- - **Intlayer** geht noch weiter mit **i18n-Middleware** (Locale-Erkennung über Header/Cookies) und **Hilfsfunktionen**, um lokalisierte URLs und `<link rel="alternate" hreflang="…">`-Tags zu generieren.
218
+ **next-i18next**
105
219
 
106
- **Warum das wichtig ist:** Weniger individuelle Verbindungs-Schichten; **konsistente Benutzererfahrung** und **sauberes SEO** über alle Sprachen hinweg.
220
+ - Verwendet **Fallbacks zur Laufzeit** (z. B. Anzeige des Schlüssels oder der Standardsprache). Der Build schlägt nicht fehl.
221
+
222
+ **intlayer**
223
+
224
+ - **Erkennung zur Build-Zeit** mit **Warnungen/Fehlern** bei fehlenden Sprachen oder Schlüsseln.
225
+
226
+ **Warum das wichtig ist:** Das Erkennen von Lücken während des Builds verhindert „mysteriöse Strings“ in der Produktion und entspricht strengen Release-Gates.
107
227
 
108
228
  ---
109
229
 
110
- ### 5) Ausrichtung auf Server-Komponenten (RSC)
230
+ ## Routing, Middleware & URL-Strategie
231
+
232
+ <Columns>
233
+ <Column>
234
+
235
+ **next-intl**
236
+
237
+ - Funktioniert mit **Next.js lokalisiertem Routing** im App Router.
238
+
239
+ </Column>
240
+ <Column>
241
+
242
+ **next-i18next**
243
+
244
+ - Funktioniert mit **Next.js lokalisiertem Routing** im App Router.
245
+
246
+ </Column>
247
+ <Column>
248
+
249
+ **intlayer**
250
+
251
+ - Alles Genannte, plus **i18n Middleware** (Locale-Erkennung über Header/Cookies) und **Hilfsmittel** zur Generierung lokalisierter URLs und `<link rel="alternate" hreflang="…">` Tags.
111
252
 
112
- - **Alle** unterstützen Next.js 13+.
113
- - **Intlayer** glättet die **Server/Client-Grenze** mit einer konsistenten API und Providern, die für RSC entwickelt wurden, sodass Sie Formatierer oder t-Funktionen nicht durch Komponentenbäume schleusen müssen.
253
+ </Column>
254
+ </Columns>
114
255
 
115
- **Warum das wichtig ist:** Klareres mentales Modell und weniger Randfälle in hybriden Bäumen.
256
+ **Warum es wichtig ist:** Weniger benutzerdefinierte Verbindungs-Schichten; **konsistente Benutzererfahrung (UX)** und **sauberes SEO** über alle Sprachen hinweg.
116
257
 
117
258
  ---
118
259
 
119
- ### 6) Leistung & Ladeverhalten
260
+ ## Ausrichtung auf Server Components (RSC)
120
261
 
121
- - **next-intl / next-i18next**: Teilweise Kontrolle über **Namespaces** und **Routen-spezifische Aufteilungen**; Risiko, ungenutzte Strings mitzuliefern, wenn die Disziplin nachlässt.
122
- - **Intlayer**: **Tree-Shaking** beim Build und **Lazy-Loading pro Wörterbuch/Locale**. Unbenutzter Inhalt wird nicht ausgeliefert.
262
+ <Columns>
263
+ <Column>
123
264
 
124
- **Warum das wichtig ist:** Kleinere Bundles und schnellerer Start, besonders bei mehrsprachigen Websites.
265
+ **next-intl**
266
+
267
+ - Unterstützt Next.js 13+. Erfordert oft das Weiterreichen von t-Funktionen/Formatierern durch Komponentenbäume in hybriden Setups.
268
+
269
+ </Column>
270
+ <Column>
271
+
272
+ **next-i18next**
273
+
274
+ - Unterstützt Next.js 13+. Ähnliche Einschränkungen beim Weitergeben von Übersetzungswerkzeugen über Grenzen hinweg.
275
+
276
+ </Column>
277
+ <Column>
278
+
279
+ **intlayer**
280
+
281
+ - Unterstützt Next.js 13+ und erleichtert die **Server/Client-Grenze** mit einer konsistenten API und RSC-orientierten Providern, wodurch das Hin- und Herschicken von Formatierern oder t-Funktionen vermieden wird.
282
+
283
+ </Column>
284
+ </Columns>
285
+
286
+ **Warum es wichtig ist:** Klareres mentales Modell und weniger Randfälle in hybriden Bäumen.
125
287
 
126
288
  ---
127
289
 
128
- ### 7) DX, Tools & Wartung
290
+ ## DX, Tools & Wartung
291
+
292
+ <Columns>
293
+ <Column>
294
+
295
+ **next-intl**
296
+
297
+ - Wird häufig mit externen Lokalisierungsplattformen und redaktionellen Workflows kombiniert.
298
+
299
+ </Column>
300
+ <Column>
301
+
302
+ **next-i18next**
303
+
304
+ - Wird häufig mit externen Lokalisierungsplattformen und redaktionellen Workflows kombiniert.
305
+
306
+ </Column>
307
+ <Column>
308
+
309
+ **intlayer**
310
+
311
+ - Bietet einen **kostenlosen Visual Editor** und ein **optionales CMS** (Git-freundlich oder externalisiert) sowie eine **VSCode-Erweiterung** und **KI-unterstützte Übersetzungen** mit Ihren eigenen Anbieter-Schlüsseln.
312
+
313
+ </Column>
314
+ </Columns>
315
+
316
+ **Warum das wichtig ist:** Senkt die Betriebskosten und verkürzt den Kommunikationszyklus zwischen Entwicklern und Inhaltserstellern.
317
+
318
+ ## Integration mit Lokalisierungsplattformen (TMS)
319
+
320
+ Große Organisationen verlassen sich oft auf Translation Management Systeme (TMS) wie **Crowdin**, **Phrase**, **Lokalise**, **Localizely** oder **Localazy**.
321
+
322
+ - **Warum Unternehmen das wichtig finden**
323
+ - **Zusammenarbeit & Rollen**: Mehrere Akteure sind beteiligt: Entwickler, Produktmanager, Übersetzer, Prüfer, Marketingteams.
324
+ - **Skalierung & Effizienz**: kontinuierliche Lokalisierung, kontextbezogene Überprüfung.
325
+
326
+ - **next-intl / next-i18next**
327
+ - Verwenden typischerweise **zentralisierte JSON-Kataloge**, sodass der Export/Import mit TMS unkompliziert ist.
328
+ - Ausgereifte Ökosysteme und Beispiele/Integrationen für die oben genannten Plattformen.
329
+
330
+ - **Intlayer**
331
+ - Fördert **dezentralisierte, komponentenbezogene Wörterbücher** und unterstützt **TypeScript/TSX/JS/JSON/MD** Inhalte.
332
+ - Dies verbessert die Modularität im Code, kann jedoch die Plug-and-Play-Integration von TMS erschweren, wenn ein Tool zentralisierte, flache JSON-Dateien erwartet.
333
+ - Intlayer bietet Alternativen: **KI-unterstützte Übersetzungen** (unter Verwendung eigener Anbieter-Schlüssel), einen **Visuellen Editor/CMS** und **CLI/CI** Workflows, um Lücken zu erkennen und vorab zu füllen.
334
+
335
+ > Hinweis: `next-intl` und `i18next` akzeptieren ebenfalls TypeScript-Kataloge. Wenn Ihr Team Nachrichten in `.ts`-Dateien speichert oder diese nach Features dezentralisiert, können ähnliche Schwierigkeiten mit TMS auftreten. Viele `next-intl`-Setups bleiben jedoch zentralisiert in einem `locales/`-Ordner, was die Umwandlung in JSON für TMS etwas erleichtert.
336
+
337
+ ## Entwicklererfahrung
338
+
339
+ Dieser Abschnitt bietet einen tiefgehenden Vergleich der drei Lösungen. Anstatt einfache Fälle zu betrachten, wie sie in der „Erste Schritte“-Dokumentation jeder Lösung beschrieben sind, betrachten wir einen realen Anwendungsfall, der einem echten Projekt ähnlicher ist.
340
+
341
+ ### App-Struktur
342
+
343
+ Die App-Struktur ist wichtig, um eine gute Wartbarkeit Ihres Codes sicherzustellen.
344
+
345
+ <Tab defaultTab="next-intl" group='techno'>
346
+
347
+ <TabItem label="next-i18next" value="next-i18next">
348
+
349
+ ```bash
350
+ .
351
+ ├── public
352
+ │ └── locales
353
+ │ ├── en
354
+ │ │ ├── home.json
355
+ │ │ └── navbar.json
356
+ │ ├── fr
357
+ │ │ ├── home.json
358
+ │ │ └── navbar.json
359
+ │ └── es
360
+ │ ├── home.json
361
+ │ └── navbar.json
362
+ ├── next-i18next.config.js
363
+ └── src
364
+ ├── middleware.ts
365
+ ├── app
366
+ │ └── home.tsx
367
+ └── components
368
+ └── Navbar
369
+ └── index.tsx
370
+ ```
371
+
372
+ </TabItem>
373
+ <TabItem label="next-intl" value="next-intl">
374
+
375
+ ```bash
376
+ .
377
+ ├── locales
378
+ │ ├── en
379
+ │ │ ├── home.json
380
+ │ │ └── navbar.json
381
+ │ ├── fr
382
+ │ │ ├── home.json
383
+ │ │ └── navbar.json
384
+ │ └── es
385
+ │ ├── home.json
386
+ │ └── navbar.json
387
+ ├── i18n.ts
388
+ └── src
389
+ ├── middleware.ts
390
+ ├── app
391
+ │ └── home.tsx
392
+ └── components
393
+ └── Navbar
394
+ └── index.tsx
395
+ ```
396
+
397
+ </TabItem>
398
+ <TabItem label="intlayer" value="intlayer">
399
+
400
+ ```bash
401
+ .
402
+ ├── intlayer.config.ts
403
+ └── src
404
+ ├── middleware.ts
405
+ ├── app
406
+ │ └── home
407
+ │ └── index.tsx
408
+ │ └── index.content.ts
409
+ └── components
410
+ └── Navbar
411
+ ├── index.tsx
412
+ └── index.content.ts
413
+ ```
414
+
415
+ </TabItem>
416
+ </Tab>
417
+
418
+ #### Vergleich
419
+
420
+ - **next-intl / next-i18next**: Zentralisierte Kataloge (JSON; Namespaces/Nachrichten). Klare Struktur, gute Integration mit Übersetzungsplattformen, kann jedoch bei wachsender App zu mehr Datei-übergreifenden Änderungen führen.
421
+ - **Intlayer**: Pro-Komponenten `.content.{ts|js|json}` Wörterbücher, die direkt bei den Komponenten liegen. Einfachere Wiederverwendung von Komponenten und lokale Nachvollziehbarkeit; fügt Dateien hinzu und setzt auf Build-Zeit-Tools.
422
+
423
+ #### Einrichtung und Laden von Inhalten
424
+
425
+ Wie bereits erwähnt, müssen Sie optimieren, wie jede JSON-Datei in Ihren Code importiert wird.
426
+ Wie die Bibliothek das Laden von Inhalten handhabt, ist wichtig.
427
+
428
+ <Tab defaultTab="next-intl" group='techno'>
429
+ <TabItem label="next-i18next" value="next-i18next">
430
+
431
+ ```tsx fileName="next-i18next.config.js"
432
+ module.exports = {
433
+ i18n: {
434
+ locales: ["en", "fr", "es"],
435
+ defaultLocale: "en",
436
+ },
437
+ };
438
+ ```
439
+
440
+ ```tsx fileName="src/app/_app.tsx"
441
+ import { appWithTranslation } from "next-i18next";
442
+
443
+ const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />;
444
+
445
+ export default appWithTranslation(MyApp);
446
+ ```
447
+
448
+ ```tsx fileName="src/app/[locale]/about/page.tsx"
449
+ import type { GetStaticProps } from "next";
450
+ import { serverSideTranslations } from "next-i18next/serverSideTranslations";
451
+ import { useTranslation } from "next-i18next";
452
+ import { I18nextProvider, initReactI18next } from "react-i18next";
453
+ import { createInstance } from "i18next";
454
+ import { ClientComponent, ServerComponent } from "@components";
455
+
456
+ export default function HomePage({ locale }: { locale: string }) {
457
+ // Deklariere explizit den Namespace, der von dieser Komponente verwendet wird
458
+ const resources = await loadMessagesFor(locale); // dein Loader (JSON, etc.)
459
+
460
+ const i18n = createInstance();
461
+ i18n.use(initReactI18next).init({
462
+ lng: locale,
463
+ fallbackLng: "en",
464
+ resources,
465
+ ns: ["common", "about"],
466
+ defaultNS: "common",
467
+ interpolation: { escapeValue: false },
468
+ });
469
+
470
+ const { t } = useTranslation("about");
471
+
472
+ return (
473
+ <I18nextProvider i18n={i18n}>
474
+ <main>
475
+ <h1>{t("title")}</h1>
476
+ <ClientComponent />
477
+ <ServerComponent />
478
+ </main>
479
+ </I18nextProvider>
480
+ );
481
+ }
482
+
483
+ export const getStaticProps: GetStaticProps = async ({ locale }) => {
484
+ // Laden Sie nur die für DIESE Seite benötigten Namespaces vor
485
+ return {
486
+ props: {
487
+ ...(await serverSideTranslations(locale ?? "en", ["common", "about"])),
488
+ },
489
+ };
490
+ };
491
+ ```
492
+
493
+ </TabItem>
494
+ <TabItem label="next-intl" value="next-intl">
495
+
496
+ ```tsx fileName="i18n.ts"
497
+ import { getRequestConfig } from "next-intl/server";
498
+ import { notFound } from "next/navigation";
499
+
500
+ // Kann aus einer gemeinsamen Konfiguration importiert werden
501
+ const locales = ["en", "fr", "es"];
502
+
503
+ export default getRequestConfig(async ({ locale }) => {
504
+ // Überprüfen Sie, ob der eingehende `locale`-Parameter gültig ist
505
+ if (!locales.includes(locale as any)) notFound();
506
+
507
+ return {
508
+ messages: (await import(`../messages/${locale}.json`)).default,
509
+ };
510
+ });
511
+ ```
512
+
513
+ ```tsx fileName="src/app/[locale]/about/layout.tsx"
514
+ import { NextIntlClientProvider } from "next-intl";
515
+ import { getMessages, unstable_setRequestLocale } from "next-intl/server";
516
+ import pick from "lodash/pick";
517
+
518
+ export default async function LocaleLayout({
519
+ children,
520
+ params,
521
+ }: {
522
+ children: React.ReactNode;
523
+ params: { locale: string };
524
+ }) {
525
+ const { locale } = params;
526
+
527
+ // Setze die aktive Anfragelocale für dieses Server-Rendering (RSC)
528
+ unstable_setRequestLocale(locale);
529
+
530
+ // Nachrichten werden serverseitig über src/i18n/request.ts geladen
531
+ // (siehe next-intl Dokumentation). Hier senden wir nur einen Teil an den Client,
532
+ // der für Client-Komponenten benötigt wird (Payload-Optimierung).
533
+ const messages = await getMessages();
534
+ const clientMessages = pick(messages, ["common", "about"]);
535
+
536
+ return (
537
+ <html lang={locale}>
538
+ <body>
539
+ <NextIntlClientProvider locale={locale} messages={clientMessages}>
540
+ {children}
541
+ </NextIntlClientProvider>
542
+ </body>
543
+ </html>
544
+ );
545
+ }
546
+ ```
547
+
548
+ ```tsx fileName="src/app/[locale]/about/page.tsx"
549
+ import { getTranslations } from "next-intl/server";
550
+ import { ClientComponent, ServerComponent } from "@components";
551
+
552
+ export default async function LandingPage({
553
+ params,
554
+ }: {
555
+ params: { locale: string };
556
+ }) {
557
+ // Streng serverseitiges Laden (nicht auf den Client hydriert)
558
+ const t = await getTranslations("about");
559
+
560
+ return (
561
+ <main>
562
+ <h1>{t("title")}</h1>
563
+ <ClientComponent />
564
+ <ServerComponent />
565
+ </main>
566
+ );
567
+ }
568
+ ```
569
+
570
+ </TabItem>
571
+ <TabItem label="intlayer" value="intlayer">
572
+
573
+ ```tsx fileName="intlayer.config.ts"
574
+ export default {
575
+ internationalization: {
576
+ locales: ["en", "fr", "es"],
577
+ defaultLocale: "en",
578
+ },
579
+ };
580
+ ```
581
+
582
+ ```tsx fileName="src/app/[locale]/layout.tsx"
583
+ import { getHTMLTextDir } from "intlayer";
584
+ import {
585
+ IntlayerClientProvider,
586
+ generateStaticParams,
587
+ type NextLayoutIntlayer,
588
+ } from "next-intlayer";
129
589
 
130
- - **next-intl / next-i18next**: In der Regel binden Sie externe Plattformen für Übersetzungen und redaktionelle Workflows ein.
131
- - **Intlayer**: Bietet einen **kostenlosen Visual Editor** und ein **optionales CMS** (Git-freundlich oder extern). Außerdem eine **VSCode-Erweiterung** für die Inhaltserstellung und **KI-unterstützte Übersetzungen** mit Ihren eigenen Provider-Schlüsseln.
590
+ export const dynamic = "force-static";
132
591
 
133
- **Warum es wichtig ist:** Senkt die Betriebskosten und verkürzt die Schleife zwischen Entwicklern und Inhaltserstellern.
592
+ const LandingLayout: NextLayoutIntlayer = async ({ children, params }) => {
593
+ const { locale } = await params;
594
+
595
+ return (
596
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
597
+ <IntlayerClientProvider locale={locale}>
598
+ {children}
599
+ </IntlayerClientProvider>
600
+ </html>
601
+ );
602
+ };
603
+
604
+ export default LandingLayout;
605
+ ```
606
+
607
+ ```tsx fileName="src/app/[locale]/about/page.tsx"
608
+ import { PageContent } from "@components/PageContent";
609
+ import type { NextPageIntlayer } from "next-intlayer";
610
+ import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";
611
+ import { ClientComponent, ServerComponent } from "@components";
612
+
613
+ const LandingPage: NextPageIntlayer = async ({ params }) => {
614
+ const { locale } = await params;
615
+ const { title } = useIntlayer("about", locale);
616
+
617
+ return (
618
+ <IntlayerServerProvider locale={locale}>
619
+ <main>
620
+ <h1>{title}</h1>
621
+ <ClientComponent />
622
+ <ServerComponent />
623
+ </main>
624
+ </IntlayerServerProvider>
625
+ );
626
+ };
627
+
628
+ export default LandingPage;
629
+ ```
630
+
631
+ </TabItem>
632
+ </Tab>
633
+
634
+ #### Vergleich
635
+
636
+ Alle drei unterstützen das Laden von Inhalten und Providern pro Locale.
637
+
638
+ - Mit **next-intl/next-i18next** laden Sie typischerweise ausgewählte Nachrichten/Namensräume pro Route und platzieren Provider dort, wo sie benötigt werden.
639
+
640
+ - Mit **Intlayer** wird eine Build-Zeit-Analyse hinzugefügt, um die Nutzung abzuleiten, was manuelle Verkabelung reduzieren und möglicherweise einen einzigen Root-Provider ermöglichen kann.
641
+
642
+ Wählen Sie je nach Teampräferenz zwischen expliziter Kontrolle und Automatisierung.
643
+
644
+ ### Verwendung in einer Client-Komponente
645
+
646
+ Nehmen wir ein Beispiel einer Client-Komponente, die einen Zähler rendert.
647
+
648
+ <Tab defaultTab="next-intl" group='techno'>
649
+ <TabItem label="next-i18next" value="next-i18next">
650
+
651
+ **Übersetzungen (müssen echtes JSON in `public/locales/...` sein)**
652
+
653
+ ```json fileName="public/locales/en/about.json"
654
+ {
655
+ "counter": {
656
+ "label": "Counter",
657
+ "increment": "Increment"
658
+ }
659
+ }
660
+ ```
661
+
662
+ ```json fileName="public/locales/fr/about.json"
663
+ {
664
+ "counter": {
665
+ "label": "Compteur",
666
+ "increment": "Incrémenter"
667
+ }
668
+ }
669
+ ```
670
+
671
+ **Client-Komponente**
672
+
673
+ ```tsx fileName="src/components/ClientComponentExample.tsx"
674
+ "use client";
675
+
676
+ import React, { useMemo, useState } from "react";
677
+ import { useTranslation } from "next-i18next";
678
+
679
+ const ClientComponentExample = () => {
680
+ const { t, i18n } = useTranslation("about");
681
+ const [count, setCount] = useState(0);
682
+
683
+ // next-i18next stellt useNumber nicht bereit; benutze Intl.NumberFormat
684
+ const numberFormat = new Intl.NumberFormat(i18n.language);
685
+
686
+ return (
687
+ <div>
688
+ <p>{numberFormat.format(count)}</p>
689
+ <button
690
+ aria-label={t("counter.label")}
691
+ onClick={() => setCount((count) => count + 1)}
692
+ >
693
+ {t("counter.increment")}
694
+ </button>
695
+ </div>
696
+ );
697
+ };
698
+ ```
699
+
700
+ > Vergessen Sie nicht, den Namespace "about" bei den serverSideTranslations der Seite hinzuzufügen
701
+ > Hier verwenden wir die Version React 19.x.x, aber bei niedrigeren Versionen müssen Sie useMemo verwenden, um die Instanz des Formatierers zu speichern, da dies eine ressourcenintensive Funktion ist
702
+
703
+ </TabItem>
704
+ <TabItem label="next-intl" value="next-intl">
705
+
706
+ **Übersetzungen (Struktur wiederverwendet; laden Sie sie in die next-intl-Nachrichten, wie Sie möchten)**
707
+
708
+ ```json fileName="locales/en/about.json"
709
+ {
710
+ "counter": {
711
+ "label": "Counter",
712
+ "increment": "Increment"
713
+ }
714
+ }
715
+ ```
716
+
717
+ ```json fileName="locales/fr/about.json"
718
+ {
719
+ "counter": {
720
+ "label": "Compteur",
721
+ "increment": "Incrémenter"
722
+ }
723
+ }
724
+ ```
725
+
726
+ **Client-Komponente**
727
+
728
+ ```tsx fileName="src/components/ClientComponentExample.tsx"
729
+ "use client";
730
+
731
+ import React, { useState } from "react";
732
+ import { useTranslations, useFormatter } from "next-intl";
733
+
734
+ const ClientComponentExample = () => {
735
+ // Direkt auf das verschachtelte Objekt zugreifen
736
+ const t = useTranslations("about.counter");
737
+ const format = useFormatter();
738
+ const [count, setCount] = useState(0);
739
+
740
+ return (
741
+ <div>
742
+ <p>{format.number(count)}</p>
743
+ <button
744
+ aria-label={t("label")}
745
+ onClick={() => setCount((count) => count + 1)}
746
+ >
747
+ {t("increment")}
748
+ </button>
749
+ </div>
750
+ );
751
+ };
752
+ ```
753
+
754
+ > Vergessen Sie nicht, die "about"-Nachricht auf der Client-Seite der Seite hinzuzufügen
755
+
756
+ </TabItem>
757
+ <TabItem label="intlayer" value="intlayer">
758
+
759
+ **Inhalt**
760
+
761
+ ```ts fileName="src/components/ClientComponentExample/index.content.ts"
762
+ import { t, type Dictionary } from "intlayer";
763
+
764
+ const counterContent = {
765
+ key: "counter",
766
+ content: {
767
+ label: t({ de: "Zähler", en: "Counter", fr: "Compteur" }),
768
+ increment: t({ de: "Erhöhen", en: "Increment", fr: "Incrémenter" }),
769
+ },
770
+ } satisfies Dictionary;
771
+
772
+ export default counterContent;
773
+ ```
774
+
775
+ **Client-Komponente**
776
+
777
+ ```tsx fileName="src/components/ClientComponentExample/index.tsx"
778
+ "use client";
779
+
780
+ import React, { useState } from "react";
781
+ import { useNumber, useIntlayer } from "next-intlayer";
782
+
783
+ const ClientComponentExample = () => {
784
+ const [count, setCount] = useState(0);
785
+ const { label, increment } = useIntlayer("counter"); // gibt Strings zurück
786
+ const { number } = useNumber();
787
+
788
+ return (
789
+ <div>
790
+ <p>{number(count)}</p>
791
+ <button aria-label={label} onClick={() => setCount((count) => count + 1)}>
792
+ {increment}
793
+ </button>
794
+ </div>
795
+ );
796
+ };
797
+ ```
798
+
799
+ </TabItem>
800
+ </Tab>
801
+
802
+ #### Vergleich
803
+
804
+ - **Zahlenformatierung**
805
+ - **next-i18next**: kein `useNumber`; verwendet `Intl.NumberFormat` (oder i18next-icu).
806
+ - **next-intl**: `useFormatter().number(value)`.
807
+ - **Intlayer**: integriertes `useNumber()`.
808
+
809
+ - **Schlüssel**
810
+ - Behalte eine verschachtelte Struktur bei (`about.counter.label`) und passe deinen Hook entsprechend an (`useTranslation("about")` + `t("counter.label")` oder `useTranslations("about.counter")` + `t("label")`).
811
+
812
+ - **Dateiablagen**
813
+ - **next-i18next** erwartet JSON in `public/locales/{lng}/{ns}.json`.
814
+ - **next-intl** ist flexibel; lade Nachrichten wie du es konfigurierst.
815
+ - **Intlayer** speichert Inhalte in TS/JS Wörterbüchern und löst sie über Schlüssel auf.
134
816
 
135
817
  ---
136
818
 
137
- ## Wann welche Lösung wählen?
819
+ ### Verwendung in einer Server-Komponente
820
+
821
+ Wir betrachten den Fall einer UI-Komponente. Diese Komponente ist eine Server-Komponente und sollte als Kind einer Client-Komponente eingefügt werden können. (Seite (Server-Komponente) -> Client-Komponente -> Server-Komponente). Da diese Komponente als Kind einer Client-Komponente eingefügt werden kann, darf sie nicht asynchron sein.
822
+
823
+ <Tab defaultTab="next-intl" group='techno'>
824
+ <TabItem label="next-i18next" value="next-i18next">
825
+
826
+ ```tsx fileName="src/pages/about.tsx"
827
+ import type { GetStaticProps } from "next";
828
+ import { useTranslation } from "next-i18next";
829
+
830
+ type ServerComponentProps = {
831
+ count: number;
832
+ };
833
+
834
+ const ServerComponent = ({ count }: ServerComponentProps) => {
835
+ const { t, i18n } = useTranslation("about");
836
+ const formatted = new Intl.NumberFormat(i18n.language).format(count);
837
+
838
+ return (
839
+ <div>
840
+ <p>{formatted}</p>
841
+ <button aria-label={t("counter.label")}>{t("counter.increment")}</button>
842
+ </div>
843
+ );
844
+ };
845
+ ```
846
+
847
+ > Da die Server-Komponente nicht asynchron sein kann, müssen die Übersetzungen und die Formatierungsfunktion als Props übergeben werden.
848
+
849
+ </TabItem>
850
+ <TabItem label="next-intl" value="next-intl">
851
+
852
+ ```tsx fileName="src/components/ServerComponent.tsx"
853
+ type ServerComponentProps = {
854
+ count: number;
855
+ t: (key: string) => string;
856
+ };
857
+
858
+ const ServerComponent = ({ t, count }: ServerComponentProps) => {
859
+ const formatted = new Intl.NumberFormat(i18n.language).format(count);
860
+
861
+ return (
862
+ <div>
863
+ <p>{formatted}</p>
864
+ <button aria-label={t("label")}>{t("increment")}</button>
865
+ </div>
866
+ );
867
+ };
868
+ ```
869
+
870
+ > Da die Server-Komponente nicht asynchron sein kann, müssen Sie die Übersetzungen und die Formatierungsfunktion als Props übergeben.
871
+ >
872
+ > - `const t = await getTranslations("about.counter");`
873
+ > - `const format = await getFormatter();`
874
+
875
+ </TabItem>
876
+ <TabItem label="intlayer" value="intlayer">
877
+
878
+ ```tsx fileName="src/components/ServerComponent.tsx"
879
+ import { useIntlayer, useNumber } from "next-intlayer/server";
880
+
881
+ const ServerComponent = ({ count }: { count: number }) => {
882
+ const { label, increment } = useIntlayer("counter");
883
+ const { number } = useNumber();
884
+
885
+ return (
886
+ <div>
887
+ <p>{number(count)}</p>
888
+ <button aria-label={label}>{increment}</button>
889
+ </div>
890
+ );
891
+ };
892
+ ```
893
+
894
+ </TabItem>
895
+ </Tab>
896
+
897
+ > Intlayer stellt **server-sichere** Hooks über `next-intlayer/server` bereit. Damit sie funktionieren, verwenden `useIntlayer` und `useNumber` eine hook-ähnliche Syntax, ähnlich wie die Client-Hooks, basieren aber im Hintergrund auf dem Server-Kontext (`IntlayerServerProvider`).
898
+
899
+ ### Metadaten / Sitemap / Robots
138
900
 
139
- - **Wählen Sie next-intl**, wenn Sie eine **minimale** Lösung wünschen, mit zentralisierten Katalogen vertraut sind und Ihre App **klein bis mittelgroß** ist.
140
- - **Wählen Sie next-i18next**, wenn Sie das **Plugin-Ökosystem von i18next** benötigen (z. B. erweiterte ICU-Regeln über Plugins) und Ihr Team i18next bereits kennt, wobei Sie **mehr Konfiguration** für Flexibilität akzeptieren.
141
- - **Wählen Sie Intlayer**, wenn Sie **komponentenbezogenen Inhalt**, **striktes TypeScript**, **Build-Zeit-Garantien**, **Tree-Shaking** und **umfangreiche Routing/SEO/Editor-Tools** schätzen – insbesondere für den **Next.js App Router** und **große, modulare Codebasen**.
901
+ Inhalte zu übersetzen ist großartig. Aber oft wird vergessen, dass das Hauptziel der Internationalisierung darin besteht, Ihre Website für die Welt sichtbarer zu machen. I18n ist ein unglaublicher Hebel, um die Sichtbarkeit Ihrer Website zu verbessern.
902
+
903
+ Hier ist eine Liste von Best Practices bezüglich mehrsprachigem SEO.
904
+
905
+ - Setzen Sie hreflang-Meta-Tags im `<head>`-Tag
906
+ > Dies hilft Suchmaschinen zu verstehen, welche Sprachen auf der Seite verfügbar sind
907
+ - Listen Sie alle Seitenübersetzungen in der sitemap.xml unter Verwendung des XML-Schemas `http://www.w3.org/1999/xhtml` auf
908
+ >
909
+ - Vergessen Sie nicht, vorangestellte Seiten in der robots.txt auszuschließen (z. B. `/dashboard` sowie `/fr/dashboard`, `/es/dashboard`)
910
+ >
911
+ - Verwenden Sie eine benutzerdefinierte Link-Komponente, um auf die am besten lokalisierte Seite weiterzuleiten (z. B. auf Französisch `<a href="/fr/about">A propos</a>`)
912
+ >
913
+
914
+ Entwickler vergessen oft, ihre Seiten über verschiedene Sprachversionen hinweg korrekt zu referenzieren.
915
+
916
+ <Tab defaultTab="next-intl" group='techno'>
917
+
918
+ <TabItem label="next-i18next" value="next-i18next">
919
+
920
+ ```ts fileName="i18n.config.ts"
921
+ export const locales = ["en", "fr"] as const;
922
+ export type Locale = (typeof locales)[number];
923
+ export const defaultLocale: Locale = "en";
924
+
925
+ export function localizedPath(locale: string, path: string) {
926
+ return locale === defaultLocale ? path : "/" + locale + path;
927
+ }
928
+
929
+ const ORIGIN = "https://example.com";
930
+ export function abs(locale: string, path: string) {
931
+ return ORIGIN + localizedPath(locale, path);
932
+ }
933
+ ```
934
+
935
+ ```tsx fileName="src/app/[locale]/about/layout.tsx"
936
+ import type { Metadata } from "next";
937
+ import { locales, defaultLocale, localizedPath } from "@/i18n.config";
938
+
939
+ export async function generateMetadata({
940
+ params,
941
+ }: {
942
+ params: { locale: string };
943
+ }): Promise<Metadata> {
944
+ const { locale } = params;
945
+
946
+ // Dynamisch die korrekte JSON-Datei importieren
947
+ const messages = (
948
+ await import("@/../public/locales/" + locale + "/about.json")
949
+ ).default;
950
+
951
+ const languages = Object.fromEntries(
952
+ locales.map((locale) => [locale, localizedPath(locale, "/about")])
953
+ );
954
+
955
+ return {
956
+ title: messages.title,
957
+ description: messages.description,
958
+ alternates: {
959
+ canonical: localizedPath(locale, "/about"),
960
+ languages: { ...languages, "x-default": "/about" },
961
+ },
962
+ };
963
+ }
964
+
965
+ export default async function AboutPage() {
966
+ return <h1>Über</h1>; // Überschrift für die "Über"-Seite
967
+ }
968
+ ```
969
+
970
+ ```ts fileName="src/app/sitemap.ts"
971
+ import type { MetadataRoute } from "next";
972
+ import { locales, defaultLocale, abs } from "@/i18n.config";
973
+
974
+ export default function sitemap(): MetadataRoute.Sitemap {
975
+ const languages = Object.fromEntries(
976
+ locales.map((locale) => [locale, abs(locale, "/about")])
977
+ );
978
+ return [
979
+ {
980
+ url: abs(defaultLocale, "/about"),
981
+ lastModified: new Date(), // Datum der letzten Änderung
982
+ changeFrequency: "monthly", // Änderungsfrequenz der Seite
983
+ priority: 0.7, // Priorität der Seite im Sitemap
984
+ alternates: { languages }, // Alternative Sprachversionen
985
+ },
986
+ ];
987
+ }
988
+ ```
989
+
990
+ ```ts fileName="src/app/robots.ts"
991
+ import type { MetadataRoute } from "next";
992
+ import { locales, defaultLocale, localizedPath } from "@/i18n.config";
993
+
994
+ const ORIGIN = "https://example.com";
995
+
996
+ const expandAllLocales = (path: string) => [
997
+ localizedPath(defaultLocale, path),
998
+ ...locales
999
+ .filter((locale) => locale !== defaultLocale)
1000
+ .map((locale) => localizedPath(locale, path)),
1001
+ ];
1002
+
1003
+ export default function robots(): MetadataRoute.Robots {
1004
+ const disallow = [
1005
+ ...expandAllLocales("/dashboard"),
1006
+ ...expandAllLocales("/admin"),
1007
+ ];
1008
+
1009
+ return {
1010
+ rules: { userAgent: "*", allow: ["/"], disallow },
1011
+ host: ORIGIN,
1012
+ sitemap: ORIGIN + "/sitemap.xml",
1013
+ };
1014
+ }
1015
+ ```
1016
+
1017
+ </TabItem>
1018
+ <TabItem label="next-intl" value="next-intl">
1019
+
1020
+ ```tsx fileName="src/app/[locale]/about/layout.tsx"
1021
+ import type { Metadata } from "next";
1022
+ import { locales, defaultLocale } from "@/i18n";
1023
+ import { getTranslations } from "next-intl/server";
1024
+
1025
+ function localizedPath(locale: string, path: string) {
1026
+ return locale === defaultLocale ? path : "/" + locale + path;
1027
+ }
1028
+
1029
+ export async function generateMetadata({
1030
+ params,
1031
+ }: {
1032
+ params: { locale: string };
1033
+ }): Promise<Metadata> {
1034
+ const { locale } = params;
1035
+ const t = await getTranslations({ locale, namespace: "about" });
1036
+
1037
+ const url = "/about";
1038
+ const languages = Object.fromEntries(
1039
+ locales.map((locale) => [locale, localizedPath(locale, url)])
1040
+ );
1041
+
1042
+ return {
1043
+ title: t("title"),
1044
+ description: t("description"),
1045
+ alternates: {
1046
+ canonical: localizedPath(locale, url),
1047
+ languages: { ...languages, "x-default": url },
1048
+ },
1049
+ };
1050
+ }
1051
+
1052
+ // ... Restlicher Seiten-Code
1053
+ ```
1054
+
1055
+ ```tsx fileName="src/app/sitemap.ts"
1056
+ import type { MetadataRoute } from "next";
1057
+ import { locales, defaultLocale } from "@/i18n";
1058
+
1059
+ const origin = "https://example.com";
1060
+
1061
+ const formatterLocalizedPath = (locale: string, path: string) =>
1062
+ locale === defaultLocale ? origin + path : origin + "/" + locale + path;
1063
+
1064
+ export default function sitemap(): MetadataRoute.Sitemap {
1065
+ const aboutLanguages = Object.fromEntries(
1066
+ locales.map((l) => [l, formatterLocalizedPath(l, "/about")])
1067
+ );
1068
+
1069
+ return [
1070
+ {
1071
+ url: formatterLocalizedPath(defaultLocale, "/about"),
1072
+ lastModified: new Date(),
1073
+ changeFrequency: "monatlich",
1074
+ priority: 0.7,
1075
+ alternates: { languages: aboutLanguages },
1076
+ },
1077
+ ];
1078
+ }
1079
+ ```
1080
+
1081
+ ```tsx fileName="src/app/robots.ts"
1082
+ import type { MetadataRoute } from "next";
1083
+ import { locales, defaultLocale } from "@/i18n";
1084
+
1085
+ const origin = "https://example.com";
1086
+ const withAllLocales = (path: string) => [
1087
+ path,
1088
+ ...locales
1089
+ .filter((locale) => locale !== defaultLocale)
1090
+ .map((locale) => "/" + locale + path),
1091
+ ];
1092
+
1093
+ export default function robots(): MetadataRoute.Robots {
1094
+ const disallow = [
1095
+ ...withAllLocales("/dashboard"),
1096
+ ...withAllLocales("/admin"),
1097
+ ];
1098
+
1099
+ return {
1100
+ rules: { userAgent: "*", allow: ["/"], disallow },
1101
+ host: origin,
1102
+ sitemap: origin + "/sitemap.xml",
1103
+ };
1104
+ }
1105
+ ```
1106
+
1107
+ </TabItem>
1108
+ <TabItem label="intlayer" value="intlayer">
1109
+
1110
+ ```typescript fileName="src/app/[locale]/about/layout.tsx"
1111
+ import { getIntlayer, getMultilingualUrls } from "intlayer";
1112
+ import type { Metadata } from "next";
1113
+ import type { LocalPromiseParams } from "next-intlayer";
1114
+
1115
+ export const generateMetadata = async ({
1116
+ params,
1117
+ }: LocalPromiseParams): Promise<Metadata> => {
1118
+ const { locale } = await params;
1119
+
1120
+ const metadata = getIntlayer("page-metadata", locale);
1121
+
1122
+ const multilingualUrls = getMultilingualUrls("/about");
1123
+
1124
+ return {
1125
+ ...metadata,
1126
+ alternates: {
1127
+ canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
1128
+ languages: { ...multilingualUrls, "x-default": "/about" },
1129
+ },
1130
+ };
1131
+ };
1132
+
1133
+ // ... Restlicher Seiten-Code
1134
+ ```
1135
+
1136
+ ```tsx fileName="src/app/sitemap.ts"
1137
+ import { getMultilingualUrls } from "intlayer";
1138
+ import type { MetadataRoute } from "next";
1139
+
1140
+ const sitemap = (): MetadataRoute.Sitemap => [
1141
+ {
1142
+ url: "https://example.com/about",
1143
+ alternates: {
1144
+ languages: { ...getMultilingualUrls("https://example.com/about") },
1145
+ },
1146
+ },
1147
+ ];
1148
+ ```
1149
+
1150
+ ```tsx fileName="src/app/robots.ts"
1151
+ import { getMultilingualUrls } from "intlayer";
1152
+ import type { MetadataRoute } from "next";
1153
+
1154
+ // Funktion, die alle mehrsprachigen URLs aus einer Liste von URLs extrahiert
1155
+ const getAllMultilingualUrls = (urls: string[]) =>
1156
+ urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);
1157
+
1158
+ const robots = (): MetadataRoute.Robots => ({
1159
+ rules: {
1160
+ userAgent: "*",
1161
+ allow: ["/"],
1162
+ disallow: getAllMultilingualUrls(["/dashboard"]), // Verbotene Pfade für alle Sprachversionen
1163
+ },
1164
+ host: "https://example.com",
1165
+ sitemap: "https://example.com/sitemap.xml",
1166
+ });
1167
+
1168
+ export default robots;
1169
+ ```
1170
+
1171
+ </TabItem>
1172
+ </Tab>
1173
+
1174
+ > Intlayer stellt eine `getMultilingualUrls`-Funktion bereit, um mehrsprachige URLs für Ihre Sitemap zu generieren.
1175
+
1176
+ ---
142
1177
 
143
1178
  ---
144
1179
 
145
- ## Praktische Migrationshinweise (next-intl / next-i18next → Intlayer)
1180
+ ## Und der Gewinner ist…
1181
+
1182
+ Es ist nicht einfach. Jede Option hat ihre Vor- und Nachteile. So sehe ich das:
1183
+
1184
+ <Columns>
1185
+ <Column>
1186
+
1187
+ **next-intl**
1188
+
1189
+ - am einfachsten, leichtgewichtig, weniger Entscheidungen, die dir aufgezwungen werden. Wenn du eine **minimale** Lösung möchtest, mit zentralisierten Katalogen zurechtkommst und deine App **klein bis mittelgroß** ist.
1190
+
1191
+ </Column>
1192
+ <Column>
1193
+
1194
+ **next-i18next**
1195
+
1196
+ - ausgereift, vollgepackt mit Funktionen, viele Community-Plugins, aber höherer Einrichtungsaufwand. Wenn du das **Plugin-Ökosystem von i18next** benötigst (z. B. erweiterte ICU-Regeln über Plugins) und dein Team i18next bereits kennt, und du **mehr Konfiguration** für Flexibilität akzeptierst.
1197
+
1198
+ </Column>
1199
+ <Column>
1200
+
1201
+ **Intlayer**
1202
+
1203
+ - entwickelt für modernes Next.js, mit modularen Inhalten, Typsicherheit, Werkzeugen und weniger Boilerplate. Wenn Sie **komponentenbezogene Inhalte**, **striktes TypeScript**, **Build-Zeit-Garantien**, **Tree-Shaking** und **batteriebetriebene** Routing/SEO/Editor-Werkzeuge schätzen – besonders für den **Next.js App Router**, Design-Systeme und **große, modulare Codebasen**.
1204
+
1205
+ </Column>
1206
+ </Columns>
1207
+
1208
+ Wenn Sie eine minimale Einrichtung bevorzugen und etwas manuelle Verkabelung akzeptieren, ist next-intl eine gute Wahl. Wenn Sie alle Funktionen benötigen und Komplexität kein Problem ist, funktioniert next-i18next. Aber wenn Sie eine moderne, skalierbare, modulare Lösung mit integrierten Werkzeugen wollen, zielt Intlayer darauf ab, Ihnen genau das sofort bereitzustellen.
1209
+
1210
+ > **Alternative für Enterprise-Teams**: Wenn Sie eine bewährte Lösung benötigen, die perfekt mit etablierten Lokalisierungsplattformen wie **Crowdin**, **Phrase** oder anderen professionellen Übersetzungsmanagementsystemen zusammenarbeitet, sollten Sie **next-intl** oder **next-i18next** wegen ihres ausgereiften Ökosystems und bewährten Integrationen in Betracht ziehen.
1211
+
1212
+ > **Zukünftige Roadmap**: Intlayer plant außerdem die Entwicklung von Plugins, die auf den **i18next**- und **next-intl**-Lösungen aufbauen. Dies bietet Ihnen die Vorteile von Intlayer für Automatisierung, Syntax und Inhaltsverwaltung, während die Sicherheit und Stabilität dieser etablierten Lösungen in Ihrem Anwendungscode erhalten bleibt.
1213
+
1214
+ ## GitHub-STARS
1215
+
1216
+ GitHub-Sterne sind ein starkes Indiz für die Popularität eines Projekts, das Vertrauen der Community und die langfristige Relevanz. Obwohl sie kein direktes Maß für die technische Qualität sind, spiegeln sie wider, wie viele Entwickler das Projekt nützlich finden, seinen Fortschritt verfolgen und es wahrscheinlich übernehmen werden. Zur Einschätzung des Werts eines Projekts helfen Sterne dabei, die Resonanz im Vergleich zu Alternativen zu vergleichen und Einblicke in das Wachstum des Ökosystems zu geben.
146
1217
 
147
- - **Pro Funktion starten**: Verschieben Sie eine Route oder Komponente nach der anderen zu **lokalen Wörterbüchern**.
148
- - **Alte Kataloge parallel behalten**: Überbrücken Sie während der Migration; vermeiden Sie einen Big Bang.
149
- - **Strenge Prüfungen aktivieren**: Lassen Sie Lücken frühzeitig durch Build-Zeit-Erkennung sichtbar werden.
150
- - **Middleware & Helfer übernehmen**: Standardisieren Sie die Lokalerkennung und SEO-Tags auf der gesamten Website.
151
- - **Bundles messen**: Erwarten Sie **Reduzierungen der Bundle-Größe**, da ungenutzte Inhalte entfernt werden.
1218
+ [![Stern-Historien-Diagramm](https://api.star-history.com/svg?repos=i18next/next-i18next&repos=amannn/next-intl&repos=aymericzip/intlayer&type=Date)](https://www.star-history.com/#i18next/next-i18next&amannn/next-intl&aymericzip/intlayer)
152
1219
 
153
1220
  ---
154
1221
 
155
1222
  ## Fazit
156
1223
 
157
- Alle drei Bibliotheken sind bei der Kernlokalisierung erfolgreich. Der Unterschied liegt darin, **wie viel Arbeit Sie investieren müssen**, um eine robuste, skalierbare Einrichtung in **modernem Next.js** zu erreichen:
1224
+ Alle drei Bibliotheken sind im Kern der Lokalisierung erfolgreich. Der Unterschied liegt darin, **wie viel Arbeit Sie investieren müssen**, um eine robuste, skalierbare Einrichtung in **modernem Next.js** zu erreichen:
158
1225
 
159
- - Mit **Intlayer** sind **modularer Inhalt**, **striktes TypeScript**, **Build-Zeit-Sicherheit**, **tree-shaken Bundles** sowie **erstklassiger App Router und SEO-Tools** **Standard**, keine lästige Pflicht.
1226
+ - Mit **Intlayer** sind **modularer Inhalt**, **striktes TypeScript**, **Build-Zeit-Sicherheit**, **tree-shaken Bundles** und **erstklassiger App Router + SEO-Tools** **Standard**, nicht lästige Pflicht.
160
1227
  - Wenn Ihr Team **Wartbarkeit und Geschwindigkeit** in einer mehrsprachigen, komponentenbasierten Anwendung schätzt, bietet Intlayer heute die **vollständigste** Erfahrung.
161
1228
 
162
- Siehe das Dokument ['Warum Intlayer?'](https://intlayer.org/doc/why) für weitere Details.
1229
+ Weitere Details finden Sie im Dokument ['Warum Intlayer?'](https://intlayer.org/doc/why).