Internacionalización de Programas Java

Las aplicaciones que manipulan texto necesitan localizar l�mites dentro del propio texto. Por ejemplo, consideremos algunas de las funciones comunes en un procesador de textos: iluminar un caracter, cortar una palabra, mover el cursor al p�rrafo siguiente, y cortar las palabras al final de la l�nea. Para realizar cada una de estas funciones, el procesador de textos debe poder detectar los l�mites l�gicos del texto. Afortunadamente, no tenemos que escribir nuestras propias rutinas para realizar an�lisis de l�mites. En su lugar, podemos aprovecharnos de los m�todos propocionados por la clase BreakIterator.

.�Sobre la clase BreakIterator

Esta secci�n explica la ejemplarizaci�n de m�todos y los cursores imaginarios de la clase BreakIterator.

clase BreakIterator es sensible a la Localidad, porque los l�mites de texto pueden variar con el idioma. Por ejemplo, la reglas para ruptura de l�neas no son las mismas para todos los idiomas. Para determinar las Localidades soportadas por la clase BreakIterator se llama al m�todo getAvailableLocales.

Locale[] locales = BreakIterator.getAvailableLocales();

Se pueden analizar cuatro tipos diferentes de l�mites con la clase BreakIterator: caracter, palabra, p�rrafo y ruptura potencial de l�nea. Cuande se ejemplariza un BreakIterator, se debe llamar al m�todo de creacci�n apropiado.

  • getCharacterInstance
  • getWordInstance
  • getSentenceInstance
  • getLineInstance

Cada ejemplar de BreakIterator s�lo puede detectar un tipo de l�mite. Si se quiere localizar el l�mite de caracter y de palabra, por ejemplo, se necesitar� crear dos ejemplares separados.

Un BreakIterator tiene un cursor imaginario que apunta al l�mite actual en una cadena de texto. Se puede mover este cursor dentro del texto con los m�todos previous y next. Por ejemplo, si hemos creado un BreakIterator con getWordInstance, cada vez que llamemos al m�todo next el cursor de mover� al siguiente l�mite de palabra dentro del texto. Los m�todos de movimiento del cursor devuelven un entero indicando la posici�n del l�mite. Esta posici�n es el �ndice del caracter de la cadena de texto que sigue al l�mite. Al igual que los Strings indexados, los l�mites est�n basados en cero. El primer l�mite es el 0, y el �ltimo l�mite es la longitud de la cadena.

Se deber�a utilizar la clase BreakIterator s�lo con texto natural. No se debe utilizar con lenguajes de programaci�n.

En las siguientes secciones, proporcionaremos ejemplos de cada tipo de l�mite. Los ejemplos de c�digo se han extraido de un fichero llamado BreakIteratorDemo.java.

.�L�mite de Caracter

En esta secci�n aprender�s la diferencia entre los caracteres de usuario y los caracteres Unicode, y como localizar los caracteres de usuario con un BreakIterator.

necesitar� localizar los l�mites de caracter si nuestra aplicaci�n permite al usuario final seleccionar caracteres individuales. o mover el cursor a trav�s del texto caracter a caracter. Para crear un BreakIterator que localice los l�mites de caracter se llama al m�todo getCharacterInstance.

BreakIterator characterIterator = 
   BreakIterator.getCharacterInstance(currentLocale);

Este tipo de BreakIterator detecta l�mites entre caracteres de usuario, no s�lo caracteres Unicode. Los caracteres de usuario var�an con el idioma, pero la clase BreakIterator puede reconocer estas diferencias porque es sensible a la Localidad. Un caracter de usuario podr�a estar compuesto por uno o m�s caracteres Unicode. Por ejemplo, el caracter de usuario � podr�a componerse combinando los caracteres Unicode '\u0075' (u) '\u00a8' (�). Sin embargo, este no es el mejor ejemplo, porque el caracter � tambi�n podr�a ser represetnado por un s�lo caracter Unicode '\u00fc'. Veremos el idioma �rabe para un ejemplo m�s realista.

En �rabe, la palabra para casa es.

Aunque esta palabra contiene tres caracteres de usuario, est� compuesta por seis caracteres Unicode.

String house = "\u0628" + "\u064e" + "\u064a" + 
               "\u0652" + "\u067a" + "\u064f";

Los caracteres Unicode de las posiciones 1,3 y 5 en la cadena house son diacr�ticos. En �rabe los diacr�ticos son necesarios, porque pueden alterar el significado de las palabras. Los diacr�ticos en nuesto ejemplo son caracteres no blancos ya que aparecen sobre los caracteres base. En un procesador de textos �rabe, no podemos mover el cursor sobre cada caracter Unicode de la cadena. En su lugar, debemos movernos sobre cada caracter de usuario, que podr�a estar compuesto por m�s de un caracter Unicode. Por lo tanto, debemos utilizar un BreakIterator para scanear los caracteres de usuario en la cadena.

En nuestro ejemplo, BreakIteratorDemo.java, hemos creado un BreakIterator para scanear caracteres ar�bicos. Luego pasamos este BreakIterator, junto con el objeto String creado anteriormente, al m�todo llamado listPositions.

BreakIterator arCharIterator =
   BreakIterator.getCharacterInstance(new Locale ("ar","SA"));

listPositions (house,arCharIterator);

El m�todo listPositions utiliza un BreakIterator para localizar los l�mites de caracter dentro de la cadena. Observa que asignamos un string particular al BreakIterator con el m�todo setText. Recuperamos el primer l�mite de caracter con el m�todo first, luego llamamos al m�todo next hasta que se devuelva la constante BreakIterator.DONE. Aqu� podemos ver el c�digo de esta rutina.

static void listPositions(String target, BreakIterator iterator) {

   iterator.setText(target);
   int boundary = iterator.first();

   while (boundary != BreakIterator.DONE) {
      System.out.println (boundary);
      boundary = iterator.next();
   }
}

El m�todo listPositions imprime las siguientes posiciones de l�mites para los caracteres de usuario de la cadena house. Las posiciones de los diacr�ticos (1, 3, 5) no se listan.

0
2
4
6

.�L�mite de Palabra

Si la aplicaci�n necesita seleccionar o lacalizar palabras dentro del texto, encontraremos util el uso de un BreakIterator.

invoca al m�todo getWordIterator para ejemplarizar un BreakIterator que detecte l�mites de palabra.

BreakIterator wordIterator =
   BreakIterator.getWordInstance(currentLocale);

Querremos crear un BreakIterator como �ste cuando nuestras aplicaciones necesiten realizar operaciones con palabras individuales. Estas operaciones podr�an ser las funciones comunes de los procesadores de textos como selecionar, cortar, pegar y copiar. O nuestras aplicaciones podr�an buscar palabras, y para hacer esto necesitan poder distinguir entre palabras completas.

Cuando se realizan an�lisis de l�mites de palabra, un BreakIterator diferencia entre las palabras y los caracteres que no forman parte de las palabras. Estos caracteres, que incluyen espacios, tabuladores, marcas de puntuaci�n, y algunos s�mbolos, tienen l�mites de palabras en �mbos lados.

En el siguiente ejemplo, extraido del programa BreakIteratorDemo.java, queremos marcar los l�mites de palabras en alg�n texto. Primero creamos el BreakIterator y luego llamamos a un m�todo que hemos escrito llamado markBoundaries.

Locale currentLocale = new Locale ("en","US");

BreakIterator wordIterator =
   BreakIterator.getWordInstance(currentLocale);

String someText = "She stopped.  " +
                  "She said, \"Hello there,\" and then went on.";

markBoundaries(someText, wordIterator);

El prop�sito de este m�todo es marcar los l�mites de palabras en un string con un caracter ('^'). Cada vez que BreakIterator detecta un l�mite palabra, insertamos este caracter en el buffer markers. Scaneamos el string en un bucle, llamando al m�todo next hasta que devuelva BreakIterator.DONE. Aqu� tenemos el c�digo de la rutina markBoundaries.


static void markBoundaries(String target, BreakIterator iterator) {

   StringBuffer markers = new StringBuffer();
   markers.setLength(target.length() + 1);
   for (int k = 0; k < markers.length(); k++) {
      markers.setCharAt(k,' ');
   }

   iterator.setText(target);
   int boundary = iterator.first();

   while (boundary != BreakIterator.DONE) {
      markers.setCharAt(boundary,'^');
      boundary = iterator.next();
   }

   System.out.println(target);
   System.out.println(markers);
} 

El m�todo markBoundaries imprime el string target y el buffer markers. Obseva donde ocurren los caracteres ('^') en relaci�n con las marcas de puntuaci�n y los espacios.

She stopped.  She said, "Hello there," and then went on.
^  ^^      ^^ ^  ^^   ^^^^    ^^    ^^^^  ^^   ^^   ^^  ^

El BreakIterator hace sencilla la selecci�n de palabras dentro de un texto. No tenemos que escribir nuestras propias rutinas para manejar las reglas de puntuaci�n de los distintos idiomas, porque la clase BreakIterator lo hace por nosotros. Aqu� podemos ver una subrutina que extrae e imprime las palabras de una cadena dada.

static void extractWords(String target, BreakIterator wordIterator) {

   wordIterator.setText(target);
   int start = wordIterator.first();
   int end = wordIterator.next();

   while (end != BreakIterator.DONE) {
      String word = target.substring(start,end);
      if (Character.isLetterOrDigit(word.charAt(0))) {
         System.out.println(word);
      }
      start = end;
      end = wordIterator.next();
   }
} 

En nuestro ejemplo, llamamos a extractWords, le pasamos la misma cadena que en el ejemplo anterior. El m�todo extractWords imprimir� la siguiente lista de palabras.

She
stopped
She
said
Hello
there
and
then
went
on.

.�L�mites de P�rrafo

Determinar los l�mites de p�rrafo puede ser problem�tico, debido a la utilizaci�n ambigua de terminadores de sentecias en muchos idiomas escritos. Esta secci�n examina algunos de los problemas que podremos encontrarnos, y como tratarlos con la clase BreakIterator.

