原文引自:
http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.htmlJSP 標準標記庫(JSP Standard Tag Library,JSTL)fmt 庫通過一組頗受關注的定制標記提供了用于訪問所有 Java 編程語言國際化功能的便利方式。Mark Kolb 研究了用于對數據進行格式化和國際化的 fmt 標記。
在本系列的前幾篇文章中,我們討論了 JSTL 及其表達式語言(EL)。我們還研究了由 core
庫定義的定制標記。具體而言,在“ JSTL 入門:表達式語言”中我們指出 EL 提供了一種簡化語言,用于在 JSP 應用程序中訪問和操作數據并使該數據可被 JSTL 定制標記用作動態屬性值。 core
庫包含了一些定制標記,用于管理限定了作用域的變量、顯示 EL 值、實現迭代內容和條件內容以及與 URL 進行交互,這是“ JSTL 入門:探討 core”的主題。
我們接下來將討論的 JSTL 庫是 fmt
庫。 fmt
庫中的定制標記支持通過資源束對文本內容進行本地化,并支持對數字和日期的顯示和解析。這些標記利用在 java.util
和 java.text
包中實現的 Java 語言的國際化 API,因此如果您已經很熟悉諸如 ResourceBundle
、 Locale
、 MessageFormat
和 DateFormat
這樣的類,那么您將發現 fmt
庫中有很多方面值得稱道。如果您不熟悉這些類,那么 fmt
庫的標記用直觀的方式來封裝國際化 API,這種方式使您能夠很容易將本地化功能合并到 JSP 應用程序中。
本地化
在 Java 語言國際化 API 中,影響數據本地化方式的因素主要有兩個。一個是用戶的 語言環境,另一個是用戶的 時區。語言環境表示某一特定區域或文化的語言習慣,包括日期、數字和貨幣金額的格式。一個語言環境始終會有一種相關聯的語言,在許多情況下這種語言是由多個語言環境共享的某種語言的方言。例如,美國英語、英國英語、澳大利亞英語和加拿大英語都具有不同的英語語言環境,而法國、比利時、瑞士和加拿大所用的法語方言則都具有不同的法語語言環境。
時區是數據本地化中的第二個因素,這僅僅是因為一些語言環境分布的地理區域很廣。當您顯示有關跨洲語言環境(比如澳大利亞英語)的時間信息時,針對用戶時區定制數據與對其進行正確格式化一樣重要。
但是這就有了一個問題:應用程序如何確定用戶的語言環境和時區?在 Java 應用程序的情況下,JVM 能夠通過與本地操作系統進行交互來設置缺省語言環境和時區。雖然這種方法對于桌面應用程序而言可以正常工作,但是它實際上并不適合于服務器端的 Java 應用程序,因為這種應用程序所處理的請求,可能來自于距離該應用程序所駐留的服務器萬里之遙的地方。
幸運的是,HTTP 協議通過 Accept-Language
請求頭將本地化信息從瀏覽器傳遞至服務器。許多 Web 瀏覽器允許用戶定制他們的語言首選項,如圖 1 所示。通常,那些沒有為一種或多種首選語言環境提供顯式設置的瀏覽器會詢問操作系統以確定在 Accept-Language
頭中發送哪個值(或哪些值)。servlet 規范通過 javax.servlet.ServletRequest
類的 getLocale()
和 getLocales()
方法自動地利用 HTTP 協議的這一功能。JSTL fmt
庫中的定制標記又會利用這些方法來自動地確定用戶的語言環境,從而相應地調整它們的輸出。
圖 1. 通過設置瀏覽器的語言首選項來選擇語言環境 
但遺憾的是,不存在將用戶的時區從瀏覽器傳輸到服務器的標準 HTTP 請求頭。因此,那些希望自己的 Web 應用程序對時間數據進行本地化的用戶,將需要實現他們自己的機制,用來確定和跟蹤特定于用戶的時區。例如,在本系列文章第 2 部分“ JSTL 入門:探討 core”中所介紹的 Weblog 應用程序包含了一種將用戶的時區首選項存儲在 cookie 中的方式。
fmt 庫
JSTL fmt
庫中的定制標記主要分成四組。第一組允許您設置本地化上下文,其它標記將在其中進行操作。換句話說,這組標記允許頁面作者顯式地設置其它 fmt
標記在格式化數據時將要使用的語言環境和時區。第二組和第三組標記分別支持對日期和數字進行格式化和解析。最后一組標記側重于對文本消息進行本地化。
既然我們已經有了些基本了解,那就讓我們集中精力逐個研究這四組標記,并演示其用法。
本地化上下文標記
正如我們已經討論過的那樣,JSTL 標記在格式化數據時所使用的語言環境往往是通過查看用戶瀏覽器發送的每個 HTTP 請求所包含的 Accept-Language
頭來確定的。如果沒有提供這樣的頭,那么 JSTL 提供一組 JSP 配置變量,您可以設置這些變量以指定缺省的語言環境。如果尚未設置這些配置變量,那么就使用 JVM 的缺省語言環境,該缺省語言環境是從 JSP 容器所運行的操作系統中獲取的。
fmt
庫提供了其自身的定制標記,以覆蓋這個確定用戶語言環境的過程: <fmt:setLocale>
。正如下面的代碼片段所示, <fmt:setLocale>
操作支持三個屬性:
<fmt:setLocale value="
expression"
scope="
scope" variant="
expression"/>
|
其中只有一個屬性是必需的: value
屬性。該屬性的值應當是命名該語言環境的一個字符串或者是 java.util.Locale
類的一個實例。語言環境名稱是這樣組成的:小寫的兩字母 ISO 語言代碼,可選地,后面可以跟下劃線或連字符以及大寫的兩字母 ISO 國家或地區代碼。
例如, en
是英語的語言代碼, US
是美國的國家或地區代碼,因此 en_US
(或 en-US
)將是美式英語的語言環境名稱。類似的, fr
是法語的語言代碼, CA
是加拿大的國家或地區代碼,因此 fr_CA
(或 fr-CA
)是加拿大法語的語言環境名稱(請參閱 參考資料以獲取所有有效的 ISO 語言和國家或地區代碼的鏈接)。當然,由于國家或地區代碼是可選的,因此 en
和 fr
本身就是有效的語言環境名稱,適用于不區別這些相應語言特定方言的應用程序。
<fmt:setLocale>
的可選屬性 scope
用來指定語言環境的作用域。 page
作用域指出這項設置只適用于當前頁,而 request
作用域將它應用于請求期間訪問的所有 JSP 頁面。如果將 scope
屬性設置成 session
,那么指定的語言環境被用于用戶會話期間訪問的所有 JSP 頁面。值 application
指出該語言環境適用于該 Web 應用程序所有 JSP 頁面的全部請求和該應用程序所有用戶的全部請求。
variant
屬性(也是可選的)允許您進一步針對特定的 Web 瀏覽器平臺或供應商定制語言環境。例如, MAC
和 WIN
分別是 Apple Macintosh 和 Microsoft Windows 平臺的變體名。
下面的代碼片段說明了如何使用 <fmt:setLocale>
標記來顯式指定用戶會話的語言環境設置:
<fmt:setLocale value="fr_CA" scope="session"/>
|
JSP 容器處理完該 JSP 代碼段之后,將忽略用戶瀏覽器設置中所指定的語言首選項。
<fmt:setTimeZone>
操作像 <fmt:setLocale>
一樣,可以用來設置其它 fmt
定制標記所使用的缺省時區值。它的語法如下所示:
<fmt:setTimeZone value="
expression"
var="
name" scope="
scope"/>
|
和 <fmt:setLocale>
一樣,只有 value
屬性是必需的,但是在本例中它應當是時區名或 java.util.TimeZone
類的實例。
遺憾的是,對于時區命名目前還沒有任何被廣泛接受的標準。因此您可以用于 <fmt:setTimezone>
標記的 value
屬性的時區名是特定于 Java 平臺的。您可以通過調用 java.util.TimeZone
類的 getAvailableIDs()
靜態方法來檢索有效的時區名列表。示例包括 US/Eastern
、 GMT+8
和 Pacific/Guam
。
和 <fmt:setLocale>
的情況一樣,您可以使用可選的 scope
屬性來指出時區設置的作用域。下面的代碼演示了 <fmt:setTimeZone>
的用法,它用來指定適用于單個用戶會話的時區:
<fmt:setTimeZone value="Australia/Brisbane" scope="session"/>
|
您還可以使用 <fmt:setTimeZone>
操作將 TimeZone
實例的值存儲在限定了作用域的變量中。在本例中,您可以使用 var
屬性來命名限定了作用域的變量,用 scope
屬性來指定該變量的作用域(例如,就象這兩個屬性用在 <c:set>
和 <c:if>
操作中)。請注意,當您以這種方式使用 <fmt:setTimeZone>
操作時,它唯一的副作用就是設置指定的變量。當指定 var
屬性時,對于任何其它 JSTL 標記使用什么時區,不會對 JSP 環境作任何更改。
這組中的最后一個標記是 <fmt:timeZone>
操作:
<fmt:timeZone value="
expression">
body content
</fmt:timeZone>
|
和 <fmt:setTimeZone>
一樣,您可以使用該標記來指定將由其它 JSTL 標記使用的時區。但是, <fmt:timeZone>
操作的作用域僅限于其標記體內容。在 <fmt:timeZone>
標記體中,由標記的 value
屬性指定的時區覆蓋了 JSP 環境中現有的任何其它時區設置。
和 <fmt:setTimeZone>
的情況一樣, <fmt:timeZone>
標記的 value
屬性應當是時區名或者是 java.util.TimeZone
實例。后面的 清單 1 中提供了一個如何使用 <fmt:timeZone>
的示例。
日期標記
fmt
庫包含了用來與日期和時間進行交互的兩個標記: <fmt:formatDate>
和 <fmt:parseDate>
。顧名思義, <fmt:formatDate>
用來格式化和顯示日期和時間(數據 輸出),而 <fmt:parseDate>
用來解析日期和時間值(數據 輸入)。
<fmt:formatDate>
的語法如下所示:
<fmt:formatDate value="
expression"
timeZone="
expression"
type="
field" dateStyle="
style"
timeStyle="
style"
pattern="
expression"
var="
name" scope="
scope"/>
|
只有 value
屬性才是必需的。其值應當是 java.util.Date
類的實例,指定要進行格式化和顯示的日期和/或時間數據。
可選的 timeZone
屬性指出將要顯示哪個時區的日期和/或時間。如果沒有顯式地指定 timeZone
屬性,那么就使用周圍任何 <fmt:timeZone>
標記所指定的時區。如果 <fmt:timeZone>
標記的主體部分沒有包含 <fmt:formatDate>
操作,那么就使用任何適用的 <fmt:setTimeZone>
操作所設置的時區。如果沒有相關的 <fmt:setTimeZone>
操作,那么就使用 JVM 的缺省時區(也就是,專為本地操作系統而設置的時區)。
type
屬性指出要顯示指定的 Date
實例的哪些字段,應當是 time
、 date
或 both
。該屬性的缺省值是 date
,因此如果沒有給出 type
屬性,那么 <fmt:formatDate>
標記(名符其實)將只顯示與 Date
實例相關的日期信息,這個信息用該標記的 value
屬性指定。
dateStyle
和 timeStyle
屬性分別指出應當如何格式化日期和時間信息。有效的樣式有 default
、 short
、 medium
、 long
和 full
。缺省值自然是 default
,指出應當使用特定于語言環境的樣式。其它四個樣式值的語義與 java.text.DateFormat
類定義的一樣。
可以使用 pattern
屬性來指定定制樣式,而不必依賴于內置樣式。給出定制樣式后,該模式屬性的值應當是符合 java.text.SimpleDateFormat
類約定的模式字符串。這些模式基于用對應的日期和時間字段代替模式內指定的字符。例如,模式 MM/dd/yyyy
表明應當顯示用正斜杠分隔的兩位數的月份和日期值以及四位數的年份值。
如果指定了 var
屬性,那就把包含格式化日期的 String
值指派給指定的變量。否則, <fmt:formatDate>
標記將寫出格式化結果。當指定了 var
屬性后, scope
屬性指定所生成變量的作用域。
清單 1(它是本系列 第 2 部分清單 8 的擴展)包含了 <fmt:formatDate>
標記的兩種用法。在第一種用法中, <fmt:formatDate>
只用來顯示第一個 weblog 項的創建時間戳記的日期部分。此外,為 dateStyle
屬性指定了一個 full
值,這樣一來所有的日期字段就將用一種特定于語言環境的格式進行顯示。
清單 1. 使用 <fmt:formatDate> 標記來顯示日期和時間值<table>
<fmt:timeZone value="US/Eastern">
<c:forEach items="${entryList}" var="blogEntry" varStatus="status">
<c:if test="${status.first}">
<tr><td align="left" class="blogDate">
<fmt:formatDate value=
"${blogEntry.created}" dateStyle="full"/>
</td></tr>
</c:if>
<tr><td align="left" class="blogTitle">
<c:out value="${blogEntry.title}" escapeXml="false"/>
</td></tr>
<tr><td align="left" class="blogText">
<c:out value="${blogEntry.text}" escapeXml="false"/>
<font class="blogPosted">
[Posted <fmt:formatDate value="${blogEntry.created}"
pattern="h:mm a zz"/>]
</font>
</td></tr>
</c:forEach>
</fmt:timeZone>
</table>
|
在 <c:forEach>
循環體中,第二個 <fmt:formatDate>
操作只用來顯示每個項的創建日期的時間部分。在本例中, pattern
屬性用來控制時間值的格式化、并控制指定一位數的小時顯示(如果可能的話)、12 小時的時鐘和縮寫時區的輸出。輸出如圖 2 所示:
圖 2. 清單 1 中 en_US 語言環境的輸出 
更準確地說,用戶瀏覽器設置指定首選項是英語時,就會產生圖 2 中所示的輸出。但是由于 <fmt:formatDate>
對用戶語言環境敏感,所以瀏覽器首選項的改變將導致生成不同的內容。例如,當給定的首選項是法語語言環境時,則結果會如圖 3 所示:
圖 3. 清單 1 中 fr_CA 語言環境的輸出 
<fmt:formatDate>
生成了 java.util.Date
實例的本地化字符串表示,而 <fmt:parseDate>
操作執行相反的操作:給定一個表示日期和/或時間的字符串,它將生成相應的 Date
對象。 <fmt:parseDate>
操作有兩種格式,如下所示:
<fmt:parseDate value="
expression"
type="
field" dateStyle="
style" timeStyle="
style"
pattern="
expression"
timeZone="
expression" parseLocale="
expression"
var="
name" scope="
scope"/>
<fmt:parseDate
type="
field" dateStyle="
style" timeStyle="
style"
pattern="
expression"
timeZone="
expression" parseLocale="
expression"
var="
name" scope="
scope">
body content
</fmt:parseDate>
|
對于第一種格式,只有 value
屬性才是必需的,它的值應當是指定日期、時間或這兩者組合的字符串。對于第二種格式,沒有必需的屬性,表示要解析的值的字符串被指定為 <fmt:parseDate>
標記必需的標記體內容。
type
、 dateStyle
、 timeStyle
、 pattern
和 timeZone
屬性對 <fmt:parseDate>
和對 <fmt:formatDate>
起一樣的作用,不同之處僅在于對于前者,它們控制日期值的解析而非顯示。 parseLocale
屬性用來指定一種語言環境,將根據這種語言環境來解析該標記的值,它應當是語言環境的名稱或 Locale
類的實例。
var
和 scope
屬性用來指定限定了作用域的變量(作為 <fmt:parseDate>
的結果),將把 Date
對象賦給該變量。如果沒有給出 var
屬性,則使用 Date
類的 toString()
方法將結果寫到 JSP 頁面中。清單 2 顯示了 <fmt:parseDate>
操作的一個示例:
清單 2. 使用 <fmt:parseDate> 標記來解析日期和時間<c:set var="usDateString">4/1/03 7:03 PM</c:set>
<fmt:parseDate value="${usDateString}" parseLocale="en_US"
type="both" dateStyle="short" timeStyle="short"
var="usDate"/>
<c:set var="gbDateString">4/1/03 19:03</c:set>
<fmt:parseDate value="${gbDateString}" parseLocale="en_GB"
type="both" dateStyle="short" timeStyle="short"
var="gbDate"/>
<ul>
<li> Parsing <c:out value="${usDateString}"/> against the
U.S. English
locale yields a date of <c:out value="${usDate}"/>.</li>
<li> Parsing <c:out value="${gbDateString}"/> against the
British English
locale yields a date of <c:out value="${gbDate}"/>.</li>
</ul>
|
清單 2 的輸出如圖 4 所示。
圖 4. 清單 2 的輸出 
由 <fmt:parseDate>
所執行的解析非常嚴格,注意這一點很重要。正如清單 2 所暗示的那樣,要解析的值必須嚴格符合特定(特定于語言環境)的樣式或模式。這當然更加受限制。另一方面,數據的解析并不是一個非常適合于表示層的任務。對于生產代碼,文本輸入的驗證和轉換最好由后端代碼(比如 servlet)來處理,而不是通過 JSP 定制標記來處理。
數字標記
就象 <fmt:formatDate>
和 <fmt:parseDate>
標記用于格式化和解析日期一樣, <fmt:formatNumber>
和 <fmt:parseNumber>
標記對數字數據執行類似的功能。
<fmt:formatNumber>
標記用來以特定于語言環境的方式顯示數字數據,包括貨幣和百分數。 <fmt:formatNumber>
操作由語言環境確定,例如,使用句點還是使用逗號來定界數字的整數和小數部分。下面是它的語法:
<fmt:formatNumber value="
expression"
type="
type" pattern="
expression"
currencyCode="
expression" currencySymbol="
expression"
maxIntegerDigits="
expression" minIntegerDigits="
expression"
maxFractionDigits="
expression" minFractionDigits="
expression"
groupingUsed="
expression"
var="
name" scope="
scope"/>
|
如 <fmt:formatDate>
的情況一樣,只有 value
屬性才是必需的。它用來指定將被格式化的數值。 var
和 scope
屬性對 <fmt:formatNumber>
操作所起的作用,如它們在 <fmt:formatDate>
中所起的作用一樣。
type
屬性的值應當是 number
、 currency
或 percentage
,并指明要對哪種類型的數值進行格式化。該屬性的缺省值是 number
。 pattern
屬性優先于 type
屬性,允許對遵循 java.text.DecimalFormat
類模式約定的數值進行更精確的格式化。
當 type
屬性的值為 currency
時, currencyCode
屬性可以用來顯式地指定所顯示的數值的貨幣單位。與語言和國家或地區代碼一樣,貨幣代碼也是由 ISO 標準管理的(請參閱 參考資料以獲取所有有效的 ISO 貨幣符號代碼的鏈接)。該代碼用來確定作為已格式化值的一部分顯示的貨幣符號。
另外,您可以使用 currencySymbol
屬性來顯式地指定貨幣符號。請注意,由于 JDK 1.4 和相關的 java.util.Currency
類的引入, <fmt:formatNumber>
操作的 currencyCode
屬性優先權超過 currencySymbol
屬性。但是對于較老版本的 JDK 而言, currencySymbol
屬性具有優先權。
maxIntegerDigits
、 minIntegerDigits
、 maxFractionDigits
和 minFractionDigits
屬性用來控制小數點前后所顯示的有效數字的個數。這些屬性要求是整數值。
groupingUsed
屬性帶有布爾值并控制是否要對小數點前面的數字分組。例如,在英語語言環境中,將較大數的每三個數字分為一組,每組用逗號定界。其它語言環境用句點或空格來定界這樣的分組。該屬性的缺省值為 true
。
清單 3 顯示了一個簡單的貨幣示例,它本身是 清單 1 的擴展。在本例中,不指定 currencyCode
或 currencySymbol
屬性。而貨幣是由語言環境設置確定的。
清單 3. 使用 <fmt:formatNumber> 標記顯示貨幣值<table>
<fmt:timeZone value="US/Eastern">
<c:forEach items="${entryList}" var="blogEntry"
varStatus="status">
<c:if test="${status.first}">
<tr><td align="left" class="blogDate">
<fmt:formatDate value=
"${blogEntry.created}" dateStyle="full"/>
</td></tr>
</c:if>
<tr><td align="left" class="blogTitle">
<c:out value="${blogEntry.title}" escapeXml="false"/>
</td></tr>
<tr><td align="left" class="blogText">
<c:out value="${blogEntry.text}" escapeXml="false"/>
<font class="blogPosted">
[My <fmt:formatNumber value="0.02" type="currency"/>
posted at <fmt:formatDate value="${blogEntry.created}"
pattern="h:mm a zz"/>]
</font>
</td></tr>
</c:forEach>
</fmt:timeZone>
</table>
|
en_US
語言環境的輸出如圖 5 所示:
圖 5. 清單 3 的 en_US 語言環境的輸出 
fr_CA
語言環境的輸出如圖 6 所示:
圖 6. 清單 3 的 fr_CA 語言環境的輸出 
如下所示, <fmt:parseNumber>
操作解析了一個數值,該數值是通過 value
屬性或該操作的標記體內容以特定于語言環境的方式提供的,將結果作為 java.lang.Number
類的實例返回。 type
和 pattern
屬性對 <fmt:parseNumber>
和對 <fmt:formatNumber>
起一樣的作用。同樣, parseLocale
、 var
和 scope
屬性對 <fmt:parseNumber>
起與 <fmt:parseDate>
一樣的作用。
<fmt:parseNumber value="
expression"
type="
type" pattern="
expression"
parseLocale="
expression"
integerOnly="
expression"
var="
name" scope="
scope"/>
<fmt:parseNumber
type="
type" pattern="
expression"
parseLocale="
expression"
integerOnly="
expression"
var="
name" scope="
scope">
body content
</fmt:parseNumber>
|
先前有關 <fmt:parseDate>
的說明同樣適用于 <fmt:parseNumber>
:解析數據并不是一項非常適合于表示層的任務。如果解析和驗證數據作為應用程序業務邏輯的一部分實現,那么軟件維護將會得到簡化。由于這個原因,通常建議大家在產品 JSP 頁面中避免同時使用 <fmt:parseDate>
和 <fmt:parseNumber>
。
只有 integerOnly
屬性才是 <fmt:parseNumber>
所獨有的。該屬性獲取一個布爾值,指出是否應當只解析所給值的整數部分。如果該屬性的值為 true
,那么就忽略要被解析的字符串中跟在小數點后面的任何數字。該屬性的缺省值為 false
。
消息標記
在 JSTL 中用 <fmt:message>
標記實現文本的本地化。該標記允許您從特定于語言環境的資源束中檢索文本消息并顯示在 JSP 頁面上。而且,由于該操作利用 java.text.MessageFormat
類所提供的功能,所以可以將參數化的值替換進這樣的文本消息,以便動態地定制本地化內容。
用于存儲特定于語言環境消息的資源束采用類或特性文件的形式,這些類或特性文件符合標準命名約定,在這種命名約定中基名和語言環境名組合在一起。例如,請研究名為 Greeting.properties
的特性文件,它駐留在我們的 weblog 應用程序的類路徑中,該類路徑位于與 com.taglib.weblog
包相對應的子目錄中。您可以通過在同一目錄下指定兩個新的特性文件,從而將該特性文件所描述的資源束本地化為英語和法語,通過追加相應的語言代碼來命名。具體而言,這兩個文件應當分別命名為 Greeting_en.properties
和 Greeting_fr.properties
。如果希望另一個本地化為加拿大法語,您可以引入第三個特性文件,在其名稱中包含了相應的國家或地區代碼(比如 Greeting_fr_CA.properties
)。
這些文件都可以定義相同的特性,但是應當將這些特性的值定制成對應的語言或方言。這種方法如清單 4 和清單 5 所示,它們給出了 Greeting_en.properties
和 Greeting_fr.properties
文件的樣本內容。在這些示例中,定義了兩個已本地化的消息。它們可以通過 com.taglib.weblog.Greeting.greeting
和 com.taglib.weblog.Greeting.return
鍵識別。但是已經將與這些鍵相關聯的值本地化為文件名中所確定的語言。請注意,出現在 com.taglib.weblog.Greeting.greeting
消息的兩個值中的 {0}
模式使已參數化的值能夠在內容生成期間動態地插入到消息中。
清單 4. Greeting_en.properties 本地化資源束的內容com.taglib.weblog.Greeting.greeting=Hello {0}, and welcome to the JSTL Blog.
com.taglib.weblog.Greeting.return=Return
|
清單 5. Greeting_fr.properties 本地化資源束的內容com.taglib.weblog.Greeting.greeting=Bonjour {0}, et bienvenue au JSTL Blog.
com.taglib.weblog.Greeting.return=Retournez
|
用 JSTL 顯示這樣的本地化內容,第一步就是指定資源束。 fmt
庫為完成這一任務提供了兩個定制標記: <fmt:setBundle>
和 <fmt:bundle>
,它們的行為和前面介紹的 <fmt:setTimeZone>
和 <fmt:timeZone>
標記相似。 <fmt:setBundle>
操作設置了一個缺省資源束,供 <fmt:message>
標記在特定作用域內使用,而 <fmt:bundle>
指定了為嵌套在其標記體內容中的全部和任意 <fmt:message>
操作所用的資源束。
下面的代碼片段顯示了 <fmt:setBundle>
標記的語法。 basename
屬性是必需的,它標識了設為缺省值的資源束。請注意, basename
屬性的值不應當包含任何本地化后綴或文件擴展名。清單 4 和清單 5 中給出的示例資源束的基名為 com.taglib.weblog.Greeting
。
<fmt:setBundle basename="
expression"
var="
name" scope="
scope"/>
|
可選的 scope
屬性指明缺省資源束設置所應用的 JSP 作用域。如果沒有顯式地指定該屬性,就假定為 page
作用域。
如果指定了可選的 var
屬性,那么將把由 basename
屬性所標識的資源束賦給該屬性值所命名的變量。在這種情況下, scope
屬性指定變量的作用域;沒有將缺省資源束賦給相應的 JSP 作用域。
您使用 <fmt:bundle>
標記(其語法如下所示)在其標記體內容的作用域內設置缺省資源束。和 <fmt:setBundle>
一樣,只有 basename
屬性才是必需的。您可以使用可選的 prefix
屬性來為任何嵌套的 <fmt:message>
操作的 key
值指定缺省前綴。
<fmt:bundle basename="
expression"
prefix="
expression">
body content
</fmt:bundle>
|
一旦設置了資源束,真正起到顯示本地化消息作用的是 <fmt:message>
標記。該操作支持兩種不同的語法,這取決于是否需要任何嵌套的 <fmt:param>
標記:
<fmt:message key="
expression" bundle="
expression"
var="
name" scope="
scope"/>
<fmt:message key="
expression" bundle="
expression"
var="
name" scope="
scope">
<fmt:param value="
expression"/>
...
</fmt:message>
|
對于 <fmt:message>
,只有 key
屬性才是必需的。 key
屬性的值用來確定要顯示在資源束中定義的哪些消息。
您可以使用 bundle
屬性來指定一個顯式的資源束,用來查找由 key
屬性標識的消息。請注意,該屬性的值必須是實際的資源束,比如當指定 <fmt:setBundle>
操作的 var
屬性時由該操作所賦予的資源束。 <fmt:message>
的 bundle
屬性不支持字符串值(比如 <fmt:bundle>
和 <fmt:setBundle>
的 basename
屬性)。
如果指定了 <fmt:message>
的 var
屬性,那么將由該標記所生成的文本消息賦給指定的變量,而不是寫到 JSP 頁面。通常,可選的 scope
屬性用來指定由 var
屬性指定的變量的作用域。
需要的時候您可以通過使用 <fmt:param>
標記的 value
屬性來提供文本消息的參數化值。或者,可以將該值指定為 <fmt:param>
標記體內容,在這種情況下省略該屬性。無論參數化值模式出現在消息文本中的什么地方,由 <fmt:param>
標記指定的值都將合并到從資源束檢索的消息,這與 java.text.MessageFormat
類的行為一致。因為參數化值可以通過其下標進行標識,因此嵌套的 <fmt:param>
標記的順序很重要。
<fmt:bundle>
、 <fmt:message>
和 <fmt:param>
標記的交互作用如清單 6 所示。此處, <fmt:bundle>
標記通過兩個嵌套的 <fmt:message>
標記指定了要在其中檢索本地化消息的資源束。這兩個 <fmt:message>
標記的第一個對應于帶有一個參數化值的消息,還出現了對應的用于該值的 <fmt:param>
標記。
清單 6. 使用 <fmt:message> 標記顯示本地化消息<fmt:bundle basename="com.taglib.weblog.Greeting">
<fmt:message key="com.taglib.weblog.Greeting.greeting">
<fmt:param value="${user.fullName}"/>
</fmt:message>
<br>
<br>
<center>
<a href=
"<c:url value='/index.jsp'/>"><fmt:message
key="com.taglib.weblog.Greeting.return"/></a>
</center>
</fmt:bundle>
|
清單 7 演示了 <fmt:bundle>
的 prefix
屬性的用法;為 prefix
屬性提供的值在嵌套的 <fmt:message>
操作中自動地預先添加到所有 key
值上。因此清單 7 相當于清單 6,只是清單 7 利用了這一便利的特性,使得能夠在兩個 <fmt:message>
標記中使用縮略的 key
值。
清單 7. <fmt:bundle> 的 prefix 屬性對 <fmt:message> 標記的影響<fmt:bundle basename="com.taglib.weblog.Greeting"
prefix="com.taglib.weblog.Greeting.">
<fmt:message key="greeting">
<fmt:param value="${user.fullName}"/>
</fmt:message>
<br>
<br>
<center>
<a href="<c:url value='/index.jsp'/>"><fmt:message key="return"/></a>
</center>
</fmt:bundle>
|
圖 7 和圖 8 演示了正在工作的 fmt
庫與消息相關的標記,顯示了由清單 7 中代碼所產生的輸出,以及 清單 4和 清單 5中的本地化資源束。圖 7 顯示了當瀏覽器首選項為英語語言環境時的結果。
圖 7. 清單 7 中 en_US 語言環境的輸出 
圖 8 顯示了指定法語的語言環境的輸出。
圖 8. 清單 7 的 fr_CA 語言環境的輸出 
結束語
JSTL fmt
庫的定制標記為 JSP 開發人員提供了一種對 Java 平臺的國際化 API 的簡單訪問。文本消息、數值和日期都可以用對語言環境敏感的方式進行顯示,還可以將時間調整到特定的時區。可以從用戶的瀏覽器設置自動確定特定用戶的語言環境,或者由頁面作者顯式指定特定用戶的語言環境。最后,除了提供用于生成和顯示格式化數據的操作之外, fmt
庫還包含了用于解析面向數字和時間數據的定制標記。
參考資料

 |

|
關于作者