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