Zadaj pytanie i otrzymaj streszczenie dokumentu, odwołując się do tej strony i wybranego dostawcy AI
Treść tej strony została przetłumaczona przy użyciu sztucznej inteligencji.
Zobacz ostatnią wersję oryginalnej treści w języku angielskimJeśli masz pomysł na ulepszenie tej dokumentacji, zachęcamy do przesłania pull requesta na GitHubie.
Link do dokumentacji na GitHubieKopiuj dokument Markdown do schowka
Lingui VS Intlayer | Benchmark internacjonalizacji (i18n) w React i Next.js
Lingui i Intlayer to dwie biblioteki w tym benchmarku, które opierają się na kompilatorze, a nie na czystym środowisku wykonawczym (runtime). Lingui wyodrębnia wiadomości z makr w czasie budowania i kompiluje katalogi per lokalizacja. Intlayer kompiluje słowniki per komponent i przeprowadza tree-shaking per lokalizacja. W teorii powinny dawać zbliżone wyniki. Liczby pokazują jednak, gdzie się różnią.
Dane pochodzą z projektu Benchmark Bloom, zestawu testów open-source, który buduje tę samą aplikację z każdą biblioteką i rejestruje, co przeglądarka faktycznie pobiera i wykonuje.
W skrócie (tl;dr): Lingui jest najbliżej Intlayera pod względem surowego kodu JavaScript na stronę: 115-120 KB vs 118.6 KB w TanStack Start po skonfigurowaniu leniwego ładowania (lazy loading), 148.6 KB vs 141.3 KB w Next.js. Różnica pojawia się w innych miejscach: komponent Lingui skompilowany w izolacji waży 58-153 KB w porównaniu do 6-8 KB w Intlayerze, hydratacja trwa 28-34 ms w porównaniu do 11-14 ms, fallback języka źródłowego wycieka 3-15% ciągówenna stronachfrw każdej zoptymalizowanej konfiguracji, a osiągnięcie tej konfiguracji wymaga ręcznego wyodrębniania, kompilowania i dobierania katalogów per trasa. Intlayer osiąga to bez dodatkowej konfiguracji.
Podsumowanie
- Lingui - Oparte na makrach (
t`...`,<Trans>,msg), ICU MessageFormat, katalogi.po/ JSON, przepływ pracylingui extract+lingui compile. Kompiluje identyfikatory wiadomości do krótkich haszy, obsługuje dynamiczne ładowanie katalogów per lokalizacja. Ugruntowane, niezależne od frameworka, z bogatym ekosystemem narzędzi dla tłumaczy opartych na formacie.po. - Intlayer - Model zawartości zorientowany na komponenty. Słowniki
.content.tsznajdują się bezpośrednio przy komponencie, kompilator w czasie budowania wykonuje tree-shaking i leniwe ładowanie per komponent oraz per lokalizacja, ścisłe typy TypeScript są generowane automatycznie z treści, a brakujące tłumaczenia powodują błąd budowania. Zawiera middleware, pomocniki SEO, Edytor Wizualny / CMS oraz tłumaczenia wspomagane przez AI.
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
Odznaki aktualizują się automatycznie. Wartości zmieniają się w czasie.
Porównanie funkcji
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Funkcja | Intlayer (react-intlayer / next-intlayer) | Lingui (@lingui/core / @lingui/react) |
|---|---|---|
| Tłumaczenia blisko komponentów | ✅ Tak, .content.ts umieszczony przy każdym komponencie | ⚠️ Ciągi źródłowe w JSX przez makra; tłumaczenia w scentralizowanych katalogach .po |
| Integracja z TypeScriptem | ✅ Ścisłe typy generowane automatycznie z treści | ⚠️ Makra są typowane; identyfikatory wiadomości nie, brakujące wpisy nie są wykrywane |
| Wykrywanie brakujących tłumaczeń | ✅ Błąd TypeScriptu + błąd/ostrzeżenie w czasie budowania | ⚠️ lingui extract raportuje statystyki; w runtime następuje powrót do tekstu źródłowego |
| Bogata treść (JSX / Markdown / komponenty) | ✅ Bezpośrednie wsparcie | ✅ <Trans> z zagnieżdżonymi komponentami |
| Obsługa ICU | ⚠️ W trakcie prac | ✅ Tak (makra plural, select, selectOrdinal) |
| Formatowanie (daty, liczby, waluty) | ✅ useNumber, useDate, ... (Intl pod maską) | ✅ i18n.date(), i18n.number() |
| Zlokalizowany routing i middleware | ✅ Wbudowane proxy/middleware, getMultilingualUrls | ❌ Brak w rdzeniu |
| Pomocniki SEO (hreflang, sitemap, robots) | ✅ Wbudowane narzędzia | ❌ Ręcznie |
| Synchroniczne komponenty serwerowe | ✅ useIntlayer z next-intlayer/server działa w każdym podrzędnym komponencie serwera | ⚠️ Wymaga instancji I18n per żądanie, przekazywanej w dół lub ustawianej przez setI18n |
| Tree-shaking (tylko użyta zawartość) | ✅ Per komponent, per lokalizacja, zautomatyzowane przez kompilator | ⚠️ Per lokalizacja przez lingui compile; podział per trasa wymaga ręcznej pracy |
| Leniwe ładowanie (Lazy loading) | ✅ importMode: 'dynamic' (jedna linijka konfiguracji) | ⚠️ Ręczny import() skompilowanych katalogów + i18n.load() / i18n.activate() |
| Usuwanie nieużywanych tłumaczeń | ✅ Nieużywane słowniki są odrzucane w czasie budowania | ✅ lingui extract --clean usuwa przestarzałe wiadomości |
| Testowanie brakujących tłumaczeń (CLI / CI) | ✅ npx intlayer content test | ⚠️ Statystyki lingui extract (domyślnie brak błędu kodu wyjścia) |
| Potok budowania (Build pipeline) | ✅ Jeden plugin (@intlayer/swc / @intlayer/babel / vite-intlayer) | ⚠️ Plugin makr (Babel lub SWC) + kroki extract + compile |
| Tłumaczenie wspomagane przez AI | ✅ Wbudowane, korzysta z własnych kluczy API dostawców | ❌ Brak |
| Wizualny Edytor / CMS | ✅ Darmowy Edytor Wizualny + opcjonalny CMS | ❌ Brak (.po współpracuje z zewnętrznymi systemami TMS) |
| Serwer MCP i Agent Skills | ✅ Tak | ❌ Brak |
| Ekosystem / społeczność | ⚠️ Mniejsza, ale dynamicznie rosnąca | ✅ Ugruntowana, niezależna od frameworka |
Benchmark
Co było mierzone
Zestaw Benchmark Bloom buduje dokładnie tę samą aplikację z każdą biblioteką: 10 stron (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), 10 lokalizacji (en, fr, es, de, it, pt, zh, ja, ko, ru), identyczne komponenty i identyczną zawartość. Strony są mierzone w językach en oraz fr. Każda biblioteka została zaimplementowana w maksymalnie czterech strategiach ładowania, od najprostszej do optymalnej:
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Strategia | Opis | Kto to stosuje |
|---|---|---|
| static | Skompilowany katalog każdego języka zaimportowany i załadowany na starcie | Szybkie prototypy, kod wygenerowany przez AI |
| dynamic | Tylko katalog aktywnego języka jest importowany przez import(), ale zawiera całą witrynę | Większość projektów |
| scoped-static | Jeden katalog na trasę, wszystkie spakowane na starcie | Rzadkość |
| scoped-dynamic | Jeden katalog na trasę + leniwy import(). Tylko bieżąca strona i bieżący język | Aplikacje z rygorystycznym budżetem wydajnościowym |
Intlayer nie posiada wariantu "scoped": kompilator automatycznie ogranicza zakres treści per komponent, więc wiersze static i dynamic są już zoptymalizowane pod tym kątem.
Dla każdego buildu zestaw rejestruje:
- Rozmiar biblioteki (Lib size): rozmiar gzip pustego komponentu importującego wyłącznie bibliotekę i18n. Stały koszt środowiska uruchomieniowego.
- JS strony (Page JS): JavaScript gzip pobrany na stronę, uśredniony dla wszystkich stron i lokalizacji.
- % wycieku lokalizacji (Locale leak %): odsetek przetłumaczonych ciągów w pobranym JS należących do języka, którego użytkownik nie przegląda (badane na
enifr, więc 50% oznacza pełną obecność drugiego języka; przy 10 zintegrowanych językach rzeczywista strata jest znacznie wyższa). - % wycieku strony (Page leak %): odsetek przetłumaczonych ciągów w pobranym JS należących do podstrony, na której użytkownik nie przebywa.
- Średnia komponentu (Component avg): średni rozmiar gzip każdego komponentu skompilowanego w izolacji. Pokazuje, ile narzutu i katalogów pociąga za sobą pojedynczy komponent.
- Reaktywność E2E: czas mierzony od momentu wyboru nowego języka do zaktualizowania atrybutu
html[lang]w drzewie DOM (Playwright, 5 iteracji). - Hydratacja: czas trwania fazy hydratacji w React.
Poniższe liczby pochodzą z testu przeprowadzonego 2026-09-12 z użyciem bibliotek@lingui/react6.6.0 orazintlayer9.5.1. Aplikacja testowa jest celowo niewielka (kilkadziesiąt ciągów na język), dlatego wartości procentowe wycieków opisują ogólny wzorzec: rosną one wraz z rozrostem treści, podczas gdy stały koszt runtime pozostaje bez zmian.
Wyniki w Next.js
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Biblioteka | Strategia | Rozmiar Lib (gz) | Średni JS strony (gz) | Wyciek języka | Wyciek strony | Śr. komponentu (gz) | Reaktywność E2E | Hydratacja |
|---|---|---|---|---|---|---|---|---|
| base (bez i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
| Lingui | static | 11.9 KB | 207.4 KB | 50.0% | 90.0% | 73.3 KB | 15.3 ms | 15.2 ms |
| Lingui | dynamic | 11.9 KB | 145.4 KB | 2.8% | 89.9% | 19.9 KB | 15.7 ms | 12.7 ms |
| Lingui | scoped-static | 11.9 KB | 148.2 KB | 2.7% | 89.1% | 20.4 KB | 15.1 ms | 13.1 ms |
| Lingui | scoped-dynamic | 11.9 KB | 148.6 KB | 14.8% | 0.0% | 152.6 KB | 16.1 ms | 14.8 ms |
next-intlayer | static | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 8.5 KB | 15.5 ms | 16.9 ms |
next-intlayer | dynamic | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 6.9 KB | 15.3 ms | 15.9 ms |
Jak interpretować wyniki
- Koszt środowiska uruchomieniowego. Pusty komponent to 11.9 KB gzip w przypadku Lingui oraz 5.5 KB w Intlayerze. W ujęciu całej strony najlepsza konfiguracja Lingui dodaje +7.3 KB w stosunku do Intlayera (148.6 vs 141.3 KB); Intlayer narzuca zaledwie +0.3 KB w porównaniu z bazową aplikacją.
- Naiwna konfiguracja jest kosztowna. Załadowanie wszystkich skompilowanych katalogów na starcie daje wynik 207.4 KB na stronę, czyli +66 KB ponad bazową aplikację. Połowa ciągów należy do niewłaściwego języka, a 90% do niewłaściwej podstrony.
- Dynamiczne ładowanie naprawia wyciek języka, ale nie strony. Z jednym katalogiem na język wyciek strony nadal wynosi ~90%: cały katalog
frjest przesyłany na każdej francuskiej podstronie. Osiągnięcie 0% wycieku podstron wymaga trybuscoped-dynamic: oddzielnego katalogu na każdą trasę, wyodrębnianego i kompilowanego osobno, dołączanego ręcznie w każdej podstronie. - Wyciek języka zapasowego (fallback). Nawet w zoptymalizowanych ustawieniach 3-15% ciągów
entrafia na podstronyfr. Makra Lingui zachowują tekst źródłowy jako fallback, przez co ląduje on w paczce obok tłumaczenia. Intlayer rozwiązuje fallbacki w czasie budowania i wysyła wyłącznie aktywny język. - Gwałtowny wzrost rozmiaru komponentu w
scoped-dynamic. Każdy komponent skompilowany w izolacji osiąga średnio 152.6 KB, ponieważ katalog każdej trasy staje się dostępny z komponentu, który go importuje. Ten sam komponent zuseIntlayer()waży średnio zaledwie 6.9 KB.
Wyniki w TanStack Start
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Biblioteka | Strategia | Rozmiar Lib (gz) | Średni JS strony (gz) | Wyciek języka | Wyciek strony | Śr. komponentu (gz) | Reaktywność E2E | Hydratacja |
|---|---|---|---|---|---|---|---|---|
| base (bez i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms | 21.6 ms |
| Lingui | static | 11.2 KB | 152.2 KB | 50.0% | 90.0% | 58.0 KB | 3.9 ms | 19.9 ms |
| Lingui | dynamic | 11.2 KB | 115.2 KB | 9.3% | 0.0% | 85.5 KB | 5.9 ms | 28.0 ms |
| Lingui | scoped-static | 11.2 KB | 120.8 KB | 4.0% | 0.0% | 147.9 KB | 7.1 ms | 33.9 ms |
| Lingui | scoped-dynamic | 11.2 KB | 120.2 KB | 8.6% | 0.0% | 83.7 KB | 42.1 ms | 32.9 ms |
intlayer | static | 5.0 KB | 125.8 KB | 50.0% | 0.0% | 8.1 KB | 3.2 ms | 11.5 ms |
intlayer | dynamic | 5.0 KB | 118.6 KB | 0.0% | 0.0% | 6.3 KB | 3.6 ms | 14.1 ms |
@intlayer/lingui (kompat) | dynamic | 10.3 KB | 137.0 KB | 9.9% | 0.0% | 12.8 KB | 2.9 ms | 19.7 ms |
Jak interpretować wyniki
- Pod względem kodu JS na stronę Lingui wygrywa o włos. Lingui w wersji
dynamicosiąga 115.2 KB, o 3.4 KB mniej niż Intlayer (118.6 KB). Skompilowane katalogi Lingui z haszowanymi identyfikatorami są bardzo zwarte, a router TanStack Start dzieli trasy na tyle sprawnie, że wyciek podstron wynosi 0% już w trybiedynamic. - Wszystkie pozostałe metryki przemawiają na korzyść Intlayera. Hydratacja w Lingui trwa 28-34 ms w porównaniu do 11-14 ms w Intlayerze: wywołania
i18n.load()+i18n.activate()wykonują się po stronie klienta, zanim React zakończy proces hydratacji. Komponenty skompilowane w izolacji ważą 58-148 KB w porównaniu do 6-8 KB. Wyciek języka nigdy nie spada do 0% (wynosi 4-9%) ze względu na obecność ciągów źródłowych. - Zmiana języka w zoptymalizowanej konfiguracji jest powolna.
scoped-dynamicw Lingui potrzebuje 42 ms na aktualizacjęhtml[lang]: katalog nowej trasy musi zostać pobrany, załadowany i aktywowany, zanim zmiana stanie się widoczna. Intlayer przełącza język w czasie 3-4 ms w obu trybach. - Wiersz
staticw Intlayerze ma już 0% wycieku stron, ponieważ dołączane są wyłącznie słowniki importowane przez komponenty danej strony. Jedna linijka konfiguracji (importMode: 'dynamic') usuwa również wyciek językowy. @intlayer/linguizachowuje składnię makr Lingui, ale zasila je ze słowników Intlayera. Poświęca nieco rozmiaru strony (137 KB ze względu na obecność runtime makr) w zamian za mniejsze komponenty (12.8 KB) i szybszą hydratację niż natywne Lingui. To doskonały krok migracyjny.
Skąd ta różnica? Dwa kompilatory, dwie jednostki pracy
Obie biblioteki korzystają z kompilatora. Różnica polega na tym, co kompilują.
Lingui kompiluje katalogi. Makra w kodzie źródłowym są wyodrębniane do jednego pliku .po na dany język, a następnie kompilowane do modułu JS na język. Podstawową jednostką jest lokalizacja (język). Dalszy podział, per trasa lub per komponent, oznacza tworzenie wielu katalogów, odpowiednie konfigurowanie lingui.config.ts i ręczne ładowanie ich na trasach. Instancja I18n jest globalna; każde wywołanie useLingui() subskrybuje komponent do tej instancji.
Skopiuj kod do schowka
Intlayer kompiluje słowniki. Każdy plik .content.ts to słownik powiązany z określonym kluczem; kompilator analizuje, który komponent importuje dany klucz i generuje, per słownik i per język, dokładnie ten fragment JSON, którego komponent potrzebuje. Podstawową jednostką jest komponent. Ograniczenie zakresu trasy jest naturalną konsekwencją: strona pobiera wyłącznie słowniki komponentów, które faktycznie renderuje.
Skopiuj kod do schowka
Dlatego wzorzec scoped-dynamic jest dla Intlayera naturalnym efektem budowania, a dla Lingui osobnym i pracochłonnym zadaniem konfiguracyjnym.
Aby uzyskać liczby z wierszadynamic, ustawdictionary.importMode: 'dynamic'w plikuintlayer.config.ts. Zobacz dokumentację optymalizacji paczki.
Doświadczenie programisty
Konfiguracja
Lingui
Skopiuj kod do schowka
Skopiuj kod do schowka
Następnie dodaj @lingui/babel-plugin-lingui-macro (lub @lingui/swc-plugin) do bundlera, uruchamiaj lingui extract po modyfikacji kodu źródłowego, lingui compile przed budowaniem aplikacji i owiń drzewo komponentów w <I18nProvider i18n={i18n}>.
Intlayer
Skopiuj kod do schowka
Dodaj intlayer() do vite.config.ts (lub withIntlayer() do next.config.ts) i owiń drzewo w <IntlayerProvider>. Brak etapów extract czy compile: słowniki budują się samoczynnie podczas pracy bundlera.
Komponent
Lingui
Skopiuj kod do schowka
Angielski tekst znajduje się w komponencie; francuski ląduje w src/locales/fr/messages.po pod haszowanym identyfikatorem po uruchomieniu lingui extract. Zapomnienie o uruchomieniu komendy lub o compile cicho przywraca wersję angielską.
Intlayer
Skopiuj kod do schowka
Skopiuj kod do schowka
Oba języki znajdują się w jednym pliku tuż obok komponentu. Brak tłumaczenia fr powoduje błąd budowania, a błędny klucz to natychmiastowy błąd TypeScriptu.
Poza komponentami
Metadane, loadery, funkcje serwerowe: dowolne miejsce bez drzewa Reacta.
Lingui
Skopiuj kod do schowka
Nowa instancja I18n per wywołanie, ręczne ładowanie właściwego katalogu oraz użycie msg + i18n._() zamiast t. Jak zauważono w uwagach do benchmarku, rozróżnienie kiedy użyć t, t` ` , i18n.t(), msg czy <Trans> bywa nieintuicyjne.
Intlayer
Skopiuj kod do schowka
Zachowaj makra Lingui, zyskaj słowniki Intlayera
@intlayer/lingui to gotowy adapter dla @lingui/core i @lingui/react. Makra kompilują się tak jak dotychczas; wywołania i18n._(), do których prowadzą, są obsługiwane przez słowniki Intlayera, a wtyczki synchronizacji .po pozwalają zachować dotychczasowe pliki jako źródło prawdy. Liczba mnoga i konstrukcje ICU renderują się identycznie.
Skopiuj kod do schowka
Zachowaj @lingui/babel-plugin-lingui-macro / @lingui/swc-plugin w potoku budowania przed kompilatorem Intlayera. Zobacz dokumentację zgodności z Lingui.
Kiedy wybrać którą bibliotekę?
- Wybierz Lingui, jeśli zależy Ci na ICU MessageFormat z typowanymi makrami, Twoi tłumacze pracują na plikach
.pow ramach istniejącego systemu TMS, preferujesz ciągi źródłowe umieszczone inline w JSX i Twój zespół bez problemu zarządza procesem extract / compile / podziału katalogów. - Wybierz Intlayer, jeśli zależy Ci na treści powiązanej bezpośrednio z komponentami, ścisłym TypeScripcie, wykrywaniu brakujących kluczy w czasie budowania, automatycznym tree-shakingu i leniwym ładowaniu bez zbędnej konfiguracji, lekkich komponentach, błyskawicznej hydratacji, natychmiastowej zmianie języka oraz wbudowanych narzędziach redakcyjnych (Edytor Wizualny, CMS, tłumaczenia AI, serwer MCP).
- Wybierz
@intlayer/lingui, jeśli używasz obecnie Lingui i chcesz stopniowo przejść na słowniki Intlayera bez modyfikowania makr.
Powiązane porównania
- next-intl vs Intlayer (ten sam benchmark)
- i18next vs Intlayer (ten sam benchmark)
- Benchmark vue-i18n vs Intlayer (ten sam benchmark)
- Kompilator vs deklaratywne i18n
Gwiazdki na GitHub
Gwiazdki na GitHubie to silny wskaźnik popularności projektu, zaufania społeczności oraz jego długoterminowej perspektywy. Choć nie mierzą bezpośrednio jakości technicznej, pokazują, jak wielu programistów ceni dany projekt i śledzi jego rozwój.
Podsumowanie
Lingui to najsilniejsza biblioteka łącząca runtime i kompilator w tym zestawieniu. Skompilowane katalogi z haszami dają rozmiar JavaScript na stronę bardzo zbliżony do Intlayera, a w TanStack Start nawet nieznacznie mniejszy. Gdyby jedynym kryterium była waga kodu na stronę, mielibyśmy remis.
Tak jednak nie jest. Kompilator Lingui zatrzymuje się na poziomie całego języka; wszystko poniżej (katalogi per trasa, leniwe ładowanie, eliminacja fallbacku z paczki) wymaga żmudnej konfiguracji. Benchmark wyraźnie pokazuje koszt tej granicy: komponenty 10-20x większe, hydratacja 2-3x wolniejsza, 3-15% wycieku językowego, który nigdy nie znika, oraz przełączanie języka trwające 42 ms w zoptymalizowanej konfiguracji. Kompilator Intlayera działa na poziomie pojedynczego komponentu, dlatego te same wartości wynoszą 6-8 KB, 11-14 ms, 0% i 3-4 ms bez żadnej ręcznej konfiguracji.
Wszystkie surowe dane, aplikacje testowe i skrypty znajdują się w repozytorium Benchmark Bloom. Możesz uruchomić je samodzielnie.
Więcej szczegółów znajdziesz w dokumencie 'Dlaczego Intlayer?'.
Komentarze
Nie ma jeszcze komentarzy. Bądź pierwszą osobą, która podzieli się swoimi przemyśleniami.
