如果你正在构建一个世界级的Web站点,你是否想过只支持美语或英语?当然不!世界上众多的站点都支持多种语言,当单击对应语言的链接时,直接进入该语言版本的站点。幸运的是,Java自身的一些组件也提供了一些让站点支持国际化功能的方法。在这里,我们使用Velocity的组件来轻松构建国际化站点。在这一章里,我们只简要介绍Java组件,之后重点介绍chapter 12里CD收藏管理示例的Velocity应用程序版本。
Java国际化组件
在这一章里,我们将调试一些可用于国际化的Java组件。为了充分理解这个处理过程,请参考http://java.sun.com/docs/books/tutorial/i18n/的Java入门教程。在我们正式开始之前,让我们把注意力集中于构建一个可以使用英语和德语阅读的Web应用。
或许最简便的方法就是为这两种语言构建两张页面。假定你已经有了一个名叫index.html的原始的Web页面。对于英语版本的,对应的位置为/en/index.html下,在相同目录的德语版本为indexgerman.html,当然,也可以为他们建立不同的目录,比如:英语版为/en/index.html,德语版为/de/index.html。
当然,构建两张或20张页面来完全这两个语言版本的页面不是太难,只是浪费了一些时间而已。但如果是若干页面,同时有些页面需要进行改动该怎么办?现在有一种好方法来为这两种语言版本构建页面,那就是使用Java、Servlets以及Velocity,这是最好的解决方案。
Java本地类
Java本地(Locale)类用于包罗其他的Java类。这个本地(Locale)对象被传递给一个类,这个类知道如何处理世界上不同的地理位置。通过传递两个参数来创建一个本地对象,这两个参数是:你想使用的语言和国家。这两个参数都使用只有2个字符的缩写,比如:英语用en,德语用de。美国用US,德国用DE。
好,你现在可以用下面的代码来创建一个本地对象:
Locale location = new Locale('en', 'US');
你可以在www.ics.uci.edu/pub/ietf/http/related/iso639.txt里查询语言代码的完整列表。国家代码可以在www.chemie.fuberlin.de/diverse/doc/ISO_3166.html里查询。
资源绑定(Bundles)
对Java国际化来说,大量工作都集中在ResourceBundle对象里。这个对象扮演了一个巨大的多维地图,让你提供一个关键字字符串和一个从Locale对象返回的值给bundle。ResourceBundle对象依靠properties files(属性文件),该文件是一个文本文件,在其中定义了关键字和其关键值。在这里总是有一个名叫MessagesBundle.properties的默认属性文件。如果ResourceBundle对象不能找到其他和所提供位置匹配的属性文件,那么,这个默认的属性文件(bundle)将被使用。让我们首先来看一下,如何创建一个ResourceBundle对象。
message = ResourceBundle.getBundle("MessagesBundle", location);
The statement instantiates a ResourceBundle object based on the property filename of MessagesBundle and the provided Locale object. If you are planning to code a Web application for English/U.S. and German/Germany locations, you need two additional properties files:
语句初始化一个基于MessagesBundle的属性文件名和所提供的本地对象的ResourceBundle对象,如果你计划用English/U.S.和German/Germany编写一个Web应用,那么你需要两个附加的属性文件:
■ MessagesBundle_en_US.properties
■ MessagesBundle_de_DE.properties
ResourceBundle对象主要负责选择属性文件。正如我们曾提及的一样,每一个属性文件包含了关键字和值对。比如:为了显示一个对用户的祝贺,你将在属性文件里包含如下的实体:
Greet = Hello
当然,你需要为默认情况包含适当的实体,即U.S.和德语文件。之后,在当前Locale对象中查询ResourceBundle对象以返回关键字“Greet”的值,比如:
String hello = messages.getString("Greet");
在这个代码里,适当的祝贺词被呈现给用户。现在,让我们看一如如何使用这些知识来构建一个国际化Web站点。
一个国际化CD Web应用
在之间的章节里,我们创建了一个应用,以用于存储和找回CD,以及他们的歌曲。和你回想的一样,应用显示了一个主Web页面以用于输入CD和歌曲,同时显示其对应的信息。这个程序使用的语言是英语。现在,我们准备对这个程序进行国际化修改。
现在让我们开始为这个主页面创建一个允许用户选择语言和国家的操作,见Listing 13.1。显示结果见Figure 13.1。
<HTML>
<BODY>
<form action="http://localhost:8080/cd/cdIndex">
<select name="country">
<option value="US">US</option>
<option value="DE">DE</option>
</select>
<BR>
<select name="language">
<option value="en">us</option>
<option value="de">de</option>
</select>
<input type="submit" value="submit">
</form>
</BODY>
</HTML>
Listing 13.1 The international.html file.
Figure 13.1 The language/country select page.
在Listing 13.1里有两个重要的操作,第一在<form>标记里。当用户单击submit按钮里,他们将发送给一个名叫cdIindex的新Servlets。这个Servlets主要负责为请求的语言获取用于显示的文本。同时也要注意国家和语言选择框。这个输入窗体被传递给cdIndex servlet,以便让Servlets知道当前需要的是哪个属性文件(即需要是什么语言版本)。
从cdIndex servlet里输出的是一个用于显示输入信息和显示CD的Velocity模板。Listing 13.2显示了这个模板的代码。
<HTML>
<HEAD>
<TITLE></TITLE>
<link rel="stylesheet" type="text/css" href="default.css">
</HEAD>
<BODY BGCOLOR="#3A6BA5" link="ffffff" alink="999999" vlink="ffffff">
<table border="1" >
<tr><td>
$createstring<BR>
<form action="http://localhost:8080/cd/cdVelocityHandler"
method="post">
<table>
<tr><td>$title</td><td><input name="title"></td></tr>
<tr><td>$artist</td><td><input name="artist"></td></tr>
<tr><td>$tracks</td><td><input name="tracks"></td></tr>
</table>
<input type="submit" name="submit" value="new">
</form>
</td>
<td valign="top">
$displaystring<BR>
<form action="http://localhost:8080/cd/cdVelocityHandler" method="post">
<table>
<tr><td>$artist</td><td><input name="artist"></td></tr>
</table>
<input type="submit" name="submit" value="obtain">
</form>
</td>
</tr>
<tr>
<td valign="top">
$viewstring<BR>
<form action="http://localhost:8080/cd/cdVelocityHandler" method="post">
<table>
<tr><td>$ID</td><td><input name="id"></td></tr>
</table>
<input type="submit" name="submit" value="tracks">
</form>
</td>
<td valign="top">
$addstring<BR>
<form action="http://localhost:8080/cd/cdVelocityHandler"
method="post">
<table>
<tr><td>$ID</td><td><input name="id"></td></tr>
<tr><td>$name</td><td><input name="name"></td></tr>
<tr><td>$length</td><td><input name="length"></td></tr>
</table>
<input type="submit" name="submit" value="addtrack">
</form>
</td>
</tr>
</table>
</BODY>
</HTML>
Listing 13.2 The index.vm Velocity template.
这个显示页面被划分为四个任务。每一个任务显示一个指示和几个字段。所有在页面上的文本显示被转换到Velocity引用。这些Velocity引用被cdIndex servlet进行填充,见Listing 13.3。
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.servlet.VelocityServlet;
import org.apache.velocity.exception.*;
import javax.naming.*;
import javax.ejb.*;
import cd.*;
import org.apache.velocity.app.Velocity;
public class cdIndex extends VelocityServlet {
protected Properties loadConfiguration(ServletConfig config )
throws IOException, FileNotFoundException
{
Properties p = new Properties();
String path = config.getServletContext().getRealPath("/");
if (path == null) {
System.out.println(
" SampleServlet.loadConfiguration() : unable to "
+ "get the current webapp root. Using '/'. Please fix.");
path = "/";
}
p.setProperty( Velocity.FILE_RESOURCE_LOADER_PATH, path );
return p;
}
public Template handleRequest( HttpServletRequest req,
HttpServletResponse res, Context context ) {
Template template = null;
String country = req.getParameter("country");
String language = req.getParameter("language");
Locale currentLocale = new Locale(language, country);
ResourceBundle messages =
ResourceBundle.getBundle("MessagesBundle", currentLocale);
context.put("title", messages.getString("title"));
context.put("artist", messages.getString("artist"));
context.put("ID", messages.getString("ID"));
context.put("name", messages.getString("name"));
context.put("length", messages.getString("length"));
context.put("tracks", messages.getString("tracks"));
context.put("createstring", messages.getString("createstring"));
context.put("displaystring", messages.getString("displaystring"));
context.put("viewstring", messages.getString("viewstring"));
context.put("addstring", messages.getString("addstring"));
try {
template = getTemplate("index.vm");
} catch( Exception e ) {
e.printStackTrace();
}
return template;
}
}
Listing 13.3 cdIndex.java.
cdIndex servlet有两个任务:第一,当被用户调用时,用于从<form>获取语言和国家信息,同时利用这些信息来构建一个Locale对象。这个Locale对象被用于获取一个ResourceBundle对象。依靠语言和国家的选择,这个ResourceBundle要么选择默认的属性文件(U.S.文件,见Listings 13.4),要么选择德语(German)文件(Listings 13. 6)。这些文件都拥有相同的目录。
第二个任务对Servlets来说或许是最为重要的任务,它主要负责向上下文中填充适当的应用或他们的值。你可以在代码看到,每一个引用连同其对应的值(通过使用messages.getString(String)方法调用)一起被加入到上下文中。最后的结果是所有cdIndex Velocity模板需要引用被填充到上下文中。
当用户选择US时,显示结果见Figure 13.2。如果选择的是German,显示结果见Figure 13.3。正如你所见的一样,为你的应用增加国际化支持是一件非常轻松的事。比如,现在需要增加西班牙语支持,只需在HTML选择里包含适当的标识符,并创建适当的属性文件即可。
title = Title:
artist = Artist:
ID = ID:
name = Name:
length = Length:
tracks = Tracks:
createstring = To Create a New CD:
displaystring = To display CDs for an Artist
viewstring = To see all Tracks for a CD
addstring = To add a new track
Listing 13.4 MessagesBundle.properties.
Figure 13.2 The U.S. display page.
Figure 13.3 The German display page.
title = Title:
artist = Artist:
ID = ID:
name = Name:
length = Length:
tracks = Tracks:
createstring = To Create a New CD:
displaystring = To display CDs for an Artist
viewstring = To see all Tracks for a CD
addstring = To add a new track
Listing 13.5 MessagesBundle_en_US.properties.
title = Titel
artist = Kônstler
ID = IDENTIFIZIERUNG
name = Name
length = L?nge
tracks = Spuren
createstring = Um eine neue CD zu schaffen
displaystring = Um CDS fôr einen Kônstler darzustellen
viewstring = Um CD Spuren anzusehen
addstring = Um Spuren hinzuzufôgen
Listing 13.6 MessagesBundle_de_DE.properties.
本章小结和下章介绍
在这一章里,我们显示了如何在Velocity中联合Java的国际化特性来构建一个世界级的Web站点,让你的用户能够获得多种语言的支持。在下一章里,我们将研究在Turbine里使用Velocity,Turbine是一个应用程序框架,它提供了一个让你构建企业级应用的工具。