On 11/30/2011 12:01 PM, Brendan Eich wrote:
On Nov 29, 2011, at 1:19 PM, Nicholas C. Zakas wrote:

The reason I started down this path is because the API, as currently designed, 
doesn't fit in with the rest of the JavaScript core language. Just to summarize 
some of my earlier points:

1) No part of core JavaScript uses namespaces today. Having a top-level 
Globalization object that [does] nothing other than provide a hook onto which 
new constructors are placed is a first and doesn't seem very useful. At the 
very least I'd consider killing the Globalization object altogether and just 
let the constructors exist in the global scope.
Injecting new names into the global scope is risky, since all the good names 
are already taking by user-defined globals.

The plan we discussed a few weeks ago was to use a built-in module, which could 
be imported from or declared freely in new opt-in code. Unversioned JS would 
have to use something like the

   Object.system.loadIntrinsic("@globalization")

API-sketch.

Whatever we do, it should be as future-friendly to modules as possible, and it 
shouldn't inject new global names into the shared scope of ES.next and 
unversioned scripts.
To make sure I understand, are you saying that all future ES functionality won't introduce new names into the global scope? And further, all new functionality would need to be loaded via a module?

2) The current proposal requires that developers maintain a LocaleList object 
and pass that into methods of NumberFormat, DateTimeFormat, and Collator 
(assuming they don't want to use the default). Needing to keep track of an 
object is a pain, but is lessened when that object does everything you need it 
to. That's why I suggested having a Locale object. Yes, you'd need to keep 
track of this object, but at least it would be one object instead of multiple 
objects.
This still seems plausible to me. It caters to Norbert's "Customer categories" 
1 and 2, if I'm not mistaken.
Which is plausible? The current proposal or my single-object proposal? :)



3) The semantic difference between DateTimeFormat.isSupported(), 
Locale.isSupported(), etc. is minimal. The point I was trying to make is that 
the current requirements for the Globalization API don't preclude having a 
single object. That's simply a design decision, not a huge barrier that can be 
overcome.
Mark's point about isSupported not being binary and simplex is good, 
independent of whether objects are grouped into a Locale or not. Again if I'm 
following correctly (please tell me if not).
Agreed, I was just brainstorming about ways to solve some of the issues being brought up. There do seem to be two categories of detection necessary for this API, one is binary (is Gregorian calendar supported) and one is best fit (what's the closest locale you can approximate).


Again, saying that "libraries will handle this" is too simple and presumptive. 
You're assuming that some library a) likes what you've done enough to invest in it, b) 
finds some advantage to this API over what it has already, and c) can integrate with what 
they already have. You could create an API that sits unused because libraries don't see 
any advantage to using it vs. what they have already.
Again I agree with you. The flip side is that, per Mark's fine message dated 
November 28, 2011 1:13:24 PM PST, internationalization is multi-state/best-fit 
and complex, with evolving big data, user preferences in the loop.

Doing a low-level built-in library and letting others built higher-level 
abstractions is plausible based on experience with things like canvas, WebGL, 
and typed arrays. We don't get to do the perfect high-level API on short 
notice, certainly not in committee. I'm skeptical we can even do a low-level 
toolkit by next spring, with two truly independent implementations 
interoperating convincingly.

So "libraries will handle this" is the wrong guiding principle, but "let's find the 
high-level sweet spot" is high-risk without more time for experimentation and user testing.
I definitely wasn't trying to suggest a truly high-level abstraction, but more a mid-level API that has some low-level characteristics and some high-level characteristics. Another way to say this is that the API makes the simple case simple ("hi! I'd just like to format a price for display") while allowing more complex cases through other means. I present XMLHttpRequest as a good example of a mid-level API, where it's easy to do a basic GET request but you can still do fancy things using CORS, binary data, HTTP streaming, etc.


I don't have any satisfying answers, but I hope this helps.

/be


-N


On 11/28/2011 4:17 PM, Norbert Lindenberg wrote:
I'm not sure why this discussion is drifting so far in the direction of a functional API. 
I thought objects, constructors, and methods are all part of ECMAScript, are widely used 
in the language specification, in libraries, and in applications, and developers have to 
understand them in order to be productive in JavaScript. So what is the advantage of 
isSupportDateTimeFormat(locale) or isSupported("DateTimeFormat", locale) over 
DateTimeFormat.isSupported(locale)?

I thought the real question is: How do we enable simpler code for the most 
common use cases? For example, don't require applications to create a 
DateTimeFormat object when it's only used once to format a date and then 
disposed of, or to specify a locale list to every API call when it never 
changes.

We should also consider what should be handled by the Globalization API, and 
what is better left to libraries. We tend to focus on the Globalization API in 
this discussion because that's what we can change directly, but I think default 
locale management is really better handled at a higher level. See
https://mail.mozilla.org/pipermail/es-discuss/2011-November/018665.html

Specific comments on Nicholas proposal:

- Extensibility is a big issue: What happens if two components within one 
application load two incompatible word break implementations - who wins, or is 
there a way to keep them separate?

- The existing locale and parameter negotiation won't work with other services: 
Our current negotiation mechanism knows a lot about collators and number and 
date formats, and nothing about other internationalization services, and it's 
not designed for adaptation to such other services. This means other services 
have to provide their own negotiation, but that conflicts with them being part 
of a single Locale object.

