-
Notifications
You must be signed in to change notification settings - Fork 106
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
Extend Formatters to allow for token formatting #30
Comments
I'm not sure about this at first glance, but it seems that we have some similarities between what you describe here and what a tagged template string does (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings#Tagged_template_strings), which ultimately give you more control over the formatting of the final output. Maybe we should think in those terms instead of introducing yet another template form. Aside from that, having the custom |
I agree, I didn't spend too much time thinking about how the API should look like, and I'd be happy to reuse template strings as long as it allows for token formatting in datetime string construction. You're also correct about format in constructor, but I would say that it may be a good tradeoff. Formatters should be consistent and if a customer needs to produce two different strings according to different formattings, he may need two different formatters. |
ICU (and Java) use a
Not sure what the right idiom is, but that's conceptually the data you might want. THen you can do whatever with the result. |
Awesome! @caridy - do you have any preference on how the API should look like? I definitely like the formatting to be on |
let me ask around tomorrow, and see if someone has a good idea about the API. I'm ok with a second argument, but I'm not ok mutating that argument as proposed above. |
Ok, so would you prefer the approach proposed by @srl295 - we return the start and end indexes of the tokens? |
@srl295 , @caridy : I wrote a patch proposal for the spec to add Can you tell me how does it look at what's the next step? I need to get something in our platform soon and would like to make it in line with the committee thinking about this feature. |
And here is the patch for |
First thing first, we need to agree on the API first. I know I dropped the ball on this one since it wasn't at the top of my list, but I can certainly spend some time on this api this week. Please, add a comment here with the exact change (minimum amount of text) so we can discuss it, reading the spec diff :) to understand the proposal is not optimal. |
Sure! The proposal is to add an optional, second argument for Example:
I considered using a separate function, but felt like it's easier to extend what [0] http://icu-project.org/apiref/icu4c/classicu_1_1DateFormat.html#a620a647dcf9ea97d7383ee1efaf182d1 |
Oh, and the reason I went for |
@zbraniecki few notes:
|
Yeah, as I'm playing with it, I am changing my mind, how about:
Alternatively we could do |
Here's |
For C++, I'm using My suggestion is to map it to field names this way:
and ignore the rest for now. [0] http://www.icu-project.org/apiref/icu4c/udat_8h.html#a4bc9d9661c115dcb337803bc89730b3a |
@caridy - what do you think about |
Here's the proposal for ecma402 spec patch to add this: https://github.com/zbraniecki/ecma402/tree/dtwithposition Opinions? @caridy , @rwaldron , @srl295 , @domenic, @rxaviers ? It's kind of top priority for me because without that our platform has very hacky solution to style tokens in time strings and we do this in multiple places. The result is that in some locales our UI is broken and I'd like to get this feature landed for the next release. |
@zbraniecki, @caridy and I spent some time discussing this today. The first thing is we both agree that the ability to do "rich-text" formatting is an important feature. I had the same initial thought as @caridy about how this feels similar to a template literal tag function… but after going further and prototyping how a library like react-intl would use this we landed on something slightly different from your proposal. Instead of having a fully formatted string with a collection of positions, we ended up wanting an array for formatted part descriptors. let dateFormat = new Intl.DateTimeFormat('en');
let date = Date.now();
let formattedDate = dateFormat.formatToParts(date)
.map(({value}) => value)
.reduce((string, part) => string + part);
let fancyFormattedDate = dateFormat.formatToParts(date)
.map(({type, value}) => {
switch (type) {
case 'month': return `<b>${value}</b>`;
default : return value;
}
})
.reduce((string, part) => string + part);
console.log(dateFormat.format(date)); // "10/30/2015"
console.log(formattedDate); // "10/30/2015"
console.log(fancyFormattedDate); // "<b>10</b>/30/2015" The bikeshed hasn't been painted here yet, but we think having an array of formatted part descriptors like this makes it easier to process each part and put them back together in a final string than trying to use substrings on positions. The parts can be processed left-to-right without worrying about throwing off the position indexes of the following parts when modifying the current part; e.g., wrapping it with HTML. For the example above, the array of part descriptors might look something like this: [
{
type: 'month',
value: '10',
},
{
type: 'separator',
value: '/'
},
{
type: 'day',
value: '30',
},
{
type: 'separator',
value: '/'
},
{
type: 'year',
value: '2015',
}
] Note how the |
To add to that, we think |
Awesome! Thanks a lot for this brainstorming. I love the API and I'll be happy to update my proposal to it. One question about naming of That's unfortunately a little bit more complex to implement and I'm wondering how you'd like to approach.
Both approaches make it easy to index positions of date time components, but not much for the separators. While ICU returns "timeSeparator" field [0], everything else is a fair game. It's hard to know if the separator between day and month will be Because of that, would you just want to use a generic term [0] http://www.icu-project.org/apiref/icu4c/udat_8h.html#a4bc9d9661c115dcb337803bc89730b3a |
I'm not sure I follow your question, but I can tell you that |
@caridy I think the concept of @zbraniecki Are you thinking we'd need something like this? {
type: 'field',
field: 'month',
value: '10'
} |
No, what I meant is that I'm not sure if "Wednesday, 03/2015 12:32 am" should be reported as:
or should we try to name separators like So the question @caridy asked stays - type |
I got Intl.js polyfill to support the proposed |
@zbraniecki I'm wondering how LRM ( I'm not an expert how these bidi markers actually work and what happens when we process the parts by wrapping them with a span. e.g.: new Date(0).toLocaleString("ar",{month:"numeric",day:"numeric",year:"numeric"}).replace(/\u200F/g, '[RLM]');
// "٣١[RLM]/١٢[RLM]/١٩٦٩" If we wanted to bold the month and create an HTML string, would the marker be part of the This is related to: #28 |
I believe that the snippets I provided are the closest thing we can do to locale-independant behavior. It may have exceptions (which may need My understanding is that the API provides the lowest common denominator and allows for higher level APIs to be built on top. |
Spec discussion: tc39/ecma402#30 It's in stage 4 and Firefox has already implemented it. For now, it's added to HARMONY_IN_PROGRESS bucket behind '--datetime-format-to-parts' flag. BUG=v8:5244 TEST=intl/date-format/date-format-to-parts.js TEST=test262/intl402/DateTimeFormat/prototype/formatToParts/* Review-Url: https://codereview.chromium.org/2273953003 Cr-Commit-Position: refs/heads/master@{#39225}
Move it to HARMONY_STAGED bucket Spec discussion: tc39/ecma402#30 It's in stage 4 and Firefox has already implemented it. BUG=v8:5244 TEST=intl/date-format/date-format-to-parts.js TEST=test262/intl402/DateTimeFormat/prototype/formatToParts/* Review-Url: https://codereview.chromium.org/2317783003 Cr-Commit-Position: refs/heads/master@{#39258}
|
|
We're waiting for second vendor to step in now. @jungshik, @littledan - do you know if there's a chance to get this into V8 even in an experimental form so that Google would be comfortable recommending it for stage4? The last call to get this into 4th edition is probably at January's TC39 meeting. |
Move Intl.DateTimeFormat.formatToParts() to HARMONY_SHIPPING bucket. Spec discussion: tc39/ecma402#30 It's in stage 4 and Firefox shipped it in Firefox 51.0. ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/formatToParts#Browser_compatibility ) BUG=v8:5244 TEST=intl/date-format/date-format-to-parts.js TEST=test262/intl402/DateTimeFormat/prototype/formatToParts/* Review-Url: https://codereview.chromium.org/2585903002 Cr-Commit-Position: refs/heads/master@{#41871}
@zbraniecki Looks like the ICU part has its upstreaming still in progress. It'll be easier for us to implement in V8 after that's done. Is there any particular reason why it has to get to Stage 4 at this meeting? Could we wait for a V8 implementation until the ICU side work is more mature? |
Yeah, certainly. I do think about ES releases as milestones, mostly because that's how the market treats them. While I'm not worried about V8 shipping features quickly, I believe that if we miss the train for ES2017 with My hopes were for those two features to be in a good shape for stage 4 in time for ES2017. If you believe that it's not worth it and if you don't share my worry about market adoption, I trust your experience on the matter. |
I think you've been doing a good job building towards getting browsers to support this by making sure there's an implementation in Mozilla and getting the ICU part upstreamed properly. I haven't seen a lot of evidence that browsers are waiting for the annual cutoff to implement features, on the other hand. I am not sure how long it will take for people to be able to depend on the feature--IE11 will probably never support it, but that browser may be in use for some time. |
Note that ICU is NOT a blocker for v8 because v8 does not plan to use ICU's C API. The ICU change made by Mozilla is just to port an existing C++ API to C API. What I'm not yet 100% sure is the practical usefulness of NumberFormt.formatToParts (and I haven't fully digested the proposed API, yet) |
Hi all, @littledan pointed out that we failed to document the rationale for the decision to add We did talk about it quite a bit during TC39 meetings, and showed examples as we were requesting the stage advancements, but never wrote down the rationale, so here's my attempt to capture the spirit of it for the record:
At the beginning, in September 2015, we discussed several approaches to allow for internationalization-friendly rich formatting of the data formatted by the Intl formatters. It was fairly clear to all of us (@ericf, @caridy, @stas, @srl295 and me) that we're aiming at the most simple, chainable, solution that will allow users to achieve the simple, most common, tasks easily, while allowing more complicated ones if needed (with accompanying complexity). The feature request was based on my experience of working on Firefox OS where we encountered a number of UX/design requirements for rich formatting including:
The initial focus, due to requirements of my use case project, were primarily focused on DateTimeFormat API, but alongside, @stasm wrote the spec proposal for the corresponding NumberFormat API. On October 30th 2015, @ericf came up with an API that serves the need elegantly in our opinion allowing for any call to
Although secondary to the first reason, I believe it's worth bringing up the principle of least astonishment. Known limitation: The The difference is that the former tokenization allows to tokenize the whole integer, although in a bit awkward way, while the latter does not allow for the styling of each component. ICU provides an API that allows to workaround this challenge by producing overlapping list of tokens where you can get start/end positions for both, the whole integer and its components. In the end, we ( @srl295 , @caridy , @ericf , @stasm and me) came to conclusion, that while such API may be useful, it's a separate API and should not be using I hope it helps! |
|
I took the liberty to update this issue description and include the proposal link. |
@zbraniecki can you add the agenda item for this? If you don't plan to be in the next meeting (Boston) I can do the update. Also, we need to work on the spec text, to get the PR ready before the next meeting, many things has changed since the revert, and we need to work things out. |
@stasm would you be interested in updating your PR to the current master? |
`Intl.NumberFormat.formatToParts` was first propsed in tc39#30. The spec for it was created in tc39#79 and merged in tc39#100. Due to browser implemantations not being ready at the time, it was moved back to Stage 3 in tc39#101. The internal refactorings were kept in master and the user-facing method `formatToParts` was removed from the spec in tc39#102. As of August 1st, 2017, `Intl.NumberFormat.prototype.formatToParts` has shipped in two engines (behind a flag): SpiderMonkey and V8. This PR brings `Intl.NumberFormat.formatToParts` back as Stage 4 proposal. > const usd = Intl.NumberFormat('en', { style: 'currency', currency: 'USD' }); > usd.format(123456.789) '$123,456.79' > usd.formatToParts(123456.789) [ { type: 'currency', value: '$' }, { type: 'integer', value: '123' }, { type: 'group', value: ',' }, { type: 'integer', value: '456' }, { type: 'decimal', value: '.' }, { type: 'fraction', value: '79' } ] > const pc = Intl.NumberFormat('en', { style: 'percent', minimumFractionDigits: 2 }) > pc.format(-0.123456) '-12.35%' > pc.formatToParts(-0.123456) [ { type: 'minusSign', value: '-' }, { type: 'integer', value: '12' }, { type: 'decimal', value: '.' }, { type: 'fraction', value: '35' }, { type: 'literal', value: '%' } ]
`Intl.NumberFormat.formatToParts` was first propsed in tc39#30. The spec for it was created in tc39#79 and merged in tc39#100 (with follow-ups). Due to browser implementations not being ready at the time, it was moved back to Stage 3 in tc39#101. The internal refactoring were kept in master and the user-facing method `formatToParts` was removed from the spec in tc39#102. As of August 1st, 2017, `Intl.NumberFormat.prototype.formatToParts` has shipped in two engines (behind a flag): SpiderMonkey and V8. This PR brings `Intl.NumberFormat.formatToParts` back as Stage 4 proposal. > const usd = Intl.NumberFormat('en', { style: 'currency', currency: 'USD' }); > usd.format(123456.789) '$123,456.79' > usd.formatToParts(123456.789) [ { type: 'currency', value: '$' }, { type: 'integer', value: '123' }, { type: 'group', value: ',' }, { type: 'integer', value: '456' }, { type: 'decimal', value: '.' }, { type: 'fraction', value: '79' } ] > const pc = Intl.NumberFormat('en', { style: 'percent', minimumFractionDigits: 2 }) > pc.format(-0.123456) '-12.35%' > pc.formatToParts(-0.123456) [ { type: 'minusSign', value: '-' }, { type: 'integer', value: '12' }, { type: 'decimal', value: '.' }, { type: 'fraction', value: '35' }, { type: 'literal', value: '%' } ]
|
two years, yay! merged fe7b0a4 |
With https://hg.mozilla.org/integration/autoland/rev/353baf72f789 landed, SpiderMonkey now exposes both without any flag. |
UPDATE:
DateTimeFormat and NumberFormat are design to provide an opaque string as an output that is not meant to be manipulated by the consumer.
Unfortunately, that is impossible if one needs to format the output and that currently forces very dirty solutions that may break internationalization.
Example use case, is formatting minutes token to be smaller or different color than hours in hour:minute string.
Modern user interfaces do that all the time - examples are Material Design in Android, modern Windows Mobile UI and PS4.
My proposal is to allow for token format strings to be available as option for the formatter. It could look like this:
For non HTML outputs, the formatting may involve console formatting characters for terminal UI apps.
The text was updated successfully, but these errors were encountered: