Erwin.Ried.cl / Desarrollos / Visual Studio /
Crea rápidamente aplicaciones en múltiples lenguajes

Con poco esfuerzo y Visual Studio 2005 es realmente sencillo crear aplicaciones que utilicen recursos localizados. En este artículo crearé una pequeña utilidad en C# localizada, que adicionalmente, te permitirá llevar un registro de las conexiones a internet y su duración (03/02/2007 02:12 AM)


Todo programador sabe lo tedioso que puede llegar a ser traducir una aplicación a otro idioma, especialmente las dificultades de organizar toda la interfaz para ajustarse a la nueva interfaz. ¿De qué forma se puede simplificar al máximo este proceso? ¿Cómo puedo distribuir el trabajo de traducción? ¿Cómo incorporo los nuevos recursos localizados?, todas estas preguntas tendrán una sencilla respuesta en este artículo.


1. Introducción

Durante unos días investigué los procedimientos para traducir aplicaciones en Visual Studio y como no pude encontrar un tutorial que explicara realmente fácil esta tarea, decidí escribir este artículo.

En la versión 2005 de Visual Studio, como veremos a continuación, las labores están increíblemente simplificadas. Específicamente la aplicación que generará este artículo tendrá como finalidad utilizar los recursos presentes en Windows (NT, 2000, XP, 2003 o Vista) para filtrar ciertos datos y entregar información útil.


2. Objetivos

El sistema va almacenando una serie de eventos en una base de datos la cual puede ser llamada desde el menú inicio, escribiendo "eventvwr.msc". Entre estos eventos, en la rama de eventos de sistema, existe una serie de eventos que indican las conexiones o desconexiones realizadas por medio de un módem. Si por cualquier motivo cuentas con una conexión cobrada por minutos, por horario, o simplemente quieres llevar un registro de tus conexiones podrías revisar esta lista y filtrar los eventos importantes:



Nota
El aspecto real de la ventana de sucesos del sistema puede diferir al mostrado en los diagramas. En la siguiente imagen se puede apreciar una captura real:



El visor de sucesos puede ser accedido desde las herramientas administrativas del equipo.


El objetivo de la aplicación entonces será organizar esta información "ya existente" con motivos útiles:



Para simplificar las cosas, entre las librerías de Visual Studio están implementadas las instrucciones para acceder a aquellos recursos.


3. Primero, el programa en nuestro idioma

Rápidamente creamos los formularios de la aplicación, el formulario principal debe tener un aspecto similar al siguiente:



y otro formulario secundario:



El procedimiento principal de la aplicación en este caso es el que accede a los sucesos del sistema y filtra los datos. Sólo se considerarán los eventos de "sistema", del usuario actual, de la categoría predeterminada (eventos de conexión, el identificador, denominado InstanceId, de estos eventos puede verse directamente en el visor de sucesos o al depurar el ciclo que accede a ellos) y que estén dentro del rango de fechas especificados por el usuario:

Código:
private void updateEventList()
{
  guiMode(false); // Deshabilitar interfaz         
  
  listDialupEvents.Items.Clear(); // Limpiar eventos previos
  totalSeconds = 0;

  EventLog[] eventLogs = EventLog.GetEventLogs();
  foreach (EventLog eventCollection in eventLogs)
  {
    if (eventCollection.Log.CompareTo("System") == 0)
    {
      string msg="", r_msg="";
      
      foreach (EventLogEntry eventLogEntry in eventCollection.Entries)
      {
        if (eventLogEntry.Source == "RemoteAccess")
        {
          // Añadirlo a la lista
          ListViewItem status = new ListViewItem();

          DateTime eTime = new DateTime();
          eTime = eventLogEntry.TimeGenerated;

          // Revisar si se encuentra dentro del intervalo
          if (eTime.Ticks > dateTimePickerEnd.Value.AddDays(1).Ticks)
          {
            break;
          }
          else
          {
            if (eTime.Ticks > dateTimePickerIni.Value.Ticks)
            {
              status.SubItems.Add(eTime.ToShortDateString());
              status.SubItems.Add(eTime.ToLongTimeString());

              // Sólo los eventos de conexión y desconexión
              switch (eventLogEntry.InstanceId)
              {
                case 20158:
                  status.ImageIndex = 1;
                  msg = Resources.ResourceManager.GetString("DialupStart_msg");
                  r_msg = eventLogEntry.ReplacementStrings[1];
                  status.Text = String.Format(msg, r_msg);
                  callStart = eTime;
                  break;
                case 20159:
                  status.ImageIndex = 2;
                  status.Text = Resources.ResourceManager.GetString("DialupEnd_msg");

                  TimeSpan callTotal = new TimeSpan(Math.Max(eTime.Ticks - 
                    callStart.Ticks,0));
                  totalSeconds += (int)callTotal.TotalSeconds;
                  status.SubItems.Add(callTotal.Hours + ":" + 
                    callTotal.Minutes + ":" + 
                    callTotal.Seconds);
                  break;
              }
              this.listDialupEvents.Items.Add(status);
            }
          }
        }
      }
      break;
    }  
  }
  guiMode(true); // Habilitar la interfaz nuevamente
}



