It’s a global economy. That’s why it’s a great idea to set up your Spring Boot app with internationalization.

Once you go international, you can reach more people in their native language. That’s a great way to increase your market share and build brand-name awareness.

Fortunately, Spring Boot makes it easy to implement internationalization. In this article, we’ll show you how to set up a website that supports three languages: English, French, and Spanish.

As is usually the case, you can check out the complete source code on GitHub.

 

Instantiate the LocaleResolver Object

The first step is to create a new configuration class and use it to instantiate a LocaleResolver object. Here’s what that code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
public class InternationalizationConfig extends WebMvcConfigurerAdapter {
     
    /**
     * Instantiate the appropriate locale resolution strategy
     * @return locale resolver
     */
    @Bean
    public LocaleResolver localeResolver() {
        //for this demo, we'll use a SessionLocaleResolver object
        //as the name implies, it stores locale info in the session
        SessionLocaleResolver resolver = new SessionLocaleResolver();
         
        //default to US locale
        resolver.setDefaultLocale(Locale.US);
         
        //get out
        return resolver;
    }
 
    ...

As you can see, the class itself is annotated with @Configuration. That tells Spring that methods within the class will create Spring-managed beans.

Indeed, that’s why the localeResolver() method is annotated with @Bean. The method returns an object that Spring’s container will manage.

In this case, localeResolver() is instantiating SessionLocaleResolver. That bean is used to store locale settings in the session.

Next, the method sets the default locale to Locale.US. That means if no locale is specified, it defaults to US-English.

Finally, the method returns the object.

 

Instantiate the LocaleChangeInterceptor Object

Once you’re done with the resolver, it’s time to create the interceptor. That’s the class that allows visitors to change the locale on a per-request basis.

How does it do that? With the use of the “lang” request parameter. That’s why you see the setParam() method in the code block below.

1
2
3
4
5
6
7
8
9
10
11
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
    //instantiate the object with an empty constructor
    LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
     
    //the request param that we'll use to determine the locale
    interceptor.setParamName("lang");
     
    //get out
    return interceptor;
}

 

Override the addInterceptors() Method

If you look again at the first code block above, you’ll see that the configuration class extends WebMvcConfigurerAdapter. That’s necessary to override the addInterceptors() method.

As the name implies, the addInterceptors() method will add the interceptor to the registry.

Here’s what that code looks like:

1
2
3
4
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(localeChangeInterceptor());
}

 

 

Create the Controller

The next step is fairly simple: just create a controller that forwards the user to the front-end. Here’s what that code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class InternationalController {
 
    @RequestMapping(value = "/international", method=RequestMethod.GET)
    public String international() {
        return "international";
    }
     
    //redirect to demo if user hits the root
    @RequestMapping("/")
    public String home(Model model) {
        return "redirect:international";
    }
}

The first method handles the /international URL path. The second method forwards the visitor to that path if he or she tries to hit the root.

 

Define the Messages

When it comes to internationalization, it’s typically handled by putting messages, labels, titles, etc. in properties files. There’s usually a single properties file per language.

The default properties file in this case is called messages.properties. Recall from above that you specified Locale.US as the default locale so you’ll put English text in messages.properties.

1
2
3
4
5
6
home.page.title=This is the English version of this website
home.page.change.header=Change the language
home.page.change.label=Select language
home.page.change.lang.en=English
home.page.change.lang.fr=French
home.page.change.lang.es=Spanish

Once you’ve saved that file, create a new properties file for each additional language that you’ll support. In this case, you need two more files because you’re supporting French and Spanish in addition to English.

Properties files for different languages typically follow the format: <file name>_<lang>.properties

Note that the “<lang>” part there is a two-letter language code.

For the purposes of this app, the pattern above translates to messages_fr.properties for French and messages_es.properties for Spanish.

Here’s what the French properties file looks like:

1
2
3
4
5
6
home.page.title=Ceci est la version française de ce site
home.page.change.header=Changer la langue
home.page.change.label=Choisir la langue
home.page.change.lang.en=Anglais
home.page.change.lang.fr=français
home.page.change.lang.es=Espanol

