Создание индексного sitemap для нескольких языков
Управление большими многоязычными сайтами для SEO
Проблема
На сайте много страниц на разных языках. Один огромный файл sitemap.xml, в котором перечислены все URL для всех языков, неэффективен, неудобен в управлении и может превышать лимиты размера файла. Это усложняет обновление URL для одного языка и мешает поисковым системам быстро находить весь контент.
Решение
Создайте файл sitemap.xml, который будет выступать в роли «индекса sitemap» и указывать на отдельные sitemap для каждого языка (например, sitemap-en.xml, sitemap-es.xml). Такой подход структурирует контент, упрощает управление и легко масштабируется при добавлении новых языков или страниц.
Шаги
1. Создайте маршрут для индексного sitemap
Вместо файла sitemap.ts нужно создать стандартный обработчик маршрута. Это даст полный контроль для генерации индексного sitemap.
Создайте app/sitemap.xml/route.ts.
// app/sitemap.xml/route.ts
import { locales, siteBaseUrl } from '@/i18n-config';
export async function GET() {
const sitemapIndex = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="[http://www.sitemaps.org/schemas/sitemap/0.9](http://www.sitemaps.org/schemas/sitemap/0.9)">
${locales
.map((locale) => {
return `
<sitemap>
<loc>${siteBaseUrl}/sitemap-${locale}.xml</loc>
<lastmod>${new Date().toISOString()}</lastmod>
</sitemap>`;
})
.join('')}
</sitemapindex>
`;
return new Response(sitemapIndex, {
headers: {
'Content-Type': 'application/xml',
},
});
}
Этот файл сообщает поисковым системам, что sitemap вашего сайта — это индекс, который указывает на другие файлы, такие как sitemap-en.xml, sitemap-es.xml и т.д.
2. Создайте динамический маршрут для sitemap языков
Далее создайте динамический маршрут, который будет генерировать отдельный sitemap для каждого языка.
Создайте app/sitemap-[lang].xml/route.ts.
// app/sitemap-[lang].xml/route.ts
import { locales, siteBaseUrl } from '@/i18n-config';
// This tells Next.js which sitemaps to build at build time
export async function generateStaticParams() {
return locales.map((lang) => ({
lang,
}));
}
// A helper function to get all pages for a language
// In a real app, this would fetch from a CMS or database
async function getPagesForLanguage(lang: string): Promise<string[]> {
// These are relative paths, *without* the lang prefix
// e.g., '/', '/about', '/blog/my-post'
return ['/', '/about', '/contact'];
}
export async function GET(
request: Request,
{ params }: { params: { lang: string } }
) {
const { lang } = params;
if (!locales.includes(lang)) {
return new Response('Not Found', { status: 404 });
}
const pages = await getPagesForLanguage(lang);
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="[http://www.sitemaps.org/schemas/sitemap/0.9](http://www.sitemaps.org/schemas/sitemap/0.9)">
${pages
.map((page) => {
const path = page === '/' ? '' : page;
return `
<url>
<loc>${siteBaseUrl}/${lang}${path}</loc>
<lastmod>${new Date().toISOString()}</lastmod>
</url>`;
})
.join('')}
</urlset>
`;
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml',
},
});
}
Теперь ваш файл sitemap.xml — это чистый индекс, а URL каждого языка аккуратно разложены по своим файлам (например, /sitemap-en.xml), которые генерируются этим динамическим маршрутом.