Technical Article

Developing Multilingual Web Applications Using JavaServer Pages Technology

Norbert Lindenberg
December 2003

JavaServer Pages (JSP) technology has become a favorite tool for developers of web applications. With JSP pages, developers can design dynamic web pages without the need for other programming knowledge. At the same time, web developers can use an extensible tag mechanism to harness the power of underlying software components.

An extension developed through the Java Community Process provides enhanced support for the development of multilingual applications. The JavaServer Pages Standard Tag Library defines, among other functionality, a set of tags that enable localization and locale-sensitive formatting.

For context, this article starts with a brief introduction to the JavaServer Pages technologies, so you can better understand how to use them to approach internationalization issues. I then discuss several core problems intrinsic to the development of multilingual web applications, and describe how to solve them using JavaServer Pages technologies: locale determination and localization, character encodings, and formatting and parsing.

The JavaServer Pages Technologies

JavaServer Pages (and several related technologies) form the presentation layer of web applications. With JSP pages, the developer can create dynamic web pages that interact with business logic, databases, and other services available on the network.

JavaServer Pages

Pages developed using JSP technology combine HTML, XML, or other static content with XML-like tags that connect to underlying software libraries, which are typically written in the Java programming language. Java technologies that are particularly important in this context are the JavaBeans components architecture (as a general-purpose interface between JSP and Java classes), the Java Database Connectivity (JDBC) APIs for access to SQL databases, and various libraries for XML processing.

JSP pages themselves are compiled to Java code in the form of servlets for execution. Servlets are web server extensions that are compiled and linked into the server, thus enabling faster execution than scripting languages. Servlets directly programmed in the Java programming language and JSP pages are often used together, with servlets acting as controllers and JSP pages as views of the application.

JavaServer Pages and the underlying servlet technology provide extensive support for handling HTTP request and response information as well as for session maintenance using cookies or URL rewriting.

An important reason for using JSP technology is that it allows the work of page authors and application developers to be separated. While it is possible to embed Java statements directly into JSP pages, developers have realized that this is best avoided and now prefer custom tags.

JavaServer Pages Standard Tag Library

The JavaServer Pages Standard Tag Library (JSTL) contains a collection of custom actions covering several areas of functionality commonly used in JSP pages. The library builds upon the experience that many of its contributors have gained from developing their own libraries, and provides a standard interface that applications can rely upon, independent of the servers they run on.

Besides the custom tags, JSTL also introduced an expression language, which further reduces the need to use scripting language expressions on JSP pages, and tag library validators to enforce constraints on the use of scripting and tag libraries on JSP pages. An enhanced version of the expression language, and the ability to suppress scripting, have subsequently been integrated into the JSP 2.0 specification, so JSTL is only required for them when using JSP 1.2.

The main areas covered by the custom actions are:

  • Variable manipulation: A few actions in the "core" library let you define variables in various scopes (page, request, session, and application), remove them, or render them into the generated page.
  • Control flow: Several actions in the "core" library provide tag-based control flow structures -- such as conditionals and iterators -- to eliminate the need for embedded scripting language code.
  • URL-related actions: A few actions in the "core" library let a JSP page import content defined by a URL, rewrite a URL from an internal form to an external form (which may include gathering information for session tracking), or redirect to a different web page.
  • XML processing: Actions in the "xml" library include parsing XML documents and extracting content using XPath expressions, control flow based on XPath expressions, and transformations using XSLT style sheets.
  • Relational database access: Actions in the "sql" library allow a web application to perform simple SQL queries and updates.
  • Internationalization and formatting (the focus of this article): The actions in the "fmt" library support locale determination, localization, character encoding determination, and locale-sensitive formatting and parsing.

Locale Determination and Localization

When designing a multilingual web application, you must first decide how to determine the user's language and locale preferences, and how to match those preferences against the set of locales that the application and the underlying Java runtime environment support. This section first describes the external environment and requirements web applications have to deal with. Next, we'll take a look at the functionality provided by the underlying Java 2 Standard Edition (J2SE) platform, and finally see how JavaServer Pages Standard Tag Library tags connect the environment and J2SE.

