How to switch between externalized messages in Spring with thymeleaf? - spring

Spring + thymeleaf
I want to display the message from Messages_pl.properties or Messages_en.properties depending on the need. And here's my problem as I don't know what to do when I want to view a message from the second file ( Messages_pl.properties is taken into account by default).
To access resource bundles by using specified basename I added the bean below to my #Configuration class:
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("Messages");
return messageSource;
}
Messages_pl.properties:
welcome.message=siemanko
Messages_en.properties:
welcome.message=hello
The fragment of my html file where I use this property:
<h1 th:text="#{message.welcome}"></h1>
Result: siemanko
what should I do to get the result as hello?

You can define on the same file Messages.properties the following :
welcome.message.pl=siemanko
welcome.message.en=hello
Then you can can a local resolver to make your project capable of determining the locale which is currently being used :
#Bean
public LocaleResolver localeResolver() {
return new CookieLocaleResolver();
}
Then add an interceptor of your language :
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
After that its simple to switch between languages , you just have to change the value of parameter lang on your link :
localhost:8080/your_page?lang=pl // will show siemanko on your page
localhost:8080/your_page?lang=en // will show hello on your page

Related

Add the language in the url / fr /, / en /, etc internationalization spring boot mvc

I followed this tutorial
https://www.baeldung.com/spring-boot-internationalization
I managed to get it to work: when I put the following url www.example.com/?lang=en I have the English version that is displayed.
However, I want to "convert" it so that the lang is directly in the example url www.example.com/en/ or www.example.com/fr/.
So i have this
#Configuration
public class Locale implements WebMvcConfigurer {
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
return slr;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
localeInterceptor.setParamName("lang");
return localeInterceptor;
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
I was thinking of using a filter, which will redirect to www.example.com/en/ or / fr / and if it can't find the language, configure the controller that if / {language} is null then it ignores it.
However, I do not know if my approach is good and especially I do not know how to retrieve the information of the language in the filter.
Could you help me ?
thank you

Problems adding spring webflow to a spring boot and joinfaces application

I am trying to add webflow to a spring boot app using joinfaces library.
I am using primefaces-spring-boot-starter and jetty-spring-boot-starter to configure jetty server.
Added necessary webflow dependencies to pom and configured necessary flowregistry, flowbuilderservices, flowexecutor and flowhandlermapping, ...
The application start correctly, reads the flows definitions from xmls and if enter to a flow via url the decision states are running correctly, reads the corresponding view state .xhtml file, calls the managed bean methods, and all are working apparently well.
But... once finished executing bean methods, when I hope to html be rendered in browser, the application is redirected to app root folder without any error in the log.
I have this behavior with all the flows of the application. Bean methods are executed correctly and when I hope to see the html... redirected to root.
Anyone tried to add webflow to a joinfaces jsf application successfully? I am missing to override some default configuration of joinfaces?
Thanks.
public class MvcConfiguration implements WebMvcConfigurer {
#Autowired
private WebFlowConfiguration webFlowConfiguration;
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.webFlowConfiguration.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
JsfFlowHandlerAdapter adapter = new JsfFlowHandlerAdapter();
adapter.setFlowExecutor(this.webFlowConfiguration.flowExecutor());
return adapter;
}
#Bean
public ViewResolver faceletsViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setViewClass(JsfView.class);
resolver.setPrefix("/");
resolver.setSuffix(".xhtml");
return resolver;
}
}
#Configuration
public class WebFlowConfiguration extends AbstractFacesFlowConfiguration {
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.setBasePath("classpath*:/META-INF/resources/flows")
.addFlowLocationPattern("/**/*.xml")
.setFlowBuilderServices(flowBuilderServices())
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setDevelopmentMode(true)
.setViewFactoryCreator(new JsfViewFactoryCreator())
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(new FlowFacesContextLifecycleListener())
.addFlowExecutionListener(new SecurityFlowExecutionListener())
.setMaxFlowExecutionSnapshots(0)
.build();
}
}

Spring Boot 2 Thymeleaf Configuration Ignoring 'templates'

