Internationalization in ICEfaces TutorialInternationalization is a common requirement of modern web applications, and is simple to achieve in JSF and ICEfaces. Supported languages can be specified and dynamically changed by page markup or from the backend. In addition JSF will automatically detect the locale of a client web browser and apply it if the project is configured properly. This tutorial assumes the reader has an understanding of JSF, ICEfaces, and Java i18n and creating and working with projects related to those technologies. The goal of this tutorial is to create a basic single page ICEfaces 2.0 project that supports English (en) and German (de) and has a few component labels that are internationalized. We will then create a basic locale switcher to let a user choose between the two languages.
Here is the entire list of steps worked through during this tutorial: Development Tools UsedThe following tools were used to create the project.
1. Make the internationalization Project
2. Add ICEfacesAdd the icefaces.jar to your project from the ICEfaces 2 bundle. This can be added to the project through a custom User Library or by putting it into internationalization/WEB-INF/lib/. The approach doesn't matter as long as the jar is included in the deployed war file. 3. Setup faces-config.xml LocalesOpen faces-config.xml and paste in the following application node: faces-config.xml application locales <application> <locale-config> <default-locale>en</default-locale> <supported-locale>de</supported-locale> </locale-config> <resource-bundle> <base-name> org.icefaces.tutorial.internationalization.resources.messages </base-name> <var>msgs</var> </resource-bundle> </application> This code performs two tasks related to internationalization. First we specify our default locale (English [en]) and our supported locale(s), in this case only German [de]. If we wanted to add more locales we could specify further supported-locale nodes. The second piece of code tells our application where the internationalized resource bundle is. The base-name points to a series of property files that we'll create in Step 4. The var is the name used to access the messages from our page markup. 4. Create Resource BundlesCreate two basic files in the package {org.icefaces.tutorials.internationalization.resources}}:
These property files were specified in faces-config.xml, and will use a key/value format. The key will be used in the page markup, and the value will be the associated label for the language specified in the filename. Paste the following key/value pairs into the messages_en.properties file: messages_en.properties Contents firstName=First Name lastName=Last Name As you can see when we reference "firstName" in the page markup, we will get the value "First Name" returned. Similary paste the German version of these values into the messages_de.properties file: messages_de.properties Contents firstName=Vorname lastName=Nachname 5. Create main.xhtmlNow we will create a simple page that will use the internationalized strings. Create a new page called main.xhtml and paste the code below: main.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://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <f:view locale="#{pageBean.currentLocale}"> <h:head> <title>Internationalization - Main</title> </h:head> <h:body> <h:form> <h:panelGrid columns="2"> <h:selectOneMenu value="#{pageBean.dropdownItem}" valueChangeListener="#{pageBean.localeChanged}"> <f:selectItems value="#{pageBean.availableLocales}"/> </h:selectOneMenu> <h:commandButton value="Change Locale"/> <h:outputLabel for="firstName" value="#{msgs.firstName}"/> <h:inputText id="firstName"/> <h:outputLabel for="lastName" value="#{msgs.lastName}"/> <h:inputText id="lastName"/> </h:panelGrid> </h:form> </h:body> </f:view> </html> The <h:selectOneMenu> will be managed through our upcoming backing bean. The component will be used to allow users to dynamically switch their locale for the entire app. Notice that the <h:outputLabel value attributes are internationalized. We use the var msgs that was previously declared in faces-config.xml, and a key that corresponds to the resource bundle. So #{msgs.firstName} will correspond to "First Name" in the English locale, or "Vorname" in the German locale. We manually specify the current locale in the <f:view> container, via the locale attribute. This allows us to modify that variable and have it apply properly to the entire page. 6. Create PageBean.javaCreate a new Java class file called PageBean in the package org.icefaces.tutorial.internationalization.beans and paste the code below: PageBean.java package org.icefaces.tutorial.internationalization.beans; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.context.FacesContext; import javax.faces.event.ValueChangeEvent; import javax.faces.model.SelectItem; @ManagedBean(name="pageBean") @SessionScoped public class PageBean implements Serializable { private List<SelectItem> availableLocales; private Locale currentLocale; private String dropdownItem; public PageBean() { setCurrentLocale(FacesContext.getCurrentInstance().getViewRoot().getLocale()); dropdownItem = currentLocale.getLanguage(); } private void generateAvailableLocales() { availableLocales = new ArrayList<SelectItem>(0); // Add the default locale availableLocales.add (makeLocaleItem(FacesContext.getCurrentInstance().getApplication().getDefaultLocale())); // Add any other supported locales for (Iterator<Locale> iter = FacesContext.getCurrentInstance().getApplication().getSupportedLocales(); iter.hasNext();) { availableLocales.add(makeLocaleItem(iter.next())); } } private SelectItem makeLocaleItem(Locale toWrap) { if (toWrap != null) { return new SelectItem(toWrap.getLanguage(), toWrap.getDisplayName()); } return null; } public List<SelectItem> getAvailableLocales() { if (availableLocales == null) { generateAvailableLocales(); } return availableLocales; } public void setAvailableLocales(List<SelectItem> availableLocales) { this.availableLocales = availableLocales; } public Locale getCurrentLocale() { return currentLocale; } public void setCurrentLocale(Locale currentLocale) { this.currentLocale = currentLocale; } public String getDropdownItem() { return dropdownItem; } public void setDropdownItem(String dropdownItem) { this.dropdownItem = dropdownItem; } public void applyLocale(Locale toApply) { System.out.println("Apply Locale: " + toApply.getDisplayName() + " (" + toApply.getLanguage() + ")"); setCurrentLocale(toApply); FacesContext.getCurrentInstance().getViewRoot().setLocale(toApply); } public void localeChanged(ValueChangeEvent event) { if (event.getNewValue() != null) { applyLocale(new Locale(event.getNewValue().toString())); } } } The bean code is fairly long, but has a few important concepts to learn. The currentLocale variable is what we use to track what java.util.Locale JSF detected or the user has selected. The initial status is set through the constructor by getting the current locale from the ViewRoot (which corresponds to <f:view> in the page), using the code: Get Current Locale from ViewRoot FacesContext.getCurrentInstance().getViewRoot().getLocale() The availableLocales list is used to populate the <h:selectOneMenu> on the page. Inside the generateAvailableLocales method we use FacesContext to retrieve the default locale (from the <default-locale> value in faces-config.xml) and all supported locales (from the <supported-locale value(s) in facets-config.xml). Then we wrap those values in javax.faces.model.SelectItem objects so the page can understand them and use them properly in the <h:selectOneMenu> component. When the locale is changed via the page level dropdown, we use the localeChanged value change listener method to apply the new locale to the page. Applying the locale is achieved through the ViewRoot, as such: Changing the Locale via ViewRoot FacesContext.getCurrentInstance().getViewRoot().setLocale(localeToSet); 7. Deploy and Test the ApplicationNow that all necessary files have been created, build and deploy the web application internationalization and visit it in a web browser. The page will look similar to the following: Selecting a different Locale and clicking the "Change Locale" button will modify the two field labels, based on the contents of our messages.properties resource bundles. If you change your web browser locale to English (en) or German (de), restart the browser, and revisit the page it will automatically detect and apply the proper locale. For example, adding a locale in Firefox: As you can see internationalization is both easy to setup and powerful to use. Resource bundles can also be access from the bean level, and default JSF error messages can be overridden, but that is beyond the scope of this tutorial. Tutorial Source Code Downloads
|
Internationalization in ICEfaces
© Copyright 2021 ICEsoft Technologies Canada Corp.