Pose una domanda e ottieni un riassunto del documento facendo riferimento a questa pagina e al provider AI di tua scelta
Il contenuto di questa pagina è stato tradotto con un'IA.
Vedi l'ultima versione del contenuto originale in ingleseSe hai un’idea per migliorare questa documentazione, non esitare a contribuire inviando una pull request su GitHub.
Collegamento GitHub alla documentazioneCopia il Markdown del documento nella porta-documenti
i18next VS Intlayer | Benchmark di internazionalizzazione (i18n) per React e Next.js
i18next è il framework di i18n più diffuso nell'ecosistema JavaScript. Attraverso react-i18next e next-i18next, alimenta un'ampia quota di applicazioni React e Next.js. Intlayer è un'alternativa basata su compilatore e con ambito per componente.
Questo articolo li mette a confronto attraverso misurazioni concrete anziché elenchi di funzionalità. I dati provengono da Benchmark Bloom, una suite open source che compila la stessa applicazione con ciascuna libreria e registra ciò che il browser scarica effettivamente.
tl;dr:i18nextè il runtime più pesante del benchmark: +77 KB gzip per pagina su Next.js nella configurazione standard (naive), +22 KB dopo l'ottimizzazione completa con namespace e lazy loading. Intlayer aggiunge appena +0.3 KB. Ogni configurazione dii18next, tranne quella completamente isolata (scoped), include ~90% di stringhe di pagine non visitate; Intlayer ne include lo 0% per impostazione predefinita. Il cambio di lingua con backend caricato in modalità lazy ha richiesto 123-185 ms conreact-i18nextcontro 3-4 ms con Intlayer. L'adattatore@intlayer/next-i18nextconserva l'API dii18nexte si attesta a 150.7 KB per pagina rispetto ai 218.5 KB dell'originale.
In sintesi
- i18next / react-i18next / next-i18next - Maturo, ricco di plugin e indipendente dal framework. Namespace, rilevatori di lingua, backend, ICU tramite plugin,
<Trans>per contenuti avanzati. I contenuti sono centralizzati inlocales/{lng}/{ns}.json. Potente, ma ogni ottimizzazione (divisione in namespace, caricamento per pagina, sicurezza dei tipi) richiede configurazioni manuali a carico dello sviluppatore. - Intlayer - Modello incentrato sui componenti. I dizionari
.content.tsrisiedono accanto al componente a cui sono destinati, un compilatore in fase di build applica tree-shaking e lazy loading per componente e per lingua, tipi TypeScript rigorosi vengono generati automaticamente dai contenuti e le traduzioni mancanti bloccano la compilazione. Include middleware, helper SEO, un editor visuale / CMS e traduzione assistita da IA.
Apri la tabella in una finestra modale per visualizzare tutti i dati in modo chiaro
I badge si aggiornano automaticamente. Le metriche variano nel tempo.
Confronto delle caratteristiche
Apri la tabella in una finestra modale per visualizzare tutti i dati in modo chiaro
| Caratteristica | Intlayer (react-intlayer / next-intlayer) | i18next (react-i18next / next-i18next) |
|---|---|---|
| Traduzioni vicine ai componenti | ✅ Sì, .content.ts posizionato accanto a ogni componente | ❌ No, cartella centralizzata locales/{lng}/{ns}.json |
| Integrazione con TypeScript | ✅ Tipi rigorosi generati in automatico dai contenuti | ⚠️ Base; richiede estensione manuale di CustomTypeOptions e tipizzazione |
| Rilevamento traduzioni mancanti | ✅ Errore TypeScript + errore/avviso in fase di compilazione | ⚠️ Fallback a runtime (saveMissing, restituzione della chiave) |
| Contenuti avanzati (JSX / Markdown) | ✅ Supporto nativo | ⚠️ <Trans> con segnaposto indicizzati |
| Supporto ICU | ⚠️ In lavorazione | ⚠️ Tramite plugin (i18next-icu) |
| Pluralizzazione | ✅ Modelli basati su enumerazioni | ✅ Suffissi _one / _other (Intl.PluralRules) |
| Formattazione (date, numeri, valute) | ✅ useNumber, useDate, ... (Intl integrato) | ⚠️ Formattatori di interpolazione o chiamate manuali a Intl.* |
| Routing localizzato e middleware | ✅ Proxy/middleware integrato, getMultilingualUrls | ⚠️ Non nativo; richiede middleware personalizzato o di terze parti |
| Helper SEO (hreflang, sitemap, robots) | ✅ Helper integrati | ❌ Manuale |
| Componenti server sincroni | ✅ useIntlayer da next-intlayer/server utilizzabile in ogni server component | ⚠️ getFixedT a livello di pagina, poi t passato come prop |
| Tree-shaking (carica solo contenuti usati) | ✅ Per componente, per lingua, automatizzato dal compilatore | ⚠️ Manuale: namespace + lista ns per pagina + backend |
| Lazy loading | ✅ importMode: 'dynamic' (una riga di configurazione) | ✅ Tramite plugin backend (i18next-resources-to-backend, i18next-http-backend) |
| Eliminazione contenuti inutilizzati | ✅ I dizionari orfani vengono scartati in fase di compilazione | ❌ Non integrato |
| Test traduzioni mancanti (CLI / CI) | ✅ npx intlayer content test | ⚠️ i18next-parser / strumenti di terze parti |
| Traduzione assistita da IA | ✅ Integrata, utilizza le tue chiavi API | ❌ No (Locize è un servizio a pagamento separato) |
| Editor Visuale / CMS | ✅ Editor Visuale gratuito + CMS opzionale | ❌ No (Locize / piattaforme esterne) |
| Server MCP e Agent Skills | ✅ Sì | ❌ No |
| Ecosistema e community | ⚠️ Più recente ma in rapida espansione | ✅ Il più esteso e consolidato |
Il benchmark
Cosa è stato misurato
La suite Benchmark Bloom costruisce la medesima applicazione con ciascuna libreria: 10 pagine (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), 10 lingue (en, fr, es, de, it, pt, zh, ja, ko, ru), componenti e contenuti identici. Le pagine sono misurate in en e fr. Ogni libreria viene testata con un massimo di quattro strategie di caricamento:
Apri la tabella in una finestra modale per visualizzare tutti i dati in modo chiaro
| Strategia | Descrizione | Casi d'uso tipici |
|---|---|---|
| static | Tutte le lingue e pagine raggruppate (resources incorporate in init()) | Prototipi veloci, codice generato da IA |
| dynamic | Solo la lingua attiva viene caricata via backend, ma tutti i namespace contemporaneamente | La maggior parte dei progetti |
| scoped-static | Un namespace per percorso, tutti inclusi in anticipo | Raro |
| scoped-dynamic | Un namespace per percorso + lazy loading tramite backend. Solo pagina e lingua correnti | Applicazioni con vincoli di performance stringenti |
Intlayer non necessita di una variante "scoped": il compilatore suddivide i contenuti per componente in modo del tutto automatico, per cui le righe static e dynamic sono già ottimizzate.
Per ciascuna build, la suite registra:
- Lib size: dimensione gzip di un componente vuoto che importa esclusivamente la libreria i18n.
- Page JS: JavaScript gzip scaricato per pagina, mediato su tutte le pagine e lingue.
- Locale leak %: percentuale di stringhe tradotte nel JS scaricato appartenenti a una lingua che l'utente non sta visualizzando.
- Page leak %: percentuale di stringhe tradotte nel JS scaricato appartenenti a pagine in cui l'utente non si trova.
- Component avg: dimensione media gzip di ciascun componente compilato isolatamente.
- E2E reactivity: intervallo reale tra la selezione di una nuova lingua e l'aggiornamento di
html[lang]nel DOM (Playwright, 5 iterazioni). - Hydration: durata della fase di idratazione di React.
I dati seguenti si riferiscono al test del 2026-09-12 connext-i18next16.3.0,react-i18next17.0.13 eintlayer9.5.1. L'applicazione di test è volutamente contenuta (poche decine di stringhe per lingua), pertanto le percentuali di dispersione mostrano un modello: crescono insieme ai contenuti mentre il costo del runtime rimane costante.
Risultati su Next.js (next-i18next)
Apri la tabella in una finestra modale per visualizzare tutti i dati in modo chiaro
| Libreria | Strategia | Lib size (gz) | Page JS avg (gz) | Locale leak | Page leak | Component avg (gz) | Reattività E2E | Hydration |
|---|---|---|---|---|---|---|---|---|
| base (senza i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
next-i18next | static | 19.7 KB | 218.5 KB | 0.0% | 89.8% | 78.5 KB | 16.4 ms | 15.6 ms |
next-i18next | dynamic | 19.7 KB | 169.5 KB | 50.0% | 89.8% | 26.1 KB | 15.4 ms | 27.7 ms |
next-i18next | scoped-static | 19.7 KB | 220.1 KB | 0.0% | 89.8% | 78.9 KB | 16.4 ms | 14.7 ms |
next-i18next | scoped-dynamic | 19.7 KB | 163.4 KB | 0.0% | 0.0% | 27.1 KB | 15.9 ms | 15.1 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-i18next (compat) | static | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 10.7 ms | 11.3 ms |
@intlayer/next-i18next (compat) | dynamic | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 11.9 ms | 10.6 ms |
Come interpretare i dati
- Costo del runtime. Il core di
i18nextabbinato areact-i18nextè il runtime più consistente: 19.7 KB gzip per un componente vuoto, rispetto ai 5.5 KB dinext-intlayer. - La configurazione base è onerosa. Incorporare
resourcesininit()produce 218.5 KB per pagina, +77.5 KB rispetto all'applicazione priva di i18n. Ogni pagina include tutti i namespace. - Ottimizzare richiede lavoro. Passare a un backend (
dynamic) risparmia 49 KB ma disperde ancora il 90% delle stringhe di altre pagine e, in questo scenario, la metà delle stringhe appartiene alla lingua errata. Aggiungere la divisione per namespace su ogni route (scoped-dynamic) raggiunge lo 0% di dispersione a 163.4 KB, rimanendo comunque +22.4 KB per pagina sopra Intlayer (141.3 KB), che non ha richiesto alcuna configurazione speciale. - Dimensioni dei componenti. Un componente con
useTranslation()compila tra i 26 e i 79 KB; lo stesso componente conuseIntlayer()si attesta a 6.9 KB. - L'idratazione sale a 27.7 ms nella configurazione
dynamic: l'istanza i18next si inizializza e risolve il proprio backend sul client prima che React possa idratare la pagina.
Risultati su TanStack Start (react-i18next)
Stessa applicazione di prova su TanStack Start con react-i18next puro, isolando la comparazione dalle specificità di Next.js.
Apri la tabella in una finestra modale per visualizzare tutti i dati in modo chiaro
| Libreria | Strategia | Lib size (gz) | Page JS avg (gz) | Locale leak | Page leak | Component avg (gz) | Reattività E2E | Hydration |
|---|---|---|---|---|---|---|---|---|
| base (no i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms | 21.6 ms |
react-i18next | static | 18.4 KB | 180.3 KB | 50.0% | 89.8% | 24.3 KB | 12.9 ms | 85.1 ms |
react-i18next | dynamic | 18.4 KB | 136.4 KB | 23.1% | 89.8% | 24.8 KB | 123.1 ms | 32.9 ms |
react-i18next | scoped-static | 18.4 KB | 184.2 KB | 50.7% | 89.8% | 25.3 KB | 185.1 ms | 25.2 ms |
react-i18next | scoped-dynamic | 18.4 KB | 127.2 KB | 0.0% | 0.0% | 26.7 KB | 17.6 ms | 11.3 ms |
intlayer | static | 5.0 KB | 125.8 KB | 50.0% | 0.0% | 8.1 KB | 3.2 ms | 11.5 ms |
intlayer | dynamic | 5.0 KB | 118.6 KB | 0.0% | 0.0% | 6.3 KB | 3.6 ms | 14.1 ms |
Come interpretare i dati
- L'app
react-i18nextdi base trasmette +69 KB per pagina rispetto all'applicazione senza i18n, e l'idratazione impiega 85 ms (4 volte il valore di base) perché l'albero completo delle risorse viene elaborato e registrato sul client prima del rendering iniziale. - Il cambio di lingua rende evidente la latenza del lazy loading. Quando le risorse vengono caricate al bisogno, il cambio lingua comporta una chiamata di rete prima dell'aggiornamento di
html[lang]: 123 ms indynamic, 185 ms inscoped-static. Intlayer aggiorna il DOM in 3-4 ms in entrambe le modalità: la modifica è istantanea e non dipende da richieste di rete. - L'assetto interamente ottimizzato
scoped-dynamictocca lo 0% di dispersione a 127.2 KB, rimanendo comunque +8.6 KB sopra la rigadynamicdi Intlayer, e ha richiesto una mappatura route-namespace, un backend di risorse e confini Suspense dedicati. - La riga
staticdi Intlayer ha già 0% di dispersione di pagina poiché vengono inclusi solo i dizionari importati dai componenti effettivi della pagina. AbilitandoimportMode: 'dynamic'si azzera anche la dispersione linguistica. - Dimensioni componenti: 24-27 KB con
react-i18nextcontro 6-8 KB con Intlayer.useTranslation()vincola ogni componente all'istanza globale di i18next.
Origine del divario: Istanza globale vs dizionari compilati
i18next è nato nel 2012 come runtime: un'istanza globale mantiene un archivio di risorse, i plugin la espandono e t() ricerca le chiavi a runtime. Tale architettura garantisce grande versatilità (qualsiasi framework, backend e formato), ma introduce inevitabilmente overhead:
Copiare il codice nella clipboard
L'istanza non può anticipare le chiavi richieste da un componente. Ottimizzare significa che tu devi suddividere i file in namespace, tu devi elencare i namespace richiesti da ogni pagina e tu devi mantenere allineata la lista quando i componenti vengono spostati. Come riportato nelle note del benchmark: "mantenere la sicurezza dei tipi e sapere esattamente quale namespace includere su quale pagina è un incubo".
Intlayer elimina l'istanza globale. I contenuti sono dichiarati accanto al componente e il compilatore risolve il grafico delle dipendenze durante il build:
Copiare il codice nella clipboard
@intlayer/swc / @intlayer/babel analizza quale componente importa quale dizionario, impacchetta esclusivamente quelli utili per la lingua corrente e scarta il resto. Il pattern "scoped-dynamic" diventa il risultato naturale del build anziché un onere manuale.
Per ottenere i parametri della rigadynamic, impostadictionary.importMode: 'dynamic'inintlayer.config.ts. Consulta la guida all'ottimizzazione del bundle.
Esperienza di sviluppo
Configurazione
next-i18next (App Router)
Copiare il codice nella clipboard
A questo si aggiunge un I18nProvider client che reinizializza l'istanza con le medesime opzioni, generateStaticParams e un elenco namespaces per ciascuna pagina.
Intlayer
Copiare il codice nella clipboard
Copiare il codice nella clipboard
Componente client
react-i18next
Copiare il codice nella clipboard
Copiare il codice nella clipboard
La pagina che renderizza questo componente deve caricare il namespaceabout, et("counter.label")rimane una stringa semplice finché non si estendeCustomTypeOptions.
Intlayer
Copiare il codice nella clipboard
Copiare il codice nella clipboard
label e increment sono tipizzati rigorosamente: ogni errore di battitura genera un errore TypeScript e una traduzione mancante blocca la compilazione.
Componente server sincrono
next-i18next
Copiare il codice nella clipboard
La pagina invoca i18n.getFixedT(locale, "about") e trasmette t e locale verso il basso tramite props.
Intlayer
Copiare il codice nella clipboard
Conserva l'API di i18next, sfrutta le prestazioni di Intlayer
Non serve riscrivere i componenti per beneficiare dei numeri del benchmark. @intlayer/i18next, @intlayer/react-i18next e @intlayer/next-i18next sono adattatori compatibili pronti all'uso: useTranslation, t(), <Trans>, {{interpolation}}, plurali _one / _other, suffissi di contesto e returnObjects continuano a funzionare, erogati tramite i dizionari compilati da Intlayer.
Copiare il codice nella clipboard
Copiare il codice nella clipboard
Nel benchmark, la versione con adattatore della medesima app Next.js è passata da 218.5 KB a 150.7 KB per pagina, da 78.5 KB a 9.7 KB per componente, da ~90% di dispersione a 0%, e l'idratazione da 15.6 ms a 11.3 ms, senza alterare il codice dell'applicazione. I file esistenti locales/{lng}/{ns}.json possono rimanere la sorgente primaria dei dati tramite il plugin di sincronizzazione JSON.
Consulta le guide di migrazione: i18next, react-i18next, next-i18next.
Quando scegliere quale soluzione?
- Scegli i18next se necessiti del suo ecosistema di plugin (rilevatori, backend, ICU, Locize), se gestisci la localizzazione anche fuori da React (servizi Node, vanilla JS, altri framework), se il tuo team ha già consolidata esperienza o se una piattaforma di traduzione richiede
locales/{lng}/{ns}.json. Considera il tempo necessario per organizzare i namespace, configurare un backend e mantenere aggiornata la mappa delle route se le performance sono critiche. - Scegli Intlayer se desideri contenuti integrati a livello di componente, TypeScript rigoroso, errori in fase di build per chiavi mancanti, tree-shaking e lazy loading a costo zero, cambio lingua istantaneo, componenti server sincroni e strumenti editoriali integrati (editor visuale, CMS, traduzione con IA, server MCP). Ideale per codebase modulari e design system.
- Scegli gli adattatori
@intlayer/*-i18nextse utilizzi già i18next e vuoi ottenere vantaggi immediati su bundle e reattività senza riscrivere i componenti.
Confronti correlati
- next-intl vs Intlayer (stesso benchmark)
- Lingui vs Intlayer (stesso benchmark)
- vue-i18n vs Intlayer benchmark (stesso benchmark)
- next-i18next vs next-intl vs Intlayer
- react-i18next vs react-intl vs Intlayer
- i18next è superato?
Stelle su GitHub
Le stelle su GitHub rispecchiano la popolarità, la fiducia della community e la rilevanza a lungo termine di un progetto. Pur non misurando direttamente la qualità tecnica, mostrano quanti sviluppatori apprezzano il progetto, ne seguono gli aggiornamenti e intendono adottarlo.
Conclusione
i18next ha meritato il proprio ruolo di riferimento: funziona ovunque, dispone di plugin per ogni esigenza ed è supportato da oltre un decennio. Il benchmark dimostra tuttavia il costo di un'architettura focalizzata sul runtime. Il setup comunemente adottato aggiunge +70-77 KB gzip per pagina, disperde ~90% dei contenuti di altre pagine e richiede più di 100 ms per un cambio lingua con lazy loading. Raggiungere lo 0% di dispersione è possibile, ma impone un backend, un namespace per route e un mapping manuale continuo, rimanendo comunque +9-22 KB sopra Intlayer.
Intlayer delega questo lavoro al compilatore. Dizionari per componente, lazy loading per lingua ed eliminazione dei contenuti orfani sono artefatti del build anziché convenzioni da gestire manualmente. Sulla stessa applicazione: +0.3 KB per pagina, 0% di dispersione, componenti da 3 a 10 volte più leggeri e cambio lingua in 3-4 ms.
Tutti i dati grezzi, le applicazioni di prova e gli script sono consultabili nel repository Benchmark Bloom. Puoi verificarli direttamente.
Per ulteriori dettagli consulta il documento 'Perché Intlayer?'.
Commenti
Ancora nessun commento. Sii il primo a condividere i tuoi pensieri.
