www.enhydra.org
 
 
 
FRONT PAGE


Gone Fishin':
Localization with Barracuda

Christian Cryder, Lutris Barracuda Architect

In the last edition of Lutris Enhydra Journal, we began with an Introduction to Barracuda in which we identified four major features of the Barracuda Presentation Framework -- Barracuda provides a Component Model, an Event Model, a Form Mapping & Validation framework, and Localization Services.

Each of these subsystems is loosely coupled, which means that you can use as much or as little of Barracuda as you wish. If you have lots of simple pages, but you need to support many different locales, then the Localization Services might be the only aspect that you need. Or, if you are going to do lots of form processing, you may wish to leverage Form Mapping & Validation. Large complex applications will probably benefit from using all of the available subsystems.

The primary point here is that Barracuda doesn't try to make any of these decisions for you -- you get to decide what makes sense for your particular needs and what doesn't. Another advantage of this loose coupling is that it makes the system a lot easier to learn because we can study one layer at a time.

Beginning with Localization Services

We will start with Localization Services, since this is an area that is easy to understand and applicable to most webapps. Let's begin the discussion by reviewing the manual approach to localizing an app. Suppose we have a sample application that uses a login screen template (ie. Login.html) that looks something like this:

<form name="LoginForm" method="POST" action="DoLogin.event">
  <h2>Please Log In!</h2>
  <p>Before you can access your account information, you must first log in. 
    Please enter your Login and Password below and then press the 'Login' button. 
    If you do not have an account, please 'Register' to create one.</p>
  <p><font color="#FF0000">
    <span id="ErrorText">Optional Error Text Goes Here</span>
  </font>
  <table summary="Login Form">
    <tr>
      <td align="right">Login: </td>
      <td><input id="login" size="20"> </td>
    </tr>
    <tr>
      <td align="right">Password: </td>
      <td><input type="password" id="password" size="20"> </td>
    </tr>
    <tr>
      <td>
        <input type="submit" value="Login" name="Login"> 
        <input type="submit" value="Register" name="Register">
      </td>
    </tr>
  </table>
</form>

The markup in green represents text that will be human readable when rendered in an HTML browser.

Now, let's say we wanted to create an application that would use this template. How would we go about it? Well, we'd probably begin by compiling the template into a DOM object using XMLC. This would allow us to programmatically load the template and populate it accordingly -- depending on whether or not the user has already tried to login, we may or may not want to show the error message, we might want to prepopulate the input fields with the last values entered, etc. Once the DOM has been manipulated as needed, we then simply render it back to the client's browser.

The Manual Localization Strategy - 2 Approaches

Ok, so far so good. But what if we wanted to support users who are running in different client locales? For instance, what if the user's locale is Spanish? In this case, we'd need several additional steps. First, we have to determine which locale the client is running in. Then we have to react accordingly. There are two different strategies we can choose from.

The first option is to simply create another template (ie. Login_spanish.html) that looks identical to the first and then manually localize the file. This makes the developer's task fairly straightforward--simply determine the target client locale and load the appropriate template. Unfortunately there are several problems with this approach. Whenever the designer makes a change to one template he must remember to make that change in all the other templates as well. The resulting maintenance overhead--along with the opportunity for introducing errors--quickly becomes onerous. In addition, what happens if the client is running a locale not explicitly supported by the server (say Finnish)? Adding new locales will always require coding changes.

A second option is to simply use one template and set all the text dynamically at runtime. This approach is much less burdensome for the designer, but is unfortunately tremendously inefficient for the server. Under this approach, every time we receive a request for a page we would load the DOM template and then dynamically set every single text element in the page (even if the locale was unchanged from the previous request). This added overhead significantly impacts performance. In addition, we still face the issue of handling clients with unsupported locales. While we could probably improve things a little with some kind of strategic cache-and-reuse-when-possible strategy, the basic architecture here is fundamentally suspect.

What we really need is a solution that makes localization easy for both the designer and developer.

Stealing a Page from Resource Bundles

At this point, it may be helpful to step back and take a look at how Java handles localized resources.  It turns out that the Sun engineers have created an elegant solution to a similar problem; by examining their approach we might be able to learn something useful.

