Wednesday, March 10, 2010

ADF Faces RC : Supplement on How to Configure Pages for an End User to Specify Locale at Runtime

I am completely lost when I read section 21.4 (Configuring Pages for an End User to Specify Locale at Runtime) of the Web User Interface Developer's Guide. Correct me if I am wrong, but it seems that, that section is still in draft mode as of this blog-posting, and that motivated me to write this post to supplement it. This post references some other sections of the guide to as not recreate instructions here. This post assumes that you already know how to configure resource bundles and how to bind the component labels to those resource bundles (also available on the guide).

We can configure our application so that end users can specify the preferred locale at runtime without them going through the browser settings. To support this we need to do the following:

  1. Register the locales and resource bundles used in your application in the faces-config.xml file.
  2. Add a String locale attribute to a session scope managed bean that holds relevant information for the user session.
  3. Create a selectOneChoice that list the supported locales from step 1 above.
  4. Set the locale attribute of the <f:view> tag of our pages to the attribute the we created.

Register the locales and resource bundles used in your application in the faces-config.xml file.

Please see section 21.3.3 (How to Register Locales and Resource Bundles in Your Application) of the Web User Interface Developer's Guide.


Add a String locale attribute to a session scope managed bean that holds relevant information for the user session

We can add the locale attribute to an existing session scope managed bean that holds other user session information or create a new one if nothing is available. We use "session scope" here so that the locale information is applied to the whole session instead of the user setting the local on every page. Below is a sample managed bean class:

package soadev.view.managed;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
public class UserSession implements Serializable {
    private String locale;
  
    public void setLocale(String locale) {
        this.locale = locale;
    }

    public String getLocale() {
        if (locale == null) {
            locale = FacesContext.getCurrentInstance().getViewRoot()
                .getLocale().toString();
        }
        return locale;
    }

    //gets all the supported locals plus the default locale defined in the faces-config.xml
    //and add it to the list of selectItems
    public List<SelectItem> getLocales() {
        List<SelectItem> items = new ArrayList<SelectItem>();
        Application application = FacesContext.getCurrentInstance()
                            .getApplication();
        Iterator supportedLocales = application.getSupportedLocales();
        while (supportedLocales.hasNext()) {
            Locale locale = (Locale) supportedLocales.next();
            items.add(new SelectItem(locale.toString(), locale.getDisplayName(locale)));
        }
        Locale defaultLocale = application.getDefaultLocale();
        items.add(new SelectItem(defaultLocale.toString(), defaultLocale.getDisplayName(defaultLocale)));
        return items;
    }
}

Create a selectOneChoice that list the supported locales from step 1 above.

Add somewhere in the page or in a user preferrence popup a selectOneChoice like below:
<af:selectOneChoice label="Select Locale" id="pt_soc2"
                     value="#{userSession.locale}"
                     autoSubmit="true">
  <f:selectItems id="si10" value="#{userSession.locales}"/>
</af:selectOneChoice>

Set the locale attribute of the <f:view> tag of our pages to the attribute the we created.

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view locale="#{userSession.locale}">

Caveat: To simplify the illustration in this post, we added our locale attribute directly to the session scope managed bean, but in practice we usually create a sort of UserPrefence class to hold the user preferred locale plus other preferences like adf skin, rowBandingIntervals, and etc... I just thought that maybe creating a post on how to implement user preference maybe worth. Is it?


Cheers!

2 comments:

  1. I tried your solution, to my ADF Application...
    First of all, the listbox does not contain a method to set the language...
    Second, how can I create a default value in the locale session variable that will take this value before the first page renders...
    I am asking because I wish to create a button with image flags, the value of which will be determined according to this session variable.
    Regards,
    Maira

    ReplyDelete
  2. Hi Maria,

    On First Issue:
    You don't need any other methods but the value attribute of your list box should be set to something like value="#{userSession.locale}" as describe above. Be sure to set autosubmit='true' so that when the user selects another value, the model in the server will be set immediately.

    On Second Issue:
    You could modify the getLocale() method accordingly to return the local you wanted. You could already find all the necessary ideas on the above codes.

    If you wanted more clarification, feel free. :-)

    Regards,
    Pino

    ReplyDelete