Tutoriel pour traduire une app Next.js v13+ avec l'app router
Publié le
Développeur React & Next.js freelance
Il est courant de devoir traduire le contenu de son site internet ou de son application web de nos jours. Avec les dernières versions de Next.js et l'app router, le mécanisme de traduction a évolué pour s'adapter aux server components.
Pour cela, il existe différentes librairies comme next-intl, react-i18next et next-translate. Le mécanisme de traduction reste le même de manière général : vous allez devoir configurer un middleware pour récupérer la langue de l'utilisateur, puis créer des fichiers de traductions et enfin les utiliser dans vos composants.
Pour ce guide, nous allons utiliser la librairie next-international qui est d'après mon expérience la plus simple à configurer et à mettre en place.
De plus, voici ses caractéristiques :
- Peut être utilisée avec l'app router et le pages router de Next.js
- 100% Type-safe
- Librairie légère & simple
- Elle peut être utilisée avec les server & client components ainsi que le rendu statique
1. Installation de next-international
Pour l'installation, vous pouvez exécuter cette commande depuis votre projet Next.js : yarn add next-international
Sur la documentation de next-international, il est recommandé de configurer l'option strict à true dans le fichier de configuration tsconfig.json. Ça permet à la librairie de fournir une meilleure expérience de développement en Typescript.
2. Création des fichiers de traduction
Une fois la librairie installée, vous pouvez créer les fichiers qui contiendront les traductions de votre application Next.js :
export default {
'hello': 'Hello',
'hello.world': 'Hello world!',
'welcome': 'Hello {name}!'
} as constexport default {
'hello': 'Bonjour',
'hello.world': 'Bonjour le monde !',
'welcome': 'Bonjour {name} !'
} as const3. Création des hooks
Nous allons créer des hooks pour utiliser les traductions dans nos composants. Pour cela, nous allons en définir deux différents, un premier pour les composants clients, un second pour les composants serveurs :
"use client"
import { createI18nClient } from 'next-international/client'
export const { useI18n, useScopedI18n, I18nProviderClient } = createI18nClient({
en: () => import('./en'),
fr: () => import('./fr')
})import { createI18nServer } from 'next-international/server'
export const { getI18n, getScopedI18n, getStaticParams } = createI18nServer({
en: () => import('./en'),
fr: () => import('./fr')
})4. Configuration du router de Next.js
Pour déterminer quelle langue est utilisée dans nos pages, nous allons déplacer toutes les routes de notre application dans un dossier app/[locale]/ afin d'avoir un paramètre locale.
Pour les composants clients, vous pouvez les englober avec le provider créé précédemment :
import { ReactElement } from 'react'
import { I18nProviderClient } from '@/locales/client'
export default function SubLayout({ params: { locale }, children }: { params: { locale: string }, children: ReactElement }) {
return (
<I18nProviderClient locale={locale}>
{children}
</I18nProviderClient>
)
}Vous pouvez également utiliser une prop fallback pour gérer le chargement de la langue utilisée par l'utilisateur.
5. Configuration du middleware
Il faut créer un middleware afin de rediriger l'utilisateur sur l'url avec la langue qu'il utilise en paramètre :
import { createI18nMiddleware } from 'next-international/middleware'
import { NextRequest } from 'next/server'
const I18nMiddleware = createI18nMiddleware({
locales: ['en', 'fr'],
defaultLocale: 'en',
urlMappingStrategy: 'rewriteDefault' // or 'rewrite' or 'redirect'
})
export function middleware(request: NextRequest) {
return I18nMiddleware(request)
}
export const config = {
matcher: ['/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)']
}En définissant le paramètre urlMappingStrategy: 'rewriteDefault', nous retirons la langue par défaut de l'url et nous gardons les autres langues dans l'url. Par exemple, si un utilisateur visite la page /en/products, il sera redirigé vers /products, alors que si il visite la page /fr/products, il restera sur /fr/products.
Pour en savoir plus, vous pouvez vous rendre sur la documentation de next-international : https://next-international.vercel.app/docs/app-middleware-configuration#rewrite-the-url-to-hide-the-locale.
6. Utilisation des traductions
Enfin, pour traduire le contenu de votre application Next.js, il ne reste plus qu'à utiliser les hooks et les fichiers de traductions créés précédemment :
'use client'
import { useI18n } from '@/locales/client'
export default function Page() {
const t = useI18n()
return (
<div>
<p>{t('hello')}</p>
<p>{t('hello.world')}</p>
<p>{t('welcome', { name: 'John' })}</p>
<p>{t('welcome', { name: <strong>John</strong> })}</p>
</div>
)
}import { getI18n } from '@/locales/server'
export default async function Page() {
const t = await getI18n()
return (
<div>
<p>{t('hello')}</p>
<p>{t('hello.world')}</p>
<p>{t('welcome', { name: 'John' })}</p>
<p>{t('welcome', { name: <strong>John</strong> })}</p>
</div>
)
}Traductions scopées
Il arrive régulièrement d'avoir un grand nombre de traductions et de les organisées par groupe (ou scope). Afin d'éviter d'avoir des longues clés à passer en paramètre des hooks et des fonctions pour récupérer des traductions, vous pouvez utiliser le hook useScopedI18n et la fonction getScopedI18n pour récupérer un groupe de traductions.
'use client'
import { useI18n, useScopedI18n } from '@/locales/client'
export default function Page() {
const scopedT = useScopedI18n('index.header.links')
//const t = useI18n()
return (
<div>
<p>{scopedT('home')}</p>
{/*<p>{t('index.header.links.home')}</p>*/}
</div>
)
}import { getI18n, getScopedI18n } from '@/locales/server'
export default async function Page() {
const scopedT = await getScopedI18n('index.header.links')
//const t = await getI18n()
return (
<div>
<p>{scopedT('home')}</p>
{/*<p>{t('index.header.links.home')}</p>*/}
</div>
)
}Pluriels
Pour gérer les traductions aux pluriels, il faut utiliser le caractère # après une clé de traduction, suivi de zero, one, two, few, many ou other :
export default {
'cows#zero': 'No cows',
'cows#one': 'A cow',
'cows#other': '{count} cows'
} as constLa traduction sera déterminée grâce au paramètre count passé aux hooks et aux fonctions qui récupèrent les traductions :
import { useI18n } from '@/locales/client'
export default function Page() {
const t = useI18n()
return (
<div>
{/* Affiche : No cows */}
<p>{t('cows', { count: 0 })}</p>
{/* Affiche : A cow */}
<p>{t('cows', { count: 1 })}</p>
{/* Affiche : 3 cows */}
<p>{t('cows', { count: 3 })}</p>
</div>
)
}Si vous souhaitez plus d'informations sur l'utilisation la librairie next-international, vous pouvez vous rendre sur la documentation : https://next-international.vercel.app/docs.
Cet article vous a été utile ?
Je peux vous accompagner sur votre projet React & Next.js.
Discutons de votre projet →