3

I've already found a way to get message from i18n message properties (outside the controller)

def messageSource = Holders.grailsApplication.mainContext.getBean 'messageSource'
....
errorMessages << [field: "transactionDate", message: messageSource.getMessage("transactionDate.require.message", null ,null)]

But then while reviewing my colleauges work, I found out that they use a different way..

def g = new ApplicationTagLib()
errorMessages.add([field: "exchangeRate", message: g.message(code: "exchangeRate.max.message")])

Obviously, this a simpler version but I want to know which way is preferred (best practice) and what is the difference of the one to the other.

user3714598
  • 1,733
  • 5
  • 28
  • 45
  • 3
    `g.message` is available inside controllers only, if you need i18 messages anywhere else in your application, you would have to get messageSource bean first – Sandeep Poonia Jan 06 '16 at 07:02
  • @SandeepPoonia Hi, hmm that's weird because my colleague was able to use g.message (outside the controller). But instead of using messageSource, He instantiated ApplicationTagLib . – user3714598 Jan 06 '16 at 07:27
  • a good link is http://stackoverflow.com/questions/6781140/fetching-some-value-from-message-properties-in-grails – Adesh Kumar Jan 06 '16 at 09:35

2 Answers2

1

Inside a Controller message and g.message are directly available from ValidationTagLib. Your colleague is assigning an object of ApplicationTagLib to variable g. I suspect ApplicationTagLib is a custom class and not provided by grails api, atleast not in 2.3.x.

If you need i18 messages anywhere except controllers in your application, then you would have to get messageSource bean first or you can create a new instance of ValidationTagLib and then call message() on that instance.

Sandeep Poonia
  • 2,158
  • 3
  • 16
  • 29
1

Just as an addition to above answers, there could be following places where you need to implement internationalisation or fetch the message from message bundles.

  1. views
  2. controllers
  3. services
  4. Filters
  5. Utility files(e.g. in util package or generalised exception message handling)
  6. Special files e.g. in Shiro security rest realms

Below are the elaborate usage scenarios:

  1. Views:- we have taglib available with message tag. Use this on views.

  2. controllers :- message method is by default available here and locale conversion is automatically handled. See this.

  3. service: we may call taglibs inside services as below:

    def myCustomTaglib = grailsApplication.mainContext.getBean('com.custom.MyCustomTagLib');
    

Or inject messageSource bean as

def messageSource 
  1. Filters / utility / Special files:- For these you may create something like below and then use it throughout.

    String i18nMessage(def input,String defaultMessage) {
        String[] languageCode = RequestContextHolder.currentRequestAttributes().request.getHeader("Accept-    Language").split("-")
        Locale locale = languageCode.length == 2 ? new Locale(languageCode[0], languageCode[1]) : new Locale(languageCode[0])
       String message = defaultMessage
       try {
            message = messageSource.getMessage(input.code,input?.args?.toArray(),locale)
        }catch (NoSuchMessageException nsme ){
            log.info("No such error message--> ${nsme.getMessage()}")
        }
       return message
     }
    

Also, if you get exception below:

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

Then, you might need to add request listener to your web.xml

 <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
</listener>

Note: web.xml is not available by default, you need to generate it from template.

These are the most common places you might need message bundle conversions. Solution at point 4 would work in almost all cases. If you notice locale has been handled here manually which we could pass after fetching from requestHeader or request params optionally.

Hope it helps.

Vinay Prajapati
  • 7,199
  • 9
  • 45
  • 86
  • 1
    Locale you have accepted from Header as language and then converted to Locale instance. It could also be obtained using `SessionLocaleResolver` but not sure if it could be used with rest / soaps as these mostly are stateless. – Adesh Kumar Jan 06 '16 at 14:58