Ricevi notifiche sui prossimi lanci di Intlayer
    Creazione:2025-08-23Ultimo aggiornamento:2025-09-29

    next-i18next VS next-intl VS intlayer | Internazionalizzazione (i18n) in Next.js

    Diamo un'occhiata alle somiglianze e differenze tra tre opzioni i18n per Next.js: next-i18next, next-intl e Intlayer.

    Questo non è un tutorial completo. È un confronto per aiutarti a scegliere.

    Ci concentriamo su Next.js 13+ App Router (con React Server Components) e valutiamo:

    1. Architettura e organizzazione dei contenuti
    2. TypeScript e sicurezza
    3. Gestione delle traduzioni mancanti
    4. Routing e middleware
    5. Prestazioni e comportamento di caricamento
    6. Esperienza sviluppatore (DX), strumenti e manutenzione
    7. SEO e scalabilità per progetti di grandi dimensioni

    In breve: Tutti e tre possono localizzare un'app Next.js. Se desideri contenuti a livello di componente, tipi TypeScript rigorosi, controlli delle chiavi mancanti in fase di build, dizionari ottimizzati tramite tree-shaking e supporto di prima classe per App Router + helper SEO, Intlayer è la scelta più completa e moderna.

    Una confusione comune tra gli sviluppatori è pensare che next-intl sia la versione Next.js di react-intl. Non è così: next-intl è mantenuto da Amann, mentre react-intl è mantenuto da FormatJS.


    In breve

    • next-intl - Formattazione dei messaggi leggera e semplice con un solido supporto per Next.js. I cataloghi centralizzati sono comuni; l'esperienza sviluppatore (DX) è semplice, ma la sicurezza e la manutenzione su larga scala rimangono per lo più a tuo carico.
    • next-i18next - i18next in versione Next.js. Ecosistema maturo e funzionalità tramite plugin (ad esempio, ICU), ma la configurazione può essere verbosa e i cataloghi tendono a centralizzarsi con la crescita dei progetti.
    • Intlayer - Modello di contenuto incentrato sui componenti per Next.js, tipizzazione TS rigorosa, controlli a tempo di compilazione, tree-shaking, middleware integrati e helper SEO, Editor Visivo/CMS opzionale e traduzioni assistite da AI.

    Library GitHub Stars Total Commits Last Commit First Version NPM Version NPM Downloads
    aymericzip/intlayer GitHub Repo stars GitHub commit activity Last Commit April 2024 npm npm downloads
    amannn/next-intl GitHub Repo stars GitHub commit activity Last Commit Nov 2020 npm npm downloads
    i18next/i18next GitHub Repo stars GitHub commit activity Last Commit Jan 2012 npm npm downloads
    i18next/next-i18next GitHub Repo stars GitHub commit activity Last Commit Nov 2018 npm npm downloads

    I badge si aggiornano automaticamente. Gli snapshot varieranno nel tempo.


    Confronto delle funzionalità affiancate (focalizzato su Next.js)

    | Funzionalità | next-intlayer (Intlayer) | next-intl | next-i18next |

    I badge si aggiornano automaticamente. Gli snapshot varieranno nel tempo.


    Confronto delle Funzionalità Affiancate (focalizzato su Next.js)

    Funzionalità next-intlayer (Intlayer) next-intl next-i18next
    Traduzioni Vicino ai Componenti ✅ Sì, contenuto collocato insieme a ogni componente ❌ No ❌ No
    Integrazione TypeScript ✅ Avanzata, tipi rigorosi generati automaticamente ✅ Buona ⚠️ Base
    Rilevamento Traduzioni Mancanti ✅ Evidenziazione errori TypeScript e errori/avvisi in fase di compilazione ⚠️ Fallback a runtime ⚠️ Fallback a runtime
    Contenuti Ricchi (JSX/Markdown/componenti) ✅ Supporto diretto ❌ Non progettato per nodi ricchi ⚠️ Limitato
    Traduzione basata su AI ✅ Sì, supporta più provider AI. Utilizzabile con le proprie chiavi API. Considera il contesto della tua applicazione e l'ambito del contenuto ❌ No ❌ No
    Editor Visivo ✅ Sì, Editor Visivo locale + CMS opzionale; può esternalizzare il contenuto della codebase; integrabile ❌ No / disponibile tramite piattaforme di localizzazione esterne ❌ No / disponibile tramite piattaforme di localizzazione esterne
    Routing Localizzato ✅ Sì, supporta percorsi localizzati nativamente (funziona con Next.js & Vite) ✅ Integrato, App Router supporta il segmento [locale] ✅ Integrato
    Generazione Dinamica delle Rotte ✅ Sì ✅ Sì ✅ Sì
    Pluralizzazione ✅ Modelli basati su enumerazioni ✅ Buono ✅ Buono
    Formattazione (date, numeri, valute) ✅ Formatter ottimizzati (Intl sotto il cofano) ✅ Buono (helper Intl) ✅ Buono (helper Intl)
    Formato del contenuto ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml WIP) ✅ .json, .js, .ts ⚠️ .json
    Supporto ICU ⚠️ In lavorazione ✅ Sì ⚠️ Tramite plugin (i18next-icu)
    Helper SEO (hreflang, sitemap) ✅ Strumenti integrati: helper per sitemap, robots.txt, metadata ✅ Buono ✅ Buono
    Ecosistema / Comunità ⚠️ Più piccolo ma in rapida crescita e reattivo ✅ Buono ✅ Buono
    Rendering lato server & Componenti Server ✅ Sì, ottimizzato per SSR / Componenti Server React ⚠️ Supportato a livello di pagina ma è necessario passare le funzioni t sull'albero dei componenti per i componenti server figli ⚠️ Supportato a livello di pagina ma è necessario passare le funzioni t sull'albero dei componenti per i componenti server figli
    Tree-shaking (caricamento solo del contenuto usato) ✅ Sì, per componente al momento della build tramite plugin Babel/SWC ⚠️ Parziale ⚠️ Parziale
    Caricamento lazy ✅ Sì, per locale / per dizionario ✅ Sì (per percorso/per locale), necessita gestione dei namespace ✅ Sì (per percorso/per locale), necessita gestione dei namespace
    Rimozione dei contenuti non utilizzati ✅ Sì, per dizionario al momento della build ❌ No, può essere gestito manualmente con la gestione dei namespace ❌ No, può essere gestito manualmente con la gestione dei namespace
    Gestione di progetti di grandi dimensioni ✅ Favorisce la modularità, adatto per sistemi di design ✅ Modulare con configurazione ✅ Modulare con configurazione
    Test delle traduzioni mancanti (CLI/CI) ✅ CLI: npx intlayer content test (audit compatibile con CI) ⚠️ Non integrato; la documentazione suggerisce npx @lingual/i18n-check ⚠️ Non integrato; si fa affidamento sugli strumenti i18next / runtime saveMissing

    Introduzione

    Next.js offre supporto integrato per il routing internazionalizzato (es. segmenti di localizzazione). Ma questa funzionalità non gestisce le traduzioni da sola. Serve comunque una libreria per rendere contenuti localizzati agli utenti.

    Esistono molte librerie i18n, ma nel mondo Next.js oggi tre stanno guadagnando popolarità: next-i18next, next-intl e Intlayer.


    Architettura e scalabilità

    • next-intl / next-i18next: Predefinito a cataloghi centralizzati per locale (più namespace in i18next). Funziona bene all'inizio, ma spesso diventa una grande area condivisa con un aumento del coupling e del churn delle chiavi.
    • Intlayer: Favorisce dizionari per componente (o per funzionalità) co-locati con il codice che servono. Questo riduce il carico cognitivo, facilita la duplicazione/migrazione delle parti dell'interfaccia utente e riduce i conflitti tra team. Il contenuto non utilizzato è naturalmente più facile da individuare ed eliminare.

    Perché è importante: In grandi codebase o configurazioni di design system, il contenuto modulare scala meglio rispetto ai cataloghi monolitici.


    Dimensioni del bundle e dipendenze

    Dopo la compilazione dell'applicazione, il bundle è il JavaScript che il browser caricherà per rendere la pagina. La dimensione del bundle è quindi importante per le prestazioni dell'applicazione.

    Due componenti sono importanti nel contesto di un bundle per applicazioni multilingue:

    • Il codice dell'applicazione
    • Il contenuto caricato dal browser

    Codice dell'applicazione

    L'importanza del codice dell'applicazione è minima in questo caso. Tutte e tre le soluzioni sono tree-shakable, il che significa che le parti di codice non utilizzate non vengono incluse nel bundle.

    Ecco un confronto della dimensione del bundle JavaScript caricato dal browser per un'applicazione multilingue con le tre soluzioni.

    Se non abbiamo bisogno di alcun formatter nell'applicazione, l'elenco delle funzioni esportate dopo il tree-shaking sarà:

    • next-intlayer: useIntlayer, useLocale, NextIntlClientProvider, (La dimensione del bundle è 180.6 kB -> 78.6 kB (gzip))
    • next-intl: useTranslations, useLocale, NextIntlClientProvider, (La dimensione del bundle è 101.3 kB -> 31.4 kB (gzip))
    • next-i18next: useTranslation, useI18n, I18nextProvider, (La dimensione del bundle è 80.7 kB -> 25.5 kB (gzip))

    Queste funzioni sono solo wrapper attorno al contesto/stato di React, quindi l'impatto totale della libreria i18n sulla dimensione del bundle è minimo.

    Intlayer è leggermente più grande di next-intl e next-i18next perché include più logica nella funzione useIntlayer. Questo è legato all'integrazione con markdown e intlayer-editor.

    Contenuti e Traduzioni

    Questa parte è spesso ignorata dagli sviluppatori, ma consideriamo il caso di un'applicazione composta da 10 pagine in 10 lingue. Supponiamo che ogni pagina integri contenuti unici al 100% per semplificare il calcolo (in realtà, molti contenuti sono ridondanti tra le pagine, ad esempio titolo della pagina, intestazione, piè di pagina, ecc.).

    Un utente che desidera visitare la pagina /fr/about caricherà il contenuto di una pagina in una determinata lingua. Ignorare l'ottimizzazione dei contenuti significherebbe caricare inutilmente l'8.200% ((1 + (((10 pagine - 1) × (10 lingue - 1)))) × 100) del contenuto dell'applicazione. Vedi il problema? Anche se questo contenuto rimane testo, e mentre probabilmente preferisci pensare a ottimizzare le immagini del tuo sito, stai inviando contenuti inutili in tutto il mondo e facendo elaborare i computer degli utenti per nulla.

    Due questioni importanti:

    • Suddivisione per percorso:

      Se sono nella pagina /about, non voglio caricare il contenuto della pagina /home

    • Suddivisione per locale:

      Se sono nella pagina /fr/about, non voglio caricare il contenuto della pagina /en/about

    Ancora una volta, tutte e tre le soluzioni sono consapevoli di queste problematiche e permettono di gestire queste ottimizzazioni. La differenza tra le tre soluzioni è l'esperienza dello sviluppatore (DX).

    next-intl e next-i18next utilizzano un approccio centralizzato per gestire le traduzioni, permettendo di suddividere i file JSON per locale e per sotto-file. In next-i18next, chiamiamo i file JSON 'namespaces'; next-intl permette di dichiarare i messaggi. In intlayer, chiamiamo i file JSON 'dictionaries'.

    • Nel caso di next-intl, come in next-i18next, il contenuto viene caricato a livello di pagina/layout, quindi questo contenuto viene caricato in un context provider. Ciò significa che lo sviluppatore deve gestire manualmente i file JSON che verranno caricati per ogni pagina.

    In pratica, questo implica che gli sviluppatori spesso saltano questa ottimizzazione, preferendo caricare tutto il contenuto nel context provider della pagina per semplicità.

    • Nel caso di intlayer, tutto il contenuto viene caricato nell'applicazione. Successivamente un plugin (@intlayer/babel / @intlayer/swc) si occupa di ottimizzare il bundle caricando solo il contenuto utilizzato nella pagina. Lo sviluppatore quindi non deve gestire manualmente i dizionari che verranno caricati. Questo permette una migliore ottimizzazione, una migliore manutenibilità e riduce i tempi di sviluppo.

    Man mano che l'applicazione cresce (soprattutto quando più sviluppatori lavorano sull'applicazione), è comune dimenticare di rimuovere il contenuto che non viene più utilizzato dai file JSON.

    Nota che tutti i file JSON vengono caricati in tutti i casi (next-intl, next-i18next, intlayer).

    Ecco perché l'approccio di Intlayer è più performante: se un componente non viene più utilizzato, il suo dizionario non viene caricato nel bundle.

    È anche importante come la libreria gestisce i fallback. Consideriamo che l'applicazione sia in inglese di default e che l'utente visiti la pagina /fr/about. Se le traduzioni in francese mancano, considereremo il fallback in inglese.

    Nel caso di next-intl e next-i18next, la libreria richiede il caricamento del JSON relativo alla locale corrente, ma anche a quella di fallback. Quindi, considerando che tutto il contenuto è stato tradotto, ogni pagina caricherà il 100% di contenuto non necessario. In confronto, intlayer elabora il fallback al momento della costruzione del dizionario. Pertanto, ogni pagina caricherà solo il contenuto utilizzato.

    Ecco un esempio dell'impatto dell'ottimizzazione della dimensione del bundle utilizzando intlayer in un'applicazione vite + react:

    Bundle ottimizzato Bundle non ottimizzato
    bundle ottimizzato bundle non ottimizzato

    TypeScript e sicurezza

    next-intl

    • Supporto solido per TypeScript, ma le chiavi non sono tipizzate rigorosamente di default; dovrai mantenere manualmente i pattern di sicurezza.

    next-i18next

    • Tipizzazioni di base per gli hook; la tipizzazione rigorosa delle chiavi richiede strumenti/configurazioni aggiuntive.

    intlayer

    • Genera tipi rigorosi dal tuo contenuto. Completamento automatico nell’IDE e errori a tempo di compilazione individuano errori di battitura e chiavi mancanti prima del deploy.

    Perché è importante: La tipizzazione forte sposta i fallimenti a sinistra (CI/build) invece che a destra (runtime).


    Gestione delle traduzioni mancanti

    next-intl

    • Si basa su fallback a runtime (es. mostra la chiave o la locale di default). La build non fallisce.

    next-i18next

    • Si basa su fallback a runtime (es. mostra la chiave o la locale di default). La build non fallisce.

    intlayer

    • Rilevamento a tempo di build con avvisi/errori per locali o chiavi mancanti.

    Perché è importante: Individuare le lacune durante la build previene “stringhe misteriose” in produzione e si allinea con rigide regole di rilascio.


    Routing, middleware e strategia URL

    next-intl

    • Funziona con il routing localizzato di Next.js sull'App Router.

    next-i18next

    • Funziona con il routing localizzato di Next.js sull'App Router.

    intlayer

    • Tutto quanto sopra, più middleware i18n (rilevamento della localizzazione tramite header/cookie) e helper per generare URL localizzati e tag <link rel="alternate" hreflang="…">.

    Perché è importante: Meno livelli di collegamento personalizzati; UX coerente e SEO pulito tra le diverse localizzazioni.


    Allineamento con Server Components (RSC)

    next-intl

    • Supporta Next.js 13+. Spesso richiede di passare funzioni t/formatter attraverso gli alberi dei componenti in configurazioni ibride.

    next-i18next

    • Supporta Next.js 13+. Vincoli simili nel passaggio degli strumenti di traduzione attraverso i confini.

    intlayer

    • Supporta Next.js 13+ e facilita il confine server/client con un'API coerente e provider orientati a RSC, evitando il passaggio continuo di formatter o funzioni t.

    Perché è importante: Modello mentale più pulito e meno casi limite negli alberi ibridi.


    DX, strumenti e manutenzione

    next-intl

    • Comunemente abbinato a piattaforme di localizzazione esterne e flussi editoriali.

    next-i18next

    • Comunemente abbinato a piattaforme di localizzazione esterne e flussi editoriali.

    intlayer

    • Fornisce un Editor Visivo gratuito e un CMS opzionale (compatibile con Git o esternalizzato), oltre a un’estensione VSCode e traduzioni assistite da AI utilizzando le tue chiavi provider.

    Perché è importante: Riduce i costi operativi e accorcia il ciclo tra sviluppatori e autori dei contenuti.

    Integrazione con piattaforme di localizzazione (TMS)

    Le grandi organizzazioni spesso si affidano a Sistemi di Gestione delle Traduzioni (TMS) come Crowdin, Phrase, Lokalise, Localizely o Localazy.

    • Perché interessa alle aziende

      • Collaborazione e ruoli: Sono coinvolti più attori: sviluppatori, product manager, traduttori, revisori, team marketing.
      • Scala ed efficienza: localizzazione continua, revisione in contesto.
    • next-intl / next-i18next

      • Tipicamente utilizzano cataloghi JSON centralizzati, quindi l'esportazione/importazione con TMS è semplice.
      • Ecosistemi maturi ed esempi/integrazioni per le piattaforme sopra menzionate.
    • Intlayer

      • Favorisce dizionari decentralizzati per componente e supporta contenuti in TypeScript/TSX/JS/JSON/MD.
      • Questo migliora la modularità nel codice, ma può rendere più difficile l'integrazione plug-and-play con TMS quando uno strumento si aspetta file JSON centralizzati e piatti.
      • Intlayer offre alternative: traduzioni assistite da AI (usando le tue chiavi provider), un Editor Visivo/CMS e workflow CLI/CI per rilevare e precompilare le lacune.

    Nota: next-intl e i18next accettano anche cataloghi TypeScript. Se il tuo team memorizza i messaggi in file .ts o li decentralizza per funzionalità, potresti incontrare attriti simili con il TMS. Tuttavia, molte configurazioni di next-intl rimangono centralizzate in una cartella locales/, che è un po' più facile da rifattorizzare in JSON per il TMS.

    Esperienza dello Sviluppatore

    Questa parte fa un confronto approfondito tra le tre soluzioni. Piuttosto che considerare casi semplici, come descritto nella documentazione 'getting started' per ogni soluzione, considereremo un caso d'uso reale, più simile a un progetto reale.

    Struttura dell'app

    La struttura dell'app è importante per garantire una buona manutenibilità del tuo codice.

    .├── locales│   ├── en│   │  ├── home.json│   │  └── navbar.json│   ├── fr│   │  ├── home.json│   │  └── navbar.json│   └── es│      ├── home.json│      └── navbar.json├── i18n.ts└── src    ├── middleware.ts    ├── app    │   └── home.tsx    └── components        └── Navbar            └── index.tsx

    Confronto

    • next-intl / next-i18next: Cataloghi centralizzati (JSON; namespace/messaggi). Struttura chiara, si integra bene con le piattaforme di traduzione, ma può portare a modifiche incrociate tra file man mano che le app crescono.
    • Intlayer: Dizionari .content.{ts|js|json} per componente co-localizzati con i componenti. Facilita il riuso dei componenti e il ragionamento locale; aggiunge file e si basa su strumenti di build-time.

    Configurazione e caricamento del contenuto

    Come accennato in precedenza, è necessario ottimizzare il modo in cui ogni file JSON viene importato nel tuo codice. Il modo in cui la libreria gestisce il caricamento dei contenuti è importante.

    i18n.ts
    import { getRequestConfig } from "next-intl/server";import { notFound } from "next/navigation";// Può essere importato da una configurazione condivisaconst locales = ["en", "fr", "es"];export default getRequestConfig(async ({ locale }) => {  // Verifica che il parametro `locale` in ingresso sia valido  if (!locales.includes(locale as any)) notFound();  return {    messages: (await import(`../messages/${locale}.json`)).default,  };});
    src/app/[locale]/about/layout.tsx
    import { NextIntlClientProvider } from "next-intl";import { getMessages, unstable_setRequestLocale } from "next-intl/server";import pick from "lodash/pick";export default async function LocaleLayout({  children,  params,}: {  children: React.ReactNode;  params: { locale: string };}) {  const { locale } = params;  // Imposta la locale attiva per questa richiesta di rendering server (RSC)  unstable_setRequestLocale(locale);  // I messaggi sono caricati lato server tramite src/i18n/request.ts  // (vedi documentazione next-intl). Qui inviamo solo un sottoinsieme al client  // necessario per i componenti client (ottimizzazione del payload).  const messages = await getMessages();  const clientMessages = pick(messages, ["common", "about"]);  return (    <html lang={locale}>      <body>        <NextIntlClientProvider locale={locale} messages={clientMessages}>          {children}        </NextIntlClientProvider>      </body>    </html>  );}
    src/app/[locale]/about/page.tsx
    import { getTranslations } from "next-intl/server";import { ClientComponent, ServerComponent } from "@components";export default async function LandingPage({  params,}: {  params: { locale: string };}) {  // Caricamento strettamente lato server (non idratato sul client)  const t = await getTranslations("about");  return (    <main>      <h1>{t("title")}</h1>      <ClientComponent />      <ServerComponent />    </main>  );}

    Confronto

    Tutti e tre supportano il caricamento di contenuti e provider per locale.

    • Con next-intl/next-i18next, di solito carichi i messaggi/namespace selezionati per ogni percorso e posizioni i provider dove necessario.

    • Con Intlayer, viene aggiunta un'analisi in fase di build per dedurre l'uso, il che può ridurre la configurazione manuale e permettere un singolo provider radice.

    Scegli tra controllo esplicito e automazione in base alle preferenze del team.

    Uso in un componente client

    Prendiamo un esempio di un componente client che rende un contatore.

    Traduzioni (struttura riutilizzata; caricale nei messaggi di next-intl come preferisci)

    locales/en/about.json
    {  "counter": {    "label": "Counter",    "increment": "Increment"  }}
    locales/fr/about.json
    {  "counter": {    "label": "Compteur",    "increment": "Incrémenter"  }}

    Componente client

    src/components/ClientComponentExample.tsx
    "use client";import React, { useState } from "react";import { useTranslations, useFormatter } from "next-intl";const ClientComponentExample = () => {  // Ambito direttamente sull'oggetto annidato  const t = useTranslations("about.counter");  const format = useFormatter();  const [count, setCount] = useState(0);  return (    <div>      <p>{format.number(count)}</p>      <button        aria-label={t("label")}        onClick={() => setCount((count) => count + 1)}      >        {t("increment")}      </button>    </div>  );};

    Non dimenticare di aggiungere il messaggio "about" nel messaggio client della pagina

    Confronto

    • Formattazione dei numeri

      • next-i18next: nessun useNumber; utilizza Intl.NumberFormat (o i18next-icu).
      • next-intl: useFormatter().number(value).
      • Intlayer: useNumber() integrato.
    • Chiavi

      • Mantieni una struttura annidata (about.counter.label) e definisci l’ambito del tuo hook di conseguenza (useTranslation("about") + t("counter.label") oppure useTranslations("about.counter") + t("label")).
    • Posizione dei file

      • next-i18next si aspetta JSON in public/locales/{lng}/{ns}.json.
      • next-intl è flessibile; carica i messaggi come preferisci.
      • Intlayer memorizza i contenuti in dizionari TS/JS e risolve tramite chiave.

    Utilizzo in un componente server

    Prendiamo il caso di un componente UI. Questo componente è un componente server e dovrebbe poter essere inserito come figlio di un componente client. (pagina (componente server) -> componente client -> componente server). Poiché questo componente può essere inserito come figlio di un componente client, non può essere async.

    src/components/ServerComponent.tsx
    type ServerComponentProps = {  count: number;  t: (key: string) => string;};const ServerComponent = ({ t, count }: ServerComponentProps) => {  const formatted = new Intl.NumberFormat(i18n.language).format(count);  return (    <div>      <p>{formatted}</p>      <button aria-label={t("label")}>{t("increment")}</button>    </div>  );};

    Poiché il componente server non può essere asincrono, è necessario passare le traduzioni e la funzione di formattazione come props.

    • const t = await getTranslations("about.counter");
    • const format = await getFormatter();

    Intlayer espone hook sicuri per il server tramite next-intlayer/server. Per funzionare, useIntlayer e useNumber utilizzano una sintassi simile agli hook client, ma dipendono internamente dal contesto server (IntlayerServerProvider).

    Metadata / Sitemap / Robots

    Tradurre i contenuti è ottimo. Ma spesso si dimentica che l'obiettivo principale dell'internazionalizzazione è rendere il tuo sito web più visibile al mondo. L'i18n è una leva incredibile per migliorare la visibilità del tuo sito web.

    Ecco una lista di buone pratiche riguardanti la SEO multilingue.

    • impostare i meta tag hreflang nel tag <head> > Aiuta i motori di ricerca a capire quali lingue sono disponibili nella pagina
    • elencare tutte le traduzioni delle pagine nel sitemap.xml utilizzando lo schema XML http://www.w3.org/1999/xhtml >
    • non dimenticare di escludere le pagine con prefisso dal robots.txt (es. /dashboard, e /fr/dashboard, /es/dashboard) >
    • utilizzare un componente Link personalizzato per reindirizzare alla pagina più localizzata (es. in francese <a href="/fr/about">A propos</a>) >

    Gli sviluppatori spesso dimenticano di referenziare correttamente le loro pagine tra le diverse localizzazioni.

    src/app/[locale]/about/layout.tsx
    import type { Metadata } from "next";import { locales, defaultLocale } from "@/i18n";import { getTranslations } from "next-intl/server";function localizedPath(locale: string, path: string) {  return locale === defaultLocale ? path : "/" + locale + path;}export async function generateMetadata({  params,}: {  params: { locale: string };}): Promise<Metadata> {  const { locale } = params;  const t = await getTranslations({ locale, namespace: "about" });  const url = "/about";  const languages = Object.fromEntries(    locales.map((locale) => [locale, localizedPath(locale, url)])  );  return {    title: t("title"),    description: t("description"),    alternates: {      canonical: localizedPath(locale, url),      languages: { ...languages, "x-default": url },    },  };}// ... Resto del codice della pagina
    src/app/sitemap.ts
    import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const formatterLocalizedPath = (locale: string, path: string) =>  locale === defaultLocale ? origin + path : origin + "/" + locale + path;export default function sitemap(): MetadataRoute.Sitemap {  const aboutLanguages = Object.fromEntries(    locales.map((l) => [l, formatterLocalizedPath(l, "/about")])  );  return [    {      url: formatterLocalizedPath(defaultLocale, "/about"),      lastModified: new Date(),      changeFrequency: "monthly",      priority: 0.7,      alternates: { languages: aboutLanguages },    },  ];}
    src/app/robots.ts
    import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const withAllLocales = (path: string) => [  path,  ...locales    .filter((locale) => locale !== defaultLocale)    .map((locale) => "/" + locale + path),];export default function robots(): MetadataRoute.Robots {  const disallow = [    ...withAllLocales("/dashboard"),    ...withAllLocales("/admin"),  ];  return {    rules: { userAgent: "*", allow: ["/"], disallow },    host: origin,    sitemap: origin + "/sitemap.xml",  };}

    Intlayer fornisce una funzione getMultilingualUrls per generare URL multilingue per la tua sitemap.



    E il vincitore è…

    Non è semplice. Ogni opzione ha dei compromessi. Ecco come la vedo:

    next-intl

    • la più semplice, leggera, con meno decisioni imposte. Se vuoi una soluzione minimale, ti senti a tuo agio con cataloghi centralizzati e la tua app è di dimensioni piccole o medie.

    next-i18next

    • matura, ricca di funzionalità, molti plugin della community, ma con un costo di configurazione più elevato. Se hai bisogno dell’ecosistema di plugin di i18next (ad esempio, regole ICU avanzate tramite plugin) e il tuo team conosce già i18next, accettando più configurazione per maggiore flessibilità.

    Intlayer

    • costruito per Next.js moderno, con contenuti modulari, sicurezza dei tipi, strumenti e meno codice boilerplate. Se apprezzi contenuti a livello di componente, TypeScript rigoroso, garanzie a tempo di build, tree-shaking e strumenti completi per routing/SEO/editor - specialmente per Next.js App Router, sistemi di design e codebase grandi e modulari.

    Se preferisci una configurazione minima e accetti un po' di collegamenti manuali, next-intl è una buona scelta. Se hai bisogno di tutte le funzionalità e non ti dispiace la complessità, next-i18next funziona. Ma se vuoi una soluzione moderna, scalabile, modulare con strumenti integrati, Intlayer mira a offrirti tutto questo pronto all'uso.

    Alternativa per team aziendali: Se avete bisogno di una soluzione ben collaudata che funzioni perfettamente con piattaforme di localizzazione consolidate come Crowdin, Phrase o altri sistemi professionali di gestione delle traduzioni, considerate next-intl o next-i18next per il loro ecosistema maturo e le integrazioni comprovate.

    Roadmap futura: Intlayer prevede anche di sviluppare plugin che lavorino sopra le soluzioni i18next e next-intl. Questo vi offrirà i vantaggi di Intlayer per l'automazione, la sintassi e la gestione dei contenuti, mantenendo al contempo la sicurezza e la stabilità fornite da queste soluzioni consolidate nel codice della vostra applicazione.

    Stelle su GitHub

    Le stelle di GitHub sono un forte indicatore della popolarità di un progetto, della fiducia della comunità e della rilevanza 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 l'attrattiva tra le alternative e forniscono informazioni sulla crescita dell'ecosistema.

    Grafico della Storia delle Stelle


    Conclusione

    Tutte e tre le librerie riescono nella localizzazione di base. La differenza è quanto lavoro devi fare per ottenere una configurazione robusta e scalabile in Next.js moderno:

    • Con Intlayer, contenuti modulari, TS rigoroso, sicurezza a tempo di build, bundle tree-shaken e App Router di prima classe + strumenti SEO sono impostazioni predefinite, non incombenze.
    • Se il tuo team valorizza la manutenibilità e la velocità in un'app multi-locale guidata da componenti, Intlayer offre l'esperienza più completa oggi disponibile.

    Consulta il documento 'Perché Intlayer?' per maggiori dettagli.