URL’s internacionalizadas en ASP.NET MVC

Hace algunos meses en una entrada asociada a Internacionalización vimos cómo cambiar la cultura manualmente en ASP.NET MVC. En el mismo continuamos con mejoras sobre la internacionalización de nuestra aplicación para que más allá de reconocer de forma automática la cultura del navegador del usuario le demos la posibilidad de que pueda cambiarlo.

Algo que venía quedando pendiente de los post’s anteriores sobre este tema es el poder reflejar en la URL la cultura en la que se está visualizando el contenido. Esto tiene varios propósitos:

  • SEO: Como podemos ver en la documentación de Google asociada a la internacionalización, se recomienda hacer visible la cultura de la página que se está visitando. Esto da una mejora en lo que a indexación por parte del motor de búsqueda se refiere.
  • Usabilidad: Además del propósito del punto anterior, le permitir al usuario que utiliza nuestra aplicación el poder ver la cultura correspondiente al contenido que está visualizando. Esto también aplicaría a la hora de compartir ese contenido con otros usuarios.
  • Diseño: Podemos decir que es mucho más natural en el diseño y estructura del contenido de nuestra aplicación que el acceso según cada cultura se vea reflejado en diferentes URL’s.

Para esto continuaremos con lo ya visto en el post mencionado y en toda esta serie de internacionalización, modificando y ajustando algunos aspectos.

Lo primero sobre lo que debemos trabajar es en que la cultura sea visible en la URL de nuestra aplicación, trabajando para ello en las rutas configuradas. En ASP.NET MVC esto se encuentra en el archivo App_Start/RouteConfig.cs, teniendo la ruta por defecto el esquema {controller}/{action}/{id}. Como no queremos cambiar el comportamiento de ese esquema de rutas debemos modificarlo para agregar la cultura pero sin modificar el comportamiento base con las implicancias que conlleva.

En esta idea que planteo lo que vamos a realizar es modificar la ruta existente agregando en la URL como primer atributo la cultura. A su vez establecemos que su valor por defecto es una cadena vacía (esto lo usaremos luego) quedando de la siguiente forma:

Con este primer paso estamos dejando que nuestra aplicación pueda manejar en parte de la URL el valor de la cultura. Pero también esto será inverso, ya que un cambio por parte del usuario en la URL establecerá un cambio en la cultura.

Ahora bien, desde el desarrollo nos queda establecer la cultura en nuestra aplicación. En el post anterior en la acción del controlador donde se establecía el cambio de cultura lo que hacíamos era guardar una Cookie con el valor de la cultura seleccionada, la cual a partir de allí viajaba en cada request posterior que realizaba el navegador. Además en el Global.asax ante cada request validábamos si existía la Cookie en cuestión, y en caso de que sea afirmativo establecíamos la cultura correspondiente. Ese era el mecanismo extra que debíamos agregar para mantener el estado de la cultura seleccionada para cada usuario en particular.

Como en este caso lo haremos a través de la URL, el uso de la Cookie no es necesario ya que estaríamos haciendo lo mismo de dos formas distintas, es decir que estaríamos usando dos vías análogas para mantener el estado. Lo primero que haremos es modificar nuestra acción del controlador donde establecíamos el valor de la cultura, simplificándolo a lo siguiente:

Lo único que estamos haciendo es establecer en la clave “culture” de la ruta que editamos anteriormente el valor seleccionado. Lo siguiente será trabajar en el punto donde se reconoce esta información y se establece la cultura en el hilo que está atendiendo el request del usuario. Aquí no podremos ubicar nuestra lógica en el método Application_BeginRequest del Global.asax como hicimos en el caso anterior, ya que necesitamos que el framework MVC haya decidido la ruta a utilizar y haya establecido los valores correspondientes a cada clave de la misma. Es por ello que en este caso nuestra lógica estará en el método virtual BeginExecuteCore de la clase Controller:

A su vez lo haremos en una clase abstracta BaseController, la cual hereda de Controller. Esto implica que todos los controladores de nuestra aplicación deberán heredar del primero en vez del segundo, permitiendo tener la funcionalidad centralizada en un solo lugar en vez de que nos quede repetida por todos los controladores.

La lógica aplicada en el mismo es bastante sencilla, veámosla en detalle:

  1. Por cada request se busca el valor de cultura recibido en la ruta.
  2. Si el mismo no fue especificado quiere decir que es un acceso inicial donde no tuve como indicación el uso de una cultura en particular (por ello establecimos en la configuración de la ruta que el valor por defecto es la cadena vacía, para poder detectar estos casos donde no se estableció un valor de forma original). Entonces debemos buscar en el hilo de ejecución el valor de cultura por defecto que se ha establecido de forma automática en base a la cultura configurada en el navegador. Caso contrario se utiliza el valor recibido en la ruta.
  3. A su vez los separamos por el guion que se utiliza como estándar para la cultura principal y la derivada.
  4. Ejecutamos la función GetCulture. En la misma estará la lógica necesaria para establecer en nuestra aplicación y ruta la cultura correspondiente. En nuestro caso estamos dando soporte para la cultura en y es, siendo la última la por defecto. Por esto validamos si la primer parte de la cultura corresponde al inglés, caso contrario directamente será español. El resultado de este método será la cultura a utilizar en la aplicación.
  5. Con dicho resultado establecemos la cultura en el hilo correspondiente al usuario.
  6. Ejecutamos la funcionalidad base del método que estamos sobre-escribiendo.

Donde la clase estática SupportedCulture tiene las constantes de los valores correspondientes que nuestra aplicación soporta:


 

De esta forma tenemos todo listo para comenzar las pruebas. Para ello utilizaremos Chrome y Firefox, estando configurado el primero en español y el segundo en inglés.

Si accedemos a ambos podremos ver por defecto que la aplicación está internacionalizada a la cultura nativa de cada uno:

InternacionalizacionUrl - CulturaOriginal.png

 

A su vez si navegamos a alguna de las opciones del menú veremos cómo aparece en la URL la cultura correspondiente a cada caso:

InternacionalizacionUrl - CulturaEnUrl

 

Y finalmente si en ambos hacemos un cambio a la cultura contraria, vemos que efectivamente se hace el cambio y se refleja en la URL:

InternacionalizacionUrl - CulturaCambiada

Como podemos ver el funcionamiento es el esperado!! 😉

 

A modo de conclusión podemos ver que es posible y bastante factible de hacer que nuestra aplicación maneje la visibilidad y cambio de la cultura a través de la URL. Además cabe mencionar que en ningún momento estamos perdiendo funcionalidad ya existente y que vimos en post’s anteriores, ya que reconocemos la cultura del usuario y la utilizamos para mostrar el contenido de forma inicial, además de que le damos la posibilidad de que la cambie y dicha elección se mantenga en la navegación posterior que haga.

En este caso estamos planteando una idea base como ejemplo, la cual puede ampliarse y mejorarse según las necesidades o particularidades que tenga la aplicación en cuestión. Por ejemplo a partir del usuario logueado podríamos ir a su perfil y recuperar la configuración de cultura preferida por él más allá de la que tiene configurada en su navegador.

Les dejo el enlace al repositorio de GitHub donde está subido el código, así al que le interesa lo puede probar y modificar según necesite: https://github.com/diegobersano/Internationalization-Demo

Espero que les sea útil, gracias por leer!!

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s