Autor:
    Data utworzenia:2026-09-13Ostatnia aktualizacja:2026-09-27

    i18next VS Intlayer: Benchmark internacjonalizacji (i18n) w React i Next.js

    i18next VS Intlayer

    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: i18next to 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 konfiguracja i18next z 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 w react-i18next wobec 3-4 ms w Intlayer. Adapter @intlayer/next-i18next zachowuje API i18next i 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 w locales/{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.ts znajdują 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.
    BibliotekaGwiazdki GitHubŁącznie commitówOstatni commitPierwsza wersjaWersja NPMPobrania NPM (miesięcznie)
    aymericzip/intlayerGitHub Repo starsGitHub commit activityLast CommitKwiecień 2024npmnpm downloads
    i18next/i18nextGitHub Repo starsGitHub commit activityLast CommitStyczeń 2012npmnpm downloads
    i18next/react-i18nextGitHub Repo starsGitHub commit activityLast CommitGrudzień 2015npmnpm downloads
    i18next/next-i18nextGitHub Repo starsGitHub commit activityLast CommitListopad 2018npmnpm downloads
    Odznaki aktualizują się automatycznie. Wartości zmieniają się w czasie.

    Porównanie funkcji

    FunkcjaIntlayer (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:

    StrategiaOpisKto to stosuje
    staticWszystkie języki i strony spakowane razem (resources wbudowane w init())Szybkie prototypy, kod z generatorów AI
    dynamicTylko aktywny język jest ładowany przez backend, ale wszystkie przestrzenie nazw na razWiększość standardowych projektów
    scoped-staticJedna przestrzeń nazw na trasę, wszystkie spakowane na startRzadko
    scoped-dynamicPrzestrzeń nazw na trasę + leniwe ładowanie przez backend. Tylko bieżąca strona i językAplikacje 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 wersjami next-i18next 16.3.0, react-i18next 17.0.13 i intlayer 9.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)

    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

    BibliotekaStrategiaLib size (gz)Page JS avg (gz)Wyciek językaWyciek stronyKomponent śr. (gz)Reaktywność E2EHydratacja
    base (bez i18n)-0.0 KB141.0 KB0.0%0.0%0.9 KB13.4 ms11.8 ms
    next-i18nextstatic19.7 KB218.5 KB0.0%89.8%78.5 KB16.4 ms15.6 ms
    next-i18nextdynamic19.7 KB169.5 KB50.0%89.8%26.1 KB15.4 ms27.7 ms
    next-i18nextscoped-static19.7 KB220.1 KB0.0%89.8%78.9 KB16.4 ms14.7 ms
    next-i18nextscoped-dynamic19.7 KB163.4 KB0.0%0.0%27.1 KB15.9 ms15.1 ms
    next-intlayerstatic5.5 KB141.3 KB0.0%0.0%8.5 KB15.5 ms16.9 ms
    next-intlayerdynamic5.5 KB141.3 KB0.0%0.0%6.9 KB15.3 ms15.9 ms
    @intlayer/next-i18next (compat)static9.4 KB150.7 KB0.0%0.0%9.7 KB10.7 ms11.3 ms
    @intlayer/next-i18next (compat)dynamic9.4 KB150.7 KB0.0%0.0%9.7 KB11.9 ms10.6 ms

    Analiza wyników

    • Koszt środowiska wykonawczego: rdzeń i18next wraz z react-i18next to najcięższy mierzony runtime: 19.7 KB gzip dla pustego komponentu, wobec 5.5 KB w next-intlayer.
    • Naiwna konfiguracja jest kosztowna: Wstrzyknięcie resources w init() 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 z useIntlayer() zajmuje zaledwie 6.9 KB.
    • Czas hydratacji: w konfiguracji dynamic wzrasta do 27.7 ms, ponieważ instancja i18next musi zainicjalizować się i przetworzyć backend po stronie klienta, zanim React ukończy hydratację.
    Pełna tabela, każda biblioteka i każda strategia, w raporcie benchmarku Next.js.

    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.

    BibliotekaStrategiaLib size (gz)Page JS avg (gz)Wyciek językaWyciek stronyKomponent śr. (gz)Reaktywność E2EHydratacja
    base (bez i18n)-0.0 KB111.0 KB0.0%0.0%0.7 KB8.1 ms21.6 ms
    react-i18nextstatic18.4 KB180.3 KB50.0%89.8%24.3 KB12.9 ms85.1 ms
    react-i18nextdynamic18.4 KB136.4 KB23.1%89.8%24.8 KB123.1 ms32.9 ms
    react-i18nextscoped-static18.4 KB184.2 KB50.7%89.8%25.3 KB185.1 ms25.2 ms
    react-i18nextscoped-dynamic18.4 KB127.2 KB0.0%0.0%26.7 KB17.6 ms11.3 ms
    intlayerstatic5.0 KB125.8 KB50.0%0.0%8.1 KB3.2 ms11.5 ms
    intlayerdynamic5.0 KB118.6 KB0.0%0.0%6.3 KB3.6 ms14.1 ms

    Analiza wyników

    • Zwykła aplikacja react-i18next wysył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 w dynamic, 185 ms w scoped-static. Intlayer aktualizuje DOM w 3-4 ms w obu trybach: przełączenie jest natychmiastowe i niezależne od sieci.
    • Zoptymalizowana konfiguracja scoped-dynamic osiąga 0% wycieków przy 127.2 KB, co nadal przewyższa Intlayer w trybie dynamic o +8.6 KB, wymagając mapowania tras i granic Suspense.
    • Intlayer w trybie static wykazuje 0% wycieku stron już na starcie, ponieważ pakowane są tylko te słowniki, które zostały zaimportowane przez komponenty danej strony. Włączenie importMode: 'dynamic' eliminuje także wyciek języka.
    • Rozmiar komponentu: 24-27 KB w react-i18next wobec 6-8 KB w Intlayer. useTranslation() wiąże każdy komponent z globalną instancją i18next.
    Pełna tabela w raporcie benchmarku TanStack Start.

    Skąd ta różnica? Globalna instancja vs skompilowane słowniki

    Centralized catalogs versus per-component dictionaries

    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:

    bash
    .
    ├── i18n.ts                      # createInstance().use(...).use(...).init({...})
    └── src
        ├── locales
        │   ├── en
        │   │   ├── common.json
        │   │   ├── home.json
        │   │   └── about.json
        │   └── fr
        │       ├── common.json
        │       ├── home.json
        │       └── about.json
        ├── components
        │   └── Counter.tsx          # useTranslation("about") + t("counter.label")
        └── app
            └── [locale]
                └── about
                    └── page.tsx     # musi wiedzieć, że potrzebuje ["common", "about"]
    

    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.

    Koszt rośnie w dwóch wymiarach jednocześnie, stron i języków:

    Theoretical content leakage by architecture

    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:

    bash
    .
    ├── intlayer.config.ts
    └── src
        ├── components
        │   └── Counter
        │       ├── index.tsx        # useIntlayer("counter")
        │       └── index.content.ts
        └── app
            └── [locale]
                └── about
                    ├── page.tsx
                    └── page.content.ts
    

    @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 wiersza dynamic, ustaw dictionary.importMode: 'dynamic' w pliku intlayer.config.ts. Szczegóły opisano w dokumentacji optymalizacji bundle.

    Doświadczenie programisty (DX)

    Konfiguracja

    src/app/i18n/server.ts
    import { createInstance } from "i18next";
    import { initReactI18next } from "react-i18next/initReactI18next";
    import resourcesToBackend from "i18next-resources-to-backend";
    import { defaultLocale } from "@/i18n.config";
    
    const backend = resourcesToBackend(
      (locale: string, namespace: string) =>
        import(`../../locales/${locale}/${namespace}.json`)
    );
    
    export const initI18next = async (
      locale: string,
      namespaces: string[] = ["common"]
    ) => {
      const i18n = createInstance();
      await i18n
        .use(initReactI18next)
        .use(backend)
        .init({
          lng: locale,
          fallbackLng: defaultLocale,
          ns: namespaces,
          defaultNS: "common",
          interpolation: { escapeValue: false },
          react: { useSuspense: false },
        });
      return i18n;
    };
    

    Do tego dochodzi kliencki I18nProvider, generateStaticParams oraz deklarowanie tablicy namespaces na każdej podstronie.

    intlayer.config.ts
    import { type IntlayerConfig, Locales } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH],
        defaultLocale: Locales.ENGLISH,
      },
    };
    
    export default config;
    
    src/app/[locale]/layout.tsx
    import { getHTMLTextDir } from "intlayer";
    import { IntlayerClientProvider, type NextLayoutIntlayer } from "next-intlayer";
    
    const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
      const { locale } = await params;
    
      return (
        <html lang={locale} dir={getHTMLTextDir(locale)}>
          <body>
            <IntlayerClientProvider locale={locale}>
              {children}
            </IntlayerClientProvider>
          </body>
        </html>
      );
    };
    
    export default LocaleLayout;
    

    Komponent kliencki

    src/locales/en/about.json
    {
      "counter": {
        "label": "Counter",
        "increment": "Increment"
      }
    }
    
    src/components/Counter.tsx
    "use client";
    
    import { useState } from "react";
    import { useTranslation } from "react-i18next";
    
    export const Counter = () => {
      const { t, i18n } = useTranslation("about");
      const [count, setCount] = useState(0);
      const numberFormat = new Intl.NumberFormat(i18n.language);
    
      return (
        <div>
          <p>{numberFormat.format(count)}</p>
          <button
            aria-label={t("counter.label")}
            onClick={() => setCount((c) => c + 1)}
          >
            {t("counter.increment")}
          </button>
        </div>
      );
    };
    
    Strona renderująca ten komponent musi załadować namespace about, a t("counter.label") pozostaje zwykłym stringiem bez rozszerzenia CustomTypeOptions.
    src/components/Counter/index.content.ts
    import { t, type Dictionary } from "intlayer";
    
    const counterContent = {
      key: "counter",
      content: {
        label: t({ en: "Counter", fr: "Compteur" }),
        increment: t({ en: "Increment", fr: "Incrémenter" }),
      },
    } satisfies Dictionary;
    
    export default counterContent;
    
    src/components/Counter/index.tsx
    "use client";
    
    import { useState } from "react";
    import { useIntlayer } from "next-intlayer";
    import { useNumber } from "next-intlayer/format";
    
    export const Counter = () => {
      const { label, increment } = useIntlayer("counter");
      const number = useNumber();
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>{number(count)}</p>
          <button aria-label={label} onClick={() => setCount((c) => c + 1)}>
            {increment}
          </button>
        </div>
      );
    };
    

    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)

    src/components/ServerCounter.tsx
    type ServerCounterProps = {
      t: (key: string) => string;
      locale: string;
      count: number;
    };
    
    export const ServerCounter = ({ t, locale, count }: ServerCounterProps) => (
      <div>
        <p>{new Intl.NumberFormat(locale).format(count)}</p>
        <button aria-label={t("counter.label")}>{t("counter.increment")}</button>
      </div>
    );
    

    Na poziomie strony wywołuje się i18n.getFixedT(locale, "about"), po czym przekazuje t i locale w dół za pomocą props.

    src/components/ServerCounter.tsx
    import { useIntlayer } from "next-intlayer/server";
    import { useNumber } from "next-intlayer/server/format";
    
    export const ServerCounter = ({ count }: { count: number }) => {
      const { label, increment } = useIntlayer("counter");
      const number = useNumber();
    
      return (
        <div>
          <p>{number(count)}</p>
          <button aria-label={label}>{increment}</button>
        </div>
      );
    };
    

    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.

    next.config.ts
    import type { NextConfig } from "next";
    import { createNextI18nPlugin } from "@intlayer/next-i18next/plugin";
    
    const withIntlayer = createNextI18nPlugin();
    
    const nextConfig: NextConfig = {};
    
    export default withIntlayer(nextConfig);
    
    vite.config.ts
    import { defineConfig } from "vite";
    import { reactI18nextVitePlugin } from "@intlayer/react-i18next/plugin";
    
    export default defineConfig({
      plugins: [reactI18nextVitePlugin()],
    });
    

    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?

    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.

    Zależy Ci na treściach przypisanych do komponentów, ścisłym TypeScript, błędach brakujących kluczy w czasie kompilacji, tree-shakingu i leniwym ładowaniu bez wysiłku, natychmiastowej zmianie języka, synchronicznych komponentach serwerowych i wbudowanych narzędziach edycyjnych (Edytor wizualny, CMS, tłumaczenie AI, serwer MCP). Szczególnie istotne w dużych, modułowych bazach kodu i systemach projektowych.

    Korzystasz już z i18next i chcesz uzyskać korzyści w wielkości paczki i reaktywności bez przepisywania komponentów. Twoje pliki locales/{lng}/{ns}.json pozostają źródłem prawdy. Zmierzone ramię w ramię w i18next vs @intlayer/i18next.

    FAQ

    Został zaprojektowany jako środowisko uruchomieniowe niezależne od frameworka: globalna instancja, potok wtyczek, magazyn zasobów, mechanizm rozwiązywania kluczy. Ta elastyczność jest kompilowana w każdej paczce. Pusty komponent importujący jedynie bibliotekę waży 19.7 KB gzip z next-i18next wobec 5.5 KB z next-intlayer, a koszt ten ponoszony jest na każdej stronie, niezależnie od objętości treści.

    Rozwiązuje problem bajtów, ale nie opóźnień. Przejście na i18next-resources-to-backend oszczędza ~49 KB na stronę, ale dodaje zapytanie sieciowe przy zmianie języka: 123 ms w konfiguracji dynamic oraz 185 ms w scoped-static, w porównaniu do 3-4 ms w Intlayer. Hydratacja wzrasta do 27.7 ms, ponieważ instancja odpytuje backend przed hydratacją Reacta.

    Tak, z konfiguracją scoped-dynamic: jeden namespace na trasę, backend zasobów i ręcznie utrzymywana mapa stron do przestrzeni nazw. Daje to 163.4 KB na stronę w Next.js, co nadal jest o +22 KB więcej niż 141.3 KB w Intlayer, który nie wymagał żadnej konfiguracji. Zobacz optymalizację paczki.

    Nie. @intlayer/i18next, @intlayer/react-i18next oraz @intlayer/next-i18next zachowują useTranslation, t(), <Trans>, {{interpolation}}, formy mnogie _one / _other, sufiksy kontekstowe i returnObjects. Wystarczy jedna linijka wtyczki w next.config.ts lub vite.config.ts. Krok po kroku w przewodniku migracji next-i18next.

    Backendy i detektory języka są akceptowane, ale pozostają bezczynne: w czasie wykonywania nie ma już nic do załadowania ani wykrycia. Detekcja języka staje się konfiguracją routingu Intlayer (prefiks URL, ciasteczko, nagłówek). Jeśli aplikacja pobiera tłumaczenia z CMS podczas żądania, użyj Intlayer CMS lub poleceń intlayer pull / push.

    Powiązane porównania

    Ten sam benchmark, inne biblioteki:

    Więcej o i18next:

    Dokumentacja referencyjna:

    Adaptery kompatybilności:

    Przewodniki migracji:

    Aby zrozumieć, skąd wzięły się te biblioteki, przeczytaj historię i18n w JavaScript.

    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.

    Wykres historii gwiazdek

    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.

    • i18next/i18next
    • i18next/react-i18next
    • i18next/next-i18next
    • 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

    • i18next
    • react-i18next
    • next-i18next
    • 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

    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.

    Powiązane posty

    Ostatnie posty