Globalizing Your App: Internationalization in Spring Boot

Learn how to transform your Spring Boot application into a multilingual powerhouse, enabling it to seamlessly adapt to various languages and regions without the need for source code modifications. Dive into the world of Spring Boot’s Internationalization (i18n) capabilities, simplifying your journey to serve a global audience.

This comprehensive blog guides you through the key phases, starting from project creation via Spring Initializr, and moving on to custom locale management and message translation. By the end, you’ll be well-versed in crafting a user-friendly, multilingual application, ushering in a new era of diverse user experiences.

Internationalization in Spring Boot Application

Internationalization (i18n) is the process of making your application adaptable to different languages and regions without engineering changes to the source code. This means that users from different countries can see your application in their preferred language, with the correct date and time formats, currencies, and other locale-specific information.

Spring Boot provides excellent support for internationalization (i18n), simplifying the process of making your REST APIs multilingual. To achieve this, you can utilize Spring Initializr, which streamlines project creation by offering a guided selection of the required dependencies.

Related read: Localization with react native i18n: A Comprehensive Guide

Then click Generate Project, unzip it and open it with your favourite IDE. I’ll use Eclipse IDE.

The first step is to create a CustomLocaleResolver class to define the user’s locale.

CustomLocaleResolver.java

package com.mb.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@Configuration
public class CustomLocaleResolver extends AcceptHeaderLocaleResolver implements WebMvcConfigurer {
List<Locale> LOCALES = Arrays.asList(
new Locale("en"),
new Locale("fr"));
@Override
public Locale resolveLocale(HttpServletRequest httpRequest) {
String langHeader = httpRequest.getHeader("Accept-Language");
return langHeader == null || langHeader.isEmpty()
? Locale.getDefault()
: Locale.lookup(Locale.LanguageRange.parse(langHeader), LOCALES);
}
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource rs = new ResourceBundleMessageSource();
rs.setBasename("messages");
rs.setDefaultEncoding("UTF-8");
rs.setUseCodeAsDefaultMessage(true);
return rs;
}
}

This project supports three locales: English, Hindi, and French. The locale should be passed in the Accept-Language header. If the header is present and not empty, we will use the locale from the header. Otherwise, we will use the default locale, which is English.

Next, let’s create our class that will be responsible for choosing the right message according to the specified locale. I’ll call it Translator, and it will have one single method, that will accept the message code that should be translated.

Translator.java

package com.mb.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.stereotype.Component;

import java.util.Locale;

@Component
public class Translator {

private static ResourceBundleMessageSource messageSource;

@Autowired
Translator(ResourceBundleMessageSource messageSource) {
Translator.messageSource = messageSource;
}

public static String toLocale(String msg) {
Locale locale = LocaleContextHolder.getLocale();
msg = msg.replaceAll(" ", "_");
msg = msg.toLowerCase();
return messageSource.getMessage(msg, null, locale);
}
}

The messageSource.getMessage() method accepts a message code as a parameter, not the message itself. We need to create message codes for our messages before we can translate them.

Create three files in the resources folder: messages.properties,messages_hi.properties and messages_fr.properties.

➡️ The following is the content of messages.properties:

hello = hello
bye = bye
thank_you = thank you
congratulations = congratulations !!!!
how_are_you = How are you ???

➡️ The following is the content of messages_fr.properties:

hello=Bonjour
bye=Au revoir
thank_you = merci
congratulations = toutes nos félicitations
how_are_you = comment vas-tu ?

➡️ The following is the content of messages_hi.properties:

hello = \u0928\u092E\u0938\u094D\u0924\u0947
bye = \u0905\u0932\u0935\u093F\u0926\u093E
thank_you = \u0927\u0928\u094D\u092F\u0935\u093E\u0926
congratulations = \u092C\u0927\u093E\u0908 \u0939\u094B
how_are_you = \u0906\u092A \u0915\u0948\u0938\u0947 \u0939\u0948\u0902

We now have message codes, such as hello and bye etc. To get the appropriate message according to the user’s locale, we pass the message code to the toLocale() method.

Experience Excellence in Software Development - Hire Our Expert Team Today!

The last step is to create a simple controller, which we can call MainController. It will have a single endpoint that accepts a message code as a request parameter.

MainController.java

package com.mb.controllers;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.mb.util.Translator;

@RestController
@RequestMapping("/api")
public class MainController {

@GetMapping("/msg")
public String getMessage(@RequestParam("msg") String message) {
return Translator.toLocale(message);
}
}

Let’s Review our Project Structure

Internationalization in spring boot project

To run the InternationalizationInSpringBoot application, you can right-click on the project in your IDE and select “Run as > Spring Boot Application”.

run spring boot project

And make simple requests using Postman:

As you can see, the responses differ depending on the value of the Accept-Language header passed in the request. This way, we can avoid checking the request for this value in each controller method and passing it to service layers. Instead, we can do it in a single place, in the CustomLocaleResolver class.

coma

Conclusion

In conclusion, this blog has taken you on a journey into the realm of internationalization within Spring Boot applications. By embracing internationalization (i18n), you can make your application adaptable to various languages and regions without needing extensive changes to your source code. We explored the robust support for i18n provided by Spring Boot, allowing effortless multilingualization of your REST APIs.

From creating a project using Spring Initializr to implementing custom locale handling and message translation, we’ve equipped you with the knowledge to develop user-friendly, multilingual applications, catering to a diverse global audience.

The full source code for the example is available on GitHub.

Keep Reading

Keep Reading

Mindbowser is excited to meet healthcare industry leaders and experts from across the globe. Join us from Feb 25th to 28th, 2024, at ViVE 2024 Los Angeles.

Learn More

Let's create something together!