Comment optimiser le SEO d’une application Next.js multilingue
Pourquoi le SEO multilingue nécessite une attention particulière
La plupart des développeurs qui ajoutent l’i18n à leur application Next.js se concentrent sur la traduction de l’interface et considèrent que le travail est terminé. Mais si les moteurs de recherche ne peuvent pas trouver, indexer et associer correctement vos différentes versions linguistiques, tout ce travail de traduction reste invisible.
Un site multilingue sans configuration SEO adaptée pose plusieurs problèmes :
- Google peut n’indexer qu’une seule version linguistique et ignorer toutes les autres
- Les utilisateurs qui recherchent en espagnol tombent sur la page en anglais
- Des pénalités pour contenu dupliqué, car Google considère
/en/aboutet/fr/aboutcomme une seule et même page - La mauvaise langue s’affiche dans les extraits des résultats de recherche
Bonne nouvelle : bien configurer le SEO multilingue dans Next.js n’est pas compliqué. Il y a six points à bien configurer, et ce guide les couvre tous avec gt-next.
1. Routage d’URL basé sur le paramètre régional
Le fondement du SEO multilingue est d’avoir des URL distinctes pour chaque langue. Les moteurs de recherche ont besoin d’URL séparées et explorables pour indexer indépendamment chaque version linguistique.
Cela signifie le paramètre régional dans l’URL — pas de cookie, pas de paramètres de requête, ni la seule détection Accept-Language.
✅ generaltranslation.com/en/about
✅ generaltranslation.com/fr/about
✅ generaltranslation.com/es/about
❌ generaltranslation.com/about?lang=fr
❌ generaltranslation.com/about (with locale in a cookie)
Configurer le routage par paramètre régional avec gt-next
Commencez par placer vos pages sous un segment dynamique [locale] :
app/
└── [locale]/
├── layout.tsx
├── page.tsx
└── about/
└── page.tsx
Créez ensuite un middleware à la racine de votre projet (proxy.ts pour Next.js 16+, ou middleware.ts pour Next.js 15 et versions antérieures) :
import { createNextMiddleware } from 'gt-next/middleware';
export default createNextMiddleware();
export const config = {
matcher: ['/((?!api|static|.*\\..*|_next).*)'],
};Cela vous donne automatiquement des URL préfixées par le paramètre régional.
Par défaut, le paramètre régional par défaut (par ex. l’anglais) n’a pas de préfixe — /about reste tel quel,
tandis que les utilisateurs espagnols voient /es/about et les utilisateurs français voient /fr/about.
2. Définir l’attribut HTML lang
L’attribut lang de votre balise <html> indique aux navigateurs et aux moteurs de recherche la langue de la page.
C’est l’une des mesures les plus simples et les plus efficaces que vous puissiez prendre pour l’accessibilité et le SEO.
Sans lui, les lecteurs d’écran doivent deviner la langue (et se trompent souvent), et les moteurs de recherche sont moins sûrs de leur classification linguistique.
gt-next fournit le Hook useLocale, ce qui simplifie grandement cela dans votre layout racine :
import { useLocale, GTProvider } from 'gt-next';
export default function RootLayout({ children }: { children: React.ReactNode }) {
const locale = useLocale();
return (
<html lang={locale}>
<body>
<GTProvider>
{children}
</GTProvider>
</body>
</html>
);
}useLocale renvoie le code de langue au format BCP 47 (par ex. en-US, ar, zh-Hans).
3. URL canoniques
Les balises canoniques indiquent aux moteurs de recherche quelle URL correspond à la version "principale" d’une page. Pour les sites multilingues, chaque version linguistique doit se désigner elle-même comme URL canonique :
<!-- Sur /fr/about -->
<link rel="canonical" href="https://example.com/fr/about" />Cela empêche les moteurs de recherche de considérer votre page en français comme un doublon de votre page en anglais.
Dans Next.js, vous définissez les URL canoniques via l’API de métadonnées.
Associez-la à getLocale de gt-next pour générer l’URL canonique correcte pour chaque paramètre régional :
import { getLocale } from 'gt-next/server';
const BASE_URL = 'https://example.com';
export async function generateMetadata() {
const locale = await getLocale();
return {
alternates: {
canonical: `${BASE_URL}/${locale}/about`,
},
};
}
export default function AboutPage() {
return <h1>About Us</h1>;
}Pour le paramètre régional par défaut, sans préfixe, adaptez en conséquence :
import { getLocale, getDefaultLocale } from 'gt-next/server';
export async function generateMetadata() {
const locale = await getLocale();
const defaultLocale = getDefaultLocale();
const path = '/about';
const prefix = locale === defaultLocale ? '' : `/${locale}`;
return {
alternates: {
canonical: `${BASE_URL}${prefix}${path}`,
},
};
}4. Balises hreflang
Les balises hreflang sont le signal SEO multilingue le plus important. Elles indiquent aux moteurs de recherche : "cette page existe dans d’autres langues, et voici les URL correspondantes."
Sans hreflang, Google doit deviner quelle version linguistique afficher dans les résultats de recherche — et il se trompe souvent.
<link rel="alternate" hreflang="en" href="https://example.com/about" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/about" />
<link rel="alternate" hreflang="es" href="https://example.com/es/about" />
<link rel="alternate" hreflang="x-default" href="https://example.com/about" />La balise x-default indique aux moteurs de recherche quelle URL afficher lorsqu’aucune des langues spécifiées ne correspond à celle de l’utilisateur.
Dans Next.js, vous pouvez ajouter hreflang via la propriété alternates.languages de l’API de métadonnées.
Voici une fonction utilitaire réutilisable qui fonctionne avec gt-next :
import { getLocale, getDefaultLocale } from 'gt-next/server';
const BASE_URL = 'https://example.com';
const SUPPORTED_LOCALES = ['en', 'fr', 'es'];
export async function getI18NMetadata(path: string) {
const locale = await getLocale();
const defaultLocale = getDefaultLocale();
const getUrl = (loc: string) => {
const prefix = loc === defaultLocale ? '' : `/${loc}`;
return `${BASE_URL}${prefix}${path}`;
};
const languages: Record<string, string> = {};
for (const loc of SUPPORTED_LOCALES) {
languages[loc] = getUrl(loc);
}
languages['x-default'] = getUrl(defaultLocale);
return {
alternates: {
canonical: getUrl(locale),
languages,
},
};
}Utilisez-le ensuite dans n’importe quelle page :
import { getI18NMetadata } from '@/lib/i18n-metadata';
export async function generateMetadata() {
return await getI18NMetadata('/about');
}Cela génère à la fois la balise canonique et toutes les balises hreflang en un seul appel.
5. Métadonnées traduites
Les moteurs de recherche affichent le titre et la description de votre page dans les résultats. S’ils sont en anglais alors que la page est en français, les utilisateurs cliqueront moins volontiers — et Google peut reléguer ce résultat plus bas dans le classement.
Utilisez la fonction getGT de gt-next pour traduire les chaînes de caractères des métadonnées :
import { getGT } from 'gt-next/server';
import { getI18NMetadata } from '@/lib/i18n-metadata';
export async function generateMetadata() {
const t = await getGT();
const i18nMeta = await getI18NMetadata('/about');
return {
title: t('About Us'),
description: t('Learn about our mission and team.'),
...i18nMeta,
};
}Vous obtenez ainsi des titres et des descriptions localisés dans les résultats de recherche, ce qui améliore considérablement le taux de clics pour les requêtes dans des langues autres que l’anglais.
6. Plans de site multilingues
Un plan de site aide les moteurs de recherche à découvrir toutes vos pages, y compris chaque version linguistique. Pour les sites multilingues, vous devez également inclure des annotations hreflang dans votre plan de site.
Next.js prend en charge les plans de site générés par programmation via un fichier sitemap.ts :
import { MetadataRoute } from 'next';
const BASE_URL = 'https://example.com';
const LOCALES = ['en', 'fr', 'es'];
const DEFAULT_LOCALE = 'en';
const PAGES = ['/', '/about', '/blog', '/contact'];
export default function sitemap(): MetadataRoute.Sitemap {
return PAGES.flatMap((path) => {
const getUrl = (locale: string) => {
const prefix = locale === DEFAULT_LOCALE ? '' : `/${locale}`;
return `${BASE_URL}${prefix}${path === '/' ? '' : path}`;
};
const languages: Record<string, string> = {};
for (const locale of LOCALES) {
languages[locale] = getUrl(locale);
}
return LOCALES.map((locale) => ({
url: getUrl(locale),
lastModified: new Date(),
alternates: { languages },
}));
});
}Cela génère un plan de site avec une entrée par page et par paramètre régional, et chaque entrée inclut des annotations hreflang pointant vers toutes les versions en langue.
Liste de contrôle
Voici un bref résumé de tout ce qui précède :
| Exigence SEO | Implémentation |
|---|---|
| Paramètre régional dans l’URL | createNextMiddleware() avec le segment dynamique [locale] |
Attribut HTML lang | useLocale() dans le layout racine |
| URL canoniques | getLocale() + API de métadonnées de Next.js alternates.canonical |
| Balises hreflang | API de métadonnées de Next.js alternates.languages avec tous les paramètres régionaux pris en charge |
| Métadonnées traduites | getGT() pour les titres et descriptions de page |
| Plan de site multilingue | sitemap.ts avec des entrées par paramètre régional et des alternatives hreflang |
Prochaines étapes
- démarrage rapide de gt-next pour configurer l’ensemble de la pile i18n
- Guide du middleware pour configurer le routage
- Guide SSG pour générer des pages multilingues de façon statique
- Prise en charge RTL pour les langues s’écrivant de droite à gauche