@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.
Files changed (129) hide show
  1. package/blog/ar/i18n_using_next-i18next.md +1 -1
  2. package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  3. package/blog/de/i18n_using_next-i18next.md +1 -1
  4. package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  5. package/blog/en/i18n_using_next-i18next.md +1 -1
  6. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  7. package/blog/en-GB/i18n_using_next-i18next.md +1 -1
  8. package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  9. package/blog/es/i18n_using_next-i18next.md +1 -1
  10. package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  11. package/blog/fr/i18n_using_next-i18next.md +1 -1
  12. package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  13. package/blog/hi/i18n_using_next-i18next.md +1 -1
  14. package/blog/id/i18n_using_next-i18next.md +1 -1
  15. package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  16. package/blog/it/i18n_using_next-i18next.md +1 -1
  17. package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  18. package/blog/ja/i18n_using_next-i18next.md +1 -1
  19. package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  20. package/blog/ko/i18n_using_next-i18next.md +1 -1
  21. package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  22. package/blog/pl/i18n_using_next-i18next.md +1 -1
  23. package/blog/pl/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  24. package/blog/pt/i18n_using_next-i18next.md +1 -1
  25. package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  26. package/blog/ru/i18n_using_next-i18next.md +1 -1
  27. package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  28. package/blog/tr/i18n_using_next-i18next.md +1 -1
  29. package/blog/uk/i18n_using_next-i18next.md +1 -1
  30. package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  31. package/blog/vi/i18n_using_next-i18next.md +1 -1
  32. package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  33. package/blog/zh/i18n_using_next-i18next.md +1 -1
  34. package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  35. package/docs/ar/bundle_optimization.md +454 -0
  36. package/docs/ar/intlayer_with_next-i18next.md +1 -1
  37. package/docs/ar/intlayer_with_next-intl.md +1 -1
  38. package/docs/ar/intlayer_with_tanstack+solid.md +24 -5
  39. package/docs/ar/intlayer_with_tanstack.md +45 -68
  40. package/docs/bn/bundle_optimization.md +454 -0
  41. package/docs/cs/bundle_optimization.md +454 -0
  42. package/docs/de/bundle_optimization.md +454 -0
  43. package/docs/de/intlayer_with_next-i18next.md +1 -1
  44. package/docs/de/intlayer_with_next-intl.md +1 -1
  45. package/docs/de/intlayer_with_tanstack+solid.md +24 -5
  46. package/docs/de/intlayer_with_tanstack.md +45 -68
  47. package/docs/en/bundle_optimization.md +36 -8
  48. package/docs/en/intlayer_with_next-i18next.md +1 -1
  49. package/docs/en/intlayer_with_next-intl.md +1 -1
  50. package/docs/en/intlayer_with_tanstack+solid.md +24 -5
  51. package/docs/en/intlayer_with_tanstack.md +45 -68
  52. package/docs/en-GB/bundle_optimization.md +454 -0
  53. package/docs/en-GB/intlayer_with_next-i18next.md +1 -1
  54. package/docs/en-GB/intlayer_with_next-intl.md +1 -1
  55. package/docs/en-GB/intlayer_with_tanstack+solid.md +24 -5
  56. package/docs/en-GB/intlayer_with_tanstack.md +47 -70
  57. package/docs/es/bundle_optimization.md +454 -0
  58. package/docs/es/intlayer_with_next-i18next.md +1 -1
  59. package/docs/es/intlayer_with_next-intl.md +1 -1
  60. package/docs/es/intlayer_with_tanstack+solid.md +24 -5
  61. package/docs/es/intlayer_with_tanstack.md +45 -68
  62. package/docs/fr/bundle_optimization.md +454 -0
  63. package/docs/fr/intlayer_with_next-i18next.md +1 -1
  64. package/docs/fr/intlayer_with_next-intl.md +1 -1
  65. package/docs/fr/intlayer_with_tanstack+solid.md +24 -5
  66. package/docs/fr/intlayer_with_tanstack.md +45 -68
  67. package/docs/hi/bundle_optimization.md +454 -0
  68. package/docs/hi/intlayer_with_next-i18next.md +1 -1
  69. package/docs/hi/intlayer_with_next-intl.md +1 -1
  70. package/docs/hi/intlayer_with_tanstack+solid.md +24 -5
  71. package/docs/hi/intlayer_with_tanstack.md +45 -68
  72. package/docs/id/bundle_optimization.md +454 -0
  73. package/docs/id/intlayer_with_next-i18next.md +1 -1
  74. package/docs/id/intlayer_with_next-intl.md +1 -1
  75. package/docs/id/intlayer_with_tanstack+solid.md +24 -5
  76. package/docs/id/intlayer_with_tanstack.md +45 -68
  77. package/docs/it/bundle_optimization.md +454 -0
  78. package/docs/it/intlayer_with_next-i18next.md +1 -1
  79. package/docs/it/intlayer_with_next-intl.md +1 -1
  80. package/docs/it/intlayer_with_tanstack+solid.md +24 -5
  81. package/docs/it/intlayer_with_tanstack.md +45 -68
  82. package/docs/ja/bundle_optimization.md +454 -0
  83. package/docs/ja/intlayer_with_next-i18next.md +1 -1
  84. package/docs/ja/intlayer_with_next-intl.md +1 -1
  85. package/docs/ja/intlayer_with_tanstack+solid.md +24 -5
  86. package/docs/ja/intlayer_with_tanstack.md +45 -36
  87. package/docs/ko/bundle_optimization.md +454 -0
  88. package/docs/ko/intlayer_with_next-i18next.md +1 -1
  89. package/docs/ko/intlayer_with_next-intl.md +1 -1
  90. package/docs/ko/intlayer_with_tanstack+solid.md +24 -5
  91. package/docs/ko/intlayer_with_tanstack.md +45 -68
  92. package/docs/nl/bundle_optimization.md +454 -0
  93. package/docs/pl/bundle_optimization.md +454 -0
  94. package/docs/pl/intlayer_with_next-i18next.md +1 -1
  95. package/docs/pl/intlayer_with_next-intl.md +1 -1
  96. package/docs/pl/intlayer_with_tanstack+solid.md +24 -5
  97. package/docs/pl/intlayer_with_tanstack.md +45 -68
  98. package/docs/pt/bundle_optimization.md +454 -0
  99. package/docs/pt/intlayer_with_next-i18next.md +1 -1
  100. package/docs/pt/intlayer_with_next-intl.md +1 -1
  101. package/docs/pt/intlayer_with_tanstack+solid.md +24 -5
  102. package/docs/pt/intlayer_with_tanstack.md +45 -68
  103. package/docs/ru/bundle_optimization.md +454 -0
  104. package/docs/ru/intlayer_with_next-i18next.md +1 -1
  105. package/docs/ru/intlayer_with_next-intl.md +1 -1
  106. package/docs/ru/intlayer_with_tanstack+solid.md +24 -5
  107. package/docs/ru/intlayer_with_tanstack.md +45 -68
  108. package/docs/tr/bundle_optimization.md +454 -0
  109. package/docs/tr/intlayer_with_next-i18next.md +1 -1
  110. package/docs/tr/intlayer_with_next-intl.md +1 -1
  111. package/docs/tr/intlayer_with_tanstack+solid.md +24 -5
  112. package/docs/tr/intlayer_with_tanstack.md +45 -68
  113. package/docs/uk/bundle_optimization.md +454 -0
  114. package/docs/uk/intlayer_with_next-i18next.md +1 -1
  115. package/docs/uk/intlayer_with_next-intl.md +1 -1
  116. package/docs/uk/intlayer_with_tanstack+solid.md +24 -5
  117. package/docs/uk/intlayer_with_tanstack.md +45 -68
  118. package/docs/ur/bundle_optimization.md +454 -0
  119. package/docs/vi/bundle_optimization.md +454 -0
  120. package/docs/vi/intlayer_with_next-i18next.md +1 -1
  121. package/docs/vi/intlayer_with_next-intl.md +1 -1
  122. package/docs/vi/intlayer_with_tanstack+solid.md +24 -5
  123. package/docs/vi/intlayer_with_tanstack.md +45 -68
  124. package/docs/zh/bundle_optimization.md +454 -0
  125. package/docs/zh/intlayer_with_next-i18next.md +1 -1
  126. package/docs/zh/intlayer_with_next-intl.md +1 -1
  127. package/docs/zh/intlayer_with_tanstack+solid.md +24 -5
  128. package/docs/zh/intlayer_with_tanstack.md +45 -68
  129. package/package.json +7 -7
