Eztebe
13 min de lectura

Web multilingüe: hreflang, URL traducidas y euskera, explicados con esta web como ejemplo

Hreflang, URL traducidas, x-default, euskera: una web en varios idiomas que Google entienda, con una web real como ejemplo y una herramienta de comprobación.

Escrito por

Una web multilingüe que se posiciona en cada idioma cabe en cinco reglas: una URL por idioma, traducida; etiquetas hreflang que forman un círculo completo; ninguna redirección según el idioma del navegador; un selector de idioma que lleva a la misma página; textos revisados por alguien que habla ese idioma.

Esta web es el ejemplo: tres idiomas, y todo lo que sigue sale de su código. Al final del artículo, una herramienta comprueba tus propias etiquetas.

Lo esencial

  • Google no indexa «traducciones», sino páginas: cada idioma tiene su URL, su título, su descripción y su contenido, un solo idioma por página.
  • Las etiquetas hreflang forman un círculo: cada versión cita a todas las demás y a sí misma, más una versión x-default. Si falta un enlace de vuelta, el par se ignora.
  • Nada de redirecciones automáticas según el idioma del navegador o la IP: Googlebot rastrea desde Estados Unidos y nunca vería tus páginas en castellano.
  • El selector de idioma lleva a la misma página en el otro idioma, nunca a la portada; y una bandera no es un idioma.
  • Para el euskera, como para cualquier idioma que no hables: traducir menos páginas, pero hacerlas revisar. Una mala versión vale menos que ninguna.

Una web multilingüe no es una web traducida

Para Google, un idioma es un conjunto de páginas distintas, cada una con su propia dirección, y no un botón que cambia los textos de la misma página. Una web en tres idiomas son, por tanto, tres webs que se responden, unidas por etiquetas que los buscadores entienden. Todo lo demás de este artículo se deduce de esa idea.

Tres prácticas habituales no producen ninguna página indexable: el widget de «traducir esta página» que sustituye los textos con JavaScript, las traducciones en paralelo dentro de la misma columna, y la traducción automática pegada sin revisar. En los tres casos Google ve una página, en un idioma, a veces dos mezclados, y tus clientes franceses no te encuentran.

Una web multilingüe de verdad cuesta más que traducir los textos, y por eso la cobro aparte, un 20 a 25 % por idioma. Ese suplemento paga lo que viene a continuación.

¿Dónde va el idioma en la URL?

En un directorio, casi siempre: /es/, /eu/, /fr/ en un solo dominio. Es lo más sencillo de gestionar, y toda la autoridad acumulada (enlaces, antigüedad) beneficia a todos los idiomas. Un dominio por país se justifica para marcas u ofertas realmente distintas, no para un despacho que habla con sus clientes a los dos lados del Bidasoa.

Las cuatro formas de colocar el idioma, y cuándo elegir cada una.

| Estructura | Ejemplo | Cuándo | | --- | --- | --- | | Directorio | eztebe.com/es/ | La opción por defecto: un dominio, una autoridad, una administración | | Dominio por país | ejemplo.es, ejemplo.fr | Ofertas, equipos o marcas distintas por país | | Subdominio | es.ejemplo.com | Rara vez útil hoy; hereda peor la autoridad del dominio principal | | Parámetro | ejemplo.com/?lang=es | Mejor evitarlo: Google lo desaconseja y las URL son ilegibles |

Una palabra sobre el .eus. Ese dominio existe para la comunidad vascohablante y tiene sentido para una web escrita en euskera. Yo elegí eztebe.com, no eztebe.eus: esta web no está en euskera, y un .eus sin euskera sería una promesa incumplida.

URL traducidas, no solo con prefijo

Una URL traducida contiene la palabra que la gente escribe en su idioma. Mi página de «web corporativa» se llama /es/servicios/web-corporativa, /fr/services/site-vitrine y /en/services/business-website: tres nombres distintos, porque la palabra clave no es la misma en los tres mercados. Un simple prefijo (/es/services/site-vitrine) daría una página en castellano con una URL en francés.

Técnicamente, hace falta una tabla de correspondencia entre la ruta interna y la ruta pública de cada idioma. En esta web cabe en un archivo:

