7.5 Use of <fmt:message>The JSTL I18N actions all work together for one purpose: to retrieve Request Encoding" on page 287 <fmt:message" on page 502 for a complete description of <fmt:message> syntax.
The key attribute, which is mandatory in the preceding syntax, specifies a key in a resource bundle. Usually, <fmt:message> actions search for a localization context (that contains a resource bundle) themselves, but you can also specify a localization context with the optional bundle attribute.<fmt:message> actions send their localized message to the current JspWriter or, if you specify the var and scope attributes, to a scoped variable. Here are three examples of how you can use <fmt:message> with the preceding syntax:
The first line of the preceding code fragment shows the simplest use of Localization Contexts" on page 263is a simple bean that contains a resource bundle and a locale; if you specify a localization context with the bundle attribute, the corresponding <fmt:message> action will use that localization context's resource bundle to retrieve a localized message. This use of <fmt:message> is not very popular, because it's cumbersome to specify a localization context every time you use <fmt:message>. [9] The word bundle is a misnomer. The <fmt:message> bundle attribute used to refer to a resource bundle, but now it refers to a localization context. You can also localize compound messages with <fmt:message>, with this syntax:
A compound message contains parameters; for example, at the bottom of your website you might show the current date with a compound message that looks like this: Today is: {0}, where {0} is a parameter that specifies the current date. You could do that like this:
The preceding code fragment uses <jsp:useBean> to create a Java beanan instance of java.util.Date. A <fmt:param> action specifies that bean as a parameter for its enclosing <fmt:message> action. That <fmt:message> action substitutes the bean's value for {0} in the compound message. In a resource bundle, you would specify that compound message like this:
See "Compound Messages and <fmt:param>" on page 283 for more information about compound messages and message parameters. Also, see Listing 7.16 on page 285 for an alternative to <jsp:useBean> in the preceding code fragment by using the fmt_rt tag library.The <fmt:message> action also lets you specify the message key in the body of the action, with this syntax:
Long message keys and message keys produced by custom actions are two reasons for the preceding syntax; for example, you might store categories for user preferences as message keys, and you might access those categories with custom actions, so you could do this:
In the preceding code fragment, the <acme:preference> custom action returns the message key associated with a user's session timeout; e.g., preferences.session.timeout. That key is used by <fmt:message> to display a localized message; for example, User Session Timeout, for an English locale. That technique essentially lets you create constant values for message keys, so that you can change the keys without changing your JSP pages.If you specify a null value or an empty string for the <fmt:message> key attribute, that <fmt:message> action will produce this message: ??????. If a <fmt:message> action cannot locate a localization context or if the specified key is not defined in the resource bundle stored in the localization context, <fmt:message> will produce output that looks like this: ???<key>???, where <key> represents the value that you specified for the action's key attribute. Localization Context LookupAs we saw in "Use of <fmt:message>" on page 265, <fmt:message> actions use a resource bundle stored in a localization context to turn message keys into localized messages. To locate a localization context, all <fmt:message> actions perform a localization context lookup; once they find a localization context, they use its resource bundle to localize their messages. That lookup works like this:
1 If the <fmt:message>bundle attribute is specified, use it.First, <fmt:message> checks to see if you specified its bundle attribute, for example:
If you specify the bundle attribute, <fmt:message> assumes that the bundle attribute's value (${messages} in the preceding code fragment) is a localization context, and it uses that localization context's resource bundle to localize its message. That localization context is most often created by business components, but you can easily create one in a scriptlet, like this:[10] [10] The scriptlet approach is not recommended; it's shown here for illustration only.
The preceding code fragment retrieves a French resource bundle, which is used to create a localization context. The scriptlet stores the localization context in page scope by using PageContext.setAttribute. Subsequently, a <fmt:message> action accesses that localization context by specifying it with the action's bundle attribute.Specifying a localization context with the <fmt:message> bundle attribute is cumbersome because you have to specify that localization context for every <fmt:message> action. It would be better if you could group <fmt:message> actions that use the same localization context; in fact, you can do just that with the <fmt:bundle> action, which is discussed next. 2 If the <fmt:message> action isnested in a <fmt:bundle> , use the enclosing <fmt:bundle> action's localization context.If you don't specify the bundle attributeas is usually the case<fmt:message> actions check to see if they are nested in a <fmt:bundle>" on page 500 for a complete description of <fmt:bundle> syntax, including the prefix attribute.
All <fmt:message> actions in the body of a <fmt:bundle> action implicitly access the localization context of their enclosing <fmt:bundle> action; for example, in the following code fragment, the first two <fmt:message> actions use the localization context established by their enclosing <fmt:bundle> action.
The third <fmt:message> action in the preceding code fragment uses a localization context that contains a resource bundle whose base name is footers. Because <fmt:message> actions check their bundle attribute first, that attribute overrides the localization context established by an enclosing <fmt:bundle>; so, in the preceding code fragment, the footers localization context overrides the messages localization context for the third <fmt:message> action.The <fmt:bundle> action has a mandatory basename attribute that specifies a resource bundle base name. That attribute is a string that <fmt:bundle> actions use to search for a resource bundle, which is subsequently stored in the <fmt:bundle> action's localization context. See "The Resource Bundle Lookup Algorithm" on page 276 for more information about that resource bundle search.The <fmt:bundle> action is great for grouping <fmt:message> actions that use the same localization context, so you don't have to specify a localization context for every <fmt:message> action. But <fmt:bundle> cannot span JSP pages; it would be nice if you could specify a localization context for all <fmt:message> actions in a particular scope, say, request or session. You can do that with the <fmt:setBundle> action, which is discussed below. 3 Use the FMT_LOCALIZATION_CONTEXT configuration setting.If a <fmt:message> action is free-standing (meaning it's not enclosed in a <fmt:bundle> action) and its bundle attribute is not specified, then the <fmt:message> action looks for a localization context in the FMT_LOCALIZATION_CONTEXT configuration setting; for example: <%-- The following <fmt:message> action is not nested in The FMT_LOCALIZATION_CONTEXT configuration setting is listed in Table 7.7.
Because you can specify a configuration setting as a string, you can specify the FMT_LOCALIZATION_CONTEXT configuration setting as a context initialization parameter in a deployment descriptor, like this:
The preceding fragment of a deployment descriptor (WEB-INF/web.xml) declares a context initialization parameter named javax.servlet.jsp.jstl.localizationContext, which is the name of the FMT_LOCALIZATION_CONTEXT configuration setting (see <fmt:setBundle>" on page 498 for a complete description of <fmt:setBundle> syntax.
Like <fmt:bundle>, <fmt:setBundle> has a mandatory basename attribute that specifies a resource bundle basename; for example:
The <fmt:setBundle> action in the preceding line of code locates a resource bundle based on the action's mandatory basename attribute (messages), and stores that resource bundle in the localization context stored in the FMT_LOCALIZATION_CONTEXT configuration setting. Instead of storing the localization context in that configuration setting, <fmt:setBundle> will store it in a scoped variable if you specify the var, and optionally the scope, attribute.Whether you specify the Resource Bundles" on page 259 for more information about resource bundles and resource bundle base names. You can also specify the FMT_LOCALIZATION_CONTEXT configuration setting in a business component, such as a servlet like the one listed below:The Config Class" on page 239 for more information about the Config class.
When the servlet in the preceding code fragment starts, it sets the FMT_LOCALIZATION_CONTEXT configuration setting with the string messages, which represents a resource bundle base name. The preceding servlet uses the Config class from the javax.servlet.jsp.jstl.core package to set the FMT_LOCALIZATION_CONTEXT configuration setting. See "The Config Class" on page 239 for more information about how you use the Config class.You can also specify the FMT_LOCALIZATION_CONTEXT configuration setting with an instance of javax.servlet.jsp.jstl.LocalizationContext; for example, the preceding servlet could be modified as follows:
This section discussed the localization context lookup. The next section discusses how a localization context's resource bundle, if not explicitly specified, is determined. Resource Bundle LookupWe've covered some ground since we started discussing <fmt:message> at "Use of <fmt:message>" on page 265; here are the highlights:
<fmt:message> actions perform a localization context lookup to find a localization context they can use to localize messages. Those localization contexts are, for the most part, created by <fmt:bundle> or <fmt:setBundle>, both of which perform a resource bundle lookup, given a resource bundle base name. If you specify a string for the FMT_LOCALIZATION_CONTEXT configuration setting, <fmt:message> actions will also perform a resource bundle lookup, using that string as a resource bundle base name. We've already discussed localization context lookups in "Localization Context Lookup" on page 268, so this section focuses on the resource bundle lookup performed by <fmt:bundle>, <fmt:setBundle>, and <fmt:message>.The resource bundle lookup performed by <fmt:bundle>, <fmt:setBundle>, and <fmt:message> requires two pieces of information: a resource bundle base name and one or more locales. You specify a resource bundle base name with the <fmt:bundle> and <fmt:setBundle> mandatory bundle attributes. The next section shows you how to specify the locale. LocalesYou can specify the locale(s) that the <fmt:bundle>, <fmt:setBundle>, and <fmt:message> actions use to find a resource bundle in one of two ways:
By default, the resource bundle lookup uses your browser's preferred locales, but you can override that default with the Configuration Settings" on page 230 shows you how to do all those things. The FMT_LOCALE configuration setting is listed in Table 7.8.
The <fmt:setLocale> value attribute specifies a locale as either a language or a language-country combination, such as fr or fr-CA. The variant attribute specifies a browser- or vendor-specific value, such as WIN for Windows or MAC for Macintosh. See "Locales" on page 258 for more information about locales and variants. In practice, variants are seldom used.The scope attribute, which can be page, request, session, or application, specifies the scope to which the locale applies. For example, if you specify application scope, the locale specified with the value attribute will apply to all JSP pages in your application. The default scope is page. The Resource Bundle Lookup AlgorithmThe resource bundle lookup algorithm performed by <fmt:message>, <fmt:bundle>, and <fmt:setBundle> starts with a resource bundle base name and a list of preferred locales. If you've set the FMT_LOCALE configuration setting, then your list of preferred locales consists of the single locale. If you haven't set the FMT_LOCALE configuration setting, then your browser's list of preferred locales will be used.For each preferred locale in order of preference, JSTL searches for resource bundles in WEB-INF/classesor a subdirectory of WEB-INF/classeswith the following names:
For the preceding names, basename represents a bundle base name, and language, country, and variant are specified by a locale. As soon as a match is found, the algorithm selects that resource bundle and stops.If the set of available resource bundles changes during the execution of a page, the resulting behavior is undefined; leaving that behavior undefined allows implementations to cache resource bundles to improve performance.If no resource bundle is found for any of the preferred locales, the resource bundle lookup is applied to the fallback locale, which you can set with the FMT_FALLBACK_LOCALE configuration variable.[17] [17] None of the JSTL actions set the FMT_FALLBACK_LOCALE configuration setting, so it's most often set in the deployment descriptor with a context initialization parameter. If <fmt:bundle>, <fmt:setBundle>, or <fmt:message> cannot find a resource bundle with the preferred locales or the fallback locale, they try to find a resource bundle with only the base name.To help clarify the resource bundle search algorithm, here are some examples that illustrate how the algorithm works:Example 1:
The algorithm matches the en_GB locale with this Java class: /WEB-INF/classes/Resources_en.class.Example 2:
The algorithm does not find a match for the de or fr locales, but it does find a match for the fallback locale; therefore, the selected resource bundle is specified with this properties file: /WEB-INF/classes/Resources_en.properties.Example 3:
The algorithm does not find a match for the fr locale, because that locale specifies French, not Canadian French. The algorithm does find a match for the sv locale (Swedish), and therefore selects the resource bundle specified with the properties file /WEB-INF/classes/Resources_sv.properties.In this case, even though the user prefers French over Swedish and has a French resource bundle, that resource bundle will not be selected, because it is Canadian French. This example illustrates that resource bundles for a specific language and country should be backed up with a resource bundle covering just the language. If the country-specific differences for a language are too significant for a language-only bundle, users should specify two locales with both language and country in their list of preferred locales. An Example of Dynamically Switching LocalesThis section discusses a Web application, shown in Figure 7-4, that lets users change their locale by clicking on an image of a flag. Changing the locale initiates the resource bundle search algorithm discussed in "The Resource Bundle Lookup Algorithm" on page 276, which changes the current resource bundle. The Login button does not initiate a login; for the sake of illustration, it simply reloads the login page. Figure 7-4. Using <fmt:setLocale>Clicking on a Flag Switches Locales![]() The application shown in Unicode and Charsets" on page 260 for more information about charsets and UTF-8. The preceding JSP page uses <fmt:setBundle> to specify a bundle base name for the JSP page. The application's properties files are listed below.The Chinese properties fileapp_zh.propertiesspecifies messages with Unicode escape sequences; see "Unicode and Charsets" on page 260 for more information about Unicode.The JSP page listed in Listing 7.9 also imports flags.jsp and set_locale.jsp. The former displays the flags, and the latter sets the locale, depending on which flag was last selected.When the application is started, no flags have been selected, so the locale is determined from the javax.servlet.jsp.jstl.fmt.locale context initialization parameter, which is specified in WEB-INF/web.xml. Listing 7.13 lists an excerpt from that deployment descriptor.In the preceding listing, the FMT_LOCALE configuration variable (whose value is javax.servlet.jsp.jstl.fmt.locale) is set to de, so the application shown in Figure 7-4 is initially displayed in German.flags.jsp is listed in Listing 7.14.The preceding JSP page displays the flags shown in Figure 7-4 on page 278. When you click on one of those flags, the current page in which flags.jsp resides is reloaded with the corresponding locale request parameter.Note that the preceding JSP page uses the rather unusual HTML construct <a href=''>. That construct causes the current HTML (or JSP) page to be reloaded with XXX appended to the page's URL as a request parameter. That construct comes in handy for developing reusable HTML or JSP components, such as the JSP page listed in Listing 7.14. You can read about that construct in section 4.0 (Resolving Relative URLs) of RFC 1808; that RFC is available online at this URL: http://www.ietf.org/rfc/rfc1808.txt.The JSP page set_locale.jsp, which sets the locale according to the last flag selected, is listed in Listing 7.15.The preceding JSP page sets the locale for the user's session with <fmt:setLocale>, depending on the value of the locale request parameter. If that request parameter has not been set, the preceding JSP page does nothing. Listing 7.9 index.jsp
Listing 7.10 WEB-INF/classes/app_en.properties
Listing 7.11 WEB-INF/classes/app_de.properties
Listing 7.12 WEB-INF/classes/app_zh.properties
Listing 7.13 WEB-INF/web.xml (Excerpt)
Listing 7.14 flags.jsp
The <fmt:setLocale> action calls ServletResponse.setLocale(), which is required by the servlet specification, to set the response charset to match the specified locale. Because of that requirement, index.jsp, listed in Listing 7.9 on page 280, should not have to specify the UTF-8 charset; however, some servlet containers do not properly implement that requirement, so the contentType page directive in Listing 7.9 on page 280 is necessary to ensure that the example works with all servlet containers. Listing 7.15 set_locale.jsp
Also, notice that flags.jsp and set_locale.jsp can be used in any JSP page to switch locales. In fact, those JSP pages, modified to display different flags, are used in the Web applications discussed below and in "Validation with JSP Pages" on page 296. Compound Messages and <fmt:param>When you go to the store, you might say, "I'm going to {0}," where {0} represents the name of the store; after all, there are only so many ways to say that you're going to the store. Sometimes you might say, "I'm going to {0} to get {1}."This phenomenon, known as parameterized text, is commonplace; in fact, you can find many occurrences of "The JSP page shown in {0} is listed in {1}" scattered throughout this book.You can parameterize text by specifying <fmt:param>" on page 504 for a more complete description of <fmt:param> syntax.
You can also specify a parameter within the body of a <fmt:param> action, with this syntax:
Figure 7-5 shows a Web application that uses both <fmt:param> syntaxes. Figure 7-5. Localizing Compound Messages with <fmt:param> Actions![]() The Web application shown in Figure 7-5 provides parameters for a disk number and date. The top picture in Figure 7-5 shows the English version of the message, and the bottom picture shows the French version.The JSP page shown in Figure 7-5 is listed in Listing 7.16.Like the JSP page shown in Figure 7-4 on page 278, the preceding JSP page imports set_locale.jsp and flags.jsp so the user can switch locales and sets the bundle base name to app for page scope.The preceding JSP page uses both syntaxes of <fmt:param> to specify parameters for a message specified with the message.diskFull key. The <fmt:param> action specifies its value in its body, whereas the <fmt_rt:param> action specifies its value with the value attribute. Notice that the second param tag uses the runtime expression library version of the param action (<fmt_rt:param>) because it creates a Java object for its value, which is something you cannot do with the expression language equivalent action (<fmt:param>).[19] [19] But you can use <fmt:param> in combination with <jsp:useBean>; see "Use of <fmt:message>" on page 265. Listing 7.16 index.jsp
The English and French properties files used by the application shown in Figure 7-5 are listed below. Listing 7.17 WEB-INF/classes/app_en.properties
Listing 7.18 WEB-INF/classes/app_fr.properties
The messages in the preceding properties files identify parameters with {0} and {1}. Those parameters are supplied by the <fmt:param> and <fmt_rt:param> actions, respectively.The preceding properties files also specify styles to format the date supplied by <fmt:param>; for example, {1, time } specifies the time portion of the date, and {1, date, full } specifies the full date without the time. You can use other styles, such as {n, percent}, to specify a number as a percent. See the Java documentation for the java.text.MessageFormat class for more information about those styles.The flags.jsp and set_locale.jsp JSP pages imported by the preceding JSP page are nearly identical to the JSP pages of the same name discussed in "An Example of Dynamically Switching Locales" on page 278, except for the flags and locales they support. Those files are listed in Listing 7.19 and Listing 7.20 for completeness. Listing 7.19 flags.jsp
Listing 7.20 set_locale.jsp
![]() |