Grails i18n in Regular Classes

The Grails web development framework is a very powerful tool for quickly creating web applications ranging from simple to enterprise ready. For that, it probably provides everything a developer ever needs. And if it’s not delivered by Grails itself there are many useful plugins and tons of existing Java libraries (including the JDK, of course, the underlying SpringSource Framework and the GDK).

However, there is one thing I have stumbled across several times now and a quick search on the internet shows that I’m not alone with this problem: how can I use the internationalization features from a regular Java or Groovy class?

User centric artifacts

Just a quick overview of how Grails lets you access your message bundles (see docs).

  • GSP files provide the Grails tag
  • Controllers basically do the same, only as a method call message(code: 'some.code')
  • The same applies for tag-libs, with the only exception that the method call needs to be prefixed with the Grails namespace g.message(code='some.code').

 

Application internal artifacts

What about services? In a service you have to inject an instance of MessageSource by adding def messageSource to your service class. This allows you to call getMessage in a similar way Grails provides in controllers. There’s one caveat though: you have to supply the locale for which you want to retrieve a message. More on that later.

Now, this was still easy but maybe you want to translate text in, let’s say, your own Groovy class (in the “src/groovy” folder). There’s no dependency injection available in that case. What do you do? For one, you could simply create a field or a local variable of type MessageSource. But that ain’t Groovy, ya now! The cool way is to add a getter method to your class at runtime which returns such a message-source. And where’s the best place to do this? Bootstrap!

import typicalnerd.TranslationHelper

class BootStrap {
 def messageSource

def init = { servletContext ->
 TranslationHelper.class.metaClass.getMessageSource = 
 TranslationHelper.class.metaClass.static.getMessageSource = { 
 messageSource 
 }
 }

def destroy = {
 }
}
Thanks to Stephan Beal for telling me in the comments to only define one closure and use it twice.

I’ve created myself a Groovy class named TranslationHelper which can be used by any other class that needs to fetch a translated string. Using Groovy’s Meta-Class system I add a static and non-static getMessageSource closure to it which captures the dependency injected messageSource of the BootStrap class. This gives me access to a message-source from within my translation helper, for both, static and instance methods.

The Locale

As already mentioned in context with services, if you make use of the MessageSource then you are responsible for supplying a locale. Apart from the need to have translation in non-user-visible artifacts I do not fancy having this boilerplate code litter my carefully styled code wherever I work with a message-source. This is another good reason for this helper class. Alright, where can one get the locale?

  • The current implicit context of a request
  • The HTTP request
  • You create one yourself

The last one is not very useful unless you want to restrict your application to one language – which can implicitly be achieved by not using the message bundles at all. I’ll focus on the first two.

Implicit context

The SpringSource framework provides LocaleContextHolder which can be found in the package org.springframework.context.i18n. You’ll only need an import and call the static method getLocale() on it. Here’s how it is done in my helper class.

package typicalnerd

import org.springframework.context.i18n.LocaleContextHolder as LCH

class TranslationHelper {

static String getMessage(String code) {
 return getMessageSource().getMessage(
 code, 
 null, 
 '', 
 LCH.getLocale())
 }
}

Here you can see two things:

  • The use of the static getMessageSource() that was added in the bootstrap
  • I created an alias LCH for LocaleContextHolder to shorten the actual code that uses this class.

There’s one important thing to keep in mind. getLocale() is bound to the context of the current thread. For classes used in the context of an invocation of one of your controller’s actions this is the locale of the request. Taken from the Grails docs (section “Scoped Controllers):

By default, a new controller instance is created for each request. In fact, because the controller is prototype scoped, it is thread-safe since each request happens on its own thread.

In this case there’s nothing to worry about. Even if your code branches into a service it belongs to the context of the calling thread. However, if you create your own threads then they are outside of the scope of any request. In this case getLocale() returns a string based on the default system locale (unless you set it explicitly before). As a quick demo (I did not want to fiddle with threads and all that code that goes with it) I put a call to my helper class in the bootstrap, and, who’d have thought, the message returned is in German, always. Calls to actions, on the other hand, return the value based on the context of the request.

HTTP request

What LocaleContextHolder is doing implicitly you can also do explicitly. The RequestContextUtils allow you to extract the locale of the request. Again, see my helper class:

package typicalnerd

import javax.servlet.http.HttpServletRequest
import org.springframework.context.i18n.LocaleContextHolder as LCH
import org.springframework.web.servlet.support.RequestContextUtils

class TranslationHelper {

static String getMessage(String code) {
 return getMessageSource().getMessage(
 code, 
 null, 
 '', 
 LCH.getLocale())
 }

static String getMessage(String code, HttpServletRequest request) {
 if (request) {
 return getMessageSource().getMessage(
 code, 
 null, 
 '', 
 RequestContextUtils.getLocale(request))
 }
 else {
 return getMessage(code)
 }
 }
}

With every call to an action you have access to a variable named request within this action. This instance is of type HttpServletRequest and can be used to extract the locale by passing it to RequestContextUtils.getLocale(). That’s basically all there is to it.

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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.