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
next-intl VS Intlayer: Benchmark internacjonalizacji (i18n) w React i Next.js

next-intl jest najpopularniejszą biblioteką i18n dla Next.js. Intlayer to oparta na kompilatorze alternatywa o zasięgu komponentów. Obie lokalizują aplikację App Router. Pytanie brzmi, ile każda z nich kosztuje po zbudowaniu aplikacji.
Ten artykuł nie jest samouczkiem. To porównanie oparte na liczbach z Benchmark Bloom, pakietu testów porównawczych open-source, który buduje tę samą aplikację z każdą biblioteką i mierzy to, co przeglądarka faktycznie pobiera i wykonuje.
W skrócie (tl;dr):next-intldodaje co najmniej +12.6 KB gzip na każdej stronie wyłącznie ze względu na swój runtime i powoduje wyciek ~90% ciągów z innych stron w standardowych konfiguracjach (staticidynamic). Wyeliminowanie tego wycieku wymaga podziału katalogów na przestrzenie nazw i ręcznego ich wybierania per strona. Z kolei kompilatorIntlayerzapewnia 0% wycieku, 3x mniejsze komponenty i narzut rzędu zaledwie +0.3 KB ponad bazową aplikację bez żadnej konfiguracji.
Podsumowanie
- next-intl - Standard społeczności Next.js. Scentralizowane pliki JSON per język, pełna obsługa ICU MessageFormat i głęboka integracja z obsługą żądań i routingiem Next.js.
- Intlayer - Model zorientowany na komponenty. Słowniki
.content.tsumieszczane są tuż obok komponentów, kompilator automatycznie wykonuje tree-shaking oraz leniwe ładowanie per komponent i per język, a także generuje ścisłe typy TypeScript.
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
Odznaki aktualizują się automatycznie.
Porównanie funkcji
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Funkcja | Intlayer (react-intlayer / next-intlayer) | next-intl (next-intl / use-intl) |
|---|---|---|
| Tłumaczenia przy komponentach | ✅ Tak, .content.ts umieszczony przy każdym komponencie | ❌ Scentralizowane pliki JSON w katalogu messages/ |
| Integracja z TypeScriptem | ✅ Ścisłe typy generowane automatycznie z treści | ⚠️ Wspierane przez ręczną konfigurację global.d.ts |
| Wykrywanie brakujących tłumaczeń | ✅ Błąd TypeScriptu + błąd/ostrzeżenie podczas budowania | ⚠️ W runtime zwracany jest klucz lub zgłaszany błąd w zależności od opcji |
| Bogata treść (JSX / Markdown / komponenty) | ✅ Bezpośrednie wsparcie | ⚠️ Poprzez t.rich() z przekazywaniem komponentów mapujących |
| Obsługa ICU MessageFormat | ⚠️ W trakcie prac | ✅ Tak, pełna obsługa standardu ICU |
| Synchroniczne komponenty serwerowe | ✅ useIntlayer z next-intlayer/server działa w każdym podrzędnym komponencie serwera | ❌ Wymaga przekazywania tłumaczeń przez propsy z asynchronicznego rodzica |
| Tree-shaking | ✅ Automatyczny dla każdego komponentu i języka | ⚠️ Wymaga ręcznego podziału na przestrzenie nazw i użycia funkcji pick() |
| Leniwe ładowanie (Lazy loading) | ✅ Jedna linijka konfiguracji (importMode: 'dynamic') | ⚠️ Wymaga ręcznego importu dynamicznego w getRequestConfig |
| Wizualny Edytor / CMS | ✅ Darmowy Wizualny Edytor + opcjonalny CMS | ❌ Brak |
| Tłumaczenia wspomagane przez AI | ✅ Wbudowane, korzysta z Twoich własnych kluczy API dostawców | ❌ Brak |
| Serwer MCP i Agent Skills | ✅ Tak | ❌ Brak |
Benchmark
Co było mierzone
Zestaw testów Benchmark Bloom buduje 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ść. Pomiary przeprowadzono na stronach w językach en i fr. Każda biblioteka została przetestowana 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 na starcie | Szybkie prototypy, kod wygenerowany przez AI |
| dynamic | Ładowany jest tylko aktywny język, ale od razu dla wszystkich stron | Większość projektów |
| scoped-static | Przestrzenie nazw per trasa, brak leniwego ładowania | Rzadkość |
| scoped-dynamic | Przestrzenie nazw per trasa + leniwe ładowanie. Tylko bieżąca strona w bieżącym języku | Aplikacje z rygorystycznym budżetem wydajnościowym |
Intlayer nie wymaga 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 wariantu rejestrowano:
- Rozmiar biblioteki (Lib size): rozmiar gzip pustego komponentu importującego wyłącznie bibliotekę i18n.
- JS strony (Page JS): ilość JavaScript gzip pobieranego na stronę.
- % wycieku języka (Locale leak %): odsetek ciągów należących do języka, którego użytkownik nie przegląda.
- % wycieku strony (Page leak %): odsetek ciągów należących do innej podstrony.
- Średnia komponentu (Component avg): średni rozmiar gzip każdego komponentu skompilowanego w izolacji.
- Reaktywność E2E: czas od wyboru nowego języka do zaktualizowania
html[lang]w DOM. - Hydratacja: czas trwania fazy hydratacji w React.
Dane poniżej pochodzą z testu z dnia 2026-09-12 z użyciem biblioteknext-intl4.14.2 iintlayer9.5.1.
Wyniki w Next.js (App Router)
Wybierz metryki i biblioteki, które Cię interesują:
Metryka
Dynamiczne ładowanie JSON
Wczytuje tłumaczenia leniwie w czasie wykonywania
Ograniczony JSON (przestrzenie nazw)
Przestrzenie nazw tłumaczeń na stronę
Czym jest ta metryka?
Całkowity skompresowany przez gzip rozmiar pakietu biblioteki umiędzynarodowienia. Obejmuje tylko dostawcę i logikę pobierania treści po tree-shakingu i minifikacji.
Dlaczego to jest ważne?
Mniejszy rozmiar biblioteki zmniejsza obciążenie u klienta.
Zobacz jako
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Biblioteka | Strategia | Rozmiar Lib (gz) | Śr. JS strony (gz) | Wyciek języka | Wyciek strony | Śr. komponentu (gz) | Reaktywność E2E | Hydratacja |
|---|---|---|---|---|---|---|---|---|
| Baza (bez i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
next-intl | static | 14.7 KB | 153.6 KB | 4.2% | 89.8% | 21.8 KB | 16.0 ms | 14.7 ms |
next-intl | dynamic | 14.7 KB | 153.6 KB | 9.7% | 89.9% | 21.8 KB | 15.6 ms | 14.8 ms |
next-intl | scoped-static | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 80.1 KB | 17.9 ms | 17.4 ms |
next-intl | scoped-dynamic | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 22.9 KB | 17.8 ms | 16.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 |
@intlayer/next-intl (kompat) | static | 8.0 KB | 147.5 KB | 0.0% | 0.0% | 8.1 KB | 14.5 ms | 12.8 ms |
@intlayer/next-intl (kompat) | dynamic | 8.0 KB | 148.7 KB | 0.0% | 0.0% | 8.1 KB | 11.7 ms | 12.8 ms |
Jak interpretować wyniki
- Koszt środowiska uruchomieniowego. Aplikacja bazowa to 141.0 KB na stronę.
next-intlzwiększa tę wartość do 153.6 KB (+12.6 KB gzip na każdej stronie), podczas gdy Intlayer narzuca zaledwie 141.3 KB (+0.3 KB). - Wyciek treści. W najczęstszych konfiguracjach (
staticidynamic)next-intlwysyła na każdej stronie ~90% ciągów z innych stron, ponieważ cały pliken.jsontrafia do dostawcy klienta. Osiągnięcie 0% wymaga ręcznego dzielenia katalogów, podczas gdy Intlayer robi to automatycznie. - Rozmiar komponentu. Komponent wywołujący
useTranslations()waży średnio 21.8 KB; ten sam komponent zuseIntlayer()waży jedynie 6.9 KB.
Pełna tabela, każda biblioteka i każda strategia, w raporcie benchmarku Next.js.
Wyniki w TanStack Start (use-intl)
use-intl jest niezależnym od frameworka rdzeniem next-intl. To samo API, ten sam format wiadomości. Porównanie go z intlayer na TanStack Start usuwa z równania specyfikę Next.js.
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Biblioteka | Strategia | Rozmiar Lib (gz) | Śr. JS strony (gz) | Wyciek języka | Wyciek strony | Śr. komponentu (gz) | Reaktywność E2E |
|---|---|---|---|---|---|---|---|
| Baza (bez i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms |
use-intl | static | 14.1 KB | 179.8 KB | 50.0% | 89.8% | 76.0 KB | 6.7 ms |
use-intl | dynamic | 14.1 KB | 119.4 KB | 0.0% | 89.8% | 75.9 KB | 7.0 ms |
use-intl | scoped-static | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 20.9 ms |
use-intl | scoped-dynamic | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 13.3 ms |
intlayer | static | 5.0 KB | 125.8 KB | 50.0% | 0.0% | 8.1 KB | 3.2 ms |
intlayer | dynamic | 5.0 KB | 118.6 KB | 0.0% | 0.0% | 6.3 KB | 3.6 ms |
@intlayer/use-intl (kompat) | dynamic | 7.3 KB | 129.7 KB | 0.0% | 0.0% | 9.3 KB | 8.7 ms |
Jak interpretować wyniki
- Naiwna konfiguracja
use-intlwysyła o 68.8 KB więcej kodu JS na stronę niż aplikacja bazowa. - W trybie
dynamicuse-intlosiąga 119.4 KB, ale nadal generuje 89.8% wycieku stron. - Różnica architektoniczna jest widoczna w rozmiarze komponentów: 76-87 KB w
use-intlw porównaniu do 6-8 KB w Intlayerze. - Przełączanie języka jest 2-4x szybsze w Intlayerze (3 ms vs 7-21 ms).
Pełna tabela w raporcie benchmarku TanStack Start.
Dlaczego jest taka różnica? Scentralizowane katalogi vs kompilowane słowniki

next-intl podąża za klasycznym wzorcem: jeden plik JSON per język, ładowany w getRequestConfig, przekazywany do NextIntlClientProvider i odczytywany przez t("namespace.key").
Skopiuj kod do schowka
Runtime nie może wiedzieć, jakich kluczy użyje dana strona, dlatego domyślnie wysyła cały katalog.
Koszt nieosiągnięcia tego celu rośnie na dwóch osiach jednocześnie: stron i języków:

Intlayer odwraca tę relację. Treść deklarowana jest tuż obok komponentu:
Skopiuj kod do schowka
Podczas budowania kompilator analizuje, które komponenty importują poszczególne słowniki i dołącza do paczki tylko to, co jest niezbędne dla aktywnego języka.
Aby uzyskać wyniki z wierszadynamic, ustawdictionary.importMode: 'dynamic'wintlayer.config.ts. Zobacz dokumentację optymalizacji paczki.
Doświadczenie programisty
Komponent klienta
Skopiuj kod do schowka
Skopiuj kod do schowka
Pamiętaj o uwzględnieniu przestrzeni nazwcounterw komunikatach przekazywanych doNextIntlClientProviderna każdej stronie renderującej ten komponent.
Skopiuj kod do schowka
Skopiuj kod do schowka
Nie trzeba niczego rejestrować na stronie: komponent dostarcza własną treść.
Synchroniczne komponenty serwerowe
Wspólne elementy interfejsu (pasek nawigacji, stopka, karty) są często komponentami serwerowymi renderowanymi wewnątrz komponentów klienckich, więc nie mogą być asynchroniczne (async).
Skopiuj kod do schowka
Strona musi wywołać await getTranslations("counter") i await getFormatter(), a następnie przekazać wyniki w dół jako propsy. Komponent przestaje być samowystarczalny.
Skopiuj kod do schowka
Metadane
Skopiuj kod do schowka
Skopiuj kod do schowka
Zachowaj API next-intl, zyskaj lekki bundle z Intlayer
Nie musisz przepisywać komponentów, aby zyskać powyższe wyniki wydajnościowe. @intlayer/next-intl to adapter typu drop-in: zachowuje useTranslations, getTranslations, useFormatter, t.rich() i formaty ICU, serwując je ze słowników skompilowanych przez Intlayera.
Skopiuj kod do schowka
W testach wersja kompatybilna tej samej aplikacji zmniejszyła rozmiar z 153.6 KB do 147.5 KB na stronę, rozmiar komponentów z 21.8 KB do 8.1 KB, a wyciek strony spadł z ~90% do 0%, bez ingerencji w kod źródłowy aplikacji. Dotychczasowe pliki messages/{locale}.json mogą pozostać źródłem prawdy dzięki wtyczce synchronizacji JSON.
Zobacz przewodnik migracji z next-intl, aby poznać szczegóły krok po kroku.
Kiedy wybrać którą bibliotekę?
Chcesz standardu ekosystemu Next.js, polegasz na ICU MessageFormat, Twoja aplikacja jest mała lub średnia, lub integrujesz się z platformą tłumaczeń (Crowdin, Phrase, Lokalise...) oczekującą scentralizowanego JSON. Zaplanuj czas na podział katalogów na przestrzenie nazw i wybieranie komunikatów za pomocą pick() na stronę, jeśli wydajność ma znaczenie.
Chcesz treści o zasięgu komponentu, ścisłego TypeScriptu, błędów brakujących kluczy w czasie budowania, automatycznego tree-shakingu i leniwego ładowania, synchronicznych komponentów serwerowych oraz wbudowanych narzędzi redakcyjnych (Edytor Wizualny, CMS, tłumaczenie AI, serwer MCP). Szczególnie istotne dla dużych, modułowych baz kodu i systemów projektowania.
Używasz już next-intl i chcesz uzyskać korzyści z rozmiaru paczki bez przepisywania aplikacji. Adapter zgodności zachowuje Twoje importy i plik messages/{locale}.json jako źródło prawdy. Zmierzono obok siebie w next-intl vs @intlayer/next-intl.
FAQ
Nie w czasie renderowania. Różnica polega na tym, co jest przesyłane do przeglądarki: next-intl kosztuje +12.6 KB gzip środowiska wykonawczego na każdej stronie i w standardowych konfiguracjach wysyła ~90% ciągów z innych stron wraz z każdą stroną. Przełączanie języka i hydratacja są porównywalne w Next.js (15-18 ms); w TanStack Start use-intl zajmuje 7-21 ms w porównaniu do 3-4 ms w Intlayer.
Tak, dzięki konfiguracji scoped-dynamic: podziel messages/{locale}.json na jedną przestrzeń nazw na trasę, a następnie użyj pick(messages, [...]) na każdej stronie i utrzymuj to mapowanie w miarę przesuwania komponentów. Wiersze scoped-* w benchmarku odzwierciedlają dokładnie tę pracę. Intlayer osiąga 0% domyślnie, ponieważ kompilator ogranicza treść do poziomu komponentu. Zobacz optymalizacja paczki.
Nie. @intlayer/next-intl zachowuje useTranslations, getTranslations, useFormatter, t.rich(), liczbę mnogą ICU oraz pomocniki nawigacji, udostępniając je ze skompilowanych słowników. Wystarczy jedna linijka wtyczki w next.config.ts. Krok po kroku w przewodniku migracji next-intl.
Natywna obsługa ICU jest w trakcie opracowywania. Adaptery zgodności (@intlayer/next-intl, @intlayer/use-intl) w pełni obsługują ICU: liczba mnoga, select, selectordinal, # i {ts, date, long} przechodzą przez mechanizm ICU Intlayera. Szczegóły znajdziesz w format wiadomości ICU.
Tak. Wtyczka synchronizacji JSON odczytuje je, dzieli klucze najwyższego poziomu na słowniki i zapisuje tłumaczenia z powrotem do tych samych plików, gdy CLI lub CMS je aktualizuje. Przepływ pracy tłumaczy pozostaje bez zmian.
Powiązane porównania
Ten sam benchmark, inne biblioteki:
Więcej o next-intl:
Dokumentacja referencyjna:
Aby zrozumieć, skąd wzięły się te biblioteki, przeczytaj historię i18n w JavaScript.
Gwiazdki na GitHub
Gwiazdki na GitHub to silny wskaźnik popularności projektu, zaufania społeczności i długoterminowej perspektywy rozwoju.
Aktywność commitów
Gwiazdki pokazują popularność. Commity pokazują, ile pracy włożono w projekt. W chwili pisania Intlayer ma około 7 500 commitów, więcej niż większość porównywanych tu bibliotek i mniej więcej 5 razy więcej niż next-intl czy next-i18next.
- amannn/next-intl
- aymericzip/intlayer
Commity na domyślnej gałęzi, źródło: GitHub API.
Intlayer to monorepo, więc ta liczba obejmuje każdy pakiet dla frameworków, CLI i dokumentację. Traktuj commity jako sygnał aktywności, a nie jakości.
Pobrania z npm
- next-intl
- next-intlayer
Źródło: API pobrań rejestru npm.
Liczba pobrań nagradza najstarsze rozwiązania, a nie najlepsze. Biblioteka wydana lata temu wciąż jest instalowana przez każdy projekt, który ją wtedy wybrał, przez każde uruchomienie CI i przez każdy pakiet, który od niej zależy. Ta liczba mierzy bezwładność bardziej niż świadomy wybór.
Asystenci AI wzmacniają ten efekt. next-intl, i18next i vue-i18n są wszędzie w kodzie, na którym ich trenowano, więc proponują je domyślnie, bez porównywania alternatyw. Każda sugestia dodaje pobrań, które napędzają kolejną sugestię. Porównuj na podstawie benchmarku, a nie liczby pobrań.
Podsumowanie
next-intl to solidna, dobrze utrzymywana biblioteka, a testy potwierdzają, że jest rozsądnym wyborem w świecie Next.js. Jednak scentralizowany model katalogów przerzuca całą odpowiedzialność za optymalizację na programistę: podstawowa konfiguracja powoduje wyciek około 90% treści z innych podstron, a sam runtime kosztuje +12.6 KB gzip na każdej stronie.
Intlayer przenosi tę pracę do kompilatora. Słowniki per komponent, leniwe ładowanie per język i usuwanie nieużywanych tłumaczeń to efekty procesu budowania. Rezultat w tej samej aplikacji: +0.3 KB na stronę, 0% wycieku, komponenty 3x mniejsze i przełączanie języka 2-4x szybsze w TanStack Start.
Wszystkie surowe dane, aplikacje testowe i skrypty znajdują się w repozytorium Benchmark Bloom.
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.
