Programación en castellano
Inicio > Tutoriales > J2SE > Internacionalización de Programas Java
-Tutoriales

Internacionalización de Programas Java


Formateo de Mensajes

A todos nos gusta utilizar programas que nos cuenten lo que están haciendo. Los programas que nos mantienen informados normalmente lo hacen mostrando mensajes de estado o de error. Por supuesto, estos mensajes necesitan ser traducidos para que puedan ser entendidos por los usuarios finales de todo el mundo. Explicamos la tradución de mensajes de textos en Aislar Objetos Específicos de la Localidad en un ResourceBundle. Normalmente con mover el mensaje String dentro de un ResourceBundle, ya está hecho. Sin embargo, si un mensaje contiene datos variables tendremos que hacer unos pasos extra para preparar su traducción.

En la siguiente lista de mensajes, hemos subrayado los datos variables.

The disk named MyDisk contains 300 files.
The current balance of account #34-98-222 is $2,745.72.
405,390 people have visited your website since January 1, 1998.
Delete all files older than 120 days.

Podríamos estar tentados a construir el último mensaje de la lista concatenando frases y variables.

double numDays;
ResourceBundle mssgBundle;
.
.
String message = mssgBundle.getString("deleteolder") +
                 numDays.toString() + 
                 mssgBundle.getString("days");

Esta aproximación funciona bien en Inglés, pero no funciona en idiomas donde los verbos aparezcan al final de la sentencia. Como el orden de las palabras de este mensaje está codificado, los localizadores no podrán crear traducciones gramáticamente correctas para todos los idiomas.

¿Cómo podemos hacer que nuestros programas sean fácilmente localizables si necesitamos utilizar mensajes concatenados? Podemos hacerlo utilizando la clase MessageFormat, que es el punto principal de esta lección.

. Tratar con Mensajes Concatenados

Un mensaje concatenado podría contener varios tipos de variables: fechas, horas, cadenas, números, monedas y porcentajes. Para formatear un mensaje concatenado de un forma independiente de la Localidad, se construye un patrón que luego se aplica a un objeto MessageFormat.

En esta sección pasaremos a través de un programa de ejemplo para demostrar cómo internacionalizar un mensaje concatenado. El programa de ejemplo hace uso de la clase MessageFormat. El código fuente completo los puedes encontrar en MessageFormatDemo.java.

. 1. Identificar las Variables del Mensaje

La versión inglesa del mensaje que queremos internacionalizar es esta.

At 1:15 PM on April 13, 1998, we detected 7 spaceships on the planet Mars.
      ^             ^                     ^                           ^
      |             |                     |                           |
     Date          Date                 Number                      String

Observa que hemos subrayado las variables, y hemos identificado qué tipo de objetos representará estos datos.

. 2. Aislar el Patrón del Mensaje en un ResourceBundle

Vamos a almecenar el mensaje en un ResourceBundle llamado MessageBundle. Aquí tienes el código de creacción del ResourceBundle.

ResourceBundle messages =
   ResourceBundle.getBundle("MessageBundle",currentLocale);

Este ResourceBundle está compuesto por un fichero de propiedades para cada Localidad. Como nuestro ResourceBundle se llama MessageBundle, el fichero de propiedades para la Localidad U.S. English se llamará MessageBundle_en_US.properties. Aquí tienes los contendos de este fichero de propiedades.

template = At {2,time,short} on {2,date,long}, we detected {1,number,integer} spaceships on the planet {0}.
planet = Mars

Hemos especificado el patrón en la primera línea del fichero de propiedades. Si comparamos este patrón con el mensaje de texto mostrado en el paso 1, veremos que se ha reemplazado cada variable del mensaje con un argumento encerrado entre corchetes. Cada argumento empieza con un dígito llamado el número de argumento, que corresponde con el índice de un elemento en un array de Object que contiene los valores de los argumentos. Observa que en el patrón, estos argumentos no están en ningún orden particular. Se pueden situar los argumentos en cualquier orden dentro del patrón. El único requerimiento es que el número del argumento tenga un elemento correspondiente en el array de valores de los argumentos. En el siguiente paso explicaremos el array de valores de argumentos, pero primero echemos un vistazo a todos los argumentos del patrón. La siguiente tabla proporciona algunos detalles sobre los argumentos.

Argumento Descripción
{2,time,short} La parte horaria de un objeto Date. El estilo "short" especifica el estilo de formato DateFormat.SHORT.
{2,date,long} La parte de la fecha de un objeto Date. El mismo objeto Date se utiliza para las dos variables de fecha y hora. En el array de argumentos Object el índice que contiene el objeto Date es el 2.
{1,number,integer} Un objeto Number, además cualificado con el estilo numérico "integer".
{0} El String del ResourceBundle que corresponde con la clave "planet".

Para una descripción completa de la síntaxis de argumentos, puedes ver la documentación del API para la clase MessageFormat.

. 3. Seleccionar los Argumentos del Mensaje

