Saltar al contenido
Neaptideestudio
blog

Hreflang en Next.js con traducciones pendientes: un ejemplo probado

Neaptide · 4 de octubre de 2026 · 9 min de lectura

Un experimento reproducible en Next.js y 18 URL publicadas revisadas: coordina hreflang, canonical, sitemap y selector cuando faltan traducciones.

En este artículo
El perfil full existe en en, ru, fr, es, it y zh; partial en en, ru y fr; original solo en en. Diez combinaciones publicadas y ocho ausentes.

Genera los enlaces de idioma a partir de las traducciones publicadas de cada página, no de todos los idiomas del sitio. Usa el mismo registro de disponibilidad para hreflang, sitemap y selector. Que el francés figure en la configuración global no significa que un artículo ya tenga versión francesa.

Lo probamos el 4 de octubre de 2026. Una configuración de Next.js deliberadamente incorrecta creó 14 enlaces hreflang y 14 enlaces de navegación hacia traducciones inexistentes, además de ocho URL inexistentes en el sitemap. Usar la disponibilidad por página eliminó los tres desajustes. Por separado, 18 URL publicadas de Neaptide superaron las comprobaciones siguientes. Ningún conjunto de datos mide posiciones ni indexación de Google.

Dos conjuntos de datos con funciones distintas

La muestra publicada incluye tres rutas en seis idiomas: el servicio GEO, la guía de webs multilingües y el artículo sobre catálogos B2B. Hicimos dos pasadas HTTP, inspeccionamos cada página renderizada y probamos un cambio de idioma por URL. Una conexión se reinició; el reintento registrado por separado tuvo éxito. Fueron 37 intentos y 36 respuestas correctas, sin ocultar el fallo inicial.

Páginas publicadas de Neaptide: seis URL por ruta
RutaURL revisadasMetadatos + sitemapCambios de idioma
/services/geo66 / 66 / 6
/blog/multilingual-website-guide66 / 66 / 6
/blog/b2b-catalog-seo66 / 66 / 6

Las 18 URL devolvieron 200, mantuvieron un canonical propio y coincidieron con las anotaciones del sitemap. Cada una declaró seis variantes y el inglés como x-default. Los 18 cambios probados conservaron la ruta. Es una acción por URL de origen, no todas las parejas de idiomas ni todo el sitio. Se examinó el artículo B2B publicado, no su nueva versión de investigación local.

Una prueba controlada de traducciones incompletas

Creamos un proyecto App Router separado con Next.js 15.5.22, React 19.2.6 y Node.js v25.2.1. Antes de medir fijamos tres perfiles: seis traducciones, tres traducciones y solo el original inglés. Cada fase tiene 18 combinaciones de ruta e idioma: 10 páginas disponibles y ocho ausentes. Dos pasadas HTTP antes y después produjeron 72 observaciones; también abrimos las 36 combinaciones en un navegador.

El perfil full existe en en, ru, fr, es, it y zh; partial en en, ru y fr; original solo en en. Diez combinaciones publicadas y ocho ausentes.
Proyecto de prueba controlado, no muestra de mercado. Las celdas verdes tienen contenido publicado; las vacías siguieron devolviendo 404 en ambas fases.

En la fase incorrecta, las tres salidas usaban la lista global de seis idiomas. Tras corregirla, usaban los registros reales de traducción. Las páginas disponibles conservaron su propio canonical. No creamos contenido de sustitución ni redirigimos traducciones ausentes a la página de inicio.

Desajustes medidos en la configuración deliberadamente incorrecta
PerfilEnlaces hreflang erróneos: antes → despuésEnlaces del selector erróneos: antes → despuésURL ausentes en sitemap: antes → después
6 idiomas0 → 00 → 00 → 0
3 idiomas9 → 09 → 03 → 0
1 idioma5 → 05 → 05 → 0

Las unidades difieren: cada enlace se cuenta por página de origen; cada URL del sitemap, por entrada. Su suma no es un número de páginas rotas. Las dos pasadas HTTP coincidieron y las 36 comprobaciones DOM concordaron con el HTML. Cinco clics confirmaron tres transiciones válidas y dos enlaces erróneos que llevaban a 404. La prueba no mide la frecuencia del defecto.

Usa un único registro de disponibilidad

