Java i18n Internationalization

¿Qué por qué se llama i18n? búscalo y verás, qué cosas.

A diferencia de otros lenguajes la internacionalización de programas en java, al menos la forma básica que trae la plataforma por defecto te permite hacer de todo (fechas, monedas, traducción de texto con parámetros) pero la forma es cuando menos engorrosa.

Lo que he puesto aquí es el típico churro que muestra cómo hacer varias cosas: detectar el locale del sistema, aplicar el que nosotros queramos, mostrar números y monedas según el locale, las fechas, etc. y por supuesto, mostrar mensajes en distintos idiomas, con o sin parámetros.

si ahondamos un poco en la documentación oficial veremos que hay dos tipos de internacionalizaciones, una es la que veremos aquí pero hay otra (ListResourceBundle) en la que hay que crear ficheros *.class para la internacionalización.

Otra cosa curiosa es que los ficheros properties con los mensajes deben estar en el classpath como si fueran clases. Por cada idioma que queremos meter debemos crear un fichero con mensajes, incluyendo uno que será el que se aplique en caso de no encontrar el locale elegido en el programa.

Messages.properties

Este sería el fichero por defecto:

# this is a comment
start = Starting program
end = Program ended
hello = Hello
name = My name is {0}
name2 = My name is {0} and Im {1,number,integer} years old \
and I was born in {2,date,long} at {2,time,short} \
and I weighed {3,number}

Message_en_US.properties

Este sería la versión inglesa-USA:

# this is a comment
start = Starting program
end = Program ended
hello = Hello
name = My name is {0}
name2 = My name is {0} and Im {1,number,integer} years old \
and I was born in {2,date,long} at {2,time,short} \
and I weighed {3,number}

Message_es_ES.properties

Y la versión española, ole ole y ole qué arte :)

# this is a comment
start = Iniciando programa
end = Programa terminado
hello = Hola
name = Mi nombre es {0}
name2 = Mi nombre es {0} y tengo {1,number,integer} años\
y nací el {2,date,long} a las {2,time,short}\
y pesé {3,number}

El programa

Un churro con todas las pruebas que se me ocurrían, aunque sé que faltan algunas.

import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Currency;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Scanner;


/**
 * Shows how to write a program with messages in different languages
 * NOTE: message files (*.properties) must be located in the classpath
 * like a *.class file
 * @author Pello Altadill
 * @greetz fat-free milk drinker
 * http://butterbeliever.com/fat-free-dairy-skim-milk-secrets/
 */
public class InternationalizationSample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Locale locale = Locale.getDefault();
        String language = locale.getDisplayLanguage();
        String country = locale.getDisplayCountry();
        Scanner reader = new Scanner(System.in);
        Integer integerNumber = new Integer(160666);
        Double doubleNumber = new Double(1666.42);
        NumberFormat numberFormatter;
        DateFormat dateFormatter;
        Currency currency;
        
        String languageCode = System.getProperty("user.language");
        String countryCode = System.getProperty("user.country");
        System.out.println("Lang: " + language + ", country: " + country);
        System.out.println("Lang: " + languageCode + ", country: " + countryCode);
        
        System.out.println("Give me lang code (en, es, eu): ");
        languageCode = reader.nextLine();
        System.out.println("Give me country code (EN, ES, EU): ");
        countryCode = reader.nextLine();
        
        // Let's show messages in selected language
        ResourceBundle messages;

        System.out.println("Setting locales to: " + languageCode +"_"+countryCode);
        locale = new Locale(languageCode, countryCode);
        messages = ResourceBundle.getBundle("Messages", locale);

        System.out.println(messages.getString("start"));
        System.out.println(messages.getString("hello"));
        System.out.println(messages.getString("end"));
        
        numberFormatter = NumberFormat.getNumberInstance(locale);
        dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, locale);
       // currency = Currency.getInstance(locale);
        
        System.out.println("Numbers: " + numberFormatter.format(integerNumber));
        System.out.println("Number Double: " + numberFormatter.format(doubleNumber));

        //numberFormatter = NumberFormat.getCurrencyInstance(locale);
        //System.out.println("Currency: " + currency);
        //System.out.println("Money: " + numberFormatter.format(doubleNumber));
        
        // PARAMETERS!!!
        // For messages with parameters we use MesssageFormat
        // This will be the param to fill de message
        Object[] messageParams = {
                "Prince"
            };
        MessageFormat formatter = new MessageFormat("");
        formatter.setLocale(locale);
        formatter.applyPattern(messages.getString("name"));
        System.out.println(formatter.format(messageParams));
        // Format samples: http://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html
        Object[] messageParams2 = {
                "Prince",
                new Integer(45),
                new Date(),
                new Double(3.4)
            };
        formatter = new MessageFormat("");
        formatter.setLocale(locale);
        formatter.applyPattern(messages.getString("name2"));
        System.out.println(formatter.format(messageParams2));
    }

}