En las siguientes líneas de código, asignamos los calores para cada argumento del patrón. Los índices de los elementos del array messageArguments corresponden con los números de los argumentos del patrón. Por ejemplo, el elemento de índice 1, que es un Integer(7), corresponde con el argumento {1,number,integer} del patrón. Extraemos los objetos String, que son los elementos 0 y 3, del ResourceBundle con getString, porque deben ser traducidos. El array de argumentos del mensaje se define de esta forma.

Object[] messageArguments = {
   messages.getString("planet"),
   new Integer(7),
   new Date()
};

. 4. Crear el Formateador

Luego, creamos un objeto MessageFormat. Seleccionamos la Localidad porque nuestro mensaje contiene objetos Date y Number, que deberían ser formateados de una manera sensible a la Localidad. Por ejemlo en inglés NorteAmericano la fechas 4/13/98 está en el formato correcto, pero en francés debería formatearse como 13/04/98. Creamos el formateador de mensajes de la siguiente forma.

MessageFormat formatter = new MessageFormat("");
formatter.setLocale(currentLocale);

. 5. Formatear el Mensaje utilizando el Patrón y los Argumentos

En este paso, demostraremos como trabajan juntos, el patrón, los argumentos del mensaje y el formateador. Primero, extraemos el String del patrón del ResourceBundle con el método getString. La clave para el patrón es "template." Pasamos el patrón al formateador con el método applyPattern. Luego, formateamos el mensaje utilizando el array de argumentos del mensaje llamando al método format. El String devuelto por este método ya está listo para utilizar. Todo esto se realiza con sólo dos líneas de código.

formatter.applyPattern(messages.getString("template"));
String output = formatter.format(messageArguments);

. 6. Ejecutar el Programa de Desmostración

Veamos que sucede cuando el programa se ejecuta con la Localidad U.S. English.

% java MessageFormatDemo en US

currentLocale = en_US

At 1:15 PM on April 13, 1998, we detected 7 spaceships on the planet Mars.

Cuando se ejecuta el programa para la Localidad Alemana, observamos que la fecha y la hora han sido localizadas.

% java MessageFormatDemo de DE

currentLocale = de_DE

Um 13.15 Uhr am 13. April 1998 haben wir 7 Raumschiffe auf dem Planeten Mars entdeckt.

. Manejar Plurales

Las palabras de un mensaje pueden variar si son en plural o singular. Con la clase ChoiceFormat, se puede mapear un número a una palabra o frase, permitiendo construir mensajes que sean gramáticamente correctos.

En Inglés, las formas plural y singular de una palabra nomalmente son diferentes. Esto puede representar un problema cuando se construyen mensajes que se refieren a cantidades. Por ejemplo, si el mensaje informa del número de ficheros en un disco, son posibles las siguientes variaciones.

There are no files on XDisk.
There is one file on XDisk.
There are 2 files on XDisk.

La forma más rápida de resolver este problema es crear un patrón de MessageFormat como éste.

There are {0,number} file(s) on {1}.

Desafortunadamente, este patrón resulta gramáticamente incorrecto.

There are 1 file(s) on XDisk.

Podemos hacer algo mejor que esto utilizando la clase ChoiceFormat. En esta sección, veremos como trarar con plurales en un mensaje, pasando a través de un programa de ejemplo llamado ChoiceFormatDemo.java. Este programa también hace uso de la clase MessageFormat que se describió en la sección anterior, Tratar con Mensajes Concatenados.

. 1. Definir el Patrón del Mensaje

Primero, identifiquemos las variables de nuestro mensaje.

There | are no files | on | XDisk | .
There | is one file  | on | XDisk | .
There | are 2 files  | on | XDisk | .
      |______________|    |_______|
            ^                 ^
            |                 |
         variable          variable

Luego, reemplazamos las variables del mensaje con argumentos, creando un patrón que puede aplicarse a un objeto MessageFormat.

There {0} on {1}.

Es muy sencillo trabajar con el argumento para el nombre del disco, que está representado por {1}. Lo trataremos igual que cualquier otra variable String en un patrón MessageFormat. Este argumento corresponde con el elemento 1 del array de valores (Ver paso 7).

Tratar con el argumento {0} es más complejo por un par de razones.

  • Primero, la frase que reemplaza este argumento varía con el número de ficheros. Para construir esta frase en tiempo de ejecución, necesitamos mapear el número de ficheros en un String particular. Por ejemplo, el número 1, mapeará el String "is one file." La clase ChoiceFormat permite realizar el mapeado necesario.
  • Segundo, si el disco contiene varios ficheros, la frase incluirá un entero. La clase MessageFormat nos permite insertar números en una frase.

. 2. Crear un ResourceBundle

Aislaremos el texto del mensaje en un ResourceBundle porque debe ser traducido.

ResourceBundle bundle =
   ResourceBundle.getBundle("ChoiceBundle",currentLocale);

Hemos decidido construir nuestro ResourceBundle con ficheros de propiedades. El fichero ChoiceBundle_en_US.properties contiene las siguientes líneas.

