JSF 2 Internationalization example

This tutorial JSF 2 internationalization example shows how you make an web based application in different languages. I will show here how you can switch in different languages like Bengali, Hindi, English, Dutch and French. You don’t need to change the language settings from the browser for switching to different languages. I have given user an option to choose a language in a dropdown where the languages are displayed in Bengali, Hindi, English, Dutch and French.

If you want you can add more languages and accordingly you need to create separate properties file for each language and configure the supported-locale in faces-config.xml file.

This application shows title, welcome message, choose language option and copyright information in Bengali, Hindi, English, Dutch and French languages. By default the selected language is English. You can also set the default language as per your choice, for that you have to configure in the LocaleSwitcher.java managed bean.

Related Posts:

Final Output

Choose language

jsf 2 internationalization

English

jsf 2 internationalization

Bengali

jsf 2 internationalization

Hindi

jsf 2 internationalization

Dutch

jsf 2 internationalization

French

jsf 2 internationalization

Prerequisites

Java at least 1.8, Gradle 6.5.1, Maven 3.6.3, JSF 2.2.20

Project Setup

Create a gradle or maven based project in Eclipse. The name of the project is jsf-2-internationalization-i18n.

If you creating gradle based project then use below build.gradle script:

plugins {
    id 'war'
    id 'java-library'
}

repositories {
    jcenter()
}

dependencies {
    implementation 'com.sun.faces:jsf-api:2.2.20'
    implementation 'com.sun.faces:jsf-impl:2.2.20'
    implementation 'javax.enterprise:cdi-api:2.0.SP1'
}

If you are creating maven based project then use below pom.xml file:

<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/maven-v4_0_0.xsd">
	
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.roytuts</groupId>
	<artifactId>jsf-2-internationalization-i18n</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	
	<dependencies>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.2.20</version>
		</dependency>
		
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.2.20</version>
		</dependency>
		
		<dependency>
			<groupId>javax.enterprise</groupId>
			<artifactId>cdi-api</artifactId>
			<version>2.0.SP1</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	
	<build>
		<finalName>jsf2-immediate-attribute</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>12</source>
					<target>12</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Deployment Descriptor – web.xml

I have modified the deployment descriptor file for jsf support and welcome file rendered as home page once the application starts up.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	
	<display-name>JSF 2 i18n - Internationalization</display-name>
	
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>
	
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
	
	<session-config>
		<session-timeout>
			30
		</session-timeout>
	</session-config>
	
	<welcome-file-list>
		<welcome-file>index.jsf</welcome-file>
	</welcome-file-list>
</web-app>

In the above web.xml file there are several properties as shown below:

<context-param>
	<param-name>javax.faces.PROJECT_STAGE</param-name>
	<param-value>Development</param-value>
</context-param>

This context-param tells which environment you will use. Environments can be Development, SystemTest, UnitTest, Extension and Production.

So I will use here Development because I want to get all the benefits for debugging, testing, error reporting etc. for developing the application.

<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

The above configuration uses FacesServlet which is related to Java Server Faces. All requests and responses from the client route through this FacesServlet.

You have also <load-on-startup/> for loading the FacesServlet at the same time when the application starts up.

You can have any value from 0 to 127 for <load-on-startup/>.

<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

You need to map the URL pattern for each request/response coming from the client. We can have *.jsf, *.faces and *.xhtml for <url-pattern/>.

Remember you cannot have multiple URL pattern for JSF application but other applications, such as, Struts can have multiple pattern for client requests.

<session-config>
	<session-timeout>
		30
	</session-timeout>
</session-config>

The above configuration is required only if are going to use http session for putting some objects in session like login based application.

<welcome-file-list>
	<welcome-file>index.jsf</welcome-file>
</welcome-file-list>

This holds a list of welcome files but remember only one of them will be used – the first one which matches with the URL pattern and file is found in the root directory.

Notice that file extension has .jsf because it should match with the URL pattern otherwise it will give you 404 – page not found.

Resource Bundle or Properties Files

Now I will create properties files for each language. The below properties files are kept under classpath folder src/main/resources.

BengaliMessages_bn.properties

