In previous articles, I have related the prerequisites, the configuration of a GAE account, the creation of a new Eclispe project with the type “Web Application Project”, the deployment of an application on the GWT embedded server named Jetty, the evolution of the interface with GWT Designer, the deployment of an application on a Jboss server, on a Tomcat server and on GAE cloud with application versioning on GAE. In this article, we will discuss about the Internationalization (i18n)/Localization of the GWT application.

Here the points of these articles:

  1. Prerequisites,
  2. Configuration GAE account,
  3. New Eclispe project with the type “Web Application Project”,
  4. Deployment on GWT embedded server named Jetty,
  5. Evolution of the interface with GWT Designer,
  6. Deployment on a Jboss server,
  7. Deployment on a Tomcat server,
  8. Deployment on GAE cloud,
  9. Creation of a new version n°2 of our application on GAE,
  10. Internationalization of the application,

  1. Internationalization of the application

    Google provides a powerful tool for the internationalization (i18n) support in the GWT Designer. It can externalize component strings, create and manage resource bundles for multiple languages, switch locales on fly and edit translated strings in context.

    Below, I will expose the differents steps to “internationalize” our GWT application created in previous posts concerning GWT (PART1 to PART3):

    • Open the EntryPoint class (in our case, it’s the class named Huojavagwttest3) with GWT Designer:

    • The editor’s internationalization functions center around two items on the Toolbar – the Externalize Strings button and the drop down Locales list (which lists any locales defined for the current window):

      So, by clicking the Externalize Strings button, the Externalize Strings dialog opens:

      Note: This Externalize Strings dialog presents the hard coded string properties assigned to any component within the window. If any NLS National Language Support string externalization sources have been created for other classes in the same package, they will be listed in the Existing sources list.

    • …click on the New button to create a new NLS strings source (opening of New source dialog):

    • …click on the OK button of the New source dialog in order to create the source:

    • …then, in the previous dialog Externalize Strings, click the Enable All button to select all of the strings within all of the components, check the checkbox to copy the extracted strings to all defined locales rather than only the default locale (this point will be explained in the next steps):

    • …finally, click the Externalize button to begin the extraction process and switch to the first tab of the dialog:

    • …more, this dialog is accessible from GWT Designer like that:

    Now, we have externalized all of the hard coded string properties assigned to any component within the window. Several components have been created automaticaly:

    • a new class AppConstants:
      package com.ho.gwt.test3.module31.client;
      
      import com.google.gwt.i18n.client.Constants;
      
      public interface AppConstants extends Constants {
      	String mntmFile_html();
      	String mntmFile_text();
      	String mntmNewItem_text();
      	String mntmNewMenu_text();
      	String mntmTest_text();
      	String mntmEdit_text();
      	String mntmHelp_text();
      	String lblNewLabel_text();
      	String nameField_text();
      	String nameField_width();
      	String sendButton_html();
      }
      
    • a properties file AppConstants.properties:
      #GWT variable: CONSTANTS
      lblNewLabel_text=Please enter your name:
      mntmEdit_text=Edit
      mntmFile_html=File
      mntmFile_text=File
      mntmHelp_text=Help
      mntmNewItem_text=Open
      mntmNewMenu_text=Other
      mntmTest_text=Test
      nameField_text=GWT User
      nameField_width=154px
      sendButton_html=Send
      
    • the previous class AppConstants is used automaticalyin the entry point Huojavagwttest3 has been modified:
      public class Huojavagwttest3 implements EntryPoint {
      	private static final AppConstants CONSTANTS = GWT.create(AppConstants.class);
      //...
      MenuItem mntmFile = new MenuItem(CONSTANTS.mntmFile_text(), false, menuBar_1);
      //...
      }
      

    Concerning the Locale, some words from Google site:
    GWT represents locale as a client property whose value can be set either using a meta tag embedded in the host page or in the query string of the host page’s URL. Rather than being supplied by GWT, the set of possible values for the locale client property is entirely a function of your module configuration.

    So, in the next steps, we will create and manage multiple locales:

    • In the Externalize Strings dialog, click on the New Locale button to create the new locales French and German:


    • …then, the Externalize Strings dialog has been updated with the 2 new Locales:

    • …in GWT Designer, the Locales drop down list now contains the values (default), de and fr. The selection of locale will update the design view to show the appropriate string values in context:

    • …so, in the Externalize strings dialog, modify/set the values of strings in each Locale:

    • …by switching between the Locales drop down list the values (default), de and fr. The selection of locale updates the design view to show the appropriate string values in context:

    • …2 new properties files have been created automaticaly AppConstants_fr.properties and AppConstants_de.properties:
      #GWT variable: CONSTANTS
      lblNewLabel_text=S'il vous plaît entrer votre nom:
      mntmEdit_text=Editer
      mntmFile_html=Fichier
      mntmFile_text=Fichier
      mntmHelp_text=Aide
      mntmNewItem_text=Ouvrir
      mntmNewMenu_text=Autre
      mntmTest_text=Test
      nameField_text=GWT Utilisateur
      nameField_width=154px
      sendButton_html=Envoyer
      
      #GWT variable: CONSTANTS
      lblNewLabel_text=Bitte geben Sie Ihren Namen:
      mntmEdit_text=Bearbeiten
      mntmFile_html=Datei
      mntmFile_text=Datei
      mntmHelp_text=Hilfe
      mntmNewItem_text=Geöffnet
      mntmNewMenu_text=Andere
      mntmTest_text=Test
      nameField_text=GWT Benutzer
      nameField_width=154px
      sendButton_html=Senden
      

    • …the XML file Huojavagwttest3.gwt.xml has been update automaticaly in order to add Locale choices to the GWT module:
      <!--  ... -->
        <inherits name="com.google.gwt.i18n.I18N"/>
        <extend-property name="locale" values="de,fr"/>
      <!--  ... -->
      

    At this stage, we will compile our application and deploy it on GWT embedded server named Jetty. To deploy an application in HOSTED mode (DEVELOPMENT mode) on the server JETTY embedded in GWT framework see the post GWT/GAE: Deployment an application on GWT embedded server named Jetty in Hosted mode.

    • … with the URLs http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997:

    • … with the URL http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997&locale=fr:

    • …with the URL http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997&locale=de:

    You could remark that some texts/strings not linked directly to the interface and hard coded in the entry point Huojavagwttest3, haven’t been proposed in the Externalize strings dialog (typically the strings concerning the server replies and the dialogbox opened from the menu-item “Test”):

    //...
    dlg.setText("Warning, Click done on the menu 121");
    //...
    label.setText("Why did you clicked on item 121?");
    //...
    Button closeButton = new Button("Close"); 
    
    //...
    dialogBox.setText("Remote Procedure Call");
    //...
    final Button closeButton = new Button("Close");
    //...
    dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
    //...
    dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
    //...
    errorLabel.setText("Please enter at least four characters");
    //...
    dialogBox.setText("Remote Procedure Call - Failure");
    //...
    dialogBox.setText("Remote Procedure Call");
    

    So, we will modify manually:

    • all properties files (one by Locale):
      AppConstants.properties

      #Manually added
      menu_dlg_Text=Warning, Click done on the menu 121
      menu_label_text=Why did you clicked on item 121?
      menu_close_button_text=Close
      
      #Manually added
      server_reply_dlg_title_text=Remote Procedure Call
      server_reply_close_button_text=Close
      server_reply_label_html=<b>Sending name to the server:</b>
      server_reply_dlg_text_html=<br><b>Server replies:</b>
      label_error_field_text=Please enter at least four characters
      server_reply_dlg_title_text_failure=Remote Procedure Call - Failure
      

      AppConstants_fr.properties

      #Manually added
      menu_dlg_Text=Attention, Click sur le menu 121
      menu_label_text=Pourquoi avez-vous cliqué sur le point 121?
      menu_close_button_text=Fermer
      
      #Manually added
      server_reply_dlg_title_text=Remote Procedure Call
      server_reply_close_button_text=Fermer
      server_reply_label_html=<b>L'envoi du nom au serveur:</b>
      server_reply_dlg_text_html=<br><b>Réponse du serveur:</b>
      label_error_field_text=S'il vous plaît entrer au moins quatre caractères
      server_reply_dlg_title_text_failure=Remote Procedure Call - Echec
      

      AppConstants_de.properties

      #Manually added
      menu_dlg_Text=Aufmerksamkeit auf das Menü 121 Klicken
      menu_label_text=Warum haben Sie klickte auf Artikel 121?
      menu_close_button_text=Schließen
      
      #Manually added
      server_reply_dlg_title_text=Remote Procedure Call
      server_reply_close_button_text=Schließen
      server_reply_label_html=<b>Senden Namen auf dem Server:</b> 
      server_reply_dlg_text_html=<br><b>Server Antworten:</b>
      label_error_field_text=Bitte geben Sie mindestens vier Zeichen
      server_reply_dlg_title_text_failure=Remote Procedure Call - Ausfall
      

    • …the constants interface AppConstants by adding new methods with name equals to the key of properties added:
      public interface AppConstants extends Constants {
      //...
      	
      	//Manually added
      	String menu_dlg_Text();
      	String menu_label_text();
      	String menu_close_button_text();
      	
      	//Manually added
      	String server_reply_dlg_title_text();
      	String server_reply_close_button_text();
      	String server_reply_label_html();
      	String server_reply_dlg_text_html();
      	String label_error_field_text();
      	String server_reply_dlg_title_text_failure();
      //...
      }
      

    • …the entry point class Huojavagwttest3:
      //...
      //dlg.setText("Warning, Click done on the menu 121");
      dlg.setText(CONSTANTS.menu_dlg_Text());
      //...
      //label.setText("Why did you clicked on item 121?");
      label.setText(CONSTANTS.menu_label_text());
      //...
      //Button closeButton = new Button("Close"); 
      Button closeButton = new Button(CONSTANTS.menu_close_button_text());
      
      //...
      //dialogBox.setText("Remote Procedure Call");
      dialogBox.setText(CONSTANTS.server_reply_dlg_title_text());
      //...
      //final Button closeButton = new Button("Close");
      final Button closeButton = new Button(CONSTANTS.server_reply_close_button_text());
      //...
      //dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
      dialogVPanel.add(new HTML(CONSTANTS.server_reply_label_html()));
      //...
      //dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
      dialogVPanel.add(new HTML(CONSTANTS.server_reply_dlg_text_html()));
      //...
      //errorLabel.setText("Please enter at least four characters");
      errorLabel.setText(CONSTANTS.label_error_field_text());
      //...
      //dialogBox.setText("Remote Procedure Call - Failure");
      dialogBox.setText(CONSTANTS.server_reply_dlg_title_text_failure());
      //...
      //dialogBox.setText("Remote Procedure Call");
      dialogBox.setText(CONSTANTS.server_reply_dlg_title_text());
      

    If we deploy our application on GWT embedded server named Jetty:

    • … with the URLs http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997:

    • … with the URL http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997&locale=fr:

    • …with the URL http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997&locale=de:

    Some words, concerning the response of server in above screenshots, it is only in english “Hello Huseyin, I am running…” because we have only modify the client side of our application. For the server side, it is necessary to set the Locale in Session on server side, or to add the parameter “locale=…” during all requests to server.

    So, we will add 2 new labels to the interface with GWT Designer in order to display the current locale and the other locales available:

    • …First, add panels and labels to obtain the below result:

    • …go to the Externalize strings dialog, and add the necessary missing labels for the locales:

    • … the entry point class Huojavagwttest3.java and the properties files are updated automatically:

      AppConstants.properties

      lblNewLabel_1_text=Current locale:
      lblNewLabel_2_text=Other locales available:
      lblNewLabel_3_text=default
      

      AppConstants_fr.properties

      lblNewLabel_1_text=Locale courante:
      lblNewLabel_2_text=Autres locales disponibles:
      lblNewLabel_3_text=default
      

      AppConstants_de.properties

      lblNewLabel_1_text=Aktuelle Ländereinstellung:
      lblNewLabel_2_text=Andere Schauplätze zur Verfügung:
      lblNewLabel_3_text=default
      

    • …at last, we update the interface to display the current locale and the other locales available in the previously added labels:
      //...
      //Current locale
      {													HorizontalPanel horizontalPanel_2 = new HorizontalPanel();	
      	verticalPanel.add(horizontalPanel_2);
      													Label lblNewLabel_1 = new Label(CONSTANTS.lblNewLabel_1_text());
      	horizontalPanel_2.add(lblNewLabel_1);
      													Label lblNewLabel_3 = new Label(CONSTANTS.lblNewLabel_3_text());
      	lblNewLabel_3.setText(""+LocaleInfo.getCurrentLocale().getLocaleName());
      	horizontalPanel_2.add(lblNewLabel_3);
      	horizontalPanel_2.setCellHorizontalAlignment(lblNewLabel_3, HasHorizontalAlignment.ALIGN_RIGHT);
      	lblNewLabel_3.setWidth("94px");
      }
      
      //...
      //Other locales available
      {
      	HorizontalPanel horizontalPanel_3 = new HorizontalPanel();
      	verticalPanel.add(horizontalPanel_3);
      
      													Label lblNewLabel_2 = new Label(CONSTANTS.lblNewLabel_2_text());
      	horizontalPanel_3.add(lblNewLabel_2);
      	horizontalPanel_3.setSpacing(20);
      	horizontalPanel_3.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
      	horizontalPanel_3.setHorizontalAlignment(HorizontalPanel.ALIGN_LEFT);
      													Label label = new Label();
      	String[] locales = LocaleInfo.getAvailableLocaleNames();
      	for (int i = 0; i < locales.length; i++) {
      		label = new Label();
      		label.setText(locales[i]);
      		horizontalPanel_3.add(label);
      	}
      }
      

      The most important parts of this code are the programmatic access to Locale Information and the getting of a list of supported locales. For more information, read the official article of Google about the Locales in GWT:

       
      lblNewLabel_3.setText(""+LocaleInfo.getCurrentLocale().getLocaleName());
      
       
      String[] locales = LocaleInfo.getAvailableLocaleNames();
      

    If we deploy again our application on GWT embedded server named Jetty:

    • … with the URLs http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997:

    • … with the URL http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997&locale=fr:

    • …with the URL http://localhost:8888/Huojavagwttest3.html?gwt.codesvr=127.0.0.1:9997&locale=de:

