jueves, enero 15, 2009

Obtener el multiidioma desde la base de datos con Apache Struts

Lo habitual a la hora de trabajar con Struts es tener uno o más ficheros .properties donde almacenamos las parejas "key" y "texto" en cada idioma que queremos que la aplicación soporte. Estos ficheros se definen en el fichero struts-config.xml de una forma parecida a esta:


<message-resources parameter="com.abel.presentation.resources.ApplicationResources" null="false"/>

En el package com/abel/presentation/resources pondremos un fichero para cada idioma como por ejemplo: ApplicationResources_en_EN.properties, ApplicationResources_fr_FR.properties o ApplicationResources.properties (este último será el por defecto). Pero en algunas ocasiones podemos tener estos textos a mostrar en la aplicación almacenados en tablas de la base de datos.
Para casos como este, en lo que nos salimos de lo "por defecto", Struts también nos facilita las cosas pudiendo cambiar la fuente de datos.
Nos definiremos una nueva clase Factoría que extenderá de MessageResourcesFactory:


package com.abel.strutsextensions;

public class FoxResourcesFactory extends MessageResourcesFactory {

public MessageResources createResources(String config) {
return new FoxMessageResources(this, config, this.returnNull);
}

}

Modificaremos el struts-config.xml para informar a Struts de la nueva fuente de los mensajes:


<message-resources parameter="database.ApplicationResources" factory="com.abel.strutsextensions.FoxResourcesFactory" null="false"/>

Y para terminar, la miga del asunto, la clase que devolverá la información. Voy a omitir el explicar como el DAO devuelve el Map donde se almacenan la información; este Map se guardará en una caché, que podremos configurar si nos interesa que se refresque o dejarla sin caducidad. El código tiene comentarios por lo que es autoexplicativo:


public final class FoxMessageResources extends MessageResources {

public static final String FOX_DEFAULT_LOCALE = "en_EN";
private static Map<String,String> _applicationLocales;

protected FoxMessageResources(MessageResourcesFactory factory, String config, boolean returnNull) {
super(factory, config, returnNull);
if (_applicationLocales == null) {
// consigo las diferentes locales con las que vamos a trabajar
_applicationLocales = PropertyGeneratorDAO.getApplicationLocales();
}
}

private String getLocaleString(Locale locale) {
String localeString;
if (locale == null) {
// si no nos pasan una locale usamos la por defecto
localeString = FOX_DEFAULT_LOCALE;
} else {
localeString = locale.toString();
if (_applicationLocales.get(localeString) == null) {
// si la locale que nos llega no está entre las válidas usamos la por defecto
localeString = FOX_DEFAULT_LOCALE;
}
}
return localeString;
}

private Map<String,String> getLocaleMessages(String localeString) {
// cargamos desde la caché
Map<String,String> messages = (Map<String,String>) FoxCacheManager.getInstance().getFromCache(localeString);
if (messages == null) {
// si la caché no contiene los datos se cargan desde la base de datos
messages = PropertyGeneratorDAO.loadPropertyFile(localeString);
FoxCacheManager.getInstance().addToCache(localeString, messages);
}
return messages;
}

@Override
public String getMessage(final Locale locale, final String key) {
String localeString = getLocaleString(locale);
Map<String,String> messagesForALocale = getLocaleMessages(localeString);
String txt = (messagesForALocale != null) ? messagesForALocale.get(key) : null;
if (txt == null) {
// ¡Esta linea es muy importante, Struts usa de forma interna llamadas a este método y si no existe la key se debe retornar con este formato!
return ("???" + key + "???");
} else {
return txt;
}
}

}

Ahora ya podemos usar igual que siempre la tag-lib de Struts <bean:message> y tendremos la aplicación traducida desde la base de datos

No hay comentarios:

Publicar un comentario