Norbert Lindenberg English: Developing Multilingual Web Applications Using JavaServer Pages Technology JavaServer Pages (JSP) 技術現(xiàn)已成為深受 Web 應用程序開發(fā)者歡迎的工具。 使用 JSP 技術,開發(fā)者不需要其他的編程知識就可以設計出動態(tài)的 web 網(wǎng)頁。 同時,Web 開發(fā)者可以使用一種可擴展的標記機制來管理基礎軟件組件的功能。 通過 Java 標準制定組織(Java Community Process)開發(fā)的一個擴展功能可為多語言應用程序的開發(fā)提供更有力的支持。 JavaServer Pages 標準標記庫除了其他一些功能,還定義了一套可實現(xiàn)本地化和地區(qū)敏感(locale-sensitive)格式化的標記。 行文方面,本文首先對 JavaServer Pages 技術進行了簡要介紹,以使您能夠更好地理解如何使用它們解決國際化的問題。 然后,我會針對多語言 web 應用程序的開發(fā)討論幾個核心問題,并介紹如何使用 JavaServer Pages 技術解決它們:這些問題包括地區(qū)確定和本地化、字符編碼、格式化以及解析。 JavaServer Pages 技術JavaServer Pages(和幾種相關技術)構成了 web 應用程序的表示層。 使用 JSP 技術,開發(fā)者可以創(chuàng)建動態(tài)的 web 頁面,這些頁面可以與商業(yè)邏輯(business logic)、數(shù)據(jù)庫以及其他可從網(wǎng)絡上獲取的服務形成互動關系。 JavaServer Pages使用 JSP 技術開發(fā)的網(wǎng)頁結合了 HTML、XML 或其他含有類似 XML 標記(這些標記與基礎軟件庫連接)的靜態(tài)內(nèi)容,通常這些軟件庫使用 Java 編程語言編寫。 在這種環(huán)境中,非常重要的 Java 技術有 JavaBeans 組件架構(作為 JSP 和 Java 類之間的常規(guī)用途接口)、用于訪問 SQL 數(shù)據(jù)庫的 Java 數(shù)據(jù)庫連接(JDBC)API 以及各種用于 XML 處理的庫。 JSP 頁面本身按照 servlet 格式被編譯為 Java 代碼,以便執(zhí)行。 Servlet 是 web 服務器的擴展,它被編譯并關聯(lián)至服務器,從而可以獲得比腳本語言更快的執(zhí)行速度。 Servlet 直接以 Java 編程語言編寫,并經(jīng)常與 JSP 網(wǎng)頁一起使用,其中 servlet 作為控制部分而 JSP 頁面作為應用程序的視圖部分。 JavaServer Pages 和底層的 servlet 技術為處理 HTTP 請求和回應信息,以及使用 Cookies 或 URL 重寫進行會話維護都提供了廣泛的支持。 使用 JSP 技術的一個很重要的原因在于它可以將網(wǎng)頁作者和應用程序開發(fā)者的工作進行分離。 盡管可以將 Java 語句直接嵌入 JSP 網(wǎng)頁,但是,開發(fā)者們已經(jīng)認識到最好避免如此,而現(xiàn)在更傾向于使用自定義標記。 JavaServer Pages 標準標記庫JavaServer Pages 標準標記庫(JSTL)包含了一系列涵蓋數(shù)個功能領域的自定義操作,這些功能在 JSP 網(wǎng)頁中經(jīng)常被使用。 該庫建立在許多參與者開發(fā)自己的庫時所獲得的經(jīng)驗基礎之上,它提供了一種應用程序可以依靠的標準接口,并且可以獨立于他們運行的服務器之外。 除了自定義標記,JSTL 還引入了一種表達語言,這種語言運進一步地減少了在 JSP 網(wǎng)頁中使用腳本語言的需求,同時還引進了標記庫驗證程序以限制在 JSP 網(wǎng)頁上對腳本和標記庫的使用。 這種改進版本的表達語言,以及限制腳本的功能已在隨后被集成到 JSP 2.0 規(guī)范之中,所以只有使用 JSP 1.2 時才要求 JSTL。 自定義操作包括的主要內(nèi)容是:
地區(qū)確定和本地化設計多語言 web 應用程序時,您必須首先決定如何確定用戶的語言和地區(qū)首選項,以及如何使這些首選項與該應用程序和基礎的 Java 運行環(huán)境支持的一套地區(qū)設置相匹配。 這部分首先描述了 web 應用程序必須具有的外部環(huán)境和要求。 下一步,我們將了解相關的 Java 2 Standard Edition (J2SE) 平臺提供的功能,最后我們將了解 JavaServer Pages 標準標記庫的標記如何連接到環(huán)境和 J2SE 中。 確定用戶首選項web 應用程序有兩種方法來確定用戶的語言首選項:首先,它可以由瀏覽器使用 HTTP 請求報頭字段 將 在許多情況下,web 應用程序是由若干組件組合而來的,這些組件可能已經(jīng)本地化為不同的語言。 一個特別值得一提的組件是 Java 運行環(huán)境,它在一些地區(qū)敏感區(qū)域可能具備支持超過 40 種語言中的 100 種區(qū)域設置的功能(例如日期格式),遠遠超出了典型的 web 應用程序。 因此,應用程序開發(fā)者必須決定是否在整個應用程序中限制所支持語言的本地化功能,或者充分發(fā)揮每個組件的功能優(yōu)勢。 第一種方法的優(yōu)勢在于用戶可以看到的全部頁面都使用同一語言,而第二種方法可能導致頁面中存在不同的語言——其中一種語言出現(xiàn)在絕大多數(shù)文本中,而另一種則出現(xiàn)在例如日期的格式中。 Java 2 Standard Edition Platform 中的本地化為了了解 JSTL 如何確定應用程序被哪些地區(qū)設置支持,我們來看看在基礎的 Java 2 Standard Edition 平臺中是如何進行本地化的。
JavaServer Pages 應用程序的本地化方法要對基于 JavaServer Pages 技術的應用程序進行本地化,方法通常有兩個。 第一個方法是使用國際化的頁面,這些頁面??梢酝ㄟ^自定義標記從資源束獲得與特定地區(qū)設置相關的內(nèi)容。 如果頁面需要保持復雜的結構并與所有地區(qū)設置同步,則通常會采取這種方法。 第二種方法使用單獨的特定地區(qū)設置頁面以及分發(fā)到適當頁面的 servlet(取決于用戶的地區(qū)選擇)。 如果頁面包含的主要是文本或者地區(qū)設置間的結構截然不同時,則通常會采取這種方法。 地區(qū)確定和 JSTL 中的本地化JSTL 構建于 J2SE 工具之上,它可進行地區(qū)確定和本地化。 使用任何一種 JSP 本地化方法(如上所述)均可以進行地區(qū)確定,而本地化功能的目的是為國際化的頁面提供支持。 JSTL 對上述兩種確定用戶地區(qū)首選項的方法都提供支持。 應用程序可以使用 JSTL 的 下面是一些您可以用于 web 應用程序開始頁面的代碼片斷。 這些代碼片斷可讓用戶非常輕松地選擇他或她的地區(qū)設置。 假設這些代碼是 <%-- Interpret user‘s locale choice --%> <c:if test="${param[‘locale‘] != null}"> <fmt:setLocale value="${param[‘locale‘]}" scope="session" /> </c:if> <%-- 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">日本</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"> </form> 第一部份(此部分必須在生成的 HTML 頁面任何內(nèi)容之前)表示用戶的地區(qū)選擇,該選擇作為一個請求參數(shù)顯示在 JSP 頁面上。 如果定義了 第二部分(此部分是生成的 HTML 頁面內(nèi)容的一部分)為用戶提供了返回同一頁面的鏈接,但是根據(jù)選定的國家提供了 最后一部分顯示如何使用 如果從 web 應用程序本身的用戶界面中選擇了地區(qū)設置,然后使用 要決定哪個地區(qū)設置是被支持的,JSTL 將參考該應用程序所使用的資源束。 有兩種操作可用于訪問資源束:
以下是一些例子。 讓我們假設某個應用程序擁有用于
那么,為什么查詢資源束時存在兩種不同的操作呢? 它們的區(qū)別在于它們使用的方法:
<fmt:setBundle basename="Errors" var="errorBundle" /> <fmt:bundle basename="Messages"> <%-- Localization context established by <fmt:bundle> tag --%> <fmt:message key="greeting" /> <p> <%-- Localization context established by <fmt:setBundle> tag --%> <fmt:message key="emptyField" bundle="${errorBundle}" /> </fmt:bundle> 其次,為什么有一個請求地區(qū)設置與本地化環(huán)境相關聯(lián)? 這個地區(qū)設置是 JSTL 將格式化標記限制到應用程序所支持的語言范圍內(nèi)的方法,這樣展現(xiàn)在讀者面前的頁面語言將完全統(tǒng)一。 嵌套于 <jsp:useBean id="now" class="java.util.Date" /> <fmt:formatDate value="${now}" timeStyle="long" dateStyle="long" /> <p> <fmt:bundle basename="Messages"> <fmt:formatDate value="${now}" timeStyle="long" dateStyle="long" /> </fmt:bundle> 如果 HTTP 最后,為什么本地化環(huán)境使用請求地區(qū)設置而不使用由資源束找到的地區(qū)設置? 答案是,這樣可以避免丟失重要的信息,某些格式標記可能需要這些信息。 很多應用程序不能區(qū)分相同語言中不同變量之間的區(qū)別,而且只提供(例如)英文資源束,期望著這些文本在英國、澳大利亞和新加坡都能被同樣理解。 然而對于日期格式,國家是很關鍵的——對于英國讀者來說,“2/6/02”表示“ 2002 年 6 月 2 日”,但對于習慣美國規(guī)范的讀者來說,則表示“2002 年 2 月 6 日”。 所以,在很多情況下,如果使用了請求地區(qū)設置(而不是資源束地區(qū)設置),則國家信息將會被保留。 字符編碼當前,我們使用兩種截然不同的模塊表示存儲在計算機中或通過網(wǎng)絡傳輸?shù)奈谋荆号f的字符編碼模式專門用于較小的語言集合、國家和/或操作系統(tǒng)(包括如 ISO 8859 系列、 Windows 代碼頁和 EUC 編碼);而新的基于 Unicode 編碼的模式能夠(至少理論上能夠)表示所有的語言并可以在任何地方使用。 舊的模塊具有很大的劣勢:
當前版本的主要軟件系統(tǒng)所包含的創(chuàng)建、分發(fā)和解釋 web 內(nèi)容都支持新的模塊;它們通常將 Unicode 用于內(nèi)部處理,或者至少知道怎么使用(用于 web、基于 Unicode 編碼的)UTF-8。 基于 Unicode 的編碼有著以下顯著的優(yōu)勢:它們支持多語言頁面并清晰區(qū)分地區(qū)設置(從字符編碼處理)問題。 同樣,因為編碼轉換而帶來的信息丟失的風險也很小,同時基于 Unicode 的編碼與現(xiàn)在的服務器和客戶端系統(tǒng)比較吻合。 盡管如此,很多 web 開發(fā)者仍然不太愿意使用 UTF-8。其中的原因可能包括對舊版本的瀏覽器支持不充分,或者缺少支持它的工具。 JavaServer Pages 技術對新舊兩種模塊都支持。 現(xiàn)在我們來看看字符編碼問題所涉及的各種不同領域,并了解 JSP 技術和 JSTL 如何處理它們。 處理源程序頁編碼JSP 源文件的編碼通常由可用的編輯工具決定,所以可能使用特定國家和操作系統(tǒng)的編碼。 字符編碼與 JSP 運行環(huán)境(“容器”)之間的通訊方法有許多種,隨著時間推移其中的機制和規(guī)則已不斷改進。 同時 JSP 源文件相應存在著兩種語法:標準語法和基于 XML 的新語法。 在檢測字符編碼時,JSP 2.0 規(guī)范將在這兩種語法中進行辨別。 對于采用 XML 語法的文件,編碼將被檢測為采用 XML 規(guī)范;這意味著 UTF-8 或 UTF-16 為默認的編碼,而其他的編碼必須在文件開始處的 XML 聲明中予以說明。 對于采用標準語法的文件,容器將考慮兩種主要的信息來源:首先它們訪問應用程序的配置描述符,查詢一個 以下是基于 JSP 2.0 的應用程序的一些簡單建議:對于采用 XML 語法的文件,確保沒有使用 UTF-8 或 UTF-16 編碼的文件能夠正確識別它們的字符編碼。 對于采用標準語法的文件,如果您對所有源文件使用 UTF-8,則請在配置描述符中只使用一個元素 <jsp-property-group> <url-pattern>/ko/KR/*</url-pattern> <page-encoding>EUC-KR</page-encoding> </jsp-property-group> 如果應用程序中的源文件不能以這種方式組織,則為每個源文件添加 關于源文件字符編碼,JSP 1.2 規(guī)范沒有清楚地區(qū)分使用標準語法的文件和使用 XML 語法的文件。 它也沒有提供識別配置描述符中的字符編碼的方法。 為確保正確檢測字符編碼,設計用于 JSP 1.2 容器的應用程序應總是識別每個使用 JSTL 定義了一個 處理 Web 頁面編碼web 應用程序必須選擇生成的 web 頁中使用的字符編碼(該編碼被稱為“反應字符編碼”),它基于目標瀏覽器的性能、頁面內(nèi)容的編寫系統(tǒng)和語言以及可能的瀏覽器主機的操作系統(tǒng)。 根據(jù) HTTP 規(guī)范,字符編碼在 如果所有目標瀏覽器都支持 UTF-8,一般來說最好使用這種編碼,這樣就可以支持多語言文檔并避免字符轉換帶來的信息丟失。 如果不能使用 UTF-8 ,必須小心謹慎地使用應用程序將字符編碼與使用的語言相匹配,包括一些特殊字符。 為防止出現(xiàn)錯誤,可能需要在整個頁面里使用同一種語言,如本文開始部分“地區(qū)確定和本地化”中所述。 同樣,也有必要避免使用“€”字符。 Web 應用程序可以直接指定一個頁面的字符編碼,也可以讓 JSP 技術根據(jù)地區(qū)設置信息間接決定。
間接決定字符編碼是可行的,只要舊的字符編碼可以被接受,并且整個頁面使用相同的語言而且避免出現(xiàn)常用字符編碼所不支持的特殊字符。 然而,若要利用 UTF-8 則要求使用顯式規(guī)范。 因為 Servlet 2.4 規(guī)范使顯式規(guī)范優(yōu)先于隱式規(guī)范,所以將字符編碼設置為 處理請求參數(shù)編碼JSP 技術不僅能夠生成 web 頁面,而且還可以接收和解釋與 HTTP 請求一起收到的參數(shù)——通常是來自某種表格的輸入,這種表格屬于前面生成的 web 頁面的一部分。 用于這些參數(shù)的字符編碼并非在任何地方都被指定,但實際標準是瀏覽器使用的編碼要與包含這些表格的網(wǎng)頁使用的編碼相同。 這意味著 web 應用程序需要跟蹤先前生成的網(wǎng)頁的編碼。 一個常用的機制是把編碼的名稱存儲到表格本身的一個隱藏域中,在下一個請求時解壓縮為第一個參數(shù),然后用它來解碼出其他的參數(shù)。 然而,JSP 頁面還可以使用會話管理來跟蹤請求之間的信息。 應用程序可以使用 JSTL 自定義操作 格式化和解析以本地化的格式表示數(shù)據(jù)(如數(shù)字和日期)是任何類型地應用程序都要完成的常見任務,就如同用戶提供的輸入解釋。 不同語言和文化所使用的格式區(qū)別很大,所以如果開發(fā)者不依靠現(xiàn)有的庫的話,那么這個工作就不會是一項簡單的任務。 幸運的是,確實存在這樣的庫。 Java 2 Standard Edition (J2SE) 平臺提供了在 JavaServer Pages 標準標記庫提供了自定義操作,可將這些功能直接應用到 JSP 頁面中。 用于格式化和解析操作的地區(qū)確定您可以在預定義的本地化環(huán)境中對數(shù)字和日期使用格式化和解析的操作(例如,如果標記嵌套于一個 數(shù)字格式化和解析JSTL 用于數(shù)字格式化和解析的自定義操作 特別值得一提的是它們對貨幣格式化的支持。 傳統(tǒng)上,許多格式化庫假設貨幣符號可以從地區(qū)設置中得出——例如,如果地區(qū)設置是中國,那么貨幣符號就是人民幣(RMB)。 在一個跨境交易的環(huán)境中,這并沒有多大的意義。 如果某個英國公司以英鎊來計算價格,而 web 應用程序將價格顯示為人民幣(RMB)的形式,就會出現(xiàn)兩個問題:第一,人民幣的匯率比英鎊低;其次,人民幣換回英鎊會比較困難。 由于貨幣的選擇屬于商業(yè)上的決定,所以貨幣必須作為值的一部分而不是格式的一部分。 因此, <fmt:formatNumber type="currency" value="${price.value}" currencyCode="${price.currency}" /> 如果 JSP 頁面指定了一個貨幣代碼,則底層的 日期和時間的格式化和解析用于日期和時間的格式化和解析的 JSTL 自定義操作 令人感興趣的一點是顯示的日期和時間不僅僅取決于一種指定地區(qū)設置的格式,還取決于時區(qū)信息。 用戶通常對服務器時區(qū)不感興趣,但另一方面,要找出用戶所在地的時區(qū)卻并不簡單。應用程序可以通過使用一些客戶端的 JavaScript 代碼來找出用戶的當前時區(qū)與格林尼治標準時間的偏差,或讓用戶指定當前時區(qū)并將其作為用戶信息的一部分。 JSTL 操作并沒有解決這個問題,但它們提供了兩個自定義操作,可以用來告知有關時區(qū)的日期和時間的格式化和解析: 信息格式化
例如,如果 JSP 頁面包含了以下語句: <jsp:useBean id="now" class="java.util.Date" /> <fmt:bundle basename="Messages"> <fmt:message key="greeting"> <fmt:param value="${now}" /> </fmt:message> </fmt:bundle> 并且找到的資源束是德語,而且 為 結論如本文所述,JavaServer Pages 技術(特別是 JavaServer Pages 標準標記庫)為您提供了一個開發(fā)多語言應用程序的堅實基礎。 您需要仔細考慮以下幾個設計選擇:如何確定用戶的語言和地區(qū)設置首選項,如何構造您用于本地化的 JSP 頁面,是否采用單一語言的頁面或充分利用現(xiàn)有的地區(qū)設置支持,以及使用哪一種字符編碼模塊。 JSP 技術使您能夠選擇其中任意一種,這樣您就可以將頁面以最佳的方式展示給全世界的讀者,而且最重要的是,以他們自己的語言來展示。 參考書目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 (ed.): Java Servlet Specification. Version 2.3.Sun Microsystems, 2001. Danny Coward, Yutaka Yoshida (ed.): Java Servlet Specification. Version 2.4.Sun Microsystems, 2003. Eduardo Pelegrlopart (ed.): JavaServer Pages Specification. Version 1.2.Sun Microsystems, 2001. Mark Roth, Eduardo Pelegr lopart (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. 關于作者Norbert Lindenberg 是 Sun Microsystems 的 Java Web Services 團隊內(nèi) Java Internationalization 技術主管。在加盟 Sun 之前,曾經(jīng)供職于 General Magic 和 Apple Computer,參與過多個國際化項目。他畢業(yè)于德國的卡爾斯魯厄大學,擁有計算機科學理科碩士學位。 |