Routage d'internationalisation (i18n)
Exemples
Next.js prend en charge nativement le routage internationalisé (i18n) depuis la version v10.0.0
. Vous pouvez fournir une liste de locales, la locale par défaut et des locales spécifiques à des domaines, et Next.js gérera automatiquement le routage.
Le support du routage i18n est conçu pour compléter les solutions existantes de bibliothèques i18n comme react-intl
, react-i18next
, lingui
, rosetta
, next-intl
, next-translate
, next-multilingual
, tolgee
, et d'autres en simplifiant les routes et l'analyse des locales.
Premiers pas
Pour commencer, ajoutez la configuration i18n
à votre fichier next.config.js
.
Les locales sont des Identifiants de Locale UTS, un format standardisé pour définir les locales.
Généralement, un identifiant de locale est composé d'une langue, d'une région et d'un script séparés par un tiret : langue-région-script
. La région et le script sont optionnels. Exemple :
en-US
- Anglais tel que parlé aux États-Unisnl-NL
- Néerlandais tel que parlé aux Pays-Basnl
- Néerlandais, sans région spécifique
Si la locale de l'utilisateur est nl-BE
et qu'elle n'est pas listée dans votre configuration, il sera redirigé vers nl
si disponible, ou vers la locale par défaut sinon.
Si vous ne prévoyez pas de supporter toutes les régions d'un pays, il est donc recommandé d'inclure les locales de pays qui serviront de solutions de repli.
module.exports = {
i18n: {
// Voici toutes les locales que vous souhaitez supporter dans
// votre application
locales: ['en-US', 'fr', 'nl-NL'],
// C'est la locale par défaut qui sera utilisée lors de la visite
// d'un chemin sans préfixe de locale, par exemple `/hello`
defaultLocale: 'en-US',
// Ceci est une liste de domaines de locales et de la locale par défaut qu'ils
// doivent gérer (nécessaire uniquement pour configurer le routage par domaine)
// Note : les sous-domaines doivent être inclus dans la valeur du domaine pour être pris en compte, par exemple "fr.example.com".
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
// un champ http optionnel peut aussi être utilisé pour tester
// les domaines de locales localement avec http au lieu de https
http: true,
},
],
},
}
Stratégies de locales
Il existe deux stratégies de gestion des locales : le Routage par Sous-chemin et le Routage par Domaine.
Routage par Sous-chemin
Le Routage par Sous-chemin place la locale dans le chemin de l'URL.
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
},
}
Avec la configuration ci-dessus, en-US
, fr
et nl-NL
seront disponibles pour le routage, et en-US
est la locale par défaut. Si vous avez une page pages/blog.js
, les URLs suivantes seront disponibles :
/blog
/fr/blog
/nl-nl/blog
La locale par défaut n'a pas de préfixe.
Routage par Domaine
En utilisant le Routage par Domaine, vous pouvez configurer des locales à servir depuis différents domaines :
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
defaultLocale: 'en-US',
domains: [
{
// Note : les sous-domaines doivent être inclus dans la valeur du domaine pour être pris en compte
// par exemple www.example.com doit être utilisé si c'est le nom d'hôte attendu
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
// spécifiez d'autres locales qui doivent être redirigées
// vers ce domaine
locales: ['nl-BE'],
},
],
},
}
Par exemple, si vous avez pages/blog.js
, les URLs suivantes seront disponibles :
example.com/blog
www.example.com/blog
example.fr/blog
example.nl/blog
example.nl/nl-BE/blog
Détection automatique de la locale
Lorsqu'un utilisateur visite la racine de l'application (généralement /
), Next.js essaie de détecter automatiquement la locale préférée de l'utilisateur en fonction de l'en-tête Accept-Language
et du domaine actuel.
Si une locale autre que la locale par défaut est détectée, l'utilisateur sera redirigé vers :
- Avec le Routage par Sous-chemin : Le chemin préfixé par la locale
- Avec le Routage par Domaine : Le domaine avec cette locale spécifiée comme par défaut
Avec le Routage par Domaine, si un utilisateur avec l'en-tête Accept-Language
fr;q=0.9
visite example.com
, il sera redirigé vers example.fr
puisque ce domaine gère la locale fr
par défaut.
Avec le Routage par Sous-chemin, l'utilisateur serait redirigé vers /fr
.
Préfixer la locale par défaut
Avec Next.js 12 et le Middleware, nous pouvons ajouter un préfixe à la locale par défaut avec une solution de contournement.
Par exemple, voici un fichier next.config.js
avec support pour quelques langues. Notez que la locale "default"
a été ajoutée intentionnellement.
module.exports = {
i18n: {
locales: ['default', 'en', 'de', 'fr'],
defaultLocale: 'default',
localeDetection: false,
},
trailingSlash: true,
}
Ensuite, nous pouvons utiliser le Middleware pour ajouter des règles de routage personnalisées :
import { NextRequest, NextResponse } from 'next/server'
const PUBLIC_FILE = /\.(.*)$/
export async function middleware(req: NextRequest) {
if (
req.nextUrl.pathname.startsWith('/_next') ||
req.nextUrl.pathname.includes('/api/') ||
PUBLIC_FILE.test(req.nextUrl.pathname)
) {
return
}
if (req.nextUrl.locale === 'default') {
const locale = req.cookies.get('NEXT_LOCALE')?.value || 'en'
return NextResponse.redirect(
new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url)
)
}
}
Ce Middleware ignore l'ajout du préfixe par défaut aux API Routes et aux fichiers publics comme les polices ou images. Si une requête est faite vers la locale par défaut, nous redirigeons vers notre préfixe /en
.
Désactiver la détection automatique de la locale
La détection automatique de la locale peut être désactivée avec :
module.exports = {
i18n: {
localeDetection: false,
},
}
Lorsque localeDetection
est défini sur false
, Next.js ne redirigera plus automatiquement en fonction de la locale préférée de l'utilisateur et ne fournira que les informations de locale détectées à partir du domaine ou du chemin de locale comme décrit ci-dessus.
Accéder aux informations de locale
Vous pouvez accéder aux informations de locale via le routeur Next.js. Par exemple, en utilisant le hook useRouter()
, les propriétés suivantes sont disponibles :
locale
contient la locale actuellement active.locales
contient toutes les locales configurées.defaultLocale
contient la locale par défaut configurée.
Lors de la pré-rendu de pages avec getStaticProps
ou getServerSideProps
, les informations de locale sont fournies dans le contexte fourni à la fonction.
Lors de l'utilisation de getStaticPaths
, les locales configurées sont fournies dans le paramètre de contexte de la fonction sous locales
et la defaultLocale
configurée sous defaultLocale
.
Transition entre les locales
Vous pouvez utiliser next/link
ou next/router
pour passer d'une locale à une autre.
Pour next/link
, une prop locale
peut être fournie pour passer à une locale différente de celle actuellement active. Si aucune prop locale
n'est fournie, la locale actuellement active est utilisée lors des transitions côté client. Par exemple :
import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/another" locale="fr">
Vers /fr/another
</Link>
)
}
Lors de l'utilisation directe des méthodes de next/router
, vous pouvez spécifier la locale
à utiliser via les options de transition. Par exemple :
import { useRouter } from 'next/router'
export default function IndexPage(props) {
const router = useRouter()
return (
<div
onClick={() => {
router.push('/another', '/another', { locale: 'fr' })
}}
>
vers /fr/another
</div>
)
}
Notez que pour changer uniquement la locale
tout en conservant toutes les informations de routage comme les valeurs de requête des routes dynamiques ou les valeurs de requête cachées de href, vous pouvez fournir le paramètre href
sous forme d'objet :
import { useRouter } from 'next/router'
const router = useRouter()
const { pathname, asPath, query } = router
// change uniquement la locale et conserve toutes les autres informations de route, y compris la requête de href
router.push({ pathname, query }, asPath, { locale: nextLocale })
Voir ici pour plus d'informations sur la structure d'objet pour router.push
.
Si vous avez un href
qui inclut déjà la locale, vous pouvez désactiver la gestion automatique du préfixe de locale :
import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/fr/another" locale={false}>
Vers /fr/another
</Link>
)
}
Utilisation du cookie NEXT_LOCALE
Next.js permet de remplacer l'en-tête accept-language avec un cookie NEXT_LOCALE=la-locale
. Ce cookie peut être défini à l'aide d'un sélecteur de langue et, lorsque l'utilisateur revient sur le site, il utilisera la locale spécifiée dans le cookie lors de la redirection de /
vers l'emplacement de locale correct.
Par exemple, si un utilisateur préfère la locale fr
dans son en-tête accept-language mais qu'un cookie NEXT_LOCALE=en
est défini, la locale en
sera utilisée lors de la visite de /
et l'utilisateur sera redirigé vers l'emplacement de la locale en
jusqu'à ce que le cookie soit supprimé ou expire.
Optimisation pour les moteurs de recherche
Comme Next.js connaît la langue de l'utilisateur, il ajoute automatiquement l'attribut lang
à la balise <html>
.
Next.js ne connaît pas les variantes d'une page, c'est donc à vous d'ajouter les balises meta hreflang
en utilisant next/head
. Vous pouvez en apprendre plus sur hreflang
dans la documentation Google pour les webmasters.
Comment cela fonctionne-t-il avec la Génération Statique ?
Notez que le Routage Internationalisé ne s'intègre pas avec
output: 'export'
car il n'utilise pas la couche de routage de Next.js. Les applications hybrides Next.js qui n'utilisent pasoutput: 'export'
sont entièrement supportées.
Routes Dynamiques et Pages getStaticProps
Pour les pages utilisant getStaticProps
avec des Routes Dynamiques, toutes les variantes de locale de la page que vous souhaitez pré-rendre doivent être retournées par getStaticPaths
. Avec l'objet params
retourné pour paths
, vous pouvez aussi retourner un champ locale
spécifiant quelle locale vous souhaitez rendre. Par exemple :
export const getStaticPaths = ({ locales }) => {
return {
paths: [
// si aucune `locale` n'est fournie, seule la defaultLocale sera générée
{ params: { slug: 'post-1' }, locale: 'en-US' },
{ params: { slug: 'post-1' }, locale: 'fr' },
],
fallback: true,
}
}
Pour les pages Optimisées Statiquement de manière Automatique et les pages non dynamiques avec getStaticProps
, une version de la page sera générée pour chaque locale. Ceci est important à considérer car cela peut augmenter les temps de build en fonction du nombre de locales configurées dans getStaticProps
.
Par exemple, si vous avez 50 locales configurées avec 10 pages non dynamiques utilisant getStaticProps
, cela signifie que getStaticProps
sera appelé 500 fois. 50 versions des 10 pages seront générées à chaque build.
Pour réduire le temps de build des pages dynamiques avec getStaticProps
, utilisez un mode fallback
. Cela vous permet de retourner uniquement les chemins et locales les plus populaires depuis getStaticPaths
pour le pré-rendu lors du build. Ensuite, Next.js construira les pages restantes au moment de l'exécution lorsqu'elles seront demandées.
Pages Optimisées Statiquement de manière Automatique
Pour les pages qui sont optimisées statiquement de manière automatique, une version de la page sera générée pour chaque locale.
Pages getStaticProps
non dynamiques
Pour les pages getStaticProps
non dynamiques, une version est générée pour chaque locale comme ci-dessus. getStaticProps
est appelé avec chaque locale
qui est rendu. Si vous souhaitez exclure une certaine locale du pré-rendu, vous pouvez retourner notFound: true
depuis getStaticProps
et cette variante de la page ne sera pas générée.
export async function getStaticProps({ locale }) {
// Appel à une API externe pour obtenir des articles.
// Vous pouvez utiliser n'importe quelle bibliothèque de récupération de données
const res = await fetch(`https://.../posts?locale=${locale}`)
const posts = await res.json()
if (posts.length === 0) {
return {
notFound: true,
}
}
// En retournant { props: posts }, le composant Blog
// recevra `posts` comme prop au moment du build
return {
props: {
posts,
},
}
}
Limites pour la configuration i18n
locales
: 100 locales au totaldomains
: 100 éléments de domaine de locale au total
Bon à savoir : Ces limites ont été ajoutées initialement pour éviter d'éventuels problèmes de performance au moment du build. Vous pouvez contourner ces limites avec un routage personnalisé en utilisant le Middleware dans Next.js 12.