@intlayer/docs 8.6.10 → 8.7.0-canary.1
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.
- package/blog/ar/i18n_using_next-i18next.md +1 -1
- package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/de/i18n_using_next-i18next.md +1 -1
- package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/en/i18n_using_next-i18next.md +1 -1
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/en-GB/i18n_using_next-i18next.md +1 -1
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/es/i18n_using_next-i18next.md +1 -1
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/fr/i18n_using_next-i18next.md +1 -1
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/hi/i18n_using_next-i18next.md +1 -1
- package/blog/id/i18n_using_next-i18next.md +1 -1
- package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/it/i18n_using_next-i18next.md +1 -1
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ja/i18n_using_next-i18next.md +1 -1
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ko/i18n_using_next-i18next.md +1 -1
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/pl/i18n_using_next-i18next.md +1 -1
- package/blog/pl/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/pt/i18n_using_next-i18next.md +1 -1
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ru/i18n_using_next-i18next.md +1 -1
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/tr/i18n_using_next-i18next.md +1 -1
- package/blog/uk/i18n_using_next-i18next.md +1 -1
- package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/vi/i18n_using_next-i18next.md +1 -1
- package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
- package/blog/zh/i18n_using_next-i18next.md +1 -1
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/docs/ar/bundle_optimization.md +454 -0
- package/docs/ar/intlayer_with_next-i18next.md +1 -1
- package/docs/ar/intlayer_with_next-intl.md +1 -1
- package/docs/ar/intlayer_with_tanstack+solid.md +24 -5
- package/docs/ar/intlayer_with_tanstack.md +45 -68
- package/docs/bn/bundle_optimization.md +454 -0
- package/docs/cs/bundle_optimization.md +454 -0
- package/docs/de/bundle_optimization.md +454 -0
- package/docs/de/intlayer_with_next-i18next.md +1 -1
- package/docs/de/intlayer_with_next-intl.md +1 -1
- package/docs/de/intlayer_with_tanstack+solid.md +24 -5
- package/docs/de/intlayer_with_tanstack.md +45 -68
- package/docs/en/bundle_optimization.md +36 -8
- package/docs/en/intlayer_with_next-i18next.md +1 -1
- package/docs/en/intlayer_with_next-intl.md +1 -1
- package/docs/en/intlayer_with_tanstack+solid.md +24 -5
- package/docs/en/intlayer_with_tanstack.md +45 -68
- package/docs/en-GB/bundle_optimization.md +454 -0
- package/docs/en-GB/intlayer_with_next-i18next.md +1 -1
- package/docs/en-GB/intlayer_with_next-intl.md +1 -1
- package/docs/en-GB/intlayer_with_tanstack+solid.md +24 -5
- package/docs/en-GB/intlayer_with_tanstack.md +47 -70
- package/docs/es/bundle_optimization.md +454 -0
- package/docs/es/intlayer_with_next-i18next.md +1 -1
- package/docs/es/intlayer_with_next-intl.md +1 -1
- package/docs/es/intlayer_with_tanstack+solid.md +24 -5
- package/docs/es/intlayer_with_tanstack.md +45 -68
- package/docs/fr/bundle_optimization.md +454 -0
- package/docs/fr/intlayer_with_next-i18next.md +1 -1
- package/docs/fr/intlayer_with_next-intl.md +1 -1
- package/docs/fr/intlayer_with_tanstack+solid.md +24 -5
- package/docs/fr/intlayer_with_tanstack.md +45 -68
- package/docs/hi/bundle_optimization.md +454 -0
- package/docs/hi/intlayer_with_next-i18next.md +1 -1
- package/docs/hi/intlayer_with_next-intl.md +1 -1
- package/docs/hi/intlayer_with_tanstack+solid.md +24 -5
- package/docs/hi/intlayer_with_tanstack.md +45 -68
- package/docs/id/bundle_optimization.md +454 -0
- package/docs/id/intlayer_with_next-i18next.md +1 -1
- package/docs/id/intlayer_with_next-intl.md +1 -1
- package/docs/id/intlayer_with_tanstack+solid.md +24 -5
- package/docs/id/intlayer_with_tanstack.md +45 -68
- package/docs/it/bundle_optimization.md +454 -0
- package/docs/it/intlayer_with_next-i18next.md +1 -1
- package/docs/it/intlayer_with_next-intl.md +1 -1
- package/docs/it/intlayer_with_tanstack+solid.md +24 -5
- package/docs/it/intlayer_with_tanstack.md +45 -68
- package/docs/ja/bundle_optimization.md +454 -0
- package/docs/ja/intlayer_with_next-i18next.md +1 -1
- package/docs/ja/intlayer_with_next-intl.md +1 -1
- package/docs/ja/intlayer_with_tanstack+solid.md +24 -5
- package/docs/ja/intlayer_with_tanstack.md +45 -36
- package/docs/ko/bundle_optimization.md +454 -0
- package/docs/ko/intlayer_with_next-i18next.md +1 -1
- package/docs/ko/intlayer_with_next-intl.md +1 -1
- package/docs/ko/intlayer_with_tanstack+solid.md +24 -5
- package/docs/ko/intlayer_with_tanstack.md +45 -68
- package/docs/nl/bundle_optimization.md +454 -0
- package/docs/pl/bundle_optimization.md +454 -0
- package/docs/pl/intlayer_with_next-i18next.md +1 -1
- package/docs/pl/intlayer_with_next-intl.md +1 -1
- package/docs/pl/intlayer_with_tanstack+solid.md +24 -5
- package/docs/pl/intlayer_with_tanstack.md +45 -68
- package/docs/pt/bundle_optimization.md +454 -0
- package/docs/pt/intlayer_with_next-i18next.md +1 -1
- package/docs/pt/intlayer_with_next-intl.md +1 -1
- package/docs/pt/intlayer_with_tanstack+solid.md +24 -5
- package/docs/pt/intlayer_with_tanstack.md +45 -68
- package/docs/ru/bundle_optimization.md +454 -0
- package/docs/ru/intlayer_with_next-i18next.md +1 -1
- package/docs/ru/intlayer_with_next-intl.md +1 -1
- package/docs/ru/intlayer_with_tanstack+solid.md +24 -5
- package/docs/ru/intlayer_with_tanstack.md +45 -68
- package/docs/tr/bundle_optimization.md +454 -0
- package/docs/tr/intlayer_with_next-i18next.md +1 -1
- package/docs/tr/intlayer_with_next-intl.md +1 -1
- package/docs/tr/intlayer_with_tanstack+solid.md +24 -5
- package/docs/tr/intlayer_with_tanstack.md +45 -68
- package/docs/uk/bundle_optimization.md +454 -0
- package/docs/uk/intlayer_with_next-i18next.md +1 -1
- package/docs/uk/intlayer_with_next-intl.md +1 -1
- package/docs/uk/intlayer_with_tanstack+solid.md +24 -5
- package/docs/uk/intlayer_with_tanstack.md +45 -68
- package/docs/ur/bundle_optimization.md +454 -0
- package/docs/vi/bundle_optimization.md +454 -0
- package/docs/vi/intlayer_with_next-i18next.md +1 -1
- package/docs/vi/intlayer_with_next-intl.md +1 -1
- package/docs/vi/intlayer_with_tanstack+solid.md +24 -5
- package/docs/vi/intlayer_with_tanstack.md +45 -68
- package/docs/zh/bundle_optimization.md +454 -0
- package/docs/zh/intlayer_with_next-i18next.md +1 -1
- package/docs/zh/intlayer_with_next-intl.md +1 -1
- package/docs/zh/intlayer_with_tanstack+solid.md +24 -5
- package/docs/zh/intlayer_with_tanstack.md +45 -68
- package/package.json +7 -7
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2025-11-25
|
|
3
|
+
updatedAt: 2026-04-08
|
|
4
|
+
title: Optimierung der i18n-Bundle-Größe und Leistung
|
|
5
|
+
description: Reduzieren Sie die Bundle-Größe Ihrer Anwendung, indem Sie Internationalisierungs-Inhalte (i18n) optimieren. Erfahren Sie, wie Sie Tree Shaking und Lazy Loading für Wörterbücher mit Intlayer nutzen.
|
|
6
|
+
keywords:
|
|
7
|
+
- Bundle-Optimierung
|
|
8
|
+
- Inhaltsautomatisierung
|
|
9
|
+
- Dynamischer Inhalt
|
|
10
|
+
- Intlayer
|
|
11
|
+
- Next.js
|
|
12
|
+
- JavaScript
|
|
13
|
+
- React
|
|
14
|
+
slugs:
|
|
15
|
+
- doc
|
|
16
|
+
- concept
|
|
17
|
+
- bundle-optimization
|
|
18
|
+
history:
|
|
19
|
+
- version: 8.7.0
|
|
20
|
+
date: 2026-04-08
|
|
21
|
+
changes: "Optionen `minify` und `purge` zur Build-Konfiguration hinzugefügt"
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Optimierung der i18n-Bundle-Größe und Leistung
|
|
25
|
+
|
|
26
|
+
Eine der häufigsten Herausforderungen bei traditionellen i18n-Lösungen, die auf JSON-Dateien basieren, ist die Verwaltung der Inhaltsgröße. Wenn Entwickler Inhalte nicht manuell in Namensräume trennen, laden Benutzer oft Übersetzungen für jede Seite und potenziell jede Sprache herunter, nur um eine einzige Seite anzuzeigen.
|
|
27
|
+
|
|
28
|
+
Beispielsweise könnte eine Anwendung mit 10 Seiten, die in 10 Sprachen übersetzt wurden, dazu führen, dass ein Benutzer den Inhalt von 100 Seiten herunterlädt, obwohl er nur **eine** benötigt (die aktuelle Seite in der aktuellen Sprache). Dies führt zu verschwendeter Bandbreite und langsameren Ladezeiten.
|
|
29
|
+
|
|
30
|
+
**Intlayer löst dieses Problem durch Optimierung zur Build-Zeit.** Es analysiert Ihren Code, um festzustellen, welche Wörterbücher tatsächlich pro Komponente verwendet werden, und fügt nur den erforderlichen Inhalt in Ihr Bundle ein.
|
|
31
|
+
|
|
32
|
+
## Inhaltsverzeichnis
|
|
33
|
+
|
|
34
|
+
<TOC />
|
|
35
|
+
|
|
36
|
+
## Bundle scannen
|
|
37
|
+
|
|
38
|
+
Die Analyse Ihres Bundles ist der erste Schritt zur Identifizierung „schwerer“ JSON-Dateien und Möglichkeiten zum Code-Splitting. Diese Tools generieren eine visuelle Treemap des kompilierten Codes Ihrer Anwendung, sodass Sie genau sehen können, welche Bibliotheken den meisten Platz verbrauchen.
|
|
39
|
+
|
|
40
|
+
<Tabs>
|
|
41
|
+
<Tab value="vite">
|
|
42
|
+
|
|
43
|
+
### Vite / Rollup
|
|
44
|
+
|
|
45
|
+
Vite verwendet Rollup unter der Haube. Das Plugin `rollup-plugin-visualizer` generiert eine interaktive HTML-Datei, die die Größe jedes Moduls in Ihrem Graphen anzeigt.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install -D rollup-plugin-visualizer
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```typescript fileName="vite.config.ts"
|
|
52
|
+
import { defineConfig } from "vite";
|
|
53
|
+
import { visualizer } from "rollup-plugin-visualizer";
|
|
54
|
+
|
|
55
|
+
export default defineConfig({
|
|
56
|
+
plugins: [
|
|
57
|
+
visualizer({
|
|
58
|
+
open: true, // Bericht automatisch im Browser öffnen
|
|
59
|
+
filename: "stats.html",
|
|
60
|
+
gzipSize: true,
|
|
61
|
+
brotliSize: true,
|
|
62
|
+
}),
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
</Tab>
|
|
68
|
+
<Tab value="nextjs (turbopack)">
|
|
69
|
+
|
|
70
|
+
### Next.js (Turbopack)
|
|
71
|
+
|
|
72
|
+
Für Projekte, die den App Router und Turbopack verwenden, bietet Next.js einen integrierten experimentellen Analyzer, der keine zusätzlichen Abhängigkeiten erfordert.
|
|
73
|
+
|
|
74
|
+
```bash packageManager='npm'
|
|
75
|
+
npx next experimental-analyze
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```bash packageManager='yarn'
|
|
79
|
+
yarn next experimental-analyze
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```bash packageManager='pnpm'
|
|
83
|
+
pnpm next experimental-analyze
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```bash packageManager='bun'
|
|
87
|
+
bun next experimental-analyze
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
</Tab>
|
|
91
|
+
<Tab value="nextjs (Webpack)">
|
|
92
|
+
|
|
93
|
+
### Next.js (Webpack)
|
|
94
|
+
|
|
95
|
+
Wenn Sie den Standard-Webpack-Bundler in Next.js verwenden, nutzen Sie den offiziellen Bundle-Analyzer. Aktivieren Sie ihn, indem Sie während des Builds eine Umgebungsvariable setzen.
|
|
96
|
+
|
|
97
|
+
```bash packageManager='npm'
|
|
98
|
+
npm install -D @next/bundle-analyzer
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```bash packageManager='yarn'
|
|
102
|
+
yarn add -D @next/bundle-analyzer
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```bash packageManager='pnpm'
|
|
106
|
+
pnpm add -D @next/bundle-analyzer
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```bash packageManager='bun'
|
|
110
|
+
bun add -d @next/bundle-analyzer
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```javascript fileName="next.config.js"
|
|
114
|
+
const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
|
115
|
+
enabled: process.env.ANALYZE === "true",
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
module.exports = withBundleAnalyzer({
|
|
119
|
+
// Ihre Next.js-Konfiguration
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Verwendung:**
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
ANALYZE=true npm run build
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
</Tab>
|
|
130
|
+
<Tab value="Webpack (CRA / Angular / etc)">
|
|
131
|
+
|
|
132
|
+
### Standard Webpack
|
|
133
|
+
|
|
134
|
+
Für Create React App (ejected), Angular oder benutzerdefinierte Webpack-Setups verwenden Sie den Branchenstandard `webpack-bundle-analyzer`.
|
|
135
|
+
|
|
136
|
+
```bash packageManager='npm'
|
|
137
|
+
npm install -D webpack-bundle-analyzer
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```bash packageManager='yarn'
|
|
141
|
+
yarn add -D webpack-bundle-analyzer
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```bash packageManager='pnpm'
|
|
145
|
+
pnpm add -D webpack-bundle-analyzer
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```bash packageManager='bun'
|
|
149
|
+
bun add -d webpack-bundle-analyzer
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```typescript fileName="webpack.config.ts
|
|
153
|
+
import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
|
|
154
|
+
|
|
155
|
+
export default {
|
|
156
|
+
plugins: [
|
|
157
|
+
new BundleAnalyzerPlugin({
|
|
158
|
+
analyzerMode: "static",
|
|
159
|
+
reportFilename: "bundle-analyzer.html",
|
|
160
|
+
openAnalyzer: false,
|
|
161
|
+
}),
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
</Tab>
|
|
167
|
+
</Tabs>
|
|
168
|
+
|
|
169
|
+
## Funktionsweise
|
|
170
|
+
|
|
171
|
+
Intlayer verwendet einen **Ansatz pro Komponente**. Im Gegensatz zu globalen JSON-Dateien wird Ihr Inhalt neben oder innerhalb Ihrer Komponenten definiert. Während des Build-Prozesses führt Intlayer folgende Schritte aus:
|
|
172
|
+
|
|
173
|
+
1. **Analysiert** Ihren Code, um `useIntlayer`-Aufrufe zu finden.
|
|
174
|
+
2. **Erstellt** den entsprechenden Wörterbuchinhalt.
|
|
175
|
+
3. **Ersetzt** den `useIntlayer`-Aufruf durch optimierten Code basierend auf Ihrer Konfiguration.
|
|
176
|
+
|
|
177
|
+
Dies stellt sicher, dass:
|
|
178
|
+
|
|
179
|
+
- Wenn eine Komponente nicht importiert wird, ihr Inhalt nicht im Bundle enthalten ist (Dead Code Elimination).
|
|
180
|
+
- Wenn eine Komponente per Lazy Loading geladen wird, ihr Inhalt ebenfalls per Lazy Loading geladen wird.
|
|
181
|
+
|
|
182
|
+
## Einrichtung nach Plattform
|
|
183
|
+
|
|
184
|
+
<Tabs>
|
|
185
|
+
<Tab value="nextjs">
|
|
186
|
+
|
|
187
|
+
### Next.js
|
|
188
|
+
|
|
189
|
+
Next.js benötigt das `@intlayer/swc`-Plugin, um die Transformation zu handhaben, da Next.js SWC für Builds verwendet.
|
|
190
|
+
|
|
191
|
+
> Dieses Plugin ist standardmäßig nicht installiert, da SWC-Plugins für Next.js noch experimentell sind. Dies kann sich in Zukunft ändern.
|
|
192
|
+
|
|
193
|
+
```bash packageManager="npm"
|
|
194
|
+
npm install -D @intlayer/swc
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```bash packageManager="yarn"
|
|
198
|
+
yarn add -D @intlayer/swc
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```bash packageManager="pnpm"
|
|
202
|
+
pnpm add -D @intlayer/swc
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```bash packageManager="bun"
|
|
206
|
+
bun add -d @intlayer/swc
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Nach der Installation erkennt und verwendet Intlayer das Plugin automatisch.
|
|
210
|
+
|
|
211
|
+
</Tab>
|
|
212
|
+
<Tab value="vite">
|
|
213
|
+
|
|
214
|
+
### Vite
|
|
215
|
+
|
|
216
|
+
Vite verwendet das `@intlayer/babel`-Plugin, das als Abhängigkeit von `vite-intlayer` enthalten ist. Die Optimierung ist standardmäßig aktiviert. Es ist nichts weiter zu tun.
|
|
217
|
+
|
|
218
|
+
</Tab>
|
|
219
|
+
<Tab value="webpack">
|
|
220
|
+
|
|
221
|
+
### Webpack
|
|
222
|
+
|
|
223
|
+
Um die Bundle-Optimierung mit Intlayer in Webpack zu aktivieren, müssen Sie das entsprechende Babel- (`@intlayer/babel`) oder SWC- (`@intlayer/swc`) Plugin installieren und konfigurieren.
|
|
224
|
+
|
|
225
|
+
```bash packageManager="npm"
|
|
226
|
+
npm install -D @intlayer/babel
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```bash packageManager="yarn"
|
|
230
|
+
yarn add -D @intlayer/babel
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```bash packageManager="pnpm"
|
|
234
|
+
pnpm add -D @intlayer/babel
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```bash packageManager="bun"
|
|
238
|
+
bun add -d @intlayer/babel
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```typescript fileName="babel.config.js"
|
|
242
|
+
const {
|
|
243
|
+
getOptimizePluginOptions,
|
|
244
|
+
intlayerOptimizeBabelPlugin,
|
|
245
|
+
} = require("@intlayer/babel");
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
plugins: [[intlayerOptimizeBabelPlugin, getOptimizePluginOptions()]],
|
|
249
|
+
};
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
</Tab>
|
|
253
|
+
</Tabs>
|
|
254
|
+
|
|
255
|
+
## Konfiguration
|
|
256
|
+
|
|
257
|
+
Sie können steuern, wie Intlayer Ihr Bundle optimiert, indem Sie die Eigenschaft `build` in Ihrer `intlayer.config.ts` verwenden.
|
|
258
|
+
|
|
259
|
+
```typescript fileName="intlayer.config.ts"
|
|
260
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
261
|
+
|
|
262
|
+
const config: IntlayerConfig = {
|
|
263
|
+
internationalization: {
|
|
264
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
265
|
+
defaultLocale: Locales.ENGLISH,
|
|
266
|
+
},
|
|
267
|
+
dictionary: {
|
|
268
|
+
importMode: "dynamic",
|
|
269
|
+
},
|
|
270
|
+
build: {
|
|
271
|
+
/**
|
|
272
|
+
* Wörterbücher minimieren, um die Bundle-Größe zu reduzieren.
|
|
273
|
+
*/
|
|
274
|
+
minify: true;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Nicht verwendete Schlüssel in Wörterbüchern entfernen (Purge)
|
|
278
|
+
*/
|
|
279
|
+
purge: true;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Gibt an, ob beim Build TypeScript-Typen geprüft werden sollen
|
|
283
|
+
*/
|
|
284
|
+
checkTypes: false;
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export default config;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
> In den meisten Fällen wird empfohlen, die Standardoption für `optimize` beizubehalten.
|
|
292
|
+
|
|
293
|
+
> Weitere Details finden Sie in der Konfigurationsdokumentation: [Konfiguration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/de/configuration.md)
|
|
294
|
+
|
|
295
|
+
### Build-Optionen
|
|
296
|
+
|
|
297
|
+
Folgende Optionen sind im `build`-Konfigurationsobjekt verfügbar:
|
|
298
|
+
|
|
299
|
+
| Eigenschaft | Typ | Standard | Beschreibung |
|
|
300
|
+
| :------------- | :-------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
301
|
+
| **`optimize`** | `boolean` | `undefined` | Steuert, ob die Build-Optimierung aktiviert ist. Wenn `true`, ersetzt Intlayer Wörterbuchaufrufe durch optimierte Injektionen. Wenn `false`, ist die Optimierung deaktiviert. Im Idealfall in der Produktion auf `true` setzen. |
|
|
302
|
+
| **`minify`** | `boolean` | `false` | Ob die Wörterbücher minimiert werden sollen, um die Bundle-Größe zu reduzieren. |
|
|
303
|
+
| **`purge`** | `boolean` | `false` | Ob nicht verwendete Schlüssel in Wörterbüchern entfernt werden sollen. |
|
|
304
|
+
|
|
305
|
+
### Minimierung
|
|
306
|
+
|
|
307
|
+
Die Minimierung von Wörterbüchern entfernt unnötige Leerzeichen, Kommentare und reduziert die Größe des JSON-Inhalts. Dies ist besonders nützlich für große Wörterbücher.
|
|
308
|
+
|
|
309
|
+
```typescript fileName="intlayer.config.ts"
|
|
310
|
+
import type { IntlayerConfig } from "intlayer";
|
|
311
|
+
|
|
312
|
+
const config: IntlayerConfig = {
|
|
313
|
+
build: {
|
|
314
|
+
minify: true,
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
export default config;
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
> Hinweis: Die Minimierung wird ignoriert, wenn `optimize` deaktiviert ist oder wenn der Visual Editor aktiviert ist (da der Editor den vollständigen Inhalt benötigt, um Bearbeitungen zu ermöglichen).
|
|
322
|
+
|
|
323
|
+
### Purging (Bereinigung)
|
|
324
|
+
|
|
325
|
+
Purging stellt sicher, dass nur die tatsächlich in Ihrem Code verwendeten Schlüssel im finalen Wörterbuch-Bundle enthalten sind. Dies kann die Größe Ihres Bundles erheblich reduzieren, wenn Sie große Wörterbücher mit vielen Schlüsseln haben, die nicht in jedem Teil Ihrer Anwendung verwendet werden.
|
|
326
|
+
|
|
327
|
+
```typescript fileName="intlayer.config.ts"
|
|
328
|
+
import type { IntlayerConfig } from "intlayer";
|
|
329
|
+
|
|
330
|
+
const config: IntlayerConfig = {
|
|
331
|
+
build: {
|
|
332
|
+
purge: true,
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
export default config;
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
> Hinweis: Purging wird ignoriert, wenn `optimize` deaktiviert ist.
|
|
340
|
+
|
|
341
|
+
### Import-Modus
|
|
342
|
+
|
|
343
|
+
Für große Anwendungen, die mehrere Seiten und Sprachen umfassen, können Ihre JSON-Dateien einen erheblichen Teil Ihrer Bundle-Größe ausmachen. Intlayer ermöglicht es Ihnen zu steuern, wie Wörterbücher geladen werden.
|
|
344
|
+
|
|
345
|
+
Der Import-Modus kann standardmäßig global in Ihrer `intlayer.config.ts`-Datei definiert werden.
|
|
346
|
+
|
|
347
|
+
```typescript fileName="intlayer.config.ts"
|
|
348
|
+
import type { IntlayerConfig } from "intlayer";
|
|
349
|
+
|
|
350
|
+
const config: IntlayerConfig = {
|
|
351
|
+
build: {
|
|
352
|
+
minify: true,
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
export default config;
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Ebenso wie für jedes Wörterbuch in Ihren `.content.{{ts|tsx|js|jsx|mjs|cjs|json|jsonc|json5}}`-Dateien.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
import { type Dictionary, t } from "intlayer";
|
|
363
|
+
|
|
364
|
+
const appContent: Dictionary = {
|
|
365
|
+
key: "app",
|
|
366
|
+
importMode: "dynamic", // Standard-Importmodus überschreiben
|
|
367
|
+
content: {
|
|
368
|
+
// ...
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
export default appContent;
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
| Eigenschaft | Typ | Standard | Beschreibung |
|
|
376
|
+
| :--------------- | :--------------------------------- | :--------- | :-------------------------------------------------------------------------------------------------------------------------------- |
|
|
377
|
+
| **`importMode`** | `'static'`, `'dynamic'`, `'fetch'` | `'static'` | **Veraltet**: Verwenden Sie stattdessen `dictionary.importMode`. Bestimmt, wie Wörterbücher geladen werden (siehe Details unten). |
|
|
378
|
+
|
|
379
|
+
Die Einstellung `importMode` legt fest, wie der Wörterbuchinhalt in Ihre Komponente eingefügt wird.
|
|
380
|
+
Sie können dies global in der Datei `intlayer.config.ts` unter dem Objekt `dictionary` definieren oder für ein bestimmtes Wörterbuch in dessen `.content.ts`-Datei überschreiben.
|
|
381
|
+
|
|
382
|
+
### 1. Statischer Modus (`default`)
|
|
383
|
+
|
|
384
|
+
Im statischen Modus ersetzt Intlayer `useIntlayer` durch `useDictionary` und fügt das Wörterbuch direkt in das JavaScript-Bundle ein.
|
|
385
|
+
|
|
386
|
+
- **Vorteile:** Sofortiges Rendering (synchron), keine zusätzlichen Netzwerkanfragen während der Hydrierung.
|
|
387
|
+
- **Nachteile:** Das Bundle enthält Übersetzungen für **alle** verfügbaren Sprachen für diese spezifische Komponente.
|
|
388
|
+
- **Ideal für:** Single Page Applications (SPA).
|
|
389
|
+
|
|
390
|
+
**Beispiel für transformierten Code:**
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
// Ihr Code
|
|
394
|
+
const content = useIntlayer("my-key");
|
|
395
|
+
|
|
396
|
+
// Optimierter Code (Statisch)
|
|
397
|
+
const content = useDictionary({
|
|
398
|
+
key: "my-key",
|
|
399
|
+
content: {
|
|
400
|
+
nodeType: "translation",
|
|
401
|
+
translation: {
|
|
402
|
+
en: "My title",
|
|
403
|
+
fr: "Mon titre",
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### 2. Dynamischer Modus
|
|
410
|
+
|
|
411
|
+
Im dynamischen Modus ersetzt Intlayer `useIntlayer` durch `useDictionaryAsync`. Dies verwendet `import()` (ähnlich wie Suspense), um speziell das JSON für die aktuelle Sprache nachzuladen (Lazy Loading).
|
|
412
|
+
|
|
413
|
+
- **Vorteile:** **Tree Shaking auf Sprach-Ebene.** Ein Benutzer, der die englische Version ansieht, lädt _nur_ das englische Wörterbuch herunter. Das französische Wörterbuch wird nie geladen.
|
|
414
|
+
- **Nachteile:** Löst pro Komponente während der Hydrierung eine Netzwerkanfrage (Asset-Abruf) aus.
|
|
415
|
+
- **Ideal für:** Große Textblöcke, Artikel oder Anwendungen, die viele Sprachen unterstützen, bei denen die Bundle-Größe kritisch ist.
|
|
416
|
+
|
|
417
|
+
**Beispiel für transformierten Code:**
|
|
418
|
+
|
|
419
|
+
```tsx
|
|
420
|
+
// Ihr Code
|
|
421
|
+
const content = useIntlayer("my-key");
|
|
422
|
+
|
|
423
|
+
// Optimierter Code (Dynamisch)
|
|
424
|
+
const content = useDictionaryAsync({
|
|
425
|
+
en: () =>
|
|
426
|
+
import(".intlayer/dynamic_dictionary/my-key/en.json").then(
|
|
427
|
+
(mod) => mod.default
|
|
428
|
+
),
|
|
429
|
+
fr: () =>
|
|
430
|
+
import(".intlayer/dynamic_dictionary/my-key/fr.json").then(
|
|
431
|
+
(mod) => mod.default
|
|
432
|
+
),
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
> Wenn Sie `importMode: 'dynamic'` verwenden und 100 Komponenten `useIntlayer` auf einer einzigen Seite nutzen, wird der Browser versuchen, 100 separate Abrufe durchzuführen. Um diesen „Wasserfall“ an Anfragen zu vermeiden, gruppieren Sie Inhalte in weniger `.content`-Dateien (z. B. ein Wörterbuch pro Seitenabschnitt) statt einer Datei pro Atom-Komponente.
|
|
437
|
+
|
|
438
|
+
### 3. Fetch-Modus
|
|
439
|
+
|
|
440
|
+
Verhält sich ähnlich wie der dynamische Modus, versucht jedoch zuerst, Wörterbücher von der Intlayer Live Sync API abzurufen. Wenn der API-Aufruf fehlschlägt oder der Inhalt nicht für Live-Updates markiert ist, erfolgt ein Fallback auf den dynamischen Import.
|
|
441
|
+
|
|
442
|
+
> Weitere Details finden Sie in der CMS-Dokumentation: [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/de/intlayer_CMS.md)
|
|
443
|
+
|
|
444
|
+
> Im Fetch-Modus können Purge und Minimierung nicht verwendet werden.
|
|
445
|
+
|
|
446
|
+
## Zusammenfassung: Statisch vs. Dynamisch
|
|
447
|
+
|
|
448
|
+
| Merkmal | Statischer Modus | Dynamischer Modus |
|
|
449
|
+
| :------------------------ | :------------------------------------------------ | :----------------------------------- |
|
|
450
|
+
| **JS-Bundle-Größe** | Größer (enthält alle Sprachen für die Komponente) | Kleiner (nur Code, kein Inhalt) |
|
|
451
|
+
| **Initiales Laden** | Sofort (Inhalt ist im Bundle) | Leichte Verzögerung (lädt JSON) |
|
|
452
|
+
| **Netzwerkanfragen** | 0 zusätzliche Anfragen | 1 Anfrage pro Wörterbuch |
|
|
453
|
+
| **Tree Shaking** | Komponentenebene | Komponentenebene + Sprach-Ebene |
|
|
454
|
+
| **Bester Anwendungsfall** | UI-Komponenten, kleine Anwendungen | Seiten mit viel Text, viele Sprachen |
|
|
@@ -256,7 +256,7 @@ export default function LocaleLayout({
|
|
|
256
256
|
params: { locale: string };
|
|
257
257
|
}) {
|
|
258
258
|
const locale: Locale = (locales as readonly string[]).includes(params.locale)
|
|
259
|
-
?
|
|
259
|
+
? params.locale
|
|
260
260
|
: defaultLocale;
|
|
261
261
|
|
|
262
262
|
const dir = isRtl(locale) ? "rtl" : "ltr";
|
|
@@ -103,7 +103,7 @@ async function loadMessages(locale: string) {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export default getRequestConfig(async ({ locale }) => {
|
|
106
|
-
if (!locales.includes(locale
|
|
106
|
+
if (!locales.includes(locale)) notFound();
|
|
107
107
|
|
|
108
108
|
return {
|
|
109
109
|
messages: await loadMessages(locale),
|
|
@@ -194,9 +194,7 @@ const RootComponent: ParentComponent = (props) => {
|
|
|
194
194
|
</head>
|
|
195
195
|
<body>
|
|
196
196
|
<IntlayerProvider locale={locale}>
|
|
197
|
-
<Suspense>
|
|
198
|
-
{props.children}
|
|
199
|
-
</Suspense>
|
|
197
|
+
<Suspense>{props.children}</Suspense>
|
|
200
198
|
</IntlayerProvider>
|
|
201
199
|
<Scripts />
|
|
202
200
|
</body>
|
|
@@ -506,12 +504,33 @@ export const Route = createFileRoute("/{-$locale}/")({
|
|
|
506
504
|
component: RouteComponent,
|
|
507
505
|
head: ({ params }) => {
|
|
508
506
|
const { locale } = params;
|
|
509
|
-
const
|
|
507
|
+
const path = "/"; // The path for this route
|
|
508
|
+
|
|
509
|
+
const metaContent = getIntlayer("app", locale);
|
|
510
510
|
|
|
511
511
|
return {
|
|
512
|
+
links: [
|
|
513
|
+
// Canonical link: Points to the current localized page
|
|
514
|
+
{ rel: "canonical", href: getLocalizedUrl(path, locale) },
|
|
515
|
+
|
|
516
|
+
// Hreflang: Tell Google about all localized versions
|
|
517
|
+
...localeMap(({ locale: mapLocale }) => ({
|
|
518
|
+
rel: "alternate",
|
|
519
|
+
hrefLang: mapLocale,
|
|
520
|
+
href: getLocalizedUrl(path, mapLocale),
|
|
521
|
+
})),
|
|
522
|
+
|
|
523
|
+
// x-default: For users in unmatched languages
|
|
524
|
+
// Define the default fallback locale (usually your primary language)
|
|
525
|
+
{
|
|
526
|
+
rel: "alternate",
|
|
527
|
+
hrefLang: "x-default",
|
|
528
|
+
href: getLocalizedUrl(path, defaultLocale),
|
|
529
|
+
},
|
|
530
|
+
],
|
|
512
531
|
meta: [
|
|
513
532
|
{ title: metaContent.title },
|
|
514
|
-
{
|
|
533
|
+
{ name: "description", content: metaContent.meta.description },
|
|
515
534
|
],
|
|
516
535
|
};
|
|
517
536
|
},
|
|
@@ -225,9 +225,7 @@ function RootDocument({ children }: { children: ReactNode }) {
|
|
|
225
225
|
<HeadContent />
|
|
226
226
|
</head>
|
|
227
227
|
<body>
|
|
228
|
-
<IntlayerProvider locale={locale}>
|
|
229
|
-
{children}
|
|
230
|
-
</IntlayerProvider>
|
|
228
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
231
229
|
<Scripts />
|
|
232
230
|
</body>
|
|
233
231
|
</html>
|
|
@@ -326,30 +324,20 @@ import { getPrefix } from "intlayer";
|
|
|
326
324
|
|
|
327
325
|
export const LOCALE_ROUTE = "{-$locale}" as const;
|
|
328
326
|
|
|
329
|
-
|
|
330
|
-
export type RemoveLocaleParam<T> = T extends string
|
|
331
|
-
? RemoveLocaleFromString<T>
|
|
332
|
-
: T;
|
|
327
|
+
export type To = StripLocalePrefix<LinkComponentProps["to"]>;
|
|
333
328
|
|
|
334
|
-
export type
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
329
|
+
export type StripLocalePrefix<T extends string | undefined> = T extends
|
|
330
|
+
| `/${typeof LOCALE_ROUTE}/`
|
|
331
|
+
| `/${typeof LOCALE_ROUTE}`
|
|
332
|
+
? "/"
|
|
333
|
+
: T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
|
|
334
|
+
? `/${Rest}`
|
|
335
|
+
: T;
|
|
338
336
|
|
|
339
337
|
type LocalizedLinkProps = {
|
|
340
338
|
to?: To;
|
|
341
339
|
} & Omit<LinkComponentProps, "to">;
|
|
342
340
|
|
|
343
|
-
// Helfer
|
|
344
|
-
type RemoveAll<
|
|
345
|
-
S extends string,
|
|
346
|
-
Sub extends string,
|
|
347
|
-
> = S extends `${infer H}${Sub}${infer T}` ? RemoveAll<`${H}${T}`, Sub> : S;
|
|
348
|
-
|
|
349
|
-
type RemoveLocaleFromString<S extends string> = CollapseDoubleSlashes<
|
|
350
|
-
RemoveAll<S, typeof LOCALE_ROUTE>
|
|
351
|
-
>;
|
|
352
|
-
|
|
353
341
|
export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {
|
|
354
342
|
const { locale } = useLocale();
|
|
355
343
|
const { localePrefix } = getPrefix(locale);
|
|
@@ -378,26 +366,26 @@ Dann können wir einen `useLocalizedNavigate`-Hook für die programmatische Navi
|
|
|
378
366
|
import { useNavigate } from "@tanstack/react-router";
|
|
379
367
|
import { getPrefix } from "intlayer";
|
|
380
368
|
import { useLocale } from "react-intlayer";
|
|
381
|
-
import {
|
|
369
|
+
import type { StripLocalePrefix } from "@/components/localized-link";
|
|
382
370
|
import type { FileRouteTypes } from "@/routeTree.gen";
|
|
383
371
|
|
|
384
|
-
type
|
|
385
|
-
|
|
386
|
-
| `/${typeof LOCALE_ROUTE}/`
|
|
387
|
-
? "/"
|
|
388
|
-
: T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
|
|
389
|
-
? `/${Rest}`
|
|
390
|
-
: never;
|
|
372
|
+
type NavigateFn = ReturnType<typeof useNavigate>;
|
|
373
|
+
type BaseNavigateOptions = Parameters<NavigateFn>[0];
|
|
391
374
|
|
|
392
375
|
type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>;
|
|
393
376
|
|
|
394
|
-
type
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
377
|
+
export type LocalizedNavigateOptions = Omit<
|
|
378
|
+
BaseNavigateOptions,
|
|
379
|
+
"to" | "params"
|
|
380
|
+
> & {
|
|
381
|
+
to: LocalizedTo;
|
|
382
|
+
params?: Omit<NonNullable<BaseNavigateOptions["params"]>, "locale">;
|
|
399
383
|
};
|
|
400
384
|
|
|
385
|
+
type LocalizedNavigate = (
|
|
386
|
+
options: LocalizedNavigateOptions
|
|
387
|
+
) => ReturnType<NavigateFn>;
|
|
388
|
+
|
|
401
389
|
export const useLocalizedNavigate = () => {
|
|
402
390
|
const navigate = useNavigate();
|
|
403
391
|
|
|
@@ -444,38 +432,6 @@ import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";
|
|
|
444
432
|
|
|
445
433
|
export const Route = createFileRoute("/{-$locale}/")({
|
|
446
434
|
component: RouteComponent,
|
|
447
|
-
head: ({ params }) => {
|
|
448
|
-
const { locale } = params;
|
|
449
|
-
const path = "/"; // The path for this route
|
|
450
|
-
|
|
451
|
-
const metaContent = getIntlayer("app", locale);
|
|
452
|
-
|
|
453
|
-
return {
|
|
454
|
-
links: [
|
|
455
|
-
// Canonical link: Points to the current localized page
|
|
456
|
-
{ rel: "canonical", href: getLocalizedUrl(path, locale) },
|
|
457
|
-
|
|
458
|
-
// Hreflang: Tell Google about all localized versions
|
|
459
|
-
...localeMap(({ locale: mapLocale }) => ({
|
|
460
|
-
rel: "alternate",
|
|
461
|
-
hrefLang: mapLocale,
|
|
462
|
-
href: getLocalizedUrl(path, mapLocale),
|
|
463
|
-
})),
|
|
464
|
-
|
|
465
|
-
// x-default: For users in unmatched languages
|
|
466
|
-
// Define the default fallback locale (usually your primary language)
|
|
467
|
-
{
|
|
468
|
-
rel: "alternate",
|
|
469
|
-
hrefLang: "x-default",
|
|
470
|
-
href: getLocalizedUrl(path, defaultLocale),
|
|
471
|
-
},
|
|
472
|
-
],
|
|
473
|
-
meta: [
|
|
474
|
-
{ title: metaContent.title },
|
|
475
|
-
{ name: "description", content: metaContent.meta.description },
|
|
476
|
-
],
|
|
477
|
-
};
|
|
478
|
-
},
|
|
479
435
|
});
|
|
480
436
|
|
|
481
437
|
function RouteComponent() {
|
|
@@ -630,12 +586,33 @@ export const Route = createFileRoute("/{-$locale}/")({
|
|
|
630
586
|
component: RouteComponent,
|
|
631
587
|
head: ({ params }) => {
|
|
632
588
|
const { locale } = params;
|
|
633
|
-
const
|
|
589
|
+
const path = "/"; // The path for this route
|
|
590
|
+
|
|
591
|
+
const metaContent = getIntlayer("app", locale);
|
|
634
592
|
|
|
635
593
|
return {
|
|
594
|
+
links: [
|
|
595
|
+
// Canonical link: Points to the current localized page
|
|
596
|
+
{ rel: "canonical", href: getLocalizedUrl(path, locale) },
|
|
597
|
+
|
|
598
|
+
// Hreflang: Tell Google about all localized versions
|
|
599
|
+
...localeMap(({ locale: mapLocale }) => ({
|
|
600
|
+
rel: "alternate",
|
|
601
|
+
hrefLang: mapLocale,
|
|
602
|
+
href: getLocalizedUrl(path, mapLocale),
|
|
603
|
+
})),
|
|
604
|
+
|
|
605
|
+
// x-default: For users in unmatched languages
|
|
606
|
+
// Define the default fallback locale (usually your primary language)
|
|
607
|
+
{
|
|
608
|
+
rel: "alternate",
|
|
609
|
+
hrefLang: "x-default",
|
|
610
|
+
href: getLocalizedUrl(path, defaultLocale),
|
|
611
|
+
},
|
|
612
|
+
],
|
|
636
613
|
meta: [
|
|
637
614
|
{ title: metaContent.title },
|
|
638
|
-
{
|
|
615
|
+
{ name: "description", content: metaContent.meta.description },
|
|
639
616
|
],
|
|
640
617
|
};
|
|
641
618
|
},
|