Open FrankYFTang opened 4 years ago
Two potential issues which can make the transition to Intl.ListFormat
a bit harder than expected:
How to handle the options
parameter? Should it apply only to the individual array elements or also to the implicitly constructed ListFormat
?
options
parameter to apply to Intl.ListFormat
object, because some property names like "style"
can have different meanings for the ListFormat
and for the elements, cf. [1].toLocaleString("en", {style: "percent"})
.The current Array.prototype.toLocaleString
specification ensures all elements are always separated with the same delimiter. This won't be the case anymore when ListFormat
is used. Here's an example using English, German, and French which shows that there's no type
/style
combination which ensures only a single delimiter is used between elements for all locales.
for (let locale of ["en", "de", "fr"]) {
for (let type of ["conjunction", "unit"]) {
for (let style of ["long", "short", "narrow"]) {
print(`${locale} (${type}-${style}):`, new Intl.ListFormat(locale, {type, style}).format(["1", "2"]))
}
}
}
ChakraCore uses LOCALE_SLIST, which can give better output for certain locales and element types (or more specifically: numbers). LOCALE_SLIST
is similar to numbers/symbols/list
in CLDR.
Intl.ListFormat
.)How to handle the options parameter?
This is a great question that I don't have an immediate answer to. One possible solution: namespace the child options like so:
[1].toLocaleString("en", {
numberOptions: {
style: "percent"
}
});
~Note: although the spec currently says that the options should be passed down verbatim, it seems that web reality at least in Chrome 80 is that we don't actually pass any options into the child toLocaleString calls. [9999].toLocaleString({ style: "percent" }) => "9,999" // Chrome 80
~
The current Array.prototype.toLocaleString specification ensures all elements are always separated with the same delimiter.
Right; this would be a normative change that we would just need to make sure everyone can agree to.
Note: although the spec currently says that the options should be passed down verbatim, it seems that web reality at least in Chrome 80 is that we don't actually pass any options into the child toLocaleString calls.
The example is missing the locales
argument. When using [9999].toLocaleString("en", { style: "percent" })
, I get a percent formatted result in V8, JSC, and SpiderMonkey.
Thanks, yes, my bad >_>
Good catch, @FrankYFTang . I agree this should be addressed. Some ideas about the issues @anba raised:
listOptions
or something like that, which we Get
out of the options bag and pass to the ListFormat
constructor.
B: Add a second options argument. (This could be pretty hard to read since they're distinguished only positionally, and also it's not analogous to anything else.)
Subjectively, I prefer the A. (This whole path feels funny to me given https://github.com/tc39/proposal-intl-list-format/pull/7 , and I wish I had considered it when making that decision... maybe Intl.ListFormat should always do options processing this way, and send each element through toLocaleString
? Though it's rather late for this kind of change.)","
. I want to just cross my fingers and hope that this change is web-compatible enough...How about this?
locale = "en";
opt = { style: "currency", currency: "TWD",
timeZone: "Asia/Taipei", dateStyle: "long",
listStyle: "short", type: "conjunction" };
[new Date(), 1234, 567, new Date()].toLocaleString(locale, opt)
currently, in Chrome we got 'October 9, 2021,NT$1,234.00,NT$567.00,October 9, 2021'
so the above is equlivent to
(new Intl.ListFormat(locale, {style: opt.listStyle, type: opt.type})).format(
[(new Date()).toLocaleString(locale, opt),
Number(1234).toLocaleString(locale, opt),
Number(567).toLocaleString(locale, opt),
new Date().toLocaleString(locale, opt)]
)
the above right now in Chrome output
'October 9, 2021, NT$1,234.00, NT$567.00, & October 9, 2021'
and we construct a listOption as {type: type, style: listStyle} to pass to ListFormat?
We discuss this in TG2 today (2021-11-04). I feel it might be an issue much more complicated than I expected and would like to park this issue and let other drive it they feel interest. People can still use Intl.ListFormat to do what they like to do and I think the possibility option conclit between different types of items is way too complicated and probably a good idea to just keep the status quo.
Maybe we should consider just deprecating Array.prototype.toLocaleString.
I think we have a general agreement that the output of toLocaleString
is locale and platform dependent and should not be depended upon? Due to this assumption I'm still in favor of doing this at some point.
Currently, there is a section in ECMA402 about Array.prototype.toLocaleString https://ecma-international.org/ecma-402/#sup-array.prototype.tolocalestring
With the newly Stage 3 Intl.ListFormat moving to Stage 4, we should consider to rewrite that section to delegate the behavior to Intl.ListFormat