Spring MVC Internationalization and Localization

Internationalization:

It is the process of developing an application in such a way that it enables the localization.
For example : Application must support to have a separate messages.properties files for each locale/region.

Localization:

It is the process of adopting an internationalized application to specific regions/locales.
We can write locale specific details in the corresponding property files.

Ex : US locale specific details can be added inside messages_en.properties and German locale specific details can be added inside messages_de.properties.

Localization is very important for any web application which can be accessible in different regions.
So that users of specific regions can feel the application, user friendly and convenient within their language itself.

When the application is accessed by US users , web application displays the messages in the US language.
When the application is accessed by German users , web application displays the messages in the German language.

To enable the internationalization in spring MVC. We need to register below 3 beans in the spring context.

1 ) MessageSource

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

ReloadableResourceBundleMessageSource bean enables the internationalization (i18N).
basename property is used to provide the location of resource bundles.
value specifies that resource bundles are located at messages_{locale}.properties.
defaultEncoding specifies the encoding used for the messages.

2)LocaleResolver

Resolves the locale based on its implementation.
It has 3 implementations

a)SessionLocaleResolver:

resolves the locale based on the predefined attribute in the session.

b)CookieLocaleResolver :

resolves the locale based on the predefined attribute in the cookie.

c)AcceptHeaderLocaleResolver :

default implementation which resolves the locale by checking accept-language header in the HTTP request.

If we don’t define any locale resolvers , spring by default takes AcceptHeaderLocaleResolver.

Lets implement SessionLocaleResolver in our application.

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

3) LocaleChangeInterceptor

This interceptor intercept the HTTP request and checks for the special parameter in the request.
The name of the parameter that it has to check in the request can be specified by the property called paramName, its value will be searched in the HTTP request by this interceptor.

1
2
3
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="language" />
</bean>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="language" />
</bean>

So here , it searches for the parameter language in the HTTP request.
Its value in the request is the locale value which it will add in the place of {locale} in the line messages_ {locale} and seraches for the corresponding messages property file.


Lets create the Spring MVC project for 2 locales , US and Germany.

Project structure

Create the 2 messages.properties files one for each locale.

messages_en.properties

1
2
3
4
5
6
label.userName=User Name
label.password = Password
label.login.header=Enter below details to login
label.login.submit=Submit
login.success.title = Login Success
login.success.welcome = Welcome {0}
label.userName=User Name
label.password = Password
label.login.header=Enter below details to login
label.login.submit=Submit
login.success.title = Login Success
login.success.welcome = Welcome {0}

messages_de.properties

1
2
3
4
5
6
label.userName= Benutzername
label.password = Passwort
label.login.header=eingeben unten Einzelheiten bis Einloggen
label.login.submit=einreichen
login.success.title Einloggen Erfolg
login.success.welcome = willkommen {0}
label.userName= Benutzername
label.password = Passwort
label.login.header=eingeben unten Einzelheiten bis Einloggen
label.login.submit=einreichen
login.success.title Einloggen Erfolg
login.success.welcome = willkommen {0}

Create spring configuration file by adding beans required to enable Internationalization.

Spring-mvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
 
    <context:component-scan base-package="com.kb.*" />
    <mvc:annotation-driven />
 
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    </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>
</beans>
<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

	<context:component-scan base-package="com.kb.*" />
	<mvc:annotation-driven />

	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/" />
		<property name="suffix" value=".jsp" />
	</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>
</beans>

Now Define the View pages

login.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<head>
<title>Spring MVC Exception Handling</title>
</head>
 
<body>
    <h2><spring:message code="label.login.header"/></h2>
 
    <form:form method="POST" modelAttribute="user" action="doLogin">
        <table>
            
            <tr>
                <td><spring:message code="label.userName"/></td>
                <td><form:input path="userName" /></td>
            </tr>
            
            <tr>
                <td><spring:message code="label.password"/></td>
                <td><form:password path="password"  showPassword="true"/></td>
            </tr>
            
            <tr>
                <td><input type="submit" name="submit" value=<spring:message code="label.login.submit"/>></td>
            </tr>
        </table>
    </form:form>
 
</body>
</html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<head>
<title>Spring MVC Exception Handling</title>
</head>

<body>
	<h2><spring:message code="label.login.header"/></h2>

	<form:form method="POST" modelAttribute="user" action="doLogin">
		<table>
			
			<tr>
				<td><spring:message code="label.userName"/></td>
				<td><form:input path="userName" /></td>
			</tr>
			
			<tr>
				<td><spring:message code="label.password"/></td>
				<td><form:password path="password"  showPassword="true"/></td>
			</tr>
			
			<tr>
				<td><input type="submit" name="submit" value=<spring:message code="label.login.submit"/>></td>
			</tr>
		</table>
	</form:form>

</body>
</html>

home.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title><spring:message code="login.success.title"/></title>
</head>
<body>
 <div align="center">
       <h2><spring:message code="login.success.welcome" arguments="${user.userName}"/></h2>
  </div>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title><spring:message code="login.success.title"/></title>
</head>
<body>
 <div align="center">
       <h2><spring:message code="login.success.welcome" arguments="${user.userName}"/></h2>
  </div>
</body>
</html>

Here this line

1
 <spring:message code="key in property file"/> 
 <spring:message code="key in property file"/> 

loads the property from the corresponding message property file based on the language parameter passed.

LoginController.java to handle login requests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.kb.controllers;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
import com.kb.model.User;
 
@Controller
public class LoginController {
 
    @RequestMapping(value="/displayLoginPage",method=RequestMethod.GET)
    public String displayLoginPage(Model model){
        User user = new User();
        model.addAttribute("user", user);
        return "/login";
    }
    
