Tutorial: Internationalize ZK Web Applications (Part 2)

In part 1 (link) we created a multi language supporting web application with the ZK Ajax framework. Out-of-the box it will follow the browser’s default or preferred language which is perfect assuming 1 user would always use the same desktop with the same browser. But what happens if you create an application that is used by different users on public browsers or in an office/production environment with shared work stations (web kiosk). The preference page might not be accessible, and 90% of users won’t even know how or are not very excited to change the browsers preferences to have their own language displayed. Did you try to change it before ? Firefox: Go to edit|preferences|Language choose..| select (add) you language and move it to the top. You want to change it back ? Go there again and….. This is not WEB 2.0 !

What we need is the application to change the language on the fly, and even better store it as a user preference if you use accounts.

We continue with the application from part 1.

Tutorial Part 2:

  • Add a method to handle the language
     public void setLanguage(String setLang) throws Exception {
    
     System.out.println("Org Language: " + session.getAttribute("preflang"));
    
     // set session wide language to new value
     if (!setLang.isEmpty()) {
     session.setAttribute("preflang", setLang);
     }
    
     // read the session language attribute
     String sessLang = (String) session.getAttribute("preflang");
     System.out.println("New Language: " + session.getAttribute("preflang"));
    
     // set the new preferred locale
     // otherwise it will use the default language (no session attribute and/or language parameter
     if (!(sessLang == null)) {
     Locale preferredLocale = org.zkoss.util.Locales.getLocale(sessLang);
     session.setAttribute(org.zkoss.web.Attributes.PREFERRED_LOCALE, preferredLocale);
     org.zkoss.util.Locales.setThreadLocal(org.zkoss.util.Locales.getLocale(sessLang));
     }
    
     // Iterate through variables of the current class
     for (Field f : this.getClass().getDeclaredFields()) {
     // System.out.println(this.getClass().getName() + "." + f.getName() + " of type " + f.getType().getName());
     String compName = this.getClass().getName() + "." + f.getName();
     String compLabel = Labels.getLabel(compName);
     String compType = f.getType().getName();
    
     // only set lable if value found, otherwise it renders empty
     if (!(compLabel == null)) {
     if (compType.equals("org.zkoss.zul.Button")) ((Button) f.get(this)).setLabel(compLabel);
     else if (compType.equals("org.zkoss.zul.Label")) ((Label) f.get(this)).setValue(compLabel);
     // Other component types need to be implemented if required
     }
     }
     }
    

    Remark: You need to extend the code if you want to derive from the users account setting.

  • Change the doAfterCompose method
    Calling setLanguage without parameter will use browser default or session attribute if present

     @Override
     public void doAfterCompose(Component comp) throws Exception {
     super.doAfterCompose(comp);
    
     // no parameter, use browser default or session attribute if present
     setLanguage("");
     }
    
  • Fix the imports
    ..
    import org.zkoss.util.resource.Labels;
    import org.zkoss.zk.ui.Component;
    import org.zkoss.zk.ui.util.GenericForwardComposer;
    import org.zkoss.zul.Button;
    import org.zkoss.zul.Label;
    
    import java.lang.reflect.Field;
    import java.util.Locale;
    import org.zkoss.zk.ui.event.Event;
    ..
    
  • Add buttons to change the language on the fly
    Remark: In a real application I would use country flags in a breadcrumb header, or use a combobox instead of buttons.
    Sorry if there is any wrong characters/word for the other languages.
    index.zul

    ..
     <separator bar="true"/>
     <hbox>
     <button id="btnEN" label="English" />
     <button id="btnDE" label="Deutsch" />
     <button id="btnCN" label="中国语文" />
     <button id="btnHI" label="हिन्दी भाषा" />
     </hbox>
    
    ..
    

    indexController.java

    ..
     Button btnDE;
     Button btnEN;
     Button btnCN;
     Button btnHI;
    ..
     public void onClick$btnDE(Event event) throws Exception {
     setLanguage("de");
     }
    
     public void onClick$btnEN(Event event) throws Exception {
     setLanguage("en");
     }
    
     public void onClick$btnCN(Event event) throws Exception {
     setLanguage("cn");
     }
    
     public void onClick$btnHI(Event event) throws Exception {
     setLanguage("hi");
     }
    ..
    
  • Maintaining the language properties files
    By now we have 4 files for english (default), german, chinese and hindi.
    Warning: There is a problem with Netbeans IDE handling UTF8 characters for non-english characters such as chinese. You can perfectly edit the labels, but it will not be displayed properly once rendered to the web page.

    Multi language properties

    Once you run the application you get the UTF-8 representation of the characters in your page.

    Character Problem

    Note the bottom button’s label is placed directly in the zul file and not retrieved from the properties file.Opening the same properties file in a text editor.

    Character Problem

    The only work-around (assuming Netbeans IDE has a problem): Edit outside, on Ubuntu you could use jEdit.

    JEdit

    Do not touch the file in Netbeans anymore. Netbeans now renders this

    Netbeans character problem

  • Running the application
    Now we have a full fledge multi-language application with on-the-fly change function.

    Chinese Web Application

    Hindi Web Application

Download project: http://sourceforge.net/projects/coffeeshop/files/ (ZKInternationalDemo20100315.zip)

Remarks:

  • Let a native speaker handle the translation, not Google.
  • Translation of text result in different lengths of labels, button, etc. Verify all you screen layouts!
  • You persist to a DB ? then you better to check if your content is properly rendered as well.
  • Not quite sure what is the impact on performance with many users changing the language on the fly.
Advertisements

4 thoughts on “Tutorial: Internationalize ZK Web Applications (Part 2)

  1. Properties storing problem is not a Netbeans problem, but is a Java standard.
    http://java.sun.com/javase/6/docs/api/java/util/Properties.html#store(java.io.OutputStream, java.lang.String)
    http://java.sun.com/javase/6/docs/api/java/util/Properties.html#store(java.io.OutputStream, java.lang.String)

    Netbeans is the only one ide that respect this standard.

    Zk load .properties files as InputStream, not as Properties class (See zk sources): If zk will load .properties files in java standard mode than all works fine. (I’ve created my preprocessor that loads correctly the .properties files and send it to zk, and all works well).

    Bye,

    Agharta

  2. I followed all steps and I just get this message and nothing else:
    Org Language: en
    New Language: pt
    or
    Org Language: pt
    New Language: en

    So, I am looking for your help because I dont know what’s going on.

    Hug
    Edu

  3. its was helpful. i just want to know how did u enter hindi texts in the resource file? the text is different from hindi.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s