i18n=JSF 2.2 এ আন্তর্জাতিকায়ন উদাহরণ
welcome=বাংলা ভাষা স্বাগতম
chooseLang=আপনার ভাষা চয়ন করুন
copyright=কপিরাইট
2014=2014-2020

Hindi – Messages_hi.properties

i18n=JSF 2.2 में अंतर्राष्ट्रीयकरण उदाहरण
welcome=हिन्दी भाषा में आपका स्वागत है
chooseLang=अपनी भाषा चुनें
copyright=सर्वाधिकार
2014=2014-2020

English – Messages.properties

i18n=Internationalization Example in JSF 2.2
welcome=Welcome to English Language
chooseLang=Choose your language
copyright=Copyright
2014=2014-2020

Dutch – Messages_nl.properties

i18n=Internationalisering Voorbeeld in JSF 2.2
welcome=Welkom bij Nederlandse Taal
chooseLang=Kies uw taal
copyright=Auteursrecht
2014=2014-2020

French – Messages_fr.properties

i18n=Internationalisation exemple dans JSF 2.2
welcome=Bienvenue à la langue française
chooseLang=Choisissez votre langue
copyright=Droit d'auteur
2014=2014-2020

JSF Managed Bean

Now look at the below JSF Managed Bean LocaleSwitcher.java. Default locale is set to English language.

package com.roytuts.jsf.internationalization.i18n;

import java.io.Serializable;
import java.util.Locale;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;

@ViewScoped
@ManagedBean
public class LocaleSwitcher implements Serializable {

	private static final long serialVersionUID = 1L;

	/**
	 * Creates a new instance of LocaleSwitcher
	 */
	public LocaleSwitcher() {
	}

	// default language - english(en)
	private String language = "en";

	// get the current locale from facescontext
	private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

	public Locale getLocale() {
		return locale;
	}

	public void setLocale(Locale locale) {
		this.locale = locale;
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	// when dropdown value gets changed - so the language and locale
	public void onLanguageChange(ValueChangeEvent vce) {
		if (vce != null) {
			String l = vce.getNewValue().toString();
			setLanguage(l);
			locale = new Locale(l);
			FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
		} else {
			FacesContext.getCurrentInstance().getViewRoot().setLocale(Locale.ENGLISH);
		}
	}

}

Locale Configuration

Create face-config.xml file and put it under WEB-INF with the below source code.

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
	<application>
		<!-- locale configuration -->
		<locale-config>
			<!-- default locale and supported locales -->
			<default-locale>en</default-locale>
			<supported-locale>bn</supported-locale>
			<supported-locale>hi</supported-locale>
			<supported-locale>nl</supported-locale>
			<supported-locale>fr</supported-locale>
		</locale-config>
		
		<!-- resource bundle configuration -->
		<resource-bundle>
			<!-- properties file base name with full package -->
			<base-name>
				Messages
			</base-name>
			<!-- properties file key will be accessed using this variable #{msg.keyName}, 
				where keyName is the property file key -->
			<var>msg</var>
		</resource-bundle>
	</application>
</faces-config>

JSF Template Files

I will use template so that you don’t need to copy common code like header/footer and most importantly here is <f:view locale=””/> tag in every page.

So put the template file under WEB-INF/template so that it cannot be tempered from outside the world.

main.xhtml

Look at the below template file with <ui:insert/> tag whose content can be overridden by template client file.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:f="http://xmlns.jcp.org/jsf/core"
	lang="#{localeSwitcher.language}">
	
<f:view locale="#{localeSwitcher.locale}">
	<h:head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<h:outputStylesheet library="css" name="default.css" />
		<h:outputStylesheet library="css" name="cssLayout.css" />
		<title><ui:insert name="title" /></title>
	</h:head>
	<h:body>
		<div id="top">
			<!-- header part -->
			<ui:insert name="top">
				<ui:include src="header.xhtml" />
			</ui:insert>
		</div>
		
		<div id="content" class="center_content">
			<ui:insert name="content"></ui:insert>
		</div>
		
