Premisa del tema
Hay tres aspectos distintos en un sitio multilingüe:
- traducción de interfaz
- contenido
- enrutamiento de URL
Si bien todos se interconectaron de diferentes maneras, desde el punto de vista de CMS, se administran utilizando diferentes elementos de la interfaz de usuario y se almacenan de manera diferente. Parece tener confianza en su implementación y comprensión de los dos primeros. La pregunta era sobre el último aspecto:"¿Traducción de URL? ¿Deberíamos hacer esto o no? ¿Y de qué manera?"
¿De qué puede estar hecha la URL?
Una cosa muy importante es que no te vuelvas fantasioso con IDN . En su lugar, favorece la transliteración (también:transcripción y romanización). Si bien a primera vista IDN parece una opción viable para URL internacionales, en realidad no funciona como se anuncia por dos razones:
- algunos navegadores convertirán los caracteres no ASCII como
'ч'
o'ž'
en'%D1%87'
y'%C5%BE'
- si el usuario tiene temas personalizados, es muy probable que la fuente del tema no tenga símbolos para esas letras
De hecho, intenté acercarme a IDN hace unos años en un proyecto basado en Yii (marco horrible, en mi humilde opinión). Encontré los dos problemas mencionados anteriormente antes de raspar esa solución. Además, sospecho que podría ser un vector de ataque.
Opciones disponibles... como yo las veo.
Básicamente, tiene dos opciones, que podrían resumirse como:
-
http://site.tld/[:query]
:donde[:query]
determina tanto el idioma como la elección del contenido -
http://site.tld/[:language]/[:query]
:donde[:language]
parte de la URL define la elección del idioma y[:query]
se usa solo para identificar el contenido
La consulta es Α y Ω ..
Digamos que eliges http://site.tld/[:query]
.
En ese caso, tiene una fuente principal de idioma:el contenido de [:query]
segmento; y dos fuentes adicionales:
- valor
$_COOKIE['lang']
para ese navegador en particular - lista de idiomas en el encabezado HTTP Accept-Language
Primero, debe hacer coincidir la consulta con uno de los patrones de enrutamiento definidos (si su elección es Laravel, entonces lea aquí ). En caso de coincidencia exitosa del patrón, debe encontrar el idioma.
Tendrías que pasar por todos los segmentos del patrón. Encuentre las posibles traducciones para todos esos segmentos y determine qué idioma se usó. Las dos fuentes adicionales (cookie y encabezado) se usarían para resolver conflictos de enrutamiento, cuando (no "si") surgen.
Tomemos por ejemplo:http://site.tld/blog/novinka
.
Esa es la transliteración de "блог, новинка"
, que en inglés significa aproximadamente "blog", "latest"
.
Como ya puede notar, en ruso "блог" se transcribirá como "blog". Lo que significa que para la primera parte de [:query]
usted (en el mejor de los casos ) terminará con ['en', 'ru']
lista de idiomas posibles. Luego tomas el siguiente segmento - "novinka". Eso podría tener solo un idioma en la lista de posibilidades:['ru']
.
Cuando la lista tiene un elemento, ha encontrado correctamente el idioma.
Pero si terminas con 2 (ejemplo:ruso y ucraniano) o más posibilidades... o 0 posibilidades, según sea el caso. Tendrá que usar cookies y/o encabezados para encontrar la opción correcta.
Y si todo lo demás falla, elige el idioma predeterminado del sitio.
Idioma como parámetro
La alternativa es usar URL, que se puede definir como http://site.tld/[:language]/[:query]
. En este caso, al traducir la consulta, no necesita adivinar el idioma, porque en ese momento ya sabe cuál usar.
También hay una fuente secundaria de lenguaje:el valor de la cookie. Pero aquí no tiene sentido meterse con el encabezado Accept-Language, porque no se trata de una cantidad desconocida de idiomas posibles en caso de "inicio en frío" (cuando el usuario abre el sitio por primera vez con una consulta personalizada).
En su lugar, tiene 3 opciones simples y priorizadas:
- si
[:language]
el segmento está configurado, utilícelo - si
$_COOKIE['lang']
está configurado, utilícelo - usar idioma predeterminado
Cuando tenga el idioma, simplemente intente traducir la consulta y, si la traducción falla, use el "valor predeterminado" para ese segmento en particular (basado en los resultados de enrutamiento).
¿No hay aquí una tercera opción?
Sí, técnicamente puede combinar ambos enfoques, pero eso complicaría el proceso y solo acomodaría a las personas que desean cambiar manualmente la URL de http://site.tld/en/news
a http://site.tld/de/news
y espera que la página de noticias cambie a alemán.
Pero incluso este caso probablemente podría mitigarse utilizando el valor de la cookie (que contendría información sobre la elección previa del idioma), para implementar con menos magia y esperanza.
¿Qué enfoque utilizar?
Como ya habrás adivinado, recomendaría http://site.tld/[:language]/[:query]
como la opción más sensata.
También en una situación de palabra real, tendría la tercera parte principal en la URL:"título". Como nombre del producto en la tienda en línea o título del artículo en el sitio de noticias.
Ejemplo:http://site.tld/en/news/article/121415/EU-as-global-reserve-currency
En este caso '/news/article/121415'
sería la consulta, y 'EU-as-global-reserve-currency'
es titulo Puramente con fines de SEO.
¿Se puede hacer en Laravel?
Un poco, pero no por defecto.
No estoy muy familiarizado con él, pero por lo que he visto, Laravel usa un mecanismo de enrutamiento simple basado en patrones. Para implementar direcciones URL multilingües, probablemente tendrá que extender la(s) clase(s) principal(es) , porque el enrutamiento multilingüe necesita acceso a diferentes formas de almacenamiento (base de datos, caché y/o archivos de configuración).
Está enrutado. ¿Y ahora qué?
Como resultado de todo, terminaría con dos valiosas piezas de información:el idioma actual y los segmentos de consulta traducidos. Estos valores luego se pueden usar para enviar a la(s) clase(s) que producirán el resultado.
Básicamente, la siguiente URL:http://site.tld/ru/blog/novinka
(o la versión sin '/ru'
) se convierte en algo como
$parameters = [
'language' => 'ru',
'classname' => 'blog',
'method' => 'latest',
];
Que solo usas para despachar:
$instance = new {$parameter['classname']};
$instance->{'get'.$parameters['method']}( $parameters );
.. o alguna variación del mismo, dependiendo de la implementación particular.