Hi,
I have a strong concern about the i18n API throwing an exception when an
unknown value is given as part of the option parameter for a constructor or
function.
For example, if I do:
new v8Intl.DateTimeFormat(x, {year: "long"});
or:
x.toLocaleTimeString("en", {year: "long"});
I get in Chrome:
"RangeError: Value long out of range for dateformat options property year".
Obviously, the above being that "year" cannot be "long".
Regardless, shouldn't bogus option values just be ignored for backwards compat?
Lets say a new type is added for any of the options supported by the spec… then
that new type will break backwards compat with old versions of the API.
Bogus hypothetical example - ES i18n.next introduces "formal", where the day
always has the first letter capitalised:
{day: "formal"}
Because of this throw behaviour, the introduction of "formal" in a future spec
would potentially break all existing implementations today. If this behaviour
is left as is, (1) all calls to the i18n API will need to be wrapped in
try/catch (as a preemptive measure as the introductions of a new option value
would cause a throw). As a side effect, (2) users on old browsers could be
negatively impacted in the future without the knowledge of the developer.
For the case of (1), developers may not even be aware that the API throws (or
has thrown) for a particular set of users using an outdated browser - I
personally found that it throws by accident. This would lead to (2), which
unfairly punishes users without the developer's knowledge - causing the
application to potentially stop working all together if the exception is not
caught.
IMHO, falling back to defaults, or by ignoring bogus values, would make the API
degrade gracefully without negatively impacting users (that is something I
really like about the API today - it does that if you feed it bogus language
tag or bogus option it does not understand). I think it should be the same for
option values.
I would also argue that having the above throw is inconsistent with the rest of
the API. The API already provides nice fallbacks to defaults in most cases. For
example, today (without i18n API support), calling any of the to*LocaleString()
simply "just works" - overcoming side-effect 2 above and not punishing users
with an exception. I think most developers would expect that kind of fallback
behaviour - you are guaranteed to get a date/time/number that the user will
understand (even if it's not as pretty as a custom formatted one):
x.toLocaleTimeString("en", {foo: "bar"})
//"12:00:00 AM"
x.toLocaleTimeString("klingon", {foo: "bar"})
//"12:00:00 AM"
…and so on… which is a great graceful fallback behaviour .
If the spec authors want to "warn" developers that they've used an unsupported
option value, maybe put into the spec to call "console.warn()" or similar, if
available. That allows developers to know they've used something
unsupported/unknown/or misspelled without punishing users - mobile safari and
Chrome do this already for meta-viewport values, so there is some helpful
precedence here. Yes, relying on "console.warn" is non standard, but this could
just be specified as non-normative text by just saying where appropriate in the
spec:
"Optionally, warn the developer that the option value is unsupported by, for
example, calling console.warn() or similar if available to the implementation."
I think all modern browsers support the console object, and so does Node.js.
On the other hand, if the developer wants to check if what they inputed as
options is supported by the API, they can call .resolvedOptions() and manually
verify that all their options were understood by the browser. So:
var formatter = new v8Intl.DateTimeFormat(x, {day: "formal"}),
options = formatter.resolvedOptions();
if(options.day !== "formal"){
//no formal support, need to use something else
options.day = "long";
formatter = new v8Intl.DateTimeFormat(x, options),
}
… continue…
Note that there is precedence also in other APIs to not throw exceptions on
bogus options. For example, the Geolocation API does not throw in the following
cases and simply "just works" (tested in Chrome):
var l = function(e){console.log(e)};
navigator.geolocation.getCurrentPosition(l, l, {maximumAge:"bananas"});
navigator.geolocation.getCurrentPosition(l, l, {maximumAge:Node})
navigator.geolocation.getCurrentPosition(l, l, {maximumAge:{}})
Kind regards,
Marcos
--
Marcos Caceres
http://datadriven.com.au
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss