Before we begin, you should understand two basic concepts: locales and resource bundles. A locale is an identifier for a language and, optionally , a country; for example, the locale en specifies the English language, and the locale en-US specifies United States English. Resource bundles store locale-sensitive information in key/value pairs; for example, you might find the key/value pair greeting=hello in an English resource bundle, and the corresponding greeting=bonjour in a French resource bundle. Resource bundles are defined by properties files or Java classes. Resource bundles are named with a base name and a locale; for example, you could define a resource in a properties file named errorMessages_en.properties . In that case, the resource bundle base name is errorMessages and the locale is en , for English. A corresponding properties file representing the French version (locale fr ) of that resource bundle would be named errorMessages_fr.properties . You typically internationalize Web applications in one of two ways:
The first option listed above is labor intensive ”you must duplicate every JSP page for each locale that you support. Because of the labor- intensive nature of that option, it is usually only viable when different locales require programmatic differences, such as different page layouts. Most of the time, the second option listed above is preferred because it's easier to implement and maintain. Instead of multiple JSP pages for each supported locale, you implement a single JSP page that extracts locale-sensitive information from resource bundles. For the most part, JSTL supports only the second option listed above, although you can use JSTL formatting tags to produce localized output for locale-specific JSP pages. Because JSTL actions are mainly intended for the second option listed above, this book discusses only that option. Localizing MessagesLet's start our examination of the JSTL internationalization actions with a very simple internationalized Web application, shown in Figure 7-1. Figure 7-1. A Simple Internationalized Web Application. The left picture shows the English version; the right picture shows the French version.
The Web application shown in Figure 7-1 consists of one JSP page and two resource bundles, one for English and another for French; that JSP page is listed in Listing 7.1. The preceding JSP page uses <fmt:message> actions to display localized messages from a resource bundle. That resource bundle is defined by a locale and a resource bundle base name, which are specified with the <fmt:setLocale> and <fmt:setBundle> actions, respectively. Using <fmt:message> is easy: you specify a key, and the action displays the key's value, which it extracts from a resource bundle; for example, in the preceding JSP page, the first <fmt:message> action prints the value ”Widgets, Inc. ”for the key company.name . That key/value pair is defined in the properties file listed in Listing 7.2. Listing 7.1 A JSP Page That Displays Localized Messages<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Specify a locale and a resource bundle base name for the <fmt:message> actions in this page --%> <fmt:setLocale value='en'/> <fmt:setBundle basename='messages'/> <%-- Use <fmt:message> to display the page title --%> <title> <fmt:message key='page.title'/> </title> </head> <body> <%-- Use <fmt:message> to display localized messages from the messages resource bundle --%> <font size='5'> <fmt:message key='company.name'/> </font> <p> <fmt:message key='company.slogan'/> <hr> </body> </html> Listing 7.2 WEB-INF/classes/messages_en.properties# English properties file page.title=Localizing Messages company.name=Widgets, Inc. company.slogan=We Make the World's Best Widget All <fmt:message> actions extract localized messages from a resource bundle. That resource bundle's name is the concatenation of a resource bundle base name with a locale, separated by an underscore ; in this case, the appropriate resource bundle is messages_en.properties . [2]
Switching locales is easy for the JSP page listed in Listing 7.1-you just change the value specified for the <fmt:setLocale> action; for example, to switch the JSP page shown in Figure 7-1 to French, you specify the locale as fr , like this: ... <html> <head> ... <fmt:setLocale value=' fr '/> ... </head> ... </html> Of course, you must have a corresponding French resource bundle; the properties file representing that resource bundle ” messages_fr.properties ”is listed in Listing 7.3. Listing 7.3 WEB-INF/classes/messages_fr.properties# French properties file page.title=Localiser les Messages company.name=Widgets, Inc. company.slogan=Nous Faisons le Meilleur Widget du Monde As you can tell from the Listing 7.2 and Listing 7.3 titles, the properties files for the Web application shown in Figure 7-1 reside in the WEB-INF/classes directory. That directory is where JSP containers look for Web application components, such as servlets, JavaBeans components (beans), custom JSP tags, and properties files. For complex Web applications, that directory can get cluttered in a hurry, so developers often put Web application components in WEB-INF/classes subdirectories that are typically qualified by company names ; for example, if you worked for Acme Inc., you might put your properties files in a WEB-INF/classes/com/acme directory. If you put your properties files in a WEB-INF/classes subdirectory, the resource bundle base name that you specify with <fmt:setBundle> must reflect that subdirectory; for example, the JSP page listed in Listing 7.4 is identical to the JSP page listed in Listing 7.1, except that the former specifies a resource bundle that corresponds to a properties file in a WEB-INF/classes/com/acme subdirectory. Notice that the resource bundle base name specified in Listing 7.4 is com.acme.messages . That resource bundle base name tells the servlet container that your messages resource bundle corresponds to a properties file (or a Java class file) in the WEB-INF/classes/com/acme directory. Whenever you place properties files in a subdirectory of WEB-INF/classes , you must specify your resource bundle base name in the same manner; for example, if you have a myMessages_en.properties file in a WEB-INF/classes/com/myCompany/resources directory, you must specify your resource bundle base name like this: com.myCompany.resources.myMessages . Listing 7.4 Accessing Properties Files in a WEB-INF/classes Subdirectory <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Specify a locale and a resource bundle base name for the <fmt:message> actions in this page --%> <fmt:setLocale value='en'/> <fmt:setBundle basename=' com.acme.messages '/> <%-- Use <fmt:message> to display the page title --%> <title> <fmt:message key='page.title'/> </title> </head> <body> <%-- Use <fmt:message> to display localized messages from the com.acme.messages resource bundle --%> <font size='5'> <fmt:message key='company.name'/> </font> <p><fmt:message key='company.slogan'/> <hr> </body> </html> Multiple Resource BundlesThe preceding example illustrates the fundamentals of JSTL I18N actions. Those actions are very flexible, and they let you localize messages in a number of different ways. For example, the JSP page shown in Figure 7-2 uses two resource bundles. Figure 7-2. Using Multiple Resource Bundles
The JSP page shown in Figure 7-2 is identical to the application shown in Figure 7-1, except that it also accesses a localized error message from a second resource bundle. The JSP page shown in Figure 7-2 is listed in Listing 7.5. The <fmt:bundle> action establishes a resource bundle that's only used by <fmt:message> actions in its body. In the preceding JSP page, the <fmt:bundle> action specifies an errors resource bundle base name. The corresponding properties file, WEB-INF/classes/errors_en.properties , represents the English resource bundle. The properties file has only one key/value pair that is listed below. error.cantFindResource=Resource Not Found The corresponding entry in the French properties file ” WEB-INF/classes/errors_fr.properties ”is listed below. error.cantFindResource=Ne pas Trouvez le Resource Compound MessagesYou can also use <fmt:message> with compound messages. A compound message is a message that contains one or more parameters; for example, the application shown in Figure 7-3 specifies the name of a resource with a parameter. Figure 7-3. Compound Messages
The JSP page shown in Figure 7-3 is listed in Listing 7.6. In the preceding JSP page, both the <fmt:bundle> and <fmt:message> actions have a body. As in Listing 7.5, the bundle base name specified for <fmt:bundle> applies only to <fmt:message> actions in the body of the <fmt:bundle> action. The body of the <fmt:message> action contains a <fmt:param> action that specifies a parameter for the message. Compound messages specify parameters in curly braces; for example, the English message for the preceding code fragment looks like this: Listing 7.5 A JSP Page That Uses Multiple Resource Bundles<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Specify a locale and a resource bundle base name for the <fmt:message> actions in this page --%> <fmt:setLocale value='en'/> <fmt:setBundle basename='messages'/> <%-- Use <fmt:message> to display the page title --%> <title><fmt:message key='page.title'/></title> </head> <body> <%-- Use <fmt:message> to display localized messages from the messages resource bundle --%> <font size='5'><fmt:message key='company.name'/></font> <p><fmt:message key='company.slogan'/></p> <hr> <fmt:bundle basename='errors'> <%-- <fmt:message> actions in the body of the enclosing <fmt:bundle> action display localized messages from the errors resource bundle --%> <b><fmt:message key='error.cantFindResource'/></b> </fmt:bundle> </body> </html> Listing 7.6 A JSP Page That Uses Compound Messages<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <%@ taglib uri='http://java.sun.com/jstl/core' prefix='c'%> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Specify a locale and a resource bundle base name for the <fmt:message> actions in this page --%> <fmt:setLocale value='fr'/> <fmt:setBundle basename='messages'/> <%-- Use <fmt:message> to display the page title --%> <title><fmt:message key='page.title'/></title> </head> <body> <%-- Use <fmt:message> to display localized messages from the messages resource bundle --%> <font size='5'><fmt:message key='company.name'/></font> <p><fmt:message key='company.slogan'/></p> <hr> <%-- Normally, the scoped variable specified below would come from a data store or would be calculated. Here we create it with <c:set> for illustration. --%> <c:set var='resourceName' value='Zenix'/> <fmt:bundle basename='errors'> <%-- <fmt:message> actions in the body of the enclosing <fmt:bundle> action display localized messages from the errors resource bundle --%> <b> <fmt:message key='error.cantFindResource'> <fmt:param value='${resourceName}'/> </fmt:message> </b> </fmt:bundle> </body> </html> Resource {0} Not Found And the French version is: Ne pas Trouvez le Resource {0} The parameter specified for the <fmt:param> action is substituted for {0} in the compound message. Messages can have any number of parameters, specified with {0} through {n-1} , where n represents the number of parameters. For every parameter specified in a message, you should specify a corresponding <fmt:param> action in the body of the <fmt:message> action. JSTL I18N actions have other features that we examine throughout the rest of this chapter; but first we need to discuss the basics of internationalization and localization. If you are already familiar with locales, resource bundles, Unicode, and charsets, you can skip the next section and start reading "An Overview of the I18N Actions" on page 264. |