- Having the Locale object store the resolved locale doesn't work because the 
resolved locale can vary between services for the same requested locale list. 
It probably makes more sense for it to store the requested locale list, and use 
that to negotiate against each service's capabilities. That's the approach used 
in YUI internationalization:
http://yuilibrary.com/yui/docs/intl/

- The Locale object as proposed doesn't seem to help the application with 
managing its own resources. YUI, on the other hand, provides support for this, 
and it seems more logical to extend the locale management in YUI to also 
support the services provided by the Globalization API than to have two 
separate mechanisms. For example, it could complement its current number 
formatting with a new locale sensitive function:

Y.DataType.Number.localeFormat = function (data, options) {
     if (Y.Lang.isNumber(data)) {
         var localeList = Y.config.lang;
         if (!Y.Lang.isArray(localeList)) {
             localeList = localeList.split(/[, ]/);
         }
         return data.toLocaleString(localeList, options);
     } else {
         // do whatever Y.DataType.Number.format does in this case
     }
}

Overall I think a container like the proposed Locale object may make sense at 
the application level, but doesn't seem like the right approach for the 
Globalization API.

Regards,
Norbert



28. новембар 2011. 11.27, Nicholas C. Zakas<standa...@nczconsulting.com>   је 
написао/ла:
On 11/28/2011 9:15 AM, Nebojša Ćirić wrote:
It's my fault - I read "discussed with Norbert" as if you and Norbert agreed on 
this approach.
No worries - email is hard. :)


We are essentially choosing beween two approaches:

1. Create an object, query its properties, use object methods (original 
approach)
2. Create Locale object, call various methods like isSupportedXXX, if service 
is supported use formatYYY or compare

They are very similar in what the user has to do (query capabilites, call 
formatters) to get the final result, so I don't think we would lose any 
functionality picking any of those.

With 1. we might end up having lots of isSupportedDate, isSupportedNumber... 
after couple of iterations of adding new features (like segmentation, 
calendars, spell check...), but if we follow the same naming style I don't see 
a problem with that.
Another approach would be to have a single isSupported() method with constants 
that you pass in. That limits the overall API size while still allowing 
developers to query capabilities. The DOM has something similar, though I think 
the globalization use case is much more appropriate: 
http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMFeatures

What would be harder for a third party developer to extend:

isSupported('x') or isSupportedX()

This in case they wanted to provide a service which native implementation 
doesn't support (yet).


As for the namespace issue, I don't see much difference between Locale and 
Globalization. We discussed Modules on the other thread and came up with:

Object.system.load('@g11n', callback()) {}

or synchronous call

var global = Object.system.load('@g11n') {
   return __Globalization__;
}

This would become module global import '@g11n' in the future. This approach 
eliminates the need of finding proper name for the namespace (and possibly for 
Locale()?).
There's a difference between creating a new native type vs. creating a 
namespace. The Locale approach creates a single top-level type and no other 
constructors. The current approach, Globalization.*, uses Globalization only as 
a namespace and has constructors hanging off of it - this isn't something 
that's currently done in ECMAScript.

Thank you for helping out. Your proposal is exactly what we need at this point 
- to help us refine our work and make it palatable to TC39 members :).
My pleasure!


24. новембар 2011. 16.47, Nicholas C. Zakas<standa...@nczconsulting.com>   је 
написао/ла:
Again, my apologies - I didn't mean to imply that Norbert agreed with any of 
this, just that a few ideas have been more solidified in my mind after speaking 
with him.

As a web developer who has built large-scale web sites that have been 
internationalized to dozens of countries, my main purpose in contributing to 
this discussion is to provide feedback on what I would have liked to see in 
such an API to make it useful to me.

The current proposal doesn't feel very JavaScript-like, and so I've been trying 
to offer alternatives that make it more JavaScript-like and, therefore, more 
likely to be used by more developers. I'm a bit concerned that design decisions 
seem to have been guided by considering the most complex use cases instead of 
the most common.

It is my opinion (and I can only speak for myself) that a single object to 
encompass  would represent a better API for JavaScript than adding a namespace, 
which hasn't been done to this point, and several new types, all of which just 
do one thing. That's a very Java-like approach, and I think JavaScript deserves 
better.

As I told Norbert, I'm very happy to lend my experience and insights to this process. I 
realize I may end up bringing things up that you all have discussed before - but 
considering that you did have a single Locale object at one point, I'd like to claim 
"great minds" think alike and continue discussing it. :)

Happy Thanksgiving.

-Nicholas



On 11/24/2011 2:44 PM, Norbert Lindenberg wrote:
I didn't agree with this approach, and Nicholas didn't claim that I did :-)

I'm very glad though that Nicholas is taking the time to provide feedback, come 
up with his own ideas, and discuss them with us. In the end, the Globalization 
API can only be successful if people like him are comfortable using the API in 
their projects, and explain it to others so that they're comfortable doing so. 
Right now, the feedback from him, Rick, several TC39 members, and others 
indicates significant discomfort, so we have some work to do. Some of that work 
may be changes to the API, but some may also be better explanation of how to 
use the API, directly from applications or in higher-level libraries.

More after Thanksgiving.

Norbert


On Nov 23, 2011, at 15:15 , Nebojša Ćirić wrote:


23. новембар 2011. 14.32, Nicholas C. Zakas<standa...@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<standa...@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@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss



--
Nebojša Ćirić



--
Nebojša Ćirić
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss





--
Nebojša Ćirić


--
Nebojša Ćirić
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to