4. Importante para "localizar" aplicaciones

Algo que no puede faltar en el proceso es la vinculación con recursos. Para los formularios y controles no es necesario, pues Visual Studio se encargará posteriormente, sin embargo para todo lo que corresponda a cadenas internas es muy importante.

Esta tarea es bastante simple, para ejemplificar la idea pensemos en un código típico que escribe un mensaje en la barra de estado:



Esto es difícilmente localizable, ¿se imaginan estar cambiando todos los mensajes de esa forma? ¿qué sucedería con lenguajes que no tienen la misma estructura para ciertas frases?

Con un poco más de esfuerzo podríamos escribir algo más elegante:



Esto se ve mucho mejor. Finalmente con el administrador de recursos de Visual Studio logramos:



Ahora, nuestra aplicación está lista para que comencemos a traducirla pues utilizando correctamente los recursos logramos independizar el código mismo del idioma y los mensajes en sí.


5. Do you understand me?

Muchas personas no lo creerán, pero comenzar a traducir todos los diálogos (en este caso de español a inglés) simplemente debemos cambiar dos propiedades del formulario:



Así, sin más, simplemente se dedican a traducir el formulario directamente reemplazando las propiedades adecuadas, por ejemplo "Text" para los botones:



Luego, Visual Studio generará un archivo de recursos indicado para la traducción. Los archivos de recursos que genera se basan en la siguiente plantilla de nombres:
<Nombre del formulario>.<localización>.resx


Es decir, para el formulario "FormMain", los recursos en inglés de nuestro programa se almacenarán en:
FormMain.en.resx


Incluso podríamos hacer diferentes versiones, por ejemplo la versión para "Ingles (Estados Unidos)" será:
FormMain.en-US.resx


Para los recursos originales (en español) se utiliza:
FormMain.resx


Basta con duplicar el archivo de recursos originales y cambiar su nombre para que el compilador lo incluya como recursos localizados, aunque, como dije anteriormente, este procedimiento es completamente automático para los formularios y sus controles cuando el formulario tiene la propiedad "Localizable" habilitada.


6. Explicación de la localización

Luego de que todos los archivos de recurso, uno por cada localización, sean generados, compilamos la aplicación. En el proceso de compilación se creará una carpeta por localización (exceptuando la por defecto, la cual se integra a la aplicación):



Cuando una aplicación (en este caso, con nombre de ejecutable "app") con elementos "localizables" (como la configuramos en el punto anterior) inicia en un equipo con Windows en inglés en Estados Unidos ("en-US"), entonces:




7. Entonces, y las cadenas restantes

Luego de la explicación anterior creo que es simple imaginarse cómo traducir las cadenas de texto que no son de controles de formulario, sino de código. Anteriormente dí un ejemplo con un código utilizando recursos, la instrucción real en C# es:

Código:
<app>.Properties.Resources.ResourceManager.GetString(<recurso>);


Claro que se puede retocar:

Código:
using <app>.Properties;
(...)
Resources.ResourceManager.GetString(<recurso>);


En donde <app> es el nombre del proyecto y <recurso> es la cadena de texto que identifica al recurso. Luego de crear archivos de recursos con los lenguajes:



Traducimos las cadenas finales que no estaban directamente dentro de un formulario:



El manejo de aquellos archivos "localizados" será administrado automáticamente al inicio de la aplicación como señalé anteriormente en el punto anterior.


8. Distribuir el trabajo de traducción

Para poder dosificar el trabajo de la traducción de recursos podemos utilizar la pequeña herramienta "WinRes.exe" (incluída en la instalación de Visual Studio) y de esta forma cualquiera puede traducir el archivo de recursos sin necesitar Visual Studio instalado:



Nota
Por defecto, el editor de recursos se encuentra en la carpeta
"SDK\v2.0\Bin\WinRes.exe"



9. Probando y comprobando las traducciones

Luego de compilar un archivo con recursos localizados claramente queremos comprobar que todo funcione correctamente. La forma menos práctica pero más sencilla es simplemente ejecutar la aplicación en un sistema operativo adecuado (por ejemplo Windows XP en inglés).

Otra forma es instalar una paquete de idiomas para nuestro actual sistema, disponibles para las versiones profesionales de ellos por Microsoft.

La última forma es simplemente añadiendo la siguiente línea de código a la aplicación (en el procedimiento "Main"):

Código:
static void Main()
{
  string language = <id_lenguaje>;
  System.Threading.Thread.CurrentThread.CurrentCulture = 
   new System.Globalization.CultureInfo(language);
  System.Threading.Thread.CurrentThread.CurrentUICulture = 
   new System.Globalization.CultureInfo(language);
  (...)
}


En donde <id_lenguaje> hace referencia al identificador, por ejemplo "es-CL" para Español (Chile) o "en-US" para Inglés (Estados Unidos).

Compilamos y ejecutamos la aplicación para forzando la carga de ciertos recursos localizados.


10. Código fuente y binarios

Código fuente y binarios actualizados el 26/01/2007

