Creación de un índice de mapa del sitio para múltiples idiomas

Gestión de sitios grandes y multilingües para SEO

Problema

Un sitio tiene un gran número de páginas en varios idiomas. Un único archivo sitemap.xml masivo que enumere todas las URL para cada idioma es ineficiente, difícil de gestionar y puede exceder los límites de tamaño de archivo. Esto dificulta la actualización de 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.

Crea 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 de idiomas

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

Crea app/sitemap-[lang].xml/route.ts.

// app/sitemap-[lang].xml/route.ts
import { locales, siteBaseUrl } from '@/i18n-config';

// Esto indica a Next.js qué sitemaps construir en tiempo de compilación
export async function generateStaticParams() {
  return locales.map((lang) => ({
    lang,
  }));
}

// Una función auxiliar para obtener todas las páginas de un idioma
// En una aplicación real, esto obtendría datos de un CMS o base de datos
async function getPagesForLanguage(lang: string): Promise<string[]> {
  // Estas son rutas relativas, *sin* el prefijo de idioma
  // por ejemplo, '/', '/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.