Internationalization with Wicket

In last article we discussed  how to localize mark-up files in wicket. It would be very annoying having 14 different html files if we have 14 different languages that we should support for that particular page/component.

In this article we are going to learn how to use resource bundles instead of localizing mark-up files. Imagine your application contains so many texts that need i18n. In this situation it is very difficult to put a wicket:id on all of these, and then add a Label to each.

Wicket provides a simple way to provide i18n support for your applications.

You can use the wicket:message element in the HTML file directly

<wicket:message key=”staticMessage” >Message</wicket:message>

The property files are

DisplayPage.properties:

staticMessage= Message

For Germany

DisplayPage_de.properties:

staticMessage= Nachricht

For Netherland

DisplayPage_nl.properties:

staticMessage= Bericht

The key “staticMessage” is used to lookup the message in the property files. The default text Message is used when the message could not be found. Wicket framework provides getString(String key) method in Component class which search for a property by given key in resource bundles.

Localized pages and panel can have their own bundle files having as base name the class name of the related component and placed in the same package.

So in our example we have DisplayPage.java class. We have created our resource bundles based on name of this class for. E.g DisplayPage_de.properties. Note all these resource files are located in same place where out DisplayPage.java class resides.

Alternatively if you want to use text from properties file in wicket components like labels etc. simply use getString(“key”) method provided by Component class in wicket.

How lookup algorithm works:

Wicket will search all resource files with the names equal to the components in your component hierarchy, starting from application level at top to component defaults as a last place to look.

So when Wickets wants to look up a message used in MyPanel, where MyPanel is contained within MyPage, and the application is called MyApplication,

Wicket will look in:

  1. MyApplication_locale.properties, …, and then MyApplication.properties (..)
  2. MyPage_locale.properties, …, and then MyPage.properties
  3. MyPanel_locale.properties, …, and then MyPanel.properties

And what if it has same key in all these hierarchy properties files?

The lookup algorithm gives priority to the bundles of the containers (parents) of the component that is requesting a localized resource. The more a container is higher in the hierarchy, the bigger is its priority over the other components. In other words properties inside the resource bundle of a page will have the priority over the properties with the same key defined in the bundles of children components.

So for example in our sample code if we have HomePage which is container for DisplayPage, have a property with same key i.e. staticMessage with some other value in its resource bundle then it will be displayed instead of property in DisplayPage resource bundles. HomePage.properties staticMessage= Title Message.

So here text “Title Message” will be displayed instead of DisplayPage.

Also note that for DisplayPage component DisplayPage.properties is a default resource bundle.

So for e.g. your locale is set to “de” and there is no resource bundle for that locale (DisplayPage_de.properties is missing) then lookup algorithm will fall back to default resource bundle in this case DisplayPage.properties

To display languages like Chinese, Japanese etc, which need UTF-8 encoding you need to just append resource bundles with .utf8.properties extension.

Finally how to change locale?

To manually switch the locale in wicket:

Session.get().setLocale(new Locale(Locale.GERMAN));

Isn’t it pretty easy to i18n wicket applications. 🙂

A complete source code for sample example could be found here.

Localizing markup files in apache wicket

In this article we are going to see how we can localize markup files in wicket with an example.

We will be using DropDownChoice from previous article “Customizing display of choice in apache wicket”.

We need to create different markup files for different locale settings. All files have following format for naming.

YourFileName_<language code>[ <COUNTRY_CODE> ].html

Note <COUNTRY_CODE> could be optional.

So here is an example for markup file for displaying content in Chinese language.

LocaleSpecificPanel_zh_CN.html

<html xmlns:wicket=http://wicket.apache.org&#8221;S>

<head>

<meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”/>

<title>TestForm</title>

<link rel=“stylesheet” type=“text/css” href=“style.css”/>

</head>

<body>

<wicket:panel>

歡迎來到中國

</wicket:panel>

</body>

</html>

In similar way we have to create markup files containing text in that particular language.

When the current locale is set to country China(language code zh_CN), markup file LocaleSpecificPanel_zh_CN.html will be used in place of the default one.

Complete source code for above example could be found here.

In next article we will see how to internationalization works in wicket. This time we will create separate resource bundles (.properties) files instead of markup files.

Customizing display of choice in apache wicket.

Many times we come across a requirement where we need to bind a key-value pair to a Drop Down component. i. e. we need to customize dropdown choice to show some display values and upon selection of that value we need to use key (some other value) for some business logic.

Let’s see how we can bind a key-value structure i.e. HashMap to a DropDownChoice component in wicket.

In this example we are going to bind a key value pair for Locale-ID and Country with DropDownChoice. i.e. we are going to display different countries in drop down and based on selection of country we will set Locale.

So first we will create a HashMap for holding key-value pairs of locale-id and country.

Map<String, String> localeMapTemp = new HashMap<String, String>();

localeMapTemp.put(“en_US”, “United States”);

localeMapTemp.put(“de_DE”, “Germany”);

localeMapTemp.put(“nl_NL”, “Netherlands”);

localeMapTemp.put(“zh_CN”, “China”);

Now we will create a helper class which will hold the above key-value pairs for the DropDownChoice.

public class SelectOption implements Serializable {

/**

*

*/

private static final long serialVersionUID = 1L;

private String key = null;

private String value = null;

public SelectOption(String key, String value) {

super();

this.key = key;

this.value = value;

}

public String getKey() {

return key;

}

public void setKey(String key) {

this.key = key;

}

public String getValue() {

return value;

}

public void setValue(String value) {

this.value = value;

}

}

We need to create a DropDownChoice object.

DropDownChoice<SelectOption> localeChoice = new DropDownChoice<SelectOption>(“dropDwonChoice”,

new PropertyModel<SelectOption>(localeModel, “selectedLocale”),

getLocaleList(),

new ChoiceRenderer<SelectOption>(“value”, “key”)){

/**

*

*/

private static final long serialVersionUID = 1L;

@Override

protected boolean wantOnSelectionChangedNotifications() {

return true;

}

@Override

protected void onSelectionChanged(Object newSelection) {

selectedLocale = ((SelectOption)newSelection).getKey();

super.onSelectionChanged(newSelection);

}

};

Now let’s understand all attributes of DropDownChoice constructor in above code snippet.

  1. First argument is id of choice element in html markup.

<select wicket:id=“dropDwonChoice”>

<option value=“en”>English</option>

<option value=“de”>German</option>

</select>

  1. Second argument i.e. new PropertyModel<Object>(localeModel, “selectedLocale”), in above code represents model object SelectOption helper class. Model class for your page in which drop down is added must use SelectOption.
  1. Third argument returned by getLocaleList() a list of SelectOption objects.

Note that the type of object returned by the model in second argument and the type of objects in the list in third argument must be the same, in this case SelectOption.

  1. And last argument is The ChoiceRenderer will use the value of the ‘key’ property of SelectOption object in the ‘value’ attribute in the rendered HTML (e. g. ‘key’ property value will be used as the option id). The ‘value’ property will be used as a display value for the given option.

If you want to customize further the values rendered in option then use your own customized choice renderer.

For e.g. if you want to use something like value-key (“German-de”) as display value in above example then you can write your own ChoiceRenderer.

class CustomChoiceRenderer implements IChoiceRenderer<SelectOption> {

/**

*

*/

private static final long serialVersionUID = 1L;

@Override

public Object getDisplayValue(SelectOption object) {

return object.getValue()+”-“+object.getKey();

}

@Override

public String getIdValue(SelectOption object, int index) {

return object.getKey();

}

}

Complete source code for above example can be found here.