Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieve locale based on the Accept-Language in Spring Boot

I have a Spring Boot (2.1.3.RELEASE) application that uses Jersey to define the (RESTful) endpoints. I'm trying to read and propagate some messages based on the locale being sent by the user-agents.

I've configured these beans:

@Bean
public LocaleResolver localeResolver() {
  final AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
  resolver.setSupportedLocales(Arrays.asList(Locale.GERMANY, Locale.US));
  resolver.setDefaultLocale(Locale.ENGLISH);
  return resolver;
}

@Bean
public MessageSource messageSource() { // Not sure if this is needed
  final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
  messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
  messageSource.setBasenames("classpath:/messages");
  messageSource.setUseCodeAsDefaultMessage(true);
  messageSource.setCacheSeconds(5);
  return messageSource;
}

...and also the bundles (inside ../src/main/resources/) like: messages.properties (fallback), messages_en_US.properties, messages_de_DE.properties, etc.

Now, the challenge is that I'm not sure how to "read" the locale sent by the user-agents in order to read the messages from the bundles appropriately. I'm injecting a MessageSource ms, and programmatically reading messages like:

final Locale locale = ???
ms.getMessage("message.duplicate-token", null, locale);

Any clues?

I've tried LocaleContextHolder.getLocale() but it's always en_US. If I hardcode the corresponding locale for the getMessage call, I'm able to retrieve the correct message(s). So I know the setup/configuration works for the most part.


Clients are sending the locale using the Accept-Language header — and values like: de-DE, en-US, etc.

like image 321
x80486 Avatar asked Apr 17 '19 22:04

x80486


2 Answers

You need add an LocaleChangeInterceptor and configure the bean as follow: Refer Spring Boot internationalization for more

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

If you want to use "Accept-Language" header only, then you can extend AcceptHeaderLocaleResolver and can customize:

package com.deb.demo.config;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

public class CustomLocaleResolver extends AcceptHeaderLocaleResolver {


    List<Locale> LOCALES = Arrays.asList(new Locale("en"),new Locale("es"),new Locale("fr"));


  @Override
  public Locale resolveLocale(HttpServletRequest request) {
     if (StringUtils.isEmpty(request.getHeader("Accept-Language"))) {
         return Locale.getDefault();
       }
     List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
     Locale locale = Locale.lookup(list,LOCALES);
      return locale;
     }
}
like image 63
DEBENDRA DHINDA Avatar answered Nov 15 '22 15:11

DEBENDRA DHINDA


I m using a bean

  @Bean
  public LocaleResolver localeResolver() {
    AcceptHeaderLocaleResolver slr = new AcceptHeaderLocaleResolver();
    slr.setDefaultLocale(Locale.UK);
    return slr;
  }

then another one

  @Bean
  public LanguageUtil languageUtil() {
    return new LanguageUtil();
  }

with

  private Locale getLocale() {
    return LocaleContextHolder.getLocale();
  }

  public String getLocalizedMessage(String messageKey) {
    return messageSource.getMessage(messageKey, null, getLocale());
  }

The header is saved into the LocaleContextHolder, and you can use it when you need it.

like image 40
cardinal Avatar answered Nov 15 '22 14:11

cardinal