Autore:
    Creazione:2026-04-20Ultimo aggiornamento:2026-05-18

    Librerie i18n per Solid - Rapporto Benchmark 2026

    Questa pagina è un rapporto di benchmark per le soluzioni i18n su Solid.

    Sommario

    Benchmark Interattivo

    Riferimento dei risultati:

    intlayer.org
    Visualizza i dati completi del benchmark

    Vedi il repository completo del benchmark qui.

    Introduzione

    Le soluzioni di internazionalizzazione sono tra le dipendenze più pesanti in un'app Solid. Il rischio principale è l'invio di contenuti non necessari: traduzioni per altre pagine e altre lingue nel bundle di una singola rotta.

    Man mano che l'app cresce, questo problema può far esplodere rapidamente il JavaScript inviato al client e rallentare la navigazione.

    In pratica, per le implementazioni meno ottimizzate, una pagina internazionalizzata può finire per essere diverse volte più pesante della versione senza i18n.

    L'autre impatto riguarda l'esperienza dello sviluppatore (DX): come si dichiara il contenuto, i tipi, l'organizzazione dei namespace, il caricamento dinamico e la reattività al cambio di lingua.

    TL;DR

    • Intlayer: Scelta consigliata per applicazioni Solid professionali che necessitano di funzionalità avanzate e ottimizzazione (v8.7.12).
    • @solid-primitives/i18n: Eccellente alternativa leggera per progetti semplici, sebbene manchi di funzionalità avanzate come il lazy loading.
    • solid-i18next: Opzione standard ma pesante (~4.7× Intlayer) con gli stessi svantaggi di React i18next.
    • Paraglide: Approccio innovativo ma DX complessa e problemi di tree-shaking in alcune configurazioni.

    Testa la tua app

    Per individuare rapidamente i problemi di leak i18n, ho configurato uno scanner gratuito disponibile qui.

    intlayer.org

    Il problema

    Due leve sono essenziali per limitare il costo di un'app multilingue:

    • Dividere il contenuto per pagina / namespace per non caricare interi dizionari quando non servono.
    • Caricare la lingua corretta in modo dinamico, solo quando necessario.

    Comprendere i limiti tecnici di questi approcci:

    Caricamento dinamico

    Senza caricamento dinamico, la maggior parte delle soluzioni mantiene i messaggi in memoria fin dal primo render, aggiungendo un overhead significativo per le app con molte rotte e lingue.

    Con il caricamento dinamico, si accetta un compromesso: meno JS iniziale, ma a volte una richiesta extra quando si cambia lingua.

    Divisione dei contenuti (Splitting)

    Le sintassi costruite attorno a t('a.b.c') sono molto comode ma spesso incoraggiano a mantenere grandi oggetti JSON a runtime. Questo modello rende difficile il tree-shaking a meno che la libreria non offra una reale strategia di divisione per pagina.

    Metodologia

    Per questo benchmark, abbiamo confrontato le seguenti librerie:

    • Base App (Nessuna libreria i18n)
    • solid-intlayer (v8.7.12)
    • @solid-primitives/i18n (v2.2.1)
    • solid-i18next (v17.0.2)
    • @inlang/paraglide-js (v2.17.0)

    Il framework è Solid con un'app multilingue di 10 pagine e 10 lingue.

    Abbiamo confrontato quattro strategie di caricamento:

    Strategia Senza namespace (globale) Con namespace (scoped)
    Caricamento statico Static: Tutto in memoria all'avvio. Scoped static: Diviso per namespace; tutto caricato all'avvio.
    Caricamento dinamico Dynamic: Caricamento on-demand per lingua. Scoped dynamic: Caricamento granulare per namespace e lingua.

    Riepilogo delle strategie

    • Static: Semplice; nessuna latenza di rete dopo il caricamento iniziale. Svantaggio: grandi dimensioni del bundle.
    • Dynamic: Riduce il peso iniziale (lazy-loading). Ideale quando si hanno molte lingue.
    • Scoped static: Mantiene il codice organizzato (separazione logica) senza complesse richieste di rete extra.
    • Scoped dynamic: Il miglior approccio per il code splitting e le prestazioni. Minimizza la memoria caricando solo ciò di cui la vista corrente e la lingua attiva hanno bisogno.

    Ciò che ho misurato:

    Ho eseguito la stessa app multilingue in un vero browser per ogni stack, quindi ho annotato ciò che è effettivamente apparso sulla rete e quanto tempo ha impiegato. Le dimensioni sono riportate dopo la normale compressione web, perché è più vicino a ciò che le persone scaricano rispetto ai conteggi grezzi delle sorgenti.

    • Internationalization library size: Dopo il bundling, tree-shaking e minification, la dimensione della libreria i18n è la dimensione dei provider + codice hooks/primitives in un componente vuoto. Non include il caricamento dei file di traduzione. Risponde a quanto è costosa la libreria prima che il tuo contenuto entri in gioco.

    • JavaScript per page: Per ogni rotta di benchmark, quanti script il browser scarica per quella visita, mediati tra le pagine della suite (e tra le lingue dove il rapporto le raggruppa). Le pagine pesanti sono pagine lente.

    • Leakage from other locales: È il contenuto della stessa pagina ma in un'altra lingua che verrebbe caricato per errore nella pagina sottoposta a audit. Questo contenuto è inutile e dovrebbe essere evitato. (ad es. contenuto della pagina /fr/about nel bundle della pagina /en/about)

    • Leakage from other routes: La stessa idea per altri schermi nell'app: se la loro copia si carica insieme quando hai aperto solo una pagina. (ad es. contenuto della pagina /en/about nel bundle della pagina /en/contact). Un punteggio elevato suggerisce uno splitting debole o bundle troppo ampi.

    • Average component bundle size: I pezzi UI comuni sono misurati uno alla volta invece di nascondersi in un numero gigante dell'app. Mostra se l'internazionalizzazione aumenta silenziosamente i componenti quotidiani. Ad esempio, se il tuo componente viene ripetuto, caricherà tutti i dati dalla memoria. Allegare un giant JSON a qualsiasi componente è come collegare un grande archivio di dati non utilizzati che rallenterà le prestazioni dei tuoi componenti.

    • Language switch responsiveness: Cambio la lingua usando il controllo dell'app e cronometro quanto tempo ci vuole prima che la pagina sia chiaramente cambiata, quello che un visitatore noterebbe, non un micro-step di laboratorio.

    • Rendering work after a language change: Un follow-up più mirato: quanto sforzo ha richiesto all'interfaccia di ridipingere per la nuova lingua una volta che lo switch è in volo. Utile quando il tempo "percepito" e il costo del framework divergono.

    • Initial page load time: Dalla navigazione al browser che considera la pagina completamente caricata per gli scenari che ho testato. Buono per confrontare i cold start.

    • Hydration time: Quando l'app lo espone, quanto tempo il client spende a trasformare l'HTML del server in qualcosa su cui puoi effettivamente fare clic. Un trattino nelle tabelle significa che quella implementazione non ha fornito una figura di hydration affidabile in questo benchmark.

    Stelle di GitHub

    Le stelle di GitHub sono un forte indicatore della popolarità di un progetto, della fiducia della comunità e della pertinenza a lungo termine. Sebbene non siano una misura diretta della qualità tecnica, riflettono quanti sviluppatori trovano il progetto utile, ne seguono i progressi e sono propensi ad adottarlo. Per stimare il valore di un progetto, le stelle aiutano a confrontare la trazione tra le alternative e forniscono approfondimenti sulla crescita dell'ecosistema.

    Star History Chart

    Risultati in dettaglio

    1 - Soluzioni da evitare

    Nessuna soluzione chiara da evitare nell'ecosistema Solid.

    2 - Soluzioni accettabili

    (solid-i18next) (solid-i18next@17.0.2):

    solid-i18next è probabilmente l'opzione più popolare perché è stata tra le prime a soddisfare le esigenze i18n delle app JavaScript. Dispone inoltre di un ampio set di plugin della comunità per problemi specifici.

    Il pacchetto è pesante (~14.6kb, circa 4.7 volte solid-intlayer).

    Tuttavia, condivide gli stessi principali svantaggi degli stack costruiti su t('a.b.c'): le ottimizzazioni sono possibili ma richiedono molto tempo, e i grandi progetti rischiano cattive pratiche (namespace + caricamento dinamico + tipi).

    (@solid-primitives/i18n) (@solid-primitives/i18n@2.2.1):

    Solid primitive è estremamente leggero ed efficiente. Consiglio questa soluzione per progetti leggeri, ma può mancare rapidamente di funzionalità per soluzioni professionali incluse la gestione dei cookie, il reindirizzamento proxy, i formattatori ecc. Manca inoltre del lazy loading e dello scoping dei namespace per l'ottimizzazione delle dimensioni della pagina.

    (Paraglide) (@inlang/paraglide-js@2.17.0):

    Paraglide offre un approccio innovativo e ben ponderato. Tuttavia, in questo benchmark il tree-shaking pubblicizzato dalla loro azienda non ha funzionato per la mia implementazione. Il workflow e la DX sono inoltre più complessi rispetto ad altre opzioni. Personalmente, non amo dover rigenerare file JS prima di ogni push, il che crea un costante rischio di conflitti di merge tramite le PR. Infine, rispetto ad altre soluzioni, Paraglide non utilizza uno store (es. Solid signal) per recuperare la lingua corrente per renderizzare il contenuto. Per ogni nodo analizzato, richiederà la lingua al localStorage / cookie ecc. Ciò porta all'esecuzione di logica non necessaria che impatta sulla reattività del componente.

    3 - Raccomandazioni

    (Intlayer) (solid-intlayer@8.7.12):

    Non giudicherò personalmente solid-intlayer per motivi di obiettività, essendo la mia soluzione.

    Nota personale

    Questa nota è personale e non influisce sui risultati del benchmark. Tuttavia, nel mondo i18n si vede spesso un consenso attorno a un pattern come const t = useTranslation('xx') + <>{t('xx.xx')}</> per i contenuti tradotti.

    Nelle app Solid, iniettare una funzione come JSX.Element è, a mio avviso, un anti-pattern. Aggiunge inoltre una complessità evitabile e un overhead di esecuzione JavaScript (anche se appena percettibile).