pattern = There {0} on {1}.
noFiles = are no files
oneFile = is one file
multipleFiles = are {2} files

El contenido de este fichero de propiedades muestra cómo se construirán y formatearán los mensajes. La primera línea contiene el patrón para MessageFormat, que explicamos en el paso anterior. Las otras líneas contienen frases que reemplazarán el argumento {0} en el patrón. La frase para la clave "multipleFiles" contiene el argumento {2}, que será reemplazado por un número.

Aquí podemos ver la versión francesa del fichero de propiedades ChoiceBundle_fr_FR.properties.

pattern = Il {0} sur {1}.
noFiles = n' y a pas des fichiers
oneFile = y a un fichier
multipleFiles = y a {2} fichiers

. 3. Crear un formateador de Mensaje

En este paso, ejemplarizamos MessageFormat y seleccionamos su Localidad.

MessageFormat messageForm = new MessageFormat("");
messageForm.setLocale(currentLocale);

. 4. Crear un formateador de Choice

El objeto ChoiceFormat nos permite elegir, basándose en un número double, un String particular. El rango de números double y los objetos String con los que se mapean, se especifican en arrays.

double[] fileLimits = {0,1,2};

String [] fileStrings = {
   bundle.getString("noFiles"),
   bundle.getString("oneFile"),
   bundle.getString("multipleFiles")
};

ChoiceFormat mapea cada elemento del array double con el elemento del array String que tiene el mismo índice. En nuestro código de ejemplo, el 0 mapea el String devuelto por la llamada a bundle.getString("noFiles"). Por coincidencia, en nuestro ejemplo, el índice es el mismo que el valor en el array fileLimits. si hubieramos seleccionado fileLimits[0] a 7, ChoiceFormat mapearía el número 7 con fileStrings[0].

Especificamos los arrays double y String cuando ejemplarizamos ChoiceFormat.

ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);

. 5. Aplicar el Patrón

¿Recuerdas el patrón que construimos en el paso 1? Ahora es el momento de recuperar el patrón del ResourceBundle y aplicarlo al objeto MessageFormat.

String pattern = bundle.getString("pattern");
messageForm.applyPattern(pattern);

. 6. Asignar lo formatos

En este paso, asignamos el objeto ChoiceFormat creado en el paso 4 al objeto MessageFormat.

Format[] formats = {choiceForm, null, NumberFormat.getInstance()};
messageForm.setFormats(formats);

El método setFormats asigna objetos Format a los argumentos del patrón del mensaje. Debemos llamar al método applyPattern antes del llamar al método setFormats. La siguiente tabla muestra cómo el array Format corresponde con los argumentos del patrón del mensaje.

Elemento del ArrayArgumento del Patrón
choiceForm{0}
null{1}
NumberFormat.getInstance(){2}

. 7. Seleccionar los Argumentos y el Formato del Mensaje

En tiempo de ejecución, asignamos las variables al array de argumentos que pasamos al objeto MessageFormat. Los elementos del array corresponden con los argumentos del patrón. Por ejemplo, messageArgument[1] mapea al argumento {1} del patrón, que es un String que contiene el nombre del disco. En el paso anterior, asignamos un objeto ChoiceFormat al argumento {0} del patrón. Por lo tanto, el número asignado a messageArgument[0] el String seleccionado por el objeto ChoiceFormat. Si messageArgument[0] es mayor o igual que 2, el String "are {2} files" reemplaza al argumento {0} del patrón. El número asignado a messageArgument[2] será substituido en lugar del argumento {2} del patrón. Intentaremos hacer esto con las siguientes líneas de código.


Object[] messageArguments = {null, "XDisk", null};

for (int numFiles = 0; numFiles < 4; numFiles++) {
   messageArguments[0] = new Integer(numFiles);
   messageArguments[2] = new Integer(numFiles);
   String result = messageForm.format(messageArguments);
   System.out.println(result);
}

. 8. Ejecutar el Programa de Demostración

Ejecutemos el programa para la Localidad U.S. English.

% java ChoiceFormatDemo  en US

currentLocale = en_US

There are no files on XDisk.
There is one file on XDisk.
There are 2 files on XDisk.
There are 3 files on XDisk.

Compara los mensajes mostrados por el programa con las frases del ResourceBundle del paso 2. Observa que el objeto ChoiceFormat selecciona la frase corecta, que el objeto MessageFormat utiliza para construir el mensaje apropiado.

La versión francesa del mensaje también parece correcta.

% java ChoiceFormatDemo fr FR

currentLocale = fr_FR

Il n' y a pas des fichiers sur XDisk.
Il y a un fichier sur XDisk.
Il y a 2 fichiers sur XDisk.
Il y a 3 fichiers sur XDisk.
 
Patrocinados
 

Copyright © 1999-2010 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Desarrollo web y diseño profesional por Color Vivo Internet. Un proyecto de los Hermanos Carrero

red internet: videos gratis | messenger gratis | decoración | juegos gratis | servidores dedicados
más internet: recursos gratis | bitácoras | gifs animados