@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: Optymalizacja rozmiaru i wydajności bundle'a i18n
|
|
5
|
+
description: Zmniejsz rozmiar bundle'a aplikacji poprzez optymalizację treści internacjonalizacji (i18n). Dowiedz się, jak wykorzystać tree shaking i lazy loading dla słowników dzięki Intlayer.
|
|
6
|
+
keywords:
|
|
7
|
+
- Optymalizacja bundle'a
|
|
8
|
+
- Automatyzacja treści
|
|
9
|
+
- Treść dynamiczna
|
|
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: "Dodano opcje `minify` i `purge` do konfiguracji builda"
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Optymalizacja rozmiaru i wydajności bundle'a i18n
|
|
25
|
+
|
|
26
|
+
Jednym z najczęstszych wyzwań w tradycyjnych rozwiązaniach i18n opartych na plikach JSON jest zarządzanie rozmiarem treści. Jeśli programiści nie rozdzielą ręcznie treści na przestrzenie nazw (namespaces), użytkownicy często pobierają tłumaczenia dla każdej strony, a potencjalnie dla każdego języka, tylko po to, by wyświetlić jedną stronę.
|
|
27
|
+
|
|
28
|
+
Na przykład aplikacja z 10 stronami przetłumaczonymi na 10 języków może spowodować, że użytkownik pobierze treść 100 stron, mimo że potrzebuje tylko **jednej** (aktualnej strony w aktualnym języku). Prowadzi to do marnowania przepustowości i wolniejszego czasu ładowania.
|
|
29
|
+
|
|
30
|
+
**Intlayer rozwiązuje ten problem poprzez optymalizację na etapie budowania.** Analizuje on kod, aby wykryć, które słowniki są faktycznie używane w poszczególnych komponentach, i wstrzykuje do bundle'a tylko niezbędną treść.
|
|
31
|
+
|
|
32
|
+
## Spis treści
|
|
33
|
+
|
|
34
|
+
<TOC />
|
|
35
|
+
|
|
36
|
+
## Skanowanie bundle'a
|
|
37
|
+
|
|
38
|
+
Analiza bundle'a to pierwszy krok do zidentyfikowania "ciężkich" plików JSON i możliwości podziału kodu (code-splitting). Narzędzia te generują wizualną mapę drzewa (treemap) skompilowanego kodu aplikacji, co pozwala dokładnie zobaczyć, które biblioteki zajmują najwięcej miejsca.
|
|
39
|
+
|
|
40
|
+
<Tabs>
|
|
41
|
+
<Tab value="vite">
|
|
42
|
+
|
|
43
|
+
### Vite / Rollup
|
|
44
|
+
|
|
45
|
+
Vite wykorzystuje pod maską Rollup. Wtyczka `rollup-plugin-visualizer` generuje interaktywny plik HTML pokazujący rozmiar każdego modułu w grafie.
|
|
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, // Automatycznie otwórz raport w przeglądarce
|
|
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
|
+
Dla projektów korzystających z App Router i Turbopack, Next.js udostępnia wbudowany eksperymentalny analizator, który nie wymaga dodatkowych zależności.
|
|
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
|
+
Jeśli używasz domyślnego bundlera Webpack w Next.js, skorzystaj z oficjalnego analizatora bundle'a. Uruchom go, ustawiając zmienną środowiskową podczas budowania.
|
|
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
|
+
// Twoja konfiguracja Next.js
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Użycie:**
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
ANALYZE=true npm run build
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
</Tab>
|
|
130
|
+
<Tab value="Webpack (CRA / Angular / etc)">
|
|
131
|
+
|
|
132
|
+
### Standardowy Webpack
|
|
133
|
+
|
|
134
|
+
W przypadku Create React App (ejected), Angulara lub niestandardowych konfiguracji Webpack, użyj standardowego narzędzia `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
|
+
## Jak to działa
|
|
170
|
+
|
|
171
|
+
Intlayer stosuje **podejście oparte na komponentach**. W przeciwieństwie do globalnych plików JSON, treść jest definiowana obok komponentów lub w ichewnątrz. Podczas procesu budowania Intlayer:
|
|
172
|
+
|
|
173
|
+
1. **Analizuje** kod w celu znalezienia wywołań `useIntlayer`.
|
|
174
|
+
2. **Buduje** odpowiadającą im treść słownika.
|
|
175
|
+
3. **Zastępuje** wywołanie `useIntlayer` zoptymalizowanym kodem na podstawie Twojej konfiguracji.
|
|
176
|
+
|
|
177
|
+
Zapewnia to, że:
|
|
178
|
+
|
|
179
|
+
- Jeśli komponent nie zostanie zaimportowany, jego treść nie zostanie dołączona do bundle'a (Dead Code Elimination).
|
|
180
|
+
- Jeśli komponent jest ładowany leniwie (lazy-loaded), jego treść również jest ładowana leniwie.
|
|
181
|
+
|
|
182
|
+
## Konfiguracja według platformy
|
|
183
|
+
|
|
184
|
+
<Tabs>
|
|
185
|
+
<Tab value="nextjs">
|
|
186
|
+
|
|
187
|
+
### Next.js
|
|
188
|
+
|
|
189
|
+
Next.js wymaga wtyczki `@intlayer/swc` do obsługi transformacji, ponieważ Next.js używa SWC do budowania.
|
|
190
|
+
|
|
191
|
+
> Ta wtyczka nie jest instalowana domyślnie, ponieważ wtyczki SWC są nadal eksperymentalne w Next.js. Może to ulec zmianie w przyszłości.
|
|
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
|
+
Po zainstalowaniu Intlayer automatycznie wykryje i użyje wtyczki.
|
|
210
|
+
|
|
211
|
+
</Tab>
|
|
212
|
+
<Tab value="vite">
|
|
213
|
+
|
|
214
|
+
### Vite
|
|
215
|
+
|
|
216
|
+
Vite używa wtyczki `@intlayer/babel`, która jest dołączona jako zależność `vite-intlayer`. Optymalizacja jest domyślnie włączona. Nie trzeba nic więcej robić.
|
|
217
|
+
|
|
218
|
+
</Tab>
|
|
219
|
+
<Tab value="webpack">
|
|
220
|
+
|
|
221
|
+
### Webpack
|
|
222
|
+
|
|
223
|
+
Aby włączyć optymalizację bundle'a za pomocą Intlayer w Webpacku, musisz zainstalować i skonfigurować odpowiednią wtyczkę Babel (`@intlayer/babel`) lub SWC (`@intlayer/swc`).
|
|
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
|
+
## Konfiguracja
|
|
256
|
+
|
|
257
|
+
Możesz kontrolować sposób optymalizacji bundle'a przez Intlayer za pomocą właściwości `build` w pliku `intlayer.config.ts`.
|
|
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
|
+
* Minifikuj słowniki, aby zmniejszyć rozmiar bundle'a.
|
|
273
|
+
*/
|
|
274
|
+
minify: true;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Usuwaj nieużywane klucze w słownikach (purge)
|
|
278
|
+
*/
|
|
279
|
+
purge: true;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Wskazuje, czy proces budowania powinien sprawdzać typy TypeScript
|
|
283
|
+
*/
|
|
284
|
+
checkTypes: false;
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export default config;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
> W większości przypadków zaleca się pozostawienie domyślnej opcji dla `optimize`.
|
|
292
|
+
|
|
293
|
+
> Zobacz dokumentację konfiguracji, aby uzyskać więcej szczegółów: [Konfiguracja](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/configuration.md)
|
|
294
|
+
|
|
295
|
+
### Opcje budowania
|
|
296
|
+
|
|
297
|
+
Dostępne są następujące opcje w obiekcie konfiguracji `build`:
|
|
298
|
+
|
|
299
|
+
| Właściwość | Typ | Domyślnie | Opis |
|
|
300
|
+
| :------------- | :-------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
301
|
+
| **`optimize`** | `boolean` | `undefined` | Kontroluje, czy optymalizacja budowania jest włączona. Jeśli `true`, Intlayer zastępuje wywołania słowników zoptymalizowanymi wstrzyknięciami. Jeśli `false`, optymalizacja jest wyłączona. Idealnie `true` na prod. |
|
|
302
|
+
| **`minify`** | `boolean` | `false` | Czy minifikować słowniki w celu zmniejszenia rozmiaru bundle'a. |
|
|
303
|
+
| **`purge`** | `boolean` | `false` | Czy usuwać nieużywane klucze w słownikach. |
|
|
304
|
+
|
|
305
|
+
### Minifikacja
|
|
306
|
+
|
|
307
|
+
Minifikacja słowników usuwa niepotrzebne białe znaki, komentarze i zmniejsza rozmiar treści JSON. Jest to szczególnie przydatne w przypadku dużych słowników.
|
|
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
|
+
> Uwaga: Minifikacja jest ignorowana, jeśli `optimize` jest wyłączone lub jeśli włączony jest Edytor Wizualny (ponieważ edytor potrzebuje pełnej treści, aby umożliwić edycję).
|
|
322
|
+
|
|
323
|
+
### Purging (Czyszczenie)
|
|
324
|
+
|
|
325
|
+
Purging zapewnia, że tylko klucze faktycznie używane w kodzie zostaną uwzględnione w końcowym bundle'u słowników. Może to znacznie zmniejszyć rozmiar bundle'a, jeśli masz duże słowniki z wieloma kluczami, które nie są używane w każdej części aplikacji.
|
|
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
|
+
> Uwaga: Purging jest ignorowany, jeśli `optimize` jest wyłączone.
|
|
340
|
+
|
|
341
|
+
### Tryb importu (Import Mode)
|
|
342
|
+
|
|
343
|
+
W przypadku dużych aplikacji, obejmujących wiele stron i języków, pliki JSON mogą stanowić znaczną część rozmiaru bundle'a. Intlayer pozwala kontrolować sposób ładowania słowników.
|
|
344
|
+
|
|
345
|
+
Tryb importu można zdefiniować domyślnie globalnie w pliku `intlayer.config.ts`.
|
|
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
|
+
Jak również dla każdego słownika w plikach `.content.{{ts|tsx|js|jsx|mjs|cjs|json|jsonc|json5}}`.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
import { type Dictionary, t } from "intlayer";
|
|
363
|
+
|
|
364
|
+
const appContent: Dictionary = {
|
|
365
|
+
key: "app",
|
|
366
|
+
importMode: "dynamic", // Nadpisz domyślny tryb importu
|
|
367
|
+
content: {
|
|
368
|
+
// ...
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
export default appContent;
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
| Właściwość | Typ | Domyślnie | Opis |
|
|
376
|
+
| :--------------- | :--------------------------------- | :--------- | :-------------------------------------------------------------------------------------------------------------------- |
|
|
377
|
+
| **`importMode`** | `'static'`, `'dynamic'`, `'fetch'` | `'static'` | **Przestarzałe**: Zamiast tego używaj `dictionary.importMode`. Określa, jak ładowane są słowniki (szczegóły poniżej). |
|
|
378
|
+
|
|
379
|
+
Ustawienie `importMode` dyktuje, w jaki sposób treść słownika jest wstrzykiwana do komponentu.
|
|
380
|
+
Możesz je zdefiniować globalnie w pliku `intlayer.config.ts` w obiekcie `dictionary` lub nadpisać dla konkretnego słownika w jego pliku `.content.ts`.
|
|
381
|
+
|
|
382
|
+
### 1. Tryb statyczny (`default`)
|
|
383
|
+
|
|
384
|
+
W trybie statycznym Intlayer zastępuje `useIntlayer` przez `useDictionary` i wstrzykuje słownik bezpośrednio do bundle'a JavaScript.
|
|
385
|
+
|
|
386
|
+
- **Zalety:** Natychmiastowe renderowanie (synchroniczne), zero dodatkowych żądań sieciowych podczas hydratacji.
|
|
387
|
+
- **Wady:** Bundle zawiera tłumaczenia dla **wszystkich** dostępnych języków dla tego konkretnego komponentu.
|
|
388
|
+
- **Najlepszy dla:** Single Page Applications (SPA).
|
|
389
|
+
|
|
390
|
+
**Przykład przetransformowanego kodu:**
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
// Twój kod
|
|
394
|
+
const content = useIntlayer("my-key");
|
|
395
|
+
|
|
396
|
+
// Zoptymalizowany kod (Statyczny)
|
|
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. Tryb dynamiczny
|
|
410
|
+
|
|
411
|
+
W trybie dynamicznym Intlayer zastępuje `useIntlayer` przez `useDictionaryAsync`. Wykorzystuje to `import()` (mechanizm typu Suspense) do leniwego ładowania pliku JSON konkretnie dla aktualnego języka.
|
|
412
|
+
|
|
413
|
+
- **Zalety:** **Tree shaking na poziomie języka.** Użytkownik przeglądający wersję angielską pobierze _tylko_ słownik angielski. Słownik francuski nigdy nie zostanie załadowany.
|
|
414
|
+
- **Wady:** Wyzwala żądanie sieciowe (pobranie zasobu) dla każdego komponentu podczas hydratacji.
|
|
415
|
+
- **Najlepszy dla:** Dużych bloków tekstu, artykułów lub aplikacji obsługujących wiele języków, gdzie rozmiar bundle'a jest krytyczny.
|
|
416
|
+
|
|
417
|
+
**Przykład przetransformowanego kodu:**
|
|
418
|
+
|
|
419
|
+
```tsx
|
|
420
|
+
// Twój kod
|
|
421
|
+
const content = useIntlayer("my-key");
|
|
422
|
+
|
|
423
|
+
// Zoptymalizowany kod (Dynamiczny)
|
|
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
|
+
> Korzystając z `importMode: 'dynamic'`, jeśli masz 100 komponentów używających `useIntlayer` na jednej stronie, przeglądarka podejmie 100 oddzielnych prób pobrania. Aby uniknąć tego "wodospadu" żądań, grupuj treści w mniejszej liczbie plików `.content` (np. jeden słownik na sekcję strony) zamiast jednego na każdy drobny komponent.
|
|
437
|
+
|
|
438
|
+
### 3. Tryb Fetch
|
|
439
|
+
|
|
440
|
+
Zachowuje się podobnie do trybu dynamicznego, ale najpierw próbuje pobrać słowniki z Intlayer Live Sync API. Jeśli wywołanie API nie powiedzie się lub treść nie jest oznaczona do aktualizacji na żywo, powraca do importu dynamicznego.
|
|
441
|
+
|
|
442
|
+
> Zobacz dokumentację CMS, aby uzyskać więcej szczegółów: [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/intlayer_CMS.md)
|
|
443
|
+
|
|
444
|
+
> W trybie fetch nie można używać czyszczenia (purge) ani minifikacji.
|
|
445
|
+
|
|
446
|
+
## Podsumowanie: Statyczny vs Dynamiczny
|
|
447
|
+
|
|
448
|
+
| Funkcja | Tryb statyczny | Tryb dynamiczny |
|
|
449
|
+
| :----------------------- | :------------------------------------------------ | :------------------------------------------ |
|
|
450
|
+
| **Rozmiar bundle'a JS** | Większy (zawiera wszystkie języki dla komponentu) | Najmniejszy (tylko kod, brak treści) |
|
|
451
|
+
| **Ładowanie początkowe** | Natychmiastowe (treść jest w bundle'u) | Lekkie opóźnienie (pobiera JSON) |
|
|
452
|
+
| **Żądania sieciowe** | 0 dodatkowych żądań | 1 żądanie na każdy słownik |
|
|
453
|
+
| **Tree Shaking** | Poziom komponentu | Poziom komponentu + Poziom języka |
|
|
454
|
+
| **Najlepszy przypadek** | Komponenty UI, małe aplikacje | Strony z dużą ilością tekstu, wiele języków |
|
|
@@ -257,7 +257,7 @@ export default function LocaleLayout({
|
|
|
257
257
|
params: { locale: string };
|
|
258
258
|
}) {
|
|
259
259
|
const locale: Locale = (locales as readonly string[]).includes(params.locale)
|
|
260
|
-
?
|
|
260
|
+
? params.locale
|
|
261
261
|
: defaultLocale;
|
|
262
262
|
|
|
263
263
|
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),
|
|
@@ -193,9 +193,7 @@ const RootComponent: ParentComponent = (props) => {
|
|
|
193
193
|
</head>
|
|
194
194
|
<body>
|
|
195
195
|
<IntlayerProvider locale={locale}>
|
|
196
|
-
<Suspense>
|
|
197
|
-
{props.children}
|
|
198
|
-
</Suspense>
|
|
196
|
+
<Suspense>{props.children}</Suspense>
|
|
199
197
|
</IntlayerProvider>
|
|
200
198
|
<Scripts />
|
|
201
199
|
</body>
|
|
@@ -505,12 +503,33 @@ export const Route = createFileRoute("/{-$locale}/")({
|
|
|
505
503
|
component: RouteComponent,
|
|
506
504
|
head: ({ params }) => {
|
|
507
505
|
const { locale } = params;
|
|
508
|
-
const
|
|
506
|
+
const path = "/"; // The path for this route
|
|
507
|
+
|
|
508
|
+
const metaContent = getIntlayer("app", locale);
|
|
509
509
|
|
|
510
510
|
return {
|
|
511
|
+
links: [
|
|
512
|
+
// Canonical link: Points to the current localized page
|
|
513
|
+
{ rel: "canonical", href: getLocalizedUrl(path, locale) },
|
|
514
|
+
|
|
515
|
+
// Hreflang: Tell Google about all localized versions
|
|
516
|
+
...localeMap(({ locale: mapLocale }) => ({
|
|
517
|
+
rel: "alternate",
|
|
518
|
+
hrefLang: mapLocale,
|
|
519
|
+
href: getLocalizedUrl(path, mapLocale),
|
|
520
|
+
})),
|
|
521
|
+
|
|
522
|
+
// x-default: For users in unmatched languages
|
|
523
|
+
// Define the default fallback locale (usually your primary language)
|
|
524
|
+
{
|
|
525
|
+
rel: "alternate",
|
|
526
|
+
hrefLang: "x-default",
|
|
527
|
+
href: getLocalizedUrl(path, defaultLocale),
|
|
528
|
+
},
|
|
529
|
+
],
|
|
511
530
|
meta: [
|
|
512
531
|
{ title: metaContent.title },
|
|
513
|
-
{
|
|
532
|
+
{ name: "description", content: metaContent.meta.description },
|
|
514
533
|
],
|
|
515
534
|
};
|
|
516
535
|
},
|
|
@@ -224,9 +224,7 @@ function RootDocument({ children }: { children: ReactNode }) {
|
|
|
224
224
|
<HeadContent />
|
|
225
225
|
</head>
|
|
226
226
|
<body>
|
|
227
|
-
<IntlayerProvider locale={locale}>
|
|
228
|
-
{children}
|
|
229
|
-
</IntlayerProvider>
|
|
227
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
230
228
|
<Scripts />
|
|
231
229
|
</body>
|
|
232
230
|
</html>
|
|
@@ -325,30 +323,20 @@ import { getPrefix } from "intlayer";
|
|
|
325
323
|
|
|
326
324
|
export const LOCALE_ROUTE = "{-$locale}" as const;
|
|
327
325
|
|
|
328
|
-
|
|
329
|
-
export type RemoveLocaleParam<T> = T extends string
|
|
330
|
-
? RemoveLocaleFromString<T>
|
|
331
|
-
: T;
|
|
326
|
+
export type To = StripLocalePrefix<LinkComponentProps["to"]>;
|
|
332
327
|
|
|
333
|
-
export type
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
328
|
+
export type StripLocalePrefix<T extends string | undefined> = T extends
|
|
329
|
+
| `/${typeof LOCALE_ROUTE}/`
|
|
330
|
+
| `/${typeof LOCALE_ROUTE}`
|
|
331
|
+
? "/"
|
|
332
|
+
: T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
|
|
333
|
+
? `/${Rest}`
|
|
334
|
+
: T;
|
|
337
335
|
|
|
338
336
|
type LocalizedLinkProps = {
|
|
339
337
|
to?: To;
|
|
340
338
|
} & Omit<LinkComponentProps, "to">;
|
|
341
339
|
|
|
342
|
-
// Pomocnicze typy
|
|
343
|
-
type RemoveAll<
|
|
344
|
-
S extends string,
|
|
345
|
-
Sub extends string,
|
|
346
|
-
> = S extends `${infer H}${Sub}${infer T}` ? RemoveAll<`${H}${T}`, Sub> : S;
|
|
347
|
-
|
|
348
|
-
type RemoveLocaleFromString<S extends string> = CollapseDoubleSlashes<
|
|
349
|
-
RemoveAll<S, typeof LOCALE_ROUTE>
|
|
350
|
-
>;
|
|
351
|
-
|
|
352
340
|
export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {
|
|
353
341
|
const { locale } = useLocale();
|
|
354
342
|
const { localePrefix } = getPrefix(locale);
|
|
@@ -377,26 +365,26 @@ Następnie możemy stworzyć hook `useLocalizedNavigate` do nawigacji programowe
|
|
|
377
365
|
import { useNavigate } from "@tanstack/react-router";
|
|
378
366
|
import { getPrefix } from "intlayer";
|
|
379
367
|
import { useLocale } from "react-intlayer";
|
|
380
|
-
import {
|
|
368
|
+
import type { StripLocalePrefix } from "@/components/localized-link";
|
|
381
369
|
import type { FileRouteTypes } from "@/routeTree.gen";
|
|
382
370
|
|
|
383
|
-
type
|
|
384
|
-
|
|
385
|
-
| `/${typeof LOCALE_ROUTE}/`
|
|
386
|
-
? "/"
|
|
387
|
-
: T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
|
|
388
|
-
? `/${Rest}`
|
|
389
|
-
: never;
|
|
371
|
+
type NavigateFn = ReturnType<typeof useNavigate>;
|
|
372
|
+
type BaseNavigateOptions = Parameters<NavigateFn>[0];
|
|
390
373
|
|
|
391
374
|
type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>;
|
|
392
375
|
|
|
393
|
-
type
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
376
|
+
export type LocalizedNavigateOptions = Omit<
|
|
377
|
+
BaseNavigateOptions,
|
|
378
|
+
"to" | "params"
|
|
379
|
+
> & {
|
|
380
|
+
to: LocalizedTo;
|
|
381
|
+
params?: Omit<NonNullable<BaseNavigateOptions["params"]>, "locale">;
|
|
398
382
|
};
|
|
399
383
|
|
|
384
|
+
type LocalizedNavigate = (
|
|
385
|
+
options: LocalizedNavigateOptions
|
|
386
|
+
) => ReturnType<NavigateFn>;
|
|
387
|
+
|
|
400
388
|
export const useLocalizedNavigate = () => {
|
|
401
389
|
const navigate = useNavigate();
|
|
402
390
|
|
|
@@ -443,38 +431,6 @@ import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";
|
|
|
443
431
|
|
|
444
432
|
export const Route = createFileRoute("/{-$locale}/")({
|
|
445
433
|
component: RouteComponent,
|
|
446
|
-
head: ({ params }) => {
|
|
447
|
-
const { locale } = params;
|
|
448
|
-
const path = "/"; // The path for this route
|
|
449
|
-
|
|
450
|
-
const metaContent = getIntlayer("app", locale);
|
|
451
|
-
|
|
452
|
-
return {
|
|
453
|
-
links: [
|
|
454
|
-
// Canonical link: Points to the current localized page
|
|
455
|
-
{ rel: "canonical", href: getLocalizedUrl(path, locale) },
|
|
456
|
-
|
|
457
|
-
// Hreflang: Tell Google about all localized versions
|
|
458
|
-
...localeMap(({ locale: mapLocale }) => ({
|
|
459
|
-
rel: "alternate",
|
|
460
|
-
hrefLang: mapLocale,
|
|
461
|
-
href: getLocalizedUrl(path, mapLocale),
|
|
462
|
-
})),
|
|
463
|
-
|
|
464
|
-
// x-default: For users in unmatched languages
|
|
465
|
-
// Define the default fallback locale (usually your primary language)
|
|
466
|
-
{
|
|
467
|
-
rel: "alternate",
|
|
468
|
-
hrefLang: "x-default",
|
|
469
|
-
href: getLocalizedUrl(path, defaultLocale),
|
|
470
|
-
},
|
|
471
|
-
],
|
|
472
|
-
meta: [
|
|
473
|
-
{ title: metaContent.title },
|
|
474
|
-
{ name: "description", content: metaContent.meta.description },
|
|
475
|
-
],
|
|
476
|
-
};
|
|
477
|
-
},
|
|
478
434
|
});
|
|
479
435
|
|
|
480
436
|
function RouteComponent() {
|
|
@@ -629,12 +585,33 @@ export const Route = createFileRoute("/{-$locale}/")({
|
|
|
629
585
|
component: RouteComponent,
|
|
630
586
|
head: ({ params }) => {
|
|
631
587
|
const { locale } = params;
|
|
632
|
-
const
|
|
588
|
+
const path = "/"; // The path for this route
|
|
589
|
+
|
|
590
|
+
const metaContent = getIntlayer("app", locale);
|
|
633
591
|
|
|
634
592
|
return {
|
|
593
|
+
links: [
|
|
594
|
+
// Canonical link: Points to the current localized page
|
|
595
|
+
{ rel: "canonical", href: getLocalizedUrl(path, locale) },
|
|
596
|
+
|
|
597
|
+
// Hreflang: Tell Google about all localized versions
|
|
598
|
+
...localeMap(({ locale: mapLocale }) => ({
|
|
599
|
+
rel: "alternate",
|
|
600
|
+
hrefLang: mapLocale,
|
|
601
|
+
href: getLocalizedUrl(path, mapLocale),
|
|
602
|
+
})),
|
|
603
|
+
|
|
604
|
+
// x-default: For users in unmatched languages
|
|
605
|
+
// Define the default fallback locale (usually your primary language)
|
|
606
|
+
{
|
|
607
|
+
rel: "alternate",
|
|
608
|
+
hrefLang: "x-default",
|
|
609
|
+
href: getLocalizedUrl(path, defaultLocale),
|
|
610
|
+
},
|
|
611
|
+
],
|
|
635
612
|
meta: [
|
|
636
613
|
{ title: metaContent.title },
|
|
637
|
-
{
|
|
614
|
+
{ name: "description", content: metaContent.meta.description },
|
|
638
615
|
],
|
|
639
616
|
};
|
|
640
617
|
},
|