FINAL CONCLUSION
In this serie of articles (PART1 to PART4) concerning GWT SDK 2.4.0 (Google Web Toolkit), GAE (Google App Engine), we have developed a Web application by using JDK 1.6, GWT 2.4 and Eclipse 3.7.

I have also related the prerequisites, the configuration of a GAE account, the creation of a new Eclispe project with the type “Web Application Project”, the deployment of an application on the GWT embedded server named Jetty, the evolution of the interface with GWT Designer, the deployment of an application on a Jboss server, on a Tomcat server, on GAE cloud with application versioning on GAE, and finally the Internationalization (i18n)/Localization of the GWT application.

Source: huojavagwttest3.zip

Notes: This file huojavagwttest3.zip contains the final version of the tutorial (from PART1 to PART4), but, it is necessary to add the librairies appengine-api-1.0-sdk-1.6.1.jar, appengine-api-labs-1.6.1.jar, appengine-jsr107cache-1.6.1.jar, datanucleus-appengine-1.0.10.final.jar, datanucleus-core-1.1.5.jar, datanucleus-jpa-1.1.5.jar, geronimo-jpa_3.0_spec-1.1.1.jar, geronimo-jta_1.1_spec-1.1.1.jar, google_sql.jar, gwt-servlet.jar, jdo2-api-2.3-eb.jar and jsr107cache-1.1.jar.

That’s all!

Best regards,

Huseyin OZVEREN