Skip to main content

3. Using Languages with resource bundles in JSF

Main steps

1. Create a folder in the src/main/java. In my case "bundles". But as I am using Maven, it is preferred to use src/main/resources.

2. Create a file with ".properties" extension in the created folder. In my case "labels.properties"


1
2
3
4
login = LOGIN DEMO
message = message:
password = password:
user = user:

3. Create additional files referring to the locales. For instance "labels_es.properties" for Spanish locales.

1
2
3
4
login = DEMO DE ACCESO AL SISTEMA
message = mensaje:
password = contraseña:
user = usuario:

4. There are basically 3 ways to inform a xhtml file how to access the resource bundles. The first one is using the file faces-config.xml, the second one is using <f:loadbundle ..> in the xml file and the third one is accessing the resource bundle by means of a request scoped bean referenced in the xhtml file.

4.1 (Using faces-context.xml)  (See Veeramani Kalyanasundaram)

4.1.a Modify the faces-config.xml file (in the webaypp/WEB-INF folder)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<faces-config 
              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"
              version="2.2">  
              
  <application>
            
    <resource-bundle>
      <base-name>bundles.labels</base-name>
      <var>label</var>
    </resource-bundle>
   
  </application>              

</faces-config>

Notes:
  a. To access the resource bundles, we need to reference the file bundle/labels.properties as bundles.labels in the <base-name> xml tag

  b. We assign a variable named label that is a map to the "localized" properties (marked in the <var> tag), and can be referenced within any xhtml file as if it were a bean!.

4.1.b The login xhtml file (whose name is test03-loginbean-lang.xhtml) is:

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:p="http://primefaces.org/ui">  
    <h:head>  
    </h:head>  
      
    <h:body>  
       <h:form>  
           <p:panel header="#{label.login}">
               #{label.user}   
               <p:keyboard value="#{loginBean.user}"/>
               <br />  
               #{label.password}
               <p:keyboard value="#{loginBean.password}"/>
               <br />
               #{label.message}
               <h:outputText value="#{loginBean.myError}"/>
             </p:panel>
             <p:commandButton value="Submit"/>
             <p:commandButton value="Login" action="#{loginBean.login}"/>
       </h:form>
    </h:body>  
</html>

The labels have been replaced with references to the label variable displayed in red colour.

