DNM+ Online
dotnetmania 2.0
Localización rápida de aplicaciones multi-idioma Un add-in que ahorra tiempo, dinero y estrés
Visual Studio 2008 es, si no la mejor, una de las mejores y más completas plataformas de desarrollo actualmente existentes. Aun así, trata de abarcar tanto, que en ocasiones quedan pequeños flecos que se pueden mejorar. La infraestructura para crear aplicaciones localizables es uno de estos ejemplos. En este artículo veremos cómo mejorarla mediante un add-in que facilita el cambio rápido de idioma en un formulario o control.

Introducción a las aplicaciones localizables A pesar de ser un adjetivo válido y totalmente aceptado por la R.A.E, como muchos de los lectores ya sabrán, el término localizable en la acepción en que lo utilizaremos aquí es un anglicismo, que por casualidades de la vida resulta tener un aspecto muy castellano, pero que en realidad hace referencia a una aplicación preparada para adaptar sus contenidos a diferentes culturas. Todo desarrollador que haya necesitado distribuir una aplicación en diferentes países valorará enormemente la infraestructura de localización proporcionada por Visual Studio y .NET Framework.

Entonces, ¿dónde está el problema? Lo cierto es que hay que buscarlo bastante, pero finalmente se encuentra.

Esos diez segundos infernales Un amigo, ingeniero industrial, me dijo una vez que un ingeniero en informática es alguien que pierde un mes entero desarrollando una herramienta para automatizar algo que se hace en un minuto. Pues sí, tiene toda la razón. Es más, casi diría que ése es precisamente nuestro trabajo. Y es que ¿por qué hacer algo en diez segundos, cuando puedes hacerlo en uno? Trataré de ilustrar a qué me refiero. Si se está trabajando en una aplicación localizable como la de la figura 1, y se necesita añadir una nueva opción (por ejemplo, la del menú principal: "Guardar como"), los pasos necesarios para cambiar el texto del menú a cada uno de los idiomas disponibles son: 1.    Seleccionar el formulario principal (ya que las opciones de localización están en el formulario). 2.    Buscar la propiedad Language en la ventana de propiedades.
3.    Desplegar el combo con las opciones. 4.    Buscar el idioma deseado en la lista (que incluye los cientos de idiomas disponibles en el sistema). 5.    Volver a seleccionar el MenuItem. 6.    Adaptar su contenido al idioma seleccionado. 7.    Volver a seleccionar el formulario principal. 8.    Volver a buscar la propiedad Language. 9.    Volver a establecer el idioma por defecto (obviamente mediante la opción Reset de la propiedad, no buscando de nuevo en la lista).

¡Nueve pasos por cada idioma! Algunos totalmente innecesarios y otros francamente molestos. Por ejemplo, buscar un idioma en una lista con cientos de opciones, cuando la inmensa mayoría de aplicaciones soportan solo dos o tres. O tener que bailar entre el formulario principal y el control una y otra vez. Está claro que son aspectos susceptibles de una profunda mejora. Caso de uso ideal ¿Cuál sería el caso de uso ideal para llevar a cabo la tarea expuesta anteriormente? En primer lugar, la selección del idioma debe ser mucho más rápida, implicando menos pasos. En segundo lugar, sería necesario tener que escoger únicamente entre los idiomas que la aplicación ya está utilizando, y no entre todos los disponibles en el sistema. De esta forma, los pasos podrían reducirse a: 1.    Pulsar un botón para cambiar el idioma 2.    En una lista que muestre únicamente los idiomas utilizados en la aplicación, hacer doble clic en el que buscamos. 3.    Adaptar el contenido al idioma seleccionado 4.    Pulsar un botón para cambiar al idioma por defecto

Si se consigue esto, el proceso quedará reducido a cuatro cómodos y rápidos pasos.

Extensiones de Visual Studio Existen dos formas de extender las funcionalidades de Visual Studio: mediante macros o mediante add-ins. Ambas tienen sus ventajas y sus inconvenientes, que he tratado de resumir en la tabla 1. ¿Qué opción es mejor en este caso? Para poder escoger una de las dos opciones, es necesario analizar los requerimientos del desarrollo que se va a realizar: 1.    Es necesario que la extensión muestre una interfaz de usuario, con una lista de idiomas, algún botón, etc. Esto se puede lograr tanto con macros como con add-ins. 2.    También se necesita averiguar qué idiomas son los que el componente editado incluye. Como se verá más adelante, para esto es necesario explorar elementos de la solución, lo cual también puede hacerse desde un macro o desde un add-in, indistintamente. 3.    Una vez el usuario haya escogido el idioma que desea "activar", necesitaremos cambiar la propiedad Language del componente diseñado. Y he aquí el problema. Dado que los macros se ejecutan en un hilo diferente al de Visual Studio, desde ellos no es posible acceder al componente que se está editando en el diseñador; únicamente a elementos del propio Visual Studio o a ficheros.

