• Aucun résultat trouvé

The i18n Library: Writing Multi-Lingual Applications

Dans le document Beginning JSP, JSF and Tomcat (Page 125-129)

</c:import>

By now, everything should be pretty clear to you. The only thing worth mentioning is that the default value for charEncoding is "ISO-8859-1". I prefer to use UTF-8 because it is equally supported by all operating systems. Also, UTF-8 can handle non-European languages and has become the de-facto standard on the Web. In case you are curious, UTF stands for UCS Transformation Format, where UCS means Universal Character Set.

c:redirect is equivalent to invoking javax.servlet.http.HttpServletResponse.sendRedirect and only admits the two attributes url and context. When designing a web site, you might find it useful to remember that c:redirect changes the page that the user sees, thereby affecting the setting of bookmarks, while with jsp:forward, the user remains unaware of the page change.

c:forTokens

In addition to c:forEach, the JSTL provides a form of string tokenizer, which lets you easily extract from a string the sub-strings separated by one or more delimiters.

If you have a comma as a single delimiter, you can use c:forEach, but if you have more than one delimiter, or if the only delimiter is not a comma, c:forTokens is for you.

The general syntax of c:forTokens is as follows:

<c:forTokens var="name" items="expr1" delims="expr2" varStatus="name"

begin="expr3" end="expr4" step="expr5">

...

</c:forTokens>

The i18n Library: Writing Multi-Lingual Applications

You can take one of two approaches to internationalizing a web application: you can either provide a different version of the JSP pages for each locale and select them via a servlet when processing each request, or you can save locale-specific data in separate resource bundles and access them via i18n actions. The JSTL internationalization actions support both, but I will concentrate on the second approach, where the work of switching between languages is actually done in JSP.

fmt:setLocale, fmt:setBundle, fmt:setMessage, and fmt:param

Suppose that you want to support English and Italian. The first thing you have to do is identify all the strings that are going to be different in the two languages and define two bundles, one for each language (see Listings 4-17 and 4-18).

Listing 4-17. MyBundle_en.java package myPkg.i18n;

import java.util.*;

public class MyBundle_en extends ListResourceBundle { public Object[][] getContents() {return contents;}

static final Object[][] contents = {

{"login.loginmess","Please login with ID and password"}, {"login.submit","Submit"},

{"login.choose","Choose the language"}, {"login.english","English"},

{"login.italian","Italian"}

};

}

Listing 4-18. MyBundle_it.java package myPkg.i18n;

import java.util.*;

public class MyBundle_it extends ListResourceBundle { public Object[][] getContents() {return contents;}

static final Object[][] contents = {

{"login.loginmess","Loggati con ID e parola d'ordine"}, {"login.submit","Invia"},

{"login.choose","Scegli la lingua"}, {"login.english","Inglese"},

{"login.italian","Italiano"}

};

}

As you can see, a bundle is nothing other than a Java class that extends the class

java.util.ListResourceBundle. In this example, you will only find a simple login page, but in reality, you’ll have to include all the language-specific messages of your application. I used the prefix login to show you that it’s possible to group messages within a bundle. You can compile the Java files from the command line with javac to obtain the two files MyBundle_en.class and MyBundle_it.class. Place both files inside the WEB-INF\classes\myPkg\i18n\ folder of your application’s root directory, as you would do with any other custom class.

Listing 4-19 shows the login page that supports two languages. To try it out, copy the folder named international from the software package for this chapter to webapps. Then type in your browser localhost:8080/international.

Listing 4-19. index.jsp of a Multilingual Application 01: <%@page language="java" contentType="text/html"%>

02: <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

03: <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

04: <c:set var="langExt" value="en"/>

05: <c:if test="${param.lang!=null}">

06: <c:set var="langExt" value="${param.lang}"/>

07: </c:if>

08: <fmt:setLocale value="${langExt}"/>

