Thursday, April 8, 2021

Internationalization of Web Application using Spring Boot

Internationalization Globe Image

Internationalization (i18n) is the process of designing and preparing the application to be usable in different locales around the world. Localization (l10n) is the process of building versions of your app for different locales, including extracting text for translation into different languages, and formatting data for particular locales.

A locale identifies a region (such as a country) in which people speak a particular language or language variant. The locale determines the formatting and parsing of dates, times, numbers, and currencies as well as measurement units and the translated names for time zones, languages, and countries.


Building a SpringBoot Application for i18n

Let’s use the spring initializr to generate a spring boot application with dependency of spring web module. Unzip the downloaded project and import it to your IDE.

The end goal of this application is to create a web page that displays a welcome message for the user “Welcome to SpringBoot Internationalization!” on the home page. And user will be presented with an option to switch the locale or language of his/her choice. 


Resource Bundles

For an application to support internationalization (i18n), it requires the capability of resolving text messages for different locales. Spring’s application context is able to resolve text messages for a target locale by their keys.

Typically, the messages for each locale should be stored in separate properties file. This properties file is called a resource bundle, they should be added in resources folder of the spring boot application.

If we are supporting multiple locales then we will have multiple resource bundles so we need to follow a naming convention so that it’s easy for spring to lookup the values as well as easy for us to maintain it.

For example, messages_en.properties / messages_fr.properties. As you can see from the name itself we can make out first one is for English and next on is for French.


Message Source

MessageSource is an interface that defines several methods for resolving messages. The ApplicationContext interface extends this interface so that all application contexts are able to resolve text messages.

An application context delegates the message resolution to a bean with the exact name messageSource. ResourceBundleMessageSource is the most common MessageSource implementation that resolves messages from resource bundles for different locales.

Here is the bean declaration for ResourceBundleMessageSource for our application.

@Bean
public ResourceBundleMessageSource messageSource() {
   ResourceBundleMessageSource source = 
         new ResourceBundleMessageSource();
   source.setDefaultEncoding("UTF-8");
   source.setBasename("messages");
   source.setCacheSeconds(600);
   return source;
}


Application Properties

Let’s add some of the important configurations related to the resource bundle message source into the application.properties file.

I have added an explanation for each of the configuration which is easy to understand, hence am not going to details.

# Whether to always apply the MessageFormat rules, parsing even messages without arguments.

spring.messages.always-use-message-format=false

# Whether to fall back to the system default Locale, if no files for a specific Locale have been found.

spring.messages.fallback-to-system-locale=true

# Whether to use the message code as the default message instead of throwing a "NoSuchMessageException". Recommended during development only.

spring.messages.use-code-as-default-message=false


Interceptor

Next, we will add an interceptor to intercept the request and identify whether user has requested a locale change or not. It will come handy when user want to change the language of the application explicitly.

@Bean
public LocaleResolver localeResolver() {
    return new SessionLocaleResolver();
}

@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
    return new LocaleChangeInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(localeChangeInterceptor());
}

The LocalChangeInterceptor looks for a request parameter name locale by default. If you are not interested to use that parameter, you can override it by giving your own parameter name.

We will add a controller that returns a web page as a response by adding the required keys into the model so that it can be access in the html page.

@Controller
public class DefaultController {
    @Autowired
    private MessageSource messageSource;
    @GetMapping("/")
    public ModelAndView getIndex(
            Map<String, Object> model, Locale locale) {
        model.put("greetMessage", messageSource
                .getMessage("welcomeText", null, locale));
        model.put("languageSupported", messageSource
                .getMessage("languageSupport", null, locale));
        return new ModelAndView("index", model);
    }
}

If you see am trying to read two keys from the messageSource, one is welcomeText and another one is languageSupport. We need to make sure whatever locales we are going to support, it has these two keys in respective locale resource bundle.

messages_en.properties
welcomeText=Welcome to SpringBoot Internationalization!
languageSupport=Language Options

messages_kn.properties
welcomeText=ಸ್ಪ್ರಿಂಗ್‌ಬೂಟ್ ಅಂತರರಾಷ್ಟ್ರೀಕರಣಕ್ಕೆ ಸುಸ್ವಾಗತ!
languageSupport=ಭಾಷಾ ಆಯ್ಕೆಗಳು

messages_fr.properties
welcomeText=Bienvenue dans SpringBoot Internationalization!
languageSupport=Options de langue

Last but not the least is to create a html page which can display the welcome message as well as provides an option to switch the locale or language.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Springboot Internationalization Demo</title>
</head>
<body>
<h1>{{greetMessage}}</h1>
<br/>
<b>{{languageSupported}}:</b>
<a href="/?locale=en">English</a>&nbsp;|&nbsp;
<a href="/?locale=hi">Hindi</a>&nbsp;|&nbsp;
<a href="/?locale=kn">Kannada</a>&nbsp;|&nbsp;
<a href="/?locale=te">Telugu</a>&nbsp;|&nbsp;
<a href="/?locale=ta">Tamil</a>&nbsp;|&nbsp;
<a href="/?locale=ar">Arabic</a>&nbsp;|&nbsp;
<a href="/?locale=zh">Chinese</a>&nbsp;|&nbsp;
<a href="/?locale=fr">French</a>&nbsp;|&nbsp;
<a href="/?locale=in">Indonesia</a>
</body>
</html>

In the above html code you can see the place holders {{greetMessage}} and {{languageSupported}}, they will be replaced with the actual messages based on the locale.

The languages supported can be returned as a list from the controller and we can loop through it and render them but for now am skipping it and hard-coding the languages supported.

Now if we compile the code and deploy our springboot application, we should be able to see the output on the web browser.

Open the browser and type in the URL — http://localhost:8181/

Internationalization English Image

Now if the user clicks on any other language options, the page should change to that specific locale or language. Let’s say I click on Kannada language, then the same web page will be rendered in that language.

Internationalization Kannada Image

Using the cURL command, you can make the request and get the response.

$ curl -X GET -H 'Accept-Language: fr' 'http://localhost:8181/'
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"><title>Springboot Internationalization Demo</title>
</head><body><h1>Bienvenue dans SpringBoot Internationalization!</h1>
<br/><b>Options de langue:</b>
<a href="/?locale=en">English</a>&nbsp;|&nbsp;
<a href="/?locale=hi">Hindi</a>&nbsp;|&nbsp;
<a href="/?locale=kn">Kannada</a>&nbsp;|&nbsp;
<a href="/?locale=te">Telugu</a>&nbsp;|&nbsp;
<a href="/?locale=ta">Tamil</a>&nbsp;|&nbsp;
<a href="/?locale=ar">Arabic</a>&nbsp;|&nbsp;
<a href="/?locale=zh">Chinese</a>&nbsp;|&nbsp;
<a href="/?locale=fr">French</a>&nbsp;|&nbsp;
<a href="/?locale=in">Indonesia</a></body>
</html>

With Localization (l10n), we should be able to manage other customization like date and time format, currency, number formatting as these things varies from locale to locale.

As usual, the source code for the above spring boot implementation is available over on GitHub.

Tags: , , , ,
Location: Mysuru, Karnataka, India

0 comments:

Post a Comment

Featured Post

Benefits & Best Practices of Code Review

Photo by Bochelly Code reviews are methodical assessments of code designed to identify bugs, increase code quality, and help developers lear...