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
i18next VS Intlayer | Benchmark internacjonalizacji (i18n) w React i Next.js
i18next to najczęściej używany framework i18n w ekosystemie JavaScript. Poprzez react-i18next i next-i18next zasila ogromną część aplikacji React i Next.js. Intlayer to nowoczesna alternatywa oparta na kompilatorze i izolacji na poziomie komponentów.
Ten artykuł porównuje oba rozwiązania na podstawie twardych pomiarów, a nie list funkcji. Liczby pochodzą z Benchmark Bloom, otwartoźródłowego pakietu testów, który buduje tę samą aplikację z każdą biblioteką i rejestruje, co przeglądarka faktycznie pobiera.
tl;dr:i18nextto najcięższe środowisko wykonawcze (runtime) w tym benchmarku: +77 KB gzip na stronę w Next.js w konfiguracji naiwnej, oraz +22 KB po pełnej optymalizacji przestrzeni nazw (namespaces) i leniwego ładowania (lazy-loading). Intlayer dodaje zaledwie +0.3 KB. Każda konfiguracjai18nextz wyjątkiem w pełni wyizolowanej (scoped) wysyła ~90% ciągów z innych stron; Intlayer domyślnie wysyła 0%. Zmiana języka z leniwie ładowanym backendem zajęła 123-185 ms wreact-i18nextwobec 3-4 ms w Intlayer. Adapter@intlayer/next-i18nextzachowuje APIi18nexti osiągnął 150.7 KB na stronę w porównaniu z 218.5 KB oryginału.
W skrócie
- i18next / react-i18next / next-i18next - Dojrzały, bogaty w pluginy, niezależny od frameworka. Przestrzenie nazw, detektory języka, backendy, ICU przez wtyczki,
<Trans>dla treści sformatowanych. Zawartość jest scentralizowana wlocales/{lng}/{ns}.json. Bardzo potężny, ale każda optymalizacja (podział przestrzeni nazw, ładowanie per strona, bezpieczeństwo typów) wymaga ręcznej konfiguracji i ciągłego utrzymania. - Intlayer - Model zorientowany na komponenty. Słowniki
.content.tsznajdują się bezpośrednio przy komponencie, który obsługują; kompilator w czasie budowania usuwa zbędny kod (tree-shaking) i ładuje treści leniwie per komponent i język. Ś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 i tłumaczenie wspomagane 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) | i18next (react-i18next / next-i18next) |
|---|---|---|
| Tłumaczenia przy komponentach | ✅ Tak, .content.ts umieszczony przy każdym komponencie | ❌ Nie, scentralizowane locales/{lng}/{ns}.json |
| Integracja z TypeScript | ✅ Ścisłe typy generowane automatycznie z treści | ⚠️ Podstawowa; ścisłe klucze wymagają rozszerzenia CustomTypeOptions i typów |
| Wykrywanie brakujących tłumaczeń | ✅ Błąd TypeScript + błąd/ostrzeżenie podczas budowania | ⚠️ Fallback w runtime (saveMissing, zwrócenie samego klucza) |
| Bogata treść (JSX / Markdown / komponenty) | ✅ Bezpośrednie wsparcie | ⚠️ <Trans> z indeksowanymi znacznikami |
| Wsparcie ICU | ⚠️ W trakcie prac | ⚠️ Przez wtyczkę (i18next-icu) |
| Liczba mnoga (Pluralization) | ✅ Wzorce oparte na wyliczeniach (enum) | ✅ Przyrostki _one / _other (Intl.PluralRules) |
| Formatowanie (daty, liczby, waluty) | ✅ useNumber, useDate, ... (wbudowane Intl) | ⚠️ Formatery interpolacji lub ręczne wywołania Intl.* |
| Zlokalizowany routing i middleware | ✅ Wbudowane proxy/middleware, getMultilingualUrls | ⚠️ Brak w rdzeniu; wymaga własnego middleware lub zewnętrznych bibliotek |
| Pomocniki SEO (hreflang, sitemap, robots) | ✅ Wbudowane pomocniki | ❌ Ręcznie |
| Synchroniczne komponenty serwerowe (RSC) | ✅ useIntlayer z next-intlayer/server działa w każdym serwerowym komponencie | ⚠️ getFixedT na poziomie strony i przekazywanie t przez Props |
| Tree-shaking (tylko używane treści) | ✅ Na poziomie komponentu i języka, zautomatyzowane przez kompilator | ⚠️ Ręcznie: przestrzenie nazw + lista ns per strona + backend |
| Leniwe ładowanie (Lazy loading) | ✅ importMode: 'dynamic' (jedna linijka konfiguracji) | ✅ Poprzez wtyczki backendu (i18next-resources-to-backend itp.) |
| Czyszczenie nieużywanych treści | ✅ Nieodwiedzane słowniki są usuwane w procesie budowania | ❌ Brak wbudowanego mechanizmu |
| Testowanie brakujących tłumaczeń (CLI / CI) | ✅ npx intlayer content test | ⚠️ i18next-parser / narzędzia firm trzecich |
| Tłumaczenie wspomagane AI | ✅ Wbudowane, używa Twoich własnych kluczy API | ❌ Nie (Locize to osobna, płatna usługa) |
| Wizualny Edytor / CMS | ✅ Darmowy Edytor Wizualny + opcjonalny CMS | ❌ Nie (Locize lub platformy zewnętrzne) |
| Serwer MCP & Agent Skills | ✅ Dostępne | ❌ Niedostępne |
| Ekosystem i społeczność | ⚠️ Młodszy, lecz dynamicznie rosnący | ✅ Największy i najbardziej dojrzały |
Benchmark
Co było mierzone
Pakiet testowy 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 języków (en, fr, es, de, it, pt, zh, ja, ko, ru), identyczne komponenty i identyczną zawartość. Pomiary przeprowadzono dla stron w językach angielskim i francuskim. Każdą bibliotekę wdrożono w maksymalnie czterech strategiach ładowania:
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Strategia | Opis | Kto to stosuje |
|---|---|---|
| static | Wszystkie języki i strony spakowane razem (resources wbudowane w init()) | Szybkie prototypy, kod z generatorów AI |
| dynamic | Tylko aktywny język jest ładowany przez backend, ale wszystkie przestrzenie nazw na raz | Większość standardowych projektów |
| scoped-static | Jedna przestrzeń nazw na trasę, wszystkie spakowane na start | Rzadko |
| scoped-dynamic | Przestrzeń nazw na trasę + leniwe ładowanie przez backend. Tylko bieżąca strona i język | Aplikacje z rygorystycznym budżetem wydajności |
Intlayer nie posiada wariantu "scoped": kompilator automatycznie ogranicza zakres treści na poziomie komponentu, dlatego wiersze static i dynamic są już w pełni zoptymalizowane.
Dla każdego buildu rejestrowane są wskaźniki:
- Lib size: rozmiar gzip pustego komponentu importującego tylko bibliotekę i18n (stały koszt runtime).
- Page JS: średni pobierany JavaScript gzip na stronę dla wszystkich stron i języków.
- Locale leak %: odsetek przetłumaczonych ciągów w pobranym JS należących do języka, którego użytkownik nie przegląda.
- Page leak %: odsetek przetłumaczonych ciągów w pobranym JS należących do strony, na której użytkownik nie przebywa.
- Component avg: średni rozmiar gzip każdego komponentu skompilowanego w izolacji.
- E2E reactivity: rzeczywisty czas od wyboru nowego języka do zaktualizowania
html[lang]w DOM (Playwright, 5 prób). - Hydration: czas trwania fazy hydratacji React.
Poniższe wyniki pochodzą z testów przeprowadzonych 2026-09-12 z wersjaminext-i18next16.3.0,react-i18next17.0.13 iintlayer9.5.1. Aplikacja testowa jest celowo zwarta, dlatego procenty wycieków opisują wzorzec: rosną one wraz z rozrostem treści, podczas gdy stały koszt środowiska wykonawczego nie ulega zmianie.
Wyniki w Next.js (next-i18next)
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Biblioteka | Strategia | Lib size (gz) | Page JS avg (gz) | Wyciek języka | Wyciek strony | Komponent śr. (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 |
next-i18next | static | 19.7 KB | 218.5 KB | 0.0% | 89.8% | 78.5 KB | 16.4 ms | 15.6 ms |
next-i18next | dynamic | 19.7 KB | 169.5 KB | 50.0% | 89.8% | 26.1 KB | 15.4 ms | 27.7 ms |
next-i18next | scoped-static | 19.7 KB | 220.1 KB | 0.0% | 89.8% | 78.9 KB | 16.4 ms | 14.7 ms |
next-i18next | scoped-dynamic | 19.7 KB | 163.4 KB | 0.0% | 0.0% | 27.1 KB | 15.9 ms | 15.1 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 |
@intlayer/next-i18next (compat) | static | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 10.7 ms | 11.3 ms |
@intlayer/next-i18next (compat) | dynamic | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 11.9 ms | 10.6 ms |
Analiza wyników
- Koszt środowiska wykonawczego: rdzeń
i18nextwraz zreact-i18nextto najcięższy mierzony runtime: 19.7 KB gzip dla pustego komponentu, wobec 5.5 KB wnext-intlayer. - Naiwna konfiguracja jest kosztowna: Wstrzyknięcie
resourceswinit()generuje 218.5 KB na stronę (+77.5 KB w stosunku do aplikacji bazowej). Każda strona nosi w sobie wszystkie przestrzenie nazw. - Optymalizacja wymaga dużych nakładów pracy: Przejście na backend (
dynamic) oszczędza 49 KB, lecz wciąż przepuszcza 90% ciągów z innych stron, a w tej konfiguracji połowa pobranych ciągów należy do nieaktywnego języka. Dopiero podział na przestrzenie nazw per trasa (scoped-dynamic) zatrzymuje wycieki przy rozmiarze 163.4 KB, co wciąż daje +22.4 KB na stronę więcej niż w Intlayer (141.3 KB), który nie wymagał żadnej żmudnej konfiguracji. - Wielkość komponentów: Komponent wywołujący
useTranslation()kompiluje się do 26-79 KB; ten sam komponent zuseIntlayer()zajmuje zaledwie 6.9 KB. - Czas hydratacji: w konfiguracji
dynamicwzrasta do 27.7 ms, ponieważ instancja i18next musi zainicjalizować się i przetworzyć backend po stronie klienta, zanim React ukończy hydratację.
Wyniki w TanStack Start (react-i18next)
Ta sama aplikacja na TanStack Start z czystym react-i18next, co eliminuje specyfikę Next.js z testu porównawczego.
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Biblioteka | Strategia | Lib size (gz) | Page JS avg (gz) | Wyciek języka | Wyciek strony | Komponent śr. (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 |
react-i18next | static | 18.4 KB | 180.3 KB | 50.0% | 89.8% | 24.3 KB | 12.9 ms | 85.1 ms |
react-i18next | dynamic | 18.4 KB | 136.4 KB | 23.1% | 89.8% | 24.8 KB | 123.1 ms | 32.9 ms |
react-i18next | scoped-static | 18.4 KB | 184.2 KB | 50.7% | 89.8% | 25.3 KB | 185.1 ms | 25.2 ms |
react-i18next | scoped-dynamic | 18.4 KB | 127.2 KB | 0.0% | 0.0% | 26.7 KB | 17.6 ms | 11.3 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 |
Analiza wyników
- Zwykła aplikacja
react-i18nextwysyła +69 KB na stronę więcej niż aplikacja bazowa, a hydratacja trwa aż 85 ms (4-krotnie dłużej), gdyż całe drzewo zasobów musi zostać przetworzone i zarejestrowane na kliencie przed pierwszym wyrenderowaniem. - Opóźnienie przy zmianie języka: Przy leniwym ładowaniu zmiana języka pociąga za sobą żądanie sieciowe zanim nastąpi aktualizacja
html[lang]: 123 ms wdynamic, 185 ms wscoped-static. Intlayer aktualizuje DOM w 3-4 ms w obu trybach: przełączenie jest natychmiastowe i niezależne od sieci. - Zoptymalizowana konfiguracja
scoped-dynamicosiąga 0% wycieków przy 127.2 KB, co nadal przewyższa Intlayer w trybiedynamico +8.6 KB, wymagając mapowania tras i granic Suspense. - Intlayer w trybie
staticwykazuje 0% wycieku stron już na starcie, ponieważ pakowane są tylko te słowniki, które zostały zaimportowane przez komponenty danej strony. WłączenieimportMode: 'dynamic'eliminuje także wyciek języka. - Rozmiar komponentu: 24-27 KB w
react-i18nextwobec 6-8 KB w Intlayer.useTranslation()wiąże każdy komponent z globalną instancją i18next.
Skąd ta różnica? Globalna instancja vs skompilowane słowniki
i18next powstał w 2012 roku jako runtime: pojedyncza globalna instancja trzyma repozytorium zasobów, wtyczki je rozszerzają, a t() szuka kluczy w czasie renderowania. Daje to wszechstronność, ale generuje narzut:
Skopiuj kod do schowka
Instancja nie wie z góry, o jakie klucze zapyta komponent, dlatego trzyma wszystkie przestrzenie nazw przekazane do załadowania. Optymalizacja wymaga, aby programista dzielił katalogi, wyliczał przestrzenie dla każdej strony i na bieżąco korygował te powiązania. Jak zauważono w notatkach z benchmarku: "Utrzymanie typowania i dokładna wiedza o tym, który namespace dołączyć do danej strony, to koszmar".
Intlayer eliminuje instancję globalną. Treści deklarowane są tuż obok komponentu, a kompilator rozwiązuje graf zależności podczas budowania:
Skopiuj kod do schowka
@intlayer/swc / @intlayer/babel rozpoznaje, który komponent importuje dany słownik, dołącza do paczki tylko te niezbędne dla aktywnego języka i usuwa nieużywane. Wzorzec "scoped-dynamic" staje się bezpośrednim efektem buildu, a nie uciążliwą procedurą do ręcznego pilnowania.
Aby uzyskać liczby z wierszadynamic, ustawdictionary.importMode: 'dynamic'w plikuintlayer.config.ts. Szczegóły opisano w dokumentacji optymalizacji bundle.
Doświadczenie programisty (DX)
Konfiguracja
next-i18next (App Router)
Skopiuj kod do schowka
Do tego dochodzi kliencki I18nProvider, generateStaticParams oraz deklarowanie tablicy namespaces na każdej podstronie.
Intlayer
Skopiuj kod do schowka
Skopiuj kod do schowka
Komponent kliencki
react-i18next
Skopiuj kod do schowka
Skopiuj kod do schowka
Strona renderująca ten komponent musi załadować namespaceabout, at("counter.label")pozostaje zwykłym stringiem bez rozszerzeniaCustomTypeOptions.
Intlayer
Skopiuj kod do schowka
Skopiuj kod do schowka
Pola label oraz increment posiadają ścisłe typowanie; każda literówka natychmiast generuje błąd TypeScript, a brak tłumaczenia dla języka francuskiego zablokuje proces budowania.
Synchroniczny komponent serwerowy (RSC)
next-i18next
Skopiuj kod do schowka
Na poziomie strony wywołuje się i18n.getFixedT(locale, "about"), po czym przekazuje t i locale w dół za pomocą props.
Intlayer
Skopiuj kod do schowka
Zachowaj API i18next, zyskaj wydajność Intlayer
Nie musisz przepisywać istniejących komponentów, aby cieszyć się zyskami z powyższego benchmarku. Adaptery @intlayer/i18next, @intlayer/react-i18next i @intlayer/next-i18next działają bezpośrednio jako zamienniki typu drop-in: wywołania useTranslation, t(), <Trans>, obsługa liczb mnogich i kontekstów działają bez zmian, serwowane przez zoptymalizowane słowniki Intlayer.
Skopiuj kod do schowka
Skopiuj kod do schowka
W benchmarku wersja z adapterem dla tej samej aplikacji Next.js zmniejszyła się z 218.5 KB do 150.7 KB na stronę, z 78.5 KB do 9.7 KB na komponent, wyciek spadł z ~90% do 0%, a czas hydratacji skrócił się z 15.6 ms do 11.3 ms - bez modyfikacji kodu komponentów. Twoje dotychczasowe pliki locales/{lng}/{ns}.json mogą pozostać źródłem danych dzięki wtyczce do synchronizacji JSON.
Zobacz przewodniki migracji: i18next, react-i18next, next-i18next.
Kiedy wybrać dane rozwiązanie?
- Wybierz i18next: jeśli bezwzględnie wymagasz jego ekosystemu wtyczek (specyficzne detektory, niestandardowe backendy, ICU, Locize), lokalizujesz treści także poza środowiskiem React (serwisy Node, czysty JS, inne frameworki), zespół ma już opanowane narzędzia lub zewnętrzna platforma tłumaczeniowa wymaga struktury
locales/{lng}/{ns}.json. Zadbaj o czas na ręczną organizację przestrzeni nazw i mapowanie tras. - Wybierz Intlayer: jeśli zależy Ci na treściach przypisanych bezpośrednio do komponentów, ścisłym bezpieczeństwie TypeScript, wykrywaniu brakujących kluczy podczas budowania, automatycznym tree-shakingu i leniwym ładowaniu bez wysiłku, natychmiastowej zmianie języka, synchronicznych komponentach serwerowych i zintegrowanych narzędziach (Edytor Wizualny, CMS, tłumaczenie AI, serwer MCP). Znakomity wybór dla aplikacji modułowych i systemów projektowych (Design Systems).
- Wybierz adaptery
@intlayer/*-i18next: jeśli posiadasz istniejący kod oparty na i18next i chcesz natychmiast zredukować wagę paczki oraz przyspieszyć działanie bez konieczności refaktoryzacji.
Powiązane porównania
- next-intl vs Intlayer (ten sam benchmark)
- Lingui vs Intlayer (ten sam benchmark)
- vue-i18n vs Intlayer benchmark (ten sam benchmark)
- next-i18next vs next-intl vs Intlayer
- react-i18next vs react-intl vs Intlayer
- Czy i18next jest przestarzały?
Gwiazdki na GitHub
Gwiazdki na GitHubie to przejrzysty wskaźnik popularności, zaufania społeczności i długoterminowego rozwoju projektu. Choć nie określają bezpośrednio jakości kodu, pokazują, jak wielu inżynierów uważa projekt za wartościowy i decyduje się na jego wdrożenie.
Podsumowanie
i18next w pełni zasłużył na swoją pozycję: działa wszędzie, posiada wtyczki do wszystkiego i jest rozwijany od ponad dekady. Benchmark ten ujawnia jednak koszty architektury zorientowanej na runtime. Typowa konfiguracja dodaje +70-77 KB gzip na stronę, przesyła ~90% zbędnych tekstów z innych podstron, a zmiana języka z leniwym ładowaniem trwa ponad 100 ms. Osiągnięcie 0% wycieków jest możliwe, lecz wymaga backendów i manualnego mapowania, a i tak pozostaje o +9-22 KB cięższe niż Intlayer.
Intlayer przenosi cały ten wysiłek na kompilator. Słowniki przy komponentach, automatyczne leniwe ładowanie per język i usuwanie martwych treści to bezpośrednie efekty procesu budowania. W tej samej aplikacji: +0.3 KB na stronę, 0% wycieków, komponenty 3-10x lżejsze oraz zmiana języka w 3-4 ms.
Wszystkie surowe dane, aplikacje testowe i skrypty znajdują się w repozytorium Benchmark Bloom. Możesz uruchomić je i sprawdzić samodzielnie.
Więcej szczegółów znajdziesz w dokumentacji 'Dlaczego Intlayer?'.
Komentarze
Nie ma jeszcze komentarzy. Bądź pierwszą osobą, która podzieli się swoimi przemyśleniami.
