Software localization

How to Internationalize Basic JSP/Servlet Web Applications (i18n)

Let's explore the possibilities of internationalizing a basic JSP/Servlet web app and how to use JSTL Taglib to localize a JSP page.
Software localization blog category featured image | Phrase

First things first, we will learn how to use JSTL Taglib to localize a JSP page. Furthermore, we will demonstrate the use of request parameter, session attribute, and the cookie value to choose a preferred language in a JSP page. Besides, we will use Maven to set up the project. Hence, we expect the reader has a basic knowledge of Java Web Application, JSP, JSTL, and Maven. You can find the full implementation of this tutorial on Phrase's GitHub.

1. Project Setup

For this simple JSP/Servlet Web Application, we only need to add jstl and javax.servlet-api dependencies into our pom.xml file:

<properties>

    <servlet.version>3.1.0</servlet.version>

    <jstl.version>1.2</jstl.version>

</properties>

<dependencies>

    <dependency>

        <groupId>jstl</groupId>

        <artifactId>jstl</artifactId>

        <version>${jstl.version}</version>

    </dependency>

    <dependency>

        <groupId>javax.servlet</groupId>

        <artifactId>javax.servlet-api</artifactId>

        <version>${servlet.version}</version>

        <scope>provided</scope>

    </dependency>

</dependencies>

We can find the latest version of those dependencies on Maven Central: jstl, javax.servlet-api

2. Localize A JSP Page

The basic approach to localize a JSP page is using JSTL in combination with resource bundles. Resource bundles are properties files which contain key-value pairs. Each value is a message which we want to show on the page. Whereas the key will be used to refer to that value on our JSP page. Thus, for each supported language, we will have one specific properties file.

Now, let's create a default messages.properties file under src/main/resources as below:

label.welcome = Welcome

Next, we create a welcome.jsp page and put under /webapp folder:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@ page isELIgnored="false" %>

<fmt:setBundle basename="messages"/>

<html>

<head>

    <title>PhraseApp - i18n</title>

</head>

<body>

    <h2>

        <fmt:message key="label.welcome" />

    </h2>

</body>

</html>

In this page, we use <fmt:setBundle> tag to set the resource bundle

Because our resource bundle file is messages.properties, thus, we set the value of basename attribute as messages. Moreover, we use <ftm:message> tag to refer to the defined key in our properties file.

Deploy the project on an Application Server (Tomcat 8.5 at port 8080 in this case) and access welcome.jsp page, we will see below result:

Project on application server in English | Phrase

Since we haven't mentioned which locale we want to use for the page, the message in default messages.properties file is used.

Now, we try to support the French language by adding another resource bundle file which is messages_fr.properties as below:

label.welcome = Bienvenue

Then, we modified the welcome.jsp page to use this new language:

.....

<fmt:setLocale value="fr"/>

<fmt:setBundle basename="messages" />

.....

Here, by using <fmt:setLocale> tag to set the preferred locale to fr, the new messages_fr.properties file will be used when we load the page. Consequently, we will see below result:

Project on application server in French | Phrase

Until here, we can notice that the name of resource bundle properties file will have below format:

[basename]_[locale].properties

Thereupon, we can support other languages, for example, Chinese and German by adding messages_zh.properties and messages_de.properties.

It's worth to note that if we set the locale to a non-existing resource bundle file, the application will use the messages.properties file as default for displaying.

3. Choosing Locale Dynamically

We have explored how to set a preferred locale for a JSP page. It would be useful if we know how to do this dynamically. In this section, we will see how to set a page locale by using request parameter, session attribute, and browser cookie.

3.1. Using Request Parameter As Locale

Let's create the requestLocale.jsp as below:

<%@ page contentType="text/html;charset=UTF-8" language="java"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page isELIgnored="false"%>

<fmt:setLocale value="${param.lang}" />

<fmt:setBundle basename="messages" />

<html lang="${param.lang}">

<head>

<title>PhraseApp - i18n</title>

</head>

<body>

	<h2>

            <fmt:message key="label.chooseRequestLocale" />

        </h2>

	<p>

            <fmt:message key="label.requestLocaleContent" />

        </p>

	<p>

            <fmt:message key="label.changeLang" />

        </p>

	<ul>

		<li><a href="?lang=en"><fmt:message key="label.lang.en" /></a></li>

		<li><a href="?lang=de"><fmt:message key="label.lang.de" /></a></li>

		<li><a href="?lang=fr"><fmt:message key="label.lang.fr" /></a></li>

		<li><a href="?lang=zh"><fmt:message key="label.lang.cn" /></a></li>

	</ul>

</body>

</html>

In this page, we set the locale to the value of request parameter lang. Thus, when accessing the page which the parameter lang=zh, we will see below result:

Project on application server in Chinese | Phrase

3.2. Using Session Attribute As Locale

Likewise, to set the locale by using a session attribute, we can implement sessionLocale.jsp as below:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@ page isELIgnored="false" %>

<%@ page session="true" %>

<fmt:setLocale value="${sessionScope.lang}"/>

<fmt:setBundle basename="messages"/>

<html lang="${sessionScope.lang}">

<head>

    <title>PhraseApp - i18n</title>

