@intlayer/docs 7.5.13 → 7.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/blog/ar/per-component_vs_centralized_i18n.md +248 -0
  2. package/blog/de/per-component_vs_centralized_i18n.md +248 -0
  3. package/blog/en/_per-component_vs_centralized_i18n.md +252 -0
  4. package/blog/en/per-component_vs_centralized_i18n.md +248 -0
  5. package/blog/en-GB/per-component_vs_centralized_i18n.md +247 -0
  6. package/blog/es/per-component_vs_centralized_i18n.md +245 -0
  7. package/blog/fr/per-component_vs_centralized_i18n.md +245 -0
  8. package/blog/hi/per-component_vs_centralized_i18n.md +249 -0
  9. package/blog/id/per-component_vs_centralized_i18n.md +248 -0
  10. package/blog/it/per-component_vs_centralized_i18n.md +247 -0
  11. package/blog/ja/per-component_vs_centralized_i18n.md +247 -0
  12. package/blog/ko/per-component_vs_centralized_i18n.md +246 -0
  13. package/blog/pl/per-component_vs_centralized_i18n.md +247 -0
  14. package/blog/pt/per-component_vs_centralized_i18n.md +246 -0
  15. package/blog/ru/per-component_vs_centralized_i18n.md +251 -0
  16. package/blog/tr/per-component_vs_centralized_i18n.md +244 -0
  17. package/blog/uk/per-component_vs_centralized_i18n.md +248 -0
  18. package/blog/vi/per-component_vs_centralized_i18n.md +246 -0
  19. package/blog/zh/per-component_vs_centralized_i18n.md +248 -0
  20. package/dist/cjs/common.cjs.map +1 -1
  21. package/dist/cjs/generated/blog.entry.cjs +20 -0
  22. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  23. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  24. package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
  25. package/dist/cjs/generated/legal.entry.cjs.map +1 -1
  26. package/dist/esm/common.mjs.map +1 -1
  27. package/dist/esm/generated/blog.entry.mjs +20 -0
  28. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  29. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  30. package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
  31. package/dist/esm/generated/legal.entry.mjs.map +1 -1
  32. package/dist/types/generated/blog.entry.d.ts +1 -0
  33. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  34. package/package.json +9 -9
  35. package/src/generated/blog.entry.ts +20 -0
