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 to obecnie domyślny wybór w zakresie i18n dla Next.js App Router: ścisła integracja z routingiem, pełna obsługa ICU MessageFormat i środowisko pracy znane każdemu, kto korzystał z klasycznych bibliotek i18n.
Intlayer podchodzi do tematu od nowa: brak scentralizowanych słowników, brak konieczności ręcznego dopasowywania przestrzeni nazw (namespaces) do tras. Treści deklarowane są bezpośrednio przy komponentach, a kompilator w czasie budowania pakuje wyłącznie to, czego wymaga dana strona.
Poniższy artykuł porównuje obie biblioteki na podstawie danych z Benchmark Bloom, otwartoźródłowego zestawu testów, który buduje tę samą aplikację z każdą biblioteką i rejestruje realny kod pobierany oraz wykonywany przez przeglądarkę.
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)
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.
Wyniki w TanStack Start (use-intl)
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).
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.
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
next-intl
Skopiuj kod do schowka
Skopiuj kod do schowka
Intlayer
Skopiuj kod do schowka
Skopiuj kod do schowka
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).
next-intl
Skopiuj kod do schowka
Intlayer
Skopiuj kod do schowka
Metadane
next-intl
Skopiuj kod do schowka
Intlayer
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ę?
- Wybierz next-intl, jeśli zależy Ci na standardzie społeczności Next.js, intensywnie korzystasz z ICU MessageFormat, Twoja aplikacja jest mała lub średnia, albo integrujesz się ze scentralizowanymi platformami TMS (Crowdin, Phrase, Lokalise...).
- Wybierz Intlayer, jeśli zależy Ci na treści powiązanej z komponentami, ścisłym TypeScripcie, wykrywaniu brakujących kluczy w czasie budowania, automatycznym tree-shakingu i leniwym ładowaniu, synchronicznych komponentach serwerowych oraz wbudowanych narzędziach edycyjnych (Wizualny Edytor, CMS, tłumaczenia AI, serwer MCP).
- Wybierz
@intlayer/next-intl, jeśli używasz jużnext-intli chcesz zredukować rozmiar paczki bez konieczności przepisywania kodu.
Powiązane porównania
- i18next vs Intlayer (ten sam benchmark)
- Lingui vs Intlayer (ten sam benchmark)
- Benchmark vue-i18n vs Intlayer (ten sam benchmark)
- next-i18next vs next-intl vs Intlayer
- Czy next-intl jest przestarzałe?
Gwiazdki na GitHub
Gwiazdki na GitHub to silny wskaźnik popularności projektu, zaufania społeczności i długoterminowej perspektywy rozwoju.
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.