En muchos idiomas el terminador de sentencia es un punto. En Ingl�s, tambi�n se utiliza un punto para especificar el separador decimal, para indicar una marca de elipsis, y para terminar abreviaturas. C�mo el punto tiene m�s de un prop�sito, no podemos determinar el l�mite se sentencia con total seguridad.

Primero, echemos un vistazo a un caso en el que si funciona la detecci�n de l�mite de sentencia. Empezaremos creando un BreakIterator con el m�todo getSentenceInstance.

BreakIterator sentenceIterator =
   BreakIterator.getSentenceInstance(currentLocale);

Para demostrar los l�mites de sentencias, utilizaremos el m�todo markBoundaries, que se explic� en la secci�n anterior. El m�todo markBoundaries imprime caracteres ('^') en un string para indicar las posiciones de los l�mites. En el siguiente ejemplo, los l�mites de sentencias est�n definidos apropiadamente.

She stopped.  She said, "Hello there," and then went on.
^             ^                                         ^

Tambi�n se pueden localizar los l�mites de sentencias que terminen en interrogaciones o puntos de exaclamaci�n.

He's vanished!  What will we do?  It's up to us.
^               ^                 ^             ^

Utilizar el punto como separador decimal no provoca ning�n error.

Please add 1.5 liters to the tank.
^                                 ^

Una marca de elipsis (puntos suspensivos) indica la omisi�n de texto dentro de un pasaje entrecomillado. En el siguiente ejemplo los puntos suspensivos generan l�mites de sentencia.

"No man is an island . . . every man . . . "
^                      ^ ^             ^ ^ ^^

Las abreviaturas tambi�n podr�an provocar errores. Si el punto es seguido por un espacio en blanco y una letra may�scula, el BreakIterator detecta un l�mite de sentencia.

My friend, Mr. Jones, has a new dog.  The dog's name is Spot.
^              ^                      ^                      ^

.�L�mite de L�nea

Esta secci�n describe como localizar las rupturas de l�nea potenciales en una cadena de texto con un BreakIterator.

Las aplicaciones que formatean texto o realizan ruptura de l�neas deben localizar las rupturas de l�neas potenciales. Se pueden encontrar estas rupturas de l�nea, o l�mites, con un BreakIterator que haya sido creado con el m�todo getLineInstance.

BreakIterator lineIterator = 
   BreakIterator.getLineInstance(currentLocale);

Este BreakIterator determina la posici�n en que se puede romper una l�nea para continuar en la siguiente l�nea. Las posiciones detectadas por el BreakIterator son rupturas de l�neas potenciales. La ruptura de l�nea real mostrada en la pantalla podr�a no ser la misma.

En los siguientes ejemplos, utilizamos el m�todo markBoundaries para ver los l�mites de l�nea detectados por un BreakIterator. Este m�todo imprime marcas en los l�mites de l�nea de la cadena fuente.

De acuerdo al BreakIterator, un l�mite de l�nea ocurre despu�s del final de una secuencia de caracteres blancos, (space, tab, newline). En el siguiente ejemplo, podemos romper la l�nea en cualquiera de los l�mites detectados.

She stopped.  She said, "Hello there," and then went on.
^   ^         ^   ^     ^      ^       ^   ^    ^    ^  ^

Las rupturas de l�neas potenciales tambi�n ocurren inmediatamente despu�s de un gui�n.

There are twenty-four hours in a day.
^     ^   ^      ^    ^     ^  ^ ^   ^

En el siguiente ejemplo, rompemos una cadena en l�neas de la misma longitud con un m�todo llamado formatLines. Utilizamos un BreakIterator para localizar las rupturas de l�neas potenciales. Para romper una l�nea, ejecutamos un System.out.println() siempre que la longitud de la l�nea actual alcance el valor del par�metro maxLength. El m�todo formatLines es corto, sencillo, y gracias al BreakIterator, independiente de la Localidad. Aqu� puedes ver su c�digo fuente.


static void formatLines(String target, int maxLength, 
                        Locale currentLocale) {

   BreakIterator boundary = BreakIterator.getLineInstance(currentLocale);
   boundary.setText(target);
   int start = boundary.first();
   int end = boundary.next();
   int lineLength = 0;

   while (end != BreakIterator.DONE) {
      String word = target.substring(start,end);
      lineLength = lineLength + word.length();
      if (lineLength >= maxLength) {
         System.out.println();
         lineLength = word.length();
      }
      System.out.print(word);
      start = end;
      end = boundary.next();
   }
} 

En el programa BreakIteratorDemo.java llamamos a formatLines de esta forma.

String moreText = "She said, \"Hello there,\" and then " +
                  "went on down the street.  When she stopped " +
                  "to look at the fur coats in a shop window, " +
                  "her dog growled.  \"Sorry Jake,\" she said. " +
                  " \"I didn't know you would take it personally.\"";

formatLines(moreText, 30, currentLocale);

Aqu� podemos ver la salida de la llamada a formatLines.

She said, "Hello there," and 
then went on down the 
street.  When she stopped to 
look at the fur coats in a 
shop window, her dog 
growled.  "Sorry Jake," she 
said.  "I didn't know you 
would take it personally."

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP