Globalization API Feedback - moar!

Nebojša Ćirić cira at google.com
Wed Nov 23 15:15:48 PST 2011


23. новембар 2011. 14.32, Nicholas C. Zakas
<standards at nczconsulting.com>је написао/ла:

>  On 11/23/2011 12:57 PM, Nebojša Ćirić wrote:
>
> Similar approach was proposed (with locale as a top object, others under
> it) and I have nothing against it, but there are some issues with your
> approach:
>
>  (code == localeID)
>
>  Sorry for being unclear - I didn't intend for this to be a complete
> alternate proposal, just a starting point. There are definitely still
> issues that would have to be resolved.
>

I just feel we are going in circles sometimes :). I am surprised Norbert
agreed with this approach - I think he was against top level Locale object.


> 1. An implementation may support NumberFormat for localeID x, but not
> support DateFormat for x (it would need to do a fallback to less specific
> one, or default). That's why we have supportedLocaleOf method on each
> object.
>
>
> So what you're saying is that there needs to be some way to feature detect
> support for number and date formats separately. That could be handled in
> any number of ways. One that pops to mind would be
> isDateFormatSupported()/isNumberFormatSupported() as an instance method.
>

That would probably work. We could add more methods in the future - say one
that tells you closest locale to the current one that does support service
in question.

2. How do you convey status of option/locale resolution to the developer?
> Which options were resolved and to what value (say I ask for 'islamic'
> calendar, but we only have 'gregory' for a given locale). In our current
> proposal we expose resolvedOptions accessor on i.e. DateTimeFormat object
> instance that has 'calendar' property, so a developer can decide what to do.
>
>
> Thanks, I was having trouble understanding what resolvedOptions was used
> for. Could the use case be handled by having a similar object on a Locale
> instance? It seems like you could include options for available calendars
> and anything else that developers could query against, such as:
>
>
>     var locale = new Locale();
>     if (locale.supportedOptions.islamicCalendar){
>         //foo
>     }
>
> You could also go a more traditional direction (at least in terms of DOM
> objects), by doing something like:
>
>     Locale.CALENDAR_ISLAMIC = 1;
>     Locale.CALENDAR_GREGORIAN = 2;
>
>
>     var locale = new Locale();
>     locale.isSupported(Locale.CALENDAR_ISLAMIC);
>
> I think feature detection is an easily solved problem if everything else
> is in place.
>

Sometimes options can influence each other. For example:

1. Ask for th locale (Thai)
2. There are two calendars available - buddhist and gregory
3. There are two numbering systems available - thai and latin

but only buddhist + thai and gregory + latin combinations are supported.

If you ask locale.isSupported('calendar': 'buddhist') you'll get true. If
you ask locale.isSupported('numberingSystem', 'latin') you'll get true
again. If you try to format date using that combination (thai + latin)
you'll get something you didn't expect.

I would propose sligthly different isSupported method:

locale.returnSupported(serviceName, options), where serviceName is one of
'dateFormat', 'numberFormat', 'collator', options object contains requested
settings (calendar, numbering system, collation options...) and method
returns the object with supported features for a given service.

> 3. This approach would require internal caching of
> collator/dateformatter/numberformatter objects.
>
>
> That's an implementation detail. I'm more interested in defining an usable
> and relatively intuitive API before worrying about optimization.
>

I agree, it's implementation detail, but you will need to pass format
parameter to each call of .format() method. I don't think that's a big
problem. Also I would move format and option parameters to the last
position (can be optional), so that user can specify only value and rely on
defaults.

