Another common task for web applications is to render text in the browser. The HTML markup language includes a number of elements that can be used to render text. JSF includes standard components that represent these HTML elements and extend their capabilities to include support for internationalization, conditional rendering, formatted text, validation messages, and more.
Many elements in HTML, such as<p>, <div>, <span>
, and<label>
for example, can be used to render text. The JSF<h:outputText>
tag renders the HtmlOutputText
component as an arbitrary text value or as a<span>
element that contains text if CSS attributes on the tag are set. The<h:outputText>
can be used to render plain text or HTML that originates from the backing bean.
The value
attribute of the tag specifies the text to be rendered. If we are rendering HTML, we should make sure to set the escape
attribute to false so that the HTML is rendered properly in the browser. The<h:outputText>
tag can also be used to render arbitrary Java objects, such as Date, Integer, Float
, and other types. When the value
attribute contains an EL expression that evaluates to a Java type other than String
, the component attempts to render the value as a string. If a converter is registered on the component, the converter is responsible for converting the object to a string.
One of the uses of the HtmlOutputText
component is to display localized messages. Let's look at a few examples of how to use this component to internationalize our JSF pages. In the process, we will have the opportunity to look at the JSF framework's internationalization support in more detail.
One of the many benefits of the JSF framework is the ability to easily internationalize our applications. As the format of date and time, numbers, and currency values can change significantly from one locale to another, JSF conveniently extends Java's internationalization (I18N) support to our user interface.
For demonstration, our JSF application will support three locales: English (our default locale), French, and Spanish. Localized messages will be stored in three message bundles named "messages_en.properties", "messages_fr.properties", and "messages_es.properties".
Since JSF 1.2, there are two ways to make message bundles available to web pages in our JSF applications.
Registering a message bundle in JSF 1.1 requires adding the following XML to the faces-config.xml
file:
<application> <message-bundle>messages</message-bundle> <locale-config> <default-locale>en</default-locale> <supported-locale>fr</supported-locale> <supported-locale>es</supported-locale> </locale-config> </application>
Notice that we specify the name of the message bundle properties file (without the locale information and without the .properties
file extension) for the<message-bundle>
element. Next, we specify the locales supported by our JSF application in the<locale-config>
element, indicating that English (en) is our default locale. To use our message bundles, we need to declare the<f:loadBundle>
tag in our JSF pages:
<f:view> <f:loadBundle var="bundle" basename="messages" /> <h:outputText value="#{bundle.welcomeMessage}" /> </f:view>
Since JSF 1.2, there is a more efficient way to use message bundles in our JSF pages. Instead of loading our message bundle on each page using the<f:loadBundle>
tag, we can simply declare our message bundle once in faces-config.xml
and use it from any page in our JSF application. The following XML must be added to faces-config.xml
to enable this feature:
<application> <resource-bundle> <base-name>messages</base-name> <var>bundle</var> </resource-bundle> </application>
The following example demonstrates how we can render our localized text in a JSF page using the<h:outputText>
tag. In this example, the text is rendered from our default message bundle for the English locale.
<f:view> <f:loadBundle basename="messages" var="bundle" /> <h:outputText value="#{bundle.welcomeMessage} (#{view.locale.displayName})" /> </f:view>
Note
Developer tip: Message bundle keys and the JSF EL
Due to the syntax of the JSF expression language, if we use the "dot" notation as in the expression #{bundle.welcomeMessage}
, then we must take care to choose valid key names for our message bundle. This means avoiding periods and spaces and using only letters and numbers for any message bundle keys we want to use in our JSF pages. Alternately, we can use the "map" notation as in the expression #{bundle['another.message.key']}
to specify any arbitrary message bundle key containing any acceptable key characters supported by the Java properties file format.
Our message bundle contains the following key/value pair:
welcomeMessage=Welcome!
In the next example, we hardcoded the locale of our view by setting the locale
attribute of the<f:view>
tag to the French locale in a separate view, and the JSF framework loaded the messages from our French message bundle.
<f:view locale="fr"> <f:loadBundle basename="messages" var="bundle" /> <h:outputText value="#{bundle.welcomeMessage} (#{view.locale.displayName})" /> </f:view>
We created a third view for the Spanish locale. As we also configured a message bundle for this locale, JSF was able to render localized messages for this locale.
<f:view locale="es"> <f:loadBundle basename="messages" var="bundle" /> <h:outputText value="#{bundle.welcomeMessage} (#{view.locale.displayName})" /> </f:view>
Creating separate pages for each locale is one approach to implement internationalization in JSF. Another approach that we can use is to create a single view without specifying the locale and let the JSF framework determine the appropriate message bundle to use, based on the locale sent by the user's browser. As users can configure their browsers to specify their preferred languages, our JSF application can rely on this information to identify the user's locale.
Detecting the browser's locale in a single view can be a more efficient approach, as we no longer have to maintain a different copy of the view for each supported locale.
If the user's locale is not supported, they will see messages for our application's default locale.
Another use of the<h:outputText>
tag is to render text conditionally. For example, we may want to display a message to the user only if he/she is currently logged into our web application. For this purpose, we can use the rendered
attribute of the<h:outputText>
tag. This attribute accepts a Boolean value, and we can use an EL expression to determine if the component should be visible or not.
Web applications often have to display dates, currencies, numbers, and other types of information to the user in a variety of ways. For example, you may want to display the date January 1, 2009 in the short format "01/01/09", in the medium format "Jan 1, 2009", or in the long format (including time information) "Thursday, January 1, 2006 5:30:15 PM".
Conveniently, the JSF Core tag<f:convertDateTime>
can be nested inside an<h:outputText>
tag to control date/time formatting. The following example demonstrates date/time formatting using the<f:convertDateTime>
tag. In this case, we display the date using the "full" date/time style.
<h:outputText value="You were born on " rendered="#{backingBean.date ne null}" /> <h:outputText value="#{backingBean.date}"> <f:convertDateTime type="date" dateStyle="full" /> </h:outputText>
The<h:outputText>
tag is also locale aware, so it renders the date according to the formatting conventions of the current locale.
The<h:outputText>
tag is a very flexible JSF component that supports a wide range of text rendering situations.
Sometimes we want to render formatted text that contains parameters to be specified later. JSF includes the<h:outputFormat>
tag for this purpose. It is able to render messages that contain special placeholders that can be filled in at runtime. Let's look at how to render parameterized messages using the HtmlOutputFormat
component.
In this example, we render a parameterized string from our message bundle and replace the parameters with values obtained from the query string, the current view, and our backing bean. The process of replacing parameters with values in a parameterized string is called interpolation. This example also demonstrates the flexibility of the JSF expression language. We are literally able to plug in values from just about any source of information available to our web page.
<h:outputFormat value="#{bundle.welcomeMessage2}"> <f:param value="#{param.username}" /> <f:param value="#{view.locale}" /> <f:param value="#{backingBean.today}" /> </h:outputFormat>
The parameterized message is defined in our message bundle. We will have a similar definition for each locale.
welcomeMessage2=Welcome {0}, your locale is {1}. The current date is {2}.
First, we configure our browser to use English as our preferred language.
Next, we set French as our preferred language.
On our third try, we set Spanish as our preferred language.
When marking up our JSF pages, we should take care to provide proper labels for components to give them a clear purpose in our user interface. This way, users will have an easier time learning how to use our JSF applications.
When rendering labels, it is more appropriate to use the HTML<label>
element than to use a<span>
element. For this purpose, we can use the JSF<h:outputLabel>
tag. This tag renders an HtmlOutputLabel
component as an HTML<label>
element and has a special for
attribute that identifies the input component represented by the label.
A nice feature about this component is that it improves the usability of forms in web browsers by providing additional information about the relationship between text labels and form controls. One enhancement in particular is that users can now click on a radio button or checkbox label to change the selection state of the control. This makes a web page more intuitive to the user and also provides accessibility information for screen readers and assistive devices.
To set the text displayed by an<h:outputLabel>
tag, you can specify a string literal or a JSF EL value expression for the value
attribute of the tag. You can also nest an<h:outputText>
tag inside an<h:outputLabel>
tag, in which case the text will be provided by the child component. The<h:outputLabel>
tag has the same internationalization support as the<h:outputText>
tag.
This example shows how to use the<h:outputLabel>
tag in conjunction with another JSF tag. The important thing to notice is the use of the for
attribute. It expects the ID of another component on the page and informs the browser that the label is intended for that particular component.
<h:outputLabel value="Remember Me" for="remember" /> <h:selectBooleanCheckbox id="remember" value="#{backingBean.rememberMe}" onclick="submit()" />
For our final example of text rendering JSF components, we can examine the<h:outputFormat>
tag. This tag renders an HtmlOutputFormat
component as formatted text within the JSF page. Formatted text can include a localized message from the application's message bundle for the current locale, or it can include a string pattern that is evaluated at request time. Interestingly, this string pattern can have placeholders that are substituted by any nested<f:param>
tags.
So for example, if we wanted to render the message "Welcome, username", we could use an<h:outputFormat>
tag that contains a parameter for the user's name. The value substituted for this parameter would be defined by a child<f:param>
tag, so the actual name of the user could come from a database, an LDAP directory, or another source. The important point is that this tag simplifies a very common task for web applications, namely rendering localized, parameterized text messages conveniently and easily.
The<h:message>
tag renders an HtmlMessage
component and is useful for displaying validation messages in a JSF page. It is important to include this tag on our JSF pages so that users will be informed when a JSF validation message occurs. Typically, the tag is placed immediately after a JSF component tag to display the validation messages for the associated component.
In this example, we render an HtmlInputText
component and specify through the<h:inputText>
tag's required
attribute that the user is expected to enter a value into to the first name text field. If the user submits the form without entering a value, an error message will be rendered by the<h:message>
tag beside the component. The for
attribute is required and is used to associate the message with a particular UI component on the page. It expects the ID of the component that the message is for.
The<h:messages>
tag is similar to the<h:message>
tag except that it renders an HtmlMessages
component that displays all validation messages for any components in the view in an unordered list. This is useful when our user interface requirements call for presenting all error messages in one place, for example, above any form fields on the page. The globalOnly
attribute is false by default, but if we set it to true, then the component only displays messages generated by the application that are not associated with a particular component.
<h:messages errorClass="error" globalOnly="false" />