According to section 9.3.2 of the JSTL spec, the formatting locale for the NumberFormat should be determined like so: "The locale lookup is similar to the resource bundle lookup described in Section 8.3.1, except that instead of trying to match a resource bundle, the locale lookup tries to find a match in a list of available locales." Instead of this happening, though, it appears that only locales that have a resource bundle are included in the lookup. Perusing the source code (up to and including the nightly build), I think I've found the problem. At the beginning of the org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport::getFormattingLocale() method, there code like this: // Get formatting locale from enclosing <fmt:bundle> Tag parent = findAncestorWithClass(fromTag, BundleSupport.class); if (parent != null) { // removed for brevity } // Use locale from default I18N localization context, unless it is null if ((locCtxt = BundleSupport.getLocalizationContext(pc)) != null) { // removed for brevity } The trouble is that this default check will succeed in finding a localization context if a Fallback locale has been set. This is in violation of the spec regarding NumberFormat. I propose the default check be moved inside of the (parent != null) block. This way the ResourceBundle checks won't interfere with the NumberFormat resource checks. Here's a diff: --- SetLocaleSupport.java 2003-01-06 16:42:10.000000000 -0500 +++ SetLocaleSupport.java.old 2003-01-06 16:30:18.000000000 -0500 @@ -277,16 +277,16 @@ } return locCtxt.getLocale(); } + } - // Use locale from default I18N localization context, unless it is null - if ((locCtxt = BundleSupport.getLocalizationContext(pc)) != null ) { - if (locCtxt.getLocale() != null) { - if (format) { - setResponseLocale(pc, locCtxt.getLocale()); - } - return locCtxt.getLocale(); - } + // Use locale from default I18N localization context, unless it is null + if ((locCtxt = BundleSupport.getLocalizationContext(pc)) != null) { + if (locCtxt.getLocale() != null) { + if (format) { + setResponseLocale(pc, locCtxt.getLocale()); } + return locCtxt.getLocale(); + } } Thanks!
I have checked the RI, and it appears to be in compliance with the spec. Section 9.2 of the spec clearly states that if a localization context exists for a formatting action, it will have priority to establish the locale of the formatting action. A formatting action will establish a locale according to the algorithm described in section 9.3 if and only if a localization context with a valid Locale cannot be established via an <fmt:bundle> ancestor or default localization context.
Yes, your reading of the spec seems correct. Nevertheless, the implementation is wrong because there is no "<fmt:bundle> ancestor or default localization context" in this case. There is only the fallback locale, which according to spec section 8.11.2: "Specifies the fallback locale to be used by the i18n-capable formatting actions if none of the preferred match any of the available locales." In other words, the fallback locale should only be used only after all other efforts to resolve a preferred locale have failed. So, perhaps my diff is not the correct solution, but there is still a problem here as the call "BundleSupport.getLocalizationContext(pc)" will return the fallback locale before the other algorithms in "SetLocaleSupport.getFormattingLocale()" method have had their chance to identify a preferred locale.
Hummm, looked at the code again and it still looks fine to me. Could you run the test JSP page below and report what you get. When I run it, the preferred locale is picked up even though a different fallback locale has been specified. My output is as follows: Default localization context: null Fallback locale is: en Preferred locale: fr,sv,en format 1234546789: 123 456 789 format today's date: 8 janv. 2003 -- Pierre ----- %@ page import="javax.servlet.jsp.jstl.core.Config" %> <%@ page import="javax.servlet.jsp.PageContext" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> <% Config.set(pageContext, Config.FMT_FALLBACK_LOCALE, "en", PageContext.PAGE_SCOPE); %> Default localization context: <%= Config.find(pageContext, Config.FMT_LOCALIZATION_CONTEXT) %><br> Fallback locale is: <%= Config.find(pageContext, Config.FMT_FALLBACK_LOCALE) %><br> Preferred locale: <%= request.getHeader("Accept-Language") %> <p> format 1234546789: <fmt:formatNumber>123456789</fmt:formatNumber><br> format today's date: <jsp:useBean id="now" class="java.util.Date" /> <fmt:formatDate value="${now}" />
Your code works correctly standalone. But I think the reason it doesn't recreate the problem for you is that you don't have a resource bundle that is associated with the fallback locale. When I made sure that there was an appropriate resource bundle for the fallback locale, this issue returned.
I've ran more tests with a resource bundle that is associated with the fallback locale, and I still don't see any problem. I'm afraid we can spend a lot of time going back and forth like this. If you still feel there is a bug, please submit sample code and/or complete instructions to allow us to reproduce the problem (i.e. we have to be able to reproduce a behavior that you feel is a bug). Until then, I'll consider this bug report invalid.
You're right, that was getting us nowhere. So, I've attached a test case. Unzip the test.jar into /usr/local/tomcat/webapps or wherever you have your web apps. Go the the /test/index.jsp page and this is similar to what you will see if you choose Italian as your browser's preferred locale: Default localization context: Resource Fallback locale is: en_US Preferred locale: it,en-us;q=0.8,en;q=0.5,en-gb;q=0.3 format -12345467.89: ($1,234,567.89) format today's date: Jan 9, 2003 As you will note, the number and date formatting is according to the fallback locale (US) and not according to the Italian locale. On the other hand, if you delete or move the WEB-INF/classes/Resource_en_us.properties file and restart tomcat, you will see this: Default localization context: Resource Fallback locale is: en_US Preferred locale: it,en-us;q=0.8,en;q=0.5,en-gb;q=0.3 format -12345467.89: -USD 1.234.567,89 format today's date: 9-gen-2003 Removing that file makes everything happy for the Italians, but shouldn't be necessary. I hope this helps clear up the issue as I really need it fixed! :)
Created attachment 4387 [details] test case
Scott, Thanks for sending a complete test. Now I see why you get these results. You previously wrote: Nevertheless, the implementation is wrong because there is no "<fmt:bundle> ancestor or default localization context" in this case. There is only the fallback locale, which according to spec section 8.11.2: "Specifies the fallback locale to be used by the i18n-capable formatting actions if none of the preferred match any of the available locales." In other words, the fallback locale should only be used only after all other efforts to resolve a preferred locale have failed. However, this is *not* the environment you have for your test case. In your test case, there is no <fmt:bundle> ancestor, but there *is* a default localization context set in web.xml: <!-- <context-param> <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name> <param-value>Resource</param-value> </context-param> --> This is therefore a totally different story... In section 9.2 of the spec, it is stated that JSTL first looks for an ancestor <fmt:bundle>, and then for the I18N default localization context before considering the "formatting locale lookup" of section 9.3. Since you have a default localization context, JSTL applies the following rule: ... if the configuration setting is of type String, the formatting action establishes its own i18n localization context and uses its locale as the formatting locale (in this case, the resource bundle component of the i18n localization context is determined according to the resource bundle determination algorithm in Section 8.3, using the configuration setting as the resource bundle basename). If the i18n localization context determined in this step does not contain any locale, go to the next step. Applying the resource bundle determination algorithm in Section 8.3, we get the following (assuming the preferred locale is French): step 1: find a match within the ordered set of preferred locales Resource_fr --> does not exist step 2: Find a match with the fallback locale (en_US in your test case) Resource_en_US --> exists!!! A match is found --> the fallback locale and the matched resource bundle are stored in the i18n localization context. This is therefore why the fallback locale takes precendence in this case. Please note that if no default localization context were specified, then the "french" locale would be used because the resource bundle determination algorithm of Section 8.3 would not be applied. Still following? Essentially, the situation is as follows: You've declared a default localization context as the resource bundle basename "Resources". Whenever a message is to be internationalized in your webapp, JSTL will always fall back on that default localization context if a resource bundle is not specified explicitely. So in the following situation: <fmt:message key="hello"/> <fmt:message key="todaysDate"/> <jsp:useBean id="now" class="java.util.Date" /> <fmt:formatDate value="${now}" /> You would get: Hello! Today's date is: jan 9 2003 even though the preferred locale might be french. The expert group felt it was better than having: Hello! Today's date is: 9 janv. 2003 because in this second instance we would be mixing two locales (english for the localized message, french for the formatting action). It was decided that sticking to a single locale made more sense. The fact that you specify a default localization context therefore impacts the locale of formatting actions if the preferred locale of the client is not supported by your resource bundles, but the fallback locale is. When you remove Resources.en_US, no locale is found for the default localization context, so the formatting locale lookup algorithm of section 9.3 kicks in. Hope this helps...
So you're telling me that if I use any resource bundle at all to internationalize my text that I will lose the ability to format my dates and numbers according to the preferred locale instead of the resource bundles I have created?I hope not, because that seems awfully short-sighted. Just because I'm displaying English text doesn't mean that all my numbers should be formatting using American-style formats. There are a lot of French that can read English just fine. So, I might not have translated all my text to French, but I think that they'd rather see the commonly accepted number (1.234,56) and date (dd-mm-yy) formats for their locale than the American numbers (1,234.56) and dates (mm-dd-yy).Is there really no way around this (rather severe) limitation other than creating a dummy resource bundle for every locale that I possibly want to have correct number and date formatting for?
If you: - specify a default localization context "Resources" - do not specify a fallback locale - provide a root bundle "Resources" then you should get the behavior you're looking for. Also, please note that there is an official alias to send comments regarding the JSTL specification (jsr-52-comments@jcp.org). The expert group is always happy to review *constructive* comments.