hreflang: SEO para un sitio en dos idiomas
Cómo hacer que Google indexe las dos versiones de tu sitio en vez de tratar una como copia de la otra. Con el error de canonical que borra un idioma entero del índice.
Para que Google indexe tu sitio en dos idiomas hacen falta dos cosas juntas: cada idioma tiene que tener su propia URL, y cada URL tiene que declararse como canónica de sí misma. Si la versión inglesa declara canónica a la española, le estás diciendo al buscador que es un duplicado y que la ignore, y no se indexará jamás por muy bien traducida que esté.
Ese es el error de una línea que se lleva por delante la mitad del contenido de un sitio bilingüe. Vamos por partes, porque hay una decisión previa que condiciona todo lo demás.
1. Elige cómo va el idioma en la URL
Tres opciones, y la decisión es difícil de revertir:
| Forma | Ejemplo | A favor | En contra |
|---|---|---|---|
| Subdominio | en.ejemplo.com |
Separación total | Autoridad repartida entre dominios |
| Prefijo de ruta | ejemplo.com/en/blog |
Lo que Google entiende mejor | Hay que reescribir todos los enlaces internos |
| Parámetro | ejemplo.com/blog?lang=en |
Cero cambios en los enlaces | Señal más débil; hay que ser muy estricto con el resto |
El prefijo de ruta es la opción por defecto si empiezas de cero. Es la que menos explicaciones necesita.
Nosotros elegimos el parámetro y conviene ser honestos sobre por qué: el sitio ya tenía decenas de rutas y más de ochenta enlaces internos, y meter /en/ obligaba a reescribirlos todos, incluidas las rutas de retorno de cada formulario, con una probabilidad alta de dejar enlaces rotos. La contrapartida es que la señal es más débil y que no queda margen para descuidos en lo que viene a continuación.
Lo que no vale en ninguna de las tres formas: servir idiomas distintos en la misma URL según el navegador o el país. Un rastreador ve una sola versión y el resto no existe.
2. Que el canonical de cada idioma apunte a sí mismo
Este es el paso que decide si funciona o no.
<!-- en /blog/mi-post -->
<link rel="canonical" href="https://ejemplo.com/blog/mi-post" />
<!-- en /blog/mi-post?lang=en -->
<link rel="canonical" href="https://ejemplo.com/blog/mi-post?lang=en" />
El fallo típico es generar el canonical solo con la ruta, olvidando el idioma. Se ve bien, valida bien, y hace que una de las dos versiones no se indique nunca. Si tu canonical se construye en un solo sitio —una plantilla base—, arreglarlo es una línea; si se escribe página a página, es cuestión de tiempo que alguna se olvide.
3. Declara las alternativas en las dos direcciones
Cada versión enumera todas las versiones, incluida ella misma:
<link rel="alternate" hreflang="es" href="https://ejemplo.com/blog/mi-post" />
<link rel="alternate" hreflang="en" href="https://ejemplo.com/blog/mi-post?lang=en" />
<link rel="alternate" hreflang="x-default" href="https://ejemplo.com/blog/mi-post" />
Tres reglas que hay que cumplir a la vez:
- Recíproco. Si A declara a B, B tiene que declarar a A. Si no, Google descarta el grupo entero.
- Absoluto. URLs completas con protocolo y dominio, nunca relativas.
- Incluyéndose. Cada página se declara también a sí misma.
x-default es a dónde mandar a quien no encaja en ningún idioma declarado. Apúntalo a la versión que sirves cuando no hay ninguna señal.
4. Genera todo esto en un solo sitio
Si el canonical y los hreflang se escriben en cada plantilla, un día alguien añade una página y se olvida. Ponlo en la plantilla base, calculado a partir de la ruta actual, y desaparece la clase entera de problema.
Lo mismo con la lista de idiomas: una constante, no un literal repetido. El día que añadas un tercero, es una línea.
5. Repite las alternativas en el sitemap
El hreflang del HTML y el del sitemap dicen lo mismo, y conviene poner los dos:
<url>
<loc>https://ejemplo.com/blog/mi-post</loc>
<xhtml:link rel="alternate" hreflang="es" href="https://ejemplo.com/blog/mi-post" />
<xhtml:link rel="alternate" hreflang="en" href="https://ejemplo.com/blog/mi-post?lang=en" />
</url>
En sitios donde el idioma va en un parámetro, esto es lo que hace que la versión secundaria tenga una URL propia que el buscador pueda distinguir. Cómo montarlo sin que se quede viejo está en sitemap.xml y robots.txt.
6. Traduce de verdad, o dilo
La trampa final. Si la traducción no existe y sirves el idioma original, tienes dos URLs con contenido idéntico y una etiqueta que promete idiomas distintos. Google lo detecta y deja de fiarse del grupo.
Dos salidas honestas:
- No declares la alternativa que no existe todavía.
- O sírvela con un aviso visible que diga que esa traducción falta.
Nosotros hacemos lo segundo, y no por comodidad: un respaldo silencioso parece un fallo del sitio, así que nadie llega a escribir la traducción que falta. Con el aviso, el problema es visible y se arregla.
Y un detalle que se olvida siempre: el atributo lang del <html> tiene que cambiar con el contenido. Si el texto es inglés y el lang dice español, los lectores de pantalla lo pronuncian mal y estás dando una señal contradictoria.
Cómo comprobar que funciona
Cuatro comprobaciones, todas con curl:
- Pide la versión secundaria y mira que el canonical incluya el idioma.
- Comprueba que los
hreflangson recíprocos entre las dos versiones. - Confirma que
<html lang>coincide con el idioma del texto. - Mira que las dos URLs estén en el sitemap con sus alternativas.
Si tienes un script de comprobación de SEO, mete las cuatro ahí. Es la clase de cosa que se rompe al refactorizar una plantilla y no avisa nadie hasta que pasan meses, como cuenta SEO técnico para desarrolladores.
Preguntas frecuentes
¿Puedo poner el idioma en un parámetro en vez de en la ruta?
Se puede, y funciona si el canonical de cada versión incluye el parámetro y los hreflang son recíprocos. Es una señal más débil que un prefijo de ruta y no perdona descuidos, así que solo tiene sentido cuando cambiar todas las rutas sería un riesgo mayor.
¿Sirve la etiqueta content-language?
Prácticamente no: Google no la usa para nada relevante desde hace años. Lo que cuenta es el hreflang, el atributo lang del <html> y, sobre todo, el idioma real del texto.
¿Necesito hreflang si solo tengo un idioma?
No. Es exclusivamente para agrupar versiones equivalentes en idiomas o regiones distintas. Con un idioma, sobra.
¿Y si el mismo idioma cambia por país, como es-ES y es-MX?
Se declara con código de idioma y región (es-ES, es-MX) y valen las mismas reglas. Merece la pena solo si el contenido cambia de verdad —precios, impuestos, normativa—; si es el mismo texto, estás creando duplicados con más pasos.
¿Google traduce solo mi sitio si no lo hago yo? Puede ofrecer una traducción automática al usuario, pero eso no indexa nada nuevo ni te posiciona en el otro idioma. Para aparecer en resultados en inglés hace falta contenido en inglés con su propia URL.
El directorio es la otra mitad de esto
115 servicios con plan gratuito real, con los límites de cada uno escritos en claro. Sin registro para empezar a mirar.