Spring I18N Múltiples lenguajes

Las aplicaciones basadas en Spring Framework soportan I18N, este término en una forma abreviada de la palabra (internationalization) ya que entre la letra inicial I y la letra final N existen 18 caracteres, I18N no es más que la capacidad que tiene una aplicación de poder manejarse en distintos idiomas, es decir podremos mostrar los textos o mensajes de la aplicación en diversos idiomas.

Normalmente los mensajes que mostraremos en la aplicación los almacenamos en un archivo de propiedades, un archivo por cada idioma disponible en nuestra aplicación, el nombre de este archivo debe tener la siguiente forma: messages_<language_code>_<country_code>.properties donde <language_code> debe ser el código de lenguaje y <country_code> el código de región, algunas veces bastará con el primero.

Veamos algunos ejemplos:

mensajes_es_ES.properties //Español de España
mensajes_es_AR.properties //Español de Argentina
mensajes_es.properties //Español genérico
mensajes_en.properties //Inglés

Para almacenar los textos en español e ingles vamos crear dos archivos, message_es.properties para español y message_en.properties para la versión en ingles, el contenido de los archivo debe estar en formato clave/valor.

message_en.properties

title: Hello I18N with Spring
text: This is a text

message_es.properties

title: Hola I18N con Spring
text: Esto es un texto

Para utilizar esta funcionalidad debemos agregar un bean de tipo ResourceBundleMessageSource, en la configuración XML esto lo hacemos de este modo:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
     
    <bean id="messageSource"
          class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n/message"/>
    </bean>
    
</beans>

Debemos establecer la propiedad basename usada para indicar la ubicación y el nombre base de los archivos, en nuestro caso el nombre base es message.

El código equivalente para la configuración desde código Java:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
public class SpringConfiguration {

    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource rbms = new ResourceBundleMessageSource();
        rbms.setBasename("i18n/message");
        return rbms;
    }
    
}

Así se queda la estructura de nuestro proyecto i18n.

spring i18n

ApplicationContext implementa MessageSource por lo que podemos acceder a los mensajes i18n a través del método getMessage().

AbstractApplicationContext ctx 
        = new AnnotationConfigApplicationContext(SpringConfiguration.class);

String msg_en = ctx.getMessage("title", null, Locale.ENGLISH);
String msg_es = ctx.getMessage("title", null, new Locale("es"));

System.out.println("English: " + msg_en);
System.out.println("Español: " + msg_es);

ctx.close();

En el método getMessage() debemos indicar primero la clave del texto que deseamos obtener, el segundo parámetro lo dejamos nulo por ahora, al final indicamos el idioma, a través de la enumeración Locale seleccionamos el lenguaje, no todos los lenguajes están disponibles mediante la enumeración por lo que en ocasiones se necesario indicarla por el constructor.

Es posible utilizar mensajes con parámetros modificables, ejemplo. 

saluda: Mi nombre es {0} y mi apellido {1}.

Los parámetros los indicamos con "{0}", el numero dentro indica el índice del parámetro, para pasar estos parámetros usamos un Object[] con las lista de los mismos.

System.out.println(ctx.getMessage(
        "saluda", 
        new Object[] { "carmelo", "marin" },
        new Locale("es")));

Esto imprime:

i18n spring

Es posible obtener el MessageSource por ejemplo inyectándolo con la anotación @Autowired de este modo podemos usar sin el ApplicationContext, por ejemplo:

@Service
public class SaludaServiceImpl implements SaludaService {

    @Autowired
    private MessageSource ms;

    @Override
    public void saluda(String name, String lastname) {
        System.out.println(
                ms.getMessage("saluda",
                        new Object[]{name, lastname},
                        Locale.ENGLISH));
    }

}

Lo usaríamos del siguiente modo:

SaludaService ss = ctx.getBean(SaludaService.class);
ss.saluda("carmelo", "marin");

El resultado será el que vemos en la imagen de arriba, salvo que el mensaje estará en ingles.

Con lo aprendido podemos crear una aplicación con soporte para varios idiomas, en próximos tutoriales diseñaremos una aplicación web con soporte como mínimo para dos idiomas.

Comentarios

Entradas populares de este blog

Conectar SQL Server con Java

Conociendo la clase cv::Mat de OpenCV

Entrenar OpenCV en Detección de Objetos

Procesamiento de imágenes en OpenCV

Acceso a la webcam con OpenCV