Zadaj pytanie i otrzymaj streszczenie dokumentu, odwołując się do tej strony i wybranego dostawcy AI
Historia wersji
- "Dodaj porównanie gwiazdek GitHub"v8.9.818.05.2026
- "Inicjalizacja benchmarku"v8.7.126.01.2026
Treść tej strony została przetłumaczona przy użyciu sztucznej inteligencji.
Zobacz ostatnią wersję oryginalnej treści w języku angielskimIf you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.
GitHub link to the documentationCopy doc Markdown to clipboard
Biblioteki i18n dla Svelte - raport z benchmarku 2026
Ta strona zawiera raport z benchmarku rozwiązań i18n dla Svelte.
Spis treści
Interaktywny benchmark
Referencja wyników:
Zobacz pełne dane benchmarku
Pełne repozytorium benchmarku znajdziesz tutaj.
Wstęp
Rozwiązania do internacjonalizacji należą do najcięższych zależności w aplikacji Svelte. Głównym ryzykiem jest wysyłanie niepotrzebnych treści: tłumaczeń dla innych stron i innych lokalizacji w paczce (bundle) pojedynczej trasy.
W miarę rozwoju aplikacji problem ten może szybko zwiększyć ilość JavaScriptu wysyłanego do klienta i spowolnić nawigację.
W praktyce, w przypadku najmniej zoptymalizowanych implementacji, strona zinternacjonalizowana może okazać się kilkukrotnie cięższa niż wersja bez i18n.
Innym skutkiem jest wpływ na doświadczenie programisty (DX): sposób deklarowania treści, typy, organizacja przestrzeni nazw (namespaces), dynamiczne ładowanie i reaktywność przy zmianie lokalizacji.
TL;DR
- Intlayer: Najbardziej wydajny wybór (v8.7.12) z najmniejszym śladem (footprint).
- Paraglide: Mocny kandydat pod kątem tree-shakingu, ale oferuje bardziej złożone doświadczenie programisty i narzut reaktywności.
- svelte-i18n: Kompleksowy i standardowy dla Svelte, ale wiąże się ze znacznie większą wagą paczki (~7x Intlayer).
Przetestuj swoją aplikację
Aby szybko wykryć problemy z wyciekami i18n, przygotowałem darmowy skaner dostępny tutaj.
Problem
Dwa dźwignie są kluczowe dla ograniczenia kosztów aplikacji wielojęzycznej:
- Dzielenie treści według stron / przestrzeni nazw, aby nie ładować całych słowników, gdy nie są potrzebne.
- Dynamiczne ładowanie odpowiedniej lokalizacji tylko wtedy, gdy jest potrzebna.
Zrozumienie technicznych ograniczeń tych podejść:
Dynamiczne ładowanie
Bez dynamicznego ładowania większość rozwiązań przechowuje komunikaty w pamięci od pierwszego renderowania, co dodaje znaczny narzut w przypadku aplikacji z wieloma trasami i lokalizacjami.
Dzięki dynamicznemu ładowaniu akceptujesz kompromis: mniej początkowego JS, ale czasami dodatkowe zapytanie przy zmianie języka.
Dzielenie treści (Splitting)
Składnie zbudowane wokół t('a.b.c') są bardzo wygodne, ale często zachęcają do utrzymywania dużych obiektów JSON w czasie wykonywania. Ten model utrudnia tree-shaking, chyba że biblioteka oferuje rzeczywistą strategię dzielenia na poszczególne strony.
Metodologia badań
W tym benchmarku porównaliśmy następujące biblioteki:
Base App(Brak biblioteki i18n)svelte-intlayer(v8.7.12)svelte-i18n(v4.0.1)@inlang/paraglide-js(v2.17.0)
Framework to Svelte z aplikacją wielojęzyczną składającą się z 10 stron i 10 języków.
Porównaliśmy cztery strategie ładowania:
Otwórz tabelę w oknie modalnym, aby wyraźnie zobaczyć całą zawartość
| Strategia | Brak przestrzeni nazw (globalna) | Z przestrzeniami nazw (scoped) |
|---|---|---|
| Ładowanie statyczne | Static: Wszystko w pamięci przy starcie. | Scoped static: Podział na przestrzenie nazw; wszystko ładowane przy starcie. |
| Ładowanie dynamiczne | Dynamic: Ładowanie na żądanie na lokalizację. | Scoped dynamic: Szczegółowe ładowanie na przestrzeń nazw i lokalizację. |
Podsumowanie strategii
- Static: Proste; brak opóźnień sieciowych po początkowym załadowaniu. Minus: duży rozmiar paczki.
- Dynamic: Zmniejsza początkową wagę (lazy-loading). Idealne, gdy masz wiele lokalizacji.
- Scoped static: Utrzymuje porządek w kodzie (logiczna separacja) bez skomplikowanych dodatkowych zapytań sieciowych.
- Scoped dynamic: Najlepsze podejście dla code splittingu i wydajności. Minimalizuje zużycie pamięci, ładując tylko to, czego potrzebuje bieżący widok i aktywna lokalizacja.
Co mierzyłem:
Uruchomiłem tę samą wielojęzyczną aplikację w prawdziwej przeglądarce dla każdego stosu, a następnie zapisałem, co faktycznie pojawiło się na sieci i ile czasu to zajęło. Rozmiary są podawane po normalnej kompresji internetowej, ponieważ jest to bliższe temu, co ludzie pobierają, niż surowe liczby źródłowe.
Rozmiar biblioteki internacjonalizacji: Po bundlingu, tree-shakingu i minifikacji rozmiar biblioteki i18n to rozmiar kodu dostawców + magazynów w pustym komponencie. Nie obejmuje wczytywania plików tłumaczeń. Odpowiada na pytanie, jak kosztowna jest biblioteka, zanim Twoja zawartość wejdzie na scenę.
JavaScript na stronie: Dla każdej trasy benchmarku, ile skryptu przeglądarka pobiera dla tej wizyty, uśrednione dla stron w zestawie (i dla lokalizacji, gdzie raport je łączy). Ciężkie strony są wolnymi stronami.
Wyciek z innych lokalizacji: To zawartość tej samej strony, ale w innym języku, która byłaby załadowana przez pomyłkę na auditowanej stronie. Ta zawartość jest niepotrzebna i powinna być unikana. (np. zawartość strony
/fr/aboutw pakiecie strony/en/about)Wyciek z innych tras: Ten sam pomysł dla innych ekranów w aplikacji: czy ich tekst towarzyszy ci, gdy otwierasz tylko jedną stronę. (np. zawartość strony
/en/aboutw pakiecie strony/en/contact). Wysoki wynik sugeruje słabe dzielenie lub zbyt szerokie pakiety.Średni rozmiar pakietu komponentu: Popularne elementy interfejsu użytkownika są mierzone jeden na raz zamiast ukrywania się wewnątrz jednej gigantycznej liczby aplikacji. Pokazuje, czy internacjonalizacja po cichu inflacyjnie wpływa na codzienne komponenty. Na przykład, jeśli twój komponent się renderuje, załaduje wszystkie te dane z pamięci. Dołączenie gigantycznego JSON-a do dowolnego komponentu to jak podłączenie dużego magazynu nieużywanych danych, który spowolni wydajność twoich komponentów.
Responsywność przełącznika języka: Przełączam język za pomocą własnej kontroli aplikacji i mierzę, ile czasu upłynie, zanim strona wyraźnie się przełączy, co odwiedzający by zauważył, a nie laboratoryjny mikro-krok.
Praca renderowania po zmianie języka: Bardziej zawężone uzupełnienie: ile wysiłku interfejs podjął, aby przemalować dla nowego języka, gdy przełącznik jest w locie. Przydatne, gdy „odczuwany" czas i koszt frameworka się rozbiegają.
Czas ładowania początkowej strony: Od nawigacji do przeglądarki uznającej stronę za w pełni załadowaną dla testowanych scenariuszy. Dobry dla porównywania zimnych startów.
Czas hydratacji: Kiedy aplikacja go ujawnia, jak długo klient spędza na zamienianiu HTML-a serwera w coś, na co faktycznie można kliknąć. Kreska w tabelach oznacza, że ta implementacja nie dostarczyła wiarygodnej liczby hydratacji w tym benchmarku.
Gwiazdki na GitHubie
Gwiazdki na GitHubie są silnym wskaźnikiem popularności projektu, zaufania społeczności i długoterminowego znaczenia. Choć nie są bezpośrednią miarą jakości technicznej, odzwierciedlają, ilu programistów uważa projekt za przydatny, śledzi jego postępy i prawdopodobnie go przyjmie. Przy szacowaniu wartości projektu gwiazdki pomagają porównać zainteresowanie alternatywami i dostarczają wglądu w rozwój ekosystemu.
Wyniki szczegółowe
1 - Rozwiązania, których należy unikać
W ekosystemie Svelte nie ma jednoznacznego rozwiązania, którego należy unikać.
2 - Rozwiązania akceptowalne
(Paraglide) (@inlang/paraglide-js@2.17.0):
Paraglide oferuje innowacyjne, przemyślane podejście. W kontekście aplikacji Vite + Svelte reklamowany przez nich tree-shaking działał zgodnie z oczekiwaniami, co jest świetne.
Ale w przypadku React + TanStack Start tree-shaking nie działał zgodnie z oczekiwaniami, podobnie w Next.js. To powiedziawszy, użycie Paraglide w projekcie Svelte i TanStack Start byłoby warte ponownego sprawdzenia.
Workflow i DX są również bardziej złożone niż w przypadku innych opcji.
Osobiście nie jestem fanem konieczności regeneracji plików JS przed każdym pushem, co stwarza ciągłe ryzyko konfliktów przy mergowaniu poprzez PR-y. Narzędzie wydaje się również bardziej skoncentrowane na Vite niż na Next.js.
Wreszcie, w porównaniu z innymi rozwiązaniami, Paraglide nie używa store'a (np. Svelte store) do pobierania aktualnej lokalizacji w celu renderowania treści. Dla każdego sparsowanego węzła będzie żądać lokalizacji z localStorage / cookie itp. Prowadzi to do wykonywania niepotrzebnej logiki, która wpływa na reaktywność komponentu.
Uwaga na temat paraglide: rozwiązanie to wstrzykuje kod do Twojej bazy kodu w celu importu; w rezultacie metryka „lib size” w raporcie z benchmarku wynosi prawie 0. Generowanie kodu jest dobrą rzeczą, ponieważ użyta funkcja będzie zawierać tylko niezbędną logikę (prefiks wszędzie vs brak prefiksu, cookie vs storage itp.). Dla porównania, Intlayer wykonuje to filtrowanie poprzez wstrzykiwanie zmiennych środowiskowych podczas budowania (build time), aby wymusić na bundlerze tree-shaking treści w zależności od logiki. Dzięki temu paraglide i intlayer okazują się być od 6 do 10 razy lżejszymi rozwiązaniami niż i18next czy next-intl.
(svelte-i18n) (svelte-i18n@3.4.0):
To rozwiązanie odpowiada na wszystkie potrzeby i18n w projekcie Svelte. Ale podobnie jak w przypadku i18next lub innych głównych rozwiązań i18n, jest ono nieco ciężkie (~15.9kb, co stanowi około 7x svelte-intlayer).
3 - Rekomendacje
(Intlayer) (svelte-intlayer@8.7.12):
Nie będę osobiście oceniać svelte-intlayer ze względu na obiektywizm, ponieważ jest to moje własne rozwiązanie.
Notatka osobista
Ta notatka jest osobista i nie wpływa na wyniki benchmarku. Mimo to w świecie i18n często widać konsensus wokół wzorca takiego jak const t = useTranslation('xx') + <>{t('xx.xx')}</> dla treści przetłumaczonych.
W aplikacjach Svelte wstrzykiwanie funkcji jako Slot jest moim zdaniem antywzorcem. Dodaje to również złożoność, której można uniknąć, oraz narzut na wykonywanie JavaScriptu (nawet jeśli jest on ledwo zauważalny).