Monday 17 April 2017

How to implement Localization in Spring application

Details given below includes Thymeleaf integration but you can use the framework that applies to  your application.
Following are certain requirements that are needed
Ø  Spring
Ø  Properties Files
Examples:
messages_en.properties - English
wellcome.world = Hello World !
 
                   fileName should have undrescore '_' and place it on classpath. Supported formats and codes can be found in : http://www.oracle.com/technetwork/java/javase/javase7locales-334809.html

Spring Configuration
Ø  SessionLocaleResolver
Register a "SessionLocaleResolver" bean, name it exactly the same characters "localeResolver". It resolves the locales by getting the predefined attribute from user's session.
Ø  LocaleChangeInterceptor
Register a "LocaleChangeInterceptor" interceptor and refer it to any handler mapping that need to support multiple languages. The "paramName" is the parameter value that's used to set the locale.

In dispatcher-servlet.xml add the below ones.
<bean id="localeResolver"
 class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
                             <property name="defaultLocale" value="en" />
</bean>
//paramName - name of the url parameter to hold the locale variable
<bean id="localeChangeInterceptor"
 class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
 <property name="paramName" value="language" />
</bean>
<mvc:interceptors>
          <mvc:interceptor>
                    <mvc:mapping path="/**" />
                   <mvc:exclude-mapping path="/css/**" />
                    <mvc:exclude-mapping path="/js/**" />
                    <mvc:exclude-mapping path="/bootstrap/**" />
                   <mvc:exclude-mapping path="/img/**" />
                   <mvc:exclude-mapping path="/fonts/**" />
                   <bean class="com..sk.tol.base.view.config.UserInterceptor" />
          </mvc:interceptor>
 <ref bean="localeChangeInterceptor"/>
</mvc:interceptors>


This will enable us to change locale simply by passing language parameter in url:
<a href="?language=en">English</a>

Below things needs to be taken care of

LocaleUtils.java
     Just write a utility class which help us to obtain various locale based formats, patterns.
jQuery Datepicker
     Properties Files
jQuery Datepicker has its own objects with language settings, like name of the days, months, etc... which are defined in separate.js files and we need to include corresponding script of every language that we will be using in the application.
<script src="js/jquery.wait.js" th:src="@{/js/locales/bootstrap-datepicker.sk.min.js}"></script>
<script src="js/jquery.wait.js" th:src="@{/js/locales/bootstrap-datepicker.en-GB.min.js}"></script>


LocaleSettings html element
We have to define one invisible element that will hold various locale related information, so we can access it from html, javaScript/jQuery.
 Place it somewhere on top of html hierarchy, so you can access it from every page you need to. In the code below you can see that we are storing the information in html data attributes with the help of Thymeleaf 'th:attr' to call our LocaleUtil java class.
<div id="localeSettings" class="ext-default-hidden"
  th:attr="data-decimal-separator=${@localeUtil.getDecimalSeparator()}, data-thousands-separator=${@localeUtil.getGroupingSeparator()}, data-locale=${#ctx.locale}">
</div>


Initialization and use
When initializing datecipicker, we only need to provide it with locale code, that we can take from our localeSetting element:
var locale = $("#localeSettings").data("locale");
$('.ext-datepicker,#ext-datepicker').datepicker({
 orientation: "bottom auto",
          language: locale
})

The property file  should hold datepicker.date.format  property name and for English language with its message_en.properties file: datepicker.date.format=M d, yyyy

Assigning the format to datepicker element through thymeleaf
<div th:attr="data-date-format=#{datepicker.date.format}" class="ext-datepicker input-append date input-group">
 <input type="datetime" class="span2 form-control ext-readonly-white add-on" th:field="*{createDateFrom}" />
          <div class="input-group-addon add-on">
                    <i class="fa fa-calendar"></i>
 </div>
</div>


jQuery inputmask
Example of Initialization of inputmask for all elements with class "positive-amount-nullable":
var cfgDefaults =
 {
  thousandsSeparator: ",",
           decimalSeparator: "."
 };
function init(){
          var $elm = $("#localeSettings");
          cfgDefaults.decimalSeparator = $elm.data("decimal-separator");
          cfgDefaults.thousandsSeparator = $elm.data("thousands-separator");
};
$(".positive-amount-nullable").off("inputmask").inputmask("currency",
 {
           removeMaskOnSubmit: true,
           placeholder: " ",
          prefix: "",
          allowPlus: false,
          allowMinus: false,
          groupSeparator: cfgDefaults.thousandsSeparator,
          radixPoint: cfgDefaults.decimalSeparator
 }
);


Now we only need to assign css class "positive-amount-nullable" to input we want to get formatted. Example:
  <input type="text" class="form-control positive-amount-nullable" th:field="*{transactionAmount}" />


Serialization / Deserialization in dto's date fields
To enable spring automatic serialization/deserialization just annotate the Date fields as follows. You can use provided custom (de)serializers.
 You can also make your own (de)serializers by extending one of AJsonLocaleDateSerializer.java or AJsonLocaleDateDeserializer.java
 See java.text.DateFormat for more info on the formats used.
@DateTimeFormat(style = "M-")
@JsonSerialize(using = JsonLocaleDateSerializer.class)
@JsonDeserialize(using = JsonLocaleDateDeserializer.class)
private Date transactionDate;

@DateTimeFormat(pattern = "HH:mm")
@JsonSerialize(using = JsonLocaleTimeSerializer.class)
@JsonDeserialize(using = JsonLocaleTimeDeserializer.class)
private Date transactionTime;

@JsonSerialize(using = JsonLocaleDateTimeSerializer.class)
@JsonDeserialize(using = JsonLocaleDateTimeDeserializer.class)
private Date transactionDateTime;


Examples of getting various info on locales
Here are example of various information we can get on front-end by using thymeleaf
<div class="active" th:text="${#ctx.locale}">Current Locale from context from session</div>
<div class="active" th:text="${#dates.createNow()}">Thymeleaf dates utility - gets current Date</div>
<div class="active" th:text="${@localeUtil.formatDate(#dates.createNow())}">Current date formatted by LocaleUtil.java</div>
<div class="active" th:text="${@localeUtil.getDateFormatPattern()}">Get date pattern from LocaleUtil.java</div>
<div class="active" th:text="${@localeUtil.formatTime(#dates.create(2016,9,5,15,45,30,231))}">Current time formatted by LocaleUtil.java</div>
<div class="active" th:text="${@localeUtil.getTimeFormatPattern()}">Get time pattern from LocaleUtil.java</div>


Get current Locale in spring MVC controller
@RequestMapping(value = { "/method" }, method = RequestMethod.GET)
public String someControllerMethod(ExampleDto dto, HttpSession session, Model m, Locale locale ) {

 // Implementation code ...

 return "someResult";
}


The current Locale can be accessed in java code by following way
Locale locale = org.springframework.context.i18n.LocaleContextHolder.getLocale();

No comments:

Post a Comment