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/i18next | To samo API, inny bundle
@intlayer/i18next, @intlayer/react-i18next i @intlayer/next-i18next to adaptery kompatybilności. Udostępniają API i18next, którego Twój kod już używa (useTranslation, t(), <Trans>, i18n.changeLanguage(), getFixedT, serverSideTranslations...) i obsługują je ze słowników skompilowanych przez Intlayer. Komponenty się nie zmieniają. Zmienia się runtime pod nimi.
Ten artykuł mierzy tę zamianę na tej samej aplikacji Next.js, zbudowanej raz z next-i18next, a raz z @intlayer/next-i18next. Liczby pochodzą z Benchmark Bloom. Aby porównać i18next i Intlayer jako biblioteki, przeczytaj i18next vs Intlayer. Ten artykuł dotyczy tego, co zmienia adapter, gdy zachowujesz swój kod bez zmian.
tl;dr: W tej samej aplikacji Next.js zastąpienienext-i18nextprzez@intlayer/next-i18nextzmniejszyło ilość kodu JavaScript na stronę z 218.5 KB do 150.7 KB gzip (konfiguracja naiwna) i pokonało w pełni zoptymalizowaną konfiguracjęnext-i18next(163.4 KB) o 12.7 KB. Średni komponent zmniejszył się z 78.5 KB do 9.7 KB, wyciek ciągów znaków z obcych stron z ~90% do 0%, hydratacja z 15.6 ms do 11.3 ms, a runtime z 19.7 KB do 9.4 KB. Żaden komponent nie był modyfikowany; zmieniono jeden plik dostawcy (provider). Wtyczkii18next(backendy, detektory języka) są akceptowane, ale nic nie robią: w środowisku wykonawczym nie ma już nic do załadowania ani wykrycia.
Czym jest @intlayer/i18next
i18next to środowisko wykonawcze (runtime). i18n.init({ resources }) lub wtyczka backendu ładuje locales/{lng}/{ns}.json do globalnej instancji; useTranslation("about") subskrybuje do niej komponent; t("title") wyszukuje klucz podczas renderowania. Przestrzenie nazw (namespaces), leniwe ładowanie (lazy loading), listy przestrzeni nazw na stronę i bezpieczeństwo typów pozostają w Twojej gestii do skonfigurowania i utrzymania.
Adaptery zachowują API i zastępują instancję:
- Aliasy importów.
createNextI18nPlugin()z@intlayer/next-i18next/plugin(lubwithI18next) opakowujewithIntlayeri dodaje aliasy Webpack / Turbopack, dzięki czemunext-i18next,react-i18nextii18nextwskazują na ich odpowiedniki@intlayer/*. W VitereactI18nextVitePlugin()z@intlayer/react-i18next/pluginrobi to samo. Żaden import nie jest zmieniany. - JSON jako źródło prawdy. Wtyczka
syncJSONodczytuje istniejące plikilocales/{lng}/{ns}.jsonzformat: "i18next"(dzięki czemu{{name}}, zagnieżdżanie$t(), sufiksy_one/_otheroraz konteksty są poprawnie parsowane) i zapisuje tłumaczenia z powrotem, gdy CLI lub CMS je zaktualizuje. - Wiązanie w miejscu wywołania (call-site binding). Krok optymalizacji Intlayer przepisuje
useTranslation("about")na wywołanie, które otrzymuje słownikaboutbezpośrednio, w aktywnym języku. Komponent przestaje odwoływać się do globalnego magazynu.
Skopiuj kod do schowka
Skopiuj kod do schowka
To przepisanie wpływa bezpośrednio na kolumny rozmiaru komponentów i wycieków stron poniżej.
Co adaptery zachowują, ignorują i czego nie zastępują
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
API i18next | Z @intlayer/* |
|---|---|
useTranslation("ns"), useTranslation("ns", { keyPrefix }) | ✅ Zachowane. Powiązane ze słownikiem ns w czasie budowania; klucze typowane na podstawie zawartości |
t("key", { name }), {{interpolation}}, zagnieżdżanie $t(key) | ✅ Zachowane |
Liczba mnoga key_one / key_other, kontekst key_male, returnObjects | ✅ Zachowane. Liczby mnogie ewaluowane za pomocą Intl.PluralRules |
<Trans> z components, numerowane tagi <1>...</1>, values | ✅ Zachowane |
withTranslation, Translation, I18nContext | ✅ Zachowane |
i18n.changeLanguage(), i18n.language, i18n.dir(), on("languageChanged") | ✅ Zachowane. changeLanguage steruje językiem Intlayer |
getFixedT(lng, ns, keyPrefix), i18n.exists(), hasLoadedNamespace() | ✅ Zachowane |
i18n.use(Backend).use(LanguageDetector).init({...}) | ⚠️ use() wywołuje init wtyczki i zwraca wynik; backendy i detektory nie mają nic do załadowania ani wykrycia |
init({ resources }), addResourceBundle() | ⚠️ resources jest ignorowane z ostrzeżeniem dev; usuń importy JSON, aby uzyskać korzyści w bundle |
I18nextProvider i18n={i18n} | ⚠️ Renderuje IntlayerProvider; właściwość i18n jest ignorowana. W App Router przekaż locale (patrz poniżej) |
serverSideTranslations(locale, ["common"]) (next-i18next) | ⚠️ Zwraca oczekiwany kształt i niczego nie ładuje. Bezpieczne do pozostawienia lub usunięcia |
appWithTranslation(App) (next-i18next) | ✅ Zachowane |
next-i18next.config.js | ⚠️ Nieodczytywane. Języki pochodzą z intlayer.config.ts |
Zwykłe useTranslation() bez przestrzeni nazw | ✅ Działa względem słownika translation dla całego pliku (splitKeys: false) |
Benchmark
Co mierzono
Zestaw Benchmark Bloom buduje tę samą aplikację w każdej konfiguracji: 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 identyczna zawartość. Strony są mierzone w en i fr.
next-i18next zbudowano w czterech strategiach ładowania, od importu JSON każdego języka do resources (static) po jedną przestrzeń nazw na trasę, ładowaną leniwie przez backend (scoped-dynamic). Adapter zbudowano na tych samych komponentach co konfigurację naiwną, ze zmienionymi plikami next.config.ts, intlayer.config.ts oraz plikiem providera. Nie ma wariantu "scoped": kompilator sam ogranicza zasięg zawartości na komponent.
Dla każdego buildu zestaw rejestruje:
- Lib size: rozmiar gzip pustego komponentu, który importuje tylko bibliotekę i18n.
- Page JS: pobrany JavaScript gzip na stronę, uśredniony dla wszystkich stron i języków.
- Locale leak %: udział przetłumaczonych ciągów w pobranym JS należących do języka, którego użytkownik nie przegląda.
- Page leak %: udział 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 między wyborem nowego języka a aktualizacją
html[lang]w DOM (Playwright, 5 iteracji). - Hydration: czas trwania fazy hydratacji React.
Poniższe liczby pochodzą z uruchomienia z dnia 2026-09-12 znext-i18next16.3.0 (react-i18next17.0.13,i18next26.4.2) oraz@intlayer/next-i18next9.5.1. Aplikacja testowa jest celowo niewielka (kilkadziesiąt ciągów na język), więc wartości procentowe wycieków opisują wzorzec: rosną one wraz z zawartością, podczas gdy koszt runtime pozostaje stały.
Wyniki w Next.js
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Konfiguracja | Strategia | Lib size (gz) | Page JS avg (gz) | Locale leak | Page leak | Component avg (gz) | E2E reactivity | Hydration |
|---|---|---|---|---|---|---|---|---|
| base (brak 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 |
@intlayer/next-i18next | static | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 10.7 ms | 11.3 ms |
@intlayer/next-i18next | dynamic | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 11.9 ms | 10.6 ms |
next-intlayer (natywny) | static | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 8.5 KB | 15.5 ms | 16.9 ms |
next-intlayer (natywny) | dynamic | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 6.9 KB | 15.3 ms | 15.9 ms |
Jak to interpretować
- 68 KB mniej na stronę względem konfiguracji naiwnej.
resources: { en, fr, ... }wysyła każdy język i każdą przestrzeń nazw na każdej stronie: 218.5 KB. Build adaptera dla tych samych komponentów osiąga 150.7 KB. Pokonuje również najlepszą konfiguracjęnext-i18next(163.4 KB, jedna przestrzeń nazw na trasę, ładowana leniwie) o 12.7 KB, ponieważ sam runtimei18nextważy 19.7 KB w porównaniu do 9.4 KB. - Wyciek spada do 0% bez dotykania jakiegokolwiek komponentu. Każda konfiguracja
next-i18nextz wyjątkiem w pełni wyizolowanej (scoped) wysyła ~90% ciągów z obcych stron. Wierszdynamicwygląda gorzej niż w teorii: wcale nie eliminuje wycieku stron i dodaje 50% wycieku języków, ponieważ backend dla danego języka nadal pobiera całą przestrzeń nazwtranslation. Adapter osiąga 0% / 0% z poziomu naiwnego kodu. - Komponenty: 8-krotnie mniejsze. Komponent
useTranslation()skompilowany w izolacji waży średnio 78.5 KB przy wbudowanychresourcesoraz 26-27 KB z backendem, ponieważtjest powiązane z globalnym magazynem. Z adapterem osiąga średnio 9.7 KB. - Hydratacja i przełączanie są szybsze. Hydratacja przyspiesza z 15.6 ms do 11.3 ms (oraz z 27.7 ms w konfiguracji
dynamic, gdzie pobieranie z backendu znajduje się na ścieżce krytycznej). Przełączanie języka przyspiesza z 15-16 ms do 11-12 ms. - Adapter to nie natywny runtime.
next-intlayerosiąga 141.3 KB, czyli +0.3 KB względem bazowej aplikacji. Adapter wnosi powierzchnię APIi18next(dialekt interpolacji, rozwiązywanie sufiksów liczby mnogiej i kontekstu, parsowanie tagów<Trans>) na wierzchu rdzenia Intlayer: 9.4 KB i +9.4 KB na stronę ponad natywną implementację. To pomost, a nie ostateczny cel.
Adapterreact-i18nextw Vite / TanStack Start nie brał udziału w tym uruchomieniu. Wartość bazowareact-i18nextw TanStack Start znajduje się w i18next vs Intlayer: 127-184 KB na stronę i 123-185 ms przełączania języka przy leniwym backendzie.
Dlaczego liczby się zmieniają
W katalogu components/ nic się nie zmieniło, więc zyski wynikają z tego, z czym powiązane jest useTranslation.
W przypadku i18next powiązaniem jest instancja globalna. Cokolwiek zostało do niej załadowane (wszystkie języki w static, cała przestrzeń nazw aktywnego języka w dynamic), jest dostępne z każdego komponentu wywołującego useTranslation(). Bundler nie może dokonać podziału poniżej tego, co zawiera instancja, a runtime nie może wiedzieć, o które klucze zapyta komponent.
Skopiuj kod do schowka
W przypadku @intlayer/next-i18next powiązaniem jest słownik. syncJSON przekształca każdy plik przestrzeni nazw w słownik; krok optymalizacji przekazuje komponentowi słownik, do którego się odwołuje, jako import, który bundler może śledzić i dzielić według stron i języków.
Skopiuj kod do schowka
i18n/i18n.ts i jego import resources stają się martwym kodem. To właśnie te 68 KB.
Migracja w trzech krokach
Instalacja
bashKopiuj kodSkopiuj kod do schowka
Polecenie wykrywa
i18next/react-i18next/next-i18next, instalujeintlayer, pakiet frameworka (next-intlayerlubreact-intlayer), pasujący adapter@intlayer/*oraz@intlayer/sync-json-plugin, a także wstępnie konfigurujeintlayer.config.ts. Zachowaj zainstalowane oryginalne pakiety: są to peer dependencies i dostarczają typy.Wskaż Intlayer pliki językowe
intlayer.config.tsKopiuj kodSkopiuj kod do schowka
Jeśli masz pojedynczy plik
translation.jsonna język (domyślna przestrzeń nazw w i18next), ustawsplitKeys: false, aby cały plik pozostał jednym słownikiem i zwykłeuseTranslation()nadal działało.Dodaj wtyczkę
next.config.tsKopiuj kodSkopiuj kod do schowka
W App Router komponenty klienckie pobierają swój język z segmentu
[locale]. KomponentI18nextProvideradaptera nie przyjmuje parametru locale, więc zastąp go raz w pliku providera:components/AppProviders.tsxKopiuj kodSkopiuj kod do schowka
Każdy komponent poniżej nadal wywołuje
useTranslation().vite.config.tsKopiuj kodSkopiuj kod do schowka
reactI18nextVitePlugin()opakowujevite-intlayeri tworzy aliasy dlareact-i18nextii18next. W projekcie bez Reacti18nextVitePlugin()z@intlayer/i18next/plugintworzy alias dla samegoi18next.
Co można potem usunąć
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Plik / wzorzec | Dlaczego |
|---|---|
resources: { en, fr, ... } i importy JSON | Ignorowane przez adapter. To tutaj znajdowało się 68 KB |
i18next-http-backend, i18next-resources-to-backend | Brak danych do pobierania w środowisku wykonawczym |
i18next-browser-languagedetector | Wykrywanie języka to konfiguracja routingu Intlayer (prefiks URL, cookie, nagłówek) |
serverSideTranslations() w getStaticProps | Zwraca pustą strukturę; nieszkodliwe, ale martwe |
next-i18next.config.js | Nieodczytywane. Języki znajdują się w intlayer.config.ts |
Listy ns: [...] per strona | Kompilator dobiera przestrzenie nazw na komponent |
Co zyskujesz poza zaoszczędzonymi bajtami
- Typowane klucze.
useTranslation("about")jest typowane względem skompilowanego słownikaabout;t("does.not.exist")powoduje błąd TypeScript zamiast zwróconego ciągu klucza. npx intlayer testkończy się błędem w CI w przypadku brakującego klucza w dowolnym języku.npx intlayer filltłumaczy brakujące klucze za pomocą Twojego klucza dostawcy (OpenAI, Anthropic, Mistral, Gemini...) i zapisuje je z powrotem dolocales/{lng}/{ns}.json.- Wizualny Edytor i CMS operują na tym samym JSON, dzięki czemu tłumacze edytują treści przez interfejs użytkownika, a pliki są aktualizowane.
- Stopniowe przejście na
.content.ts. Dowolny komponent może przełączyć się zuseTranslation("about")nauseIntlayer("about")z plikiem zawartości zlokalizowanym obok komponentu. Słowniki JSON i.content.tswspółistnieją.
Ograniczenia, które warto znać przed rozpoczęciem
- Backendy i detektory są nieaktywne.
i18n.use(HttpBackend)wywołujeinitwtyczki i nic więcej. Jeśli Twoja aplikacja polegała na pobieraniu tłumaczeń z CMS w czasie wykonywania, ten mechanizm już nie działa; użyj CMS Intlayer lub poleceńintlayer pull/push. resourcesjest ignorowane, a nie scalane. W przeciwieństwie do niektórych innych adapterów,@intlayer/i18nextnie używa wbudowanychresourcesjako mechanizmu fallback. Każdy klucz musi istnieć w zsynchronizowanych słownikach, co weryfikujeintlayer test.- App Router wymaga edycji providera. Jeden plik, pokazany powyżej. Pages Router z
appWithTranslationnie wymaga żadnych zmian. next-i18next.config.jsnie jest odczytywany.localePath,fallbackLng,reloadOnPrerenderi pokrewne nie mają odpowiedników; języki i fallback pochodzą zintlayer.config.ts.- Adapter nie jest darmowy. 9.4 KB runtime i +9.4 KB na stronę względem
next-intlayer. Gdy każdy komponent przejdzie nauseIntlayer, można go usunąć.
Kiedy używać którego rozwiązania?
- Pozostań przy
i18next, jeśli Twoja aplikacja zależy od backendów czasu wykonywania (tłumaczenia serwowane przez CMS w momencie żądania), od ekosystemu wtyczek lub od środowiska innego niż React, którego adaptery nie obsługują. - Użyj
@intlayer/*, jeśli używaszreact-i18next/next-i18nexti zależy Ci na zaoszczędzeniu 68 KB, 8-krotnie mniejszych komponentach, 0% wycieków, typowanych kluczach i testach w CI bez konieczności przepisywania kodu. To idealny punkt wyjścia dla istniejącej bazy kodui18next. - Wybierz rozwiązanie natywne (
next-intlayer/react-intlayer) dla nowych projektów lub gdy adapter spełnił już swoje zadanie. Jest najlżejszy z całej trójki (5.5 KB, +0.3 KB na stronę) i odblokowuje synchroniczne komponenty serwerowe oraz pliki.content.tspowiązane z komponentami.
Powiązane porównania
- i18next vs Intlayer (biblioteki, ten sam benchmark)
- next-intl vs @intlayer/next-intl (ta sama seria adapterów)
- Lingui vs @intlayer/lingui (ta sama seria adapterów)
- vue-i18n vs @intlayer/vue-i18n (ta sama seria adapterów)
- Przewodniki migracji: i18next, react-i18next, next-i18next
- Dokumentacja adapterów kompatybilności: i18next, react-i18next, next-i18next
Podsumowanie
i18next to najcięższy runtime w tym benchmarku, a adaptery usuwają większość z niego bez konieczności rezygnacji z jego API. Na tej samej aplikacji Next.js oznacza to 68 KB mniej na stronę niż w konfiguracji naiwnej, 12.7 KB mniej niż w najlepiej zoptymalizowanej ręcznie, 8x mniejsze komponenty, 0% wycieków oraz 4 ms szybszą hydratację, w zamian za plik konfiguracyjny, jedną linijkę wtyczki i zmianę w jednym providerze. Backendy i detektory stają się operacjami no-op, resources jest ignorowane zamiast scalane, a natywny runtime next-intlayer pozostaje o kolejne 9 KB lżejszy.
Wszystkie surowe dane, aplikacje testowe i skrypty znajdują się w repozytorium Benchmark Bloom. Uruchom je 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.