Cambios y novedades de la versión 1.0.0.3:
- La duración de cada conexión se muestra ahora como hh:mm:ss, anteriormente era h:m:s
- Al cambiar el intervalo de fechas, se actualiza la lista automáticamente
- Ahora puede compilarse correctamente en cualquier equipo

Versión 1.0.0.2:
- Botón exportar en el dialogo principal
- Iconos en los botones de función principal
- La ventana de cálculo de costo ahora refleja los cambios instantáneamente
- Exportar selección no está habilitado cuando no hay selección

Versión 1.0.0.1:
- Se pueden exportar los eventos
- La ventana recuerda su posición y tamaño
- Correcciones


Como siempre no pueden faltar los recursos utilizados en el transcurso de este artículo como tampoco el archivo ejecutable de la misma aplicación:



Importante
Algunos elementos de la interfaz dependen de la configuración regional además de la configuración de idioma y localidad del equipo, por ejemplo el formato de las horas y en este caso de la fecha.

Esto significa que la ejecución del programa con recursos en inglés no necesariamente afectará el formato de la fecha a la configuración AAAA-MM-DD. Sin embargo estos parámetros (globales del equipo) pueden configurarse en el panel de control según las preferencias y necesidades del usuarios


Descarga del ejecutable:
files/articles/dialup_events_multilanguage_01/dialup_events_v1.0.0.3_bin.rar

Nota
En el paquete del código ejecutable se incluye, además de los recursos en inglés, un archivo XML de configuración.

Adicionalmente se recomienda incrementar el tamaño del registro, por defecto el límite puede impedir que el registro se extienda más de un par de dias, desde el visor de eventos, en propiedades del registro de sucesos del sistema puede configurarse un nuevo valor para el tamaño y duración de los mismos.


Descarga del código fuente (C#, VS2005):
files/articles/dialup_events_multilanguage_01/dialup_events_v1.0.0.3_source.rar


11. Conclusiones

Dos objetivos cumplidos: permitir la utilización de información "escondida" para propósitos útiles como generar un registro de conexiones (código que se puede modificar fácilmente para cualquier otro fin relacionado con los "sucesos") y aprender de lo fácil que puede llegar a ser localizar nuestra aplicación.

Relacionado con el tema de la localización puedo sacar algunas conclusiones adicionales:

-Planificar bien el desarrollo antes de escribir cualquier línea de código, especialmente del código que involucra cadenas que deben ser traducidas.

-Nunca comenzar la traducción de partes que no estén completamente terminadas.

-Preparar buena música, traducir cosas es muy tedioso aún en desarrollos extremadamente diminutos como el actual.

Haga clic sobre una de las estrellas para calificar este artículo.

Opiniones y comentarios (Escribir un nuevo comentario)
hola... me gusta el articulo, pero se puede hacer lo mismo en asp.net? Lo necesito urgente
Escrito por Erwin Oviedo (22/03/2007 04:12 PM)
Desde Visual Studio 2005 también se pueden hacer soluciones web "localizables"
Escrito por Erwin Ried (22/03/2007 04:15 PM)
shit!!! se me olvidaba publicar una imagen para una mejor orientación... no sé si tú página soporta el incluir tags html en los posts de los usuarios... así que sólo pongo el link: http://img407.imageshack.us/my.php?image=signingyx1.jpg Saludos!!!
Escrito por Alejandro (28/01/2007 03:23 PM)
Hola... bajé tu actualización pero al momento de compilar el proyecto me tiraba un error: Error 1 Unable to find manifest signing certificate in the certificate store. Así que para compilarlo si presenta ese mismo error hay que ir a: Propiedades del proyecto-->Signing y desactivar la opción "Sign the ClickOnce manifests" Saludos!!!
Escrito por Alejandro (28/01/2007 03:21 PM)
Muchas gracias por el aviso, actualizo el proyecto pronto corregido
Escrito por Erwin Ried (29/01/2007 12:22 AM)
Hola de nuevo... Puede ser algo complicado al principio, pero después se asimila y aprende muy rapida y facil... A todo esto, el programa tiene algunos detalles (errores) q yo creo q ya cachaste: por ejemplo q si presionas sl botón con el simbolo '$' al momento de calcular el costo tira un total de segundos negativos y un costo negativo tb... pero es un detalle pequeño. Saludos!!!
Escrito por Alejandro (17/01/2007 08:18 PM)
Jeje, no lo probé mucho, gracias por el aviso, pronto lo subo corregido
Escrito por Erwin Ried (18/01/2007 02:23 AM)
Hola... interesante el articulo, aunque ya lo habia usado el semestre pasado para hacer el proyecto de 'Ing. de software 1', aunque el proyecto requería estar en inglés, pero nunca estaba de más ponerle algún otro idioma ;) Saludos!!!
Escrito por Alejandro (16/01/2007 09:02 PM)
Genial, algunas personas que habían visto la opción me dijieron que no la comprendían completamente, especialmente la parte que se podría decir "más confusa" era la de los recursos fuera de los formularios
Escrito por Erwin Ried (17/01/2007 12:48 AM)

Copyright © 2013 por Erwin Ried.