Un sito Next.js davvero multilingue con next-intl
Routing localizzato, rendering statico, hreflang e cambio di lingua: come strutturo un sito Next.js in dieci lingue senza sacrificare le prestazioni né la SEO.
Perché il multilingue è un vero tema di architettura
Tradurre un'interfaccia è facile. Fare un sito multilingue corretto — indicizzabile, veloce, manutenibile — è una decisione di architettura che si prende all'inizio, non alla fine. Questo portfolio esiste in dieci lingue, ed ecco le scelte che reggono su scala.
Il routing per segmento di locale
L'approccio più robusto con l'App Router: un segmento dinamico [locale] alla radice. Ogni pagina vive sotto app/[locale]/…, e la lingua diventa un dato d'URL di primo livello (/fr/projects, /en/projects).
Con next-intl, quel segmento viene validato al rendering:
- Le locale supportate sono elencate in una configurazione
routingcentrale. - Una locale sconosciuta scatena un
notFound()pulito anziché una pagina rotta. - La navigazione passa da un
Linklocalizzato che antepone automaticamente la lingua giusta.
Il vantaggio: i componenti non maneggiano mai la locale «a mano». Chiedono una traduzione e il sistema pensa al resto.
La trappola del rendering statico
È l'errore che costa di più in produzione. Se chiami le traduzioni senza fissare prima la locale, next-intl legge gli header della richiesta. Risultato: la pagina passa al rendering dinamico e perdi il prerendering statico — a volte con un errore DYNAMIC_SERVER_USAGE in produzione.
Il rimedio sta in una riga, proprio in cima a ogni pagina:
setRequestLocale(locale);
Chiamata prima di qualsiasi getTranslations, garantisce un rendering completamente statico. Combinata con un generateStaticParams che incrocia locale × slug, prerenderizza ogni pagina in ogni lingua al build.
Il multilingue statico non è più lento del monolingue. È solo più esigente sull'ordine delle chiamate.
Gli hreflang, ovvero come evitare di farsi concorrenza da soli
Senza alcuna indicazione, Google tratta le tue dieci versioni linguistiche come dieci pagine rivali sulle stesse parole chiave. La soluzione è l'hreflang: ogni pagina dichiara l'insieme delle sue varianti.
Due punti devono restare sincronizzati:
- I metadati di ogni pagina — tramite un helper
generateAlternatesche produce i tagalternate. - La sitemap — ogni URL vi elenca le sue lingue e un
x-default.
La coerenza tra queste due fonti è ciò che fa sì che una ricerca in spagnolo atterri su /es e non su /fr.
Il cambio di lingua, dal lato utente
Un selettore di lingua deve cambiare la locale senza perdere la pagina corrente. Il riflesso ingenuo — rimandare alla home — è frustrante. Con l'usePathname localizzato di next-intl, recuperi il percorso senza prefisso e lo riemetti nella lingua scelta. L'utente resta esattamente dov'era.
Ciò che mi porto a casa
- Il segmento
[locale]alla radice è la fondazione; tutto ne deriva. setRequestLocaleprima delle traduzioni: non negoziabile per mantenere lo statico.- Gli
hreflangsi gestiscono in doppio (metadati e sitemap), sempre sincronizzati. - La direzione del testo (RTL per l'arabo) si pilota a livello di
<html dir>, non pagina per pagina.
Fatto bene, il multilingue diventa invisibile: ogni visitatore ha l'impressione che il sito sia stato scritto per lui, e Google sa esattamente quale porta aprirgli.