Ir al contenido
← Todos los artículos

Laravel multilingüe: rutas traducidas bien hechas

Aplicaciones web 5 min de lectura

La mayoría de las aplicaciones Laravel multilingües se construyen igual: una tabla de rutas en inglés con un prefijo de locale atornillado delante. Funciona, y deja a las versiones que no son inglés sin poder posicionar por nada que alguien busque de verdad.

Por qué el slug tiene que estar traducido

Un prospecto neerlandés que busca precios busca tarieven. La URL es una señal de relevancia real, aunque modesta, y más importante: es lo que aparece en los resultados, se comparte en mensajes y lo leen los asistentes. /nl/pricing anuncia la traducción de un sitio inglés. /nl/tarieven anuncia una página en neerlandés.

Lo mismo vale para toda la ruta. Este sitio corre /pricing, /nl/tarieven y /es/precios; /ai-development, /nl/ai-development y /es/desarrollo-ia. El mercado neerlandés usa el término inglés para esa, así que traducirla sería peor.

Ese último detalle es el punto de verdad: la elección de slug es una decisión de keyword por idioma, no una tarea de traducción. No se puede automatizar, y es la razón de que los slugs vivan en archivos de traducción, donde una persona puede fijarlos uno a uno.

Cómo construirlo

Pon los slugs en un archivo de traducción por locale, una entrada por página:

// lang/nl/routes.php
return [
    'pricing' => 'tarieven',
    'about' => 'over',
    'ai-development' => 'ai-development',
];

Luego registra las rutas una sola vez, resolviendo cada URI a través del traductor, dentro del mecanismo de rutas localizadas que uses. Cada locale obtiene su propia ruta con su propio path y un nombre prefijado por locale, de modo que route('pricing') da la URL del locale actual y los enlaces son correctos en todas partes sin un solo condicional en una plantilla.

Dos reglas hacen que esto aguante con el tiempo. No renombres nunca un slug que ya posiciona. No hay ventaja, y heredas una redirección que hay que mantener para siempre. Y guarda la tabla de redirecciones de URLs antiguas como datos en un solo array, no como una pila de closures sueltos, para que un test pueda afirmarla entera.

Los errores de hreflang que importan

Aquí es donde más se rompen los sitios multilingües, y los fallos son silenciosos.

El conjunto debe ser recíproco y referenciarse a sí mismo. La página de cada locale lista todos los locales, incluido el suyo. Si la página en neerlandés apunta a inglés y español pero la inglesa no apunta de vuelta al neerlandés, los buscadores descartan la relación.

x-default no es opcional. Le dice al motor qué servir a alguien a quien no le encaja ninguno de tus locales. Apúntalo al idioma de mayor alcance, normalmente el inglés.

Los canonicals se quedan dentro del locale. El canonical de la página en neerlandés es la URL en neerlandés. Un canonical que apunta desde la página neerlandesa a la inglesa es una instrucción de sacar la página neerlandesa del índice, y es un accidente notablemente frecuente.

Lista solo los locales que existen. Si un artículo de blog tiene versión inglesa y no neerlandesa, no emitas un alternate en neerlandés. Por eso las traducciones necesitan un identificador compartido (el nombre de archivo, o una clave) independiente del slug traducido, para que el sistema sepa si una traducción existe en vez de asumirlo.

No redirijas nunca a un crawler por Accept-Language

Redirigir automáticamente a los visitantes de primera visita al idioma de su navegador es bueno para las personas y desastroso si también aplica a los bots. Un crawler que llega con una IP europea y sin preferencia de idioma acaba rebotado a un locale, y los demás quedan sin rastrear y sin indexar.

Tres reglas lo mantienen seguro: exime por completo a los user agents de crawlers conocidos; redirige solo una primera visita, condicionada a una cookie, para que quien eligió un idioma lo conserve; y usa siempre una redirección temporal, nunca una permanente, porque el destino depende del visitante.

Testear lo que no se ve

Dos tests pillan la mayor parte.

Afirma que cada ruta se resuelve en cada locale, devuelve 200 y renderiza exactamente un h1. Impúlalo desde la config de locales para que añadir un idioma extienda la cobertura sola. Si añadir un locale exige un cambio de código en cualquier sitio que no sea una entrada de config y un directorio de idioma, la arquitectura está mal y este test es lo que te lo dice.

Luego afirma los conjuntos hreflang: para cada página en cada locale, el conjunto contiene cada locale, se contiene a sí mismo, incluye x-default, y cada URL del conjunto se resuelve. La reciprocidad es exactamente el tipo de propiedad tediosa de comprobar a mano y trivial de comprobar en un bucle.

La versión corta

Slugs traducidos desde archivos de traducción. Un solo registro de rutas para todos los locales. Hreflang recíproco y autorreferenciado con x-default. Canonicals dentro del locale. Bots exentos de las redirecciones de idioma. Tests que iteran la lista de locales en vez de dejarla fija.

Haz eso y añadir un cuarto idioma es un directorio y una entrada de config, que es la única definición razonable de terminado aquí.

Preguntas que también surgen

¿Subdirectorios, subdominios o dominios separados?

Subdirectorios para casi todo el mundo. Mantienen toda la autoridad en un solo dominio y son los más baratos de operar. Los dominios de país solo compensan con operaciones locales de verdad detrás, y multiplican el mantenimiento por el número de mercados.

¿El idioma por defecto debería tener prefijo?

Es más limpio sin él, para que la home en inglés se quede en la raíz. Eso sí implica que el router tiene que distinguir una ruta sin prefijo de un prefijo de locale, algo que los paquetes establecidos de Laravel ya resuelven. Redirige de forma permanente las URLs antiguas con prefijo si cambias esto.

¿Basta la traducción automática?

Para una primera versión de una página larga, a menudo sí. Para titulares, llamadas a la acción y cualquier cosa que deba posicionar, no: la elección de keywords cambia por idioma y una traducción literal de un titular inglés se lee como una traducción. Que un hablante nativo revise todo aquello de lo que depende una decisión de compra.

¿Cómo sabemos que un locale está roto?

Testéalo. Afirma que cada ruta en cada locale devuelve 200 con un solo h1, y afirma que el conjunto hreflang es recíproco y se referencia a sí mismo. Esos dos tests pillan casi todas las regresiones multilingües antes de publicar.

Quién escribe esto

Alexander (Sander) van Hooff

Alexander (Sander) van Hooff construye aplicaciones web desde 2015 y hoy dedica la mayor parte de su tiempo a llevar funciones de IA a productos que ya tienen usuarios. Vuewer es su estudio, dirigido desde la provincia de Alicante para clientes de toda Europa.

Trabaja con Vuewer

Lecturas relacionadas

Aplicaciones web 4 min de lectura

Por qué seguimos eligiendo Laravel en 2026

Un argumento honesto a favor de un framework de diez años: qué hace Laravel mejor que las alternativas, qué hace peor, y los casos en los que elegiríamos otra cosa.

Búsqueda, AEO y GEO 4 min de lectura

SEO, AEO y GEO: qué ha cambiado de verdad

Tres siglas, un cambio: los buscadores ahora responden en vez de enlazar. Qué cambia eso sobre cómo hay que escribir las páginas, y qué no cambia en absoluto.

Ponte en contacto

Nos encantará saber de ti.

¿Tienes una pregunta o necesitas ayuda con una web o una aplicación web? Tanto si empiezas de cero, como si quieres mejorar lo que ya tienes o te has atascado en algo complejo.

Rellena el formulario y te responderemos lo antes posible.