In todayโs globalized web applications, itโs crucial to support multiple languages to reach a wider audience. Spring Boot makes it easy to implement internationalization (i18n), allowing you to externalize messages and tailor them based on user locale.
In this guide, you’ll learn how to implement internationalization in Spring Boot with full working examples using the package com.kscodes.springboot.

๐ What is Internationalization (i18n)?
Internationalization (abbreviated as i18n) is the process of designing an application to support various languages and regional formats without changing the codebase. This is often implemented using:
- Message resource bundles (
messages_en.properties,messages_fr.properties, etc.) - Locale resolvers to determine user locale
- Spring MVC to display locale-based content
๐ Step-by-Step Guide to Internationalization (i18n) in Spring Boot
๐งฑ Step 1: Create Message Resource Files
Create src/main/resources/messages_*.properties files for each language you want to support.
messages_en.properties (Default – English)
welcome.message=Welcome to KSCodes!
error.notfound=Resource not found
messages_fr.properties (French)
welcome.message=Bienvenue sur KSCodes!
error.notfound=Ressource non trouvรฉe
๐ง Step 2: Configure MessageSource Bean
package com.kscodes.springboot.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import java.nio.charset.StandardCharsets;
@Configuration
public class I18nConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
return messageSource;
}
}
๐ Step 3: Configure LocaleResolver
Use AcceptHeaderLocaleResolver to pick locale from request header (e.g., Accept-Language).
package com.kscodes.springboot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import java.util.Locale;
@Configuration
public class LocaleConfig {
@Bean
public LocaleResolver localeResolver() {
AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
resolver.setDefaultLocale(Locale.ENGLISH);
return resolver;
}
}
๐ Step 4: Create a REST Controller to Use i18n
package com.kscodes.springboot.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import java.util.Locale;
@RestController
public class GreetingController {
@Autowired
private MessageSource messageSource;
@GetMapping("/greeting")
public String getGreeting(@RequestHeader(name = "Accept-Language", required = false) Locale locale) {
return messageSource.getMessage("welcome.message", null, locale);
}
@GetMapping("/error")
public String getErrorMessage(@RequestHeader(name = "Accept-Language", required = false) Locale locale) {
return messageSource.getMessage("error.notfound", null, locale);
}
}
๐ฆ Step 5: Make a Test Call
Using curl or Postman:
curl -H "Accept-Language: fr" http://localhost:8080/greeting
Response
Bienvenue sur KSCodes!
Without header:
Welcome to KSCodes!
๐ Optional: Using Query Params for Locale (SessionLocaleResolver)
If you prefer users to change language via query param (e.g., ?lang=fr), use:
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.ENGLISH);
return resolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
Also register the interceptor:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
Now you can call:
http://localhost:8080/greeting?lang=fr
๐ Security and Performance Tips
- Use UTF-8 encoding for all
.propertiesfiles. - Avoid loading too many language files unnecessarily.
- Use caching for messages when using ReloadableResourceBundleMessageSource.
๐ก Best Practices for Internationalization in Spring Boot
- Use consistent keys across languages (
welcome.message,error.notfound). - Keep messages short and readable.
- Validate translated
.propertiesfiles with native speakers. - Handle fallback when the language is missing.
โ Summary
- Use
@MessageSourceto load language-specific property files. - Use
LocaleResolverto detect user locale (via headers or query). - Implement
Accept-Languageor?lang=based language switching. - Property files should be named
messages_{lang}.properties.