i18n React

Lingui czy i18next w 2026: która biblioteka i18n do React i React Native

Lingui i i18next porównane na podstawie dokumentacji i danych z npm: format komunikatów, makra, kompilacja, rozmiar, liczba mnoga i React Native.

Autor: Mateusz Muszarski Zaktualizowano 6 min czytania In English

Wybierz i18next, jeśli zależy Ci na największym ekosystemie, kluczach nazwanych przez siebie i tłumaczeniach ładowanych jako JSON w czasie działania aplikacji. Wybierz Lingui, jeśli wolisz pisać tekst źródłowy tam, gdzie się wyświetla, trzymać liczbę mnogą w jednym komunikacie ICU i kompilować katalogi przy buildzie, z rdzeniem ważącym około 2 kB po gzipie. Używam Lingui w Linkoglocie (30 języków, Expo) i na tej stronie.

TL;DR

  • i18next ma zasięg: około 15 razy więcej pobrań z npm tygodniowo niż Lingui, długą listę wtyczek i typowane klucze w TypeScripcie.
  • Lingui przenosi pracę na czas builda: makra tworzą ID, katalogi kompilują się do JavaScriptu, a wtyczka bundlera potrafi wywrócić build przy brakującym tłumaczeniu.
  • Obie działają w React Native na Hermesie z polyfillami Intl. Zanim wybierzesz, przetestuj liczbę mnogą w najtrudniejszym ze swoich języków na prawdziwym urządzeniu.

Nazywasz klucze czy piszesz tekst źródłowy?

Różnicę widać już w pierwszej linijce kodu. W i18next wymyślasz klucz, wpisujesz tekst do pliku JSON i w czasie działania szukasz go po kluczu:

{ "greeting": "Hello {{name}}" }
const { t } = useTranslation();
return <p>{t("greeting", { name })}</p>;

W Lingui piszesz angielski tekst w miejscu, gdzie się wyświetla. Makro zamienia go przy buildzie na komunikat z krótkim, wygenerowanym ID:

import { t } from "@lingui/core/macro";

t`Hello ${name}`;
// po przejściu makra (przykład z dokumentacji Lingui):
// i18n._({ id: "mVmaLu", message: "Hello {name}", values: { name } })

Żaden z tych modeli nie jest błędny. Nazwane klucze nie zmieniają się, gdy poprawiasz angielski tekst, a z TypeScriptem podpowiadają się w edytorze. Tekst źródłowy oznacza, że nie musisz niczego nazywać, a identyczne teksty łączą się w jeden komunikat. Druga strona medalu: poprawione angielskie zdanie dostaje nowe ID, więc tłumacz widzi je jako nowe.

Łączenie też ma haczyk. W moim katalogu „Stop” występuje dwa razy: raz jako przycisk, raz jako etap pętli z sekcji Jak pracuję, gdzie po polsku potrzebuję słowa „Etap”. Rozdziela je context:

const stopLabel = t({ message: "Stop", context: "a stop on the product loop, as in a bus stop" });
msgid "Stop"
msgstr "Stop"

msgctxt "a stop on the product loop, as in a bus stop"
msgid "Stop"
msgstr "Etap"
Pierwszy etap pętli z sekcji Jak pracuję po angielsku, z etykietą Stop 01, Client en
Ten sam etap po polsku, z etykietą Etap 01, Klient pl
Ten sam etap na stronie głównej po angielsku i po polsku. Bez kontekstu etap i przycisk dzieliłyby jedno polskie słowo.

Czy obie biblioteki używają formatu ICU?

