jueves, 3 de mayo de 2012

Internacionalización JSF 2.0

Existe varios ejemplos de internacionalización de jsf 2.0, el inconveniente de estos ejemplos sencillos es que nos dejan con un problema ya que en la mayoría de ellos solo nos muestran como hacerlo por un solo request, hay algunas formas de modificar esto, la que más me agrado es la que voy poner aqui, es sencilla y no necesitan modificar sus archivos xhtml.

Vamos a utilizar un PhaseListener de jsf 2, El codigo es el siguiente

package org.nl.example;
import java.util.Locale;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

public class LifeCycleListener implements PhaseListener {

public PhaseId getPhaseId() {
    return PhaseId.ANY_PHASE;
}

public void beforePhase(PhaseEvent event) {
    System.out.println("START PHASE " + event.getPhaseId());
    FacesContext context;

    if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
        context = event.getFacesContext();
        Application application = context.getApplication();
        ValueExpression ve = application.getExpressionFactory()
                                        .createValueExpression(context.getELContext(),
                                                #{localeManagedBean.locale}", Locale.class);
        try {
             System.out.println("setting locale in phase listener");
             Locale localeToSet = (Locale) ve.getValue(context.getELContext());
             context.getViewRoot().setLocale(localeToSet);

        } catch (Exception e) {
             System.out.println("error in getting locale");
        }
    }
}

public void afterPhase(PhaseEvent event) {
    System.out.println("END PHASE " + event.getPhaseId());
}
}

El PhaseListener debe ser colocado en faces-config.xml asi:


<lifecycle>
    <phase-listener>org.nl.example.LifeCycleListener</phase-listener>
</lifecycle>


El PhaseListener uunicamente le importa la fase de RENDER_RESPONSE que es la fase donde faces crea el contenido de respuesta, y ahi obtiene un locale a partir de un managebean, en este caso el managebean es localeManageBean el cual su alcance es de sesion, este a su vez contienen una propiedad de tipo Locale, la cual tiene almacenado la locale de nuestro idioma, tambie podemos actualizarla con una nueva Locale correspondiente al nuevo idioma en el que se presenten las paginas, el codigo es mas o menos asi:

package org.nl.example;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ValueChangeEvent;

@ManagedBean(name = "localeManagedBean")
@SessionScoped
public class LocaleManagedBean implements Serializable {

 private static final long serialVersionUID = 1L;

 private String localeCode;
 private Locale locale;

 private static Map countries;
 static {
  countries = new LinkedHashMap();
  countries.put("English", Locale.ENGLISH); // label, value
  countries.put("Spanish", new Locale("es"));
 }

        public LocaleManagedBean() {
  super();
  locale = (Locale) countries.get("Spanish");
 }

 public Map getCountriesInMap() {
  return countries;
 }

 public String getLocaleCode() {
  return localeCode;
 }

 public void setLocaleCode(String localeCode) {
  this.localeCode = localeCode;
 }

 public Locale getLocale() {
  return locale;
 }

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

 public void countryLocaleCodeChanged(ValueChangeEvent e) {

  String newLocaleValue = e.getNewValue().toString();

  // loop country map to compare the locale code
  for (Map.Entry entry : countries.entrySet()) {

   if (entry.getValue().toString().equals(newLocaleValue)) {
    locale = (Locale) entry.getValue();
    break;
   }
  }
 }

}

Este MeanageBean puede ser utilizado para colocar el nuevo idioma con el metodo countryLocaleCodeChange, no estoy seguro si este método debe retornar a una pagina, dado que en mi caso yo obtengo la Locale a travez de una cookie que fue colocada por spring mvc, espero me comenten si tienen que hacer alguna adecuación.

Espero les sirva les dejo algunas ligas que me sirvieron

http://www.mkyong.com/jsf2/jsf-2-internationalization-example/

http://www.java.net/node/703940