It's common to provide a toString
implementation on a domain object that may well end up being used in the view. However, this doesn't allow for internationalization in the view. A good solution that I've used a number of times is to have classes implement Spring's MessageSourceResolvable interface. Consider this domain class that represents an image file:
grails-app/domain/Image.groovy
class Image { String name String path User uploadedBy org.joda.time.DateTime dateCreated static transients = ['file'] File getFile() { new File(ConfigurationHolder.config.image.base.dir, path) } String toString() { "$name uploaded by $uploadedBy.username on $dateCreated - ${file.size()} bytes" } }
The toString
implementation is all well and good if we're targeting an English-speaking audience but with some simple changes we can make it i18n compliant:
grails-app/domain/Image.groovy
class Image implements org.springframework.context.MessageSourceResolvable { // properties as above static transients = ["codes", "arguments", "defaultMessage"] Object[] getArguments() { [name, uploadedBy.username, dateCreated.toDate(), file.size()] as Object[] } String[] getCodes() { ['image.info'] as String[] } String getDefaultMessage() { "$name uploaded by $uploadedBy.username on $dateCreated - ${file.size()} bytes" } }
In our message properties file we can add:
grails-app/i18n/messages.properties
image.info={0} uploaded by {1} on {2,date} - ${3,number,integer} bytes
In the view we can display our object like this:
<g:message error="${imageInstance}"/>
Yes, that is the error
attribute we're passing to the message tag! Grails intends the attribute to be used for outputting validation errors but the underlying mechanism is the same - Spring's ObjectError
implements MessageSourceResolvable
and that's how Grails' message tag resolves the displayed error message. Rather than passing separate code
, args
and default
attributes to the tag we can pass the single MessageSourceResolvable
instance and its implementation will take care of supplying those values.
Note: I added a message
attribute to the message tag to avoid the confusion caused by using error
. This is in Grails from version 1.2-M1 onwards.
We can now add translations of our object description. For example:
grails-app/i18n/messages_af.properties
image.info={0} opgelaai deur {1} op {2,date} - ${3,number,integer} grepe
It's worth noting that the format of the dateCreated
property will be automatically determined by the request locale so the value will be formatted correctly for the user.
I've found this technique can also be very useful on enum classes. For example:
src/groovy/com/mycompany/Season.groovy
package com.mycompany enum Season implements org.springframework.context.MessageSourceResolvable { SPRING, SUMMER, AUTUMN, WINTER Object[] getArguments() { [] as Object[] } String[] getCodes() { ["${getClass().name}.${name()}"] as String[] } String getDefaultMessage() { name() } }
grails-app/i18n/messages.properties
com.mycompany.Season.SPRING=Spring com.mycompany.Season.SUMMER=Summer com.mycompany.Season.AUTUMN=Autumn com.mycompany.Season.WINTER=Winter
grails-app/i18n/messages_en_US.properties
com.mycompany.Season.AUTUMN=Fall
11 comments:
This is very usefull information. Thanks for posting!
Thanks for the tips.
Does the trick on enums work for scaffolded views ? I mean, will the list of values in the generated select tag be displayed from the message bundles ?
@Philippe as of Grails 1.3.4 it should, yes. I committed the code for that to Grails myself.
You also gotta add ['codes', 'arguments', 'defaultMessage'] to your list of transients. In 1.2.4 at least.
yeah, good point
In Grails 2.x you can use my plugin: http://grails.org/plugin/enum-message-source-resolvable to DRY implement MessageSourceResolvable on enums
The above mentioned plugin was updated and now lives at http://grails.org/plugin/i18n-enums
sa réponse répliques de sacs à main Ysl voir le site Web Hermes Dolabuy cliquez pour lire sacs de répliques en ligne
Post a Comment