// src/i18n/routing.ts (extracto)
export const routing = defineRouting({
  locales: ["fr", "es", "en"],
  defaultLocale: "fr",
  localePrefix: "always",
  localeDetection: false,
  pathnames: {
    "/services/[slug]": { fr: "/services/[slug]", es: "/servicios/[slug]", en: "/services/[slug]" },
    "/projets": { fr: "/projets", es: "/proyectos", en: "/projects" },
    "/a-propos": { fr: "/a-propos", es: "/sobre-mi", en: "/about" },
    "/contact": "/contact",
  },
});

El propio [slug] se traduce: site-vitrine pasa a ser web-corporativa. Esa tabla se usa después tres veces: para los enlaces internos, para las etiquetas hreflang y para el selector de idioma. Así se garantiza que los tres cuentan la misma historia.

El círculo hreflang

La etiqueta hreflang le dice a Google: «esta página existe también en francés, en esta dirección». Cada versión de la página lleva la lista completa de versiones, incluida ella misma, más una versión por defecto, x-default. Google solo acepta la relación si es recíproca: si la página francesa no cita a la página en castellano, el par se ignora.

Hay tres formas de declarar estas etiquetas: en el <head> de la página, en una cabecera HTTP Link o en el sitemap. Con una basta; dos no hacen daño si dicen exactamente lo mismo, pero es mantenimiento por duplicado. Esta web usa el <head> y el sitemap, generados por el mismo código, así que no pueden contradecirse.

Los códigos siguen la norma ISO 639-1 para el idioma, con una región ISO 3166-1 opcional: es, eu, fr, en-GB. Una región sola (ES) no es válida; es_ES con guion bajo, tampoco. Añade la región solo si el contenido cambia de verdad de un país a otro: es-MX para una página con precios y vocabulario mexicanos; si no, es a secas, que cubre a todos los hispanohablantes.

El círculo: lo que contiene el <head> de cada una de las tres versiones

Versión FR

eztebe.com/fr/services/site-vitrine

  1. hreflang="fr"/fr/services/site-vitrineella misma
  2. hreflang="es"/es/servicios/web-corporativa
  3. hreflang="en"/en/services/business-website
  4. hreflang="x-default"/fr/services/site-vitrine

Versión ES

eztebe.com/es/servicios/web-corporativa

  1. hreflang="fr"/fr/services/site-vitrine
  2. hreflang="es"/es/servicios/web-corporativaella misma
  3. hreflang="en"/en/services/business-website
  4. hreflang="x-default"/fr/services/site-vitrine

Versión EN

eztebe.com/en/services/business-website

  1. hreflang="fr"/fr/services/site-vitrine
  2. hreflang="es"/es/servicios/web-corporativa
  3. hreflang="en"/en/services/business-websiteella misma
  4. hreflang="x-default"/fr/services/site-vitrine

Las tres listas son idénticas, salvo por una línea: cada página aparece en ellas, incluida ella misma, y x-default señala la versión francesa, la que se sirve cuando ningún idioma coincide. Ejemplo real, tomado de esta web.

En esta web, la lista la construye una única función, llamada por cada página. Produce la canónica, los hreflang y el x-default, y deja fuera los idiomas en los que la página no existe:

// src/lib/seo.ts (extracto)
const languages: Record<string, string> = {};
for (const l of locales) {
  const h = hrefFor(l); // null si la página no existe en ese idioma
  if (h) languages[l] = absoluteUrl(l, h);
}
languages["x-default"] = absoluteUrl(defaultLocale, hrefFor(defaultLocale)!);

return {
  alternates: { canonical: absoluteUrl(locale, hrefFor(locale)!), languages },
};

Lo que sale en el HTML de la página en castellano:

<link rel="canonical" href="https://www.eztebe.com/es/servicios/web-corporativa">
<link rel="alternate" hreflang="fr" href="https://www.eztebe.com/fr/services/site-vitrine">
<link rel="alternate" hreflang="es" href="https://www.eztebe.com/es/servicios/web-corporativa">
<link rel="alternate" hreflang="en" href="https://www.eztebe.com/en/services/business-website">
<link rel="alternate" hreflang="x-default" href="https://www.eztebe.com/fr/services/site-vitrine">

Dos detalles marcan la diferencia. Las URL son absolutas, con www y sin barra final, exactamente como las sirve la web: una URL que redirige rompe el círculo. Y la canónica de cada versión apunta a sí misma, nunca a la versión francesa: una canónica que señala otro idioma le dice a Google que ignore todo lo demás.