Domyślnie nie. Lingui używa ICU MessageFormat wszędzie: zmienne, liczba mnoga i select siedzą w jednym komunikacie, na przykład {count, plural, one {# file} other {# files}}. W i18next {{name}} służy do interpolacji, a każda forma liczby mnogiej to osobny klucz z sufiksem. Wstawiane wartości są domyślnie escapowane, żeby ograniczyć ryzyko XSS.

ICU w i18next da się włączyć wtyczką i18next-icu, opartą na intl-messageformat od formatjs. Jej README ostrzega, że z wtyczką działa wyłącznie format ICU, więc {{name}} przestaje działać. Wybierz jedną składnię na projekt.

Jak działają makra, ekstrakcja i kompilacja?

  1. 01 Piszesz Makro obejmuje angielski tekst tam, gdzie się wyświetla.
  2. 02 Ekstrakcja lingui extract zbiera komunikaty do jednego katalogu .po na język.
  3. 03 Tłumaczenie Człowiek, skrypt albo LLM wypełnia katalog, razem z komentarzami i kontekstem.
  4. 04 Kompilacja lingui compile, wtyczka Vite albo transformer Metro zamienia .po na JavaScript.
  5. 05 Wysyłka Do bundla trafiają skompilowane komunikaty, bez parsera.

Makra działają przy buildzie (Babel, SWC albo natywna transformacja w @lingui/vite-plugin). Według dokumentacji generują krótkie ID, pozwalają TypeScriptowi sprawdzać komponenty jak zwykły kod i usuwają z buildu produkcyjnego komentarze dla tłumaczy oraz domyślne teksty. Ekstraktor znajduje makra, jawne wywołania i18n._() i wyrażenia oznaczone komentarzem /** i18n */; komunikatu zapisanego w zmiennej nie wyciągnie.

i18next pomija kompilację. JSON trafia do bundla albo jest ładowany przez wtyczki backendowe, a przestrzenie nazw (namespaces) dzielą tłumaczenia, żeby doładowywać je na żądanie. Ekstrakcją zajmuje się i18next-cli, zestaw narzędzi oparty na SWC: wyciąga klucze, generuje typy TypeScript, wykrywa zahardkodowane teksty, synchronizuje pliki językowe i raportuje stan tłumaczeń.

Ile ważą paczki?

Dane z bundlephobii z 2026-10-05, po minifikacji oraz po minifikacji i gzipie (1 kB = 1000 bajtów):

Paczka Wersja Min Gzip
i18next 26.4.2 43,6 kB 13,7 kB
react-i18next 17.0.15 25,9 kB 10,2 kB
@lingui/core 6.9.0 5,0 kB 2,1 kB
@lingui/react 6.9.0 3,8 kB 1,8 kB

Wiersze z rdzeniami zgadzają się z porównaniem na stronie Lingui. react-i18next deklaruje i18next jako peer dependency, więc jego wiersz nie zawiera samego i18next. Twoje katalogi dokładają bajty w obu przypadkach, a tree-shaking zmienia sumy, więc zanim podasz komuś liczbę, zmierz własny build.

Jak obie radzą sobie z liczbą mnogą?

Obie trzymają się kategorii z CLDR (zero, one, two, few, many, other) i obie opierają się na Intl.PluralRules. Różni się kształt danych. Angielski potrzebuje dwóch form, polski czterech. W i18next to cztery klucze, a zmienna musi nazywać się count:

{
  "files_one": "{{count}} plik",
  "files_few": "{{count}} pliki",
  "files_many": "{{count}} plików",
  "files_other": "{{count}} pliku"
}

W Lingui programista pisze tylko angielskie formy makrem plural, a polski tłumacz wypełnia jeden komunikat:

msgid "{count, plural, one {# file} other {# files}}"
msgstr "{count, plural, one {# plik} few {# pliki} many {# plików} other {# pliku}}"

Kod się nie zmienia, gdy dochodzi język z większą liczbą form. To praktyczny argument za ICU: gramatyka każdego języka zostaje w jego własnym pliku.

A co z TypeScriptem?

i18next daje typowane klucze i typy zwracanych wartości. Deklarujesz zasoby w rozszerzeniu CustomTypeOptions, a t sprawdza i podpowiada klucze. Najnowsze wersje wymagają TypeScriptu 5, a dokumentacja uprzedza, że typowanie może wydłużyć kompilację w dużych projektach (na ten przypadek jest zoptymalizowane API selektorów).

W Lingui nie ma kluczy do typowania. Makra to zwykłe template literals i JSX, więc TypeScript sprawdza wstawiane wartości jak każdy inny kod. Tracisz podpowiadanie kluczy, ale nie masz listy kluczy, którą trzeba utrzymywać.

Czy działają w React Native i Expo?

Obie działają i obie potrzebują tych samych polyfilli na Hermesie. Dokumentacja liczby mnogiej i18next mówi, że Hermes wciąż nie implementuje Intl.PluralRules. Od wersji 24 nie ma fallbacku: bez polyfilla działają tylko angielskie formy _one i _other. Samouczek React Native od Lingui (Lingui 5 lub nowsze, React Native 0.76 albo Expo 52, Hermes) każe dodać polyfille Intl.Locale i Intl.PluralRules z paczek formatjs.

react-i18next opisuje się jako framework dla React i React Native. Lingui używa tej samej paczki @lingui/react w obu środowiskach, dokłada transformer Metro dla plików .po i opcję defaultComponent, dzięki której przetłumaczony tekst ląduje w Text. Niezależnie od wyboru przetestuj liczbę mnogą na prawdziwym urządzeniu: polska forma utknięta w other łatwo umyka, gdy testy robi się po angielsku.

Jak duży jest każdy ekosystem?

i18next jest dużo większy. W tygodniu od 2026-09-28 do 2026-10-04 npm odnotował około 27,8 mln pobrań i18next i około 1,9 mln pobrań @lingui/core. Poza Reactem i18next ma integracje z Angularem i Vue, działa w Node.js i Deno i ma długą listę wtyczek (backendy, wykrywanie języka, konwertery z gettext, CSV i RESX). Jego twórcy rozwijają też Locize, serwis do zarządzania tłumaczeniami zrobiony pod i18next.

Lingui obsługuje React, React Native, Vue, SolidJS, Astro, Svelte i Node.js, a pod spodem jest niezależny od frameworka @lingui/core. Domyślny format katalogów to PO, czyli gettext: czytelny przy długich komunikatach, z komentarzami, kontekstami i metadanymi, obsługiwany przez wiele narzędzi do lokalizacji. comment i context podane w makrze trafiają do katalogu, a to pomaga zarówno tłumaczowi, jak i modelowi językowemu.

Jak używam Lingui?

Linkoglot to moja aplikacja do nauki języków, zbudowana w Expo i React Native. Przy 30 katalogach format pliku liczy się tak samo jak API. Pliki PO z komunikatami ICU trzymają reguły liczby mnogiej każdego języka w jego pliku, a zwykły tekst łatwo przetworzyć skryptem. Ten skrypt stał się później lingui-translate-ai, narzędziem CLI, które wypełnia katalogi Lingui przy pomocy LLM; opisuję je w tekście Tłumaczenie katalogów Lingui przez LLM.

Ta strona działa na Astro 7 z lingui-for-astro, integracją społecznościową (nie od zespołu Lingui), która przetwarza makra w plikach .astro i wyciąga z nich komunikaty. Wtyczka Vite kompiluje każdy plik .po przy imporcie, więc w repozytorium nie ma skompilowanych katalogów, a build produkcyjny ustawia failOnMissing:

lingui({
  macroTransform: true,
  failOnMissing: BUILD ? "catalog" : false,
  failOnCompileError: true,
});

Przy wartości "catalog" build się wywraca, jeśli w polskim albo hiszpańskim katalogu brakuje komunikatu, i sprawdza to, zanim zadziałają języki zapasowe. Brakujący polski tekst nie trafi na produkcję jako ciche angielskie zdanie. Adresy, hreflang i przełącznik języka wokół tego opisuję w tekście wielojęzyczna strona w Astro z Lingui.

Którą bibliotekę wybrać?

Jeśli potrzebujesz Skłaniaj się ku
Największego ekosystemu albo serwisu do tłumaczeń od tych samych twórców (Locize) i18next
Tłumaczeń ładowanych z serwera w czasie działania i18next
Nazwanych kluczy z podpowiedziami w TypeScripcie i18next
Tekstu źródłowego w kodzie, bez nazywania kluczy Lingui
Liczby mnogiej i select w jednym komunikacie ICU Lingui (albo i18next z i18next-icu)
Najmniejszego rdzenia Lingui
Buildu, który pada przy brakującym tłumaczeniu Lingui
Katalogów PO dla tłumaczy i skryptów Lingui
React Native na Hermesie Obie, z polyfillami Intl

Ograniczenia

  • To nie jest benchmark. Każde zachowanie pochodzi z oficjalnej dokumentacji; nie budowałem tej samej aplikacji w obu bibliotekach.
  • Liczby to migawka. Rozmiary z bundlephobii i pobrania z API npm sprawdziłem 5 października 2026; zanim je zacytujesz, sprawdź aktualne.

Jeśli wybierasz dla zespołu, sprawdź obie biblioteki na jednym prawdziwym ekranie z liczbą mnogą, w tym ze swoich języków, który ma najwięcej form. Projekty, w których używam Lingui, znajdziesz na stronie z moimi pracami.

Źródła

  1. Lingui: Introduction (otwiera się w nowej karcie) (dostęp: )
  2. Lingui vs i18next (otwiera się w nowej karcie) (dostęp: )
  3. Lingui: Macros reference (otwiera się w nowej karcie) (dostęp: )
  4. Lingui: Message extraction (otwiera się w nowej karcie) (dostęp: )
  5. Lingui: Pluralization (otwiera się w nowej karcie) (dostęp: )
  6. Lingui: Catalog formats (otwiera się w nowej karcie) (dostęp: )
  7. Lingui: React Native tutorial (otwiera się w nowej karcie) (dostęp: )
  8. Lingui: Vite plugin (otwiera się w nowej karcie) (dostęp: )
  9. i18next documentation (otwiera się w nowej karcie) (dostęp: )
  10. i18next: Plurals (otwiera się w nowej karcie) (dostęp: )
  11. i18next: Interpolation (otwiera się w nowej karcie) (dostęp: )
  12. i18next: TypeScript (otwiera się w nowej karcie) (dostęp: )
  13. i18next-icu (GitHub) (otwiera się w nowej karcie) (dostęp: )
  14. i18next-cli (GitHub) (otwiera się w nowej karcie) (dostęp: )
  15. react-i18next documentation (otwiera się w nowej karcie) (dostęp: )
  16. @lingui/core on npm (otwiera się w nowej karcie) (dostęp: )
  17. i18next on npm (otwiera się w nowej karcie) (dostęp: )
  18. lingui-for-astro on npm (otwiera się w nowej karcie) (dostęp: )
  19. Bundlephobia: i18next 26.4.2 (otwiera się w nowej karcie) (dostęp: )
  20. Bundlephobia: react-i18next 17.0.15 (otwiera się w nowej karcie) (dostęp: )
  21. Bundlephobia: @lingui/core 6.9.0 (otwiera się w nowej karcie) (dostęp: )
  22. Bundlephobia: @lingui/react 6.9.0 (otwiera się w nowej karcie) (dostęp: )
  23. npm downloads API: i18next, last week (otwiera się w nowej karcie) (dostęp: )
  24. npm downloads API: @lingui/core, last week (otwiera się w nowej karcie) (dostęp: )

Wszystkie wpisy

Artykuł 5 min czytania

Tłumaczenie katalogów Lingui przez LLM

Jak tłumaczyć katalogi .po z Lingui modelem językowym, co się psuje (zmienne, liczba mnoga, ton) i jakie testy puścić, zanim katalog trafi na produkcję.