The Play! Framework has been rocking my world recently – the speed of development is just mind-blowing! If you haven’t tried it out yet, and you develop web applications, it is definitely something to check out!

One issue that has arisen though (no framework is perfect, although Play! is proving that some are more perfect than others) is the ability to mix the backing source of i18n’d messages – specifically, I have a requirement for users to be able to specify their own terminology in place of the standard i18n messages held in properties files.

Digging into the source code of Play!, you can see that the play.i18n.Messages class is referenced directly in the templating engine and unlike in other areas of Play!, it doesn’t seem possible to override the the class. Play! uses a lot of static methods, with bytecode voodoo to allow dynamic dispatch, but the i18n mechanism seems to be fairly rigid in what it can achieve.

In the view templates, i18n messages can be accessed in a couple of ways – using the &{‘message.key’} syntax, which is nice and concise and handled at the server level, or by using the i18n tag, which dumps all the i18n messages of the correct locale into the html along with a javascript method to access a value by its key :

#{i18n /}
...
alert(i18n('message.key'));

Looking at the source of the i18n tag, an interesting possibility opens up:

%{
js_messages=new com.google.gson.Gson().toJson(play.i18n.Messages.all(play.i18n.Lang.get()));
}%

<script type="text/javascript" charset="utf-8">

var i18nMessages = ${js_messages};
/**
 * Fixme : only parse single char formatters eg. %s
 */
var i18n=function(code) {
    if( arguments.length > 1 ) {
        var message = i18nMessages[code] || "";
        for( var i=1; i< arguments.length; i++ ) {
            message = message.replace( /%\w/, arguments[i]); 
        }
        return message;
    }
    return i18nMessages && i18nMessages[code] || code;
};

</script>

By creating a custom tag with just a small difference to the original, then a message source with the required database/property file mix can be used - let's call this one mixedI18n.html, and place it in the views/tags package of the application:

%{
js_messages=new com.google.gson.Gson().toJson(be.objectify.i18n.MixedMessages.all(play.i18n.Lang.get()));
}%
... as above ...

MixedMessages simply takes the properties associated with the locale from play.i18n.Messages, grabs any overrides from the database and inserts them into the Properties object, and returns it - now the mixed messages are available for the i18n() javascript function to access:

<head>
#{mixedI18n /}
</head>

...
alert(i18n('message.key'));

Because the value is being retrieved from javascript, you may need to do a spot of DOM manipulation along the lines of

document.getElementById('element-id').appendChild(document.createTextNode(i18n('message.key')));

which is far from the elegance of &{'message.key'} but for the moment, this seems to be the only way of doing it.

But hey, it *is* possible as least!

6 thoughts on “Mixing database and property sources for i18n in the Play! Framework

  1. Thank you very much, I’ve switched from .net (7 years of experience) to play framework, too. As a language java is far behind c#, but play framework is a game changer. It’s more and more simple and complete than aspnet mvc. And developement time is shorter in play as proved in DevDerby 2010. You can also mix Scala with java, too.

  2. Came here having just discovered Play and trying to determine its viability in my environment. I’ve been looking at alternatives to Struts but what I continue to find is that framework developers seem to think static text files are a sufficient storage medium for all an application’s text. It’s driving me nuts. At least in Struts I was able to implement my own DB-backed MessageResources class quite cleanly. Still haven’t figured it out in Struts2 and from your findings it sounds rather difficult in Play as well. Kudos for your investigation and solution but IMO, there’s NO WAY I’m going to rely on JS just to load messages.

    With all the power and flexibility in these frameworks, it boggles my mind that we’re still stuck with text files for messages.

  3. Thanks for your comment. Interestingly, given some recent work I’ve done, I’ve come to the conclusion I would do this differently now using a tag instead. Better names than those used in the example would be used 😉

    Tag: myI18n.html
    ${controllers.MyI18n.get(_key)}

    Controller: controllers.MyI18n
    public class MyI18nContrller extends Controller
    {
    public static String get(String key)
    {
    // make a call to the db, static properties file, dynamic text, whatever, here
    }
    }

    Usage in a template:
    #{myI18n key:’foo’}

    The tag could of course be expanded to include parameters.

    This is a much cleaner and efficient way of doing what I suggested above, and I think this also addresses your point above.

    I completely agree with you regarding the thought that static text files files are inadequate for storing messages. As a Brit living and working in Belgium, I’m extremely aware of the need for better i18n support, and am spending a probably unhealthy amount of time thinking of a better way to do it 🙂

  4. Thanks for your response Steve. I’ll give that a whirl as I test out Play. It seems like the world of frameworks would do well with a single standard for message support that makes it really straight-forward to drop in your own implementation. Then I look at the package-centric organization of messages in Struts 2 versus the purpose-centric organization of others and think it might not be that simple after all.

Leave a Reply

Your email address will not be published. Required fields are marked *