Globalization API Feedback - moar!

Nicholas C. Zakas standards at nczconsulting.com
Wed Nov 23 14:32:02 PST 2011


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.

> 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.

>
> 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.

>
> 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.

>
> 23. новембар 2011. 12.09, Nicholas C. Zakas 
> <standards at nczconsulting.com <mailto: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 <mailto:es-discuss at mozilla.org>
>     https://mail.mozilla.org/listinfo/es-discuss
>
>
>
>
> -- 
> Nebojša Ćirić

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111123/7202ae53/attachment-0001.html>


More information about the es-discuss mailing list