blob: 696ab69291253c06c5c4713af791547580a62ac7 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="author" content="troy.giunipero@sun.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="description" content="This tutorial unit describes how to create multilingual pages for web applications">
<meta name="keywords" content="NetBeans, IDE, integrated development environment,
Java, Java EE, open source, web technology, e-commerce, resource bundle, locale, internationalization,
localization">
<link rel="stylesheet" type="text/css" href="../../../../netbeans.css">
<link rel="stylesheet" type="text/css" href="../../../../print.css" media="print">
<link rel="stylesheet" type="text/css" href="../../../../lytebox.css" media="screen">
<script type="text/javascript" src="../../../../images_www/js/lytebox-compressed.js"></script>
<title>The NetBeans E-commerce Tutorial - Adding Language Support</title>
</head>
<body>
<!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -->
<h1>The NetBeans E-commerce Tutorial - Adding Language Support</h1>
<div style="margin-left:-3px">
<div class="feedback-box margin-around float-left" style="margin-right:15px">
<h4>Tutorial Contents</h4>
<ol>
<li><a href="intro.html">Introduction</a></li>
<li><a href="design.html">Designing the Application</a></li>
<li><a href="setup-dev-environ.html">Setting up the Development Environment</a></li>
<li><a href="data-model.html">Designing the Data Model</a></li>
<li><a href="page-views-controller.html">Preparing the Page Views and Controller Servlet</a></li>
<li><a href="connect-db.html">Connecting the Application to the Database</a></li>
<li><a href="entity-session.html">Adding Entity Classes and Session Beans</a></li>
<li><a href="manage-sessions.html">Managing Sessions</a></li>
<li><a href="transaction.html">Integrating Transactional Business Logic</a></li>
<li><strong>Adding Language Support</strong>
<ul style="margin: 5px 0 0 -2em">
<li><a href="#resourceBundles">Understanding Resource Bundles</a></li>
<li><a href="#multilingual">Making Pages Multilingual</a></li>
<li><a href="#toggle">Implementing a Language Toggle</a></li>
<li><a href="#seeAlso">See Also</a></li>
</ul></li>
<li><a href="security.html">Securing the Application</a></li>
<li><a href="test-profile.html">Testing and Profiling</a></li>
<li><a href="conclusion.html">Conclusion</a></li>
</ol>
</div>
</div>
<p><img src="../../../../images_www/articles/68/netbeans-stamp-68-69.png" class="stamp"
alt="Content on this page applies to NetBeans IDE, versions 6.8 and 6.9"
title="Content on this page applies to NetBeans IDE, versions 6.8 and 6.9"></p>
<p>The goal of this tutorial unit is to demonstrate how to enable language support
for a web application. &quot;Language support&quot; here refers to the ability
to display page views according to the customer-specified languages. Within the
context of the <code>AffableBean</code> application, we have agreed to provide
support for both English and Czech, as per the previously outlined
<a href="design.html#requirements">customer requirements</a>.</p>
<p>In order to accomplish this, you rely on Java's support for internationalization.
You create a <em>resource bundle</em> for each language and let the Java runtime
environment determine the appropriate language for incoming client requests. You
also implement a 'language toggle' to enable users to switch the languages manually.</p>
<p>The NetBeans IDE provides special support for localizing application content. This
includes a Customizer dialog that enables you to add new locales to an existing
resource bundle base name, as well as a special Properties editor that lets you
view and edit key-value pairs for all locales in a table layout. These are both
utilized in this tutorial.</p>
<p>You can view a live demo of the application that you build in this tutorial:
<a href="http://services.netbeans.org/AffableBean/" target="_blank">NetBeans
E-commerce Tutorial Demo Application</a>.</p>
<br style="clear:left;">
<br>
<table>
<tbody>
<tr>
<th class="tblheader" scope="col">Software or Resource</th>
<th class="tblheader" scope="col">Version Required</th>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html" target="_blank">NetBeans IDE</a></td>
<td class="tbltd1">Java bundle, 6.8 or 6.9</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" target="_blank">Java Development Kit (JDK)</a></td>
<td class="tbltd1">version 6</td>
</tr>
<tr>
<td class="tbltd1"><a href="#glassFish">GlassFish server</a></td>
<td class="tbltd1">v3 or Open Source Edition 3.0.1</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://dev.mysql.com/downloads/mysql/" target="_blank">MySQL database server</a></td>
<td class="tbltd1">version 5.1</td>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot8.zip">AffableBean
project</a></td>
<td class="tbltd1">snapshot 8</td>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot9.zip">AffableBean
project</a></td>
<td class="tbltd1">snapshot 9</td>
</tr>
</tbody>
</table>
<p><strong class="notes">Notes:</strong></p>
<ul>
<li>The NetBeans IDE requires the Java Development Kit (JDK) to run properly.
If you do not have any of the resources listed above, the JDK should be
the first item that you download and install.</li>
<li>The NetBeans IDE Java Bundle includes Java Web and EE technologies, which are
required for the application you build in this tutorial.</li>
<li id="glassFish">The NetBeans IDE Java Bundle also includes the GlassFish server,
which you require for this tutorial. You could
<a href="http://glassfish.dev.java.net/public/downloadsindex.html" target="_blank">download
the GlassFish server independently</a>, but the version provided with the
NetBeans download has the added benefit of being automatically registered with
the IDE.</li>
<li>You can follow this tutorial unit without having completed previous units. To
do so, see the <a href="setup.html">setup instructions</a>, which describe how
to prepare the database and establish connectivity between the IDE, GlassFish,
and MySQL.</li>
</ul>
<br>
<h2 id="resourceBundles">Understanding Resource Bundles</h2>
<p>In Java, a resource bundle is a representation of the
<a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/util/ResourceBundle.html" target="_blank"><code>java.util.ResourceBundle</code></a>
class. As stated in the Javadoc,</p>
<blockquote style="margin-top: 0">
<em>Resource bundles contain locale-specific objects. When your program needs
a locale-specific resource, a String for example, your program can load it
from the resource bundle that is appropriate for the current user's locale.
In this way, you can write program code that is largely independent of the
user's locale isolating most, if not all, of the locale-specific information
in resource bundles.
<br><br>
This allows you to write programs that can:</em>
<ul style="margin: 5px 0 0 -1em">
<li><em>be easily localized, or translated, into different languages</em></li>
<li><em>handle multiple locales at once</em></li>
<li><em>be easily modified later to support even more locales</em></li>
</ul>
</blockquote>
<p>From the Javadoc, you can also note that the <code>ResourceBundle</code> is parent
to both <a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/util/ListResourceBundle.html" target="_blank"><code>ListResourceBundle</code></a>
and <a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/util/PropertyResourceBundle.html" target="_blank"><code>PropertyResourceBundle</code></a>.
In this tutorial we utilize the <code>PropertyResourceBundle</code>, which manages
resources as text files that use the <code>.properties</code> extension and contain
locale-specific information in the form of key-value pairs. With new each translation,
a new version of the resource bundle is created by appending the locale identifier
to the base name using an underscore ('<code>_</code>'). For example, snippets from
two of the resource bundles you create in this tutorial look as follows:</p>
<p><strong>messages_en.properties</strong></p>
<pre class="examplecode" style="margin-top:0">
meats=meats
bakery=bakery</pre>
<p><strong>messages_cs.properties</strong></p>
<pre class="examplecode" style="margin-top:0">
meats=maso
bakery=pečivo</pre>
<p>In the above example, '<code>messages</code>' represents the base name, and the locale
identifier is the two-letter code which is appended using an underscore. (i.e., '<code>en</code>'
for English, '<code>cs</code>' for Czech). The two-letter codes are derived from the
international <a href="http://en.wikipedia.org/wiki/ISO_639" target="_blank">ISO 639</a>
standard, which lists codes that represent the names of languages. The ISO 639 standard
is adopted by the <a href="http://www.w3.org/International/" target="_blank">W3C
Internationalization Activity</a> and is used by all major browsers (these are the codes
understood in the <code>Accept-Language</code> HTTP header). It is also internalized in the
<a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/util/Locale.html" target="_blank"><code>java.util.Locale</code></a>
class.</p>
<br>
<h2 id="multilingual">Making Pages Multilingual</h2>
<p>Returning to the <code>AffableBean</code> application, after continued discussions with
the customer you've agreed on the following implementation details:</p>
<ul style="margin: 0 0 0 -.7em" id="impDeets">
<li>The website initially displays based on the preferred language of the user's
browser.</li>
<li>If the browser's preferred language is neither English nor Czech, the site
displays text in English.</li>
<li>The user has the option of changing the language by means of a 'language toggle'
in the page header.</li>
<li>When using the language toggle to change the language, the user remains in the
same page view.</li>
<li>The language toggle should not appear for the confirmation page, as a user will
already have selected his or her language prior to checkout.</li>
</ul>
<p>In order to implement the above points, divide the task into two parts. Start by
creating basic bilingual support for page views. Once bilingual support is in place,
implement the language toggle that enables users to manually switch languages.</p>
<p>There are three basic steps that you need to follow to incorporate multilingual support
into your web pages.</p>
<ol style="margin: 0">
<li>Create a resource bundle for each language you plan to support.</li>
<li>Register the resource bundle with the application by setting a context parameter
in the <code>web.xml</code> deployment descriptor.</li>
<li>In page views, replace 'hard-coded' text with <code>&lt;fmt:message&gt;</code> tags
that reference keys in the resource bundles.</li>
</ol>
<p>The following exercise demonstrates how to integrate English and Czech language support
into the <code>AffableBean</code> welcome page by applying the above three steps, and
finishes by showing how to test for browser language support using Firefox.</p>
<ol>
<li><a href="#createResource">Create Resource Bundles</a></li>
<li><a href="#register">Register the Resource Bundle with the Application</a></li>
<li><a href="#replace">Replace 'Hard-Coded' Text with <code>&lt;fmt:message&gt;</code> Tags</a></li>
<li><a href="#test">Test Supported Languages</a></li>
</ol>
<div class="indent">
<h3 id="createResource">Create Resource Bundles</h3>
<ol>
<li>Open the <code>AffableBean</code> project <a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot8.zip">snapshot
8</a> in the IDE. Click the Open Project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/open-project-btn.png"
alt="Open Project button"> ) button and use the wizard to navigate to the location
on your computer where you downloaded the project.</li>
<li>Click the Run Project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ) button to run the project and ensure that it is properly
configured with your database and application server.
<br><br>
<p class="alert">If you receive an error when running the project, revisit the
<a href="setup.html">setup instructions</a>, which describe how to prepare the
database and establish connectivity between the IDE, GlassFish, and MySQL.</p></li>
<li>Begin by creating a default resource bundle to contain text used in page views. Click
the New File (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/new-file-btn.png"
alt="New File button"> ) button in the IDE's toolbar. (Alternatively, press Ctrl-N;
&#8984;-N on Mac.)</li>
<li>Under Categories select Other, then under File Types select Properties File.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/new-file-wzd.png"
class="margin-around b-all" alt="New File wizard"
title="Create a new resource bundle using the File wizard">
<br>
Note that the wizard provides a description for the selected file type:
<blockquote>
<em>Creates a resource bundle (<code>.properties</code>) file suitable for internationalizing
applications by separating out all human-visible text strings from your code. Resource
bundle files can also be used to collect other types of strings, such as properties for
Ant scripts. The created resource bundle contains only one locale, but you can add additional
locales from the created file's contextual menu. The bundle can be edited in a text file
(property-file format) for a specific locale or in a table that displays information for
all locales.</em>
</blockquote></li>
<li>Click Next. In the Name and Location step, name the file <code>messages</code> and type
in <code>src/java/resources</code> in the Folder field. This will instruct the wizard
to place the resource bundle in a new package named <code>resources</code>.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/new-properties-file-wzd.png"
class="margin-around b-all" alt="New Properties File wizard"
title="Specify the name and location of the resource bundle"></li>
<li>Click Finish. The <code>messages.properties</code> resource bundle is generated and opens
in the editor.
<br><br>
Note that the new <code>messages.properties</code> file name does not have a language
code appended to it, as was previously described. This is because this file will be used
as the <em>default</em> resource bundle. The default resource bundle is applied when the
Java runtime environment does not find a direct match for the requested locale.</li>
<li>Open the project's <code>index.jsp</code> file in the editor and note that the following
text is currently used:
<ul style="margin: 5px 0 0 -1em">
<li><strong>Greeting:</strong> <code>Welcome to the online home of the Affable Bean Green Grocer.</code></li>
<li><strong>Introductory Message:</strong> <code>Enjoy browsing and learning more about our
unique home delivery service bringing you fresh organic produce, dairy, meats, breads
and other delicious and healthy items to your doorstep.</code></li>
</ul>
Also, note that we'll need language-specific names for the four categories that display
when <code>index.jsp</code> renders in the browser. Since these names are currently taken
from the database, we can use them as keys in the resource bundle.
<br><br>
Recall that one of the <a href="#impDeets">implementation details</a> outlined above states
that &quot<em>if the browser's preferred language is neither English nor Czech, the site
displays text in English.</em>&quot; Therefore, the values that we apply to the
<code>messages.properties</code> file will be in English.</li>
<li>In the <code>messages.properties</code> file, begin adding key-value pairs for the text used
in the welcome page. Add the following content.
<pre class="examplecode">
# welcome page
greeting=Welcome to the online home of the Affable Bean Green Grocer.
introText=Our unique home delivery service brings you fresh organic produce, dairy, meats, breads and other delicious and healthy items direct to your doorstep.
# categories
dairy=dairy
meats=meats
bakery=bakery
fruit\ &\ veg=fruit & veg</pre>
Comments are added using a number sign ('<code>#</code>'). Also, because the <code>fruit & veg</code>
category name contains spaces, it is necessary to escape the space characters using a backslash
('<code>\</code>') in order to apply the name as a resource bundle key.
<br><br>
We are now finished with the default resource bundle for the application's welcome page.
Let's continue by creating resource bundles for the customer-specified languages.</li>
<li>In the Projects window, expand the Source Packages node, then right-click the <code>resources</code>
&gt; <code>messages.properties</code> file node and choose Customize. The Customizer dialog
opens.</li>
<li>In the Customizer dialog, click the Add Locale button. In the New Locale dialog that
displays, enter '<code>en</code>' in the Language Code combo box, then click OK.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/new-locale-dialog.png"
class="margin-around b-all" alt="New Locale dialog"
title="The New Locale dialog enables you to add a new locale to an existing resource bundle base name">
<br>
<p class="tips">A <em>locale</em> can be defined by both a language and a geographic region.
The optional country code which can be used to specify the region can be applied to define
formatting for dates, time, numbers, and currency. For more information, see the technical
article, <a href="http://java.sun.com/developer/technicalArticles/J2SE/locale/" target="_blank">Understanding
Locale in the Java Platform</a>.</p></li>
<li>Click the Add Locale button again, then enter '<code>cs</code>' in the Language Code combo
box and click OK. The Customizer dialog displays as follows.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/customizer-dialog.png"
class="margin-around b-all" alt="New Locale dialog"
title="The New Locale dialog enables you to add a new locale to an existing resource bundle base name"></li>
<li>Click Close. In the Projects window, note that your resource bundles look as follows. You can
expand a resource bundle to view the keys it contains.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/projects-window.png"
class="margin-around b-all" alt="Resource bundles displayed in Projects window"
title="View resource bundles and the keys they contain in the Projects window"></li>
<li>Right-click any of the three resource bundles and choose Open. The Properties editor opens,
enabling you to view and edit key-value pairs for all locales in a table layout.
<br>
<a href="../../../../images_www/articles/73/javaee/ecommerce/language/properties-editor.png"
rel="lytebox" title="Use the Properties editor to view and edit key-value pairs for all locales">
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/properties-editor.png"
class="margin-around b-all" alt="Properties editor for resource bundles" style="width:688px"
title="Click to enlarge"></a>
<p class="tips">Press Shift-Esc to maximize the window in the IDE.</p>
Note that when you add a new locale using the Customizer dialog, as you did for English and
Czech in the previous steps, the keys and values of the default resource bundle are copied
to the new locale.</li>
<li>Modify the values for the Czech resource bundle. You can do this by <em>either</em> clicking
into the table cells for each row and typing your entries directly <em>or</em> selecting the
cell you want to edit and typing into the <strong>Value</strong> field located at the bottom
of the Properties editor.
<ul style="margin: 5px 0 0 -1em">
<li><strong>greeting:</strong> <code>Vítejte v našem domácím on-line obchodě Affable Bean Green Grocer.</code></li>
<li><strong>introText:</strong> <code>Naše jedinečná dodávková služba Vám zajistí dopravu čerstvých organických produktů, mléčných výrobků, uzenin, pečiva a dalších delikates a zdravých výroků až ke dveřím.</code></li>
<li><strong>dairy:</strong> <code>mléčné výrobky</code></li>
<li><strong>meats:</strong> <code>maso</code></li>
<li><strong>bakery:</strong> <code>pečivo</code></li>
<li><strong>fruit & veg:</strong> <code>ovoce a zeleniny</code></li>
</ul>
<p class="tips">You can also add a comment to each key-value pair. Any text you enter into
the <strong>Comment</strong> field in the Properties editor is added to the resource
bundle text file above the key-value pair as a comment (i.e., following a '<code>#</code>'
sign).</p></li>
<li>Double-click the <code>messages_cs.properties</code> file node in the Projects window. Note
that the text file has been updated according to your changes in the Properties editor.
<pre class="examplecode">
# welcome page
greeting=Vítejte v našem domácím on-line obchodě Affable Bean Green Grocer.
introText=Naše jedinečná dodávková služba Vám zajistí dopravu čerstvých organických produktů, mléčných výrobků, uzenin, pečiva a dalších delikates a zdravých výroků až ke dveřím.
# categories
dairy=mléčné výrobky
meats=maso
bakery=pečivo
fruit\ &\ veg=ovoce a zeleniny</pre></li>
</ol>
<p>We now have the following resource bundles defined:</p>
<ul style="margin: 5px 0 0 -1em">
<li>default (English)</li>
<li>Czech</li>
<li>English</li>
</ul>
<p>You might assume that if the default bundle is in English, then there is no need to
create a resource bundle explicitly for English. However, consider the following scenario:
a client browser's list of preferred languages includes both Czech and English, with
English taking precedence over Czech. If the application doesn't provide a resource
bundle for English but does for Czech, pages sent to that browser will be in Czech
(since a Czech bundle was defined). This is clearly not the desired behavior for that
browser.</p>
<h3 id="register">Register the Resource Bundle with the Application</h3>
<p>The purpose of this step is to inform JSTL's format (i.e.,
<a href="http://download.oracle.com/docs/cd/E17802_01/products/products/jsp/jstl/1.1/docs/tlddocs/fmt/tld-summary.html" target="_blank"><code>fmt</code></a>)
tag library where it can locate any resource bundles existing in the application. You
accomplish this by instructing the application to create a
<a href="http://download.oracle.com/docs/cd/E17477_01/javaee/5/jstl/1.1/docs/api/javax/servlet/jsp/jstl/fmt/LocalizationContext.html" target="_blank"><code>LocalizationContext</code></a>
using the existing resource bundles. This can be done by setting a context parameter
in the application's <code>web.xml</code> deployment descriptor.</p>
<p class="tips">The topic of setting context parameters is also covered in
<a href="connect-db.html#param">Connecting the Application to the Database</a>.</p>
<ol>
<li>In the Projects window, expand the Configuration Files node, then double-click
<code>web.xml</code> to open it in the editor.</li>
<li>Under the deployment descriptor's General tab, expand the Context Parameters
category.</li>
<li>Click the Add button, then in the Add Context Parameter dialog enter the following
values.
<ul style="margin: 5px 0 0 -1em">
<li><strong>Parameter Name:</strong> <code>javax.servlet.jsp.jstl.fmt.localizationContext</code></li>
<li><strong>Parameter Value:</strong> <code>resources.messages</code></li>
</ul>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/add-context-parameter.png"
class="margin-around b-all" alt="Add Context Parameter dialog"
title="Add context parameters under the General tab for web.xml">
<p class="tips">The <code>LocalizationContext</code> class belongs to the
<code>javax.servlet.jsp.jstl.fmt</code> package. You can verify this by viewing
the <a href="http://java.sun.com/products/jsp/jstl/1.1/docs/api/index.html" target="_blank">JSTL
1.1 API Reference</a> online.</p></li>
<li>Click OK. The new context parameter is added to the table of existing context parameters
under the General tab.</li>
<li>Click the deployment descriptor's XML tab. Note that the following entry has been
added to the file:
<pre class="examplecode">
&lt;context-param&gt;
&lt;param-name&gt;javax.servlet.jsp.jstl.fmt.localizationContext&lt;/param-name&gt;
&lt;param-value&gt;resources.messages&lt;/param-value&gt;
&lt;/context-param&gt;</pre></li>
</ol>
<h3 id="replace">Replace Hard-Coded Text with <code>&lt;fmt:message&gt;</code> Tags</h3>
<p>In order to apply the localized text of resource bundles to your web pages, you reference
the keys from the key-value pairs you created. You can reference the keys using JSTL's
<code>&lt;fmt:message&gt;</code> tags.</p>
<ol>
<li>Open the project's <code>index.jsp</code> page in the editor. (If already opened,
press Ctrl-Tab to switch to the file.)</li>
<li>Delete instances of hard-coded text that display in the page's left column, and
in their place enter <code>&lt;fmt:message&gt;</code> tags using the <code>key</code>
attribute to specify the resource bundle key. The page's left column will look as
follows.
<pre class="examplecode">
&lt;div id=&quot;indexLeftColumn&quot;&gt;
&lt;div id=&quot;welcomeText&quot;&gt;
&lt;p style=&quot;font-size: larger&quot;&gt;<strong>&lt;fmt:message key='greeting'/&gt;</strong>&lt;/p&gt;
&lt;p&gt;<strong>&lt;fmt:message key='introText'/&gt;</strong>&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</pre></li>
<li>Add <code>&lt;fmt:message&gt;</code> tags for the four category names, but use
the <code>${category.name}</code> expression as the value for the <code>key</code>
attribute. Since the category name is also used as the value for the <code>&lt;img&gt;</code>
tag's <code>alt</code> attribute, follow the same procedure. The page's right
column will look as follows.
<pre class="examplecode">
&lt;div id=&quot;indexRightColumn&quot;&gt;
&lt;c:forEach var=&quot;category&quot; items=&quot;${categories}&quot;&gt;
&lt;div class=&quot;categoryBox&quot;&gt;
&lt;a href=&quot;&lt;c:url value='category?${category.id}'/&gt;&quot;&gt;
&lt;span class=&quot;categoryLabel&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;categoryLabelText&quot;&gt;<strong>&lt;fmt:message key='${category.name}'/&gt;</strong>&lt;/span&gt;
&lt;img src=&quot;${initParam.categoryImagePath}${category.name}.jpg&quot;
alt=&quot;<strong>&lt;fmt:message key='${category.name}'/&gt;</strong>&quot; class=&quot;categoryImage&quot;&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;/c:forEach&gt;
&lt;/div&gt;</pre></li>
<li>Finally, ensure that you have the <code>fmt</code> tag library declared in the
web page. Enter the following at the top of the file:
<pre class="examplecode">&lt;%@ taglib prefix=&quot;fmt&quot; uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; %&gt;</pre>
<p class="notes"><strong>Note:</strong> Here you add the tag library declaration
to the top of the <code>index.jsp</code> file. However, when you begin using
<code>&lt;fmt&gt;</code> tags elsewhere in the project, it may make more sense
to remove the tag library declaration from individual page views, and add it
to the header (<code>header.jspf</code>) file. This practice is adopted in
<a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot9.zip">snapshot
9</a> (and later snapshots).</p>
</li>
</ol>
<p>You've now completed the tasks necessary for providing bilingual support for the
application's welcome page. The following step demonstrates how to test the language
support in your browser.</p>
<h3 id="test">Test Supported Languages</h3>
<p>You could theoretically test for the following scenarios involving the application's
supported languages, as well as an unsupported language (e.g., Korean):</p>
<div class="indent">
<table>
<tbody>
<tr>
<th class="tblheader" scope="col">Use-case</th>
<th class="tblheader" scope="col">Outcome</th>
</tr>
<tr>
<td class="tbltd1">&nbsp;1. Browser has no preferred language</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;2. Browser prefers only English</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;3. Browser prefers only Czech</td>
<td class="tbltd1">Czech displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;4. Browser prefers only Korean</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;5. Browser prefers Korean and English; Korean takes precedence</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;6. Browser prefers Korean and English; English takes precedence</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;7. Browser prefers Korean and Czech; Korean takes precedence</td>
<td class="tbltd1">Czech displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;8. Browser prefers Korean and Czech; Czech takes precedence</td>
<td class="tbltd1">Czech displays</td>
</tr>
<tr>
<td class="tbltd1">&nbsp;9. Browser prefers English and Czech; English takes precedence</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">10. Browser prefers English and Czech; Czech takes precedence</td>
<td class="tbltd1">Czech displays</td>
</tr>
<tr>
<td class="tbltd1">11. Browser prefers, in the following order, English, Czech, Korean</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">12. Browser prefers, in the following order, English, Korean, Czech</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">13. Browser prefers, in the following order, Czech, English, Korean</td>
<td class="tbltd1">Czech displays</td>
</tr>
<tr>
<td class="tbltd1">14. Browser prefers, in the following order, Czech, Korean, English</td>
<td class="tbltd1">Czech displays</td>
</tr>
<tr>
<td class="tbltd1">15. Browser prefers, in the following order, Korean, English, Czech</td>
<td class="tbltd1">English displays</td>
</tr>
<tr>
<td class="tbltd1">16. Browser prefers, in the following order, Korean, Czech, English</td>
<td class="tbltd1">Czech displays</td>
</tr>
</tbody>
</table>
</div>
<br>
<p>Rather than stepping through all 16 scenarios, we'll demonstrate how to examine scenario 3 above, in which
the browser's preferred language is Czech, using the Firefox browser.</p>
<ol>
<li>In Firefox, choose Tools &gt; Options (Firefox &gt; Preferences on Mac). In the window that
displays, click the Content tab.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/firefox-content.png"
class="margin-around b-all" alt="Firefox options - Content tab"
title="Examine your browser's preferred languages"></li>
<li>Under the Languages heading, click Choose.</li>
<li>Select any language that is currently listed in the provided text area, then click Remove.
(You should remember your language list and reinstate languages after completing this tutorial.)</li>
<li>Click the 'Select Language to Add' drop-down and select <code>Czech [cs]</code>. Then
click the Add button. The Czech language is added to the text area.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/firefox-languages.png"
class="margin-around b-all" alt="Firefox options - General tab"
title="Specify your browser's preferred languages"></li>
<li>Click OK, then press Esc to close Firefox' Options window.</li>
<li>Run the project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ). When the welcome page opens in your browser, note
that text is displayed in Czech.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/czech-text.png"
class="margin-around b-all" alt="Czech text displayed in welcome page" style="width:688px"
title="The displayed language is determined by your browser's language preferences"></li>
</ol>
</div>
<br>
<h2 id="toggle">Implementing a Language Toggle</h2>
<p>Now that basic Czech-English language support is in place, continue by implementing the language
toggle in the application's page views. We can divide this task into three parts:</p>
<ul>
<li><a href="#toggleDisplay">Create Toggle Display and Synchronize with the Browser's Preferred Language</a></li>
<li><a href="#handleRequest">Implement Functionality to Handle a Request from the Language Toggle</a></li>
<li><a href="#keepTrack">Enable the Application to Keep Track of the Originating Page View</a></li>
</ul>
<div class="indent">
<h3 id="toggleDisplay">Create Toggle Display and Synchronize with the Browser's Preferred Language</h3>
<ol>
<li>Use the Go to File dialog to open the <code>header</code> JSP fragment in the editor. Press
Alt-Shift-O (Ctrl-Shift-O on Mac), then type '<code>h</code>' in the dialog and click OK.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/go-to-file-dialog.png"
class="margin-around b-all" alt="Go to File dialog"
title="Use the Go to File dialog to quickly open project resources in the editor"></li>
<li>In the <code>header.jspf</code> file, locate the first <code>&lt;div class=&quot;headerWidget&quot;&gt;</code>
tag (line 56), and replace the <code>[ language toggle ]</code> placeholder text with the
following HTML markup.
<pre class="examplecode">
&lt;div class=&quot;headerWidget&quot;&gt;
<strong>&lt;%-- language selection widget --%&gt;
english | &lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;chooseLanguage?language=cs&quot;&gt;česky&lt;/a&gt;&lt;/div&gt;</strong>
&lt;/div&gt;</pre>
This markup implements the language toggle's appearance when English is the displayed
language. In other words, the toggle provides a link allowing the user to select the
Czech (i.e., '<code>česky</code>') option. The link is used to send a request for
<code>chooseLanguage</code>, and creates a query string (<code>?language=cs</code>) that
specifies the requested language code.
<br><br>
<p class="notes"><strong>Note:</strong> Recall that in Unit 5, <a href="page-views-controller.html#controller">Preparing
the Page Views and Controller Servlet</a>, you set the <code>ControllerServlet</code>
to handle the <code>/chooseLanguage</code> URL pattern.</p>
<p class="tips">Snapshot 8 includes the <a href="http://jquery.com/" target="_blank">jQuery</a>
JavaScript library and takes advantage of various UI effects to enhance the appearance
and behavior of the website. Aside from a
<a href="http://plugins.jquery.com/project/validate" target="_blank">jQuery plugin
for client-side validation</a> (discussed in the <a href="transaction.html#client">previous
tutorial unit</a>), the snapshot implements an easing effect for category headings in
the welcome page, as well as for category buttons in the category page. Configuration
is included in <code>header.jspf</code> of the project snapshot. Rounded corners are
implemented using CSS3's <a href="http://www.w3.org/TR/css3-background/#corners"
target="_blank">border-radius</a> property (applied in <code>affablebean.css</code>).</p></li>
<li>Run the project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ) to see what the toggle looks like in the browser.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/language-toggle.png"
class="margin-around b-all" alt="Language toggle in browser"
title="Run the project to view the language toggle">
<br>
Currently, the language toggle appears as in the above image regardless of what language
the page displays in. In the next step, you integrate JSTL logic into the toggle so that
it renders according to the language displayed on the page.</li>
<li id="step4">Modify the toggle implementation as follows.
<pre class="examplecode">
&lt;div class=&quot;headerWidget&quot;&gt;
&lt;%-- language selection widget --%&gt;
<strong>&lt;c:choose&gt;
&lt;c:when test=&quot;${pageContext.request.locale.language ne 'cs'}&quot;&gt;
english
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;c:url var=&quot;url&quot; value=&quot;chooseLanguage&quot;&gt;
&lt;c:param name=&quot;language&quot; value=&quot;en&quot;/&gt;
&lt;/c:url&gt;
&lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;english&lt;/a&gt;&lt;/div&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt; |
&lt;c:choose&gt;
&lt;c:when test=&quot;${pageContext.request.locale.language eq 'cs'}&quot;&gt;
česky
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;c:url var=&quot;url&quot; value=&quot;chooseLanguage&quot;&gt;
&lt;c:param name=&quot;language&quot; value=&quot;cs&quot;/&gt;
&lt;/c:url&gt;
&lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;česky&lt;/a&gt;&lt;/div&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;</strong>
&lt;/div&gt;</pre>
In the above implementation, you rely on conditional tags from JSTL's <code>core</code>
tag library to display the left and right portions of the toggle according to the language
used by the request locale. What is the &quot;language used by the request locale&quot;?
When a request is made, the browser passes a list of preferred locales in the <code>Accept-Language</code>
HTTP header. The Java runtime environment on the server reads the list and determines
the best match based on the locales defined by the application's resource bundles. This
match is then recorded in the <code>ServletRequest</code> object, and can be accessed
using the <code>getLocale</code> method. For example, you could access the preferred
locale from a servlet with the following statement.
<pre class="examplecode">request.getLocale();</pre>
<p class="tips">You can use the IDE's HTTP Monitor (Window &gt; Debugging &gt; HTTP
Server Monitor) to examine HTTP headers for client requests. In order to use the
HTTP Monitor, you need to first activate it for the server you are using. Unit 8,
<a href="manage-sessions.html">Managing Sessions</a> provides a demonstration
under the sub-section, <a href="manage-sessions.html#http-monitor">Examining
Client-Server Communication with the HTTP Monitor</a>.</p>
<p>To determine the language of the preferred locale, you use the <code>Locale</code>
class' <code>getLanguage</code> method. Again, from a servlet you could access the
language of the client request's preferred locale with the following.</p>
<pre class="examplecode">request.getLocale().getLanguage();</pre>
<p>Returning to the code you just added to the <code>header.jspf</code> fragment,
you utilize the <code>pageContext.request</code> implicit object to access the
<code>ServletRequest</code> for the given client request. Using dot notation, you
then proceed to call the same methods as you would from a servlet. In the above
example, accessing the &quot;language used by the request locale&quot; is as simple
as:</p>
<pre class="examplecode">${pageContext.request.locale.language}</pre>
<p class="notes"><strong>Note:</strong> The above implementation uses <code>&lt;c:url&gt;</code>
tags to set up the toggle link. This is done in order to properly encode the request
URL in the event that URL rewriting is used as a means for session tracking. Unit 8,
<a href="manage-sessions.html#encodeUrl">Managing Sessions</a> provides a brief
explanation of how the <code>&lt;c:url&gt;</code> tags can be used.</p></li>
<li>Add a basic language test to the <code>header.jspf</code> file. This will enable us to
check whether the toggle is properly rendering according to the client request's preferred
language. Enter the following after the page's <code>&lt;body&gt;</code> tag.
<pre class="examplecode">
&lt;body&gt;
<strong>&lt;%-- Language test --%&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;tests:&lt;/strong&gt;
&lt;br&gt;
&lt;code&gt;\${pageContext.request.locale.language}&lt;/code&gt;: ${pageContext.request.locale.language}
&lt;/p&gt;</strong>
&lt;div id=&quot;main&quot;&gt;</pre></li>
<li>Ensure that you have set Czech as your browser's preferred language. (If you are
following this tutorial unit sequentially, you've already done this. If not, refer
to the steps outlined above in <a href="#test">Test Supported Languages</a>.)</li>
<li>Run the project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ) and examine the application welcome page in the browser.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/language-test.png"
class="margin-around b-all" style="width:688px" alt="Language test and welcome page displayed in browser"
title="Language toggle displays according to request's preferred language">
<br>
If your browser's preferred language is set to Czech, you can note the following:
<ul style="margin: 5px 0 0 -1em">
<li>The test that we introduced in the previous step indicates that '<code>cs</code>'
is the preferred language.</li>
<li>Czech text is displayed in the page.</li>
<li>The language toggle provides a link enabling the user to select English.</li>
</ul>
</li>
</ol>
<h3 id="handleRequest">Implement Functionality to Handle a Request from the Language Toggle</h3>
<p>Now that the toggle is in place and it appears according to the language displayed
in the page, let's continue by adding code to the <code>ControllerServlet</code>
that handles the request sent when a user clicks the link in the language toggle.</p>
<p>As indicated in the current language toggle implementation from <a href="#step4">step 4</a>
above, the requested URL with query string looks as follows:</p>
<ul style="margin: 5px 0 0 -1em">
<li><strong>English:</strong> <code>chooseLanguage?language=en</code></li>
<li><strong>Czech:</strong> <code>chooseLanguage?language=cs</code></li>
</ul>
<p>Our goal is to register the language choice, and then display both the page view and
language toggle based on the chosen language. We can accomplish this by extracting
the <code>language</code> parameter from the query string and creating a session-scoped
<code>language</code> attribute that remembers the language selected by the user. Then
we'll return to the <code>header.jspf</code> fragment and apply the
<a href="http://download-llnw.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/fmt/setLocale.html" target="_blank"><code>&lt;fmt:setLocale&gt;</code></a>
tag to set the page language based on the user's choice. With the <code>&lt;fmt:setLocale&gt;</code>
tag we can manually switch the language used in the page display. We'll also modify
the language toggle so that if the <code>language</code> attribute has been set, the
toggle's appearance is determined according to the <code>language</code> attribute's
value.</p>
<ol>
<li>Open the <code>ControllerServlet</code> in the editor. Use the Go To File dialog
- press Alt-Shift-O (Ctrl-Shift-O on Mac), then type '<code>controller</code>' and
click OK. In the opened file, locate the portion of the <code>doGet</code> method
that handles the <code>chooseLanguage</code> request (line 126).</li>
<li>Delete the <code>// TODO: Implement language request</code> comment and enter code
to extract the <code>language</code> parameter from the request query string.
<pre class="examplecode">
// if user switches language
} else if (userPath.equals(&quot;/chooseLanguage&quot;)) {
<strong>// get language choice
String language = request.getParameter(&quot;language&quot;);</strong>
}</pre></li>
<li>Place the <code>language</code> parameter in the request scope. Add the following.
<pre class="examplecode">
// if user switches language
} else if (userPath.equals(&quot;/chooseLanguage&quot;)) {
// get language choice
String language = request.getParameter(&quot;language&quot;);
<strong>// place in request scope
request.setAttribute(&quot;language&quot;, language);</strong>
}</pre></li>
<li>As a temporary measure, have the application forward the response to the
<code>index.jsp</code> welcome page when the language toggle link is clicked.
Add the following code.
<pre class="examplecode">
// if user switches language
} else if (userPath.equals("/chooseLanguage")) {
// get language choice
String language = request.getParameter("language");
// place in request scope
request.setAttribute("language", language);
<strong>// forward request to welcome page
try {
request.getRequestDispatcher("/index.jsp").forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
return;</strong>
}</pre>
Naturally, forwarding the user to the welcome page regardless of what page
he or she is on is not an ideal way to handle the language toggle's behavior.
We'll return to this matter in the next sub-section, <a href="#keepTrack">Enable
the Application to Keep Track of the Originating Page View</a>. For the meantime
however, this will allow us to examine the results of the current language
toggle implementation when running the project.</li>
<li>Switch to the <code>header.jspf</code> fragment (If the file is already opened
in the editor, press Ctrl-Tab and choose the file.) and apply the
<a href="http://download-llnw.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/fmt/setLocale.html" target="_blank"><code>&lt;fmt:setLocale&gt;</code></a>
tag to set the page language based on the new <code>language</code> variable.
Add the following.
<pre class="examplecode">
&lt;%@taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;%@taglib prefix=&quot;fn&quot; uri=&quot;http://java.sun.com/jsp/jstl/functions&quot; %&gt;
<strong>&lt;%@taglib prefix=&quot;fmt&quot; uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; %&gt;
&lt;%-- Set language based on user's choice --%&gt;
&lt;c:if test=&quot;${!empty language}&quot;&gt;
&lt;fmt:setLocale value=&quot;${language}&quot; scope=&quot;session&quot; /&gt;
&lt;/c:if&gt;</strong>
&lt;%@page contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;
&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;</pre>
Since the <code>language</code> variable is only created when the user clicks the
link in the language toggle, you perform a test using
<a href="http://download-llnw.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/c/if.html" target="_blank"><code>&lt;c:if&gt;</code></a>
tags to determine whether the variable exists before attempting to set the language.
When applying the <code>&lt;fmt:setLocale&gt;</code> tag, you set its scope to
<code>session</code> as you want the user-selected language to take precedence
for the remainder of his or her session on the website. Also, since this is the
first time the <code>fmt</code> library is used in the header, you declare the tag
library.
<br><br>
<p class="tips">You can read the EL expression <code>${!empty language}</code> as,
&quot;False if the <code>language</code> variable is null or an empty string.&quot;
See the
<a href="http://download-llnw.oracle.com/javaee/5/tutorial/doc/bnahq.html#bnaim" target="_blank">Java
EE 5 Tutorial: Examples of EL Expressions</a> for other available examples.</p></li>
<li>Modify the language toggle implementation so that if a value has been set by the
<code>&lt;fmt:setLocale&gt;</code> tag, the toggle displays according to the language
specified by that value. (You can determine this value using the
<code>${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}</code> expression.)
<br><br>
Enclose the current implementation within <code>&lt;c:choose&gt;</code> tags, and
create logic similar to the current implementation in the event that the locale has
been manually set. (Changes are displayed in <strong>bold</strong>.)
<pre class="examplecode">
&lt;div class=&quot;headerWidget&quot;&gt;
&lt;%-- language selection widget --%&gt;
<strong>&lt;c:choose&gt;
&lt;%-- When user hasn't explicitly set language,
render toggle according to browser's preferred locale --%&gt;
&lt;c:when test=&quot;${empty sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}&quot;&gt;</strong>
&lt;c:choose&gt;
&lt;c:when test=&quot;${pageContext.request.locale.language ne 'cs'}&quot;&gt;
english
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;c:url var=&quot;url&quot; value=&quot;chooseLanguage&quot;&gt;
&lt;c:param name=&quot;language&quot; value=&quot;en&quot;/&gt;
&lt;/c:url&gt;
&lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;english&lt;/a&gt;&lt;/div&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt; |
&lt;c:choose&gt;
&lt;c:when test=&quot;${pageContext.request.locale.language eq 'cs'}&quot;&gt;
česky
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;c:url var=&quot;url&quot; value=&quot;chooseLanguage&quot;&gt;
&lt;c:param name=&quot;language&quot; value=&quot;cs&quot;/&gt;
&lt;/c:url&gt;
&lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;česky&lt;/a&gt;&lt;/div&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;
<strong>&lt;/c:when&gt;
&lt;%-- Otherwise, render widget according to the set locale --%&gt;
&lt;c:otherwise&gt;
&lt;c:choose&gt;
&lt;c:when test=&quot;${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session'] ne 'cs'}&quot;&gt;
english
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;c:url var=&quot;url&quot; value=&quot;chooseLanguage&quot;&gt;
&lt;c:param name=&quot;language&quot; value=&quot;en&quot;/&gt;
&lt;/c:url&gt;
&lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;english&lt;/a&gt;&lt;/div&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt; |
&lt;c:choose&gt;
&lt;c:when test=&quot;${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session'] eq 'cs'}&quot;&gt;
česky
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;c:url var=&quot;url&quot; value=&quot;chooseLanguage&quot;&gt;
&lt;c:param name=&quot;language&quot; value=&quot;cs&quot;/&gt;
&lt;/c:url&gt;
&lt;div class=&quot;bubble&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;česky&lt;/a&gt;&lt;/div&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;</strong>
&lt;/div&gt;</pre></li>
<li>Before examining the project in a browser, add another test that displays the
value set by the <code>&lt;fmt:setLocale&gt;</code> tag. Add the following code
beneath the test you created earlier.
<pre class="examplecode">
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;tests:&lt;/strong&gt;
&lt;br&gt;
&lt;code&gt;\${pageContext.request.locale.language}&lt;/code&gt;: ${pageContext.request.locale.language}
<strong>&lt;br&gt;
&lt;code&gt;\${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}&lt;/code&gt;: ${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}</strong>
&lt;/p&gt;</pre>
<p class="tips"><code>javax.servlet.jsp.jstl.fmt.locale.session</code> is the <em>string
literal</em> key for the <code>Locale</code> set by the <code>&lt;fmt:setLocale&gt;</code>
tag. You can verify this by clicking in the editor's left margin to set a breakpoint (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/breakpoint-badge.png"
alt="Breakpoint badge"> ) on the new test, then running the debugger (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/debug-project-btn.png"
alt="Debug Project button"> ) on the project. When you click the toggle link to change
languages in the browser, examine the Variables window (Alt-Shift-1; Ctrl-Shift-1 on
Mac) when the debugger suspends on the breakpoint.
<br>
<a href="../../../../images_www/articles/73/javaee/ecommerce/language/variables-window.png"
rel="lytebox" title="Run debugger and view variable and expression values in the Variables window">
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/variables-window.png"
class="margin-around b-all" style="width:654px" alt="Variables window"
title="Click to enlarge"></a>
<br>
EL expressions presented in this tutorial primarily use dot (<code>.</code>) notation. The
format depicted in the expression above is known as <em>bracket</em> (<code>[]</code>) notation
whereby you enter the string literal key within quotes in order to extract the object's value:
<div style="margin:-10px 0 0 43px">
<pre class="examplecode" style="width:637px">${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}</pre>
</div>
<p style="margin-left:34px">Numerous EL resolver classes exist for the purpose of resolving expressions.
For example, when the above expression is encountered at runtime, the
<a href="http://download-llnw.oracle.com/javaee/6/api/javax/servlet/jsp/el/ImplicitObjectELResolver.html" target="_blank"><code>ImplicitObjectResolver</code></a>
first returns a <code>Map</code> that maps session-scoped attribute names to their values. (In the
above image of the Variables window, you can verify that session attributes are maintained in a
<a href="http://download-llnw.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html" target="_blank"><code>ConcurrentHashMap</code></a>.)
In order to resolve the remainder of the expression, the
<a href="http://download-llnw.oracle.com/javaee/6/api/javax/el/MapELResolver.html" target="_blank"><code>MapELResolver</code></a>
is used to get the value of the key named '<code>javax.servlet.jsp.jstl.fmt.locale.session</code>'.
<br><br>
For more information, refer to the Java EE 5 Tutorial:
<a href="http://download-llnw.oracle.com/javaee/5/tutorial/doc/bnahq.html#bnaif" target="_blank">Unified
Expression Language: Resolving Expressions</a>.</li>
<li>Run the project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ) and examine the application welcome page in the browser.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/toggle-page1.png"
class="margin-around b-all" style="width:688px" alt="Welcome page displayed in browser"
title="Welcome page displays according to browser's preferred language">
<br>
In the above image, the server identifies Czech (<code>cs</code>) as the browser's preferred
language from the <code>Accept-Language</code> HTTP header. This is indicated from the first
test. The page displays in Czech, and the language toggle enables the user to choose English.
The second test remains blank as the <code>&lt;fmt:setLocale&gt;</code> tag has not yet been
called.</li>
<li>Click the toggle link for English.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/toggle-page2.png"
class="margin-around b-all" style="width:688px" alt="Welcome page displayed in browser"
title="Welcome page displays in English, according to toggle selection">
<br>
When clicking the toggle link, the default Czech language is overridden by means of the
<code>&lt;fmt:setLocale&gt;</code> tag implemented in the <code>header.jspf</code> file.
Although the browser's preferred language remains Czech, you see that the page now displays
according to the new language made available by the language toggle.</li>
<li>Click the toggle link for Czech.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/toggle-page3.png"
class="margin-around b-all" style="width:688px" alt="Welcome page displayed in browser"
title="Welcome page displays in Czech, according to toggle selection">
<br>
Changing the language back to the browser's preferred language works as expected, however
note that the deciding factor is no longer the language detected from the <code>Accept-Language</code>
HTTP header, but is the language specified from the <code>&lt;fmt:setLocale&gt;</code> tag.</li>
<li>Before continuing, remove the tests you added to the <code>header.jspf</code> file.
(Deleted code in <strong><strike>strike-through</strike></strong> text.)
<pre class="examplecode">
&lt;body&gt;
<strong><strike>&lt;%-- Language tests --%&gt;</strike>
<strike>&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;tests:&lt;/strong&gt;</strike>
<strike>&lt;br&gt;</strike>
<strike>&lt;code&gt;\${pageContext.request.locale.language}&lt;/code&gt;: ${pageContext.request.locale.language}</strike>
<strike>&lt;br&gt;</strike>
<strike>&lt;code&gt;\${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}&lt;/code&gt;: ${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}</strike>
<strike>&lt;/p&gt;</strike></strong>
&lt;div id=&quot;main&quot;&gt;</pre></li>
</ol>
<h3 id="keepTrack">Enable the Application to Keep Track of the Originating Page View</h3>
<p>One of the <a href="#impDeets">implementation details</a> which you have agreed on with
the Affable Bean staff is that when the language toggle is used to change the language,
the user remains in the same page view. In our current implementation, the welcome page
is returned whenever the language toggle is clicked. A more user-friendly approach would
be to provide the application with a means of tracking the request page view, and forwarding
the request to that page view when the language toggle link is clicked.</p>
<p>We can accomplish this by setting a session-scoped <code>view</code> attribute within each
of the page views, then referencing this attribute in the <code>ControllerServlet</code>
in order to determine where to forward the request. There are however several caveats
to consider when dealing with the language toggle in the confirmation page. These are
discussed and dealt with in steps 7-11 below.</p>
<p>Begin this exercise with <a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot9.zip">snapshot
9</a> of the <code>AffableBean</code> project. This snapshot includes completed English
and Czech resource bundles for all page views, all page views have been modified to use
text from the resource bundles, and the language toggle is presented in a state corresponding
to this point in the tutorial.</p>
<ol>
<li>Open <a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot9.zip">snapshot
9</a> in the IDE. Click the Open Project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/open-project-btn.png"
alt="Open Project button"> ) button and use the wizard to navigate to the location
on your computer where you downloaded the project.</li>
<li>Click the Run Project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ) button to run the project. When navigating through the site,
note that when you click the language toggle from any of the page views, you are returned
to the application's welcome page.
<br><br>
<p class="alert">If you receive an error when running the project, revisit the
<a href="setup.html">setup instructions</a>, which describe how to prepare the
database and establish connectivity between the IDE, GlassFish, and MySQL.</p></li>
<li>Use <a href="http://download.oracle.com/docs/cd/E17802_01/products/products/jsp/jstl/1.1/docs/tlddocs/c/set.html" target="_blank"><code>&lt;c:set&gt;</code></a>
tags to set a session-scoped <code>view</code> attribute for each of the page views.
Open each of the page views in the editor and add the following code to the top of
each file.
<h4>index.jsp</h4>
<pre class="examplecode">
&lt;%-- Set session-scoped variable to track the view user is coming from.
This is used by the language mechanism in the Controller so that
users view the same page when switching between English and Czech. --%&gt;
&lt;c:set var='view' value='/index' scope='session' /&gt;</pre>
<h4>category.jsp</h4>
<pre class="examplecode">
&lt;%-- Set session-scoped variable to track the view user is coming from.
This is used by the language mechanism in the Controller so that
users view the same page when switching between English and Czech. --%&gt;
&lt;c:set var='view' value='/category' scope='session' /&gt;</pre>
<h4>cart.jsp</h4>
<pre class="examplecode">
&lt;%-- Set session-scoped variable to track the view user is coming from.
This is used by the language mechanism in the Controller so that
users view the same page when switching between English and Czech. --%&gt;
&lt;c:set var='view' value='/cart' scope='session' /&gt;</pre>
<h4>checkout.jsp</h4>
<pre class="examplecode">
&lt;%-- Set session-scoped variable to track the view user is coming from.
This is used by the language mechanism in the Controller so that
users view the same page when switching between English and Czech. --%&gt;
&lt;c:set var='view' value='/checkout' scope='session' /&gt;</pre>
Based on customer-agreed <a href="#impDeets">implementation details</a>, we
do not need to provide a means of switching languages on the confirmation page
view. From a usability perspective, a user will have already selected his or
her preferred language prior to checkout. From an implementation perspective,
recall that we destroy the user session upon a successfully completed order.
(Refer back to the final paragraph in <a href="manage-sessions.html">Managing
Sessions</a>, which describes how to apply the <code>invalidate</code> method
to explicitly terminate a user session.) If the Affable Bean staff were to insist
on allowing customers to view their orders bilingually, you would need to consider
the following scenarios, dependent on whether you destroy the user session
upon displaying the confirmation page:
<ol style="margin: 5px 0 0 0em; list-style-type:lower-alpha">
<li><strong>Session destroyed:</strong> Would be necessary to take
extra measures to ensure that a <code>chooseLanguage</code> request
from the confirmation page refers to the appropriate order, and can
display customer-sensitive details in a secure fashion.</li>
<li><strong>Session maintained:</strong> Would risk enabling users
to mistakenly place double orders on their shopping cart. Also, by
not terminating user sessions when they are no longer needed, an
unnecessary load may be placed on the server.</li>
</ol></li>
<li>Open the <code>ControllerServlet</code> in the editor. (If already opened,
press Ctrl-Tab and choose the file.) In the opened file, locate the portion
of the <code>doGet</code> method that handles the <code>chooseLanguage</code>
request (line 126).
<br><br>
Note that currently <code>chooseLanguage</code> requests are forwarded to
the <code>index.jsp</code> welcome page.
<pre class="examplecode">
// if user switches language
} else if (userPath.equals(&quot;/chooseLanguage&quot;)) {
// get language choice
String language = request.getParameter(&quot;language&quot;);
// place in session scope
session.setAttribute(&quot;language&quot;, language);
<strong>// forward request to welcome page
try {
request.getRequestDispatcher(&quot;/index.jsp&quot;).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
return;</strong>
}</pre></li>
<li>Use the <code>view</code> session attribute to forward the request back
to the originating page view. Make the following changes (in <strong>bold</strong>).
<pre class="examplecode">
// if user switches language
} else if (userPath.equals(&quot;/chooseLanguage&quot;)) {
// get language choice
String language = request.getParameter(&quot;language&quot;);
// place in request scope
request.setAttribute(&quot;language&quot;, language);
<strong>String userView = (String) session.getAttribute(&quot;view&quot;);
if ((userView != null) &&
(!userView.equals(&quot;/index&quot;))) { // index.jsp exists outside 'view' folder
// so must be forwarded separately
userPath = userView;
} else {
// if previous view is index or cannot be determined, send user to welcome page</strong>
try {
request.getRequestDispatcher(&quot;/index.jsp&quot;).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
return;
<strong>}</strong>
}</pre>
In the above implementation, you extract the value of the <code>view</code> attribute
and, provided that the view:
<ul style="margin: 5px 0 0 -1em">
<li>can be identified (i.e., the value is not null),</li>
<li>does not originate from the welcome page (<code>index.jsp</code> does not
reside in the same location as other page views, and therefore cannot be
resolved using the <code>doGet</code> method's way of forwarding requests)</li>
</ul>
<span class="indent">...you set it to the <code>doGet</code> method's <code>userPath</code>
variable, and forward the request using the method's existing <code>RequestDispatcher</code>:</span>
<pre class="examplecode">
// use RequestDispatcher to forward request internally
String url = &quot;/WEB-INF/view&quot; + userPath + &quot;.jsp&quot;;
try {
request.getRequestDispatcher(url).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}</pre></li>
<li>Run the project (
<img src="../../../../images_www/articles/73/javaee/ecommerce/common/run-project-btn.png"
alt="Run Project button"> ) to test it in the browser. When you navigate to the
category, cart or checkout pages, switch languages using the language toggle.
When you do so, you now remain within the same page view.</li>
<li>In the browser, complete an order so that the application forwards you to the
confirmation page. When you click the language toggle from the confirmation page,
note that you are sent back to the website's welcome page.
<br><br>
Implementation-wise, you may consider this to be sufficient. However, the Affable
Bean staff have explicitly asked you to remove the language toggle from this page
view. One way to accomplish this is to perform a test to determine whether the request
<em>servlet path</em> contains '<code>/confirmation</code>'.
<br><br>
Switch to the <code>header.jspf</code> file in the editor and surround the language
toggle with the following test. You can use JSTL's functions (i.e.,
<a href="http://download.oracle.com/docs/cd/E17802_01/products/products/jsp/jstl/1.1/docs/tlddocs/fn/tld-summary.html" target="_blank"><code>fn</code></a>)
library to perform string operations.
<pre class="examplecode">
&lt;div class=&quot;headerWidget&quot;&gt;
<strong>&lt;%-- If servlet path contains '/confirmation', do not display language toggle --%&gt;
&lt;c:if test=&quot;${!fn:contains(pageContext.request.servletPath,'/confirmation')}&quot;&gt;</strong>
&lt;%-- language selection widget --%&gt;
&lt;c:choose&gt;
...
&lt;/c:choose&gt;
<strong>&lt;/c:if&gt;</strong>
&lt;/div&gt;</pre>
Examine the above code snippet and note the following points:
<ul style="margin: 5px 0 0 -1em">
<li>The servlet path can be accessed from the <code>HttpServletRequest</code>
using the <a href="http://download.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getServletPath%28%29" target="_blank"><code>getServletPath</code></a>
method. Because we use a <code>RequestDispatcher</code> to forward the request
to the confirmation page (<code>ControllerServlet</code>, line 158), the servlet
path becomes:
<pre class="examplecode" style="width: 651px">/WEB-INF/view/confirmation.jsp</pre></li>
<li>Using the <code>pageContext.request.servletPath</code> EL expression is
comparable to calling <code>request.getServletPath()</code> from a servlet.</li>
<li>The <a href="http://download.oracle.com/docs/cd/E17802_01/products/products/jsp/jstl/1.1/docs/tlddocs/fn/contains.fn.html" target="_blank"><code>fn:contains()</code></a>
function allows you to test if an input string contains the specified substring.</li>
<li>The <code>fn</code> tag library has already been declared for you at the top of
in the <code>header.jspf</code> file in snapshot 9:
<pre class="examplecode" style="width: 651px">&lt;%@taglib prefix=&quot;fn&quot; uri=&quot;http://java.sun.com/jsp/jstl/functions&quot; %&gt;</pre></li>
</ul></li>
<li>Run the project again and step through to the confirmation page. Note that the page
no longer displays the language toggle.
<br>
<img src="../../../../images_www/articles/73/javaee/ecommerce/language/confirmation-page.png"
class="margin-around b-all" style="width:688px" alt="Confirmation page displayed in browser"
title="Language toggle no longer displays in confirmation page"></li>
<li>In the browser, step through to the confirmation page but switch languages once along the
way using the language toggle. Note that when you complete an order, the confirmation page
inadvertently switches back to the originally displayed language. You may rightly identify
the cause: upon a successfully completed order, the <code>ControllerServlet</code> destroys
the user session and consequently the session-scoped locale that was set using the
<code>&lt;fmt:setLocale&gt;</code> tag is also lost.
<br><br>
To remedy this, open the <code>ControllerServlet</code> and locate the <code>invalidate()</code>
method which is used to destroy user sessions (approximately line 259).
<br><br>
<p class="tips">Use the editor's quick search facility: press Ctrl-F (&#8984;-F on Mac)
and type in '<code>invalidate</code>'.</p></li>
<li>Add code that extracts the session-scoped locale value prior to destroying the user session
and resets the request-scoped <code>language</code> attribute to the locale value after the
session has been destroyed. (Changes in <strong>bold</strong>.)
<pre class="examplecode">
// if order processed successfully send user to confirmation page
if (orderId != 0) {
<strong>// in case language was set using toggle, get language choice before destroying session
Locale locale = (Locale) session.getAttribute(&quot;javax.servlet.jsp.jstl.fmt.locale.session&quot;);
String language = &quot;&quot;;
if (locale != null) {
language = (String) locale.getLanguage();
}</strong>
// dissociate shopping cart from session
cart = null;
// end session
session.invalidate();
<strong>if (!language.isEmpty()) { // if user changed language using the toggle,
// reset the language attribute - otherwise
request.setAttribute(&quot;language&quot;, language); // language will be switched on confirmation page!
}</strong>
// get order details
Map orderMap = orderManager.getOrderDetails(orderId);
...
userPath = &quot;/confirmation&quot;;
}</pre></li>
<li>Run the project and again, step through to the confirmation page but switch languages
once along the way using the language toggle. Note that when you complete an order,
the confirmation page now displays in the language you selected.</li>
</ol>
</div>
<p>You have now successfully integrated language support into the <code>AffableBean</code>
application according to customer specification. You've factored out all text from page views,
placed it into resource bundles, and have applied JSTL's <code>fmt</code> tag library to
use resource bundle content based on the user's preferred language. You also implemented
a language toggle that enables users to switch between English and Czech, and override their
browser's default language choice. Download and examine
<a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252Fecommerce%252FAffableBean_snapshot10.zip">snapshot
10</a> to compare your work with the state of the project at the end of this tutorial unit.</p>
<div class="feedback-box">
<a href="/about/contact_form.html?to=3&amp;subject=Feedback: NetBeans E-commerce Tutorial - Adding Language Support">Send
Us Your Feedback</a></div>
<br style="clear:both;">
<br>
<h2 id="seeAlso">See Also</h2>
<div class="indent">
<h3>NetBeans Resources</h3>
<ul>
<li><a href="../javaee-intro.html" target="_blank">Introduction to Java EE Technology</a></li>
<li><a href="../javaee-gettingstarted.html" target="_blank">Getting Started with Java EE Applications</a></li>
<li><a href="https://netbeans.org/projects/www/downloads/download/shortcuts.pdf">Keyboard Shortcuts & Code Templates Card</a></li>
<li><a href="../../../trails/java-ee.html" target="_blank">Java EE & Java Web Learning Trail</a></li>
</ul>
<h3>External Resources</h3>
<ul>
<li><a href="http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/i18n/index.html" target="_blank">The Java Tutorials: Internationalization</a></li>
<li><a href="http://download.oracle.com/docs/cd/E17477_01/javaee/5/tutorial/doc/bnaxu.html" target="_blank">Java EE 5 Tutorial: Internationalizing and Localizing Web Applications</a></li>
<li><a href="http://java.sun.com/developer/technicalArticles/Intl/MultilingualJSP/index.html" target="_blank">Developing Multilingual Web Applications Using JavaServer Pages Technology</a></li>
<li><a href="http://java.sun.com/developer/technicalArticles/J2SE/locale/" target="_blank">Internationalization: Understanding Locale in the Java Platform</a></li>
<li><a href="http://java.sun.com/developer/technicalArticles/Intl/ResourceBundles/" target="_blank">Java Internationalization: Localization with ResourceBundles</a></li>
<li><a href="http://www.ibm.com/developerworks/java/library/j-jstl0415/" target="_blank">A JSTL primer, Part 3: Presentation is everything</a></li>
<li><a href="http://java.sun.com/javase/technologies/core/basic/intl/" target="_blank">Java Internationalization</a> [Technology Homepage]</li>
<li><a href="http://en.wikipedia.org/wiki/Internationalization_and_localization" target="_blank">Internationalization and localization</a> [Wikipedia]</li>
<li><a href="http://www.loc.gov/standards/iso639-2/php/code_list.php" target="_blank">ISO 639-2 Language Code List</a> [Library of Congress]</li>
<li><a href="http://www.w3.org/International/articlelist#language" target="_blank">W3C Internationalization Activity: Articles, best practices & tutorials: Language</a></li>
<li><a href="http://jquery.com/" target="_blank">jQuery</a></li>
</ul>
</div>
</body>
</html>