Sunday, August 1, 2021

Spring MessageSource Internationalization (i18n) Support

In an interview if difference between BeanFactory and ApplicationContext is asked one of the reason given by people to use ApplicationContext is the support for internationalization provided by ApplicationContext. This post shows the same thing; how Internationalization (i18n) using ApplicationContext and MessageSource can be provided in Spring.

Spring ApplicationContext and MessageSource

The ApplicationContext interface extends an interface called MessageSource in Spring framework which provides support for internationalization (i18n) functionality. Spring also provides the interface HierarchicalMessageSource, which can resolve messages hierarchically. Using these two interfaces Spring effects message resolution. The methods defined on these interfaces include:

  • String getMessage(String code, Object[] args, String default, Locale loc)- The basic method used to retrieve a message from the MessageSource. When no message is found for the specified locale, the default message is used. In the properties file it will look for the key which is having the same values as code parameter.
  • String getMessage(String code, Object[] args, Locale loc)- Essentially the same as the previous method, but with one difference: no default message can be specified; if the message cannot be found, a NoSuchMessageException is thrown.
  • String getMessage(MessageSourceResolvable resolvable, Locale locale)- All properties used in the preceding methods are also wrapped in a class named MessageSourceResolvable, which you can use with this method.

When an ApplicationContext is loaded, it automatically searches for a MessageSource bean defined in the context. The bean must have the name messageSource. If such a bean is found, all calls to the preceding methods are delegated to the message source.

There are two MessageSource implementations provided by Spring framework ResourceBundleMessageSource and StaticMessageSource. The StaticMessageSource is rarely used but provides programmatic ways to add messages to the source. ResourceBundleMessageSource can be configured as shown below.

<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">

Internationalization example in Spring using MessageSource

Here we’ll have two properties file format and error, for locale specific files you add the locale along with the file name. If you are having format file for locale UK (en_gb) and US (en_us) then you will create two files format_en_GB.properties and format_en_US.properties.

While defining the message source bean you just need to provide the base name (i.e. format or error) based on the passed locale correct properties file will be picked.

Configuration file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
  <bean id="messageSource"
      class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
      <list>
        <value>config/format</value>
        <value>config/error</value>
      </list>
    </property>
  </bean>    
</beans>

Since the properties folder are inside config folder thus the name config/format and config/error.

Internationalization (i18n) in Spring

format_en_GB.properties

dateformat=use date format dd/mm/yyyy

format_en_US.properties

dateformat=use date format mm/dd/yyyy

error_en_US.properties

argument.required=The {0} is required.

error_de.properties

argument.required=Der {0} ist erforderlich.

You can run it using the following code.

public class App {

 public static void main(String[] args) {
  
   AbstractApplicationContext context = new ClassPathXmlApplicationContext
           ("appcontext.xml");
   System.out.println("date format msg " + context.getMessage(
   "dateformat", null, Locale.UK));
  
   System.out.println("date format msg " + context.getMessage("
    dateformat", null, Locale.US));
  
   System.out.println("Name error msg " + context.getMessage("argument.required", 
          new Object[]{"Name"}, Locale.US));
   System.out.println("Name error msg " + context.getMessage("argument.required", 
          new Object[]{"Name"}, Locale.GERMANY));
  
   context.close();
 }
}

Output

date format msg use date format dd/mm/yyyy
date format msg use date format mm/dd/yyyy
Name error msg The Name is required.
Name error msg Der Name ist erforderlich.

Accessing MessageSource in Spring Bean Using MessageSourceAware interface

In the above example the message is resolved using the ApplicationContext but in most of the scenarios you would need to resolve a message with in a bean. For that bean should implement the MessageSourceAware interface and use its setMessageSource() method to set the defined MessageSource.

Spring Example using MessageSourceAware

public class TestService implements MessageSourceAware {
 
 private MessageSource messageSource;
 @Override
 public void setMessageSource(MessageSource messageSource) {
  this.messageSource = messageSource;

 } 
 public void displayMessage(){

  System.out.println("Name error msg " + messageSource.getMessage("
                      argument.required", new Object[]{"Name"}, Locale.US));
  System.out.println("Name error msg " + messageSource.getMessage("
                      argument.required", new Object[]{"Name"}, Locale.GERMANY));
 }
}

The configuration you need to add for this bean is as follows.

<bean id="testService" class="org.netjs.config.TestService">
    <property name="messageSource" ref="messageSource" />
</bean>

You can run it using the following code.

public class App {
  public static void main(String[] args) {
    AbstractApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
   
    TestService testService = context.getBean("testService", TestService.class);
    testService.displayMessage();
  
    context.close();
  }
}

Which gives following output-

Name error msg The Name is required.
Name error msg Der Name ist erforderlich.

That's all for this topic Spring MessageSource Internationalization (i18n) Support. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Dependency Injection Using factory-method in Spring
  2. Wiring Collections in Spring
  3. How to Inject Null And Empty String Values in Spring
  4. @Import Annotation in Spring JavaConfig
  5. How to Inject Prototype Scoped Bean in Singleton Bean

You may also like-

  1. Spring Profiles With Examples
  2. JDBCTemplate with ResultSetExtractor Example in Spring
  3. ServiceLocatorFactoryBean in Spring
  4. Benefits, Disadvantages And Limitations of Autowiring in Spring
  5. How HashSet Works Internally in Java
  6. Garbage Collection in Java
  7. StringBuilder Class in Java With Examples
  8. super Keyword in Java With Examples

No comments:

Post a Comment