4.2 (using <f:loadbundle..> in the xhtml file. (See Veeramani Kalyanasundaram)

4.2.1 Let's copy the file test03-loginbean-lang.xhtml into test04-loginbean-lang.xhtml, and in the h:head part add this code <f:loadBundle basename="bundles.labels" var="label" /> where basename refers the path to our bundle/labels.properties and var refers to a variable to hold the i18n properties

The test04-loginbean-lang.xhtml is


 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
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:p="http://primefaces.org/ui">  
    <h:head>
      <f:loadBundle basename="bundles.labels" var="label" />
    </h:head>  
      
    <h:body>  
       <h:form>  
           <p:panel header="#{label.login}">
               #{label.user}   
               <p:keyboard value="#{loginBean.user}"/>
               <br />  
               #{label.password}
               <p:keyboard value="#{loginBean.password}"/>
               <br />
               #{label.message}
               <h:outputText value="#{loginBean.myError}"/>
             </p:panel>
             <p:commandButton value="Submit"/>c
             <p:commandButton value="Login" action="#{loginBean.login}"/>
       </h:form>
    </h:body>  
</html>

See <f:loadbundle..> in line number 6

4.3 accessing through a bean. (See Balusc in Stackoverflow)

BalusC suggested: "Put it in request map yourself in (post)constructor of a request scoped bean which is referenced in the view."

This means that if you pass the resource bundle to the "ExternalContext map",  the bundle will be accessible by the xhtml file.

4.3.1 Let's copy the LoginBean.java to LoginBean and copy the code proposed by BalusC in a new method called init() (annotated by @PostConstruct)

LoginBeanBundle.java:


 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package org.ximodante.jsf.login;

import java.io.Serializable;
import java.util.ResourceBundle;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Named;

import lombok.Getter;
import lombok.Setter;


@Named
@RequestScoped
public class LoginBeanBundle implements Serializable{
 private static final long serialVersionUID = 1L;
 @Getter @Setter private String user;
 @Getter @Setter private String password;
 @Getter private String myError="";
  
  
 public String login () {
  if (user.equalsIgnoreCase("ximo") && password.equals("password")) {
   return "test02-application-page";
  } else {
   myError="Bad User/password";
   return "test02-login-page";
  }
  }
 
 @PostConstruct
 private void init() {
  FacesContext facesContext=FacesContext.getCurrentInstance();
  ResourceBundle bundle = ResourceBundle.getBundle("bundles.labels", facesContext.getViewRoot().getLocale());
  ExternalContext externalContext=facesContext.getExternalContext();
  externalContext.getRequestMap().put("label", bundle);
 }
 

} 

Notes:
  a. To access the resource bundles, we need to reference the file bundle/labels.properties as bundles.labels in the ResourceBundle.getBundle method

  b. We save the resource bundle into the RequestMap assigning a property named label that is a map to the "localized" properties. Now it can be accessed by the xhtml file.

To simplify let's copy the test03-loginbean-lang.xhtml into test05-loginbeanbundle-lang.xhtm and replace LoginBean with LoginBeanBundle.

The test05-loginbeanbundle-lang.xhtm is


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:p="http://primefaces.org/ui">  
    <h:head>  
    </h:head>  
      
    <h:body>  
       <h:form>  
           <p:panel header="#{label.login}">
               #{label.user}   
               <p:keyboard value="#{loginBeanBundle.user}"/>
               <br />  
               #{label.password}
               <p:keyboard value="#{lloginBeanBundle.password}"/>
               <br />
               #{label.message}
               <h:outputText value="#{loginBeanBundle.myError}"/>
             </p:panel>
             <p:commandButton value="Submit"/>
             <p:commandButton value="Login" action="#{loginBeanBundle.login}"/>
       </h:form>
    </h:body>  
</html>


loginBeanBundle is the new bean.

Happy coding!







Comments

Popular posts from this blog

10. JSF How to access my resources files?

Sometimes it is really difficult to access any resources form different Java applications. So let's see some scenarios: 1. Executable jar application in a NO WEB environment. Take into account that this is not a JSF application !!! It is desired to have a property file outside the "jar file" so that we can change properties when needed. For instance, we will place the properties file in the same folder that the "jar file" lies. To access the folder where the jar is, the trick is to access the folder where the compiled classed are placed and scale 3 folders . (Oh! rather strange, if anybody knows a better idea.., he will be welcome). Here is a simple code. The name of the class containing the code is ThisClass, and we have created a Property class that feeds with a file in the same folder that the" jar file" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 /** * Gets the folder where resides the executable...

9. JSF: Solving common problems

1. Target Unreachable, identifier [bean] resolved to null When you reference a bean in a xhtml file with "#{bean.method}" and get this error, you should verify that: The bean implements Serializable . The references (javax.servlet-api.4.0.0, javax.faces.2.3.3,  javax.el.api.3.0.1, org.primefaces.6.1) have been selected in your pom.xml You have created the files bean.xml and faces-config.xml in the webapp/WEB-INF folder You have used the correct annotations from CDI  (javax.inject.Named and javax.enterprise.context.SessionScoped, ...) and not ManagedBean or jsf2.2 scopes. 2. Bean declaring a passivating scope must be passivation capable This error causes server not starting and fills up the console with long chained exceptions. It is very annoying. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 SEVERE: A child container failed during start java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to star...

2. Create a Maven JSF project and a simple login page

Updated on Oct-25-2107 0. Introduction Remember to install previously: Java JDK 8 Eclipse Oxygen Lombok  Apache Tomcat 9 1. Create a Maven Project In the top menu select : File - New - Maven Project Press Next Now fill the next form as follows It is important to select: Group id: org.ximodante.jsf  (or another packet you like) Packaging: war Artifact Id and Name: JSFv02 or any name for the project Press Finish 2. The pom.xml file Eclipse complains about the simple generated file. It seems that a web.xml is required if the packaging is selected to war. The simple generated file is  1 2 3 4 5 6 7 8 9 <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/xsd/maven-4.0.0.xsd" > <modelVersion> 4.0.0 </modelVersion> <groupId> org.ximodante...