El sitemap repite la misma lista para cada URL, con la fecha real de última modificación del contenido:

// src/app/sitemap.ts (extracto): una entrada por idioma, cada una con todas las alternativas
locales.map((l) => ({
  url: absoluteUrl(l, hrefFor(l)!),
  lastModified: fechaDeActualizacionDelContenido,
  alternates: { languages }, // fr, es, en, x-default
}));

No redirijas según el idioma del navegador

Es tentador mandar a un visitante francés a /fr/ nada más llegar. Google lo desaconseja por una razón sencilla: Googlebot rastrea desde Estados Unidos, en inglés. Con una redirección automática nunca vería /es/ ni /fr/, y tus páginas en castellano no existirían para él. Lo mismo vale para una redirección según la dirección IP.

Esta web desactiva la detección (localeDetection: false), y su raíz redirige a /fr de forma permanente, con un 308, porque el idioma por defecto es fijo. Cada URL responde siempre lo mismo, a todo el mundo. Si quieres orientar al visitante, un aviso discreto «cette page existe en français» cumple la función sin romper nada.

El selector de idioma lleva a la misma página

El selector de idioma es un enlace a la misma página en el otro idioma: la página de «web corporativa» en francés, no la portada francesa. Un visitante que cambia de idioma y cae en la portada se va. Cada enlace lleva los atributos hreflang y lang de su idioma de destino, y su texto está escrito en ese idioma: «Français», no «Francés».

Sin banderas. Una bandera señala un país, no un idioma: un lector vascohablante vive en España o en Francia, y un hispanohablante puede estar en Buenos Aires. La palabra basta, y la lee todo el mundo.

Una trampa vivida en esta web: en el momento de la generación estática, la ruta interna (/services/web-corporativa) y la ruta pública no coincidían en las páginas en castellano, y el HTML servido a los robots contenía enlaces del selector en 404 (/fr/services/web-corporativa). Nada visible en el navegador, donde todo se recalculaba en el cliente.

Lo descubrió un rastreo con Screaming Frog. Desde entonces el selector se apoya en la tabla de correspondencia de slugs, idéntica en la generación y en el navegador. Moraleja: revisa el HTML en bruto, no solo la pantalla.

El euskera, y cualquier idioma que no hables

En Gipuzkoa, una versión en euskera es una muestra de respeto, y a menudo lo que esperan las instituciones. Pero una versión en euskera chapucera hace más daño que ninguna versión: le dice al lector que no se le ha tomado en serio.

Yo no hablo euskera. Cuando un cliente la necesita, encargo la traducción a un traductor e integro su trabajo con las mismas etiquetas que los demás idiomas.

Tres reglas para un idioma que no dominas:

  1. Traducir menos, pero bien. La portada, los servicios, el contacto, el aviso legal. Los artículos del blog, solo cuando tienen sentido para ese público. Una página que no existe en un idioma no aparece en su círculo hreflang, y no pasa nada.
  2. Un idioma por página. Nada de párrafos en castellano en medio de una página en euskera. Un término suelto en otro idioma se marca con lang: <span lang="eu">amatxi</span>.
  3. Nada de traducción automática en bruto publicada. Google trata las traducciones automáticas publicadas en masa sin revisar como contenido de poco valor. Si una versión no se ha revisado, ponla en noindex o no la publiques todavía.

El código del euskera es eu, sin región: el euskera es el mismo a los dos lados de la frontera. Si el aviso legal o los precios cambian entre la versión para España y la de Francia, son dos páginas, eu-ES y eu-FR. Si no, una sola.

Los metadatos, idioma por idioma

Cada versión tiene su title, su descripción y su imagen para compartir, escritos a partir de las palabras clave que se buscan en ese idioma, no traducidos. «Web corporativa», «site vitrine» y «business website» no son traducciones entre sí: son las palabras que cada mercado escribe en Google.

El atributo lang de la página sigue la norma BCP 47 (es-ES, fr-FR, en-GB), y el código inLanguage de los datos estructurados dice lo mismo.

Los detalles que delatan una traducción: las fechas («30 de octubre de 2026» frente a «30 octobre 2026»), los números (3.000 € frente a 3 000 €), la puntuación (los signos de apertura ¿ y ¡ en castellano, los espacios antes de ? y : en francés), las comillas. El navegador sabe hacerlo todo con la API Intl, siempre que se lo pidas.

