Wie man mehrsprachige Sitemaps in Next.js (Pages Router) v16 erstellt
Organisieren Sie Sitemaps nach Sprachen für Skalierbarkeit
Problem
Sitemaps helfen Suchmaschinen, Seiten einer Website zu entdecken und zu indexieren. Bei einer mehrsprachigen Website mit Hunderten oder Tausenden von Seiten pro Sprache wird eine einzelne Sitemap, die jede URL für jede Locale auflistet, schnell unüberschaubar. Große monolithische Sitemaps können die im Sitemap-Protokoll definierten Grenzen von 50.000 URLs oder 50 MB Größe überschreiten, was sie ungültig macht. Selbst wenn sie innerhalb der Grenzen bleiben, ist es ineffizient, eine massive Datei jedes Mal neu zu generieren und zu validieren, wenn sich Inhalte in einer Sprache ändern. Mit dem Wachstum der Website und der Hinzufügung weiterer Sprachen oder Seiten skaliert dieser Ansatz nicht.
Lösung
Organisieren Sie Sitemaps in einer Hierarchie mit einer Sitemap-Indexdatei. Die Indexdatei listet separate sprachspezifische Sitemaps auf, die jeweils URLs für eine einzelne Locale enthalten. Diese Struktur hält einzelne Sitemap-Dateien überschaubar und innerhalb der Protokollgrenzen. Wenn sich Inhalte in einer Sprache ändern, muss nur die Sitemap dieser Sprache neu generiert werden. Der Ansatz skaliert natürlich, wenn neue Sprachen hinzugefügt werden – jede erhält ihre eigene Sitemap, auf die im Index verwiesen wird. Suchmaschinen crawlen zuerst den Index und folgen dann den Links zu den einzelnen Sprach-Sitemaps.
Schritte
1. Erstellen einer Sitemap-Indexseite
Erstellen Sie eine Seite im Verzeichnis pages, um den Sitemap-Index dynamisch mit getServerSideProps zu generieren.
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() {}
Der Index verwendet das Root-Element <sitemapindex> mit <sitemap>-Einträgen, die jeweils ein <loc>-Child enthalten, das auf eine sprachspezifische Sitemap verweist. Die Funktion getServerSideProps setzt den Content-Type-Header auf text/xml und schreibt die XML-Antwort direkt.
2. Sprachspezifische Sitemap-Seiten erstellen
Erstellen Sie eine dynamische Routenseite, um individuelle Sitemaps für jede Sprache zu generieren.
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() {}
Die dynamische Route extrahiert die Locale aus URL-Parametern und generiert XML, das nur URLs für diese Sprache enthält. Jede Sitemap bleibt auf den Inhalt einer einzelnen Locale fokussiert.
3. Sprachspezifische Inhalte abrufen
Ersetzen Sie die Platzhalter-Funktion getPagesByLocale durch Ihre tatsächliche Datenquelle.
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,
}));
}
Diese Funktion fragt Ihr CMS, Ihre Datenbank oder API ab, um Seiten für die angegebene Locale abzurufen. Sie gibt strukturierte Daten zurück, die der Sitemap-Generator in XML-Einträge umwandelt.
4. Statische Seiten zu jeder Sitemap hinzufügen
Fügen Sie statische Routen, die in jeder Sprache existieren, neben dynamischen Inhalten ein.
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>`;
}
Die Kombination von statischen und dynamischen Seiten stellt sicher, dass jede Sprach-Sitemap vollständig ist. Statische Seiten verwenden den aktuellen Zeitstempel als Datum ihrer letzten Änderung.
5. Referenzieren Sie den Index in robots.txt
Fügen Sie den Standort des Sitemap-Index in Ihre robots.txt-Datei ein, damit Suchmaschinen ihn entdecken können.
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
Sie müssen nur die Indexdatei auflisten; Suchmaschinen folgen automatisch den Links zu einzelnen Sprach-Sitemaps. Platzieren Sie diese Datei im Verzeichnis public.