The java.util library defines two classes that are most interesting to our current discussion. The Locale class is used to represent a target Locale. It consists of a Language, Country, and (optionally) Variant codes. A locale could be something as broad as "English" or as specific as "English, US, Creole". As you can see, this allows us to cover just about all client locales. The other class pertinent to our discussion is ResourceBundle. While we don't need to know the all details of this class, the main point to understand is that this class is used to access a resource (like a property file) based on a specific locale.

The way these two classes work together is quite simple. Let's say I have 4 property files:

  • foo.properties (default)
  • foo_en.properties (English version)
  • foo_en_US.properties (English version, United States)
  • foo_es.properties (Spanish version)

When I ask the ResourceBundle to load the "foo" properties file, it looks at the target locale and figures out which physical file is the closest possible match. For instance, if I pass in a locale for "English, US, Creole", I will get back a reference to foo_en_US.properties. If I pass in a reference to a "Spanish" locale, I will get back the Spanish version of the file. If I request a locale for which there are no matches (say Finnish) then it will return the default.

This is really nice for the developer because I only have to know the name of the base resource ("foo") and the target locale. This makes it easy to write code that doesn't need to be recompiled every time we need to support and additional locale.

Applying this Concept to XMLC Templates

Wouldn't it be slick if we could load XMLC generated DOM templates in the same way that we can load ResourceBundles? With Barracuda we can. Barracuda provides a specialized DefaultDOMLoader that allows you to specify an XMLC template (ie. FooHTML.class) along with the target client locale ( "English, US, Creole"). This class then goes through a matching process similar to that of ResourceBundle to find the closest matching template. If no match exists, the default will be returned.

This certainly is convenient for the developer--we can load a class based on client locale and not have to worry about whether or not the specific template actually exists or not. But what about the designer? How do we avoid the maintenance nightmare of supporting separate *ML templates for each supported locale? It turn out Barracuda can help here as well.

The Barracuda Localization Taskdef

Barracuda provides a custom Ant taskdef that will automatically create localized versions of any given template. For instance, let's say that we have a template called Login.html (see above). All the designer has to do is to create a simple properties file called Login.properties that contains references to all the text which can be localized. If we were to return to our initial Login example, the file might look something like this:

Login.Data.Header = Please Log In!
Login.Data.Expl = Before you can access your account...
Login.Data.Error = Optional Error Text Goes Here
Login.Label.Login = Login: 
Login.Label.Password = Password: 
Login.Input.Login = Login
Login.Input.Register = Register

The keys we are using here are totally arbitrary. The only requirement is that they be unique.

Now all we need to do is create custom properties files for the specific locales we wish to support. For instance, let's say we want to support Spanish users. All we have to do is create a Login_es.properties file that defines localized values for the keys defined in the master properties file:

Login.Data.Header = Ingrese Por favor!
Login.Data.Expl = Antes de que pueda acceder su cuenta...
Login.Label.Login = Usuario: 
Login.Label.Password = Clave: 
Login.Input.Login = Usuario
Login.Input.Register = Registrarse

When the localization taskdef compiles the XMLC templates it not only creates a LoginHTML.class but it also detects the presence of the Spanish properties file from which it then automatically creates a LoginHTML_es.class. Any values in the localized properties file will be automatically inserted into the template. Any values which are missing (in this case, Login.Data.Error, will be left alone, effectively defaulting the value to the contents of the master file...just what we'd expect with a ResourceBundle!).

Now if we use the Barracuda DOM Loader class and specify a Spanish locale, we'll get a reference to the Spanish template. And all this happens automatically!

Putting it All together

Ok, let's review the localization process.

  1. The designer creates one master template (Login.html) and then places localized content in separate properties files (Login.properties, Login_es.properties, etc.).

  2. When the system gets compiled multiple XMLC objects will get created (LoginHTML.class, LoginHTML_es.class, etc.).

  3. To use the templates in a webapp, the developer simply asks Barracuda to determine the client locale (based on an HTTP Request) and then uses the DefaultDOMLoader to load the localized version of a target template.

That's it! Barracuda takes care of the dirty work, creating and loading the proper localized templates as needed. The whole process is easy to implement -- and maintain -- for both designer and developer.

Getting More Information

If you'd like to learn more about Barracuda Localization, you might want to check out the Barracuda Localization Tutorial or browse the project documentation at http://barracuda.enhydra.org. In the next issue, we'll take a peek at the Barracuda Component Model!

 

 
TOP

Lutris Technologies    Legal Notices    Privacy Policy