Open In App

Spring – Resource Bundle Message Source (i18n)

Last Updated : 22 Jun, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

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:

Project Structure

 

Let us see the important files one by one

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         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.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"?>
             xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd
                        http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context.xsd">
 
    <!-- 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"?>
<web-app version="2.5" 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_2_5.xsd">
 
    <!-- 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.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads