Tweeteame!
Internacionalización es el proceso de diseñar una aplicación para que pueda ser adaptada a diferentes idiomas y regiones, sin necesitad de cambios de ingeniería. Algunas veces el término internacionalización se abrevia i18n, porque en el idioma inglés hay 18 letras entre la "i" y la "n" de Internacionalización.
Un programa internacionalizado tiene las siguientes características.
Una vez internacionalizado una aplicación, queda lista para la Localización (L10N).
Los mercados globales son lucrativos. Vender tus aplicaciones en todo el mundo genera muchas rentas e incrementa la cuota de mercado. Para tener éxito en el mercado internacional tus aplicaciones deben soportar idiomas locales y convenciones para el formateo de datos. Tus clientes no esperarán menos de ti. Por ejemplo, los Norteamericanos esperan sus mensajes en Inglés, las fechas en el formato mm/dd/yy, y la moneda expresada en dólares ($). Los Alemanes querrán sus mensajes en Alemán, las fechas en el formato dd.mm.yyyy, y la moneda expresada en Marcos alemanes (DM).
Las compañías de software utilizaban las formas más duras para personalizar sus programas. En la primera versión de un producto, codificaban dentro del programa los datos dependientes de la cultura como los textos o las fechas. Cuando querían soportar un nuevo idioma, tenían que hacer una copia del código fuente, cambiar todos los elementos necesarios y recompilar, Para liberar una nueva versión, tenían que actualizar los diferentes ficheros de código fuente y luego lanzar un nuevo conjunto de ejecutables. Este proceso no sólo era tedioso, también era propenso a errores y costoso. Afortunadamente, han emergido nuevas técnicas para ayudar a desarrollar software global: la Internacionalización y la Localización.
Localización es el proceso de adaptar software para una región o idioma específico añadiendo componentes específicos de la localidad y traduciendo el texto. El término Localización normalmente se contrae como "l10n" porque en idioma inglés hay 10 letras entre la "L" y la "n".
La traducción del texto es una importante tarea de localización. Durante la internacionalización, los textos como las etiquetas de los componentes GUI y los mensajes de error son almacenados fuera del código fuente para ser recuperados en tiempo de ejecución. Antes de que el texto pueda recuperarse debe ser traducido. Como el texto no está dentro del código fuente, el programa no requiere ninguna modificación. Los traductores trabajan con ficheros de texto que son leídos por el programa, no están dentro de él. Así, el mismo ejecutable funciona en cualquier parte del mundo.
Las convenciones de formateo de fechas, números y monedas varían con el idioma y la región. Los localizadores podrían necesitar especificar algunos patrones de formateo. O, el programa podría proporcionarlos automáticamente. En cualquier caso, los localizadores deben probar el software para verificar que las convenciones de formateo están según los requerimientos locales.
Aunque las aplicaciones multi-media existen desde hace años, casi todos los programas primarios utilizan texto para comunicarse con el usuario final. Esto es especialmente cierto en la comunidad de negocios. Si estás leyendo una página Web on-line, mira la cantidad de texto mostrado por las otras aplicaciones que se están ejecutando en tu navegador. ¿Has visto todos esos botones y menús? Todos necesitan ser traducidos si las aplicaciones van a ser vendidas en todo el mundo. No solo esto, también los mensajes de estado, los informes impresos y las pantallas de ayuda en línea requieren traducción. Como las aplicaciones muestran y generan tanto texto, las cuentas de traducción forman la mayor parte del costo de la localización.
Si manejas adecuadamente los elementos textuales de tu programa, podrás reducir el coste de la traducción. Deberías mover el texto traducible a ficheros de propiedades, donde puedan ser cargados en objetos ResourceBundle.
Las convenciones de formateo de números varía con el país. Se podrían utilizar diferentes caracteres para marcar el punto decimal y para separar los miles. La siguiente tabla muestra sólo unas pocas formas diferentes de formatear un número particular.
País | Número Formateado |
Francia | 123 456,78 |
Alemania | 123.456,78 |
U.S.A. | 123,456.78 |
Las unidades de moneda varían con el país. y también el formato de la cantidad. La siguiente tabla ilustra algunos ejemplos.
País | Moneda | Ejemplo |
España | Peseta | 1.234,56Pts |
Italia | Lira | L. 1.234,56 |
U.S.A. | Dollar | $1,234.56 |
El formateo de fechas y horas varía con el país. La siguiente tabla muestra algunos ejemplos.
País | Fecha | Hora |
Canada | 30/4/98 | 20:15 |
Alemania | 30.4.1998 | 20:15 Uhr |
U.S.A. | 4/30/98 | 10:15 PM |
Con el advenimiento de las aplicaciones GUI, las imágenes aparecen en cualquier lugar de nuestras pantallas. Las encontramos en iconos, gráficos, fotografías, dibujos y banners. Aunque la utilización de imágenes es universal, su significado no lo és. Por ejemplo, podrías estar tentado a utilizar señales de tráfico para ayudar a los usuarios finales a navegar a través de la aplicación. Pero como las señales de tráfico varían de un país a otro, tu programa debería mostrar diferentes versiones de los iconos en diferentes paises. Afortunadamente, puedes manejar objetos Image para las diferentes regiones y aislarlos en un ListResourceBundle.
Los colores tienen diferentes significados a lo largo del mundo. En U.S.A. el color blanco significa pureza, pero en Japón significa muerte. En Egipto, el color rojo representa la muerte, pero en China sugiere felicidad. Al igual que los objetos Image, los objetos Color dependientes de la cultura pueden ser manejados si son almacenados en un ListResourceBundle.
Si tus aplicaciones generan sonidos, debes tener en cuenta que el mismo sonido podría no ser reconocido en todo el mundo. Por ejemplo, las sirenas de policía son diferentes en U.S.A y en Alemania. Por su puesto, si tu aplicación da instrucciones verbales, las instrucciones deben ser traducidas. Puedes seguir la pista de de objetos AudioClip dependientes de la cultura si los almacenas en objetos ListResourceBundle.
Utilizando un ejemplo sencillo, veremos como internacionalizar un programa que muestra mensajes de texto en el idioma apropiado. En esta sección se detalla cómo trabajan juntos los objetos Locale y ResourceBundle, y cómo utilizar los ficheros de propiedades.
En la primera versión del código fuente, codificamos las versiones inglesas de los mensajes que queríamos mostrar. Esta NO es la forma de escribir software internacionalizado.
Supongamos que hemos escrito un programa que muestra tres mensajes.
System.out.println("Hello.");System.out.println("How are we?");System.out.println("Goodbye.");Hemos decidido que este programa necesita mostrar estos tres mensajes para la gente que vive en Francia y en Alemania. Desafortunadamente tu personal de programación no es multi-lingüe., por eso necesitas ayuda para traducir los mensajes al Francés y al Alemám. Cómo los traductores no son programadores, tenemos que sacar los mensajes fuera del código fuente a ficheros de texto que puedan ser editados por los traductores. También queremos que el programa sea lo suficientemente flexibe para poder mostrar los mensajes en otros idiomas, pero ahora mismo no sabemos qué idiomas. Por lo tanto, queremos que el usuario final especifique su idioma en el momento de la ejecución.
Parece que este programa necesita ser internacionalizado.
Abajo se detalla el código fuente del programa internacionalizado. Observa que el texto de los mensajes no está codificado.
import java.util.*; public class I18NSample { static public void main(String[] args) { if (args.length != 2) { System.out.println("Please specify language and country codes."); System.out.println("For example: java I18NSample fr FR"); System.exit(-1); } Locale currentLocale; ResourceBundle messages; String language = new String(args[0]); String country = new String(args[1]); currentLocale = new Locale(language, country); messages = ResourceBundle.getBundle("MessagesBundle",currentLocale); System.out.println(messages.getString("greetings")); System.out.println(messages.getString("inquiry")); System.out.println(messages.getString("farewell")); }}
Para ejecutar el programa de ejemplo, se especifica el idioma y el país en la línea de comandos. Esta sección muestra varios ejemplos.
Nuestro programa internacionalizado es flexible, porque permite que el usuario final pueda especificar el idioma y el país en la línea de comandos. En el siguiente ejemplo, el programa muestra los mensajes en Fancés, porque el código de lenguaje es fr (Francés), y el código de país es FR (Fráncia).
% java I18NSample fr FRBonjour.Comment allez-vous?Au revoir.En el siguiente ejemplo, el código de idioma es en (Inglés) y el código de país es US (Estados Unidos).
% java I18NSample en USHello.How are you?Goodbye.
Si observamos el código fuente internacionalizado, se puede ver que los mensajes en inglés dentro del código han desaparecido. Como estos mensajes ya no están dentro del código, y como el codigo del idioma se especifica en el momento de la ejecución, el mismo ejecutable puede ser distribuido por todo el mundo. No se requieren recompilaciones para su localización, Nuestro programa ha sido internacionalizado.
Un fichero de propiedades almacena información sobre las características de un programa o un entorno. Estos ficheros de propiedades tienen formato de texto plano. Se pueden crear con cualquier editor de textos, por ejemplo el Block de Notas.
En nuestro ejemplo, el fichero de propiedades almacena los textos traducibles de los mensajes que deseamos mostrar. Antes de que nuestro programa fuera internacionalizado, las versiones inglesas de los mensajes fueron codificadas dentro de sentencias System.out.println. Nuestro fichero de propiedades por defecto, que se llama MessagesBundle.properties, contiene las siguientes líneas.
greetings = Hellofarewell = Goodbyeinquiry = How are you?Ahora que los mensajes están en un fichero de propiedades, podemos traducirlos a varios idiomas. No se necesita modificar el código fuente. Nuestro traductor de Francés, ha creado un fichero de propiedades llamado MessagesBundle_fr_FR.properties, que contiene estas líneas.
greetings = Bonjour.farewell = Au revoir.inquiry = Comment allez-vous?
Observa que los valores situados a la derecha de los signos igual "=" han sido traducidos, pero las claves del lado izquierdo del signo no han cambiado. Estas claves no deben cambiar, porque el programa se referirá a ellas cuando recupere el texto traducido.
El nombre del fichero de propiedades es importante. El nombre del fichero MessagesBundle_fr_FR.properties contiene el código del idioma fr y el código del país FR. Estos códigos también se utilizan cuando se crea un objeto Locale.
Un objeto Locale define un idioma particular y un país. La siguiente sentencia define un objeto Locale para el idioma Inglés y el país de Estados Unidos.
aLocale = new Locale("en","US");El siguiente ejemplo crea objetos Locale para el idioma francés en Canada y Fráncia.
caLocale = new Locale("fr","CA");frLocale = new Locale("fr","FR");Queremos mantener flexible el programa de ejemplo, por ello, en vez de codificar los códigos de idioma y de país en el código fuente, los obtenemos de la línea de comandos en el momento de la ejecución.
String language = new String(args[0]);String country = new String(args[1]);currentLocale = new Locale(language, country);Los objetos Locale son sólo identificadores. Después de definir un objeto Locale, se lo pasas a otro objeto que realiza las tareas útiles, como formatear fechas y números. Estos objetos se llaman sensibles a la localidad, porque su comportamiento varía de acuerdo a la localidad. Un ResourceBundle es un ejemplo de objeto sensible a la localidad.
Los objetos ResourceBundle contienen objetos específicos de una localidad. Estos objetos ResourceBundle se utilizan para aislar los datos sensibles a la localidad, como texto traducible, etc. En nuestro programa de ejemplo, el ResourceBundle está constituido por los ficheros de propiedades que contienen los mensajes que queremos mostrar.
Nuestro objeto ResourceBundle se crea de esta forma.
message = ResourceBundle.getBundle("MessagesBundle",currentLocale)Los argumentos pasados al método getBundle identifican a los ficheros de propiedades a los que queremos acceder. El primer argumento, MessagesBundle, se refiere a esta familia de ficheros de propiedades.
MessagesBundle_en_US.propertiesMessagesBundle_fr_FR.propertiesMessagesBundle_de_DE.properties
El objeto Locale, que es el segundo argumento de getBundle, específica el fichero elegido de MessagesBundle. Cuando se creó el objeto Locale, se le pasaron al constructor los códigos del idioma y del país. Observa que estos códigos forman parte del nombre de los ficheros de propiedades de MessagesBundle.
Ahora, todo lo que tenemos que hacer es traducir los mensajes de ResourceBundle.
Los ficheros de propiedades contienen parejas clave/valor. Los valores consisten en texto traducido que nuestro programa mostrará. Especificaremos las claves cuando querramos utilizar los mensajes traducidos del ResourceBundle con el método getString. Por ejemplo, para recuperar el mensaje identificado por la clave "greetings", llamaríamos a getString de esta forma.
String msg1 = messages.getString("greetings");En nuestro ejemplo, utilizamos la clave greetings porque refleja el contenido del mensaje, podrías haber utilizado cualquier otro String, como s1 o msg1. Sólo recordar que la clave debe estar escrita en tu programa y que debe estar presente en los ficheros de propiedades. Si tu traductor modifica accidentalmente las claves de los ficheros de propiedades, getString no podrá encontrar los mensajes.
Los programas almacenan y operan con números de una forma independiente de la Localidad. Antes de mostrar o imprimir un número el programa debe convertirlo a un String que esté en un formato sensible a la Localidad. Por ejemplo, en Francia, el número 123456.78 debería ser formateado como 123 456,78, y en Alemania debería aparecer como 123.456,78. En esta sección, se verá como hacer que tus programas sean independientes de las convenciones de la localidad para los puntos decimales, los separadores de millares, y otras propiedades de formateo.
Se pueden utilizar los métodos de fábrica de NumberFormat para formatear números de tipos de datos primitivos, como double, y sus correspondientes objetos, como Double.
En el siguiente fragmento de código, formatearemos un Double de acuerdo a la Localidad. Primero, obtendremos un ejemplar de NumberFormat específico de la Localidad, llamando a getNumberInstance. Luego llamamos al método format con el Double como argumento. El método format devuelve el número formateado en un String, que está listo para ser mostrado.
Double amount = new Double(345987.246);NumberFormat numberFormatter;String amountOut; numberFormatter = NumberFormat.getNumberInstance(currentLocale);amountOut = numberFormatter.format(amount);System.out.println(amountOut + " " + currentLocale.toString());La salida de este ejemplo muestra como el formato del mismo número varía con la Localidad.
345 987,246 fr_FR345.987,246 de_DE345,987.246 en_USSi estás escribiendo aplicaciones de negocios, necesitarás formatear y mostrar valores en monedas. Las monedas se formatean de la misma forma que los números, excepto en que se llama a getCurrencyInstance para crear el formateador. Cuando se llama al método format , devuelve un String que incluye el número formateado y el signo de moneda apropiado.
El siguiente código muestra como formatear moneda de una forma específica de la Localidad.
Double currency = new Double(9876543.21);NumberFormat currencyFormatter;String currencyOut; currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);currencyOut = currencyFormatter.format(currency);System.out.println(currencyOut + " " + currentLocale.toString());La salida genera por las líneas precedentes sería esta.
9 876 543,21 F fr_FR9.876.543,21 DM de_DE$9,876,543.21 en_USA primera vista, esta salida podría parecer errónea, porque los valores numéricos son iguales. Por supuesto, 9 876 543,21 F no es equivalente a 9.876.543,21 DM. Sin embargo, recuerda que la clase NumberFormat no puede cambiar monedas. Los métodos pertenecientes a la clase NumberFormat formatean monedas, pero no las convierten.
También se pueden utilizar los métodos de la clase NumberFormat para formatear porcentajes. Para obtener el formateador específico de la localidad se llama al método getPercentInstance. Con este formateador, un fracción como 0.75 se mostrará como 75%.
El siguiente código muestra como formatear porcentajes.
Double percent = new Double(0.75);NumberFormat percentFormatter;String percentOut; percentFormatter = NumberFormat.getPercentInstance(currentLocale);percentOut = percentFormatter.format(percent);
Los objetos Date representan fechas y horas. No se puede mostrar o imprimir un objeto Date sin convertirlo primero a un String que esté en el formato apropiado. Pero, ¿Cuál es el formato adecuado? Primero, el formato debería estar conforme a las convenciones de la Localidad del usuario final. Por ejemplo, los alemanes reconocerán esto 9.4.98 como una fecha válida, pero los norteamericanos esperarán que la misma fecha aparezca como 4/9/98. Segundo, el formato debería incluir la información necesaria. Por ejemplo, un programa que mida el rendimiento de una red podría mostrar milisegundos. Probablemente un calendario de citas on-line no mostrará milisegundos, pero si que mostrará los días de la semana.
Esta sección se explica como formatear fechas y horas en diferentes formas, y de una manera sensible a la Localidad. Si sigues las técnicas descritas en esta sección, tus programas no sólo mostrarán las fechas y horas en la Localidad apropiada, sino que el código fuente permanecerá independiente de cualquier Localidad especificada.
Formatear fechas con la clase DateFormat es un proceso en dos pasos. Primero se crea un formateador con el método getDateInstance. Segundo, se llama al método format, que devuelve un String que contiene la fecha formateada. En el siguiente ejemplo, hemos formateado la fecha de hoy llamando a estos dos métodos.
Date today;String dateOut;DateFormat dateFormatter; dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, currentLocale);today = new Date();dateOut = dateFormatter.format(today); System.out.println(dateOut + " " + currentLocale.toString());Aquí está la salida generada por este código. Observa que los formatos de fechas varían con la Localidad. Como DateFormat es sensible a la Localidad, tiene cuidado de los detalles de formateo para cada Localidad.
9 avr 98 fr_FR9.4.1998 de_DE09-Apr-98 en_USEn el ejemplo de código anterior, hemos específicado el estilo de formato DEFAULT. Este estilo es sólo uno de los estilos de formato predefinidos que proporciona la clase DateFormat.
La siguiente tabla muestra cómo se formatea cada estilo para las Localidades de U.S. y Francia.
Estilo | Localidad U.S. | Localidad Francia |
DEFAULT | 10-Apr-98 | 10 avr 98 |
SHORT | 4/10/98 | 10/04/98 |
MEDIUM | 10-Apr-98 | 10 avr 98 |
LONG | April 10, 1998 | 10 avril 1998 |
FULL | Friday, April 10, 1998 | vendredi, 10 avril 1998 |
Los objetos Date representan tanto fechas como horas. Formatear horas con la clase DateFormat es similar al formateo de fechas, excepto en que el formateador se crea con el método getTimeInstance.
DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, currentLocale);La siguiente tabla muestra los estilos de formatos predefinidos para las horas en las localidades de U.S. y Alemania.
Estilo | Localidad U.S. | Localidad Alemania |
DEFAULT | 3:58:45 PM | 15:58:45 |
SHORT | 3:58 PM | 15:58 |
MEDIUM | 3:58:45 PM | 15:58:45 |
LONG | 3:58:45 PM PDT | 15:58:45 GMT+02:00 |
FULL | 3:58:45 oclock PM PDT | 15.58 Uhr GMT+02:00 |
Para mostrar la fecha y la hora en la misma String, se crea el formateador con el método getDateTimeInstance. El primer parámetro es el estilo de fecha y el segundo es el estilo de la hora. El tercer parámetro es nuestro viejo amigo Locale. Aquí tienes un ejemplo rápido.
DateFormat formatter; formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, currentLocale);Para la localidad de U.S., el formateado de este ejemplo, formateará la fecha y la hora de esta forma.
April 10, 1998 4:05:54 PM PDT
Si el ejemplo del formateador se hubiera creado con la Localidad Francia, el String devuelto por el método format sería.
11 avril 1998 01:05:54 GMT+02:00
| < Prev | Próximo > |
|---|