20.07.2011

GWT: UiBuilder Internationalisation the simple way

UiBinder, the tool for declarative UIs for GWT, can of course be internationalised. The procedure is explained in the GWT docs. But this approach looks a little bit too complex to me, especially because I already have a simple I18N interface for my App. I would like to use that one and have only one place to add translations to.

GWT I18N, recalled


GWT provides us with a very simple way of doing I18N. Simply create an interface like that one:
public interface Text extends Messages {
 public static final Text LANG = GWT.create(Text.class);
 String create();
 String save();
 String delete();
}
In the same folder, put a properties file called Text.properties:
create=Create
save=Save
delete=Delete
and for your german user, for example, add another text file Text_de_DE.properties:
create=Neu
save=Speichern
delete=Löschen
In order to set the correct locale from the users request, I usually convert from index.html to index.jsp (do not forget to change your welcome file in web.xml, too) and add:
<meta name="gwt:property" 
         content="locale=<%= request.getLocale() %>">
Finally, add this to your Module.gwt.xml:
<inherits name="com.google.gwt.i18n.I18N"/>
  <extend-property name="locale" values="en"/>
  <extend-property name="locale" values="de_DE"/>
  <set-property-fallback name="locale" value="en"/>
Now, instead of writing string literals in your app code, use this interface:
Button save = new Button(Text.LANG.save());


Now, what about UiBuilder?


The recipe for I18N of UiBuilder templates describe a procedure where the property files above can be generated from annotated templates. Cool, but you know, I do not want two different techniques and qould like to re-use the simple Text interface from above.

And of course this is simple. As explained here, import the interface as an external resource and simply use it:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
   xmlns:g="urn:import:com.google.gwt.user.client.ui"
   xmlns:t="urn:import:de.joergviola.tripmark.client.util">
 <ui:with field='i18n' type='de.joergviola.tripmark.client.i18n.Text'/>
 <g:HorizontalPanel spacing="3">
   <g:Anchor text="{i18n.save}" ui:field="save"/>
   <g:Anchor text="{i18n.delete}" ui:field="delete"/>
 </g:HorizontalPanel>
</ui:UiBinder>
That's it - simple, eh?