Aplicaciones Internacionalizadas en Java
Cuando diseñamos una aplicación Java, tenemos que tener en cuenta tanto las necesidades actuales como futuras de nuestra aplicación.
Es posible que pensemos que nuestro programa solo necesita mostrar mensajes en nuestro idioma local (en este caso castellano) pero, con mucha probabilidad, en un futuro cercano deba funcionar en otros ….. pongase Ingles, Catalán, etc
Una vez completada una aplicación, sin tener este factor en cuenta, el coste
de internacionalizarla y realizar las prubas de regresión puede ser muy elevado
o incluso …. puede ser necesario un rediseño completo.
Java, propociona un conjunto de clases para facilitarnos esta labor…
Locale
Un Locale representa una región concreta … podemos ver la seleccionada
actualmente.
package roberto; /* * primerPrograma.java * * Created on July 16, 2003, 3:53 AM */ import java.text.*; import java.util.*; /** * * @author Administrator */ public class primerPrograma { /** Constructor por defecto de la clase */ public primerPrograma() { } /** * Punto de entrada estático de la aplicación * @param args recibe los parámetros de linea de comando */ public static void main(String[] args) { primerPrograma oInstanciaLocal = new primerPrograma(); oInstanciaLocal.ejecutaProceso(); } /** * Ejecutamos el proceso como un instancia local */ private void ejecutaProceso() { Locale lDefecto = Locale.getDefault(); muestraDatosLocale(lDefecto); Locale[] listaLocales = Locale.getAvailableLocales(); for(int i=0 ; i < listaLocales.length ; i++) { muestraDatosLocaleTab(listaLocales[i]); } } void muestraDatosLocale(Locale lActual) { depura("El pais mostrado es: " +lActual.getDisplayCountry()); depura("El pais es: " +lActual.getCountry()); depura("El lenguaje actual es: " + lActual.getLanguage()); depura("La varidedad del lenguaje es: " + lActual.getDisplayVariant()); depura("El pais actual es: " +lActual.getLanguage()); depura("El nobre actual es: " +lActual.getDisplayName()); try { depura("El pais ISO actual es: " +lActual.getISO3Country()); depura("El lenguaje ISO actual es: " +lActual.getISO3Language()); depura(""); } catch (Exception e) { } } void muestraDatosLocaleTab(Locale lActual) { muestraSimple(lActual.getDisplayCountry()); muestraSimple(lActual.getCountry()); muestraSimple(lActual.getLanguage()); muestraSimple(lActual.getDisplayVariant()); muestraSimple(lActual.getLanguage()); muestraSimple(lActual.getDisplayName()); try { muestraSimple(lActual.getISO3Country()); muestraSimple(lActual.getISO3Language()); depura(""); } catch (Exception e) { } } void muestraSimple(String pCadena) { System.out.print(pCadena + "\t"); } void depura(String pCadena) { System.out.println(pCadena); } } |
La salida actual es:
Y todas las actualmente definidas (las hemos importado en excel)
Crear una nueva localización
Vamos a crear una localización que represente España
package roberto; /* * primerPrograma.java * * Created on July 16, 2003, 3:53 AM */ import java.text.*; import java.util.*; /** * * @author Administrator */ public class primerPrograma { /** Constructor por defecto de la clase */ public primerPrograma() { } /** * Punto de entrada estático de la aplicación * @param args recibe los parámetros de linea de comando */ public static void main(String[] args) { primerPrograma oInstanciaLocal = new primerPrograma(); oInstanciaLocal.ejecutaProceso(); } /** * Ejecutamos el proceso como un instancia local */ private void ejecutaProceso() { Locale lDefecto = Locale.getDefault(); muestraDatosLocale(lDefecto); Locale lCastellano = new Locale("ES","es"); muestraDatosLocale(lCastellano); } void muestraDatosLocale(Locale lActual) { depura("El pais mostrado es: " +lActual.getDisplayCountry()); depura("El pais es: " +lActual.getCountry()); depura("El lenguaje actual es: " + lActual.getLanguage()); depura("La varidedad del lenguaje es: " + lActual.getDisplayVariant()); depura("El pais actual es: " +lActual.getLanguage()); depura("El nobre actual es: " +lActual.getDisplayName()); try { depura("El pais ISO actual es: " +lActual.getISO3Country()); depura("El lenguaje ISO actual es: " +lActual.getISO3Language()); depura(""); } catch (Exception e) { } } void depura(String pCadena) { System.out.println(pCadena); } } |
La salida del programa es
El pais mostrado es: United States El pais es: US El lenguaje actual es: en La varidedad del lenguaje es: El pais actual es: en El nobre actual es: English (United States) El pais ISO actual es: USA El lenguaje ISO actual es: eng El pais mostrado es: Spain El pais es: ES El lenguaje actual es: es La varidedad del lenguaje es: El pais actual es: es El nobre actual es: Spanish (Spain) El pais ISO actual es: ESP El lenguaje ISO actual es: spa |
Ficheros de recursos para cada idioma
En siguiente paso sería crear una mecanismo para que en función del idioma,
se utilice un juego particular.
Podemos crear un fichero de propiedades, que tengan la misma clave y un valor
distinto para cada idioma. Solo tenemos que tener la precaucion de saber como
nombrarlos….
Recurrimos a la ayuda Java
Nos ayudamos de NetBeans para crear el fichero de propiedades
Seleccionamos el nombre
Añadimos una versión «localizada»
Seleccionamos Español de España
Comprobamos que se ha creado y pulsamos el botón de nueva
propiedad
Creamos una nueva propiedad (ver que tenemos seleccionado
la versión local españona)
Podemos editar la tabla para cambiar el texto en la inglesa
Realmente se han creado dos ficheros en el sistema
Si vemos el Ingles tiene este aspecto
# Sample ResourceBundle properties file
#Este es el saludo de bienvenida |
Y el castellano
# Sample ResourceBundle properties file
#Este es el saludo de bienvenida |
Si ejecutamos nuestro programa
package roberto; /* * primerPrograma.java * * Created on July 16, 2003, 3:53 AM */ import java.text.*; import java.util.*; /** * * @author Administrator */ public class primerPrograma { /** Constructor por defecto de la clase */ public primerPrograma() { } /** * Punto de entrada estático de la aplicación * @param args recibe los parámetros de linea de comando */ public static void main(String[] args) { primerPrograma oInstanciaLocal = new primerPrograma(); oInstanciaLocal.ejecutaProceso(); } /** * Ejecutamos el proceso como un instancia local */ private void ejecutaProceso() { Locale lDefecto = Locale.getDefault(); muestraDatosLocale(lDefecto); ResourceBundle recursos = ResourceBundle.getBundle("CRecursosApp",lDefecto); depura("El saludo en Ingles es: " + recursos.getString("SALUDO")); Locale lCastellano = new Locale("ES","es"); muestraDatosLocale(lCastellano); recursos = ResourceBundle.getBundle("CRecursosApp",lCastellano); depura("El saludo en Castellano es: " + recursos.getString("SALUDO")); } void muestraDatosLocale(Locale lActual) { depura("El pais mostrado es: " +lActual.getDisplayCountry()); depura("El pais es: " +lActual.getCountry()); depura("El lenguaje actual es: " + lActual.getLanguage()); depura("La varidedad del lenguaje es: " + lActual.getDisplayVariant()); depura("El pais actual es: " +lActual.getLanguage()); depura("El nobre actual es: " +lActual.getDisplayName()); try { depura("El pais ISO actual es: " +lActual.getISO3Country()); depura("El lenguaje ISO actual es: " +lActual.getISO3Language()); depura(""); } catch (Exception e) { } } void depura(String pCadena) { System.out.println(pCadena); } } |
La salida es
El pais mostrado es: United States El pais es: US El lenguaje actual es: en La varidedad del lenguaje es: El pais actual es: en El nobre actual es: English (United States) El pais ISO actual es: USA El lenguaje ISO actual es: eng El saludo en Ingles es: Hello Word El pais mostrado es: Spain El pais es: ES El lenguaje actual es: es La varidedad del lenguaje es: El pais actual es: es El nobre actual es: Spanish (Spain) El pais ISO actual es: ESP El lenguaje ISO actual es: spa El saludo en Castellano es: Hola compañeros |
MessageFormat, Mensajes con parámetros variables
Normalmente los mensajes no son solo texto sino que hay que intercalar
variables dentro del mensaje.
Todo esto ya esta pensado ….
Podemos definir en nuestra cadena de caracteres … por indice basado en 0
…
Es decir … del tipo
Hello Word, user number {0} of today, day {1} |
Modificamos nuestro código … podemos recuperar la cadena y crear un
formateador
MessageFormat
fCadenaFormatear = new MessageFormat(recursos.getString(«SALUDO»));
Creamos un array
Object
aoParametros[] = {«1»,new Date()};
Y decimos que se combinen ambos
fCadenaFormatear.format(aoParametros)
En el caso de la cadena en castellano, podemos decir que los objetos se
formatéen, usando los parámetros locales
fCadenaFormatear.setLocale(lCastellano);
package roberto; /* * primerPrograma.java * * Created on July 16, 2003, 3:53 AM */ import java.text.*; import java.util.*; /** * * @author Administrator */ public class primerPrograma { /** Constructor por defecto de la clase */ public primerPrograma() { } /** * Punto de entrada estático de la aplicación * @param args recibe los parámetros de linea de comando */ public static void main(String[] args) { primerPrograma oInstanciaLocal = new primerPrograma(); oInstanciaLocal.ejecutaProceso(); } /** * Ejecutamos el proceso como un instancia local */ private void ejecutaProceso() { Locale lDefecto = Locale.getDefault(); ResourceBundle recursos = ResourceBundle.getBundle("CRecursosApp",lDefecto); MessageFormat fCadenaFormatear = new MessageFormat(recursos.getString("SALUDO")); Object aoParametros[] = {"1",new Date()}; depura("Cadena Formateada en Ingles " + fCadenaFormatear.format(aoParametros)); // ahora en castellano Locale lCastellano = new Locale("ES","es"); recursos = ResourceBundle.getBundle("CRecursosApp",lCastellano); fCadenaFormatear = new MessageFormat(recursos.getString("SALUDO")); fCadenaFormatear.setLocale(lCastellano); depura("Cadena Formateada en Castellano es " + fCadenaFormatear.format(aoParametros)); } void depura(String pCadena) { System.out.println(pCadena); } } |
La salida, podemos ver que aparece tal y como deseamos.
Cadena Formateada en Ingles Hello Word, user number 1 of today, day 7/18/03 8:57 AM Cadena Formateada en Castellano es Hola eres el usuario 1 de hoy, dia 18/07/03 8:57 |
Podemos especificar el formato con más detalle
Modificando la cadena, sin modificar el programa
Hello Word, user number {0,number, #,000.##} of today, day {1,date,short} |
La salida es:
Cadena Formateada en Ingles Hello Word, user number 001 of today, day 7/18/03 Cadena Formateada en Castellano es Hola eres el usuario 1 de hoy, dia 18/07/03 9:29 |