feat: add sitemap.xml generation and sitemap <link> tag

Add app/sitemap.ts covering the homepage, supported-sites page, and
all 15 per-platform downloader pages across every locale, with
hreflang alternates between locales. Reference it from <head> via
<link rel="sitemap"> in the locale layout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 12:01:14 +02:00
co-authored by Claude Sonnet 5
parent fd7515f8c2
commit 1d27d22581
2 changed files with 34 additions and 0 deletions
+1
View File
@@ -75,6 +75,7 @@ export default async function LocaleLayout({
return ( return (
<html lang={locale} suppressHydrationWarning> <html lang={locale} suppressHydrationWarning>
<head> <head>
<link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml" />
<script <script
type="application/ld+json" type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
+33
View File
@@ -0,0 +1,33 @@
import type { MetadataRoute } from 'next'
import { routing } from '@/i18n/routing'
import { DOWNLOADER_PLATFORMS } from '@/lib/downloader-platforms'
const STATIC_PATHS = ['', 'supported-sites']
function urlFor(baseUrl: string, locale: string, path: string) {
return `${baseUrl}/${locale}${path ? `/${path}` : ''}`
}
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? ''
const paths = [...STATIC_PATHS, ...DOWNLOADER_PLATFORMS.map((platform) => platform.slug)]
const entries: MetadataRoute.Sitemap = []
for (const path of paths) {
const languages = Object.fromEntries(
routing.locales.map((locale) => [locale, urlFor(baseUrl, locale, path)])
)
for (const locale of routing.locales) {
entries.push({
url: languages[locale],
alternates: { languages },
changeFrequency: path === '' ? 'weekly' : 'monthly',
priority: path === '' ? 1 : path === 'supported-sites' ? 0.5 : 0.8,
})
}
}
return entries
}