Internationalization is not working in Spring Boot v2.3.1.RELEASE - spring-boot

I'm trying to implement Internationalization in Spring boot. I have configured a configuration class, message.properties and its jsp implementation like below. But it is not working in runtime. When i check the chrome browser debugger, it seems to redirect my Internationalization URL to default url always.
Below are the structure of my application
Configuration Class
#Configuration
public class LocaleConfig 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 registry){
registry.addInterceptor(localeChangeInterceptor());//.addPathPatterns("/*");
}
#Bean
public ReloadableResourceBundleMessageSource messageSource()
{
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:locale/messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(3600); //refresh once per hour
return messageSource;
}
}
messages.properties files are under src/main/resources package ->locale folder
messages.properties
#login page
title.login.page=Login Page
label.login.header=Login To Your Account
messages_fr.properties
#login page
title.login.page=Page de connexion
label.login.header=Connectez-vous à votre compte
.jsp Page
<title><spring:message code="title.login.page"/></title>
<spring:message code="label.login.header"/>
It is redirecting my url when i enter
http://localhost:8080/****/user/login?lang=fr
to
http://localhost:8080/****/user/login
And Language translation is not happening. Assist me on this!

Related

Spring Webflow: How to establish my own ReloadableResourceBundleMessageSource for a flow

Spring Webflow 2.5.1.
I have my own implementation of ReloadableResourceBundleMessageSource. I can successfully establish it in Spring MVC via:
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource source = new AwareReloadableResourceBundleMessageSource();
source.setCacheSeconds(cacheSeconds);
source.setBasename("WEB-INF/i18n/messages");
source.setUseCodeAsDefaultMessage(true);
source.setDefaultEncoding("UTF-8");
return source;
}
My application uses both Spring MVC and Webflow.
I would like to have instances of the same AwareReloadableResourceBundleMessageSource in place for the individual per-flow messages.properties files.
I have tried:
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
...
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource ms = new AwareReloadableResourceBundleMessageSource();
ms.setBasename("messages");
System.out.println("MESSAGE SOURCE AwareReloadableResourceBundleMessageSource");
return ms;
}
}
But the messageSource() method is not called.
I have seen: https://stackoverflow.com/a/8126164
Any pointers/techniques/code snipppets very gratefully accepted.
Try the following:
Configure messageSource() within a ValidatorFactory bean, AND
Configure the ValidatorFactory bean within FlowBuilderServices
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setValidator(getValidator())
.build();
}
#Bean
public LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}

Spring Boot, Hibernate validator language based on LocaleContextHolder

I've a Spring Boot 2.4.2 REST application using JPA, Hibernate, etc.
So far I use a MessageSource for applications errors (located in i18n/messages), and the default ValidationMessagesfor bean validations.
This is part of my configuration:
public static Set<Locale> LOCALES = Set.of(new Locale("en"), new Locale("it"));
#Bean
public LocaleResolver localeResolver() {
SmartLocaleResolver localeResolver = new SmartLocaleResolver();
return localeResolver;
}
public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
#Override
public Locale resolveLocale(HttpServletRequest request) {
if (StringUtils.isBlank(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;
}
}
#Primary
#Bean("messageSource")
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/i18n/messages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
My application supports 2 languages so far: it and en.
The problem right now is that application's messages are correctly localized in the agent's language (browser) but Validations errors are not.
I found out that Hibernate uses the default locale (Locale.getDefault()) and to customize the behaviour I should customize the locale resolution.
So I tried creating a custom hibernateValidator (that I set in my entityFactory) :
#Bean
public MessageSource validationMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/ValidationMessages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
#Bean("hibernateValidator")
public LocalValidatorFactoryBean hibernateValidator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setValidationMessageSource(validationMessageSource());
return factoryBean;
}
and the resolver:
public class HibernateLocaleResolver implements LocaleResolver {
#Override
public Locale resolve(LocaleResolverContext context) {
return LocaleContextHolder.getLocale();
}
}
Doing this, the locale resolution works fine, but the parameter replacement doesn't. What I mean is for messages like this:
server.validators.ArraySize.message = The number of values must be between [{min}] and [{max}].
I've an exception:
"exception": "java.lang.IllegalArgumentException", "message": "can't parse argument number: min"
So I changed the configuration above adding the MessageInterpolator:
factoryBean.setMessageInterpolator(new ResourceBundleMessageInterpolator(LOCALES, Locale.ENGLISH, new HibernateLocaleResolver(), false));
At this point the parameters are resolved correctly, but again the locale resolution doesn't work.
Can you point me out in the right direction, trying to explain the best practice to follow for the combination Spring Boot - Hibernate Validator?
I solved the problem. I hope this can help someone else. This is my configuration file:
#Primary
#Bean("messageSource")
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/i18n/messages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
#Bean
public MessageSource validationMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/ValidationMessages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setValidationMessageSource(validationMessageSource());
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
and the LocaleConfiguration:
#Configuration
public class LocaleConfiguration implements WebMvcConfigurer {
#Bean
public LocaleResolver localeResolver() {
SmartLocaleResolver localeResolver = new SmartLocaleResolver();
return localeResolver;
}
public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
#Override
public Locale resolveLocale(HttpServletRequest request) {
if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
return Locale.getDefault();
}
List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
Locale locale = Locale.lookup(list, Constants.LOCALES);
return locale;
}
}
}
the important part I saw made the difference are these lines:
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
In this way the interpolator works fine as well as the localization of the message.

Springboot locale with Rest request and Thymeleaf

So another application directs user to my server. The redirect is Post request (application/json) with value language in the JSON. How should I set the locale value in RestController? So that Thymeleaf could render the correct text.
Setting locale with LocaleContextHolder doesn't do the trick.
You should follow this guide here since Internationalization is a common task in spring-boot. In case if you need a short answer:
First configure a LocaleResolver in your Application.java:
#Bean(name = "localeResolver")
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(new Locale("tr", "TR"));
return slr;
}
Then again in your Application.java file configure a LocaleChangeInterceptor:
#Bean(name = "localeChangeInterceptor")
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
And finally register your LocaleChangeInterceptor (also in Application.java):
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
Now if you send a request parameter named "lang" with your POST request spring will use its value to determine the desired locale and change it accordingly.
Ended up with the following solution:
WebMvcConfigurer has these
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver r = new SessionLocaleResolver();
r.setDefaultLocale(new Locale("jp"));
return r;
}
And in the controller I call this classes public method:
#Component
public class WebLanguage {
public void setLocale(HttpServletRequest request, HttpServletResponse response) {
if (!request.getParameterMap().containsKey("lang")) return;
LocaleResolver localeResolver = localeResolver(request);
localeResolver.setLocale(request, response, new Locale(request.getParameterMap().get("lang")[0]));
}
LocaleResolver localeResolver(HttpServletRequest request) {
return RequestContextUtils.getLocaleResolver(request);
}
}

spring boot Locale Resolver default spanish

I can not find a way to change the default locale from Locale.US to Spanish. It is not in the list and I can not find anything that explains how.
#Configuration
public class SpringMvcConfiguration extends WebMvcConfigurerAdapter {
#Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(Locale.US);
return sessionLocaleResolver;
}
#Bean
LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry interceptorRegistry){
interceptorRegistry.addInterceptor(localeChangeInterceptor());
}
}
There is no constant like Locale.US to help you. But you can instantiate a new Locale passing the correct languange information like new Locale("es") as explained in the documentation. Or use the Locale.Builder that was added in Java 8.

Thymeleaf org.thymeleaf.exceptions.TemplateInputException: Error resolving template

I've tried a lot of solutions but it just doesn't work. I'm using Intellij 2016.1.
I can't force the app to resolve templates.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/login/login", template might not exist or might not be accessible by any of the configured Template Resolvers
config
#Configuration
#ComponentScan(basePackages = "com.unibooker")
#EnableWebMvc
public class Config extends WebMvcConfigurerAdapter{
#Bean
public TemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("classpath:/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
#Bean(name = "templateEngine")
public SpringTemplateEngine getTemplateEngine()
{
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(this.templateResolver());
templateEngine.setMessageSource(this.messageSource());
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
#Bean
public ViewResolver setupViewResolver()
{
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(this.getTemplateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
#Bean
public MessageSource messageSource()
{
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(3600);
return messageSource;
}
#Bean
public LocaleResolver localeResolver()
{
CookieLocaleResolver resolver = new CookieLocaleResolver();
resolver.setDefaultLocale(new Locale("pl"));
resolver.setCookieName("locale");
resolver.setCookieMaxAge(86400);
return resolver;
}
#Override
public void addInterceptors(InterceptorRegistry registry)
{
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("locale");
registry.addInterceptor(interceptor);
}
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
Project structure - IMAGE
I have tried to move templates to resources but still nothing. Please help. I have no more ideas how to fix this ... It worked earlier and then stopped.
Thymeleaf Resolver will look under templates/login/ for a login.html page. Based on your project structure and configuration, you rightly have a login folder inside template but you don't have a login.html inside the directory which is why the reason for the error.
Either create a login.html inside the login folder or use the index.html page which is already there. In your spring controller you should return the appropriate page.
For example,
Assuming that you need to show the login page your controller method should return,
return "login/login" // to display login.html under `templates/login`
or
return "login/index" // to display index.html under `templates/login`

Resources