Spring - I18n

springmvc

https://www.youtube.com/watch?v=lD0VkLf1kG4

// Spring MVC - i18n

For complicated cases, look at how Laravel handle internationalization
or how Meteor handle internationalization.

Add to the application context configuration file:

<bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
    <property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <property name="defaultLocale" value="en" />
</bean>
<mvc:interceptors>
    <bean id="localeChangeInterceptor"
        class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        <property name="paramName" value="language" />
    </bean>
</mvc:interceptors>

Add the messages files (/src/main/resources/messages_en.properties):

welcome.message=Welcome in English
todo.caption= Todo Caption in English

Add to JSP file:

<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<spring:message code="todo.caption" />

<fmt:setLocale value="en"/>
<fmt:setBundle basename="com.tutorialspoint.Example" var="lang"/>
<fmt:message key="count.one" bundle="${lang}"/><br/>
<fmt:message key="count.two" bundle="${lang}"/><br/>

Spring support for internationalization (i18n) through the use of Interceptors, 
Locale Resolvers and Resource Bundles.  

For simplicity, let’s assume that our application supports only two locales – 
en and fr. If no user locale is specified, we will use english as default locale. 
Let’s create spring resource bundles for both these locales that will be used in 
the JSP page.

//messages_en.properties code:
label.title=Login Page
label.firstName=First Name
label.lastName=Last Name
label.submit=Login

//messages_fr.properties code:
label.title=Connectez-vous page
label.firstName=Pr\u00E9nom
label.lastName=Nom
label.submit=Connexion

Note that we are using unicode for special character in the french locale
resource bundles, so that it gets interpreted properly.  Both resource bundles
are in the classpath of the application.

In the JSP, we reference a particular message:

<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<spring:message code="label.firstName" />

Spring takes care of loading the appropriate resource bundle messages and make 
it available for the JSP pages to use.

Spring Bean configuration file is the place where all the magic happens. This 
is the beauty of Spring framework as it helps us to focus more on business logic 
rather than coding for trivial tasks. Let’s see how our spring bean configuration 
file looks and we will look at each of the beans one be one.

<beans:bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <beans:property name="basename" value="classpath:messages" />
    <beans:property name="defaultEncoding" value="UTF-8" />
</beans:bean>

<beans:bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <beans:property name="defaultLocale" value="en" />
    <beans:property name="cookieName" value="myAppLocaleCookie"></beans:property>
    <beans:property name="cookieMaxAge" value="3600"></beans:property>
</beans:bean>

<interceptors>
    <beans:bean
            class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <beans:property name="paramName" value="locale" />
    </beans:bean>
</interceptors>

messageSource bean is configured to enable i18n for our application. basename 
property is used to provide the location of resource bundles. classpath:messages 
means that resource bundles are located in the classpath and follows name 
pattern as messages_{locale}.properties. defaultEncoding property is used to 
define the encoding used for the messages.

The org.springframework.web.servlet.i18n.CookieLocaleResolver is used to set a 
cookie in the client request so that further requests can easily recognize the 
user locale. For example, we can ask user to select the locale when he launches 
the web application for the first time and with the use of cookie, we can 
identify the user locale and automatically send locale specific response. We 
can also specify the default locale, cookie name and maximum age of the cookie 
before it gets expired and deleted by the client browser.

If your application maintains user sessions, then you can also use 
org.springframework.web.servlet.i18n.SessionLocaleResolver as localeResolver to 
use a locale attribute in the user’s session. The configuration is similar to 
CookieLocaleResolver.

<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <property name="defaultLocale" value="en" />
</bean>

If we don’t register any “localeResolver”, AcceptHeaderLocaleResolver will be 
used by default, which resolves user locale by checking the accept-language 
header in the client HTTP request.

org.springframework.web.servlet.i18n.LocaleChangeInterceptor interceptor is 
configured to intercept the user request and identify the user locale. The 
parameter name is configurable and we are using request parameter name for 
locale as “locale”. Without this interceptor, we won’t be able to change the 
user locale and send the response based on the new locale settings of the user. 
It needs to be part of interceptors element otherwise Spring won’t configure it 
as an interceptor.

Locale.getDefault()
NumberFormat.getInstance().format(321.24f); // Using the default locale
NumberFormat.getInstance(new Locale(“nl”)).format(4032.3f);
NumberFormat.getInstance(new Locale.GERMANY).format(4032.3f); // There are predefined locales
NumberFormat.getCurrencyInstance().format(321.24f); // Format currency
NumberFormat.getCurrentyInstance(Locale.CHINA).format(321.24f); // Format currency
// Control the number of digits after the dot
NumberFormat numberFormat = NumberFormat.getInstance();
numberFormat.setMaximumFractionDigits(3);
numberFormat.format(12.1234f)

What are the overall steps that we have to do in order to implement i18n?

  1. Add messageSource, localeResolver beans and mvc:interceptor tag to our application context configuration file
  2. Add the message files to the resources folder. The message files should have name such as messages_en.properties, or message_fr.properties.

What are the things that we have to add to our application context configuration file in order to implement i18n?

We have to add the messageSource, localeResolver beans and the mvc:intercepter tag to our application context configuration file (/src/main/webapp/WEB-INF/todo-servlet.xml):

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.in28minutes" />

    <mvc:annotation-driven />

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
        <property name="defaultLocale" value="en" />
    </bean>

    <mvc:interceptors>
        <bean id="localeChangeInterceptor"
            class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="language" />
        </bean>
    </mvc:interceptors>

    <mvc:resources mapping="/webjars/**" location="/webjars/" />

</beans>

/src/main/webapp/WEB-INF/views/common/header.jspf:

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<html>
<head>
<title>Todos Application</title>
<link href="webjars/bootstrap/3.3.6/css/bootstrap.min.css"
    rel="stylesheet">
</head>

<body>

/src/main/resources/messages_en.properties:

welcome.message=Welcome in English
todo.caption= Todo Caption in English

Somewhere in our JSP:

<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<spring:message code="todo.caption" />

How can we use the <fmt:message> tag?

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
<head>
<title>JSTL fmt:message Tag</title>
</head>
<body>

<fmt:setLocale value="en"/>
<fmt:setBundle basename="com.tutorialspoint.Example" var="lang"/>

<fmt:message key="count.one" bundle="${lang}"/><br/>
<fmt:message key="count.two" bundle="${lang}"/><br/>
<fmt:message key="count.three" bundle="${lang}"/><br/>

</body>
</html>
  1. key: Message key to retrieve (Required: No, Default: Body)
  2. bundle: Resource bundle to use (Required: No, Default: Default bundle)
  3. var: Name of the variable to store the localized message (Required: No, Default: Print to page)
  4. scope: Scope of the variable to store the localized message (Required: No, Default: Page)

In the above code, we call setLocale, and setBundle before using <fmt:message>

How can we determine the default locale?

Locale.getDefault()

How can we use the NumberFormat class to format number according to different locale?

NumberFormat.getInstance().format(321.24f); // Using the default locale
NumberFormat.getInstance(new Locale(“nl”)).format(4032.3f);
NumberFormat.getInstance(new Locale.GERMANY).format(4032.3f); // There are predefined locales

How can we use the NumberFormat class to format currency according to different locale?

NumberFormat.getCurrencyInstance().format(321.24f);
NumberFormat.getCurrentyInstance(Locale.CHINA).format(321.24f);

How can we use the NumberFormat class to control the number of digits after the dot?

NumberFormat numberFormat = NumberFormat.getInstance();
numberFormat.setMaximumFractionDigits(3);
numberFormat.format(12.1234f)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License