@@ -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
- // Utilitas utama
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 To = RemoveLocaleParam<LinkComponentProps["to"]>;
334
-
335
- type CollapseDoubleSlashes<S extends string> =
336
- S extends `${infer H}//${infer T}` ? CollapseDoubleSlashes<`${H}/${T}`> : S;
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
- // Pembantu
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 @@ Kemudian kita dapat membuat hook `useLocalizedNavigate` untuk navigasi secara te
377
365
  import { useNavigate } from "@tanstack/react-router";
378
366
  import { getPrefix } from "intlayer";
379
367
  import { useLocale } from "react-intlayer";
380
- import { LOCALE_ROUTE } from "@/components/localized-link";
368
+ import type { StripLocalePrefix } from "@/components/localized-link";
381
369
  import type { FileRouteTypes } from "@/routeTree.gen";
382
370
 
383
- type StripLocalePrefix<T extends string> = T extends
384
- | `/${typeof LOCALE_ROUTE}`
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 LocalizedNavigate = {
394
- (to: LocalizedTo): ReturnType<ReturnType<typeof useNavigate>>;
395
- (
396
- opts: { to: LocalizedTo } & Record<string, unknown>
397
- ): ReturnType<ReturnType<typeof useNavigate>>;
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 metaContent = getIntlayer("page-metadata", locale);
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
- { content: metaContent.description, name: "description" },
614
+ { name: "description", content: metaContent.meta.description },
638
615
  ],
