Bug 15822 - Incorrect determination of formatting locale for numberFormat tag
Summary: Incorrect determination of formatting locale for numberFormat tag
Status: RESOLVED INVALID
Alias: None
Product: Taglibs
Classification: Unclassified
Component: Standard Taglib (show other bugs)
Version: unspecified
Hardware: All All
: P3 blocker (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-01-06 21:47 UTC by Scott Ganyo
Modified: 2004-11-16 19:05 UTC (History)
0 users



Attachments
test case (463.58 KB, application/octet-stream)
2003-01-09 20:52 UTC, Scott Ganyo
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Scott Ganyo 2003-01-06 21:47:10 UTC
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!
Comment 1 Pierre Delisle 2003-01-08 00:18:36 UTC
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.
Comment 2 Scott Ganyo 2003-01-08 03:19:30 UTC
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.
Comment 3 Pierre Delisle 2003-01-08 19:52:30 UTC
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}" />
Comment 4 Scott Ganyo 2003-01-09 18:41:31 UTC
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.
Comment 5 Pierre Delisle 2003-01-09 20:23:18 UTC
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.
Comment 6 Scott Ganyo 2003-01-09 20:51:22 UTC
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! :)
Comment 7 Scott Ganyo 2003-01-09 20:52:04 UTC
Created attachment 4387 [details]
test case
Comment 8 Pierre Delisle 2003-01-10 00:57:19 UTC
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...
Comment 9 Scott Ganyo 2003-01-10 03:31:30 UTC
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?
Comment 10 Pierre Delisle 2003-01-13 22:25:20 UTC
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.