I'm migrating an existing application to Spring 5.0.0.M3 & Spring Boot 2.0.0.M3. With Spring Boot I'm also importing the Thymeleaf starter.
The application has 2 template folders mails and templates. If I specify the below configuration for email templates, the templates folder is ignored; e.g. I'm getting FileNotFoundException for templates in this folder.
#Configuration
public class ThymeleafConfiguration {
#SuppressWarnings("unused")
private final Logger log = LoggerFactory.getLogger(ThymeleafConfiguration.class);
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("mails/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
}
I've tried setting the setOrder parameter to 2, 10, etc. which made no difference. If I remove the resolver method, the templates folder is recognized, but the mails folder isn't.
Any ideas what might be going on?
What I understand is you have mails and templates sub-folders under the resources folder.
You can add resource folder as the prefix in your ClassLoaderTemplateResolver. Then add ResourceHandler for both mails and templates sub-folders.
ClassLoaderTemplateResolver
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new
ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("resources/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
Place your ResourceHandler method in your application class, which your have annotated with #SpringBootApplication.
ResourceHandler
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/mails/**")) {
registry.addResourceHandler("/mails/**").addResourceLocations("classpath:/resources/mails/");
}
if (!registry.hasMappingForPattern("/templates/**")) {
registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/resources/templates/");
}
}
When you return your view name from any method, it can be like:
return "mails/page1";
or
return "templates/page2";

Spring Boot Controller Locale Not Changing with Parameter

I'm having some trouble with using Spring Boot with Kotlin to handle locale. I created these settings in my application.properties file:
spring.messages.basename=messages/messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8
Then created an autowired instance of MessageSource in my controller:
#Autowired
lateinit var messageSource: MessageSource
When put a locale in the url as a parameter, the parameter doesn't seem to get picked up when I call LocaleContextHolder.getLocale(), so it is always en_US. Though, I can manually pick it up using #RequestParam(value="locale") locale: Locale as a parameter to my controller function and use it from there in the controller function, but not in other functions. I thought that spring boot LocaleContextHolder was supposed to hold the current locale based on the request URL automatically for the whole session.
I read an older article that mentioned using a LocaleChangeInterceptor bean as well as beans for MessageSource and LocaleResolver in your main class, but another article said Spring Boot doesn't require that. I tried it anyway with no difference. These are the functions I used:
#Bean
open fun localeResolver(): LocaleResolver {
val slr = SessionLocaleResolver()
slr.setDefaultLocale(Locale.US)
return slr
}
#Bean
open fun localeChangeInterceptor(): LocaleChangeInterceptor {
val localeChangeInterceptor = LocaleChangeInterceptor()
localeChangeInterceptor.paramName = "locale"
return localeChangeInterceptor
}
#Bean
open fun messageSource(): ResourceBundleMessageSource {
val source = ResourceBundleMessageSource()
source.setBasenames("messages/messages")
source.setDefaultEncoding("UTF-8")
return source
}
Any suggestions on what to try next other than capturing the locale manually and making it a parameter in every function that gets called by the controller? Thanks!
OK, looks like the missing piece was implementing a WebMvcConfigurerAdapter, setting up a SessionLocaleResolver bean, and overriding the addInterceptors function to manually add my LocaleChangeInterceptor. I used a separate Configuration class to do this.
#Configuration
open class CustomWebMvcConfigurerAdapter : WebMvcConfigurerAdapter() {
//internationalization beans
#Bean
open fun localeResolver(): LocaleResolver {
val slr = SessionLocaleResolver()
slr.setDefaultLocale(Locale.US)
return slr
}
#Bean
open fun localeChangeInterceptor(): LocaleChangeInterceptor {
val localeChangeInterceptor = LocaleChangeInterceptor()
localeChangeInterceptor.paramName = "locale"
return localeChangeInterceptor
}
override fun addInterceptors(registry: InterceptorRegistry?) {
registry?.addInterceptor(localeChangeInterceptor())
super.addInterceptors(registry)
}
}
I guess I misunderstood, thinking that Spring Boot handled the LocaleChangeInterceptor on it's own if you created the proper bean, but I guess you have to still override a WebMvcConfigurerAdapter and force the interceptor in there. If I've missed something and someone has a cleaner solution, I'd be happy to give you the accepted answer since what I'm doing here just feels like a messy workaround.

LocalContextHandler usage

I am very new to LocalContexHandler. I have read about it. From what I understood it is used to retrieve locale information in a java application.
I am passing the locale from the url as follows:
url?lang = fr
When I am trying to retrieve the locale in java application as follows:
Locale locale = LocaleContextHolder.getLocale();
It is giving null value. Can someone help me understand it's usage or is there any other alternative for the same?
If you want to pass locale in URL you must register LocaleChangeInterceptor interceptor and create LocaleResolver bean. For example SessionLocaleResolver stores chosen locale in session. Then LocaleContextHolder#getLocale will return not-null value. Take a look in Spring documentation to section Using locales. Below you can see basic Java configuration for you example.
If you want just use LocaleContextHolder you have to call LocaleContextHolder#setLocale from your code before calling LocaleContextHolder#getLocale. It's just simple holder class that stores LocaleContext in ThreadLocal variable.
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// Rest of Web MVC configuration omitted
#Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(localeChangeInterceptor());
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale("fr");
return sessionLocaleResolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
}

Resources