@intlayer/docs 7.3.2 → 7.3.4
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/compiler_vs_declarative_i18n.md +137 -54
- package/blog/de/compiler_vs_declarative_i18n.md +131 -48
- package/blog/en/compiler_vs_declarative_i18n.md +112 -27
- package/blog/en-GB/compiler_vs_declarative_i18n.md +110 -27
- package/blog/es/compiler_vs_declarative_i18n.md +128 -45
- package/blog/fr/compiler_vs_declarative_i18n.md +133 -50
- package/blog/hi/compiler_vs_declarative_i18n.md +136 -53
- package/blog/id/compiler_vs_declarative_i18n.md +124 -41
- package/blog/it/compiler_vs_declarative_i18n.md +130 -47
- package/blog/ja/compiler_vs_declarative_i18n.md +140 -57
- package/blog/ko/compiler_vs_declarative_i18n.md +134 -51
- package/blog/pl/compiler_vs_declarative_i18n.md +134 -51
- package/blog/pt/compiler_vs_declarative_i18n.md +128 -45
- package/blog/ru/compiler_vs_declarative_i18n.md +135 -52
- package/blog/tr/compiler_vs_declarative_i18n.md +131 -48
- package/blog/vi/compiler_vs_declarative_i18n.md +136 -53
- package/blog/zh/compiler_vs_declarative_i18n.md +132 -49
- package/docs/en/interest_of_intlayer.md +4 -0
- package/docs/en/per_locale_file.md +98 -77
- package/package.json +6 -6
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
createdAt: 2025-11-24
|
|
3
3
|
updatedAt: 2025-11-24
|
|
4
4
|
title: Kompilator kontra deklaratywne i18n
|
|
5
|
-
description: Eksploracja kompromisów architektonicznych między "magiczna" internacjonalizacją opartą na kompilatorze a
|
|
5
|
+
description: Eksploracja kompromisów architektonicznych między "magiczna" internacjonalizacją opartą na kompilatorze a eksplicytnym, deklaratywnym zarządzaniem treścią.
|
|
6
6
|
keywords:
|
|
7
7
|
- Intlayer
|
|
8
8
|
- Internacjonalizacja
|
|
@@ -20,37 +20,69 @@ slugs:
|
|
|
20
20
|
|
|
21
21
|
# Argumenty za i przeciw internacjonalizacji opartej na kompilatorze
|
|
22
22
|
|
|
23
|
-
Jeśli
|
|
23
|
+
Jeśli budujesz aplikacje webowe od ponad dekady, wiesz, że internacjonalizacja (i18n) zawsze była punktem zapalnym. Często jest to zadanie, którego nikt nie chce wykonywać — wyciąganie stringów, zarządzanie plikami JSON i martwienie się o zasady pluralizacji.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Niedawno pojawiła się nowa fala **narzędzi i18n opartych na kompilatorze**, obiecujących, że ta uciążliwość zniknie. Oferta jest kusząca: **Po prostu pisz tekst w swoich komponentach, a narzędzie budujące zajmie się resztą.** Bez kluczy, bez importów, po prostu magia.
|
|
26
26
|
|
|
27
27
|
Ale jak to bywa ze wszystkimi abstrakcjami w inżynierii oprogramowania, magia ma swoją cenę.
|
|
28
28
|
|
|
29
|
-
W tym wpisie na blogu
|
|
29
|
+
W tym wpisie na blogu przeanalizujemy przejście od bibliotek deklaratywnych do podejść opartych na kompilatorze, ukryte długi architektoniczne, które wprowadzają, oraz dlaczego „nudny" sposób może nadal być najlepszym rozwiązaniem dla profesjonalnych aplikacji.
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Spis treści
|
|
32
|
+
|
|
33
|
+
<TOC/>
|
|
34
|
+
|
|
35
|
+
## Krótka historia internacjonalizacji
|
|
32
36
|
|
|
33
37
|
Aby zrozumieć, gdzie jesteśmy, musimy spojrzeć wstecz, skąd zaczęliśmy.
|
|
34
38
|
|
|
35
|
-
Około 2011–2012 krajobraz JavaScript wyglądał zupełnie inaczej. Bundlery
|
|
39
|
+
Około 2011–2012 krajobraz JavaScript wyglądał zupełnie inaczej. Bundlery, jakie znamy dzisiaj (Webpack, Vite), nie istniały lub były na bardzo wczesnym etapie rozwoju. Sklejaliśmy skrypty bezpośrednio w przeglądarce. W tym okresie powstały biblioteki takie jak **i18next**.
|
|
36
40
|
|
|
37
|
-
Rozwiązały one problem w jedyny możliwy wtedy sposób: **Słowniki w czasie wykonywania
|
|
41
|
+
Rozwiązały one problem w jedyny możliwy wtedy sposób: **Słowniki w czasie wykonywania**. Ładowało się ogromny obiekt JSON do pamięci, a funkcja wyszukiwała klucze na bieżąco. Było to niezawodne, jawne i działało wszędzie.
|
|
38
42
|
|
|
39
43
|
Przenieśmy się do dziś. Mamy potężne kompilatory (SWC, bundlery oparte na Rust), które potrafią analizować Abstrakcyjne Drzewa Składniowe (AST) w ciągu milisekund. Ta moc dała początek nowemu pomysłowi: _Dlaczego ręcznie zarządzamy kluczami? Dlaczego kompilator nie może po prostu zobaczyć tekstu "Hello World" i zamienić go za nas?_
|
|
40
44
|
|
|
41
45
|
Tak narodziło się i18n oparte na kompilatorze.
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
> **Przykład i18n opartego na kompilatorze:**
|
|
48
|
+
>
|
|
49
|
+
> - Paraglide (Moduły poddane tree-shakingowi, które kompilują każdą wiadomość do małej funkcji ESM, dzięki czemu bundlery mogą automatycznie usuwać nieużywane lokalizacje i klucze. Importujesz wiadomości jako funkcje zamiast wyszukiwać je po kluczach tekstowych.)
|
|
50
|
+
> - LinguiJS (Kompilator makr do funkcji, który przepisuje makra wiadomości, takie jak `<Trans>`, na zwykłe wywołania funkcji JS podczas budowania. Otrzymujesz składnię ICU/MessageFormat z bardzo małym narzutem w czasie wykonywania.)
|
|
51
|
+
> - Lingo.dev (Skupia się na automatyzacji procesu lokalizacji poprzez wstrzykiwanie przetłumaczonej zawartości bezpośrednio podczas budowania aplikacji React. Może automatycznie generować tłumaczenia za pomocą AI i integrować się bezpośrednio z CI/CD.)
|
|
52
|
+
> - Wuchale (Preprocesor skoncentrowany na Svelte, który wyodrębnia tekst inline w plikach .svelte i kompiluje go do funkcji tłumaczeniowych bez dodatkowych wrapperów. Unika kluczy tekstowych i całkowicie oddziela logikę ekstrakcji treści od głównego środowiska uruchomieniowego aplikacji.)
|
|
53
|
+
> - Intlayer (Kompilator / CLI do ekstrakcji, który analizuje twoje komponenty, generuje typowane słowniki i opcjonalnie może przepisać kod, aby używać jawnej zawartości Intlayer. Celem jest wykorzystanie kompilatora dla szybkości, zachowując deklaratywne, niezależne od frameworka jądro.)
|
|
54
|
+
|
|
55
|
+
> **Przykład deklaratywnego i18n:**
|
|
56
|
+
>
|
|
57
|
+
> - i18next / react-i18next / next-i18next (Dojrzały standard branżowy wykorzystujący słowniki JSON w czasie wykonywania oraz rozbudowany ekosystem wtyczek)
|
|
58
|
+
> - react-intl (Część biblioteki FormatJS, skupiająca się na standardowej składni komunikatów ICU oraz ścisłym formatowaniu danych)
|
|
59
|
+
> - next-intl (Specjalnie zoptymalizowany dla Next.js z integracją dla App Router i React Server Components)
|
|
60
|
+
> - vue-i18n / @nuxt/i18n (Standardowe rozwiązanie ekosystemu Vue oferujące bloki tłumaczeń na poziomie komponentów oraz ścisłą integrację reaktywności)
|
|
61
|
+
> - svelte-i18n (Lekka nakładka na Svelte stores dla reaktywnych tłumaczeń w czasie wykonywania)
|
|
62
|
+
> - angular-translate (Przestarzała biblioteka dynamicznych tłumaczeń oparta na wyszukiwaniu kluczy w czasie wykonywania zamiast scalania podczas budowania)
|
|
63
|
+
> - angular-i18n (Natywne podejście Angulara, działające ahead-of-time, scalające pliki XLIFF bezpośrednio z szablonami podczas budowania)
|
|
64
|
+
> - Tolgee (Łączy deklaratywny kod z SDK w kontekście, umożliwiając edycję "kliknij, aby przetłumaczyć" bezpośrednio w interfejsie użytkownika)
|
|
65
|
+
> - Intlayer (Podejście per-komponent, wykorzystujące pliki deklaracji treści umożliwiające natywne tree-shaking oraz walidację TypeScript)
|
|
66
|
+
|
|
67
|
+
## Kompilator Intlayer
|
|
68
|
+
|
|
69
|
+
Chociaż **Intlayer** jest rozwiązaniem, które zasadniczo zachęca do **deklaratywnego podejścia** do Twoich treści, zawiera kompilator, który pomaga przyspieszyć rozwój lub ułatwić szybkie prototypowanie.
|
|
70
|
+
|
|
71
|
+
Kompilator Intlayer przeszukuje AST (Abstract Syntax Tree) Twoich komponentów React, Vue lub Svelte, a także innych plików JavaScript/TypeScript. Jego rolą jest wykrywanie zakodowanych na stałe łańcuchów znaków i wyodrębnianie ich do dedykowanych deklaracji `.content`.
|
|
72
|
+
|
|
73
|
+
> Aby uzyskać więcej szczegółów, zapoznaj się z dokumentacją: [Intlayer Compiler Docs](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/compiler.md)
|
|
74
|
+
|
|
75
|
+
## Urok Kompilatora (Podejście "Magiczne")
|
|
44
76
|
|
|
45
|
-
|
|
77
|
+
Jest powód, dla którego to nowe podejście zyskuje na popularności. Dla dewelopera doświadczenie jest niesamowite.
|
|
46
78
|
|
|
47
|
-
### 1. Szybkość i
|
|
79
|
+
### 1. Szybkość i "Flow"
|
|
48
80
|
|
|
49
|
-
Kiedy jesteś w strefie, zatrzymanie się,
|
|
81
|
+
Kiedy jesteś w strefie, zatrzymanie się, aby wymyślić semantyczną nazwę zmiennej (`home_hero_title_v2`), przerywa twój flow. Przy podejściu kompilatora wpisujesz `<p>Welcome back</p>` i idziesz dalej. Tarcie jest zerowe.
|
|
50
82
|
|
|
51
|
-
### 2. Misja Ratunkowa dla Dziedzictwa
|
|
83
|
+
### 2. Misja Ratunkowa dla Dziedzictwa (Legacy)
|
|
52
84
|
|
|
53
|
-
Wyobraź sobie, że dziedziczysz ogromną bazę kodu z 5000
|
|
85
|
+
Wyobraź sobie, że dziedziczysz ogromną bazę kodu z 5000 komponentami i zerowymi tłumaczeniami. Dostosowanie tego do ręcznego systemu opartego na kluczach to koszmar trwający miesiącami. Narzędzie oparte na kompilatorze działa jako strategia ratunkowa, natychmiast wyciągając tysiące ciągów znaków bez konieczności ręcznego dotykania pojedynczego pliku.
|
|
54
86
|
|
|
55
87
|
### 3. Era AI
|
|
56
88
|
|
|
@@ -59,79 +91,130 @@ To nowoczesna korzyść, której nie powinniśmy pomijać. Asystenci kodowania A
|
|
|
59
91
|
- **Deklaratywne:** Musisz przepisać wynik AI, aby zastąpić tekst kluczami.
|
|
60
92
|
- **Kompilator:** Kopiujesz i wklejasz kod AI i po prostu działa.
|
|
61
93
|
|
|
62
|
-
## Sprawdzenie
|
|
94
|
+
## Sprawdzenie rzeczywistości: Dlaczego „magia” jest niebezpieczna
|
|
95
|
+
|
|
96
|
+
Chociaż „magia” jest kusząca, abstrakcja przecieka. Poleganie na narzędziu do budowania, które ma rozumieć intencje człowieka, wprowadza architektoniczną kruchość.
|
|
97
|
+
|
|
98
|
+
### Kruchość heurystyczna (gra w zgadywanie)
|
|
99
|
+
|
|
100
|
+
Kompilator musi zgadywać, co jest treścią, a co kodem. Prowadzi to do sytuacji brzegowych, w których kończysz na „walce” z narzędziem.
|
|
101
|
+
|
|
102
|
+
Rozważ te scenariusze:
|
|
103
|
+
|
|
104
|
+
- Czy `<span className="active"></span>` jest wyodrębniane? (To jest string, ale prawdopodobnie klasa).
|
|
105
|
+
- Czy `<span status="pending"></span>` jest wyodrębniane? (To jest wartość propsa).
|
|
106
|
+
- Czy `<span>{"Hello World"}</span>` jest wyodrębniane? (To jest wyrażenie JS).
|
|
107
|
+
- Czy `<span>Hello {name}. How are you?</span>` jest wyodrębniane? (Interpolacja jest skomplikowana).
|
|
108
|
+
- Czy `<span aria-label="Image of cat"></span>` jest wyodrębniane? (Atrybuty dostępności wymagają tłumaczenia).
|
|
109
|
+
- Czy `<span data-testid="my-element"></span>` jest wyodrębniany? (ID testów NIE powinny być tłumaczone).
|
|
110
|
+
- Czy `<MyComponent errorMessage="An error occurred" />` jest wyodrębniany?
|
|
111
|
+
- Czy `<p>This is a paragraph{" "}\n containing multiple lines</p>` jest wyodrębniany?
|
|
112
|
+
- Czy wynik funkcji `<p>{getStatusMessage()}</p>` jest wyodrębniany?
|
|
113
|
+
- Czy `<div>{isLoading ? "The page is loading" : <MyComponent/>} </div>` jest wyodrębniany?
|
|
114
|
+
- Czy ID produktu takie jak `<span>AX-99</span>` jest wyodrębniany?
|
|
115
|
+
|
|
116
|
+
Nieuchronnie kończysz na dodawaniu specyficznych komentarzy (np. `// ignore-translation` lub specyficznych atrybutów jak `data-compiler-ignore="true"`) aby zapobiec łamaniu logiki Twojej aplikacji.
|
|
117
|
+
|
|
118
|
+
### Jak Intlayer radzi sobie z tą złożonością?
|
|
63
119
|
|
|
64
|
-
|
|
120
|
+
Intlayer używa podejścia mieszanego do wykrywania, czy pole powinno zostać wyodrębnione do tłumaczenia, starając się zminimalizować fałszywe trafienia:
|
|
65
121
|
|
|
66
|
-
|
|
122
|
+
1. **Analiza AST:** Sprawdza typ elementu (np. rozróżnia `reactNode`, `label` lub właściwość `title`).
|
|
123
|
+
2. **Rozpoznawanie wzorców:** Wykrywa, czy ciąg znaków jest napisany wielką literą lub zawiera spacje, co sugeruje, że jest to prawdopodobnie tekst czytelny dla człowieka, a nie identyfikator kodu.
|
|
67
124
|
|
|
68
|
-
|
|
125
|
+
### Twardy limit danych dynamicznych
|
|
69
126
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- Czy `<MyComponent errorMessage="An error occurred" />` jest tłumaczone?
|
|
73
|
-
- Czy identyfikator produktu taki jak `"AX-99"` jest tłumaczony?
|
|
127
|
+
Ekstrakcja przez kompilator opiera się na **analizie statycznej**. Musi zobaczyć dosłowny ciąg znaków w Twoim kodzie, aby wygenerować stabilny identyfikator.
|
|
128
|
+
Jeśli Twoje API zwraca ciąg znaków z kodem błędu, taki jak `server_error`, nie możesz go przetłumaczyć za pomocą kompilatora, ponieważ kompilator nie zna tego ciągu w czasie kompilacji. Jesteś zmuszony do zbudowania drugorzędnego systemu działającego wyłącznie w czasie wykonywania, przeznaczonego tylko dla danych dynamicznych.
|
|
74
129
|
|
|
75
|
-
|
|
130
|
+
### Brak dzielenia na fragmenty
|
|
76
131
|
|
|
77
|
-
|
|
132
|
+
Niektóre kompilatory nie dzielą tłumaczeń na fragmenty na poziomie stron. Jeśli Twój kompilator generuje duży plik JSON na język (np. `./lang/en.json`, `./lang/fr.json` itd.), prawdopodobnie załadujesz zawartość ze wszystkich stron podczas odwiedzania jednej strony. Dodatkowo każdy komponent korzystający z Twoich treści zostanie prawdopodobnie zainicjowany z dużo większą ilością danych niż to konieczne, co może powodować problemy z wydajnością.
|
|
78
133
|
|
|
79
|
-
|
|
80
|
-
Jeśli twoje API zwraca kod błędu w postaci ciągu znaków, np. `server_error`, nie możesz go przetłumaczyć za pomocą kompilatora, ponieważ kompilator nie wie o istnieniu tego ciągu w czasie budowania. Jesteś zmuszony do stworzenia drugiego systemu działającego tylko w czasie wykonywania, przeznaczonego wyłącznie dla danych dynamicznych.
|
|
134
|
+
Bądź również ostrożny przy dynamicznym ładowaniu tłumaczeń. Jeśli tego nie zrobisz, załadujesz zawartość dla wszystkich języków oprócz bieżącego.
|
|
81
135
|
|
|
82
|
-
|
|
136
|
+
> Aby zobrazować problem, rozważ stronę z 10 podstronami i 10 językami (wszystkie w 100% unikalne). Załadujesz zawartość dla dodatkowych 99 podstron (10 × 10 - 1).
|
|
83
137
|
|
|
84
|
-
|
|
138
|
+
### „Eksplozja chunków” i wodospady sieciowe
|
|
85
139
|
|
|
86
|
-
|
|
140
|
+
Aby rozwiązać problem chunkowania, niektóre rozwiązania oferują chunkowanie per komponent, a nawet per klucz. Jednak problem jest tylko częściowo rozwiązany. Głównym argumentem tych rozwiązań jest często stwierdzenie „Twoja zawartość jest tree-shaken”.
|
|
87
141
|
|
|
88
|
-
|
|
142
|
+
Rzeczywiście, jeśli ładujesz zawartość statycznie, twoje rozwiązanie usunie nieużywaną zawartość (tree-shake), ale i tak skończysz z zawartością ze wszystkich języków załadowaną wraz z aplikacją.
|
|
89
143
|
|
|
90
|
-
|
|
144
|
+
Więc dlaczego nie ładować go dynamicznie? Tak, w takim przypadku załadujesz więcej treści niż jest to konieczne, ale nie jest to pozbawione kompromisów.
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
Dynamiczne ładowanie treści izoluje każdą część treści w osobnym kawałku (chunku), który będzie ładowany tylko wtedy, gdy komponent zostanie wyrenderowany. Oznacza to, że wykonasz jedno żądanie HTTP na każdy blok tekstu. 1000 bloków tekstu na Twojej stronie? → 1000 żądań HTTP do Twoich serwerów. Aby ograniczyć szkody i zoptymalizować czas pierwszego renderowania aplikacji, będziesz musiał wstawić wiele granic Suspense lub Skeleton Loaderów.
|
|
147
|
+
|
|
148
|
+
> Uwaga: Nawet z Next.js i SSR, Twoje komponenty będą nadal hydradowane po załadowaniu, więc żądania HTTP nadal będą wykonywane.
|
|
149
|
+
|
|
150
|
+
Rozwiązanie? Przyjęcie rozwiązania, które pozwala deklarować zakresowe deklaracje treści, tak jak robią to `i18next`, `next-intl` lub `intlayer`.
|
|
151
|
+
|
|
152
|
+
> Uwaga: `i18next` i `next-intl` wymagają ręcznego zarządzania importami przestrzeni nazw / wiadomości dla każdej strony, aby zoptymalizować rozmiar pakietu. Powinieneś użyć analizatora pakietów, takiego jak `rollup-plugin-visualizer` (vite), `@next/bundle-analyzer` (next.js) lub `webpack-bundle-analyzer` (React CRA / Angular / itp.), aby wykryć, czy nie zaśmiecasz swojego pakietu nieużywanymi tłumaczeniami.
|
|
153
|
+
|
|
154
|
+
### Obciążenie wydajności w czasie działania
|
|
155
|
+
|
|
156
|
+
Aby uczynić tłumaczenia reaktywnymi (tak, aby aktualizowały się natychmiast po zmianie języka), kompilator często wstrzykuje hooki zarządzania stanem do każdego komponentu.
|
|
157
|
+
|
|
158
|
+
- **Koszt:** Jeśli renderujesz listę 5 000 elementów, inicjujesz 5 000 hooków `useState` i `useEffect` wyłącznie dla tekstu. React musi zidentyfikować i ponownie wyrenderować wszystkich 5 000 konsumentów jednocześnie. Powoduje to ogromne zablokowanie "Głównego Wątku", zamrażając interfejs użytkownika podczas przełączania. Zużywa to pamięć i cykle CPU, które oszczędzają biblioteki deklaratywne (które zazwyczaj używają pojedynczego dostawcy Context).
|
|
159
|
+
|
|
160
|
+
> Uwaga: problematyka jest podobna w innych frameworkach niż React.
|
|
93
161
|
|
|
94
162
|
## Pułapka: Vendor Lock-in
|
|
95
163
|
|
|
96
|
-
|
|
164
|
+
Uważaj, aby wybrać rozwiązanie i18n, które pozwala na ekstrakcję lub migrację kluczy tłumaczeń.
|
|
97
165
|
|
|
98
|
-
W
|
|
166
|
+
W przypadku biblioteki deklaratywnej, Twój kod źródłowy wyraźnie zawiera zamiar tłumaczenia: to są Twoje klucze i masz nad nimi kontrolę. Jeśli chcesz zmienić bibliotekę, zazwyczaj wystarczy zaktualizować import.
|
|
99
167
|
|
|
100
|
-
W podejściu
|
|
101
|
-
Jeśli ta biblioteka przestanie być utrzymywana lub jeśli ją przerosniesz, utkniesz. Nie możesz łatwo „wyjść” z niej, ponieważ nie masz żadnych kluczy tłumaczeń w swoim kodzie źródłowym. Musiałbyś ręcznie przepisać całą aplikację, aby przejść na inne rozwiązanie.
|
|
168
|
+
W podejściu kompilatora, Twój kod źródłowy może być po prostu zwykłym tekstem angielskim, bez śladu logiki tłumaczenia: wszystko jest ukryte w konfiguracji narzędzia budującego. Jeśli ten plugin przestanie być utrzymywany lub chcesz zmienić rozwiązanie, możesz utknąć. Nie ma łatwego sposobu na „wyjście”: w Twoim kodzie nie ma użytecznych kluczy i może być konieczne ponowne wygenerowanie wszystkich tłumaczeń dla nowej biblioteki.
|
|
102
169
|
|
|
103
|
-
|
|
170
|
+
Niektóre rozwiązania oferują również usługi generowania tłumaczeń. Brak kredytów? Brak tłumaczeń.
|
|
104
171
|
|
|
105
|
-
|
|
172
|
+
Kompilatory często haszują tekst (np. `"Hello World"` -> `x7f2a`). Twoje pliki tłumaczeń wyglądają wtedy tak: `{ "x7f2a": "Hola Mundo" }`. Pułapka: jeśli zmienisz bibliotekę, nowa biblioteka widzi `"Hello World"` i szuka tego klucza. Nie znajdzie go, ponieważ Twój plik tłumaczeń jest pełen haszy (`x7f2a`).
|
|
106
173
|
|
|
107
|
-
|
|
174
|
+
### Uzależnienie od Platformy
|
|
175
|
+
|
|
176
|
+
Wybierając podejście oparte na kompilatorze, zamykasz się w podstawowej platformie. Na przykład, niektóre kompilatory nie są dostępne dla wszystkich bundlerów (takich jak Vite, Turbopack lub Metro). To może utrudnić przyszłe migracje i możesz potrzebować przyjąć wiele rozwiązań, aby pokryć wszystkie swoje aplikacje.
|
|
177
|
+
|
|
178
|
+
## Druga Strona: Ryzyka Podejścia Deklaratywnego
|
|
179
|
+
|
|
180
|
+
Aby być sprawiedliwym, tradycyjny sposób deklaratywny też nie jest idealny. Ma swoje własne "pułapki".
|
|
181
|
+
|
|
182
|
+
1. **Piekło przestrzeni nazw:** Często musisz ręcznie zarządzać, które pliki JSON ładować (`common.json`, `dashboard.json`, `footer.json`). Jeśli zapomnisz o którymś, użytkownik zobaczy surowe klucze.
|
|
108
183
|
2. **Nadmierne pobieranie:** Bez ostrożnej konfiguracji bardzo łatwo jest przypadkowo załadować _wszystkie_ klucze tłumaczeń dla _wszystkich_ stron podczas początkowego ładowania, co powoduje nadmierne powiększenie rozmiaru paczki.
|
|
109
|
-
3. **
|
|
184
|
+
3. **Dryf synchronizacji:** Często zdarza się, że klucze pozostają w pliku JSON długo po usunięciu komponentu, który ich używał. Twoje pliki tłumaczeń rosną w nieskończoność, wypełnione "zombie kluczami".
|
|
110
185
|
|
|
111
|
-
## Środkowa
|
|
186
|
+
## Środkowa droga Intlayer
|
|
112
187
|
|
|
113
|
-
To właśnie tutaj narzędzia takie jak **Intlayer** próbują wprowadzać innowacje. Intlayer rozumie, że
|
|
188
|
+
To właśnie tutaj narzędzia takie jak **Intlayer** próbują wprowadzać innowacje. Intlayer rozumie, że choć kompilatory są potężne, to ukryta magia jest niebezpieczna.
|
|
114
189
|
|
|
115
|
-
Intlayer oferuje
|
|
190
|
+
Intlayer oferuje podejście mieszane, pozwalające korzystać z zalet obu metod: deklaratywnego zarządzania treścią, które jest również kompatybilne z jego kompilatorem, co oszczędza czas programowania.
|
|
191
|
+
|
|
192
|
+
A nawet jeśli nie używasz kompilatora Intlayer, Intlayer oferuje polecenie `transform` (dostępne również za pomocą rozszerzenia VSCode). Zamiast wykonywać magię w ukrytym kroku budowania, faktycznie może **przepisać kod twojego komponentu**. Skanuje twój tekst i zastępuje go jawnie zadeklarowanymi treściami w twojej bazie kodu.
|
|
116
193
|
|
|
117
194
|
Daje to najlepsze z obu światów:
|
|
118
195
|
|
|
119
196
|
1. **Szczegółowość:** Trzymasz tłumaczenia blisko swoich komponentów (poprawiając modularność i tree-shaking).
|
|
120
|
-
2. **Bezpieczeństwo:** Tłumaczenie staje się jawnie zapisanym kodem, a nie ukrytą magią podczas
|
|
121
|
-
3. **Brak uzależnienia:** Ponieważ kod jest przekształcany
|
|
197
|
+
2. **Bezpieczeństwo:** Tłumaczenie staje się jawnie zapisanym kodem, a nie ukrytą magią podczas budowania.
|
|
198
|
+
3. **Brak uzależnienia:** Ponieważ kod jest przekształcany w deklaratywną strukturę w twoim repozytorium, możesz łatwo nacisnąć tabulator lub użyć copilot w IDE, aby generować deklaracje treści, nie ukrywając logiki w wtyczce webpack.
|
|
122
199
|
|
|
123
|
-
##
|
|
200
|
+
## Wnioski
|
|
124
201
|
|
|
125
202
|
Więc, którą opcję powinieneś wybrać?
|
|
126
203
|
|
|
127
|
-
**Jeśli
|
|
128
|
-
Podejście oparte na kompilatorze jest dobrym wyborem. Pozwala
|
|
204
|
+
**Jeśli tworzysz MVP lub chcesz działać szybko:**
|
|
205
|
+
Podejście oparte na kompilatorze jest dobrym wyborem. Pozwala na niezwykle szybkie działanie. Nie musisz się martwić o strukturę plików czy klucze. Po prostu budujesz. Dług techniczny to problem dla „Przyszłego Ciebie”.
|
|
206
|
+
|
|
207
|
+
**Jeśli jesteś Junior Developerem lub nie zależy Ci na optymalizacji:**
|
|
208
|
+
Jeśli chcesz jak najmniej ręcznego zarządzania, podejście oparte na kompilatorze jest prawdopodobnie najlepsze. Nie będziesz musiał samodzielnie obsługiwać kluczy czy plików tłumaczeń — po prostu piszesz tekst, a kompilator automatyzuje resztę. To zmniejsza nakład pracy przy konfiguracji i typowe błędy i18n związane z ręcznymi krokami.
|
|
209
|
+
|
|
210
|
+
**Jeśli internacjonalizujesz istniejący projekt, który już zawiera tysiące komponentów do refaktoryzacji:**
|
|
211
|
+
Podejście oparte na kompilatorze może być tutaj pragmatycznym wyborem. Początkowa faza ekstrakcji może zaoszczędzić tygodnie lub miesiące ręcznej pracy. Jednak rozważ użycie narzędzia takiego jak polecenie `transform` Intlayer, które może wyodrębnić ciągi znaków i przekształcić je w jawne deklaracje treści deklaratywnej. Daje to szybkość automatyzacji przy jednoczesnym zachowaniu bezpieczeństwa i przenośności podejścia deklaratywnego. Otrzymujesz to, co najlepsze z obu światów: szybką początkową migrację bez długoterminowego długu architektonicznego.
|
|
129
212
|
|
|
130
|
-
**Jeśli tworzysz profesjonalną aplikację klasy
|
|
213
|
+
**Jeśli tworzysz profesjonalną aplikację klasy Enterprise:**
|
|
131
214
|
Magia zazwyczaj jest złym pomysłem. Potrzebujesz kontroli.
|
|
132
215
|
|
|
133
216
|
- Musisz obsługiwać dynamiczne dane z backendów.
|
|
134
|
-
- Musisz zapewnić wydajność na urządzeniach o
|
|
135
|
-
- Musisz
|
|
217
|
+
- Musisz zapewnić wydajność na urządzeniach o niskiej wydajności (unikając eksplozji hooków).
|
|
218
|
+
- Musisz zapewnić, że nie zostaniesz na stałe związany z konkretnym narzędziem do budowania.
|
|
136
219
|
|
|
137
|
-
|
|
220
|
+
Dla profesjonalnych aplikacji **Deklaratywne Zarządzanie Treścią** (takie jak Intlayer lub sprawdzone biblioteki) pozostaje złotym standardem. Oddziela to Twoje obszary odpowiedzialności, utrzymuje architekturę w czystości i zapewnia, że zdolność Twojej aplikacji do obsługi wielu języków nie zależy od „czarnej skrzynki” kompilatora, który zgaduje Twoje intencje.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
createdAt: 2025-11-24
|
|
3
3
|
updatedAt: 2025-11-24
|
|
4
4
|
title: Compilador vs. i18n Declarativo
|
|
5
|
-
description: Explorando as
|
|
5
|
+
description: Explorando as compensações arquitetônicas entre a internacionalização "mágica" baseada em compilador e o gerenciamento explícito e declarativo de conteúdo.
|
|
6
6
|
keywords:
|
|
7
7
|
- Intlayer
|
|
8
8
|
- Internacionalização
|
|
@@ -20,15 +20,19 @@ slugs:
|
|
|
20
20
|
|
|
21
21
|
# O Caso a Favor e Contra a i18n Baseada em Compilador
|
|
22
22
|
|
|
23
|
-
Se você tem construído aplicações web por mais de uma década, sabe que a Internacionalização (i18n) sempre foi um ponto de atrito. Frequentemente é a tarefa que ninguém quer fazer — extrair strings, gerenciar arquivos JSON e se preocupar com regras de pluralização.
|
|
23
|
+
Se você tem construído aplicações web por mais de uma década, sabe que a Internacionalização (i18n) sempre foi um ponto de atrito. Frequentemente, é a tarefa que ninguém quer fazer — extrair strings, gerenciar arquivos JSON e se preocupar com regras de pluralização.
|
|
24
24
|
|
|
25
|
-
Recentemente, uma nova onda de ferramentas de i18n "baseadas em compilador" surgiu, prometendo fazer essa dor desaparecer. A proposta é sedutora: **Basta escrever o texto nos seus componentes e deixar a ferramenta de build cuidar do resto.** Sem chaves, sem imports, apenas
|
|
25
|
+
Recentemente, uma nova onda de ferramentas de i18n **"baseadas em compilador"** surgiu, prometendo fazer essa dor desaparecer. A proposta é sedutora: **Basta escrever o texto nos seus componentes e deixar a ferramenta de build cuidar do resto.** Sem chaves, sem imports, apenas mágica.
|
|
26
26
|
|
|
27
|
-
Mas, como em todas as abstrações na engenharia de software,
|
|
27
|
+
Mas, como em todas as abstrações na engenharia de software, mágica tem um preço.
|
|
28
28
|
|
|
29
|
-
Neste post do blog, exploraremos a
|
|
29
|
+
Neste post do blog, exploraremos a transição de bibliotecas declarativas para abordagens baseadas em compilador, as dívidas arquiteturais ocultas que elas introduzem e por que o jeito "chato" ainda pode ser o melhor para aplicações profissionais.
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Índice
|
|
32
|
+
|
|
33
|
+
<TOC/>
|
|
34
|
+
|
|
35
|
+
## Uma Breve História da Internacionalização
|
|
32
36
|
|
|
33
37
|
Para entender onde estamos, precisamos olhar para onde começamos.
|
|
34
38
|
|
|
@@ -36,21 +40,49 @@ Por volta de 2011–2012, o cenário do JavaScript era muito diferente. Bundlers
|
|
|
36
40
|
|
|
37
41
|
Elas resolveram o problema da única forma possível na época: **Dicionários em tempo de execução**. Você carregava um enorme objeto JSON na memória, e uma função buscava as chaves dinamicamente. Era confiável, explícito e funcionava em qualquer lugar.
|
|
38
42
|
|
|
39
|
-
Avançando para hoje. Temos compiladores poderosos (SWC, bundlers baseados em Rust) que conseguem analisar Árvores de Sintaxe Abstrata (AST) em milissegundos. Esse poder deu origem a uma nova ideia: _Por que
|
|
43
|
+
Avançando para hoje. Temos compiladores poderosos (SWC, bundlers baseados em Rust) que conseguem analisar Árvores de Sintaxe Abstrata (AST) em milissegundos. Esse poder deu origem a uma nova ideia: _Por que estamos gerenciando chaves manualmente? Por que o compilador não pode simplesmente ver o texto "Hello World" e substituí-lo para nós?_
|
|
40
44
|
|
|
41
45
|
Assim, nasceu o i18n baseado em compilador.
|
|
42
46
|
|
|
47
|
+
> **Exemplo de i18n baseado em compilador:**
|
|
48
|
+
>
|
|
49
|
+
> - Paraglide (Módulos tree-shaken que compilam cada mensagem em uma pequena função ESM para que os bundlers possam eliminar automaticamente locais e chaves não utilizados. Você importa mensagens como funções em vez de fazer buscas por chaves de string.)
|
|
50
|
+
> - LinguiJS (Compilador de macro para função que reescreve macros de mensagem como `<Trans>` em chamadas de função JS simples durante o build. Você obtém a sintaxe ICU/MessageFormat com uma pegada de runtime muito pequena.)
|
|
51
|
+
> - Lingo.dev (Foca em automatizar o pipeline de localização injetando conteúdo traduzido diretamente durante a construção da sua aplicação React. Pode gerar traduções automaticamente usando IA e integrar-se diretamente ao CI/CD.)
|
|
52
|
+
> - Wuchale (Pré-processador focado em Svelte que extrai texto inline em arquivos .svelte e compila em funções de tradução sem wrappers. Evita chaves de string e separa completamente a lógica de extração de conteúdo do runtime principal da aplicação.)
|
|
53
|
+
> - Intlayer (Compilador / CLI de extração que analisa seus componentes, gera dicionários tipados e pode opcionalmente reescrever o código para usar conteúdo explícito do Intlayer. O objetivo é usar o compilador para velocidade mantendo um núcleo declarativo e agnóstico ao framework.)
|
|
54
|
+
|
|
55
|
+
> **Exemplo de i18n declarativo:**
|
|
56
|
+
>
|
|
57
|
+
> - i18next / react-i18next / next-i18next (O padrão maduro da indústria que usa dicionários JSON em runtime e um extenso ecossistema de plugins)
|
|
58
|
+
> - react-intl (Parte da biblioteca FormatJS, focada na sintaxe padrão de mensagens ICU e formatação rigorosa de dados)
|
|
59
|
+
> - next-intl (Otimizado especificamente para Next.js com integração para o App Router e React Server Components)
|
|
60
|
+
> - vue-i18n / @nuxt/i18n (A solução padrão do ecossistema Vue que oferece blocos de tradução a nível de componente e integração estreita com reatividade)
|
|
61
|
+
> - svelte-i18n (Um wrapper leve em torno dos stores do Svelte para traduções reativas em tempo de execução)
|
|
62
|
+
> - angular-translate (A biblioteca legada de tradução dinâmica que depende de buscas por chaves em tempo de execução ao invés de mesclagem em tempo de build)
|
|
63
|
+
> - angular-i18n (A abordagem nativa do Angular, ahead-of-time, que mescla arquivos XLIFF diretamente nos templates durante a build)
|
|
64
|
+
> - Tolgee (Combina código declarativo com um SDK em contexto para edição "click-to-translate" diretamente na interface)
|
|
65
|
+
> - Intlayer (Abordagem por componente, usando arquivos de declarações de conteúdo que permitem tree-shaking nativo e validação TypeScript)
|
|
66
|
+
|
|
67
|
+
## O Compilador Intlayer
|
|
68
|
+
|
|
69
|
+
Embora o **Intlayer** seja uma solução que fundamentalmente incentiva uma **abordagem declarativa** para o seu conteúdo, ele inclui um compilador para ajudar a acelerar o desenvolvimento ou facilitar prototipagem rápida.
|
|
70
|
+
|
|
71
|
+
O compilador Intlayer percorre a AST (Abstract Syntax Tree) dos seus componentes React, Vue ou Svelte, assim como outros arquivos JavaScript/TypeScript. Seu papel é detectar strings hardcoded e extraí-las para declarações dedicadas `.content`.
|
|
72
|
+
|
|
73
|
+
> Para mais detalhes, consulte a documentação: [Documentação do Compilador Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/compiler.md)
|
|
74
|
+
|
|
43
75
|
## O Encanto do Compilador (A Abordagem "Mágica")
|
|
44
76
|
|
|
45
77
|
Há uma razão pela qual essa nova abordagem está em alta. Para um desenvolvedor, a experiência é incrível.
|
|
46
78
|
|
|
47
79
|
### 1. Velocidade e "Flow"
|
|
48
80
|
|
|
49
|
-
Quando você está concentrado, parar para pensar em um nome de variável (`home_hero_title_v2`) quebra seu fluxo. Com a abordagem do compilador, você digita `<p>Welcome back</p>` e continua. O atrito é zero.
|
|
81
|
+
Quando você está concentrado, parar para pensar em um nome de variável semântico (`home_hero_title_v2`) quebra seu fluxo. Com a abordagem do compilador, você digita `<p>Welcome back</p>` e continua. O atrito é zero.
|
|
50
82
|
|
|
51
83
|
### 2. A Missão de Resgate do Legado
|
|
52
84
|
|
|
53
|
-
Imagine herdar uma base de código enorme com 5.000 componentes e
|
|
85
|
+
Imagine herdar uma base de código enorme com 5.000 componentes e nenhuma tradução. Adaptar isso com um sistema manual baseado em chaves é um pesadelo que dura meses. Uma ferramenta baseada em compilador atua como uma estratégia de resgate, extraindo instantaneamente milhares de strings sem que você precise tocar em um único arquivo manualmente.
|
|
54
86
|
|
|
55
87
|
### 3. A Era da IA
|
|
56
88
|
|
|
@@ -59,79 +91,130 @@ Este é um benefício moderno que não devemos ignorar. Assistentes de codifica
|
|
|
59
91
|
- **Declarativo:** Você precisa reescrever a saída da IA para substituir o texto por chaves.
|
|
60
92
|
- **Compilador:** Você copia e cola o código da IA, e ele simplesmente funciona.
|
|
61
93
|
|
|
62
|
-
## A
|
|
94
|
+
## A Realidade: Por que a "Magia" é Perigosa
|
|
95
|
+
|
|
96
|
+
Embora a "mágica" seja atraente, a abstração apresenta vazamentos. Confiar em uma ferramenta de build para entender a intenção humana introduz fragilidade arquitetural.
|
|
97
|
+
|
|
98
|
+
### Fragilidade Heurística (O Jogo de Adivinhação)
|
|
99
|
+
|
|
100
|
+
O compilador precisa adivinhar o que é conteúdo e o que é código. Isso leva a casos extremos onde você acaba "lutando" contra a ferramenta.
|
|
101
|
+
|
|
102
|
+
Considere estes cenários:
|
|
103
|
+
|
|
104
|
+
- `<span className="active"></span>` é extraído? (É uma string, mas provavelmente uma classe).
|
|
105
|
+
- `<span status="pending"></span>` é extraído? (É um valor de prop).
|
|
106
|
+
- `<span>{"Hello World"}</span>` é extraído? (É uma expressão JS).
|
|
107
|
+
- `<span>Hello {name}. How are you?</span>` é extraído? (Interpolação é complexa).
|
|
108
|
+
- `<span aria-label="Image of cat"></span>` é extraído? (Atributos de acessibilidade precisam de tradução).
|
|
109
|
+
- O `<span data-testid="my-element"></span>` é extraído? (IDs de teste NÃO devem ser traduzidos).
|
|
110
|
+
- O `<MyComponent errorMessage="An error occurred" />` é extraído?
|
|
111
|
+
- O `<p>This is a paragraph{" "}\n containing multiple lines</p>` é extraído?
|
|
112
|
+
- O resultado da função `<p>{getStatusMessage()}</p>` é extraído?
|
|
113
|
+
- O `<div>{isLoading ? "The page is loading" : <MyComponent/>} </div>` é extraído?
|
|
114
|
+
- Um ID de produto como `<span>AX-99</span>` é extraído?
|
|
115
|
+
|
|
116
|
+
Inevitavelmente, você acaba adicionando comentários específicos (como `// ignore-translation`, ou props específicas como `data-compiler-ignore="true"`) para evitar que isso quebre a lógica da sua aplicação.
|
|
117
|
+
|
|
118
|
+
### Como o Intlayer lida com essa complexidade?
|
|
63
119
|
|
|
64
|
-
|
|
120
|
+
Intlayer utiliza uma abordagem mista para detectar se um campo deve ser extraído para tradução, tentando minimizar falsos positivos:
|
|
65
121
|
|
|
66
|
-
|
|
122
|
+
1. **Análise AST:** Verifica o tipo do elemento (por exemplo, distinguindo entre um `reactNode`, um `label` ou uma prop `title`).
|
|
123
|
+
2. **Reconhecimento de Padrões:** Detecta se a string está capitalizada ou inclui espaços, sugerindo que provavelmente é um texto legível por humanos e não um identificador de código.
|
|
67
124
|
|
|
68
|
-
O
|
|
125
|
+
### O Limite Rígido para Dados Dinâmicos
|
|
69
126
|
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
- O `<MyComponent errorMessage="An error occurred" />` é traduzido?
|
|
73
|
-
- Um ID de produto como `"AX-99"` é traduzido?
|
|
127
|
+
A extração pelo compilador depende de **análise estática**. Ele deve ver a string literal no seu código para gerar um ID estável.
|
|
128
|
+
Se a sua API retornar uma string de código de erro como `server_error`, você não poderá traduzi-la com um compilador porque o compilador não sabe que essa string existe em tempo de build. Você será forçado a construir um sistema secundário "apenas em tempo de execução" apenas para dados dinâmicos.
|
|
74
129
|
|
|
75
|
-
|
|
130
|
+
### Falta de chunking
|
|
76
131
|
|
|
77
|
-
|
|
132
|
+
Certos compiladores não fragmentam as traduções por página. Se o seu compilador gerar um arquivo JSON grande por idioma (por exemplo, `./lang/en.json`, `./lang/fr.json`, etc.), você provavelmente acabará carregando conteúdo de todas as suas páginas para uma única página visitada. Além disso, cada componente que usa seu conteúdo provavelmente será hidratado com muito mais conteúdo do que o necessário, o que pode causar problemas de desempenho.
|
|
78
133
|
|
|
79
|
-
|
|
80
|
-
Se sua API retorna uma string de código de erro como `server_error`, você não pode traduzi-la com um compilador porque ele não sabe que essa string existe em tempo de build. Você é forçado a construir um sistema secundário "apenas em tempo de execução" só para dados dinâmicos.
|
|
134
|
+
Também tenha cuidado ao carregar suas traduções dinamicamente. Se isso não for feito, você carregará conteúdo para todos os idiomas além do atual.
|
|
81
135
|
|
|
82
|
-
|
|
136
|
+
> Para ilustrar o problema, considere um site com 10 páginas e 10 idiomas (todos 100% únicos). Você carregaria conteúdo para 99 páginas adicionais (10 × 10 - 1).
|
|
83
137
|
|
|
84
|
-
|
|
138
|
+
### "Explosão de Chunks" e Cascatas de Rede
|
|
85
139
|
|
|
86
|
-
|
|
140
|
+
Para resolver o problema do chunking, algumas soluções oferecem chunking por componente, ou até mesmo por chave. No entanto, o problema é apenas parcialmente resolvido. O argumento de venda dessas soluções é frequentemente dizer "Seu conteúdo é tree-shaken."
|
|
87
141
|
|
|
88
|
-
|
|
142
|
+
De fato, se você carregar conteúdo estaticamente, sua solução fará tree-shake no conteúdo não utilizado, mas você ainda acabará com conteúdo de todos os idiomas carregado junto com sua aplicação.
|
|
89
143
|
|
|
90
|
-
|
|
144
|
+
Então, por que não carregar dinamicamente? Sim, nesse caso você carregará mais conteúdo do que o necessário, mas isso não é sem compensações.
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
Carregar conteúdo dinamicamente isola cada pedaço de conteúdo em seu próprio chunk, que só será carregado quando o componente for renderizado. Isso significa que você fará uma requisição HTTP por bloco de texto. 1.000 blocos de texto na sua página? → 1.000 requisições HTTP para seus servidores. E para limitar o impacto e otimizar o tempo de renderização inicial da sua aplicação, você precisará inserir múltiplos limites de Suspense ou Skeleton Loaders.
|
|
147
|
+
|
|
148
|
+
> Nota: Mesmo com Next.js e SSR, seus componentes ainda serão hidratados após o carregamento, então as requisições HTTP ainda serão feitas.
|
|
149
|
+
|
|
150
|
+
A solução? Adotar uma solução que permita declarar declarações de conteúdo com escopo, como fazem `i18next`, `next-intl` ou `intlayer`.
|
|
151
|
+
|
|
152
|
+
> Nota: `i18next` e `next-intl` exigem que você gerencie manualmente a importação dos namespaces / mensagens para cada página, a fim de otimizar o tamanho do seu bundle. Você deve usar um analisador de bundle como `rollup-plugin-visualizer` (vite), `@next/bundle-analyzer` (next.js) ou `webpack-bundle-analyzer` (React CRA / Angular / etc) para detectar se você está poluindo seu bundle com traduções não utilizadas.
|
|
153
|
+
|
|
154
|
+
### Sobrecarga de Performance em Tempo de Execução
|
|
155
|
+
|
|
156
|
+
Para tornar as traduções reativas (para que atualizem instantaneamente quando você troca de idioma), o compilador frequentemente injeta hooks de gerenciamento de estado em cada componente.
|
|
157
|
+
|
|
158
|
+
- **O Custo:** Se você renderizar uma lista de 5.000 itens, estará inicializando 5.000 hooks `useState` e `useEffect` apenas para o texto. O React precisa identificar e re-renderizar todos os 5.000 consumidores simultaneamente. Isso causa um bloqueio massivo na "Main Thread", congelando a interface durante a troca. Isso consome memória e ciclos de CPU que bibliotecas declarativas (que normalmente usam um único provedor de Context) economizam.
|
|
159
|
+
|
|
160
|
+
> Note que o problema é semelhante para outros frameworks além do React.
|
|
93
161
|
|
|
94
162
|
## A Armadilha: Vendor Lock-in
|
|
95
163
|
|
|
96
|
-
|
|
164
|
+
Tenha cuidado ao escolher uma solução i18n que permita a extração ou migração das chaves de tradução.
|
|
97
165
|
|
|
98
|
-
|
|
166
|
+
No caso de uma biblioteca declarativa, seu código-fonte contém explicitamente sua intenção de tradução: estas são suas chaves, e você as controla. Se quiser mudar de biblioteca, geralmente só precisa atualizar a importação.
|
|
99
167
|
|
|
100
|
-
|
|
101
|
-
|
|
168
|
+
Com uma abordagem de compilador, seu código-fonte pode ser apenas texto em inglês simples, sem nenhum vestígio da lógica de tradução: tudo está oculto na configuração da ferramenta de build. Se esse plugin deixar de ser mantido ou você quiser mudar de solução, pode ficar preso. Não há uma maneira fácil de "ejetar": não existem chaves utilizáveis no seu código, e você pode precisar re-gerar todas as suas traduções para uma nova biblioteca.
|
|
169
|
+
|
|
170
|
+
Algumas soluções também oferecem serviços de geração de tradução. Sem mais créditos? Sem mais traduções.
|
|
171
|
+
|
|
172
|
+
Os compiladores frequentemente fazem hash do texto (por exemplo, `"Hello World"` -> `x7f2a`). Seus arquivos de tradução ficam parecidos com `{ "x7f2a": "Hola Mundo" }`. A armadilha: se você trocar de biblioteca, a nova biblioteca vê `"Hello World"` e procura por essa chave. Ela não vai encontrar porque seu arquivo de tradução está cheio de hashes (`x7f2a`).
|
|
173
|
+
|
|
174
|
+
### Bloqueio de Plataforma
|
|
175
|
+
|
|
176
|
+
Ao escolher uma abordagem baseada em compilador, você se prende à plataforma subjacente. Por exemplo, certos compiladores não estão disponíveis para todos os bundlers (como Vite, Turbopack ou Metro). Isso pode tornar as migrações futuras difíceis, e você pode precisar adotar múltiplas soluções para cobrir todas as suas aplicações.
|
|
102
177
|
|
|
103
178
|
## O Outro Lado: Riscos da Abordagem Declarativa
|
|
104
179
|
|
|
105
180
|
Para ser justo, a forma tradicional declarativa também não é perfeita. Ela tem seu próprio conjunto de "armadilhas".
|
|
106
181
|
|
|
107
|
-
1. **Inferno dos Namespaces:**
|
|
108
|
-
2. **Carregamento
|
|
109
|
-
3. **
|
|
182
|
+
1. **Inferno dos Namespaces:** Você frequentemente precisa gerenciar manualmente quais arquivos JSON carregar (`common.json`, `dashboard.json`, `footer.json`). Se você esquecer algum, o usuário verá as chaves brutas.
|
|
183
|
+
2. **Carregamento excessivo:** Sem uma configuração cuidadosa, é muito fácil carregar acidentalmente _todas_ as suas chaves de tradução para _todas_ as páginas no carregamento inicial, inchando o tamanho do seu bundle.
|
|
184
|
+
3. **Desalinhamento de sincronização:** É comum que chaves permaneçam no arquivo JSON muito tempo depois do componente que as utiliza ter sido deletado. Seus arquivos de tradução crescem indefinidamente, cheios de "chaves zumbis".
|
|
110
185
|
|
|
111
|
-
## O Meio-
|
|
186
|
+
## O Meio-termo do Intlayer
|
|
112
187
|
|
|
113
|
-
É aqui que ferramentas como o **Intlayer** estão tentando inovar. O Intlayer entende que, embora compiladores sejam poderosos,
|
|
188
|
+
É aqui que ferramentas como o **Intlayer** estão tentando inovar. O Intlayer entende que, embora os compiladores sejam poderosos, a mágica implícita é perigosa.
|
|
114
189
|
|
|
115
|
-
O Intlayer oferece
|
|
190
|
+
O Intlayer oferece uma abordagem mista, permitindo que você se beneficie das vantagens de ambas as abordagens: gerenciamento declarativo de conteúdo, também compatível com seu compilador para economizar tempo de desenvolvimento.
|
|
191
|
+
|
|
192
|
+
E mesmo que você não use o compilador Intlayer, o Intlayer oferece um comando `transform` (também acessível usando a extensão VSCode). Em vez de apenas fazer mágica na etapa oculta de build, ele pode realmente **reescrever o código do seu componente**. Ele escaneia seu texto e o substitui por declarações explícitas de conteúdo na sua base de código.
|
|
116
193
|
|
|
117
194
|
Isso lhe dá o melhor dos dois mundos:
|
|
118
195
|
|
|
119
|
-
1. **Granularidade:** Você mantém suas traduções próximas aos seus componentes (melhorando modularidade e tree-shaking).
|
|
120
|
-
2. **Segurança:** A tradução
|
|
121
|
-
3. **Sem
|
|
196
|
+
1. **Granularidade:** Você mantém suas traduções próximas aos seus componentes (melhorando a modularidade e o tree-shaking).
|
|
197
|
+
2. **Segurança:** A tradução se torna código explícito, não mágica oculta em tempo de build.
|
|
198
|
+
3. **Sem Lock-in:** Como o código é transformado em uma estrutura declarativa dentro do seu repositório, você pode facilmente pressionar tab, ou usar o copilot do seu IDE, para gerar suas declarações de conteúdo, sem esconder lógica em um plugin do webpack.
|
|
122
199
|
|
|
123
200
|
## Conclusão
|
|
124
201
|
|
|
125
202
|
Então, qual você deve escolher?
|
|
126
203
|
|
|
127
|
-
**Se você
|
|
128
|
-
A abordagem baseada em compilador é uma escolha válida. Ela permite que você avance incrivelmente rápido. Você não precisa se preocupar com estruturas de arquivos ou chaves. Você
|
|
204
|
+
**Se você está construindo um MVP, ou quer avançar rapidamente:**
|
|
205
|
+
A abordagem baseada em compilador é uma escolha válida. Ela permite que você avance incrivelmente rápido. Você não precisa se preocupar com estruturas de arquivos ou chaves. Você apenas constrói. A dívida técnica é um problema para o "Você do Futuro".
|
|
206
|
+
|
|
207
|
+
**Se você é um Desenvolvedor Júnior, ou não se importa com otimização:**
|
|
208
|
+
Se você quer o mínimo de gerenciamento manual, uma abordagem baseada em compilador provavelmente é a melhor. Você não precisará lidar com chaves ou arquivos de tradução - apenas escreva o texto, e o compilador automatiza o resto. Isso reduz o esforço de configuração e os erros comuns de i18n ligados a etapas manuais.
|
|
209
|
+
|
|
210
|
+
**Se você está internacionalizando um projeto existente que já inclui milhares de componentes para refatorar:**
|
|
211
|
+
Uma abordagem baseada em compilador pode ser uma escolha pragmática aqui. A fase inicial de extração pode economizar semanas ou meses de trabalho manual. No entanto, considere usar uma ferramenta como o comando `transform` do Intlayer, que pode extrair strings e convertê-las em declarações explícitas de conteúdo declarativo. Isso oferece a velocidade da automação enquanto mantém a segurança e a portabilidade de uma abordagem declarativa. Você obtém o melhor dos dois mundos: migração inicial rápida sem dívida arquitetural a longo prazo.
|
|
129
212
|
|
|
130
213
|
**Se você está construindo uma Aplicação Profissional, de Nível Empresarial:**
|
|
131
|
-
|
|
214
|
+
Magia geralmente é uma má ideia. Você precisa de controle.
|
|
132
215
|
|
|
133
|
-
- Você precisa lidar com dados dinâmicos
|
|
216
|
+
- Você precisa lidar com dados dinâmicos de backends.
|
|
134
217
|
- Você precisa garantir desempenho em dispositivos de baixo custo (evitando explosões de hooks).
|
|
135
218
|
- Você precisa garantir que não fique preso a uma ferramenta de build específica para sempre.
|
|
136
219
|
|
|
137
|
-
Para aplicativos profissionais, **Gerenciamento Declarativo de Conteúdo** (como Intlayer ou bibliotecas consolidadas) continua sendo o padrão ouro. Ele separa suas preocupações, mantém sua arquitetura limpa e garante que a capacidade do seu aplicativo de falar múltiplos idiomas não dependa de um compilador "caixa
|
|
220
|
+
Para aplicativos profissionais, o **Gerenciamento Declarativo de Conteúdo** (como Intlayer ou bibliotecas consolidadas) continua sendo o padrão ouro. Ele separa suas preocupações, mantém sua arquitetura limpa e garante que a capacidade do seu aplicativo de falar múltiplos idiomas não dependa de um compilador "caixa-preta" tentando adivinhar suas intenções.
|