Multi-language api in Spring boot
It is better to build a multilingual website because it helps your website to access to more users. The multilingual website is known as Internationalization (i18n) that is opposed to Localization (L10n).
If you are building an application globally there would be multi-language application in order to get big audience.
Note: Internationalization is a word comprising 18 characters, the first character is i and the last one is n, so it is commonly abbreviated as i18n.
Spring provides extensive support for internationalization (i18n) through the use of Spring interceptors, Locale Resolvers and Resource Bundles for different locales.
So first lets create the project structure for our project and then apply i18n.
So, create Spring boot project with https://start.spring.io/ and add dependecies -> Web and Lombok, choose java version (which version you want), building tool as Maven. And leave other settings as default which website offered to us. Now download the project and extract folder and open with IntelliJ IDEA or the IDE that you preferred.
package com.example.demo.configuration;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@Configuration
public class CustomLocaleResolver extends AcceptHeaderLocaleResolver {
List<Locale> LOCALES = Arrays.asList(
new Locale("EN"),
new Locale("RU"),
new Locale("AZ")
);
@Override
public Locale resolveLocale(HttpServletRequest request) {
String headerLang = request.getHeader("Accept-Language");
return headerLang == null || headerLang.isEmpty()
? Locale.getDefault()
: Locale.lookup(Locale.LanguageRange.parse(headerLang), LOCALES);
}
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource rs = new ResourceBundleMessageSource();
rs.setBasename("message");
rs.setDefaultEncoding("UTF-8");
rs.setUseCodeAsDefaultMessage(true);
return rs;
}
}
Add configuration class inside config folder. In my case, I have chosen 3 languages, but you can extend this list with your version. According to these languages, I also created message_language.properties file inside resources folder:
How this Configuration works?
As you can see we accept language from api header -> “Accept-Language”, if language is declared in the api header then we will take it, otherwise we will take the default language with Locale.getDefault() method. We can change our application default language in the application startup using
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
SpringApplication.run(DemoApplication.class, args);
}
Inside util folder create Translator class with the following code:
package com.example.demo.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 translate(String msgCode) {
Locale locale = LocaleContextHolder.getLocale();
return messageSource.getMessage(msgCode, null, locale);
}
}
That’s is, you just configured the Custom Locale Resolver and now we can apply it to our services:
package com.example.demo;
import com.example.demo.codes.ExceptionCode;
import com.example.demo.response.RespStatus;
import com.example.demo.response.RespStatusList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static com.example.demo.util.Translator.translate;
import static java.util.Objects.isNull;
@SpringBootApplication
@RestController
@Slf4j
public class DemoApplication {
@GetMapping(value = "/account")
public RespStatusList getAccountById(@RequestParam(name = "accountId", required = false) Integer id) {
RespStatusList response = new RespStatusList();
if (isNull(id)) {
response.setStatus(
new RespStatus(
ExceptionCode.ACCOUNT_NOT_FOUND,
translate("account_not_found")
)
);
return response;
}
log.info("accountId: {}", id);
response.setStatus(
new RespStatus(
ExceptionCode.SUCCESS,
translate("success")
)
);
return response;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I created simple api in order to testing our configuration and also added translations for “success” and “account_not_found” to properties file:
IntelliJ IDEA offered to us plugin for resource bundle, with the help of this plugin, we can easily add the translations for messages.
But, there is one key point you have to remember, in IntelliJ IDEA the default encoding for .properties file is ISO-8859–1 and you should change it in order to accept other language characters. To doing it in IntelliJ IDEA:
- click CTRL + ALT + S
- search for properties
- change encoding format to UTF-8
- apply changes and click okay
You are all done!
It is time to test our api. I prefer to test api with Postman.
Open Postman and type endpoint you created choose Http method
Write Accept-Language and prefered language code (I wrote az), and send request:
We can see that the statusMessage field showed the result in Azerbaijani language, now let’s try to change the language and test api again:
That’s it, I hope you can create your own multi-language api from now :)
The source code of project can be found from Github