SpringOne 2GX 2011

Chicago, October 25-28, 2011

Reading i18n messages from the database with Grails

Posted by: Graeme Rocher on 2010-04-16 08:18:15.0
In a recent consulting engagement, a client wanted to know how to go about reading i18n messages from the database rather than static properties files (the default in Grails). Considering how easy this is to do I was surprised when I Googled it that there was no information on how this is achieved.

Anyway it's dead simple. Just create a domain class that models a message:

class Message {

String code

Locale locale

String text

}


Then implement a class that extends the org.springframework.context.support.AbstractMessageSource class. In the example below I am using simple GORM finders to lookup a message using the code and locale

class DatabaseMessageSource extends AbstractMessageSource {


protected MessageFormat resolveCode(String code, Locale locale) {

Message msg = Message.findByCodeAndLocale(code, locale)

def format

if(msg) {

format = new MessageFormat(msg.text, msg.locale)

}

else {

format = new MessageFormat(code, locale )

}

return format;

}

}


Then wire it in using Spring by configuring a "messageSource" bean in the grails-app/conf/spring/resources.groovy file:

beans = {

messageSource(DatabaseMessageSource)

}


And that's it. Now you're serving messages from the database. Of course this is a terrible inefficient implementation since we're hitting the database for ever message code used in the application. However, it's pretty easy to introduce caching. Just create a cache key:

@Immutable

class MessageKey implements Serializable {

String code

Locale locale

}


Then configure an appropriate cache bean (I'm using Ehcache) in Spring and wire it into your MessageSource:

beans = {

messageCache(EhCacheFactoryBean) {

timeToLive = 500

// other cache properties

}

messageSource(DatabaseMessageSource) {

messageCache = messageCache

}

}


Finally, update your implementation to use caching:

class DatabaseMessageSource extends AbstractMessageSource {


Ehcache messageCache

@Override

protected MessageFormat resolveCode(String code, Locale locale) {

def key = new MessageKey(code,locale)

def format = messageCache.get(key)?.value

if(!format) {

Message msg = Message.findByCodeAndLocale(code, locale)

if(msg) {

format = new MessageFormat(msg.text, msg.locale)

}

else {

format = new MessageFormat(code, locale)

}

messageCache.put new Element(key, format)

return format

}

return format;

}

}





About Graeme Rocher

Graeme Rocher

As Head of Grails Development for SpringSource, Graeme Rocher is the project lead and co-founder of the Grails web application framework. He's a member of the JSR-241 Expert Group which standardizes the Groovy language. Graeme authored the Definitive Guide to Grails for Apress and is a frequent speaker at JavaOne, JavaPolis, NoFluffJustStuff, JAOO, the Sun TechDays and more. Graeme joined SpringSource in late 2008 upon the acquisition of G2One Inc. Before founding G2One, Graeme was the CTO of SkillsMatter, a skills transfer company specializing in open source technology and agile software development, where Graeme was in charge of the company's courseware development strategy and general technical direction.

More About Graeme »

NFJS, the Magazine

2011-06-01 00:00:00.0 Issue Now Available
  • Spock: I Have Been, & Always Shall Be, Your Friendly Testing Framework

    by Kenneth Kousen
  • WebSockets: Bidirectional Communication Over TCP

    by Johnny Wey
  • High Powered Messaging with RabbitMQ

    by James Carr
  • GORM: Object Persistence Done Right

    by Dave Klein
Learn More »