Wie man mehrsprachige Sitemaps in TanStack Start v1 erstellt
Sitemaps nach Sprache für Skalierbarkeit organisieren
Problem
Sitemaps helfen Suchmaschinen, alle Seiten einer Website zu entdecken und zu crawlen. Eine mehrsprachige Website mit Hunderten oder Tausenden von Seiten pro Sprache kann schnell enorme Sitemaps generieren. Eine einzelne Datei, die jede URL für jede Sprache auflistet, wird unhandlich und kann die im Sitemap-Protokoll definierten Grenzen von 50.000 URLs oder 50 MB Größe überschreiten. Wenn Sie die Struktur einer Sprache aktualisieren, müssen Sie die gesamte Datei neu generieren und validieren. Große monolithische Sitemaps sind schwer zu warten, langsam zu verarbeiten und skalieren nicht, wenn Sie Sprachen oder Inhalte hinzufügen.
Lösung
Teilen Sie Ihre Sitemap in mehrere Dateien auf und verwenden Sie eine Sitemap-Indexdatei, um viele Sitemaps auf einmal einzureichen. Erstellen Sie einen Sitemap-Index auf oberster Ebene unter /sitemap.xml, der auf separate, sprachspezifische Sitemaps wie /sitemap-en.xml und /sitemap-es.xml verweist. Das XML-Format einer Sitemap-Indexdatei ähnelt einer regulären Sitemap und ist durch das Sitemap-Protokoll definiert. Dies hält einzelne Dateien überschaubar, ermöglicht die unabhängige Aktualisierung jeder Sprache und skaliert gut, wenn Sie neue Sprachen oder Seiten hinzufügen.
Schritte
1. Erstellen Sie einen Helper zur Generierung von Sitemap-XML
Erstellen Sie eine Hilfsfunktion, die aus einem Array von URL-Einträgen gültiges Sitemap-XML generiert.
export function generateSitemapXML(urls: Array<{ loc: string; lastmod?: string; changefreq?: string; priority?: number }>): string {
const entries = urls.map(url => {
let entry = ` <url>
<loc>${url.loc}</loc>`
if (url.lastmod) entry += `
<lastmod>${url.lastmod}</lastmod>`
if (url.changefreq) entry += `
<changefreq>${url.changefreq}</changefreq>`
if (url.priority !== undefined) entry += `
<priority>${url.priority}</priority>`
entry += `
</url>`
return entry
}).join('
')
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${entries}
</urlset>`
}
Diese Funktion akzeptiert ein Array von URL-Objekten und gibt einen korrekt formatierten XML-String mit dem erforderlichen Namespace und der erforderlichen Struktur zurück.
2. Erstellen Sie einen Helper zur Generierung der Sitemap-Index-XML
Erstellen Sie eine zweite Hilfsfunktion, die einen Sitemap-Index generiert, der auf mehrere untergeordnete Sitemaps verweist.
export function generateSitemapIndexXML(sitemaps: Array<{ loc: string; lastmod?: string }>): string {
const entries = sitemaps.map(sitemap => {
let entry = ` <sitemap>
<loc>${sitemap.loc}</loc>`
if (sitemap.lastmod) entry += `
<lastmod>${sitemap.lastmod}</lastmod>`
entry += `
</sitemap>`
return entry
}).join('
')
return `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${entries}
</sitemapindex>`
}
Der Sitemap-Index verwendet ein <sitemapindex>-Root-Tag und enthält einen <sitemap>-Eintrag für jede Sitemap, mit einem <loc>-Child-Eintrag für jedes übergeordnete Tag.
3. Definieren Sie eine Server-Route für den Haupt-Sitemap-Index
Erstellen Sie eine Server-Route unter /sitemap.xml, die den Sitemap-Index mit allen sprachspezifischen Sitemaps zurückgibt.
import { createFileRoute } from "@tanstack/react-router";
import { generateSitemapIndexXML } from "~/utils/sitemap";
const SUPPORTED_LOCALES = ["en", "es", "fr", "de"];
const BASE_URL = "https://example.com";
export const Route = createFileRoute("/sitemap")({
server: {
handlers: {
GET: async () => {
const sitemaps = SUPPORTED_LOCALES.map((locale) => ({
loc: `${BASE_URL}/sitemap-${locale}.xml`,
lastmod: new Date().toISOString().split("T")[0],
}));
const xml = generateSitemapIndexXML(sitemaps);
return new Response(xml, {
headers: {
"Content-Type": "application/xml",
"Cache-Control": "public, max-age=3600",
},
});
},
},
},
});
Diese Route generiert einen Index, der auf eine Sitemap pro Sprache verweist und wird als XML mit entsprechenden Caching-Headern bereitgestellt.
4. Definieren Sie Server-Routen für sprachspezifische Sitemaps
Erstellen Sie eine dynamische Server-Route, die eine Sitemap für jede Sprache basierend auf dem Locale-Parameter generiert.
import { createFileRoute } from "@tanstack/react-router";
import { generateSitemapXML } from "~/utils/sitemap";
const BASE_URL = "https://example.com";
async function getUrlsForLocale(locale: string) {
return [
{ loc: `${BASE_URL}/${locale}`, changefreq: "daily", priority: 1.0 },
{
loc: `${BASE_URL}/${locale}/about`,
changefreq: "monthly",
priority: 0.8,
},
{
loc: `${BASE_URL}/${locale}/contact`,
changefreq: "monthly",
priority: 0.8,
},
];
}
export const Route = createFileRoute("/sitemap-$locale")({
server: {
handlers: {
GET: async ({ params }) => {
const { locale } = params;
const urls = await getUrlsForLocale(locale);
const xml = generateSitemapXML(urls);
return new Response(xml, {
headers: {
"Content-Type": "application/xml",
"Cache-Control": "public, max-age=3600",
},
});
},
},
},
});
Server-Routen unterstützen dynamische Pfadparameter auf die gleiche Weise wie TanStack Router, sodass eine Datei mit dem Namen $locale eine Route erstellt, die einen dynamischen Locale-Parameter akzeptiert. Jede sprachspezifische Sitemap wird unabhängig generiert und kann aktualisiert werden, ohne andere Sprachen zu beeinflussen.
5. URLs aus Ihrer Datenquelle abrufen
Ersetzen Sie die Platzhalter-Funktion getUrlsForLocale mit Logik, die tatsächliche URLs aus Ihrer Datenbank, CMS oder Routendefinitionen abruft.
async function getUrlsForLocale(locale: string) {
const pages = await db.page.findMany({
where: { locale, published: true },
select: { slug: true, updatedAt: true },
});
return pages.map((page) => ({
loc: `${BASE_URL}/${locale}/${page.slug}`,
lastmod: page.updatedAt.toISOString().split("T")[0],
changefreq: "weekly",
priority: 0.7,
}));
}
Dieses Beispiel fragt eine Datenbank nach veröffentlichten Seiten in der angegebenen Sprache ab und ordnet sie Sitemap-Einträgen mit Metadaten zu. Passen Sie die Abfrage- und Zuordnungslogik an Ihr Datenmodell und Ihre URL-Struktur an.