Getting Started internationalizing (i18n) with Intlayer and Next.js 14 with App Router

    Cosa è Intlayer?

    Intlayer è una libreria innovativa e open-source per l'internazionalizzazione (i18n) progettata per semplificare il supporto multilingue nelle moderne applicazioni web. Intlayer si integra perfettamente con l'ultimo framework Next.js 14, inclusa la sua potente App Router. È ottimizzata per funzionare con i Server Components per un rendering efficiente ed è completamente compatibile con Turbopack (da Next.js >= 15).

    Con Intlayer, puoi:

    • Gestire facilmente le traduzioni utilizzando dizionari dichiarativi a livello di componente.
    • Localizzare dinamicamente metadati, rotte e contenuti.
    • Accedere alle traduzioni sia nei componenti lato client che lato server.
    • Garantire il supporto TypeScript con tipi autogenerati, migliorando l'autocompletamento e il rilevamento degli errori.
    • Beneficiare di funzionalità avanzate, come il rilevamento dinamico della lingua e il cambio di lingua.

    Intlayer è compatibile con Next.js 12, 13, 14 e 15. Se stai utilizzando Next.js Page Router, puoi fare riferimento a questa guida. Per Next.js 15 con o senza turbopack, consulta questa guida.


    Guida passo-passo per configurare Intlayer in un'applicazione Next.js

    Passo 1: Installa le dipendenze

    Installa i pacchetti necessari utilizzando npm:

    bash
    npm install intlayer next-intlayer
    • intlayer

      Il pacchetto principale che fornisce strumenti di internazionalizzazione per la gestione della configurazione, traduzione, dichiarazione dei contenuti, transpilation e comandi CLI.

    • next-intlayer

      Il pacchetto che integra Intlayer con Next.js. Fornisce provider di contesto e hook per l'internazionalizzazione di Next.js. Inoltre, include il plugin Next.js per integrare Intlayer con Webpack o Turbopack, oltre a middleware per rilevare la lingua preferita dell'utente, gestire i cookie e gestire i reindirizzamenti URL.

    Passo 2: Configura il tuo progetto

    Crea un file di configurazione per configurare le lingue della tua applicazione:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // Le tue altre lingue    ],    defaultLocale: Locales.ENGLISH,  },};export default config;

    Tramite questo file di configurazione, puoi configurare URL localizzati, reindirizzamenti middleware, nomi dei cookie, la posizione e l'estensione delle dichiarazioni dei contenuti, disabilitare i log di Intlayer nella console e altro ancora. Per un elenco completo dei parametri disponibili, consulta la documentazione di configurazione.

    Passo 3: Integra Intlayer nella configurazione di Next.js

    Configura il tuo setup Next.js per utilizzare Intlayer:

    next.config.mjs
    import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {};export default withIntlayer(nextConfig);

    Il plugin withIntlayer() di Next.js è utilizzato per integrare Intlayer con Next.js. Garantisce la costruzione dei file di dichiarazione dei contenuti e li monitora in modalità di sviluppo. Definisce le variabili di ambiente di Intlayer all'interno degli ambienti Webpack o Turbopack. Inoltre, fornisce alias per ottimizzare le prestazioni e garantisce la compatibilità con i componenti server.

    Passo 4: Configura il Middleware per il rilevamento della lingua

    Configura il middleware per rilevare la lingua preferita dell'utente:

    src/middleware.ts
    export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = {  matcher:    "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\..*|_next).*)",};

    Il intlayerMiddleware è utilizzato per rilevare la lingua preferita dell'utente e reindirizzarlo all'URL appropriato come specificato nella configurazione. Inoltre, consente di salvare la lingua preferita dell'utente in un cookie.

    Adatta il parametro matcher per corrispondere alle rotte della tua applicazione. Per maggiori dettagli, consulta la documentazione di Next.js sulla configurazione del matcher.

    Passo 5: Definisci rotte dinamiche per la lingua

    Rimuovi tutto da RootLayout e sostituiscilo con il seguente codice:

    src/app/layout.tsx
    import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;

    Mantenere il componente RootLayout vuoto consente di impostare gli attributi lang e dir nel tag <html>.

    Per implementare il routing dinamico, fornisci il percorso per la lingua aggiungendo un nuovo layout nella tua directory [locale]:

    src/app/[locale]/layout.tsx
    import type { Next14LayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: Next14LayoutIntlayer = ({  children,  params: { locale },}) => (  <html lang={locale} dir={getHTMLTextDir(locale)}>    <body className={inter.className}>{children}</body>  </html>);export default LocaleLayout;

    Il segmento di percorso [locale] è utilizzato per definire la lingua. Esempio: /en-US/about si riferirà a en-US e /fr/about a fr.

    Poi, implementa la funzione generateStaticParams nel layout della tua applicazione.

    src/app/[locale]/layout.tsx
    export { generateStaticParams } from "next-intlayer"; // Riga da inserireconst LocaleLayout: Next14LayoutIntlayer = ({  children,  params: { locale },}) => {  /*... Resto del codice*/};export default LocaleLayout;

    generateStaticParams garantisce che la tua applicazione pre-costruisca le pagine necessarie per tutte le lingue, riducendo il calcolo a runtime e migliorando l'esperienza utente. Per maggiori dettagli, consulta la documentazione di Next.js su generateStaticParams.

    Passo 6: Dichiara i tuoi contenuti

    Crea e gestisci le dichiarazioni dei tuoi contenuti per memorizzare le traduzioni:

    src/app/[locale]/page.content.ts
    import { t, type Dictionary } from "intlayer";const pageContent = {  key: "page",  content: {    getStarted: {      main: t({        en: "Get started by editing",        fr: "Commencez par éditer",        es: "Comience por editar",        it: "Inizia modificando",      }),      pageLink: "src/app/page.tsx",    },  },} satisfies Dictionary;export default pageContent;

    Le dichiarazioni dei tuoi contenuti possono essere definite ovunque nella tua applicazione purché siano incluse nella directory contentDir (di default, ./src). E corrispondano all'estensione del file di dichiarazione dei contenuti (di default, .content.{ts,tsx,js,jsx,mjs,cjs}). Per maggiori dettagli, consulta la documentazione sulla dichiarazione dei contenuti.

    Passo 7: Utilizza i contenuti nel tuo codice

    Accedi ai tuoi dizionari di contenuti in tutta la tua applicazione:

    src/app/[locale]/page.tsx
    import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type Next14PageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const Page: Next14PageIntlayer = ({ params: { locale } }) => {  const content = useIntlayer("page", locale);  return (    <>      <p>        {content.getStarted.main}        <code>{content.getStarted.pageLink}</code>      </p>      <IntlayerServerProvider locale={locale}>        <IntlayerClientProvider locale={locale}>          <ServerComponentExample />          <ClientComponentExample />        </IntlayerClientProvider>      </IntlayerServerProvider>    </>  );};export default Page;
    • IntlayerClientProvider è utilizzato per fornire la lingua ai componenti lato client. Può essere posizionato in qualsiasi componente genitore, incluso il layout. Tuttavia, è consigliato posizionarlo in un layout perché Next.js condivide il codice del layout tra le pagine, rendendolo più efficiente. Utilizzando IntlayerClientProvider nel layout, eviti di reinizializzarlo per ogni pagina, migliorando le prestazioni e mantenendo un contesto di localizzazione coerente in tutta l'applicazione.
    • IntlayerServerProvider è utilizzato per fornire la lingua ai figli lato server. Non può essere impostato nel layout.

      Layout e pagina non possono condividere un contesto server comune perché il sistema di contesto server si basa su un archivio dati per richiesta (tramite il meccanismo di cache di React), causando la ricreazione di ogni "contesto" per segmenti diversi dell'applicazione. Posizionare il provider in un layout condiviso interromperebbe questo isolamento, impedendo la corretta propagazione dei valori del contesto server ai tuoi componenti server.

    src/components/ClientComponentExample.tsx
    "use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";const ClientComponentExample: FC = () => {  const content = useIntlayer("client-component-example"); // Crea la dichiarazione dei contenuti correlata  return (    <div>      <h2>{content.title} </h2>      <p>{content.content}</p>    </div>  );};
    src/components/ServerComponentExample.tsx
    import type { FC } from "react";import { useIntlayer } from "next-intlayer/server";const ServerComponentExample: FC = () => {  const content = useIntlayer("server-component-example"); // Crea la dichiarazione dei contenuti correlata  return (    <div>      <h2>{content.title} </h2>      <p>{content.content}</p>    </div>  );};

    Se desideri utilizzare i tuoi contenuti in un attributo string, come alt, title, href, aria-label, ecc., devi chiamare il valore della funzione, come:

    jsx
    <img src={content.image.src.value} alt={content.image.value} />

    Per saperne di più sull'hook useIntlayer, consulta la documentazione.

    (Opzionale) Passo 8: Internazionalizzazione dei tuoi metadati

    Nel caso tu voglia internazionalizzare i tuoi metadati, come il titolo della tua pagina, puoi utilizzare la funzione generateMetadata fornita da Next.js. All'interno della funzione utilizza la funzione getTranslation per tradurre i tuoi metadati.

    src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx
    import {  type IConfigLocales,  getTranslation,  getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalParams } from "next-intlayer";export const generateMetadata = ({  params: { locale },}: LocalParams): Metadata => {  const t = <T>(content: IConfigLocales<T>) => getTranslation(content, locale);  /**   * Genera un oggetto contenente tutti gli URL per ogni lingua.   *   * Esempio:   * ```ts   *  getMultilingualUrls('/about');   *   *  // Restituisce   *  // {   *  //   en: '/about',   *  //   fr: '/fr/about',   *  //   es: '/es/about',   *  // }   * ```   */  const multilingualUrls = getMultilingualUrls("/");  return {    title: t<string>({      en: "My title",      fr: "Mon titre",      es: "Mi título",      it: "Il mio titolo",    }),    description: t({      en: "My description",      fr: "Ma description",      es: "Mi descripción",      it: "La mia descrizione",    }),    alternates: {      canonical: "/",      languages: { ...multilingualUrls, "x-default": "/" },    },    openGraph: {      url: multilingualUrls[locale],    },  };};// ... Resto del codice

    Scopri di più sull'ottimizzazione dei metadati nella documentazione ufficiale di Next.js.

    (Opzionale) Passo 9: Internazionalizzazione del tuo sitemap.xml e robots.txt

    Per internazionalizzare il tuo sitemap.xml e robots.txt, puoi utilizzare la funzione getMultilingualUrls fornita da Intlayer. Questa funzione ti consente di generare URL multilingue per il tuo sitemap.

    src/app/sitemap.ts
    import { getMultilingualUrls } from "intlayer";import type { MetadataRoute } from "next";const sitemap = (): MetadataRoute.Sitemap => [  {    url: "https://example.com",    alternates: {      languages: getMultilingualUrls("https://example.com"),    },  },  {    url: "https://example.com/login",    alternates: {      languages: getMultilingualUrls("https://example.com/login"),    },  },  {    url: "https://example.com/register",    alternates: {      languages: getMultilingualUrls("https://example.com/register"),    },  },];export default sitemap;
    src/app/robots.ts
    import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";const getAllMultilingualUrls = (urls: string[]) =>  urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);const robots = (): MetadataRoute.Robots => ({  rules: {    userAgent: "*",    allow: ["/"],    disallow: getAllMultilingualUrls(["/login", "/register"]),  },  host: "https://example.com",  sitemap: `https://example.com/sitemap.xml`,});export default robots;

    Scopri di più sull'ottimizzazione del sitemap nella documentazione ufficiale di Next.js. Scopri di più sull'ottimizzazione del robots.txt nella documentazione ufficiale di Next.js.

    (Opzionale) Passo 10: Cambia la lingua dei tuoi contenuti

    Per cambiare la lingua dei tuoi contenuti, puoi utilizzare la funzione setLocale fornita dall'hook useLocale. Questa funzione ti consente di impostare la lingua dell'applicazione e aggiornare i contenuti di conseguenza.

    src/components/LocaleSwitcher.tsx
    "use client";import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import { type FC } from "react";import Link from "next/link";const LocaleSwitcher: FC = () => {  const { locale, pathWithoutLocale, availableLocales, setLocale } =    useLocale();  return (    <div>      <button popoverTarget="localePopover">{getLocaleName(locale)}</button>      <div id="localePopover" popover="auto">        {availableLocales.map((localeItem) => (          <Link            href={getLocalizedUrl(pathWithoutLocale, localeItem)}            hrefLang={localeItem}            key={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={(e) => {              e.preventDefault();              setLocale(localeItem);            }}          >            <span>              {/* Lingua - es. FR */}              {localeItem}            </span>            <span>              {/* Lingua nel proprio locale - es. Français */}              {getLocaleName(localeItem, locale)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* Lingua nel locale corrente - es. Francés con locale corrente impostato su Locales.SPANISH */}              {getLocaleName(localeItem)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Lingua in inglese - es. French */}              {getLocaleName(localeItem, Locales.ENGLISH)}            </span>          </Link>        ))}      </div>    </div>  );};

    Riferimenti alla documentazione:

    Per garantire che la navigazione della tua applicazione rispetti la lingua corrente, puoi creare un componente Link personalizzato. Questo componente aggiunge automaticamente il prefisso agli URL interni con la lingua corrente, in modo che, ad esempio, quando un utente francofono clicca su un link alla pagina "About", venga reindirizzato a /fr/about invece che a /about.

    Questo comportamento è utile per diversi motivi:

    • SEO e User Experience: Gli URL localizzati aiutano i motori di ricerca a indicizzare correttamente le pagine specifiche per lingua e forniscono agli utenti contenuti nella loro lingua preferita.
    • Coerenza: Utilizzando un link localizzato in tutta l'applicazione, garantisci che la navigazione rimanga all'interno della lingua corrente, evitando cambi di lingua inaspettati.
    • Manutenibilità: Centralizzando la logica di localizzazione in un unico componente, semplifichi la gestione degli URL, rendendo il tuo codice più facile da mantenere ed estendere man mano che l'applicazione cresce.

    Di seguito è riportata l'implementazione di un componente Link localizzato in TypeScript:

    src/components/Link.tsx
    "use client";import { getLocalizedUrl } from "intlayer";import NextLink, { type LinkProps as NextLinkProps } from "next/link";import { useLocale } from "next-intlayer";import { forwardRef, PropsWithChildren, type ForwardedRef } from "react";/** * Funzione di utilità per verificare se un URL è esterno. * Se l'URL inizia con http:// o https://, viene considerato esterno. */export const checkIsExternalLink = (href?: string): boolean =>  /^https?:///.test(href ?? "");/** * Un componente Link personalizzato che adatta l'attributo href in base alla lingua corrente. * Per i link interni, utilizza `getLocalizedUrl` per aggiungere il prefisso dell'URL con la lingua (es. /fr/about). * Questo garantisce che la navigazione rimanga all'interno dello stesso contesto linguistico. */export const Link = forwardRef<  HTMLAnchorElement,  PropsWithChildren<NextLinkProps>>(({ href, children, ...props }, ref: ForwardedRef<HTMLAnchorElement>) => {  const { locale } = useLocale();  const isExternalLink = checkIsExternalLink(href.toString());  // Se il link è interno e viene fornito un href valido, ottieni l'URL localizzato.  const hrefI18n: NextLinkProps["href"] =    href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href;  return (    <NextLink href={hrefI18n} ref={ref} {...props}>      {children}    </NextLink>  );});Link.displayName = "Link";

    Come Funziona

    • Rilevamento dei Link Esterni:
      La funzione helper checkIsExternalLink determina se un URL è esterno. I link esterni vengono lasciati invariati perché non necessitano di localizzazione.

    • Recupero della Lingua Corrente:
      L'hook useLocale fornisce la lingua corrente (es. fr per il francese).

    • Localizzazione dell'URL:
      Per i link interni (cioè non esterni), getLocalizedUrl viene utilizzato per aggiungere automaticamente il prefisso dell'URL con la lingua corrente. Ciò significa che se il tuo utente è in francese, passando /about come href verrà trasformato in /fr/about.

    • Restituzione del Link:
      Il componente restituisce un elemento <a> con l'URL localizzato, garantendo che la navigazione sia coerente con la lingua.

    Integrando questo componente Link in tutta la tua applicazione, mantieni un'esperienza utente coerente e consapevole della lingua, beneficiando anche di un miglior SEO e usabilità.

    Configura TypeScript

    Intlayer utilizza l'augmentazione dei moduli per ottenere i vantaggi di TypeScript e rendere il tuo codice più robusto.

    alt text

    alt text

    Assicurati che la configurazione di TypeScript includa i tipi autogenerati.

    tsconfig.json
    {  // ... Le tue configurazioni TypeScript esistenti  "include": [    // ... Le tue configurazioni TypeScript esistenti    ".intlayer/**/*.ts", // Includi i tipi autogenerati  ],}

    Configurazione Git

    Si consiglia di ignorare i file generati da Intlayer. Questo ti consente di evitare di commetterli nel tuo repository Git.

    Per fare ciò, puoi aggiungere le seguenti istruzioni al tuo file .gitignore:

    .gitignore
    # Ignora i file generati da Intlayer.intlayer

    Approfondisci

    Per approfondire, puoi implementare l'editor visivo o esternalizzare i tuoi contenuti utilizzando il CMS.

    Se hai un’idea per migliorare questa documentazione, non esitare a contribuire inviando una pull request su GitHub.

    Collegamento GitHub alla documentazione