Los errores que más veo

  1. Hreflang sin enlace de vuelta. La página en castellano cita a la francesa; la francesa no cita a la castellana. El par se ignora. Remedio: una sola función genera la lista para todas las versiones.
  2. Una canónica hacia el idioma principal. Todas las versiones apuntan a /es/. Google solo indexa el castellano. Cada versión es canónica de sí misma.
  3. Sin x-default, o un x-default que redirige. Señala una página real, que responda con un 200.
  4. Códigos inventados. ES (región sola), es_ES (guion bajo), uk para el Reino Unido (es en-GB; uk es el ucraniano).
  5. URL relativas o que redirigen. Los hreflang deben apuntar a la URL final, absoluta, tal como se sirve.
  6. Una redirección según el idioma o la IP. Como se ha visto arriba: Googlebot solo verá un idioma.
  7. Dos idiomas en una página. Menú en castellano, texto en francés, porque la traducción «está en marcha». Para Google, esa página no está en ningún idioma.
  8. Un selector hacia la portada. El visitante pierde su página, y tú pierdes al visitante.
  9. Un sitemap sin alternativas. No es un error, pero desaprovecha una ocasión de confirmar el círculo.

Comprueba tu web

Search Console ya no tiene un informe dedicado a los hreflang desde 2022. Quedan los rastreadores (Screaming Frog, Ahrefs) y esta pequeña herramienta, que hace lo que hace Google: lee una página, abre cada una de sus versiones y comprueba que el círculo se cierra.

Comprueba los hreflang de tu web

Pega la dirección de una página: la herramienta lee sus etiquetas hreflang, abre cada versión y comprueba que el círculo está completo. No se guarda nada.

Lee primero los errores: enlace de vuelta que falta, canónica que apunta a otro sitio, código no válido, versión que redirige. Los avisos (x-default ausente, atributo lang que falta) no bloquean la indexación, pero se corrigen en cinco minutos. Prueba con una página de servicio antes que con la portada: ahí es donde se esconden los errores, porque los slugs están traducidos.

Preguntas frecuentes

¿Hace falta un dominio por idioma?

Rara vez. Los directorios (/es, /eu, /fr) en un solo dominio son más fáciles de gestionar y concentran la autoridad que acumula la web. Un dominio por país se justifica cuando las ofertas, los equipos o las marcas cambian de verdad de un país a otro.

¿hreflang es o es-ES?

es, salvo que el contenido cambie según el país. es cubre a todos los hispanohablantes, de Irun a Buenos Aires. es-MX tiene sentido para una página con precios, vocabulario o condiciones mexicanas, y solo si existe al lado una página es o es-ES.

¿Google penaliza la traducción automática?

No por sí misma. Lo que Google filtra es el contenido publicado en masa sin valor añadido, y una traducción automática sin revisar entra ahí. Traduce con las herramientas que quieras, haz revisar el resultado por alguien que hable el idioma, y no indexes lo que no se haya revisado.

¿Cuántas páginas hay que traducir?

Las que traen clientes: la portada, los servicios, el contacto, el aviso legal. Los artículos del blog, solo cuando tienen sentido para ese mercado; una página ausente en un idioma simplemente sale de su círculo hreflang. Mejor cinco páginas correctas que cuarenta aproximadas.

¿Cuánto cuesta un idioma adicional?

En una web que construyo yo, entre un 20 y un 25 % del precio de la web por idioma, traducción incluida cuando la hago yo mismo (castellano, francés, inglés). El detalle está en mi tarifa.

¿Hace falta un .eus?

Si la web está escrita en euskera, o si la identidad vasca está en el centro de la marca, sí. Si no, un .com o un .es con un directorio /eu/ hace exactamente el mismo trabajo para Google, y sin una promesa que la web no cumple.

Y ahora

Si tu web ya existe en varios idiomas, pásala por la herramienta de arriba: en un minuto sabrás si el círculo está completo. Si está por construir, es el tema de mi página sitio multilingüe, y puedes contarme tu proyecto: hablamos una hora y recibes un presupuesto en 48 horas.

Todos los artículos

¿Un proyecto donde surgen estas preguntas?

Puedo ayudarte a resolverlas, y a construir lo que viene después.