09: <fmt:setBundle basename="myPkg.i18n.MyBundle"

10: var="lang" scope="session"/>

11: <html><head><title>i18n</title></head><body>

12: <h1><fmt:message key="login.loginmess" bundle="${lang}"/></h1>

13: <form method="post" action="home.jsp">

14: <input name=id>

15: <input name=passwd>

16: <input type="submit"

17: value="<fmt:message key="login.submit" bundle="${lang}"/>"

18: >

19: <h2><fmt:message key="login.choose" bundle="${lang}"/></h2>

20: <a href="index.jsp?lang=en">

21: <fmt:message key="login.english" bundle="${lang}"/>

22: </a>

23: &nbsp;

24: <a href="index.jsp?lang=it">

25: <fmt:message key="login.italian" bundle="${lang}"/>

26: </a>

27: </body></html>

Lines 4-7 ensure that the page variable langExt is not null by setting it to en when the page is requested the first time. Line 8 sets the locale to the requested language code. The list of valid language codes is defined in the International Organization for Standardization (ISO) 639 standard. They’re in lowercase (e.g., it for Italian), so you can’t confuse them with the country codes defined in the ISO 3166 standard, which are in uppercase (e.g., IT for Italy).

In line 9, you set the bundle. Notice that it looks like the fully qualified class name of the two bundle classes but without the trailing underscore and language code. This is exactly how it should be done.

Otherwise, the JSTL won’t find your messages. After executing fmt:setBundle, the session variable lang points to the bundle in the correct language, thanks to the locale and the basename attribute.

After that, an element like the following one will insert in the appropriate language the message identified by the value of the key attribute:

<fmt:message key="keyName" bundle="${lang}"/>

Notice how the double quotes are nested in line 17 without causing any problem. This is because the actions are processed first. By the time Tomcat arrives to process the HTML, only the outer double quotes remain.

Figure 4-4 shows what the page looks like the first time you view it.

Figure 4-4. The first time you view index.jsp

Figure 4-5 shows how the page looks when you choose Italian by clicking on the corresponding bottom link.

Figure 4-5. The Italian version of index.jsp

If Tomcat cannot find a bundle, it will display the key name preceded and followed by three question marks, as shown in Figure 4-6. This indicates that you must have made a mistake in the directory names.

Figure 4-6. index.jsp cannot find the messages.

Besides value, fmt:setLocale admits two additional attributes. The first one, scope, defines the scope of the locale. In the example, the default (i.e., page) is used, but scope lets you, for example, save the locale as a session attribute. The remaining attribute, variant, lets you specify non-standardized locales.

fmt:setMessage also supports a var/scope pair of attributes to let you store the generated string into a scoped variable. You can also place the sub-action fmt:param inside the body of fmt:message and set its attribute value to a string that you want to append to the message.

fmt:bundle, fmt:setTimeZone, and fmt:timeZone

Similar to fmt:SetBundle is fmt:bundle, but while you choose the basename the same way you do with fmt:setBundle, you cannot store your choice in a scoped variable. Instead, the basename you choose

applies to all elements inside the body of fmt:bundle. Additionally, fmt:bundle also supports the attribute prefix, which extends the basename. For example, if you replace lines 9-10 in Listing 4-19 with

<fmt:bundle basename="myPkg.i18n.MyBundle" prefix="login.">

and insert </fmt:bundle> immediately above the last line, you then replace the existing line 21:

<fmt:message key="login.english" bundle="${lang}"/>

with:

<fmt:message key="english"/>

fmt:setTimeZone sets the current time zone to what specified in the attribute value, like in

<fmt:setTimeZone value="America/Los_Angeles"/>

but it can also store a time zone into a scoped variable specified by the var/scope attribute pair.

When you define a time zone with fmt:timeZone, on the other hand, it only applies to the elements that appear in the body of the action.

Dans le document Beginning JSP, JSF and Tomcat (Page 125-129)