Crear un índice de sitemap para múltiples idiomas

Gestionar sitios grandes multiidioma para SEO

Problema

Un sitio tiene un gran número de páginas en muchos idiomas. Un único archivo sitemap.xml masivo que enumera cada URL para cada idioma es ineficiente, difícil de gestionar y puede exceder los límites de tamaño de archivo. Esto dificulta actualizar las URL de un idioma o que los motores de búsqueda descubran eficientemente todo el contenido.

Solución

Crear un archivo sitemap.xml que actúe como un "índice de sitemap", apuntando a otros sitemaps específicos por idioma (por ejemplo, sitemap-en.xml, sitemap-es.xml). Este enfoque organiza el contenido, es más fácil de gestionar y escala eficientemente a medida que se añaden nuevos idiomas o páginas.

Pasos

1. Crear la ruta del índice de sitemap

En lugar del archivo sitemap.ts, debes crear un manejador de ruta estándar. Esto te da control total para generar un índice de sitemap.

Crear 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',
    },
  });
}

Este archivo indica a los motores de búsqueda que el sitemap de tu sitio es un índice que apunta a otros archivos, como sitemap-en.xml, sitemap-es.xml, etc.

2. Crear la ruta dinámica para sitemaps por idioma

A continuación, crea la ruta dinámica que generará cada sitemap específico por idioma.

Crear 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',
    },
  });
}

Ahora, tu archivo sitemap.xml es un índice limpio, y las URL de cada idioma están organizadas ordenadamente en sus propios archivos (por ejemplo, /sitemap-en.xml), que son generados por esta ruta dinámica.