Tuesday, September 18, 2012

Spring 3 MVC Internationalization & Localization (i18n & l10N) and Reloader

In this post I will discuss about Internationalization (I18N) and Localization (L10N) in Spring 3.0 MVC. 

What is i18n and L10n?

In computing, internationalization and localization are means of adapting computer software to different languages and regional differences. Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting internationalized software for a specific region or language by adding locale-specific components and translating text.
The terms are frequently abbreviated to the numeronyms i18n (where 18 stands for the number of letters between the first i and last n in internationalization) and L10n respectively, due to the length of the words. The capital L in L10n helps to distinguish it from the lowercase i in i18n. Let's begin:


First we must create our properties files. For example when I configured spring I have used '<mvc:resources mapping="/resource/**" location="/resource/" />', this handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory. So I have created my properties files in directory resources/messages/ folder.

  1. messages.properties
  2. messages_az.properties
  3. messages_ru.properties
Second we need to declare these files in spring configuration file. We will use class org.springframework.context.support.ReloadableResourceBundleMessageSource to define the message resources. Also, note that we will provide a feature where user will be able to select language for the application. This is implemented by using org.springframework.web.servlet.i18n.LocaleChangeInterceptor class. The LocaleChangeInterceptor class will intercept any changes in the locale. These changes are then saved in cookies for future request. org.springframework.web.servlet.i18n.CookieLocaleResolverclass will be used to store the locale changes in cookies.
Open your <applicationdispatchername>-servlet.xml config file and add following bean definitions:
    <!-- Will help us to change locale for "lang" param, example: ?lang=az -->
 <mvc:interceptors>
     <mvc:interceptor>
         <mvc:mapping path="/**"/>
         <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="lang" />
   </bean>
     </mvc:interceptor>
 </mvc:interceptors>
 
 
 <!--
  - i18n configurations
  - basename : path to properties
  - fallbackToSystemLocale : will use messages.properties if no one found requested locale
 -->
 <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
     <property name="basename" value="/resource/messages/messages" />
     <property name="fallbackToSystemLocale" value="false"/>
     <property name="defaultEncoding" value="UTF-8"/>
 </bean>
 
 <!-- i18n configurations: which i18n resolver we want use CookieLocaleResolver or SessionLocaleResolver -->
 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
     <!-- <property name="defaultLocale" value="az"/> -->
 </bean>

Third create any jsp page to test your i18n configs :)
<%@taglib uri="http://www.springframework.org/tags" prefix="s"%>
 
<h3><s:message code="label.title"/></h3><br>

<a href="?lang=en">en</a> | <a href="?lang=az">az</a> | <a href="?lang=ru">ru</a>

That is all. But if u use this on production and u want change text in properties then u must restart server. To prevent that u can use <property name="cacheSeconds" value="0" /> property for your messageSource bean definition. In this case on every request messages will cleared from cache and will loaded again. So this is not what we want. And how we can do it?
For example I have wrote one Controller for that. And I want share this controller with u :)
package com.handysofts.stereotypes.controller;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

/**
 * This controller class written for reload language.
 * When u change message properties files, on interface it will be old one,
 * because spring loads messages to cash and save it there. So when u change
 * your properties simple call URL "/reloadlang" and it will load new one texts :)
 * 
 * 
 * @author Vasif Mustafayev
 *
 */

@Controller
public class ReloadLangController {
 
 private static Logger log = Logger.getLogger(ReloadLangController.class);
 
 @Autowired
 ReloadableResourceBundleMessageSource messageSource;
 
 @RequestMapping("/reloadlang")
 public String showMainPage(){
  log.info("=============== RELOAD LANGUAGE ===============");
  messageSource.clearCache();
  return "redirect:/";
 }

}

So this helps u when u want change properties files without restart. Only u need save your properties file and then call URL: "http://<your web project url>/reloadlang" and be happy :)

3 comments:

  1. For best localization results I recommend you use this online software: https://poeditor.com/. It's one of the best.

    ReplyDelete
  2. In case you want to use java configuration for i18 and l10, find the link.

    ReplyDelete