Internacionalización de JSP con JSTL

De ChuWiki

Cuando hacemos una página JSP, podemos querer que los textos que ve el usuario salgan en el idioma del usuario. Lo ideal sería que los textos salieran en un idioma u otro en función del idioma del navegador. Opcionalmente, el usuario quizás debería poder elegir idioma si el navegador no ha dado correctamente con el suyo.

Afortunadamente, la librería JSTL (Java Standard Tag Lib) nos facilita mucho esta tarea.


Instalación de JSTL[editar]

Necesitamos, por supuesto, tener la librería JSTL instalada. Es sencillo, vamos a la página de descargas del proyecto y nos la bajamos. Necesitamos los dos jar jstl-api-1.2.jar y jstl-impl-1.2.jar. Una vez descargados, debemos poner ambos jar en el directorio WEB-INF/lib de nuestro proyecto JSP.

En nuestra página jsp, debemos incluir dichas tag libs. En concreto, el core y la de internacionalización fmt.

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>


Ficheros bundle con los textos[editar]

Los textos que verá el usuario en la página no podemos escribirlos directamente en la página JSP. En su lugar, debemos crear tantos ficheros de propiedades (.properties) como lenguajes distintos queramos. El nombre de estos ficheros puede ser cualquier nombre, seguido de _xx_YY.properties, donde xx es el nombre el idioma (es para español, en para inglés, fr para francés, ...) e YY el país concreto (es_ES para español de España, es_AR para español de Argentina, es_MX para México, ...). Dentro de estos ficheros debemos poner una clave para cada texto que queremos visualizar y la clave debe ser la misma en todos los ficheros. Por ejemplo, si hay un sitio en el JSP donde se va a saludar, los ficheros pueden contener esto

   # fichero_es_ES.properties
   saludo=Hola

   # fichero_en_UK.properties
   saludo=Hello

   # fichero_fr_FR.properties
   saludo=allo

La clave para el texto de saludo es "saludo" en todos los ficheros y será esta clave la que usaremos en el fichero JSP para poner el texto.

Un detalle con estos ficheros. Si el idioma del navegador es español de españa, se buscarán las claves y textos en fichero_es_ES.properties. Si alguna clave no se encuentra o no existe el fichero, entonces se buscará esa clave en fichero_es.properties (sin las letras del país). Y si aún así no se encuentra, entonces se buscará en fichero.properties. Esto nos permite poner en fichero.properties todas las claves en un idioma por defecto (normalmente inglés) y luego ir poniendo en fichero_es.properties todos los textos en español estándar y finalmente, en fichero_es_AR.properties sólo aquellos textos que en Argentina se digan de distinta forma.

Finalmente, estos ficheros deben ponerse todos juntos en algún sitio del classpath de la aplicación web. Por ejemplo, podemos poner dentro del classpath un directorio bundle y meter ahí los ficheros

WEB-INF/classes/bundle/fichero.properties
WEB-INF/classes/bundle/fichero_es.properties
WEB-INF/classes/bundle/fichero_es_AR.properties
WEB-INF/classes/bundle/fichero_fr.properties


La etiqueta fmt:message en el JSP[editar]

Ahora, en la página JSP, primero tenemos que indicar dónde están esos ficheros. Para ello usamos la etiqueta de JSTL fmt:setBundle

fmt:setBundle basename="bundle.fichero" />

donde indicamos el directorio dentro del classpath donde hemos puesto los ficheros de properties con los textos. Sólo ponemos la primera parte del nombre, sin poner la parte _xx_YY.properties, en nuestro caso, sólo ponemos "fichero"

Y ahora sólo tenemos que usar la etiqueta fmt:message para poner los textos. Para escribir el saludo pondremos

<p>El saludo en el idioma del navegador : <fmt:message key="idioma"/></p>

que nos mostrara "El saludo en el idioma del navegador : Hello" si el navegador es inglés, o "El saludo en el idioma del navegador : Hola" si es español.

Por supuesto, lo de "El saludo en el idioma del navegador : " debería estar también con una clave en los ficheros de properties en distintos idiomas, pero así queda un poco más claro el ejemplo al mostar parte del párrafo en el html de una forma "normal".


Elegir el idioma[editar]

Podemos, por ejemplo, a petición del usuario, poner el idioma que él nos pida en vez de el que indique el navegador. Para ello debemos usar la etiqueta fmt:setLocale para indicar el idioma que queremos

<fmt:setLocale value="en" scope="session"/>

o si queremos elegir también el país concreto

<fmt:setLocale value="en_UK" scope="session"/>

hará que el JSP se muestre en inglés independiemente del idioma del navegador. El scope="session" hará que ese sea el idioma elegido para toda la sesión, por lo que cualquier otra página jsp que visualice el usuario de nuestra aplicación la verá en inglés. Si no ponemos el scope="session", por defecto es scope="page", por lo que sólo se verá en inglés esa página jsp. Las demás páginas jsp de nuestra aplicación se seguirían viendo en el idioma del navegador.

Un detalle nada más que puede traernos de cabeza. Es importante fijar el locale fmt:setLocale antes de indicar la ubicación de los ficheros con fmt:setBundle, ya que el fichero se elige en el momento de fijar el bundle y para entonces ya tiene que estar elegido el idioma.

Un trozo de código como este en una página puede permitir elegir el idioma al usuario

<a href="texto.jsp?locale=en">ingles</a>
<a href="texto.jsp?locale=es">español</a>
<a href="texto.jsp?">auto</a>

son tres enlaces a texto.jsp y según el elegido, se le pasará un parámetro "locale" a la página texto.jsp. Allí, en texto.jsp, podemos poner algo como esto para usar la etiqueta fmt:setLocale y fijar el idioma

   <c:if test="${param.locale!=null}">
      <fmt:setLocale value="${param.locale}" />
   </c:if>
   <fmt:setBundle basename="bundle.fichero" />

de esta forma, si el parámetro es null es porque el usuario ha seleccionado idioma "auto"mático y se cogerá el del navegador. O si ha cogido uno de los otros enlaces, param.locale no será null y valdrá "en" o "es" según el elegido.


Obtener el idioma[editar]

Si hemos cambiado el idioma con fmt:setLocale con scope="session", afectará a todas las páginas que visitemos en la sesión. Es posible que desde otra página queramos saber qué idioma se ha elegido. Es fácil conseguirlo, pero no evidente. La forma sería esta

   <c:out value="${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}"/>

Y si lo hemos cambiado para la página (es el scope por defecto)

   <c:out value="${pageScope['javax.servlet.jsp.jstl.fmt.locale.page']}"/>