639
616
  };
640
617
  },
@@ -0,0 +1,454 @@
1
+ ---
2
+ createdAt: 2025-11-25
3
+ updatedAt: 2026-04-08
4
+ title: Ottimizzazione della dimensione del bundle i18n e prestazioni
5
+ description: Riduci la dimensione del bundle della tua applicazione ottimizzando i contenuti di internazionalizzazione (i18n). Scopri come sfruttare il tree shaking e il lazy loading per i dizionari con Intlayer.
6
+ keywords:
7
+ - Ottimizzazione del bundle
8
+ - Automazione dei contenuti
9
+ - Contenuto dinamico
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: "Aggiunte le opzioni `minify` e `purge` alla configurazione di build"
22
+ ---
23
+
24
+ # Ottimizzazione della dimensione del bundle i18n e prestazioni
25
+
26
+ Una delle sfide più comuni con le soluzioni i18n tradizionali che si affidano a file JSON è la gestione della dimensione dei contenuti. Se gli sviluppatori non separano manualmente i contenuti in namespace, gli utenti finiscono spesso per scaricare le traduzioni per ogni pagina e potenzialmente per ogni lingua solo per visualizzare una singola pagina.
27
+
28
+ Ad esempio, un'applicazione con 10 pagine tradotte in 10 lingue potrebbe comportare il download dei contenuti di 100 pagine da parte di un utente, anche se ne serve solo **una** (quella corrente nella lingua corrente). Ciò comporta uno spreco di larghezza di banda e tempi di caricamento più lenti.
29
+
30
+ **Intlayer risolve questo problema attraverso l'ottimizzazione in fase di build.** Analizza il tuo codice per rilevare quali dizionari sono effettivamente utilizzati per ogni componente e reinserisce solo il contenuto necessario nel tuo bundle.
31
+
32
+ ## Sommario
33
+
34
+ <TOC />
35
+
36
+ ## Scansiona il tuo bundle
37
+
38
+ Analizzare il tuo bundle è il primo passo per identificare file JSON "pesanti" e opportunità di code-splitting. Questi strumenti generano una mappa ad albero visiva del codice compilato della tua applicazione, permettendoti di vedere esattamente quali librerie stanno consumando più spazio.
39
+
40
+ <Tabs>
41
+ <Tab value="vite">
42
+
43
+ ### Vite / Rollup
44
+
45
+ Vite utilizza Rollup internamente. Il plugin `rollup-plugin-visualizer` genera un file HTML interattivo che mostra le dimensioni di ogni modulo nel tuo grafico.
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, // Apre automaticamente il report nel tuo browser
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
+ Per i progetti che utilizzano App Router e Turbopack, Next.js fornisce un analizzatore sperimentale integrato che non richiede dipendenze extra.
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
+ Se stai utilizzando il bundler Webpack predefinito in Next.js, usa l'analizzatore di bundle ufficiale. Attivalo impostando una variabile d'ambiente durante la build.
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
+ // La tua configurazione Next.js
120
+ });
121
+ ```
122
+
123
+ **Utilizzo:**
124
+
125
+ ```bash
126
+ ANALYZE=true npm run build
127
+ ```
128
+
129
+ </Tab>
130
+ <Tab value="Webpack (CRA / Angular / etc)">
131
+
132
+ ### Webpack Standard
133
+
134
+ Per Create React App (ejected), Angular o configurazioni Webpack personalizzate, usa lo standard di settore `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
+ ## Come funziona
170
+
171
+ Intlayer utilizza un **approccio per componente**. A differenza dei file JSON globali, i tuoi contenuti sono definiti insieme o all'interno dei tuoi componenti. Durante il processo di build, Intlayer:
172
+
173
+ 1. **Analizza** il tuo codice per trovare le chiamate a `useIntlayer`.
174
+ 2. **Costruisce** il contenuto del dizionario corrispondente.
175
+ 3. **Sostituisce** la chiamata a `useIntlayer` con codice ottimizzato in base alla tua configurazione.
176
+
177
+ Questo assicura che:
178
+
179
+ - Se un componente non viene importato, il suo contenuto non viene incluso nel bundle (Dead Code Elimination).
180
+ - Se un componente è caricato in modalità lazy, anche il suo contenuto viene caricato in modalità lazy.
181
+
182
+ ## Configurazione per piattaforma
183
+
184
+ <Tabs>
185
+ <Tab value="nextjs">
186
+
187
+ ### Next.js
188
+
189
+ Next.js richiede il plugin `@intlayer/swc` per gestire la trasformazione, poiché Next.js utilizza SWC per le build.
190
+
191
+ > Questo plugin non è installato di default perché i plugin SWC sono ancora sperimentali per Next.js. Potrebbe cambiare in futuro.
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
+ Una volta installato, Intlayer rileverà e utilizzerà automaticamente il plugin.
210
+
211
+ </Tab>
212
+ <Tab value="vite">
213
+
214
+ ### Vite
215
+
216
+ Vite utilizza il plugin `@intlayer/babel` che è incluso come dipendenza di `vite-intlayer`. L'ottimizzazione è abilitata di default. Non c'è altro da fare.
217
+
218
+ </Tab>
219
+ <Tab value="webpack">
220
+
221
+ ### Webpack
222
+
223
+ Per abilitare l'ottimizzazione del bundle con Intlayer su Webpack, è necessario installare e configurare il plugin Babel (`@intlayer/babel`) o SWC (`@intlayer/swc`) appropriato.
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
+ ## Configurazione
256
+
257
+ Puoi controllare come Intlayer ottimizza il tuo bundle tramite la proprietà `build` nel tuo `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
+ * Minimizza i dizionari per ridurre la dimensione del bundle.
273
+ */
274
+ minify: true;
275
+
276
+ /**
277
+ * Elimina le chiavi inutilizzate nei dizionari
278
+ */
279
+ purge: true;
280
+
281
+ /**
282
+ * Indica se la build deve controllare i tipi TypeScript
283
+ */
284
+ checkTypes: false;
285
+ },
286
+ };
287
+
288
+ export default config;
289
+ ```
290
+
291
+ > Mantenere l'opzione predefinita per `optimize` è raccomandato nella stragrande maggioranza dei casi.
292
+
293
+ > Vedi la doc di configurazione per maggiori dettagli: [Configurazione](https://github.com/aymericzip/intlayer/blob/main/docs/docs/it/configuration.md)
294
+
295
+ ### Opzioni di Build
296
+
297
+ Le seguenti opzioni sono disponibili sotto l'oggetto di configurazione `build`:
298
+
299
+ | Proprietà | Tipo | Predefinito | Descrizione |
300
+ | :------------- | :-------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
301
+ | **`optimize`** | `boolean` | `undefined` | Controlla se l'ottimizzazione della build è abilitata. Se `true`, Intlayer sostituisce le chiamate ai dizionari con iniezioni ottimizzate. Se `false`, l'ottimizzazione è disabilitata. Idealmente a `true` in produzione. |
302
+ | **`minify`** | `boolean` | `false` | Se minimizzare i dizionari per ridurre la dimensione del bundle. |
303
+ | **`purge`** | `boolean` | `false` | Se eliminare le chiavi inutilizzate nei dizionari. |
304
+
305
+ ### Minimizzazione
306
+
307
+ Minimizzare i dizionari rimuove spazi bianchi non necessari, commenti e riduce la dimensione dei contenuti JSON. Ciò è particolarmente utile per dizionari di grandi dimensioni.
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
+ > Nota: La minimizzazione viene ignorata se `optimize` è disabilitato o se il Visual Editor è abilitato (poiché l'editor ha bisogno del contenuto completo per consentire le modifiche).
322
+
323
+ ### Purging (Eliminazione)
324
+
325
+ Il purging assicura che solo le chiavi effettivamente utilizzate nel codice siano incluse nel bundle finale dei dizionari. Ciò può ridurre significativamente la dimensione del bundle se si hanno dizionari grandi con molte chiavi che non vengono utilizzate in ogni parte dell'applicazione.
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
+ > Nota: Il purging viene ignorato se `optimize` è disabilitato.
340
+
341
+ ### Modalità di Importazione
342
+
343
+ Per applicazioni di grandi dimensioni, comprese diverse pagine e lingue, i tuoi file JSON possono rappresentare una parte significativa della dimensione del tuo bundle. Intlayer ti consente di controllare come vengono caricati i dizionari.
344
+
345
+ La modalità di importazione può essere definita di default a livello globale nel file `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
+ Così come per ogni dizionario nei tuoi file `.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", // Sovrascrive la modalità di importazione predefinita
367
+ content: {
368
+ // ...
369
+ },
370
+ };
371
+
372
+ export default appContent;
373
+ ```
374
+
375
+ | Proprietà | Tipo | Predefinito | Descrizione |
376
+ | :--------------- | :--------------------------------- | :---------- | :--------------------------------------------------------------------------------------------------------------------------- |
377
+ | **`importMode`** | `'static'`, `'dynamic'`, `'fetch'` | `'static'` | **Deprecato**: Usa `dictionary.importMode` invece. Determina come vengono caricati i dizionari (vedi i dettagli di seguito). |
378
+
379
+ L'impostazione `importMode` dettata come il contenuto del dizionario viene iniettato nel tuo componente.
380
+ Puoi definirlo globalmente nel file `intlayer.config.ts` sotto l'oggetto `dictionary`, oppure puoi sovrascriverlo per un dizionario specifico nel suo file `.content.ts`.
381
+
382
+ ### 1. Modalità Statica (`default`)
383
+
384
+ In modalità statica, Intlayer sostituisce `useIntlayer` con `useDictionary` e inietta il dizionario direttamente nel bundle JavaScript.
385
+
386
+ - **Pro:** Rendering istantaneo (sincrono), zero richieste di rete extra durante l'idratazione.
387
+ - **Contro:** Il bundle include le traduzioni per **tutte** le lingue disponibili per quel componente specifico.
388
+ - **Ideale per:** Single Page Applications (SPA).
389
+
390
+ **Esempio di codice trasformato:**
391
+
392
+ ```tsx
393
+ // Il tuo codice
394
+ const content = useIntlayer("my-key");
395
+
396
+ // Codice ottimizzato (Statico)
397
+ const content = useDictionary({
398
+ key: "my-key",
399
+ content: {
400
+ nodeType: "translation",
401
+ translation: {
402
+ en: "My title",
403
+ fr: "Mon titolo",
404
+ },
405
+ },
406
+ });
407
+ ```
408
+
409
+ ### 2. Modalità Dinamica
410
+
411
+ In modalità dinamica, Intlayer sostituisce `useIntlayer` con `useDictionaryAsync`. Questo utilizza `import()` (meccanismo simile a Suspense) per caricare in modalità lazy specificamente il JSON per la lingua corrente.
412
+
413
+ - **Pro:** **Tree shaking a livello di lingua.** Un utente che visualizza la versione inglese scaricherà _solo_ il dizionario inglese. Il dizionario francese non viene mai caricato.
414
+ - **Contro:** Attiva una richiesta di rete (recupero dell'asset) per componente durante l'idratazione.
415
+ - **Ideale per:** Grandi blocchi di testo, articoli o applicazioni che supportano molte lingue in cui la dimensione del bundle è critica.
416
+
417
+ **Esempio di codice trasformato:**
418
+
419
+ ```tsx
420
+ // Il tuo codice
421
+ const content = useIntlayer("my-key");
422
+
423
+ // Codice ottimizzato (Dinamico)
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
+ > Quando usi `importMode: 'dynamic'`, se hai 100 componenti che usano `useIntlayer` in una singola pagina, il browser tenterà 100 recuperi separati. Per evitare questo "waterfall" di richieste, raggruppa i contenuti in meno file `.content` (ad esempio, un dizionario per sezione della pagina) invece di uno per ogni singolo componente atomico.
437
+
438
+ ### 3. Modalità Fetch
439
+
440
+ Si comporta in modo simile alla modalità dinamica ma tenta prima di recuperare i dizionari dall'API Intlayer Live Sync. Se la chiamata API fallisce o il contenuto non è contrassegnato per gli aggiornamenti live, ricorre all'importazione dinamica.
441
+
442
+ > Vedi la documentazione CMS per maggiori dettagli: [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/it/intlayer_CMS.md)
443
+
444
+ > In modalità fetch, purghe e minimizzazioni non possono essere utilizzate.
445
+
446
+ ## Riepilogo: Statico vs Dinamico
447
+
448
+ | Caratteristica | Modalità Statica | Modalità Dinamica |
449
+ | :----------------------- | :--------------------------------------------------- | :------------------------------------- |
450
+ | **Dimensione Bundle JS** | Maggiore (include tutte le lingue per il componente) | Minore (solo codice, nessun contenuto) |
451
+ | **Caricamento Iniziale** | Istantaneo (Il contenuto è nel bundle) | Leggero ritardo (Recupera JSON) |
452
+ | **Richieste di Rete** | 0 richieste extra | 1 richiesta per dizionario |
453
+ | **Tree Shaking** | Livello componente | Livello componente + Livello lingua |
454
+ | **Miglior Caso d'Uso** | Componenti UI, Piccole Applicazioni | Pagine con molto testo, molte lingue |
@@ -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
- ? (params.locale as any)
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 as any)) notFound();
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 metaContent = getIntlayer("page-metadata", locale);
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
- { content: metaContent.description, name: "description" },
533
+ { name: "description", content: metaContent.meta.description },
515
534
  ],
516
535
  };
517
536
  },