为多语言网站创建 sitemap 索引

管理大型多语言站点以提升 SEO

问题

一个网站拥有大量页面,并支持多种语言。如果将所有语言的每个 URL 都列在一个庞大的 sitemap.xml 文件中,不仅效率低下,难以维护,还可能超出文件大小限制。这会导致单独更新某一语言的 URL 变得困难,也不利于搜索引擎高效发现全部内容。

解决方案

创建一个 sitemap.xml 文件,作为“sitemap 索引”,指向其他按语言划分的 sitemap(例如 sitemap-en.xmlsitemap-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.xmlsitemap-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),这些文件由该动态路由生成。