Internationalization (i18n) is the process of designing a software application so that it can potentially 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.
Spring framework is shipped with LocaleResolver and MessageSource interfaces to support internationalization and thus localization as well. The beans of these types allow the application to access String resources, called messages, stored in a variety of languages.
To implement i18n, for each language you maintain a list of messages in language-specific property files with identical keys. We get a localized message using the message key, and Spring returns the message from language-specific property file.
Let’s start analyzing the changes that you will need to make to add i18n support to your spring web application.
Step 1: Add Locale-specific Message Resources
If you want to support multiple locales, then the first step is to have each locale-specific properties file have texts in that locale-specific language.
In our example, I am supporting two locales. The first is the United States with language English, and the second locale is Chinese. The US locale is the default.
/src.main/resources/messages.properties
lbl.Id=Employee Id
lbl.firstName=First Name
lbl.lastName=First Name
lbl.page=All Employees in System
/src.main/resources/messages_zh_CN.properties
lbl.Id=\u5458\u5DE5ID
lbl.firstName=\u540D\u5B57
lbl.lastName=\u59D3
lbl.page=\u7CFB\u7EDF\u4E2D\u7684\u6240\u6709\u5458\u5DE5
Notice the naming convention for these property files. Locale-specific files have locale short-code appended to their name.
Additionally, define the base name of the message bundle files in application.properties file.
spring.messages.basename=messages
Step 2: Adding LocaleResolver Bean
To make the Spring MVC application support internationalization, you will need to register two beans.
2.1. SessionLocaleResolver
SessionLocaleResolver resolves locales by inspecting a predefined attribute in a user’s session. If the session attribute doesn’t exist, this locale resolver determines the default locale from the accept-language
HTTP header.
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.US); // Set the default locale
return localeResolver;
}
2.2. LocaleChangeInterceptor
LocaleChangeInterceptor interceptor detects if a special parameter is present in the current HTTP request. The parameter name can be customized with the paramName
property of this interceptor. If such a parameter is present in the current request, this interceptor changes the user’s locale according to the parameter value.
The default parameter name is ‘locale‘.
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang"); // Set the request parameter name to change the locale
return interceptor;
}
The complete application context file for this application looks like this:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import java.util.Locale;
@Configuration
public class WebConfig implements WebMvcConfigurer {
// Define the LocaleResolver bean
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.US); // Set the default locale
return localeResolver;
}
// Define the LocaleChangeInterceptor bean
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang"); // Set the request parameter name to change the locale
return interceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// Register the LocaleChangeInterceptor
registry.addInterceptor(localeChangeInterceptor());
}
}
Step 3: View Template Changes to Display Locale-specific Messages
The next step is to make view changes to support displaying locale-specific text messages. This example uses JSPs so it can be done using spring TLDs in the below manner. Notice the use of ‘spring:message‘ tags to print the messages.
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>Spring MVC Hello World</title>
</head>
<body>
<h2><spring:message code="lbl.page" text="All Employees in System" /></h2>
<table border="1">
<tr>
<th><spring:message code="lbl.Id" text="Employee Id" /></th>
<th><spring:message code="lbl.firstName" text="First Name" /></th>
<th><spring:message code="lbl.lastName" text="Last Name" /></th>
</tr>
<c:forEach items="${employees}" var="employee">
<tr>
<td>${employee.id}</td>
<td>${employee.firstName}</td>
<td>${employee.lastName}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
Step 4: Accessing Localized Messages in Controller
While sending API responses, if you want to access the localized messages, you can inject the MessageSource bean in the controller class and use messageSource.getMessage() method.
The following is a sample controller class that access the localized messages in API controller.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Locale;
@Controller
public class GreetingController {
@Autowired
private MessageSource messageSource;
@GetMapping("/greeting")
public String greeting(@RequestParam(name = "locale", required = false) String localeParam, Model model) {
Locale locale = Locale.getDefault();
if (localeParam != null && !localeParam.isEmpty()) {
locale = new Locale(localeParam);
}
String greetingMessage = messageSource.getMessage("greeting", null, "Default Greeting", locale);
model.addAttribute("greeting", greetingMessage);
return "greeting";
}
}
Step 5: Test the Application
Hit the URL: http://localhost:8080/springmvcexample/employee-module/getAllEmployees
As you see that all labels are displayed in English language.

Now hit the URL: http://localhost:8080/springmvcexample/employee-module/getAllEmployees?lang=zh_CN
Now, the locale has been changed to Chinese and all labels are displayed in Chinese language.

Other Project Files
EmployeeController.java
@Controller
@RequestMapping("/employee-module")
public class EmployeeController
{
@Autowired
EmployeeManager manager;
@RequestMapping(value="/getAllEmployees", method = RequestMethod.GET)
public String welcome(Model model)
{
model.addAttribute("employees",manager.getAllEmployees());
return "employeesListDisplay";
}
EmployeeDAO.java
import java.util.List;
import com.howtodoinjava.demo.model.EmployeeVO;
public interface EmployeeDAO
{
public List<EmployeeVO> getAllEmployees();
}
EmployeeDAOImpl.java
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.howtodoinjava.demo.model.EmployeeVO;
@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
public List<EmployeeVO> getAllEmployees()
{
List<EmployeeVO> employees = new ArrayList<EmployeeVO>();
EmployeeVO vo1 = new EmployeeVO();
vo1.setId(1);
vo1.setFirstName("Lokesh");
vo1.setLastName("Gupta");
employees.add(vo1);
EmployeeVO vo2 = new EmployeeVO();
vo2.setId(2);
vo2.setFirstName("Raj");
vo2.setLastName("Kishore");
employees.add(vo2);
return employees;
}
}
EmployeeManager.java
import java.util.List;
import com.howtodoinjava.demo.model.EmployeeVO;
public interface EmployeeManager
{
public List<EmployeeVO> getAllEmployees();
}
EmployeeManagerImpl.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.howtodoinjava.demo.dao.EmployeeDAO;
import com.howtodoinjava.demo.model.EmployeeVO;
@Service
public class EmployeeManagerImpl implements EmployeeManager {
@Autowired
EmployeeDAO dao;
public List<EmployeeVO> getAllEmployees()
{
return dao.getAllEmployees();
}
}
EmployeeVO.java
import java.io.Serializable;
public class EmployeeVO implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
//Getters and setters
}
Please let me know if any queries or thoughts.
Happy Learning !!
Comments