SpringBoot + Thymeleaf + i18n (Internationalization)

Hello again.
This week I had to study how to implement i18n in a Spring Boot + Thymeleaf CRM application I am developing. Spring Boot really makes it easy to setup but while I was searching about it on the Web I found a lot of misinformation and so I decided to make a post about it.
As usual, you can find the complete project on Github: https://github.com/mtrojahn/springboot-thymeleaf-i18n.
Let’s start by the pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.marcelustrojahn</groupId> <artifactId>springboot-thymeleaf-i18n</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-thymeleaf-i18n</name> <description>Example on how to implement i18n with Spring Boot and Thymeleaf</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> <version>1.5</version> <executions> <execution> <goals> <goal>addSources</goal> <goal>addTestSources</goal> <goal>generateStubs</goal> <goal>compile</goal> <goal>testGenerateStubs</goal> <goal>testCompile</goal> <goal>removeStubs</goal> <goal>removeTestStubs</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Application.groovy
package com.marcelustrojahn.boot import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.context.annotation.ComponentScan @SpringBootApplication @ComponentScan(basePackages = ["com.marcelustrojahn.controllers"]) class Application { static void main(String[] args) { SpringApplication.run(Application, args) } }
As you can see, Application.groovy is pretty much the default for any Spring Boot application. I only changed @ComponentScan to lookup the package that contains my HelloWorldController.groovy but I could have easily created both files on the same package to avoid this configuration but hey, let’s do it the right way, right?
The HelloWorldController.groovy is very simple and just directs the “/helloworld” URL to it’s proper view.
package com.marcelustrojahn.controllers import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.GetMapping @Controller class HelloWorldController { @GetMapping("/helloworld") helloWorld() { "helloworld" } }
And here is the view:
<!DOCTYPE html> <html th:lang="${#locale.language}" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>i18n Example!</title> <meta charset="utf-8"/> </head> <body> <div th:text="#{helloworld}"></div> </body> </html>
A little explanation is in place here. The <html> tag has a th:lang=”${#locale.language}” which serves the purpose of informing your browser the language that is going to be displayed. This doesn’t have much impact but it’s a good thing to do so you avoid unexpected problems, like indexing by search engines and such.
Bellow you will se the “#{helloworld}” directive. “#{}” tags in Thymeleaf are about messages from i18n files. You won’t need to configure much about it because Spring Boot takes care of most of the work.
message.properties
helloworld=Hello World!
The message.properties file is where your default language is. Any other language has to have it’s own file and it’s name must be properly formatted. For example:
message_pt_BR.properties
helloworld=Olá Mundo!
If you use an IDE like Intellij IDEA, dealing with these files is very easy. The IDEA understand them and group them so you can edit these messages in batch.
Here’s the one catch. For your messages to be found you need to configure your application.yml properly
spring: messages: basename: i18n/messages
Now you just need to run your project. In my case, my system’s default language is English and I have Portuguese as an additional language pack on my Firefox browser. By default, the application will render in English so the resulting source will be this:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>i18n Example!</title> <meta charset="utf-8" /> </head> <body> <div>Hello World!</div> </body> </html>
If I change the default language of my browser to Portuguese, this is what I get:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="pt"> <head> <title>i18n Example!</title> <meta charset="utf-8" /> </head> <body> <div>Olá Mundo!</div> </body> </html>
To change the language pack on Firefox, go to Options / Content and click on Languages:
I hope this post helps you. Leave a comment if you need anything and until the next time!
thanks for this example help me a lot 10/10