Si sumamos a estos puntos el hecho de que para crear un add-in se puede utilizar C# como lenguaje de programación (algo que personalmente prefiero), la elección está clara.

El proyecto Se crea un nuevo proyecto (en este caso llamado LangSelector), de tipo "Extensibility (Visual Studio Add-in)". Una vez completado el asistente, obtendremos una solución como la que muestra la figura 2. El asistente crea de forma automática los archivos XML de registro de la extensión (LangSelector.AddIn), por lo que no es necesario preocuparse de registrarla, al menos en la máquina que se esté utilizando para el desarrollo. No obstante, es recomendable consultar la referencia [1] para obtener más información acerca del registro de add-ins y la referencia [3] para conocer más acerca del gestor de add-ins de Visual Studio. El lugar donde se debe introducir código es la clase Connect.cs, más concretamente en el método Exec, llamado cada vez que se invoca el add-in, y que inicialmente tiene la forma que se presenta en el listado 1. Más exactamente, en el punto donde se indica "Do your stuff here". Para simplificar la explicación del código, hemos dividido la tarea completa a desarrollar en varios pasos. Para construir la extensión completa, copie sucesivamente cada uno de los listados que se exponen a continuación a partir del punto indicado del método Exec. 1. Comprobar que es un
documento válido
Es necesario asegurarse de que el editor de Visual Studio tiene un documento activo. Para ello, se puede utilizar la variable miembro _applicationObject generada por el asistente, que permite interactuar con algunos componentes de Visual Studio. Una de las propiedades de este objeto es ActiveDocument, que proporciona un enlace al documento actualmente abierto en el editor. Si el valor de esta propiedad es nulo, no es posible continuar.
La propiedad ActiveDocument.ProjectItem (que será muy utilizada a partir de ahora) da acceso a una clase que contiene información sobre el fichero de proyecto del proyecto relacionado con el documento activo. Inicialmente, y como paso opcional, nos permite comprobar si el documento tiene cambios y proceder a guardarlo antes de cambiar el idioma. Todo esto queda reflejado en el listado 2. 2. Obtener la lista de idiomas
disponibles Cuando un formulario o control es localizable, Visual Studio crea un fichero de tipo .resx por cada idioma adicional que incluye, agrupándolos en el Explorador de Soluciones como nodos hijos del componente. De esta forma, analizando la colección currentItem.ProjectItems es posible conocer la lista de idiomas disponibles. 3. Acceder al componente editado El listado 4 muestra cómo acceder al componente editado en el diseñador de Visual Studio. Esto no podría hacerse en un macro, ya que por los motivos explicados anteriomente, host.RootComponent no sería un IComponent válido. Cabe señalar que una vez se dispone del componente, no es posible acceder a sus propiedades directamente. Es necesario hacerlo a través de un objeto System.ComponentModel.PropertyDescriptor, creado por el método TypeDescriptor.GetProperties. 4. Preguntar al usuario qué idioma desea utilizar El listado 5 consulta al usuario qué idioma desea utilizar. Para ello, se basa en un formulario muy simple que contiene un ListBox y un par de botones, con el aspecto de la figura 3. Este formulario ofrece una propiedad llamada Values, que es una colección de cadenas asociada al ListBox, y devuelve el índice seleccionado a través de otra propiedad SelectedIndex. 5. Asignar el idioma seleccionado El último paso, que se presenta en el listado 6, consiste en crear un objeto de tipo CultureInfo que refleje el idioma seleccionado en la lista, y asignarlo a la propiedad Language del componente editado. Integración en Visual Studio Una vez que el add-in está compilado y registrado, Visual Studio lo muestra por defecto como una opción más en el menú "Tools". Es bastante más cómodo incluirlo en una barra de herramientas, lo que se puede realizar fácilmente accediendo al menú "Tools" | "Customize" | "Rearrange Commands", y agregando a la barra de herramientas deseada un nuevo botón que enlace con el add-in.

Trabajo pendiente Para completar las aportaciones de este add-in, lo ideal sería desarrollar otro que automáticamente asigne al componente el idioma por defecto, sin necesidad de escoger en ninguna lista. Así, volver al modo de trabajo normal después de retocar los contenidos sería cuestión de un único clic. Partiendo del ejemplo de este artículo, desarrollar este segundo add-in es sumamente sencillo.

Conclusión Pocas cosas hay en Visual Studio que no me gusten, y las que finalmente encuentro, casi siempre pueden solucionarse mediante add-ins o macros que, además, ya suelen estar desarrollados y publicados de forma gratuita. Siguiendo los patrones de trabajo mostrados en este artículo, podrían desarrollarse muchos otros add-ins que faciliten sensiblemente nuestra vida de desarrolladores.

blog comments powered by Disqus
autor
referencias