    @RequestMapping(value="/doLogin",method=RequestMethod.POST)
    public String doLogin(@ModelAttribute User user,Model model){
        
        String userName=user.getUserName();
        String password = user.getPassword();
        if("kb".equals(userName) && "1234".equals(password)){
            model.addAttribute("user", user);
            return "/home";
        }
        return "/login";
        
    }
    
}
package com.kb.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.kb.model.User;

@Controller
public class LoginController {

	@RequestMapping(value="/displayLoginPage",method=RequestMethod.GET)
	public String displayLoginPage(Model model){
		User user = new User();
		model.addAttribute("user", user);
		return "/login";
	}
	
	@RequestMapping(value="/doLogin",method=RequestMethod.POST)
	public String doLogin(@ModelAttribute User user,Model model){
		
		String userName=user.getUserName();
		String password = user.getPassword();
		if("kb".equals(userName) && "1234".equals(password)){
			model.addAttribute("user", user);
			return "/home";
		}
		return "/login";
		
	}
	
}

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
 
    <display-name>Spring Localization</display-name>
 
    <!-- Spring MVC dispatcher servlet -->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
            /WEB-INF/spring-mvc.xml,
        </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">

	<display-name>Spring Localization</display-name>

	<!-- Spring MVC dispatcher servlet -->
	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
			/WEB-INF/spring-mvc.xml,
		</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Spring</groupId>
  <artifactId>Spring_Localization</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>Spring_Localization Maven Webapp</name>
  <url>http://maven.apache.org</url>
   <properties>
        <org.springframework.version>4.2.0.RELEASE</org.springframework.version>
    </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>javax.servlet.jsp.jstl-api</artifactId>
    <version>1.2.1</version>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
  </dependencies>
  <build>
    <finalName>SpringLocalization</finalName>
    <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
  </build>
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Spring</groupId>
  <artifactId>Spring_Localization</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>Spring_Localization Maven Webapp</name>
  <url>http://maven.apache.org</url>
   <properties>
		<org.springframework.version>4.2.0.RELEASE</org.springframework.version>
	</properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
	<groupId>javax.servlet.jsp.jstl</groupId>
	<artifactId>javax.servlet.jsp.jstl-api</artifactId>
	<version>1.2.1</version>
</dependency>
<dependency>
	<groupId>taglibs</groupId>
	<artifactId>standard</artifactId>
	<version>1.1.2</version>
</dependency>
  </dependencies>
  <build>
    <finalName>SpringLocalization</finalName>
    <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
  </build>
</project>

Now Localization is done in the application.

Spring looks for the parameter language in the HTTP request as we configured.
And loads the corresponding message property file.

Deploy the application and Let’s access below url

http://localhost:8080/SpringLocalization/displayLoginPage

Here in the Request URL, we have not passed the configured locale parameter, so it takes default as en as we have specified in spring configuration file.

Input username as kb and password as 1234

see below output

Now try to pass the German locale in the HTTP request as below

http://localhost:8080/SpringLocalization/displayLoginPage?language=de

All the messages in this page are appearing in German language as they are getting loaded by messages_de.properties file.

Input username as kb and password as 1234

Click on submit

Now try to access the below url where we are not passing language parameter and check the output

http://localhost:8080/SpringLocalization/displayLoginPage

The output is shown in the German locale, even though we have not passed the language=de parameter in the second request, It still refers to language as de.

This is happening because of our SessionLocaleResolver which keeps the current locale throughout the session if we don’t pass any locale explicitly.

How to load the property from messages property file in the java file ?

We need to autowire MessageSource inside the java class where we need to load the property and we can access the required property as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Controller
public class LoginController {
    
    @Autowired
    MessageSource messageSource;
 
    @RequestMapping(value="/displayLoginPage",method=RequestMethod.GET)
    public String displayLoginPage(Model model){
        User user = new User();
        model.addAttribute("user", user);
        return "/login";
    }
    
    @RequestMapping(value="/doLogin",method=RequestMethod.POST)
    public String doLogin(@ModelAttribute User user,Model model){
        
        String userName=user.getUserName();
        String password = user.getPassword();
        if("kb".equals(userName) && "1234".equals(password)){
            model.addAttribute("user", user);
            return "/home";
        }
        String loginSuccessWelcome = messageSource.getMessage("login.success.welcome", new Object[]{user.getUserName()}, LocaleContextHolder.getLocale());
        System.out.println(loginSuccessWelcome);
        return "/login";
        
    }
@Controller
public class LoginController {
	
	@Autowired
	MessageSource messageSource;

	@RequestMapping(value="/displayLoginPage",method=RequestMethod.GET)
	public String displayLoginPage(Model model){
		User user = new User();
		model.addAttribute("user", user);
		return "/login";
	}
	
	@RequestMapping(value="/doLogin",method=RequestMethod.POST)
	public String doLogin(@ModelAttribute User user,Model model){
		
		String userName=user.getUserName();
		String password = user.getPassword();
		if("kb".equals(userName) && "1234".equals(password)){
			model.addAttribute("user", user);
			return "/home";
		}
		String loginSuccessWelcome = messageSource.getMessage("login.success.welcome", new Object[]{user.getUserName()}, LocaleContextHolder.getLocale());
		System.out.println(loginSuccessWelcome);
		return "/login";
		
	}

messageSource.getMessage method is called by passing below arguments

1)Key in the property file , in our case it is login.success.welcome
2)Argument that needs to be added dynamically to the property value , in our case we have just one argument userName
3)Locale – the locale from which it has to load the property.

Now when we run the above project with this controller and access the home page
We will get the property value loaded from the corresponding locale as below

Download this project Spring_Localization.zip

About the Author

Karibasappa G C (KB)
Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on