En el proyecto, TRANSLATIONS solo contiene contenido publicado. availableLocales obtiene sus idiomas y generateStaticParams crea esas rutas. Con dynamicParams = false, las combinaciones ausentes siguen sin estar disponibles; las funciones de página y metadatos también comprueban el registro. El fragmento usa las mismas funciones del proyecto probado. La descarga contiene ambas fases; consulta la rama after para estudiar la corrección.

export const availableLocales = profile => Object.keys(TRANSLATIONS[profile] || {});
export const translation = (profile, locale) => TRANSLATIONS[profile]?.[locale];
export const pageUrl = (profile, locale, phase) => `${ORIGIN}/${locale}/${phase}/${profile}`;
export async function generateMetadata({ params }) {
  const { phase, profile, locale } = await params;
  const content = translation(profile, locale);
  if (!PHASES.includes(phase) || !content) notFound();
  return {
    title: content.title,
    alternates: { canonical: pageUrl(profile, locale, phase), languages: languageAlternates(profile, phase) },
  };
}

En la rama after, languageAlternates solo devuelve equivalentes publicados. Añade el inglés como x-default a los perfiles multilingües y omite anotaciones de idioma en el perfil exclusivamente inglés. Es una elección explícita. Si el original está en otro idioma, elige un destino existente para ese grupo. Si los slugs varían, guarda las URL equivalentes en vez de sustituir un prefijo; no probamos slugs traducidos aquí.

Canonical, hreflang y navegación cumplen funciones distintas

Canonical identifica la URL preferida; hreflang conecta equivalentes localizados. Nuestras traducciones usan canonical propios. El selector debe llevar al mismo contenido en un idioma disponible. Un enlace opcional y bien identificado al inicio de otro idioma es navegación normal, no la traducción de una página ausente.

Google describe enlaces de idioma absolutos, recíprocos y con autorreferencia. HTML y sitemap son métodos alternativos; comparamos ambos porque el proyecto utiliza los dos.

Cuando la traducción todavía no está lista

Retira la versión ausente del grupo de traducciones y del selector de páginas equivalentes. Excluye los borradores del sitemap público. Si ofreces el original inglés, identifica su idioma y enlaza su URL inglesa real. Una respuesta 200 con texto inglés bajo una ruta francesa no demuestra que exista una traducción francesa.

En nuestro proyecto estático, las ocho combinaciones ausentes devolvían 404 y noindex en ambas fases. Medimos las respuestas reales. Una implementación dinámica o con streaming necesita comprobar sus propios estados; encontrar notFound() en el código no basta como observación.

Comprueba el resultado tras cada nueva traducción

  1. Abre cada equivalente publicado y revisa estado, URL final, idioma y canonical.
  2. Compara cada alternativa anunciada con el registro de disponibilidad y comprueba el destino y sus enlaces de vuelta.
  3. Contrasta el sitemap con el contenido publicado. Si incluye anotaciones de idioma, compáralas con el HTML.
  4. Usa el selector en las páginas afectadas. Prueba una traducción disponible y el comportamiento ante una ausente.
  5. Repite al publicar o retirar una traducción. Conserva fecha, ruta y evidencia; observa la indexación por separado en Search Console.

Reproduce la prueba

Descarga el proyecto fuente, los resultados y la metodología completa. El ZIP excluye dependencias y archivos compilados. Compila y arranca el proyecto en el puerto indicado y ejecuta el recopilador HTTP. Las pruebas originales del navegador se documentan por separado; el recopilador no las repite.

Es una prueba técnica del mismo día realizada por un investigador. Abarca tres rutas publicadas y ejemplos estáticos controlados, no la calidad de todas las traducciones, el canonical elegido por Google, la indexación, las posiciones, el tráfico ni las citas de IA.

faq

Lo esencial en breve

¿Debe hreflang incluir todos los idiomas del sitio?

Incluye los equivalentes publicados de esa página. La lista general de idiomas no demuestra que cada artículo exista en todos ellos.

¿Deben usar todas las traducciones el canonical inglés?

Nuestras traducciones conservan canonical propios. No designes el original inglés como canonical de cada traducción distinta solo porque se publicó primero.

¿X-default tiene que apuntar al inglés?

No. El inglés es el destino disponible que elegimos para esta prueba. Selecciona una página existente adecuada para tus usuarios y ese grupo de traducciones.

¿Eliminar los enlaces incorrectos mejoró las posiciones?

No medimos posiciones. El resultado observado fue la desaparición de enlaces de idioma inválidos y entradas ausentes en el sitemap, manteniendo disponibles las páginas previstas.