Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Array.prototype.toLocaleString to use ListFormat #422

Open
FrankYFTang opened this issue Mar 31, 2020 · 10 comments
Open

Change Array.prototype.toLocaleString to use ListFormat #422

FrankYFTang opened this issue Mar 31, 2020 · 10 comments
Labels
c: text Component: case mapping, collation, properties Proposal Larger change requiring a proposal s: comment Status: more info is needed to move forward

Comments

@FrankYFTang
Copy link
Contributor

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

@anba
Copy link
Contributor

anba commented Mar 31, 2020

Two potential issues which can make the transition to Intl.ListFormat a bit harder than expected:

  1. How to handle the options parameter? Should it apply only to the individual array elements or also to the implicitly constructed ListFormat?
    • I'll guess I can answer this myself: I don't think we can reuse the 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"}).
  2. 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"]))
    }
  }
}

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

@sffc sffc added c: text Component: case mapping, collation, properties s: discuss Status: TG2 must discuss to move forward labels Apr 2, 2020
@sffc
Copy link
Contributor

sffc commented Apr 2, 2020

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.

@anba

This comment has been minimized.

@sffc

This comment has been minimized.

@littledan
Copy link
Member

Good catch, @FrankYFTang . I agree this should be addressed. Some ideas about the issues @anba raised:

  1. I agree with your analysis. The two options I see here are
    A: Add an options bag entry for 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 Fix two normative issues proposal-intl-list-format#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.)
  2. Yes, this would be a change. For better or worse, the current browser engines agree that the separator should be ",". I want to just cross my fingers and hope that this change is web-compatible enough...
  3. I like the idea of adding an option to Intl.ListFormat to ask for a number list mode; I'm skeptical of deciding on this mode automatically.

@FrankYFTang
Copy link
Contributor Author

FrankYFTang commented Oct 8, 2021

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?

@FrankYFTang
Copy link
Contributor Author

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.

@sffc sffc added s: help wanted Status: help wanted; needs proposal champion and removed s: in progress Status: the issue has an active proposal labels Nov 6, 2021
@sffc sffc removed this from the ES 2022 milestone Nov 6, 2021
@sffc
Copy link
Contributor

sffc commented Nov 6, 2021

@sffc sffc removed s: help wanted Status: help wanted; needs proposal champion Small Smaller change solvable in a Pull Request labels May 19, 2022
@sffc sffc added s: comment Status: more info is needed to move forward Proposal Larger change requiring a proposal labels May 19, 2022
@sffc
Copy link
Contributor

sffc commented Jul 12, 2022

Maybe we should consider just deprecating Array.prototype.toLocaleString.

  1. It is more clear and explicit for people to use Intl.ListFormat
  2. There are likely people who depend on Array.prototype.toLocaleString having its current behavior
  3. No great solution to the conflicting options issue discussed above

@ryzokuken
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: text Component: case mapping, collation, properties Proposal Larger change requiring a proposal s: comment Status: more info is needed to move forward
Projects
Archived in project
Development

No branches or pull requests

6 participants