@@ -0,0 +1,248 @@
1
+ ---
2
+ createdAt: 2025-09-10
3
+ updatedAt: 2025-09-10
4
+ title: Per-Komponen vs. i18n Terpusat: Pendekatan Baru dengan Intlayer
5
+ description: Tinjauan mendalam tentang strategi internasionalisasi di React, membandingkan pendekatan terpusat, per-key, dan per-komponen, serta memperkenalkan Intlayer.
6
+ keywords:
7
+ - i18n
8
+ - React
9
+ - Internasionalisasi
10
+ - Intlayer
11
+ - Optimisasi
12
+ - Ukuran Bundle
13
+ slugs:
14
+ - blog
15
+ - per-component-vs-centralized-i18n
16
+ ---
17
+
18
+ # Per-Komponen vs. i18n Terpusat
19
+
20
+ Pendekatan per-komponen bukanlah konsep baru. Misalnya, dalam ekosistem Vue, `vue-i18n` mendukung [i18n SFC (Single File Component)](https://vue-i18n.intlify.dev/guide/advanced/sfc.html). Nuxt juga menawarkan [terjemahan per-komponen](https://i18n.nuxtjs.org/docs/guide/per-component-translations), dan Angular menggunakan pola serupa melalui [Feature Modules](https://v17.angular.io/guide/feature-modules)-nya.
21
+
22
+ Bahkan dalam aplikasi Flutter, kita sering menemukan pola ini:
23
+
24
+ ```bash
25
+ lib/
26
+ └── features/
27
+ └── login/
28
+ ├── login_screen.dart
29
+ └── login_screen.i18n.dart # <- Terjemahan berada di sini
30
+ ```
31
+
32
+ ```dart fileName='lib/features/login/login_screen.i18n.dart'
33
+ import 'package:i18n_extension/i18n_extension.dart';
34
+
35
+ extension Localization on String {
36
+ static var _t = Translations.byText("en") +
37
+ {
38
+ "Hello": {
39
+ "en": "Hello",
40
+ "fr": "Bonjour",
41
+ },
42
+ };
43
+
44
+ String get i18n => localize(this, _t);
45
+ }
46
+ ```
47
+
48
+ Namun, di dunia React, kita terutama melihat pendekatan yang berbeda, yang akan saya kelompokkan menjadi tiga kategori:
49
+
50
+ <Columns>
51
+ <Column>
52
+
53
+ **Pendekatan terpusat** (i18next, next-intl, react-intl, lingui)
54
+
55
+ - (with no namespaces) menganggap satu sumber untuk mengambil konten. Secara default, Anda memuat konten dari semua halaman ketika aplikasi Anda dimuat.
56
+
57
+ </Column>
58
+ <Column>
59
+
60
+ **Pendekatan granular** (intlayer, inlang)
61
+
62
+ - pengambilan konten dilakukan secara granular per key, atau per-komponen.
63
+
64
+ </Column>
65
+ </Columns>
66
+
67
+ > Dalam blog ini, saya tidak akan fokus pada solusi berbasis compiler, yang sudah saya bahas di sini: [Compiler vs Declarative i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/id/compiler_vs_declarative_i18n.md).
68
+ > Perlu dicatat bahwa i18n berbasis compiler (mis. Lingui) hanya mengotomatisasi ekstraksi dan pemuatan konten. Di balik layar, mereka sering berbagi batasan yang sama dengan pendekatan lainnya.
69
+
70
+ > Perlu dicatat bahwa semakin Anda memperinci cara mengambil konten, semakin besar risiko Anda memasukkan state dan logika tambahan ke dalam komponen Anda.
71
+
72
+ Pendekatan granular lebih fleksibel daripada yang terpusat, tetapi sering kali merupakan tradeoff. Bahkan jika "tree shaking" diiklankan oleh perpustakaan tersebut, dalam praktiknya Anda sering kali akan berakhir memuat sebuah halaman dalam setiap bahasa.
73
+
74
+ Jadi, secara garis besar, keputusan dibagi seperti ini:
75
+
76
+ - Jika aplikasi Anda memiliki lebih banyak halaman daripada bahasa, Anda sebaiknya memilih pendekatan granular.
77
+ - Jika Anda memiliki lebih banyak bahasa daripada halaman, Anda sebaiknya condong ke pendekatan terpusat.
78
+
79
+ Tentu saja, penulis pustaka menyadari keterbatasan ini dan menyediakan solusi.
80
+ Di antaranya: memecah menjadi namespaces, memuat file JSON secara dinamis (`await import()`), atau menghapus konten saat build.
81
+
82
+ Pada saat yang sama, Anda harus tahu bahwa ketika Anda memuat konten secara dinamis, Anda memperkenalkan permintaan tambahan ke server Anda. Setiap `useState` atau hook tambahan berarti permintaan server tambahan.
83
+
84
+ > Untuk mengatasi hal ini, Intlayer menyarankan mengelompokkan beberapa definisi konten di bawah kunci yang sama, Intlayer kemudian akan menggabungkan konten tersebut.
85
+
86
+ Tetapi dari semua solusi tersebut, jelas bahwa pendekatan terpusat adalah yang paling populer.
87
+
88
+ ### Jadi mengapa pendekatan terpusat begitu populer?
89
+
90
+ - Pertama, i18next adalah solusi pertama yang menjadi banyak digunakan, mengikuti filosofi yang terinspirasi dari arsitektur PHP dan Java (MVC), yang mengandalkan pemisahan tanggung jawab yang ketat (memisahkan konten dari kode). Ia hadir pada 2011, menetapkan standarnya bahkan sebelum pergeseran besar menuju Arsitektur Berbasis Komponen (seperti React).
91
+ - Kemudian, setelah sebuah library banyak diadopsi, menjadi sulit menggeser ekosistem ke pola lain.
92
+ - Menggunakan pendekatan terpusat juga mempermudah penggunaan Translation Management Systems seperti Crowdin, Phrase, atau Localized.
93
+ - Logika di balik pendekatan per-komponen lebih kompleks daripada yang terpusat dan membutuhkan waktu pengembangan ekstra, terutama saat Anda harus memecahkan masalah seperti mengidentifikasi di mana konten berada.
94
+
95
+ ### Oke, tapi kenapa tidak tetap berpegang pada pendekatan Terpusat?
96
+
97
+ Biarkan saya jelaskan mengapa ini bisa menjadi masalah untuk aplikasi Anda:
98
+
99
+ - **Data yang Tidak Digunakan:**
100
+ Saat sebuah halaman dimuat, Anda sering memuat konten dari semua halaman lain. (Di aplikasi 10-halaman, itu berarti 90% konten yang dimuat tidak digunakan). Anda memuat modal secara lazy? Library i18n tidak peduli, ia tetap memuat string terlebih dahulu.
101
+ - **Performa:**
102
+ Untuk setiap re-render, setiap komponen Anda di-hydrate dengan payload JSON besar, yang memengaruhi reaktivitas aplikasi Anda seiring pertumbuhannya.
103
+ - **Pemeliharaan:**
104
+ Memelihara file JSON besar itu merepotkan. Anda harus loncat antar file untuk memasukkan terjemahan, memastikan tidak ada terjemahan yang hilang dan tidak ada **orphan keys** yang tertinggal.
105
+ - **Sistem desain:**
106
+ Ini menciptakan ketidakcocokan dengan design systems (misalnya, komponen `LoginForm`) dan membatasi duplikasi komponen antar aplikasi.
107
+
108
+ **"Tapi kami menciptakan Namespaces!"**
109
+
110
+ Tentu, dan itu merupakan langkah maju yang besar. Mari lihat perbandingan ukuran bundle utama dari setup Vite + React + React Router v7 + Intlayer. Kami mensimulasikan aplikasi 20-halaman.
111
+
112
+ Contoh pertama tidak memasukkan terjemahan yang dimuat secara lazy per locale dan tidak ada pemecahan namespace. Yang kedua mencakup pembersihan konten + pemuatan dinamis untuk terjemahan.
113
+
114
+ | Bundle dioptimalkan | Bundle tidak dioptimalkan |
115
+ | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
116
+ | ![bundle tidak teroptimasi](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle_no_optimization.png?raw=true) | ![bundle yang teroptimasi](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true) |
117
+
118
+ Jadi berkat namespaces, kita berpindah dari struktur ini:
119
+
120
+ ```bash
121
+ locale/
122
+ ├── en.json
123
+ ├── fr.json
124
+ └── es.json
125
+ ```
126
+
127
+ Menjadi struktur ini:
128
+
129
+ ```bash
130
+ locale/
131
+ ├── en/
132
+ │ ├── common.json
133
+ │ ├── navbar.json
134
+ │ ├── footer.json
135
+ │ ├── home.json
136
+ │ └── about.json
137
+ ├── fr/
138
+ │ └── ...
139
+ └── es/
140
+ └── ...
141
+
142
+ ```
143
+
144
+ Sekarang Anda harus mengelola secara rinci bagian mana dari konten aplikasi Anda yang harus dimuat, dan di mana. Kesimpulannya, sebagian besar proyek justru melewatkan bagian ini karena kompleksitasnya (lihat [panduan next-i18next](https://github.com/aymericzip/intlayer/blob/main/docs/blog/id/i18n_using_next-i18next.md) misalnya untuk melihat tantangan yang muncul hanya dengan mengikuti praktik yang baik).
145
+ Akibatnya, proyek-proyek tersebut berakhir dengan masalah pemuatan JSON besar-besaran yang dijelaskan sebelumnya.
146
+
147
+ > Perlu dicatat bahwa masalah ini bukan spesifik untuk i18next, melainkan untuk semua pendekatan terpusat yang disebutkan di atas.
148
+
149
+ Namun, saya ingin mengingatkan Anda bahwa tidak semua pendekatan granular menyelesaikan hal ini. Misalnya, pendekatan `vue-i18n SFC` atau `inlang` tidak secara inheren melakukan lazy load terjemahan per-locale, sehingga Anda hanya menukar masalah ukuran bundle dengan masalah lain.
150
+
151
+ Selain itu, tanpa separation of concerns yang tepat, akan jauh lebih sulit untuk mengekstrak dan menyediakan terjemahan Anda kepada penerjemah untuk ditinjau.
152
+
153
+ ### Bagaimana pendekatan per-komponen Intlayer menyelesaikan ini
154
+
155
+ Intlayer melakukan beberapa langkah:
156
+
157
+ 1. **Deklarasi:** Deklarasikan konten Anda di mana saja dalam codebase Anda menggunakan file `*.content.{ts|jsx|cjs|json|json5|...}`. Ini memastikan separation of concerns sambil menjaga konten tetap ditempatkan bersama. Sebuah file konten bisa per-locale atau multibahasa.
158
+ 2. **Pemrosesan:** Intlayer menjalankan langkah build untuk memproses logika JS, menangani fallback terjemahan yang hilang, menghasilkan tipe TypeScript, mengelola konten duplikat, mengambil konten dari CMS Anda, dan lainnya.
159
+ 3. **Pembersihan:** Ketika aplikasi Anda dibangun, Intlayer membersihkan konten yang tidak terpakai (sedikit mirip dengan bagaimana Tailwind mengelola kelas Anda) dengan mengganti konten sebagai berikut:
160
+
161
+ **Deklarasi:**
162
+
163
+ ```tsx
164
+ // src/MyComponent.tsx
165
+ export const MyComponent = () => {
166
+ const content = useIntlayer("my-key");
167
+ return <h1>{content.title}</h1>;
168
+ };
169
+ ```
170
+
171
+ ```tsx
172
+ // src/myComponent.content.ts
173
+ export const {
174
+ key: "my-key",
175
+ content: t({
176
+ en: { title: "My title" },
177
+ fr: { title: "Mon titre" }
178
+ })
179
+ }
180
+
181
+ ```
182
+
183
+ **Pemrosesan:** Intlayer membangun kamus berdasarkan file `.content` dan menghasilkan:
184
+
185
+ ```json5
186
+ // .intlayer/dynamic_dictionary/id/my-key.json
187
+ {
188
+ "key": "my-key",
189
+ "content": { "title": "Judul saya" },
190
+ }
191
+ ```
192
+
193
+ **Penggantian:** Intlayer mengubah komponen Anda selama proses build aplikasi.
194
+
195
+ **- Mode Impor Statis:**
196
+
197
+ ```tsx
198
+ // Representasi komponen dalam sintaks mirip JSX
199
+ export const MyComponent = () => {
200
+ const content = useDictionary({
201
+ key: "my-key",
202
+ content: {
203
+ nodeType: "translation",
204
+ translation: {
205
+ id: { title: "Judul saya" },
206
+ en: { title: "My title" },
207
+ fr: { title: "Mon titre" },
208
+ },
209
+ },
210
+ });
211
+
212
+ return <h1>{content.title}</h1>;
213
+ };
214
+ ```
215
+
216
+ **- Mode Impor Dinamis:**
217
+
218
+ ```tsx
219
+ // Representasi komponen dalam sintaks mirip JSX
220
+ export const MyComponent = () => {
221
+ const content = useDictionaryAsync({
222
+ en: () =>
223
+ import(".intlayer/dynamic_dictionary/en/my-key.json", {
224
+ with: { type: "json" },
225
+ }).then((mod) => mod.default),
226
+ // Sama untuk bahasa lain
227
+ });
228
+
229
+ return <h1>{content.title}</h1>;
230
+ };
231
+ ```
232
+
233
+ > `useDictionaryAsync` menggunakan mekanisme mirip Suspense untuk memuat JSON terlokalisasi hanya saat dibutuhkan.
234
+
235
+ **Manfaat utama dari pendekatan per-komponen ini:**
236
+
237
+ - Menjaga deklarasi konten Anda dekat dengan komponen memungkinkan pemeliharaan yang lebih baik (mis. memindahkan sebuah komponen ke aplikasi atau design system lain. Menghapus folder komponen akan menghapus konten terkait juga, seperti yang mungkin sudah Anda lakukan untuk berkas `.test`, `.stories`)
238
+
239
+ /// Pendekatan per-komponen mencegah agen AI perlu melompat ke semua berkas Anda yang berbeda. Pendekatan ini memperlakukan semua terjemahan di satu tempat, membatasi kompleksitas tugas dan jumlah token yang digunakan.
240
+
241
+ ### Keterbatasan
242
+
243
+ Tentu saja, pendekatan ini datang dengan trade-offs:
244
+
245
+ - Lebih sulit untuk terhubung ke sistem l10n lain dan tooling tambahan.
246
+ - Anda menjadi terkunci (yang pada dasarnya sudah terjadi dengan solusi i18n manapun karena sintaks spesifik mereka).
247
+
248
+ Itulah alasan mengapa Intlayer berusaha menyediakan rangkaian alat lengkap untuk i18n (100% gratis dan OSS), termasuk terjemahan AI menggunakan AI Provider dan API keys milik Anda. Intlayer juga menyediakan tooling untuk menyinkronkan JSON Anda, berfungsi seperti formatter pesan ICU / vue-i18n / i18next untuk memetakan konten ke format spesifik mereka.
@@ -0,0 +1,247 @@
1
+ ---
2
+ createdAt: 2025-09-10
3
+ updatedAt: 2025-09-10
4
+ title: "i18n per componente vs. i18n centralizzato: un nuovo approccio con Intlayer"
5
+ description: "Un'analisi approfondita delle strategie di internazionalizzazione in React, confrontando gli approcci centralizzato, per-key e per-componente, e presentando Intlayer."
6
+ keywords:
7
+ - i18n
8
+ - React
9
+ - Internazionalizzazione
10
+ - Intlayer
11
+ - Ottimizzazione
12
+ - Dimensione del bundle
13
+ slugs:
14
+ - blog
15
+ - per-component-vs-centralized-i18n
16
+ ---
17
+
18
+ # i18n per componente vs i18n centralizzato
19
+
20
+ L'approccio per-componente non è un concetto nuovo. Ad esempio, nell'ecosistema Vue, `vue-i18n` supporta l'[i18n SFC (Single File Component)](https://vue-i18n.intlify.dev/guide/advanced/sfc.html). Nuxt offre anche [traduzioni per-componente](https://i18n.nuxtjs.org/docs/guide/per-component-translations), e Angular utilizza un pattern simile attraverso i suoi [Feature Modules](https://v17.angular.io/guide/feature-modules).
21
+
22
+ Anche in un'app Flutter spesso troviamo questo schema:
23
+
24
+ ```bash
25
+ lib/
26
+ └── features/
27
+ └── login/
28
+ ├── login_screen.dart
29
+ └── login_screen.i18n.dart # <- Le traduzioni risiedono qui
30
+ ```
31
+
32
+ ```dart fileName='lib/features/login/login_screen.i18n.dart'
33
+ import 'package:i18n_extension/i18n_extension.dart';
34
+
35
+ extension Localization on String {
36
+ static var _t = Translations.byText("en") +
37
+ {
38
+ "Hello": {
39
+ "en": "Hello",
40
+ "fr": "Bonjour",
41
+ },
42
+ };
43
+
44
+ String get i18n => localize(this, _t);
45
+ }
46
+ ```
47
+
48
+ Tuttavia, nel mondo React vediamo principalmente approcci differenti, che raggrupperò in tre categorie:
49
+
50
+ <Columns>
51
+ <Column>
52
+
53
+ **Approccio centralizzato** (i18next, next-intl, react-intl, lingui)
54
+
55
+ - (senza namespaces) considera un'unica sorgente per recuperare i contenuti. Per impostazione predefinita, carichi i contenuti di tutte le pagine quando la tua app si avvia.
56
+
57
+ </Column>
58
+ <Column>
59
+
60
+ **Approccio granulare** (intlayer, inlang)
61
+
62
+ - dettagliare il recupero dei contenuti per chiave o per componente.
63
+
64
+ </Column>
65
+ </Columns>
66
+
67
+ > In questo blog non mi concentrerò sulle soluzioni compiler-based, che ho già trattato qui: [Compiler vs Declarative i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/it/compiler_vs_declarative_i18n.md).
68
+ > Nota che l'i18n compiler-based (ad es., Lingui) automatizza semplicemente l'estrazione e il caricamento dei contenuti. Sotto il cofano, spesso condividono le stesse limitazioni di altri approcci.
69
+
70
+ > Nota che più granularizzi il modo in cui recuperi i tuoi contenuti, maggiore è il rischio di inserire stato e logica aggiuntiva nei tuoi componenti.
71
+
72
+ Gli approcci granulari sono più flessibili di quelli centralizzati, ma spesso è un compromesso. Anche se quelle librerie pubblicizzano il "tree shaking", nella pratica finirai spesso per caricare una pagina in tutte le lingue.
73
+
74
+ Quindi, in termini generali, la decisione si riduce a:
75
+
76
+ - Se la tua applicazione ha più pagine che lingue, dovresti favorire un approccio granulare.
77
+ - Se hai più lingue che pagine, dovresti orientarti verso un approccio centralizzato.
78
+
79
+ Naturalmente, gli autori delle librerie sono consapevoli di queste limitazioni e forniscono delle soluzioni. Tra queste: suddividere in namespace, caricare dinamicamente file JSON (`await import()`), o eliminare i contenuti in fase di build.
80
+
81
+ Allo stesso tempo, dovresti sapere che quando carichi dinamicamente i tuoi contenuti, introduci richieste aggiuntive al tuo server. Ogni ulteriore `useState` o hook comporta una richiesta aggiuntiva al server.
82
+
83
+ > Per risolvere questo punto, Intlayer suggerisce di raggruppare più definizioni di contenuto sotto la stessa chiave; Intlayer poi effettuerà il merge di quei contenuti.
84
+
85
+ Ma da tutte queste soluzioni risulta chiaro che l'approccio più popolare è quello centralizzato.
86
+
87
+ ### Perché dunque l'approccio centralizzato è così popolare?
88
+
89
+ - In primo luogo, i18next è stata la prima soluzione ad essere ampiamente adottata, seguendo una filosofia ispirata alle architetture PHP e Java (MVC), che si basano su una rigorosa separazione delle responsabilità (mantenere il contenuto separato dal codice). È arrivata nel 2011, stabilendo i suoi standard prima della grande transizione verso le architetture basate su componenti (come React).
90
+ - Inoltre, una volta che una libreria viene ampiamente adottata, diventa difficile spostare l'intero ecosistema verso altri pattern.
91
+ - L'utilizzo di un approccio centralizzato rende anche le cose più semplici in sistemi di gestione delle traduzioni (Translation Management Systems) come Crowdin, Phrase o Localized.
92
+ - La logica alla base di un approccio per componente è più complessa rispetto a quella centralizzata e richiede più tempo di sviluppo, soprattutto quando bisogna risolvere problemi come identificare dove si trova il contenuto.
93
+
94
+ ### Ok, ma perché non limitarsi semplicemente a un approccio centralizzato?
95
+
96
+ Lasciami spiegare perché può essere problematico per la tua app:
97
+
98
+ - **Dati non utilizzati:**
99
+ Quando una pagina si carica, spesso carichi anche i contenuti di tutte le altre pagine. (In un'app di 10 pagine, significa il 90% di contenuti caricati e non usati). Carichi in lazy un modal? La libreria i18n non se ne cura, carica comunque prima le stringhe.
100
+ - **Prestazioni:**
101
+ A ogni re-render, ciascuno dei tuoi componenti viene idratato con un enorme payload JSON, il che impatta la reattività dell'app man mano che cresce.
102
+ - **Manutenzione:**
103
+ Gestire grandi file JSON è doloroso. Devi saltare tra file diversi per inserire una traduzione, assicurandoti che non manchino traduzioni e che non rimangano **orphan keys**.
104
+ - **Design system:**
105
+ Ciò crea incompatibilità con i design system (ad es., un componente `LoginForm`) e vincola la duplicazione dei componenti tra diverse app.
106
+
107
+ **"Ma abbiamo inventato i Namespaces!"**
108
+
109
+ Certo, ed è un enorme passo avanti. Diamo un'occhiata al confronto delle dimensioni del bundle principale di una configurazione Vite + React + React Router v7 + Intlayer. Abbiamo simulato un'applicazione di 20 pagine.
110
+
111
+ Il primo esempio non include traduzioni lazy-loaded per locale né splitting dei namespace. Il secondo include content purging + caricamento dinamico delle traduzioni.
112
+
113
+ | Bundle ottimizzato | Bundle non ottimizzato |
114
+ | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
115
+ | ![bundle non ottimizzato](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle_no_optimization.png?raw=true) | ![bundle ottimizzato](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true) |
116
+
117
+ Quindi, grazie ai namespaces, siamo passati da questa struttura:
118
+
119
+ ```bash
120
+ locale/
121
+ ├── en.json
122
+ ├── fr.json
123
+ └── es.json
124
+ ```
125
+
126
+ To this one:
127
+
128
+ ```bash
129
+ locale/
130
+ ├── en/
131
+ │ ├── common.json
132
+ │ ├── navbar.json
133
+ │ ├── footer.json
134
+ │ ├── home.json
135
+ │ └── about.json
136
+ ├── fr/
137
+ │ └── ...
138
+ └── es/
139
+ └── ...
140
+
141
+ ```
142
+
143
+ Ora devi gestire con precisione quale parte del contenuto della tua app debba essere caricata e dove. In conclusione, la stragrande maggioranza dei progetti salta semplicemente questa fase a causa della complessità (vedi ad esempio la guida [next-i18next](https://github.com/aymericzip/intlayer/blob/main/docs/blog/it/i18n_using_next-i18next.md) per vedere le sfide che comporta (anche solo) seguire le buone pratiche).
144
+ Di conseguenza, questi progetti finiscono col trovarsi di fronte al problema del caricamento massiccio dei JSON spiegato in precedenza.
145
+
146
+ > Nota che questo problema non è specifico di i18next, ma riguarda tutti gli approcci centralizzati elencati sopra.
147
+
148
+ Tuttavia, voglio ricordarti che non tutti gli approcci granulari risolvono questo problema. Ad esempio, gli approcci basati su `vue-i18n SFC` o su `inlang` non effettuano intrinsecamente il lazy loading delle traduzioni per locale, quindi si finisce semplicemente per scambiare il problema delle dimensioni del bundle con un altro.
149
+
150
+ Inoltre, senza una corretta separazione delle responsabilità, diventa molto più difficile estrarre e fornire le traduzioni ai traduttori per la revisione.
151
+
152
+ ### Come l'approccio per componente di Intlayer risolve questo
153
+
154
+ Intlayer procede in diversi passaggi:
155
+
156
+ 1. **Dichiarazione:** Dichiara i tuoi contenuti ovunque nella tua codebase usando file `*.content.{ts|jsx|cjs|json|json5|...}`. Questo garantisce la separazione delle responsabilità mantenendo i contenuti collocati insieme. Un file di contenuto può essere per-locale o multilingue.
157
+ 2. **Elaborazione:** Intlayer esegue uno step di build per elaborare la logica JS, gestire i fallback per traduzioni mancanti, generare i tipi TypeScript, gestire contenuti duplicati, recuperare contenuti dal tuo CMS e altro.
158
+ 3. **Pulizia:** Quando la tua app viene buildata, Intlayer elimina i contenuti non utilizzati (un po' come Tailwind gestisce le tue classi) sostituendo il contenuto come segue:
159
+
160
+ **Dichiarazione:**
161
+
162
+ ```tsx
163
+ // src/MyComponent.tsx
164
+ export const MyComponent = () => {
165
+ const content = useIntlayer("my-key");
166
+ return <h1>{content.title}</h1>;
167
+ };
168
+ ```
169
+
170
+ ```tsx
171
+ // src/myComponent.content.ts
172
+ export const {
173
+ key: "my-key",
174
+ content: t({
175
+ it: { title: "Il mio titolo" },
176
+ en: { title: "My title" },
177
+ fr: { title: "Mon titre" }
178
+ })
179
+ }
180
+
181
+ ```
182
+
183
+ **Elaborazione:** Intlayer costruisce il dizionario basato sul file `.content` e genera:
184
+
185
+ ```json5
186
+ // .intlayer/dynamic_dictionary/en/my-key.json
187
+ {
188
+ "key": "my-key",
189
+ "content": { "title": "My title" },
190
+ }
191
+ ```
192
+
193
+ **Sostituzione:** Intlayer trasforma il tuo componente durante la fase di build dell'applicazione.
194
+
195
+ **- Modalità di importazione statica:**
196
+
197
+ ```tsx
198
+ // Rappresentazione del componente in sintassi simile a JSX
199
+ export const MyComponent = () => {
200
+ const content = useDictionary({
201
+ key: "my-key",
202
+ content: {
203
+ nodeType: "translation",
204
+ translation: {
205
+ en: { title: "My title" },
206
+ fr: { title: "Mon titre" },
207
+ },
208
+ },
209
+ });
210
+
211
+ return <h1>{content.title}</h1>;
212
+ };
213
+ ```
214
+
215
+ **- Modalità di importazione dinamica:**
216
+
217
+ ```tsx
218
+ // Rappresentazione del componente in sintassi simile a JSX
219
+ export const MyComponent = () => {
220
+ const content = useDictionaryAsync({
221
+ en: () =>
222
+ import(".intlayer/dynamic_dictionary/en/my-key.json", {
223
+ with: { type: "json" },
224
+ }).then((mod) => mod.default),
225
+ // Lo stesso per altre lingue
226
+ });
227
+
228
+ return <h1>{content.title}</h1>;
229
+ };
230
+ ```
231
+
232
+ > `useDictionaryAsync` utilizza un meccanismo simile a Suspense per caricare il JSON localizzato solo quando necessario.
233
+
234
+ **Vantaggi principali di questo approccio per componente:**
235
+
236
+ - Mantenere la dichiarazione del contenuto vicino ai componenti consente una migliore manutenibilità (es. spostare un componente in un'altra app o in un design system. Eliminando la cartella del componente si rimuovono anche i contenuti correlati, come probabilmente già fai per i file `.test`, `.stories`)
237
+
238
+ - Un approccio per componente evita che gli agenti AI debbano saltare tra tutti i tuoi file. Tratta tutte le traduzioni in un unico posto, limitando la complessità del compito e la quantità di token utilizzati.
239
+
240
+ ### Limitazioni
241
+
242
+ Naturalmente, questo approccio comporta dei compromessi:
243
+
244
+ - È più difficile connettersi ad altri sistemi di l10n e a tooling aggiuntivo.
245
+ - Sei vincolato (cosa che è praticamente già il caso con qualsiasi soluzione i18n a causa della loro sintassi specifica).
246
+
247
+ Per questo motivo Intlayer cerca di fornire un set completo di strumenti per l'i18n (100% gratuito e OSS), inclusa la traduzione AI usando il tuo AI Provider e le tue API keys. Intlayer fornisce anche tooling per sincronizzare i tuoi JSON, funzionando come formatter di messaggi tipo ICU / vue-i18n / i18next per mappare il contenuto nei loro formati specifici.