And here’s what the Spanish properties file looks like:

1
2
3
4
5
6
home.page.title=Esta es la versión en inglés de este sitio web
home.page.change.header=Cambia el idioma
home.page.change.label=Seleccione el idioma
home.page.change.lang.en=Inglés
home.page.change.lang.fr=francés
home.page.change.lang.es=Español

Keep in mind that you should save your properties files in /src/main/resources. That’s where Spring Boot will look for them.

 

Create the Front End

Once you’ve completed saving your properties files, it’s time to work on the front end.

The front-end code is an HTML file that uses Thymeleaf to create dynamic content. Here’s the relevant part of the code that displays a locale-specific title:

1
2
3
<div class="col-md-6 ">
    <h1 th:text="#{home.page.title}"></h1>
</div>

Here, the code is reading the home.page.title property from one of the properties files that you just created. It prints out the title in the appropriate language.

How does the system know which properties file to use? It looks at the “lang” paramter in the request URL. If that parameter doesn’t exist, then it defaults to English.

 

Allow Visitors to Change the Language

Since the purpose of this tutorial is to demonstrate how to display the home page of a website in different languages, it makes sense to enable visitors to change the language. You can do that with a simple dropdown.

Here’s what that code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div class="portlet light ">
    <div class="portlet-title">
        <div class="caption">
            <i class="icon-globe"></i>
            <span class="caption-subject bold uppercase" th:text="#{home.page.change.header}"></span>
        </div>
    </div>
    <div class="portlet-body form">
        <form role="form">
            <div class="form-body">
                <div class="form-group">
                    <label th:text="#{home.page.change.label}"></label>
                    <div class="input-group">
                        <span class="input-group-addon">
                            <i class="fa fa-question"></i>
                        </span>
                        <select id="languageSelect" class="form-control">
                            <option value="">--SELECT--</option>
                            <option value="en" th:text="#{home.page.change.lang.en}"></option>
                            <option value="es" th:text="#{home.page.change.lang.es}"></option>
                            <option value="fr" th:text="#{home.page.change.lang.fr}"></option>
                        </select>
                    </div>
                </div>
            </div>
        </form>
    </div>
</div>

Take a cursory glance at that code and you’ll see that it’s referencing a couple of additional properties: home.page.change.header and home.page.change.label. Again, those values are retrieved from locale-specific properties files.

The options in the <select> element also rely on the properties files. They display locale-specific names of different languages (English, Spanish, and French). The user has the opportunity to select any one of those languages from the dropdown.

What happens when the user selects a dropdown? Well, nothing by default. That’s why you need to add a listener.

1
2
3
4
5
6
7
8
9
10
<script type="text/javascript">
    $(document).ready(function() {
        $("#languageSelect").change(function () {
            var selectedOption = $('#languageSelect').val();
            if (selectedOption != '') {
                window.location.replace('./international?lang=' + selectedOption);
            }
        });
    });
</script>

That’s some fairly simple jQuery code. It instantly reloads the page with the “lang” request parameter set according to the language the user selected.

 

Testing It Out

Now that the coding is done, it’s time to test out your Spring Boot app. Run the application and hit the following URL:

http://localhost:8090/

That should forward you to the /international path. There, you should see the home page displayed in the default language (English):

internationalization

 

Now, select “French” from the dropdown and watch what happens. Your web page should refresh and display the following:

internationalization2

 

As you can see, not only has the text on the page changed to French, but the URL itself includes the “lang” request parameter and it’s set to “fr” (for “French”).

Congratulations! You now have internationalization!

 

Wrapping It Up

Many webmasters disregard internationalization because they think it’s too complicated. However, it’s easier than many of them realize.

If you’ve blown off internationalization in the past, why not take a few moments today to add it to your own Spring Boot app? You’ll give your website a global presence.

Drop by GitHub to view the complete source.

Have fun!