Comment créer des sitemaps multilingues dans Next.js (Pages Router) v16
Organiser les sitemaps par langue pour une meilleure évolutivité
Problème
Les sitemaps aident les moteurs de recherche à découvrir et indexer les pages d'un site web. Pour un site multilingue avec des centaines ou des milliers de pages par langue, un sitemap unique répertoriant chaque URL pour chaque locale devient rapidement ingérable. Les sitemaps monolithiques volumineux peuvent dépasser les limites de 50 000 URLs ou de 50 Mo définies par le protocole sitemap, les rendant invalides. Même lorsqu'ils restent dans les limites, régénérer et valider un fichier massif chaque fois que le contenu change dans une langue est inefficace. À mesure que le site se développe et ajoute plus de langues ou de pages, cette approche ne s'adapte pas.
Solution
Organisez les sitemaps en hiérarchie à l'aide d'un fichier d'index de sitemap. Le fichier d'index répertorie des sitemaps spécifiques à chaque langue, chacun contenant des URLs pour une seule locale. Cette structure maintient les fichiers sitemap individuels gérables et dans les limites du protocole. Lorsque le contenu change dans une langue, seul le sitemap de cette langue doit être régénéré. L'approche s'adapte naturellement à mesure que de nouvelles langues sont ajoutées—chacune obtient son propre sitemap référencé dans l'index. Les moteurs de recherche explorent d'abord l'index, puis suivent les liens vers les sitemaps de chaque langue.
Étapes
1. Créer une page d'index de sitemap
Créez une page dans le répertoire pages pour générer dynamiquement l'index de sitemap en utilisant getServerSideProps.
import { GetServerSideProps } from "next";
const SITE_URL = "https://example.com";
const LOCALES = ["en", "es", "fr", "de"];
function generateSitemapIndex(locales: string[]): string {
const sitemapEntries = locales
.map((locale) => {
return `
<sitemap>
<loc>${SITE_URL}/sitemap-${locale}.xml</loc>
<lastmod>${new Date().toISOString()}</lastmod>
</sitemap>`;
})
.join("");
return `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${sitemapEntries}
</sitemapindex>`;
}
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
const sitemap = generateSitemapIndex(LOCALES);
res.setHeader("Content-Type", "text/xml");
res.write(sitemap);
res.end();
return {
props: {},
};
};
export default function SitemapIndex() {}
L'index utilise l'élément racine <sitemapindex> avec des entrées <sitemap>, chacune contenant un enfant <loc> pointant vers un sitemap spécifique à une langue. La fonction getServerSideProps définit l'en-tête Content-Type sur text/xml et écrit directement la réponse XML.
2. Créer des pages de plan du site spécifiques à chaque langue
Créez une page de route dynamique pour générer des plans du site individuels pour chaque langue.
import { GetServerSideProps } from "next";
const SITE_URL = "https://example.com";
interface PageData {
slug: string;
lastModified: string;
}
async function getPagesByLocale(locale: string): Promise<PageData[]> {
return [
{ slug: "about", lastModified: "2024-01-15" },
{ slug: "contact", lastModified: "2024-01-20" },
];
}
function generateSitemap(locale: string, pages: PageData[]): string {
const urlEntries = pages
.map((page) => {
return `
<url>
<loc>${SITE_URL}/${locale}/${page.slug}</loc>
<lastmod>${page.lastModified}</lastmod>
</url>`;
})
.join("");
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urlEntries}
</urlset>`;
}
export const getServerSideProps: GetServerSideProps = async ({
params,
res,
}) => {
const locale = params?.locale as string;
const pages = await getPagesByLocale(locale);
const sitemap = generateSitemap(locale, pages);
res.setHeader("Content-Type", "text/xml");
res.write(sitemap);
res.end();
return {
props: {},
};
};
export default function LocaleSitemap() {}
La route dynamique extrait la locale des paramètres d'URL et génère un XML contenant uniquement les URLs pour cette langue. Chaque plan du site reste concentré sur le contenu d'une seule locale.
3. Récupérer le contenu spécifique à la locale
Remplacez la fonction getPagesByLocale de substitution par votre source de données réelle.
async function getPagesByLocale(locale: string): Promise<PageData[]> {
const response = await fetch(
`https://api.example.com/pages?locale=${locale}`,
);
const data = await response.json();
return data.pages.map((page: any) => ({
slug: page.slug,
lastModified: page.updatedAt,
}));
}
Cette fonction interroge votre CMS, base de données ou API pour récupérer les pages pour la locale spécifiée. Elle renvoie des données structurées que le générateur de plan du site transforme en entrées XML.
4. Ajouter des pages statiques à chaque plan du site
Incluez des routes statiques qui existent dans chaque langue à côté du contenu dynamique.
function generateSitemap(locale: string, pages: PageData[]): string {
const staticPages = [
{ slug: "", lastModified: new Date().toISOString() },
{ slug: "about", lastModified: new Date().toISOString() },
];
const allPages = [...staticPages, ...pages];
const urlEntries = allPages
.map((page) => {
const path = page.slug ? `/${locale}/${page.slug}` : `/${locale}`;
return `
<url>
<loc>${SITE_URL}${path}</loc>
<lastmod>${page.lastModified}</lastmod>
</url>`;
})
.join("");
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urlEntries}
</urlset>`;
}
La combinaison de pages statiques et dynamiques garantit que chaque plan du site linguistique est complet. Les pages statiques utilisent l'horodatage actuel comme date de dernière modification.
5. Référencer l'index dans robots.txt
Ajoutez l'emplacement de l'index du sitemap à votre fichier robots.txt pour que les moteurs de recherche puissent le découvrir.
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
Vous n'avez besoin de lister que le fichier d'index ; les moteurs de recherche suivront automatiquement les liens vers les sitemaps de chaque langue. Placez ce fichier dans le répertoire public.