Spring – Resource Bundle Message Source (i18n)
A software is a multi purpose usage one. By using Message Source, it can be applicable to all languages. That concept is called i18n, that is according to the user locality, dynamic web pages are rendered in the user screen. We need to keep all the constants in a separate properties file which matches to each and every locality. In this article, let us see how it can be handled in spring via a maven project.
Example Project
Project Structure:

Let us see the important files one by one
pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 < modelVersion >4.0.0</ modelVersion > < groupId >com.gfg</ groupId > < artifactId >springinternationlization</ artifactId > < name >springinternationlization</ name > < packaging >war</ packaging > < version >1.0.0-BUILD-SNAPSHOT</ version > < properties > < java-version >1.6</ java-version > < org.springframework-version >4.0.2.RELEASE</ org.springframework-version > < org.aspectj-version >1.7.4</ org.aspectj-version > < org.slf4j-version >1.7.5</ org.slf4j-version > </ properties > < dependencies > <!-- Spring --> < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-context</ artifactId > < version >${org.springframework-version}</ version > < exclusions > <!-- Exclude Commons Logging in favor of SLF4j --> < exclusion > < groupId >commons-logging</ groupId > < artifactId >commons-logging</ artifactId > </ exclusion > </ exclusions > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-webmvc</ artifactId > < version >${org.springframework-version}</ version > </ dependency > <!-- Logging --> < dependency > < groupId >org.slf4j</ groupId > < artifactId >slf4j-api</ artifactId > < version >${org.slf4j-version}</ version > </ dependency > < dependency > < groupId >org.slf4j</ groupId > < artifactId >jcl-over-slf4j</ artifactId > < version >${org.slf4j-version}</ version > < scope >runtime</ scope > </ dependency > < dependency > < groupId >org.slf4j</ groupId > < artifactId >slf4j-log4j12</ artifactId > < version >${org.slf4j-version}</ version > < scope >runtime</ scope > </ dependency > < dependency > < groupId >log4j</ groupId > < artifactId >log4j</ artifactId > < version >1.2.15</ version > < exclusions > < exclusion > < groupId >javax.mail</ groupId > < artifactId >mail</ artifactId > </ exclusion > < exclusion > < groupId >javax.jms</ groupId > < artifactId >jms</ artifactId > </ exclusion > < exclusion > < groupId >com.sun.jdmk</ groupId > < artifactId >jmxtools</ artifactId > </ exclusion > < exclusion > < groupId >com.sun.jmx</ groupId > < artifactId >jmxri</ artifactId > </ exclusion > </ exclusions > < scope >runtime</ scope > </ dependency > <!-- @Inject --> < dependency > < groupId >javax.inject</ groupId > < artifactId >javax.inject</ artifactId > < version >1</ version > </ dependency > <!-- Servlet --> < dependency > < groupId >javax.servlet</ groupId > < artifactId >servlet-api</ artifactId > < version >2.5</ version > < scope >provided</ scope > </ dependency > < dependency > < groupId >javax.servlet.jsp</ groupId > < artifactId >jsp-api</ artifactId > < version >2.1</ version > < scope >provided</ scope > </ dependency > < dependency > < groupId >javax.servlet</ groupId > < artifactId >jstl</ artifactId > < version >1.2</ version > </ dependency > <!-- Test --> < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < version >4.7</ version > < scope >test</ scope > </ dependency > </ dependencies > < build > < plugins > < plugin > < artifactId >maven-eclipse-plugin</ artifactId > < version >2.9</ version > < configuration > < additionalProjectnatures > < projectnature >org.springframework.ide.eclipse.core.springnature</ projectnature > </ additionalProjectnatures > < additionalBuildcommands > < buildcommand >org.springframework.ide.eclipse.core.springbuilder</ buildcommand > </ additionalBuildcommands > < downloadSources >true</ downloadSources > < downloadJavadocs >true</ downloadJavadocs > </ configuration > </ plugin > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-compiler-plugin</ artifactId > < version >2.5.1</ version > < configuration > < source >1.8</ source > < target >1.8</ target > < compilerArgument >-Xlint:all</ compilerArgument > < showWarnings >true</ showWarnings > < showDeprecation >true</ showDeprecation > </ configuration > </ plugin > < plugin > < groupId >org.codehaus.mojo</ groupId > < artifactId >exec-maven-plugin</ artifactId > < version >1.2.1</ version > < configuration > < mainClass >org.test.int1.Main</ mainClass > </ configuration > </ plugin > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-war-plugin</ artifactId > < version >3.3.1</ version > </ plugin > </ plugins > </ build > </ project > |
Spring Resource Bundle can be represented by means of
messages_en.properties (This is the default setting)
label.title=Initial Page label.emailId=Email label.password=Password label.submit=Welcome
messages_fr.properties (For french locale)
label.title=Page initiale label.emailId=e-mail label.password=Mot de passe label.submit=Bienvenu
messages_de.properties (For german locale)
label.title=Startseite label.emailId=E-Mail-ID label.password=Passwort label.submit=Herzlich willkommen
Let us see a simple controller class that just prints the locale that we are using. By default, the locale is set to en
HomePageController.java
Java
import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class HomePageController { private static final Logger logger = LoggerFactory.getLogger(HomePageController. class ); @RequestMapping (value = "/" , method = RequestMethod.GET) // When no locale is passed in the parameter, we will // get en as answer public String home(Locale locale, Model model) { logger.info( "You have come with the locale as {}." , locale); return "homepage" ; } } |
homepage.jsp
HTML
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%> <%@ page session="false"%> < html > < head > < title >< spring:message code = "label.title" /></ title > < style > table { border-collapse: collapse; } th, td { border: 1px solid #ccc; padding: 10px; text-align: left; } tr:nth-child(even) { background-color: #eee; } tr:nth-child(odd) { background-color: #fff; } </ style > </ head > < body > < form method = "post" action = "login" > < table border = "1" > < tr > < td >< label > < strong >< spring:message code = "label.emailId" /></ strong > </ label ></ td > < td >< input name = "emailId" /></ td > </ tr > < tr > < td >< label > < strong >< spring:message code = "label.password" /></ strong > </ label ></ td > < td >< input name = "password" /></ td > </ tr > < tr > < spring:message code = "label.submit" var = "labelSubmit" ></ spring:message > < td colspan = "2" >< input type = "submit" value = "${labelSubmit}" /></ td > </ tr > </ table > </ form > </ body > </ html > |
Let us see the main configuration file which indicates what are the default locale file to be picked
servlet-context.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://www.springframework.org/schema/mvc <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --> <!-- Enables the Spring MVC @Controller programming model --> < annotation-driven /> <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --> < resources mapping = "/resources/**" location = "/resources/" /> <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --> < beans:bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > < beans:property name = "prefix" value = "/WEB-INF/views/" /> < beans:property name = "suffix" value = ".jsp" /> </ beans:bean > < beans:bean id = "messageSource" class = "org.springframework.context.support.ReloadableResourceBundleMessageSource" > < beans:property name = "basename" value = "classpath:messages" /> < beans:property name = "defaultEncoding" value = "UTF-8" /> </ beans:bean > < beans:bean id = "localeResolver" class = "org.springframework.web.servlet.i18n.CookieLocaleResolver" > <!-- defaultLocale is set to en and hence when no param is passed, english will be the default locale --> < beans:property name = "defaultLocale" value = "en" /> < beans:property name = "cookieName" value = "myAppLocaleCookie" ></ beans:property > < beans:property name = "cookieMaxAge" value = "3600" ></ beans:property > </ beans:bean > < interceptors > < beans:bean class = "org.springframework.web.servlet.i18n.LocaleChangeInterceptor" > < beans:property name = "paramName" value = "locale" /> </ beans:bean > </ interceptors > < context:component-scan base-package = "com.gfg.spring" /> </ beans:beans > |
Key Important Points:
- annotation-driven tag: It enables the Controller programming model,. From this only controllers are identified to handle client requests.
- context:component-scan: The place for the Spring to be looked for the annotated components and register them automatically as Spring bean.
- messageSource bean: It is mainly configured to enable i18n, i.e. supportivity for all languages for our application. In this, basename property is used to provide about the location of resource bundles. classpath:messages means that resource bundles are located in the classpath. messages_{locale}.properties is the identification file for the locale settings. Here for the locale, it can be ‘en’, (english)/’fr’ (french) /’de’ (german), etc., defaultEncoding property : Here usually we need to specify as UTF-8 as this is used to define the encoding used for the messages.
- localeResolver: This is a very important and initiating point for setting a default locale , cookie name and age of the cookies
- org.springframework.web.servlet.i18n.LocaleChangeInterceptor: With this, we can able to change the new locale that the user wants to have. Without this, spring cannot configure
web.xml (Deployment descriptor of MVC application)
This will indicate which file to be looked for context configuration and it is configurable. For our example, below is the web.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://Java.sun.com/xml/ns/javaee <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> < context-param > < param-name >contextConfigLocation</ param-name > < param-value >/WEB-INF/spring/root-context.xml</ param-value > </ context-param > <!-- Creates the Spring Container shared by all Servlets and Filters --> < listener > < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class > </ listener > <!-- Processes application requests --> < servlet > < servlet-name >appServlet</ servlet-name > < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > < init-param > < param-name >contextConfigLocation</ param-name > < param-value >/WEB-INF/spring/appServlet/servlet-context.xml</ param-value > </ init-param > < load-on-startup >1</ load-on-startup > </ servlet > < servlet-mapping > < servlet-name >appServlet</ servlet-name > < url-pattern >/</ url-pattern > </ servlet-mapping > </ web-app > |
Let us execute and see the output of console as well as the rendering web page

Let us execute the same page by passing locale as fr

Now it is for locale = de

Conclusion
Hence a single software in a spring application can be customizable by having different message resources each one for specific language.
Please Login to comment...