Skip to content
Advertisement

Spring Boot & Thymeleaf – Localized text does not appear

I am currently working on the localization of my (second) Spring Boot project. However, I have come to a halt after several hours of struggling: I am unable to get a user-editable Session localization.

The problem appears to occur as soon as the user sends a GET request with the lang parameter. (travel down below to see the results I am getting)

Details

Spring Boot version:(3.0.0-M3)

Expected localized content

i18n/messages.properties is empty

i18n/messages_en_US.properties:

morning=good morning
afternoon=bye

i18n/messages_fr_FR.properties:

morning=salut
afternoon=a+

i18n/messages_ja_JP.properties:

morning=ohayou
afternoon=jane

Configuration

application.properties (section related to this issue):

spring.messages.always-use-message-format=true
spring.messages.basename=i18n.messages
spring.messages.fallback-to-system-locale=false
spring.messages.use-code-as-default-message=false

LocalizationConfiguration file:

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;

@Configuration
public class LocalizationConfiguration implements WebMvcConfigurer {

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        // localeResolver.setDefaultLocale(Locale.US);
        return localeResolver;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
        localeChangeInterceptor.setParamName("lang");
        return localeChangeInterceptor;
    }

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

}

Display

Page Controller:

@GetMapping
@RequestMapping(value = "/international")
public String getInternationalView(Model model) {
    return "international";
}

Template loaded (international.html):

<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" th:with="lang=${#locale.language}" th:lang="${lang}">
<head>
<script src="https://kit.fontawesome.com/2f4c03ee9b.js" crossorigin="anonymous"></script>

<script th:src="@{/webjars/jquery/3.0.0/jquery.min.js}"></script>
<script th:src="@{/webjars/popper.js/2.9.3/umd/popper.min.js}"></script>
<script th:src="@{/webjars/bootstrap/5.1.3/js/bootstrap.min.js}"></script>
<link th:rel="stylesheet" th:href="@{/webjars/bootstrap/5.1.3/css/bootstrap.min.css} "/>

<meta charset="UTF-8"/>
<title>Localization tests</title>
</head>
<body>
    <p th:text="${#locale}"></p>
    <p th:text="#{morning}"></p>
    <p th:text="#{afternoon}"></p>
    
    <div class="dropdown">
        <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
            <i class="fa-solid fa-language fa-4x"></i>
        </button>
        <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
            <li><a class="dropdown-item" th:href="@{''(lang=en)}">English</a></li>
            <li><a class="dropdown-item" th:href="@{''(lang=fr)}">Français</a></li>
            <li><a class="dropdown-item" th:href="@{''(lang=jp)}">日本語</a></li>
        </ul>
    </div>
</body>
</html>

What is being displayed

Found result

As you can see in the above gif, the first display of the page shows the messages in the browser’s language. However, as soon as an other language is selected the page breaks apart, with the exception of the #locale parameter.

Advertisement

Answer

Try it.

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;

@Configuration
public class ApplicationConfig implements WebMvcConfigurer {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:/i18n/messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
        localeChangeInterceptor.setParamName("lang");
        return localeChangeInterceptor;
    }

    @Bean(name = "localeResolver")
    public SessionLocaleResolver sessionLocaleResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(new Locale("en"));
        return localeResolver;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    } 
}
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement