Master Spring Boot Internationalization (i18n) in 10 Simple Steps
This guide walks you through configuring Spring Boot for full‑stack internationalization, covering dependency setup, message resource files, application properties, locale resolver and interceptor, controller and service usage, Thymeleaf templates, custom resolvers, testing, and handling static content.
Overview
Spring Boot offers robust i18n support that lets developers create multilingual applications with minimal effort. The following steps demonstrate how to configure and use internationalization from scratch.
1. Add Maven dependencies
<dependencies>
<!-- Web dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf template engine -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>2. Create message resource files
Place the following .properties files under src/main/resources: messages.properties – default language messages_zh_CN.properties – Simplified Chinese messages_fr.properties – French
# messages.properties
welcome.message=Welcome to our application!
user.greeting=Hello, {0}
page.title=Home Page # messages_zh_CN.properties
welcome.message=欢迎使用我们的应用程序!
user.greeting=你好,{0}
page.title=首页 # messages_fr.properties
welcome.message=Bienvenue dans notre application !
user.greeting=Bonjour, {0}
page.title=Page d'accueil3. Configure i18n settings
# application.properties
spring.messages.basename=messages
spring.messages.encoding=UTF-8
spring.messages.fallback-to-system-locale=false4. Configure locale resolver and interceptor
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.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import java.util.Locale;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// Default locale = English
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.ENGLISH);
return slr;
}
// Parameter name for switching language, e.g. ?lang=zh_CN
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}5. Use messages in a 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 java.util.Locale;
@Controller
public class HomeController {
@Autowired
private MessageSource messageSource;
@GetMapping("/")
public String home(Model model, Locale locale) {
String welcomeMessage = messageSource.getMessage("welcome.message", null, locale);
String userGreeting = messageSource.getMessage("user.greeting", new Object[]{"John"}, locale);
model.addAttribute("welcomeMessage", welcomeMessage);
model.addAttribute("userGreeting", userGreeting);
model.addAttribute("pageTitle", messageSource.getMessage("page.title", null, locale));
return "home";
}
}6. Display messages in a Thymeleaf template
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${pageTitle}">Home Page</title>
</head>
<body>
<h1 th:text="${welcomeMessage}">Welcome message</h1>
<p th:text="${userGreeting}">User greeting</p>
<!-- Language switch links -->
<div>
<a th:href="@{/(lang='en')}">English</a> |
<a th:href="@{/(lang='zh_CN')}">中文</a> |
<a th:href="@{/(lang='fr')}">Français</a>
</div>
<!-- Direct message lookup in template -->
<p th:text="#{welcome.message}">Welcome message</p>
<p th:text="#{user.greeting(${'Jane'})}">User greeting</p>
</body>
</html>7. Advanced: custom locale resolver
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class CustomLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String langHeader = request.getHeader("Accept-Language");
if (langHeader != null && !langHeader.isEmpty()) {
return Locale.forLanguageTag(langHeader);
}
return Locale.getDefault();
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
// No implementation needed for read‑only resolver
}
}8. Use i18n in the service layer
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
import java.util.Locale;
@Service
public class UserService {
@Autowired
private MessageSource messageSource;
public String getLocalizedWelcomeMessage(String username, Locale locale) {
return messageSource.getMessage("user.greeting", new Object[]{username}, locale);
}
}9. Write tests to verify messages
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.MessageSource;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class I18nTest {
@Autowired
private MessageSource messageSource;
@Test
public void testEnglishMessages() {
String message = messageSource.getMessage("welcome.message", null, Locale.ENGLISH);
assertEquals("Welcome to our application!", message);
}
@Test
public void testChineseMessages() {
String message = messageSource.getMessage("welcome.message", null, Locale.SIMPLIFIED_CHINESE);
assertEquals("欢迎使用我们的应用程序!", message);
}
}10. Internationalize static content
@GetMapping("/about")
public String about(Model model, Locale locale) {
String content;
if (Locale.SIMPLIFIED_CHINESE.equals(locale)) {
content = "关于我们的中文内容...";
} else {
content = "About us content in English...";
}
model.addAttribute("aboutContent", content);
return "about";
}Conclusion
The complete Spring Boot i18n solution includes:
Message resource .properties files for each language.
A locale resolver that determines the current language.
An interceptor that enables ?lang=xx URL parameters.
Message retrieval in controllers, services, and Thymeleaf templates.
Further extensions can store localized content in a database or customize language selection based on user preferences.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ray's Galactic Tech
Practice together, never alone. We cover programming languages, development tools, learning methods, and pitfall notes. We simplify complex topics, guiding you from beginner to advanced. Weekly practical content—let's grow together!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
