What is Internationalization & Why do we need it?
The method of adapting your application to multiple languages, regional quirks, and technological needs of a targeted locality is known as internationalization and localization, or i18n and L10n, respectively.
Because we are living in an era of globalization and we want to make our application accessible to as many users as possible and having your application available in multiple languages helps to do that.
Internationalization in Spring Boot 101
MessageSource
The message source interface was developed by Spring developers to help with internationalization in Spring Boot applications. Here we (or more precisely Spring Boot auto-configuration) will be using its ResourceBundleMessageSource
1 implementation for our language resource resolving purpose. Under the hood, the class uses JDK's ResourceBundle
2 implementataion.
By default, Spring Boot looks for the presence of a messages
resource bundle (i.e, messages.properties)at the root of the classpath.
If we want to define a custom resource bundle for our messages we can do it by using the property spring.messages.basename
in application.properties
Rules to follow for resource file
- All resource file should be kept in same package.
- All resource file must share a common basename.
- The default resource file should simply have the basename like
basename.properties
. - Additional properties files must be named in the following pattern:
- Resource file for a specific language should have the name as
basename_languageCode.properties
- If we want to restrict the target location down to a particular country, it should be named as
basename_languageCode_countryCode.properties
- Resource file for a specific language should have the name as
LocaleResolver 3
The interface is used for web-based locale resolution strategies that allow for both request and response-based locale resolution and change.
There are a few LocaleResolver
implementations in Spring that are utilised in various scenarios.
In our example, we will be using CookieLocaleResolver
implementation, that uses a cookie sent back to the user in case of a custom setting, with a fallback to the specified default locale or the request's accept-header
locale.
LocaleChangeInterceptor 4
LocaleChangeInterceptor
will intercept each request that the application receives and eagerly inspect the HTTP request for the argument set in the LocaleChangeInterceptor bean definition.
In our example, we will be using "lang" as a parameter.
To utilise the interceptor we should add it to the Spring InterceptorRegistry and to do that we will use WebMvcConfigurer
and override the method addInterceptors
.
Implementation
Let's create a basic Spring Boot web application using Spring Initializer and add Spring Web and Thymeleaf dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Let's create a simple controller with a method annotated with @GetMapping
to the root url.
HomeController.java
@Controller
public class HomeController {
@GetMapping(value = "/")
public String home() {
return "home";
}
}
Let's write the configuration to resolve the locale.
MvcConfigurer.java
@Configuration
public class MvcConfigurer implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver () {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
return localeResolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
Let's create our message resource.
messages.properties
title=Internationalization Demo
message=The website ApneKaamSeKaamRakho or AKSKR as we call it, is currently in the works, and two great minds are working to create a fun website where you can connect and be entertained by playing entertaining games and trivia quizzes, among other things.
The website will be up and running soon, so keep an eye out for it.
lang-en=English
lang-es=Spanish
messages_es.properties
title=Demostración de internacionalización
message=El sitio web ApneKaamSeKaamRakho o AKSKR, como lo llamamos, está actualmente en proceso, y dos grandes mentes están trabajando para crear un sitio web divertido donde pueda conectarse y entretenerse jugando juegos divertidos y cuestionarios de trivia, entre otras cosas.
lang-en=Inglés
lang-es=Español
Let's create a simple Thymeleaf template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title th:text="#{title}">Internationalization Demo</title>
</head>
<body>
<div class="one">
<a class="one" href="https://www.akskr.com" target="_blank">
<div>A<span>PNE</span></div>
<div>K<span>AAM</span></div>
<div>S<span>E</span></div>
<div>K<span>AAM</span></div>
<div>R<span>AKHO</span></div>
</a>
</div>
<br>
<br>
<div th:text="#{message}" class="para"></div>
<br>
<br>
<br>
<button type="button" th:text="#{lang-en}" onclick="window.location.href='http://localhost:8080/?lang=en'"
class="btn"></button>
<button type="button" th:text="#{lang-es}" onclick="window.location.href='http://localhost:8080/?lang=es'"
class="btn"></button>
</body>
</html>
On clicking the button, the page is reloaded with and additional parameter lang=en
or lang=es
for English or Spanish respectively.
Testing
To test our implementation let's run our application and go to http://localhost:8080/
.
We will see that our application is loaded in English.
Let's try switching the language through buttons. We will see that our website is switched to Spanish language.
Now, let's change the default language of our browser to Spanish and move it to top in the list.
Now, navigate to http://localhost:8080/
and the website would load in Spanish by default.
Now, you can try switching your language to English and reload the page and see it will load in English.
Summary
In this article, we learnt how we can localize our application and integrate internationalization in Spring Boot. We learned how to use MessageSource implementations to perform simple translations, how to resolve languages using the details of incoming HTTP requests using LocaleResolver and LocaleChangeInterceptor classes, and how to switch to a different language with a single click in our internationalized Spring Boot web application.
As always you can find the source code for the example @ Github