		<div id="bottom">
			<ui:insert name="bottom">
				<ui:include src="footer.xhtml" />
			</ui:insert>
		</div>
	</h:body>
</f:view>
</html>

header.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
	xmlns:f="http://xmlns.jcp.org/jsf/core">
<body>
	<ui:composition>
		<h:form prependId="false">
			<h:panelGrid columns="3">
				<h:outputText value="#{msg.i18n}" />
				<h:outputLabel>&nbsp;|&nbsp;</h:outputLabel>
				<h:panelGroup>
					<h:outputText value="#{msg.chooseLang}" />
					<h:selectOneMenu value="#{localeSwitcher.language}"
						onchange="submit()" style="margin-left:5px;"
						valueChangeListener="#{localeSwitcher.onLanguageChange}">
						<f:selectItem itemValue="bn" itemLabel="বাংলা" />
						<f:selectItem itemValue="hi" itemLabel="हिंदी" />
						<f:selectItem itemValue="en" itemLabel="English" />
						<f:selectItem itemValue="nl" itemLabel="Nederlands" />
						<f:selectItem itemValue="fr" itemLabel="Français" />
					</h:selectOneMenu>
				</h:panelGroup>
			</h:panelGrid>
		</h:form>
	</ui:composition>
</body>
</html>

footer.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<body>
	<ui:composition>
		<p style="text-align: left; width: 100%;">
			<h:outputText value="#{msg.copyright} &copy; 2014-2020" escape="false" />
		</p>
	</ui:composition>
</body>
</html>

Now I will look into the index.xhtml file. This is a template client file.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<body>
	<ui:composition template="./WEB-INF/template/main.xhtml">
		<ui:define name="title">
			#{msg.i18n}
		</ui:define>
		<ui:define name="content">
			<h:outputText value="#{msg.welcome}"></h:outputText>
		</ui:define>
	</ui:composition>
</body>
</html>

Styles

Simple css styling under wepapp/resources/css directory.

cssLayout.css

#top {
	position: relative;
	background-color: #036fab;
	color: white;
	padding: 5px;
	margin: 0px 0px 10px 0px;
}

#bottom {
	position: relative;
	background-color: #c2dfef;
	padding: 5px;
	margin: 10px 0px 0px 0px;
}

#left {
	float: left;
	background-color: #ece3a5;
	padding: 5px;
	width: 150px;
}

#right {
	float: right;
	background-color: #ece3a5;
	padding: 5px;
	width: 150px;
}

.center_content {
	position: relative;
	background-color: #dddddd;
	padding: 5px;
}

.left_content {
	background-color: #dddddd;
	padding: 5px;
	margin-left: 170px;
}

.right_content {
	background-color: #dddddd;
	padding: 5px;
	margin: 0px 170px 0px 170px;
}

#top a:link, #top a:visited {
	color: white;
	font-weight: bold;
	text-decoration: none;
}

#top a:link:hover, #top a:visited:hover {
	color: black;
	font-weight: bold;
	text-decoration: underline;
}

default.css

body {
	background-color: #ffffff;
	font-size: 12px;
	font-family: Verdana, "Verdana CE", Arial, "Arial CE",
		"Lucida Grande CE", lucida, "Helvetica CE", sans-serif;
	color: #000000;
	margin: 10px;
}

h1 {
	font-family: Arial, "Arial CE", "Lucida Grande CE", lucida,
		"Helvetica CE", sans-serif;
	border-bottom: 1px solid #AFAFAF;
	font-size: 16px;
	font-weight: bold;
	margin: 0px;
	padding: 0px;
	color: #D20005;
}

a:link, a:visited {
	color: #045491;
	font-weight: bold;
	text-decoration: none;
}

a:link:hover, a:visited:hover {
	color: #045491;
	font-weight: bold;
	text-decoration: underline;
}

That’s all. Hope you got idea how to internationalize JSF 2 application.

Source Code

Download

Thanks for reading.

Related posts

2 Thoughts to “JSF 2 Internationalization example”

  1. pj

    In jsf 2.2 we don’t use faces-config.xml anymore isn’t it? so how to do ? Thans

    1. even in jsf 2.2 you can use faces-config.xml file

Leave a Comment