</head>

<body>

	<h2>

	    <fmt:message key="label.welcome" />

	</h2>

	<p>

            <fmt:message key="label.sessionLocaleContent" />

        </p>

</body>

</html>

In this example, we refer to attribute lang in sessionScope as preferred locale.

Therefore, let's create a SessionLocaleFilter to allow us updating the session attribute lang:

@WebFilter(filterName = "SessionLocaleFilter", urlPatterns = {"/*"})

public class SessionLocaleFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

      throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        if (req.getParameter("sessionLocale") != null) {

            req.getSession().setAttribute("lang", req.getParameter("sessionLocale"));

        }

        chain.doFilter(request, response);

    }

    public void destroy() {}

    public void init(FilterConfig arg0) throws ServletException {}

}

This filter will check if the request parameter sessionLocale is available for the incoming request. If yes, the filter will update the attribute lang of the current session to that value.

Now, let's create a changeLocale.jsp page to help us update this session attribute:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@ page isELIgnored="false" %>

<fmt:setLocale value="${param.lang}"/>

<fmt:setBundle basename="messages"/>

<html lang="${param.lang}">

<head>

    <title>PhraseApp - i18n</title>

</head>

<body>

	<h2>

		<fmt:message key="label.chooseSessionLocale" />

	</h2>

	<ul>

		<li><a href="?sessionLocale=en"><fmt:message key="label.lang.en" /></a></li>

		<li><a href="?sessionLocale=de"><fmt:message key="label.lang.de" /></a></li>

		<li><a href="?sessionLocale=fr"><fmt:message key="label.lang.fr" /></a></li>

		<li><a href="?sessionLocale=zh"><fmt:message key="label.lang.cn" /></a></li>

	</ul>

	<c:if test="${not empty param.sessionLocale}">

		<fmt:message key="label.cookieChangeSuccess" />

		<button><a href="sessionLocale.jsp"><fmt:message key="label.viewPage" /></a></button>

	</c:if>

</body>

</html>

Then, we can run the application to access this changeLocale.jsp page and choose the German language. After that, we open our sessionLocale.jsp to see the result as below:

Project on application server in German| Phrase

3.3. Using Browser Cookie As Locale

Accordingly, using the same method, we can implement a page which uses the value of a browser cookie as locale. Thus, we have below cookieLocale.jsp page:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@ page isELIgnored="false" %>

<%@ page session="true" %>

<fmt:setLocale value="${cookie['lang'].value}"/>

<fmt:setBundle basename="messages"/>

<html lang="${cookie['lang'].value}">

<head>

    <title>PhraseApp - i18n</title>

</head>

<body>

	<h2>

	    <fmt:message key="label.welcome" />

	</h2>

	<p>

            <fmt:message key="label.cookieLocaleContent" />

        </p>

</body>

</html>

Suppose that we store the locale in the cookie by the key lang. Hence, we access this cookie value by using the expression cookie['lang'].value. Thus, our page will use that value as preferred locale.

Furthermore, we need to create a CookieLocaleFilter which helps us changing browser cookie value before we can test our page:

@WebFilter(filterName = "CookieLocaleFilter", urlPatterns = { "/*" })

public class CookieLocaleFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

      throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        HttpServletResponse res = (HttpServletResponse) response;

        if (req.getParameter("cookieLocale") != null) {

            Cookie cookie = new Cookie("lang", req.getParameter("cookieLocale"));

            res.addCookie(cookie);

        }

        chain.doFilter(request, response);

    }

    public void destroy() {}

    public void init(FilterConfig arg0) throws ServletException {}

}

For each incoming request, the above filter will check if a parameter cookieLocale is available. If yes, its value will be set to browser cookie with the key lang.

Again, let's update the changeLocale.jsp to allow us changing this cookie value:

...

        <h2>

		<fmt:message key="label.chooseCookieLocale" />

	</h2>

	<ul>

		<li><a href="?cookieLocale=en"><fmt:message key="label.lang.en" /></a></li>

		<li><a href="?cookieLocale=de"><fmt:message key="label.lang.de" /></a></li>

		<li><a href="?cookieLocale=fr"><fmt:message key="label.lang.fr" /></a></li>

		<li><a href="?cookieLocale=zh"><fmt:message key="label.lang.cn" /></a></li>

	</ul>

	<c:if test="${not empty param.cookieLocale}">

		<fmt:message key="label.cookieChangeSuccess" />

		<button><a href="cookieLocale.jsp"><fmt:message key="label.viewPage" /></a></button>

	</c:if>

...

Similarly, let's run the application and open this changeLocale.jsp to choose Chinese as cookie locale. Then we can access cookieLocale.jsp to view the result:

Project on application server in Chinese | Phrase

4. Conclusion

In this article, we have explored how to localize a JSP page on a basic Java Web Application. Moreover, we also learn how to choose locale dynamically by using request parameter, session attribute, and browser cookie.

Our approach is using JSTL in combination with resource bundle where we use <ftm:setLocale> and <ftm:setBundle> to refer to a resource bundle properties file.

Please view our Github repository for full implementation of this article.

Ready to delve deeper into the world of internationalization and localization in Java? The following guides will get you started on the right path: