In this mini-post, I would share you a solution to “internationalize” your application due to Spring message source. This component allow the additional capabilities to the ApplicationContext interface which extends an interface called MessageSource, and therefore provides internationalization (i18n) functionalities.
Spring currently provides two MessageSource implementations: ResourceBundleMessageSource and StaticMessageSource, however, this latter implementation StaticMessageSource is rarely used but provides programmatic ways to add messages to the source. So, we will use the ReloadableResourceBundleMessageSource implementation.
In this post, I will expose only the configuration needed to implement message Resource. Then, I try to explain the use cases of MessageSource in Java class, JSP, Spring MVC validator or viewer. My examples are recovered from a project base on Spring MVC.
How to implement message Resource, follow the steps below:
- Step 1. Add the Message Source bean definition to the Spring Context Xml file
<!-- ################### SPRING APPLICATION MESSAGES PROPERTIES ################### --> <!-- Files concerned: --> <!-- /WEB-INF/ApplicationMessageSource_en_US.properties --> <!-- /WEB-INF/ApplicationMessageSource_fr_FR.properties --> <!-- /WEB-INF/ApplicationMessageSource_zh_CN.properties --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="defaultEncoding" value="UTF-8"/> <property name="basenames"> <list> <value>/WEB-INF/ApplicationMessageSource</value> </list> </property> </bean>
- Step 2. Add the beans definitions concerning the SPRING Support Internationalization.
To make Spring MVC application supports the internationalization, we need register 2beans :
SessionLocaleResolver
Register a “SessionLocaleResolver” bean, named it exactly the same characters “localeResolver“.
It resolves the locales by getting the predefined attribute from user’s session.
Note: If you do not register any “localeResolver”, the default AcceptHeaderLocaleResolver will be used,
which resolves the locale by checking the accept-language header in the HTTP request.<!-- ################### SPRING Support Internationalization ################### --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"> <property name="defaultLocale" value="en_US" /> </bean> <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> <property name="paramName" value="language" /> </bean>
LocaleChangeInterceptor
Register a “LocaleChangeInterceptor” interceptor and reference it to any handler mapping that need
to supports the multiple languages. The “paramName” is the parameter value that’s used to set the locale.In this case,
1.welcome.htm?language=en – Get the message from English properties file.
2.welcome.htm?language=zh_CN – Get the message from Chinese properties file.<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" > <property name="interceptors"> <list> <ref bean="localeChangeInterceptor" /> </list> </property> </bean>
- Step 3. Create 3 properties files to store English, French and Chinese messages:
ApplicationMessageSource_en_US.propertiesuser.list.form.title=Users' List book.list.form.title=Books' List of User user.add.form.title=Add a new user book.add.form.title=Add a new book field.required={0} is required! field.username=User Name
ApplicationMessageSource_fr_FR.properties
user.list.form.title=Liste des utilisateurs book.list.form.title=Liste des livres de l'utilisateur user.add.form.title=Ajouter un nouveau utilisateur book.add.form.title=Ajouter un nouveau livre field.required={0} est obligatoire! field.username=Nom Utilisateur
ApplicationMessageSource_zh_CN.properties
user.list.form.title=Users' List \u5feb\u4e50\u5b66\u4e60 book.list.form.title=Books' List of User \u5feb\u4e50\u5b66\u4e60 user.add.form.title=Add a new user \u5feb\u4e50\u5b66\u4e60 book.add.form.title=Add a new book \u5feb\u4e50\u5b66\u4e60 field.required={0} is required \u5feb\u4e50\u5b66\u4e60! field.username=User Name \u5feb\u4e50\u5b66\u4e60
How to use this message Resource in Java class, JSP, Spring MVC validator or viewer:
- In a simple java class, the messages are dipslayed from properties file:
public class MyExample { private MessageSource messages; public void setMessages(MessageSource messages) { this.messages = messages; } public void execute() { String message = this.messages.getMessage("field.required", new Object [] {"UserName"}, "Required", null); System.out.println(message); } }
- In a Web based application, we need a JSP page containing three hyperlinks which allow the change of the locale manually:
Language : <a href="?language=en_US">English</a> | <a href="?language=fr_FR">Français</a> | <a href="?language=zh_CN">快乐学习</a>
… the ${pageContext.response.locale} can be used to display the current user’s locale like:
Current user’s locale: ${pageContext.response.locale}<br/>
to display the message from the corresponds properties file by checking the current user’s locale.
And the messages are displayed from the corresponds properties file by checking the current user’s locale and using automatically the spring:message tag:
<u><spring:message code="user.list.form.title"/></u><br/> <a href="../user/create.htm"><img src="../img/adduser.png" border="0"/> <spring:message code="user.add.form.title"/></a> <a href="../user/pdflist.htm"><img src="../img/pdf.gif" border="0"/> <spring:message code="label.get.pdf.users.list"/></a>
- The use of MessageSource in the Spring MVC validator or viewer is similar to the simple Java class:
Validator
It’s an example of a validator that validates the data received from cliebt. Its declaration in configuration file could be like:<!-- SPRING MVC Data Validation --> <bean id="bookValidator" class="com.ho.persistence.hibernate.spring.ex1.web.validator.BookValidator"> <property name="messageSource" ref="messageSource" /><!-- Injection of MessageSource --> </bean>
…its use in Java code:
/** * Class for validation of input validation for the new user form. * @author huseyin * */ public class BookValidator implements Validator { // Spring Message Source private MessageSource messageSource; public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } public void validate(Object obj, Errors errors) { Book book = (Book) obj; /** * To add an error these parameters are needed: * - the concerned field name * - error message key * - default message if no message is not found for the key */ String nameField = this.messageSource.getMessage("field.name", new Object [] {}, null); String aboutbookField = this.messageSource.getMessage("field.about.book", new Object [] {}, null); // Validateur permet de sp�cifier des erreurs sur chaque propri�t� du formulaire if ( ! errors.hasFieldErrors("name")) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "field.required", new Object [] {nameField}, "Required field"); // validateur permet de sp�cifier des erreurs � un niveau global if( errors.hasErrors() ) { errors.reject("register.error"); } } ... }
Viewer
It’s an example of a viewer that generates a PDF. Its declaration in configuration file could be like:<!-- Book List View PDF --> <bean id="bookListPDFView" class="com.ho.persistence.hibernate.spring.ex1.web.view.BookListPdfReportView"> <property name="messageSource" ref="messageSource"/> <!-- Injection of MessageSource --> </bean>
…its use in Java code:
public class BookListPdfReportView extends AbstractPdfView { // Spring Message Source private MessageSource messageSource; public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } @Override protected void buildPdfDocument(Map model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { List<Book> bookList = (List<Book>) model.get("bookList"); // G�n�ration du PDF Table table = new Table(2); // Noms des colonnes renseign�s dans "ApplicationResources.properties" table.addCell(this.messageSource.getMessage("column.header.name", null, null)); table.addCell(this.messageSource.getMessage("column.header.about.book", null, null)); ... } }
-
Warning: The Spring MVC controller which “extends MultiActionController” doesn’t work with “ControllerClassNameHandlerMapping”.
To conclude, this post, I would add comments about the the UTF-8 encoding:
- First, remember put the “<%@ page contentType=”text/html;charset=UTF-8″ %>” on top of the page, else the page may not able to display the UTF-8 (Chinese) characters properly.
- Use the SPRING UTF-8 servlet filter CharacterEncodingFilter defined in the le web.xml in order to force the encoding.Be careful to position the filter in the first position in the list of different filters!
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter>
-
Convert your *.properties file with ‘non-Latin 1′ or ‘non-Unicode’ characters to ‘Unicode-encoded’ characters via “native2ascii” utility supported by the JDK. It is usable in command line like:
– “C:\Program Files (x86)\Java\jdk1.6.0_26\bin\native2ascii.exe” -encoding utf8 C:\MyFiles\Development\Java\dev\SpringHibernateIntegration1\WebContent\WEB-INF\ApplicationMessageSource_fr_FR.properties_no_unicode C:\MyFiles\Development\Java\dev\SpringHibernateIntegration1\WebContent\WEB-INF\ApplicationMessageSource_fr_FR.properties– “C:\Program Files (x86)\Java\jdk1.6.0_26\bin\native2ascii.exe” -encoding utf8 C:\MyFiles\Development\Java\dev\SpringHibernateIntegration1\WebContent\WEB-INF\ApplicationMessageSource_zh_CN.properties_no_unicode C:\MyFiles\Development\Java\dev\SpringHibernateIntegration1\WebContent\WEB-INF\ApplicationMessageSource_zh_CN.properties
Best regards,
With Spring3 you can just implement the MessageSourceAware interface, and skip the injection of messagesource in the context
Yes Somaiah, you are right!!!
Thanks for the article. I had trouble making chinese localization work.
One piece of advice: You don’t have to convert your property files.
Property files come in two flavors: .properties and as xml file. Xml files have an encoding, so you can just use plain UTF-8. This is an example:
查看消息
Nooooooo it removed all those nice xml tags. This site has an example:
http://www.kodejava.org/examples/267.html
Thank you Maruis for your message and the XML example.
Huseyin
Hello body, I saw you used a Chinese name ‘杨木金’, do you know him? ^_^ I think that guy is a great software engineer.
Hi, I don’t know this ‘famous person’, it’s simply a copy/paste action from internet (chinese text) 🙂