>
> 23. новембар 2011. 12.09, Nicholas C. Zakas <standards at nczconsulting.com>је написао/ла:
>
>> After meeting with Norbert to discuss the use cases and design decision
>> rationale, I've come to a different understanding of the goals of the
>> globalization API. Some things I learned:
>>
>> 1. Augmenting native types with some default locale support may be
>> dangerous. Consider the case where a single web page displays two modules
>> with different locales. Which one wins? Therefore, "default" locale
>> behavior for native types is impractical.
>> 2. Locale information is most frequently used for formatting numbers and
>> dates as well as comparing strings. The locale information doesn't permeate
>> the entire execution context.
>> 3. Developers are likely to want to define locale information once and
>> then reuse that multiple times through a script.
>>
>> Given this, I'd like to propose an alternate approach to the one
>> currently taken in the API and also different from my initial email. It
>> goes like this:
>>
>> Have a single, top-level type called Locale defined as:
>>
>>    function Locale(code){
>>
>>        //whatever has to happen to process the code
>>
>>        this.code = code;
>>    }
>>
>>    /*
>>     * Determine if a locale is supported.
>>     * @param code The code to check.
>>     * @return True if supported, false if not.
>>     */
>>    Locale.isLocaleSupported = function(code){
>>        ...
>>    };
>>
>>    /*
>>     * Replaces supportedLocalesOf
>>     * @param code The code to check.
>>     * @return Array of supported locales.
>>     */
>>    Locale.getSupportedLocales = function(code){
>>        ...
>>    };
>>
>>    /*
>>     * Replaces Globalization.Collator
>>     * @param a The first item.
>>     * @param b The second item.
>>     * @param options (Optional) The options to use when comparing.
>>     * @return -1 if a comes before b, 0 if they're equal, 1 otherwise
>>     */
>>    Locale.prototype.compare = function(a, b, options){
>>        ...
>>    };
>>
>>    /*
>>     * Replaces Globalization.NumberFormat
>>     * @param format A pattern format string for outputting the number.
>>     * @param value The value to format.
>>     * @return The number formatted as a string.
>>     */
>>     Locale.prototype.formatNumber = function(format, value){
>>        ...
>>    };
>>
>>    /*
>>     * Replaces Globalization.DateFormat
>>     * @param format A pattern format string for outputting the date.
>>     * @param value The date to format.
>>     * @return The number formatted as a string.
>>     */
>>    Locale.prototype.formatDate = function(format, value){
>>        ...
>>    };
>>
>> You would then be able to create a single Locale instance and have that
>> be used in your script. If the constructor is used without an argument,
>> then default locale information is used:
>>
>>    var locale = new Locale();
>>
>> If you provide a code, then that is used:
>>
>>    var locale = new Locale("en-us");
>>
>> If you provide multiple codes, then the first supported one is used:
>>
>>    var locale = new Locale(["en-us", "en-gb"]);
>>
>> Then, you can use that locale information for the other operations you
>> want to do:
>>
>>    locale.formatDate("DMYs-short", new Date());
>>    locale.formatNumber("##.##", 55);
>>    locale.compare("foo", "bar");
>>
>> By the way, not saying this is the format pattern string that should be
>> used, it's just for discussion.
>>
>> I like having a single object to deal with instead of multiple for
>> everything the API is trying to do. It seems a lot more intuitive than
>> needing to manage a LocaleList that is passed into new instances of
>> NumberFormat and DateFormat all the time (that's a bunch of housekeeping
>> for developers).
>>
>> Thoughts?
>>
>> -Nicholas
>>
>>
>>
>>
>> On 11/21/2011 11:12 AM, Nicholas C. Zakas wrote:
>>
>>> As promised, more verbose feedback for the Globalization API. My general
>>> feeling is that the API is overly verbose for what it's doing. I'll state
>>> my bias up front: I'm not a fan of introducing a bunch of new types to
>>> handle formatting. I'd much rather have additional methods that perform
>>> formatting on existing objects. My feedback is mostly about eliminating the
>>> new constructors - which has an added bonus of eliminating the
>>> Globalization namespace because there would be only one constructor left:
>>> Collator.
>>>
>>> 1. LocaleList
>>>
>>> I'm not sure why this type is necessary. I don't believe that locale
>>> resolution is an expensive operation, and even if it is, I'd expect the
>>> implementation to cache the results of such resolution for later use. I'd
>>> just leave this as an internal construct and instruct developers to use
>>> arrays all the time.
>>>
>>> 2. supportedLocalesOf
>>>
>>> I find this method name strange - I've read it several times and am
>>> still not sure I fully understand what it does. Perhaps
>>> "getSupportedLocales()" is a better name for this method? (I always prefer
>>> methods begin with verbs.)
>>>
>>> 3. NumberFormat
>>>
>>> Number formatting seems simple enough that it could just be added as a
>>> series of methods on Number.prototype. The three types of formatting
>>> (currency, decimal, percent) could each have their own method. Currency
>>> formatting has relatively few options to specify, so it's method can be:
>>>
>>>    /*
>>>     * Formats the number as if it were currency
>>>     * @param code Currency code, e.g., "EUR"
>>>     * @param type (Optional) The way to format the currency code,
>>> "code", "symbol" (default),
>>>     * @param locales - (Optional) Array of locales to use.
>>>     */
>>>    Number.prototype.toCurrencyString = function(code, type, locales) {
>>>        ...
>>>    };
>>>
>>>    var num = 500;
>>>    console.log(num.toCurrencyCode("EUR", "code"));    //"EUR 500.00"
>>>
>>>
>>> Decimal and percent formatting options are slightly different in that
>>> they include significant digits options. For that, I prefer to use a
>>> formatting string rather than the multitude of optional properties as
>>> currently defined (see
>>> http://www.exampledepot.com/egs/java.text/FormatNum.html). The
>>> formatting string indicates must-have digits as 0 and optional digits as #,
>>> allowing you to very succinctly specify how you want your number to be
>>> output. For example:
>>>
>>>    /*
>>>     * Formats the number as a decimal string.
>>>     * @param format Format string indicating max/min significant digits
>>>     * @param locales (Optional) Array of locales to use.
>>>     */
>>>    Number.prototype.toDecimalString = function(format, locales){
>>>        ...
>>>    };
>>>
>>>    /*
>>>     * Formats the number as a percent string.
>>>     * @param format Format string indicating max/min significant digits
>>>     * @param locales (Optional) Array of locales to use.
>>>     */
>>>    Number.prototype.toPercentString = function(format, locales){
>>>        ...
>>>    };
>>>
>>>    var num = 1234.567;
>>>    console.log(numtoDecimalString("000##.##")); "01234.57"
>>>
>>> 4. DateTimeFormat
>>>
>>> As with NumberFormat, it seems like this could more succinctly be
>>> implemented as a method on Date.prototype. As its easiest:
>>>
>>>    /*
>>>     * Format a date
>>>     * @param options The already-defined options for DateTimeFormat
>>>     * @param locales (Optional) Array of locales to use.
>>>     */
>>>    Date.prototype.toFormatString = function(options, locales){
>>>        ...
>>>    };
>>>
>>> In an ideal world, I'd like to see options overloaded so it can be an
>>> options object as specified now or a formatting string. I understand that
>>> there was a sentiment against formatting strings due to their limitations
>>> and edge case errors. However, I'd like to point out that any
>>> internationalized web application is highly likely to already be using
>>> formatting strings for dates, since this is pretty much how every other
>>> language handles date formatting. That means supporting format strings in
>>> JavaScript would allow application developers to reuse the settings they
>>> already have. As it stands now, you'd need to create two different ways of
>>> formatting dates for a web app: one for your server-side language and one
>>> for your client-side language (until the day everything is running on
>>> Node.js, of course). I'd prefer my client-side code to reuse settings and
>>> configuration that the server-side code uses, otherwise I end up with two
>>> very different pieces of code doing the exact same thing, and there be
>>> dragons.
>>>
>>> -Nicholas
>>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
>
>  --
> Nebojša Ćirić
>
>
>


-- 
Nebojša Ćirić
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111123/4eef6cc1/attachment-0001.html>


More information about the es-discuss mailing list