Determining the User's Preferences

A web application has two ways to determine the user's language preferences: First, it can use language and locale preferences that are transmitted from the browser to the server using the HTTP request header field Accept-Language. While the standard provides for a variety of language tags, normal use combines an ISO 639 language code (for example, ja for Japanese) and an ISO 3166 country code (for example, IT for Italy). Browsers usually let the user create a list of languages as part of their preferences. Unfortunately, this way is not very reliable; users may or may not create the list, and the list may or may not include a locale that the application supports. Because of these uncertainties, multilingual applications usually also employ a second way: They let the user choose directly from a list of supported languages, and store the chosen language as part of the user's profile or just for the duration of the session. A good approach is to use the Accept-Language information initially, when nothing is known about the user, but give the user an opportunity to choose a language explicitly on the application's start page.

It's worth noting that the Accept-Language locales are intended primarily for language and cultural preferences. They shouldn't, for example, be interpreted as indicating the user's country of residence. Also, in many cases browsers provide locales that only have a language code, while some locale-sensitive functionality (for example, date formatting) varies from country to country. In many cases, it may be reasonable to assume the conventions of the main country using the language (if no country is specified); for example, use a date format known in Japan if only Japanese is specified. However, if important functionality depends on the country (for example, the currency), the user needs to be given a chance to correct the assumption.

In many cases, web applications are assembled from several components, which may be localized for different language sets. One particularly interesting component is the Java runtime environment, which in some locale-sensitive areas of functionality (such as date formatting) may support over 100 locales in over 40 languages, far more than typical web applications. Thus, the developer of an application has to decide whether to restrict localized functionality to the languages supported throughout the application, or take advantage of the capabilities of each component. The first approach has the advantage that the user sees pages that use the same language throughout, while the second may result in pages that mix different languages -- one language for most of the text, but a different one for, say, formatted dates.

Localization in the Java 2 Standard Edition Platform

To understand how JSTL determines which locales are supported by an application, let's take a look at how localization is done in the underlying Java 2 Standard Edition platform. Two classes in the java.util package are at the core: Locale and ResourceBundle.

Locale objects simply identify locales: they combine an ISO 639 language code (for example, ja for Japanese), an ISO 3166 country code (for example, IT for Italy), and possibly a (non-standardized) variant string. Note that HTTP uses the same ISO standards for its locale identifiers, so comparison is usually easy.

