JSF Resource Bundles

El uso de resource bundles puede ser una herramienta poderosa para implementar la internacionalización (i18n) en aplicaciones JSF 2.0. Los resource bundles permiten a los desarrolladores almacenar mensajes y títulos localizados en un archivo separado, al que se puede acceder fácilmente en páginas JSF. La configuración de resource bundles en JSF es bastante sencilla y, una vez configurados, los desarrolladores pueden acceder a los mensajes y títulos localizados con facilidad.

En este artículo, analizaremos el uso y la configuración de los resource bundles en JSF 2.0 y cómo se pueden usar para hacer que una aplicación JSF sea accesible para usuarios de todo el mundo.

Configurar el resource bundle

Es deseable evitar escribir los mensajes ubicados en las vistas directamente en las páginas. Un resource bundle consta de un archivo de texto con extensión .properties conteniendo los mensajes de la aplicación en forma de pares clave/valor, y facilitan en mantenimiento de la aplicación al mantener los mensajes en un solo lugar. El archivo properties debe estar ubicado en la carpeta resources del proyecto. En nuestro ejemplo el archivo es el que sigue:

messages.properties

msg1=Primer mensaje
msg2.subitem=Segundo mensaje
msg3.escape=<table border=1><tr><td>CODIGO</td><td>DESCRIPCION</td></tr><tr><td>01</td><td>JAVA</td></tr></table>
msg4.param=Item ingresado: {0}

El siguiente paso es declarar el resource bundle en la aplicación. Si se necesita que sea accesible por cualquier página de la aplicación se debe declarar en el archivo faces-config.xml como se muestra a continuación:

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">

    <application>
		<resource-bundle>
			<base-name>messages</base-name>
			<var>bundle</var>
		</resource-bundle>        
	</application>
</faces-config>

En el tag <base-name> se declara el nombre del archivo y en el tag <var> se declara el nombre de la variable para hacer referencia al bundle desde las páginas.

En JSF también es posible hacer la declaración de los resource bundles para que sean accesibles localmente a una página agregando el siguiente tag a la vista correspondiente:

<f:loadBundle basename="messages" var="bundle" />

Acceder al resource bundle desde la página

El código de la página que accede a los mensajes declarados en el properties es el siguiente:

home.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
		xmlns:h="http://xmlns.jcp.org/jsf/html"
		xmlns:f="http://java.sun.com/jsf/core"
		xmlns:jsf="http://xmlns.jcp.org/jsf">
	<head>
		<title>Ejemplo Resource Bundle</title>
	</head>
	<body>
		<table>
			<tr>
				<td><h:outputText value="#{bundle.msg1}"></h:outputText></td>
			</tr>
			<tr>
				<td><h:outputText value="#{bundle['msg2.subitem']}"></h:outputText></td>
			</tr>
			<tr>
				<td><h:outputText value="-> Escape TRUE: #{bundle['msg3.escape']}"></h:outputText></td>
			</tr>
			<tr>
				<td><h:outputText value="-> Escape FALSE: #{bundle['msg3.escape']}" escape="false"></h:outputText></td>
			</tr>
			<tr>
				<td>
					<h:outputFormat value="#{bundle['msg4.param']}">
						<f:param value="TECLADO" />
					</h:outputFormat>
				</td>
			</tr>
		</table>
	</body>
</html>

El primer caso muestra la forma de acceso a un mensaje con una key simple:

El segundo caso muestra que cuando la key contiene puntos en la invocacion debe ir entre corchetes:

En el tercer caso se muestra un mensaje con formato html. Es posible indicarle al componente si el mensaje se debe visualizar como texto plano con el atributo escape=”true” (valor por defecto) o si visualizarlo con formato, con escape=”false”:

El último caso muestra como parametrizar los mensajes mediante el elemento <f:param>:

Internacionalización con Resource Bundles

A continuación un ejemplo de cómo implementar la internacionalización mediante archivos properties. Se agregarán al proyecto los siguientes archivos properties en la siguiente ubicación:

i18n_en.properties

msg.saludo=Welcome!

i18n_es.properties

msg.saludo=Bienvenido!

i18n.properties

msg.saludo=Welcome!

En la página importamos el bundle localmente con la etiqueta f:loadBundle. En el evento change del elemento h:selectOneRadio invoca al método changeLocale() del bean.

El atributo render=”ajaxText indica que se debe refrescar el h:outputText al finalizar la invocación vía AJAX.

i18n-example.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
		xmlns:h="http://xmlns.jcp.org/jsf/html"
		xmlns:f="http://java.sun.com/jsf/core"
		xmlns:jsf="http://xmlns.jcp.org/jsf">
	<f:loadBundle basename="i18n.i18n" var="i18nbundle" />
	
	<h:head>
		<title>Ejemplo i18n</title>
	</h:head>
	<h:body>
		<h:form>
			<table>
				<tr>
					<td>
						<h:outputText id="ajaxText" value="#{i18nbundle['msg.saludo']}" />
					</td>
				</tr>
				<tr>
					<td>
						<h:selectOneRadio id="selectLocale" value="#{internationalizationBean.locale}">
							<f:selectItem itemValue="es" itemLabel="Espanol" />
							<f:selectItem itemValue="en" itemLabel="Ingles" />
							<f:ajax event="change" render="ajaxText" listener="#{internationalizationBean.changeLocale()}" />
						</h:selectOneRadio>
					</td>
				</tr>
			</table>
		</h:form>
	</h:body>
</html>

Finalmente, el método changeLocale() accede al contexto para asignar el Locale seleccionado.

InternationalizationBean.java

import java.io.Serializable;
import java.util.Locale;

import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;

@Named(value = "internationalizationBean")
@SessionScoped
public class InternationalizationBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private String locale;


	public String changeLocale() {
		System.out.println("InternationalizationBean.changeLocal() : ENTRADA");
		FacesContext context = FacesContext.getCurrentInstance();
		context.getViewRoot().setLocale(new Locale(this.locale));
		return locale;
	}
	
	
	public String getLocale() {
		return locale;
	}

	public void setLocale(String locale) {
		this.locale = locale;
	}

}

Conclusión

El uso y la configuración de resource bundles en JSF pueden proporcionar una excelente manera de localizar una aplicación y hacerla accesible a usuarios de todo el mundo. El uso de resource bundles para almacenar subtítulos y mensajes localizados es una manera fácil y efectiva de hacer que las aplicaciones JSF soporten internacionalización. Con la ayuda de los resource bundles, los desarrolladores pueden concentrarse en crear la mejor experiencia de usuario posible para su aplicación en lugar de preocuparse por problemas específicos del idioma.


Te puede interesar:

JSF Managed Beans

En JSF, los Managed Beans se pueden configurar de varias maneras, como anotaciones, configuración XML o mediante programación.

Seguir leyendo →

Arquitectura y Ciclo de Vida JSF

Cómo funciona el ciclo de vida de una aplicación JSF. En el artículo relacionado se cubre el manejo de eventos.

Seguir leyendo →