ResourceBundle objects are containers of localizable objects, organized as key/value pairs. A base resource bundle defines a base bundle name, the set of keys, and default values (commonly the English values, but that's by no means required). For example, a simple Messages resource bundle might define the key greeting-day with the default value Hello. Additional language and country-specific bundles can be defined, whose names consist of the base name (with suffixes indicating the language and country codes and the variant), and which provide localized values. For example, a German Messages_de resource bundle could give the value Guten Tag for the key greeting-day, and an Austrian Messages_de_AT bundle could override this with the value Servus. Resource bundles can be implemented as Java classes or as simple "properties" text files.

Localization Approaches for JavaServer Pages Applications

To localize JavaServer Pages-based applications, two approaches are commonly used. The first uses internationalized pages that obtain locale-dependent content through custom tags, often from resource bundles. This approach is generally preferred if the pages have complicated structure that needs to be kept in sync between all locales. The second approach uses separate locale-specific pages, and a servlet that dispatches to the appropriate page, depending on the user's preferred locales. This approach may be preferred if the pages contain mainly text, or if the structure should differ significantly between locales.

Locale Determination and Localization in JSTL

JSTL builds on the facilities of J2SE to provide locale determination and localization. The locale determination capabilities can be used with either JSP localization approach (described earlier), while the localization functionality is intended to support internationalized pages.

JSTL supports both ways of determining the user's locale preferences that were described above. An application can specify a fixed locale (usually one that the user has explicitly selected from the list of supported languages), using JSTL's <fmt:setLocale> action. Once this action is used, the specified locale is used for all locale-sensitive operations. If the <fmt:setLocale> action has not been used, locale-sensitive operations will search for the first supported locale from the list of preferred locales provided by the Accept-Language header.

Here are a few code snippets you could use on the start page of a web application. Together, these code snippets let the user choose his or her locale in a very simple way. The code assumes that it is part of a page locale-choice.jsp:

<%-- Interpret user's locale choice --%>
<c:if test="${param['locale'] != null}">
  <fmt:setLocale value="${param['locale']}" scope="session" />
<%-- Offer locale choice to user --%>
<a href="locale-choice.jsp?locale=en-US">USA</a> -
<a href="locale-choice.jsp?locale=de-DE">Deutschland</a> -
<a href="locale-choice.jsp?locale=ja-JP">&#26085;&#26412;</a>
<%-- Use URL rewriting to ensure proper session tracking --%>
<form method="get" action="<c:url value='/locale-choice.jsp' />">
  <input type=submit value="Stay in session">

The first section (which must come before any content for the generated HTML page) interprets the user's locale choice, which reaches the JSP page as a request parameter. If the locale parameter is defined, it is used to set the locale for the session.

The second section (which is part of the content of the generated HTML page) offers the user links that return to the same page, but with the locale parameter set according to the selected country. Note that the country names are given in the local languages, so that users can easily identify them even if the rest of the page is localized to a language that the user cannot read. For example, "&#26085;&#26412;" are the numerical character references for "日本", the Japanese word for "Japan". Modern browsers will render the text correctly if a Japanese font is available; for older browsers, an image may be more appropriate.

The last section shows how to use the <c:url> tag to generate URLs that include a session ID if necessary to keep track of the session (if the user has cookies enabled, cookies are used instead of URL rewriting). This ensures that the locale selection, once made, is available to all pages of the web application.

If the locale has been chosen from a web application's own user interface, and then set using <fmt:setLocale>, it can be assumed that the application actually supports this locale. On the other hand, if <fmt:setLocale> hasn't been used and JSTL has to find a supported locale from the locale list from the Accept-Language header, things get more complicated.

To decide which locales are supported, JSTL looks at the resource bundles that the application uses. There are two actions that provide access to resource bundles: <fmt:bundle> and <fmt:setBundle>. Their basic function is the same: they look up a resource bundle and create a "localization context," which holds references to the bundle and to the locale that was used to request the bundle.

The resource bundle lookup used by the <fmt:bundle> and <fmt:setBundle> actions allows for multiple request locales (so that it can handle the list provided by the Accept-Language header), and uses a fallback locale defined by the web application. If a locale was set using the <fmt:setLocale> action, the <fmt:bundle> and <fmt:setBundle> actions request a bundle for that locale or, if unsuccessful, for the fallback locale. If <fmt:setLocale> has not been used, the actions successively request a bundle for the locales provided by the Accept-Language header and for the fallback locale, until a request succeeds. In each case, the basic lookup (for a bundle base name and one request locale) looks for a resource bundle for the request locale itself, and successively for simpler locales obtained by dropping first the variant and then the country components from the request locale. If lookup is unsuccessful for all request locales as well as the fallback locale, the base bundle is used.

Here are some examples. Let's assume an application has bundles for en, zh_CN, zh_TW, ja, and ko. The fallback locale is set to en. The <fmt:setLocale> tag is not used. The following table shows the bundles and locales of the resulting localization contexts for several request locale lists:

Requested Locales Result Bundle Result Locale

zh_SG, zh_CN



zh, ja









ja, zh_CN



Connoisseurs of the ResourceBundle class will notice that the lookup strategy used by the JSTL actions differs from that used by ResourceBundle. The strategy used by ResourceBundle accepts only one request locale, which is insufficient to handle the locale list provided by the Accept-Language header, and it falls back to the Java runtime's default locale, which is irrelevant to a web application and its users and whose use would lead to non-portable behavior.

Now, why are there two separate actions for looking up resource bundles? The difference is in the way they're used: the <fmt:bundle> tag provides a context for nested tags, while the <fmt:setBundle> action stores the resulting localization context in a variable that can be accessed by subsequent actions on the same page and, depending on the variable's scope, by actions on other pages.

One JSTL tag that takes advantage of the localization context is the <fmt:message> action. In its simplest form, it obtains a message for a given key from the resource bundle of a localization context and inserts it into the generated page. The following example shows the different ways it can be used:

<fmt:setBundle basename="Errors" var="errorBundle" />
<fmt:bundle basename="Messages">
  <%-- Localization context established by <fmt:bundle> tag --%>
  <fmt:message key="greeting" />
  <%-- Localization context established by <fmt:setBundle> tag --%>
  <fmt:message key="emptyField" bundle="${errorBundle}" />

Next, why is there a request locale associated with the localization context? This locale is JSTL's way of restricting the formatting tags to the languages that the application supports, so that the pages presented to the user use the same language throughout. Formatting actions that are nested within a <fmt:bundle> tag use that tag's localization context to determine the locale they should use. For example, let's look at the following page fragment:

<jsp:useBean id="now" class="java.util.Date" />
<fmt:formatDate value="${now}" timeStyle="long" dateStyle="long" />
<fmt:bundle basename="Messages">
  <fmt:formatDate value="${now}" timeStyle="long" dateStyle="long" />

If the HTTP Accept-Language locales are fr and en, and the underlying Java runtime supports date formatting for both languages (but the web application's Messages bundle only exists in en), the first date will be formatted in French, but the second one in English. A page designer can therefore determine whether to use uniform language or whether to take advantage of all existing localization by choosing appropriate tag nesting.

Finally, why does the localization context use the request locale and not the locale of the resource bundle found? The answer is that it avoids the loss of important information that may be needed for some formatting tags. Many applications don't make a distinction between different variants of the same language, and provide, for example, only English resource bundles, hoping that the text can be understood equally well in England, Australia, and Singapore. For date formatting, however, the country is critical -- "2/6/02" means "2 June 2002" to British readers, but "February 6, 2002" to readers used to US conventions. So, in many cases, if the request locale (rather than the resource bundle locale) is used, country information will be preserved.

Character Encoding

Two distinct models for representing text for storage in computers or for transmission over networks are in use today: the old model of character encodings that are specific to small sets of languages, countries, and/or operating systems (which includes, for example, the ISO 8859 series, Windows code pages, and EUC encodings); and the new model of Unicode-based encodings that can (at least theoretically) represent all languages and be used anywhere.

The old model has significant disadvantages:

  • Old character encodings usually only support a small set of languages each. For example, Shift-JIS supports Japanese and English, but not other Asian or European languages. ISO 8859-1 supports a number of Western European languages, but not Eastern European ones.
  • Character conversion may result in unexpected loss of information. Developers often choose ISO 8859-1 as the encoding for German, French, and other Western European languages, and then are surprised to find that the "€" character -- the symbol for the common currency of Germany, France, and numerous other European countries -- is not supported by this encoding. To avoid this loss of information, you would have to use Windows-1252, ISO 8859-15, or other encodings, depending on the browser's underlying operating system.

Current versions of the main software systems involved in creating, distributing, and interpreting web content favor the new model; they typically use Unicode for internal processing, or at least know how to work with UTF-8, the Unicode-based encoding used on the web. Unicode-based encodings have clear advantages: they allow multilingual pages and cleanly separate the issues of locale handling from character encoding. Also, there is little risk of information loss due to encoding conversion, and Unicode-based encodings fit in well with modern server and client systems.

Despite this, many web developers are still reluctant to use UTF-8. Reasons given may include support for old browser versions that don't work well with this encoding, or the lack of tool support for it.

The JavaServer Pages technologies support both models. We'll now take a look at the various areas where character encoding issues come into play, and see how JSP technology and JSTL handle them.

Handling Source Page Encodings

The encoding of JSP source files is often determined by available editing tools, so a country and operating system-specific encoding may be used. There are a number of ways to communicate the character encoding to the JSP runtime environment (the "container"), and the mechanisms and rules have evolved somewhat over time. It also becomes relevant that there are two syntaxes for JSP source files: the standard syntax and a newer XML-based syntax.

The JSP 2.0 specification distinguishes between the two syntaxes when detecting the character encoding. For files in XML syntax, the encoding is detected as described in the XML specification; this means that UTF-8 or UTF-16 are the default and any other encoding must be declared in the XML declaration at the beginning of the file. For files in standard syntax, containers look at two primary sources of information: First they look in the deployment descriptor of the application for an element page-encoding in a jsp-property-group whose URL pattern matches the file; then for an attribute pageEncoding in the page itself. If neither is present, containers also look for the charset of the contentType attribute (see the next section, "Handling Web Page Encodings"), or use ISO 8859-1 as the ultimate fallback.

Here are some simple recommendations for applications based on JSP 2.0: For files in XML syntax, make sure that files that are not encoded in UTF-8 or UTF-16 properly identify their character encodings. For files in standard syntax, if you use UTF-8 for all your source files, just use a single element page-encoding in the deployment descriptor to state this. If you use locale-specific encodings, organize or name your files according to the locale, and use page-encoding elements to describe the relationship. For example, if all Korean files are encoded in EUC-KR and are stored in the /ko/KR subdirectory of the web application, use the following:


If source files in your application can't be organized this way, add a pageEncoding attribute to each source file. Keep in mind, however, that this attribute must be found at the beginning of the file, and that it can only be used to identify character encodings that are extensions of ASCII. The latter restriction allows for UTF-8 and many old character encodings, but not for UTF-16 or EBCDIC-based encodings. Relying on the charset value of the contentType attribute to identify the source page encoding is not recommended; it should only be used to identify the web page encoding (see the next section).

The JSP 1.2 specification didn't clearly distinguish between files in standard syntax and files in XML syntax with regards to source file character encodings. It also didn't provide a way to identify character encodings in the deployment descriptor. To ensure correct character encoding detection, applications designed for JSP 1.2 containers should therefore always identify the character encoding of each source file using the pageEncoding attribute.

JSTL defines a <c:import> action which allows the inclusion of external data specified by a URL into a JSP-generated page. This action allows the specification of a character encoding, which is used if the external data doesn't specify its own encoding.

Handling Web Page Encodings

A web application has to select the character encoding to be used for generated web pages, the "response character encoding", based on the capabilities of the targeted browsers, the writing system(s) and language(s) of the page content, and possibly the browser's host operating system. According to the HTTP specification, the character encoding is specified in the charset parameter of the Content-Type entity header.

If all targeted browsers support UTF-8, it is generally best to use this encoding, so that multilingual documents are supported and information loss due to character conversion is avoided.

If UTF-8 cannot be used, the application has to be careful to match a character encoding with the language(s) being used, including special characters. To avoid mishaps, it may be necessary to enforce the use of the same language throughout the page, as discussed in the "Locale Determination and Localization" section earlier in this article. It may also be necessary to avoid the use of the "€" character.

Web applications can either specify the character encoding of a page explicitly, or let the JSP technologies determine it implicitly from locale information.

  • Explicit specification is easiest via the page's contentType attribute, which lets the application specify the character encoding along with the content type of the generated page. If an application wants to set the character encoding while processing a request, it needs to use a custom action or some Java code to call the javax.servlet.ServletResponse.setContentType method or the new (in Servlet 2.4) javax.servlet.ServletResponse.setCharacterEncoding method.
  • Implicitly, the character encoding is also determined by the JSTL formatting actions (including <fmt:message>) whenever they create a localization context, and the <fmt:bundle>, <fmt:setBundle>, and <fmt:setLocale> actions unconditionally. Through the ServletResponse.setLocale method, they map the locale of the localization context or the given locale to a character encoding and set it on the page's content type. The Servlet 2.4 specification provides a way for applications to control the mapping through a locale-encoding-mapping-list element in the deployment descriptor. If the application does not provide this element, or when you're using a container based on older Servlet specifications, the mapping from locale to character encoding depends on the container; typical implementations rely on old character encodings.

Implicit determination of the character encoding is fine, as long as old character encodings are acceptable, and the page uses the same language throughout and avoids special characters that may not be supported in commonly used character encodings. To take advantage of UTF-8, however, explicit specification is required. Since the Servlet 2.4 specification gives explicit specifications precedence over implicit specifications, setting the character encoding as part of the contentType attribute is sufficient -- later use of JSTL formatting actions will not affect the character encoding. In earlier versions of the Servlet specification, however, an explicit specification was not guaranteed to override the implicit determination from locale information. If compatibility with containers based on older specifications is desired, you must freeze the character encoding by calling ServletResponse.flushBuffer between the explicit character encoding specification and the first use of custom actions that might implicitly determine the character encoding.

Handling Request Parameter Encodings

JSP pages can not only generate web pages, they can also receive and interpret the parameters that come with an HTTP request -- typically input from a form that was part of a previously generated web page. The character encoding used for these parameters is not specified anywhere, but the de facto standard is that browsers use the same encoding as for the page containing the form.

This means that a web application needs to keep track of the encoding used for previously generated pages. One commonly used mechanism is to store the name of the encoding in a hidden field in the form itself, extract it as the first parameter from the next request, and then use it to decode the other parameters. However, JSP pages can also use session management to keep track of information between requests.

Applications can use the JSTL custom action <fmt:requestEncoding> to specify the encoding in which parameters are expected to be encoded. If the application always sends pages in UTF-8, it can simply specify this encoding as the request encoding. Otherwise, if it specifies the encoding of generated pages explicitly, it should keep track of the encoding as part of the session information, and pass it explicitly to the <fmt:requestEncoding> action. If it relies on implicit determination of character encodings, it simply uses the <fmt:requestEncoding> action without specifying a character encoding; the actions that implicitly determine the encoding for generated pages also store information in the session that <fmt:requestEncoding> can retrieve and use.

Formatting and Parsing

Presenting data such as numbers and dates in localized formats is a common task in any kind of application, as is the interpretation of input that the user has provided. The formats for different languages and cultures vary widely, so this would be a non-trivial task for developers if they couldn't rely on existing libraries.

Fortunately, such libraries do exist. The Java 2 Standard Edition platform (J2SE) provides a set of classes for formatting and parsing common data types in the java.text package, and in Sun's implementation these classes are localized for over 100 locales.

The JavaServer Pages Standard Tag Library provides custom actions that make this functionality directly available to JSP pages.

Locale Determination for Formatting and Parsing Actions

You can use the formatting and parsing actions for numbers and dates with a predefined localization context (for example, if the tags are nested inside an <fmt:bundle> tag), or without. If you use the actions with a predefined localization context, they use the locale of that localization context. Otherwise, they determine the locale to be used in a modified version of the resource bundle lookup strategy for the <fmt:bundle> and <fmt:setBundle> actions (described earlier in this article). The main difference is that instead of looking for resource bundles, the algorithm determines the supported locales by using the methods java.text.NumberFormat.getAvailableLocales (for the number formatting and parsing actions) or java.text.DateFormat.getAvailableLocales (for the date and time formatting and parsing actions).

Number Formatting and Parsing

The JSTL custom actions for number formatting and parsing, <fmt:formatNumber> and <fmt:parseNumber>, are based on the J2SE class java.text.NumberFormat and handle simple numbers as well as percent and currency values.

Of particular interest is their support for currency formatting. Traditionally, many formatting libraries assumed that the currency symbol can be derived from the locale -- for example, if the locale is China, the currency is the RMB. In a world of cross-border transactions, this doesn't make much sense. If a company is British and calculates its prices in pounds, but the web application then displays them in RMB, there are two problems: first, the RMB is worth much less than the pound; second, the RMB may be difficult to convert back to pounds. Since choice of currency is really a business decision, currency must be treated as part of the value, instead of as part of the format.

The <fmt:formatNumber> action therefore lets the application specify an ISO 4217 currency code or a currency symbol, which overrides the currency that localized number formatting uses by default. Assuming that the application is using a price bean with value and currency properties, the following page fragment could format the price:

<fmt:formatNumber type="currency" value="${price.value}"
  currencyCode="${price.currency}" />

If the JSP page specifies a currency code, the underlying NumberFormat object attempts to use a currency symbol for the given currency that's localized for the locale of the localization context being used. For example, if given the currency code USD for US dollar, it may use the symbol "$" if the locale is en_US, US$ in some other locales where that's acceptable as the currency symbol, or fall back to the currency code USD if no localized symbol is known.

Date and Time Formatting and Parsing

The JSTL custom actions for date and time formatting and parsing -- <fmt:formatDate> and <fmt:parseDate> -- are based on the J2SE class java.text.DateFormat and handle a variety of date and time representations.

One interesting issue is that the displayed date and time depend not only on a locale-specific format, but also on knowledge about a time zone. The server time zone is generally of no interest to the user, but on the other hand, there's no simple way to find out which time zone the user is in. Applications may be able to find out about the offset of the user's current time zone from GMT by using some client-side JavaScript code, or they may let the user specify the current time zone as part of a user profile. The JSTL actions don't solve this problem, but they provide two custom actions that can be used to tell the date and time formatting and parsing about the time zone: <fmt:timeZone> and <fmt:setTimeZone>. As with <fmt:bundle> and <fmt:setBundle>, the <fmt:timeZone> tag defines the time zone for nested tags, while <fmt:setTimeZone> stores the time zone in a variable for use by subsequent actions.

Message Formatting

The <fmt:message> action (mentioned earlier), can not only obtain a string from a resource bundle and insert it into the generated page, it can also perform parametric replacement and format the parameters as necessary. It is based on the java.text.MessageFormat class, so the string that the action obtains from the resource bundle can actually be a MessageFormat pattern string. The <fmt:param> action provides the necessary arguments.

For example, if the JSP page contains the following text:

<jsp:useBean id="now" class="java.util.Date" />
<fmt:bundle basename="Messages">
  <fmt:message key="greeting">
    <fmt:param value="${now}" />

and the resource bundle found is German and provides the value "Willkommen! Heute ist der {0,date,long}." for the key greeting, the page content produced on, say, June 21, 2002, would be "Willkommen! Heute ist der 21. Juni 2002."


As this article has shown, the JavaServer Pages technologies -- in particular the JavaServer Pages Standard Tag Library -- provide you with a solid foundation on which you can build multilingual applications. There are a few design choices that you should carefully consider: how to determine the user's language and locale preference, how to structure your JSP pages for localization, whether to enforce single-language pages or use existing locale support to the fullest, and which character encoding model to use. The JSP technologies enable you to implement either choice, so you can reach your worldwide audience in the most appropriate manner -- and, most importantly, in their own language.


R. Fielding et al.: Hypertext Transfer Protocol -- HTTP/1.1. RFC 2616. The Internet Society, 1999.

Dave Raggett et al. (ed.): HTML 4.01 Specification. World Wide Web Consortium, 1999.

Tim Bray et al. (ed.): Extensible Markup Language (XML) 1.0 (Second Edition). World Wide Web Consortium, 2000.

Java 2 Platform, Standard Edition, v 1.4.2 API Specification. Sun Microsystems, 2002.

Danny Coward, Yutaka Yoshida (ed.): Java Servlet Specification. Version 2.4. Sun Microsystems, 2003.

Mark Roth, Eduardo Pelegrí-Llopart (ed.): JavaServer Pages Specification. Version 2.0. Sun Microsystems, 2003.

Pierre Delisle (ed.): JavaServer Pages Standard Tag Library. Version 1.0. Sun Microsystems, 2002.

Pierre Delisle (ed.): JavaServer Pages Standard Tag Library. Version 1.1. Sun Microsystems, 2003.