Skip to content
This repository has been archived by the owner on May 23, 2019. It is now read-only.

How about ordinals? #84

Closed
carystanley opened this issue Nov 26, 2014 · 22 comments · Fixed by #102
Closed

How about ordinals? #84

carystanley opened this issue Nov 26, 2014 · 22 comments · Fixed by #102
Assignees

Comments

@carystanley
Copy link

It would be great if intl-messageformat supported ordinal numbers:

1st, 2nd, 3rd, 4th, 10th, 11th, 12th, 13th, 52nd, 53rd, etc...

Here is a really simple version of the logic:

    function ordinal_suffix(num) {
        var s = ["th", "st", "nd", "rd"],
            v = num % 100;
        return num + (s[(v - 20) % 10] || s[v] || s[0]);
    }

I am unsure if ordinal works differently in other languages besides english

@caridy
Copy link
Collaborator

caridy commented Nov 27, 2014

@carystanley that's exactly right. To implement ordinals we need to use CLDR to produce the logic per locale. this is not the first time we get this feature requests, we will evaluate it, but it doesn't belong to this repo for sure since ICU message format does not support ordinals, just like it doesn't support relative time, we can also push for that in that front.

@ericf
Copy link
Collaborator

ericf commented Nov 27, 2014

I did some research and the CLDR has Rule-Based Number Format (RBNF) data, which includes spellout ("three") and ordinal ("3rd"). As of CLDR v26, these rules are defined in ICU Message syntax — which is just like how our Intl RelativeFormat's data is defined and works.

I see a few ways we could implement ordinals:

1) Add support for selectordinal to IntlMessageFormat:

This would be the easiest to implement, and not add any extra locale data to the library, but it would force the translators to add the correct ordinal suffix inside the optional parts of the messages, e.g.:

Go to the {floor, selectordinal,
  =0 {ground} 
  one {#st} 
  two {#nd}
  few {#rd}
  other {#th}
} floor.

2) Create an IntlRuleBasedNumberFormat lib, use externally:

To support automatic ordinal formatting leveraging the rules built into CLDR, we could create a new IntlRuleBasedNumberFormat, and like IntlRelativeFormat it would be used externally from the ICU Message string; i.e., you would format the value using IntlRuleBasedNumberFormat before passing it to the IntlMessageFormat instance, e.g.:

Go to the {floor} floor.
var msg  = new IntlMessageFormat('Go to the {floor} floor.', 'en');
var rbnf = new IntlRuleBasedNumberFormat('en', {style: 'ordinal'});

var output = msg.format({
    floor: rbnf.format(3)
});

console.log(output); // => "Go to the 3rd floor."

The benefit of this approach is that it doesn't add k-weight to IntlMessageFormat — just like how relative time formatting is separate. The downside is that it's not built into IntlMessageFormat, therefore deviates from the standard ICU Message. That said, at the end of the day, it would still be built into react-intl, handlebars-intl, and dust-intl :-/

Using this external approach in templates would look like this; e.g., in Handlebars:

{{formatMessage (intlGet "messages.floor")
  floor=(formatOrdinal 3)
}}

3) Create an IntlRuleBasedNumberFormat lib, use internally:

The last option would be like option 2) and create a new IntlRuleBasedNumberFormat lib, but also have IntlRelativeFormat depend on it and use it internally — just like it does for Intl.NumberFormat and Intl.DateTimeFormat.

The difference with this approach is that it would add k-weight to the intl-messageformat package both in terms of the runtime, and the locale data. This approach would allow for the ordinal argument type to be used within the ICU Message strings; e.g.:

Go to the {floor, ordinal} floor.

Edit: The ICU Message syntax defines ordinal as an argument type; we just don't currently support it in our implementation.


What do you guys think?

@juandopazo
Copy link
Contributor

It looks like Intl.MessageFormat needs a plugin system.

@caridy
Copy link
Collaborator

caridy commented Nov 28, 2014

@juandopazo we don't need a plugin system, we just need to convince ICU folks that {floor, ordinal} makes sense, just like {floor, number} does it :)

@ericf my vote goes to option 2, which will pave the way to option 3, just like we did for relative, and we can engage with ICU to try the waters there.

@ericf
Copy link
Collaborator

ericf commented Nov 28, 2014

@caridy @juandopazo I wasn't clear before, but ordinal is an argument type defined by the ICU Message syntax; we just don't currently support it in our implementation. I edited option 3 above to make this clear. So there's no need to convince the ICU folks, they already support it 😄

If you look at the details of the ICU Message syntax, you'll see they have support for selectordinal, ordinal, and spellout argument types — all of which we don't currently support. Note that choiceStyle and ChoiceFormat have been deprecated.

@caridy
Copy link
Collaborator

caridy commented Nov 28, 2014

awesome, lets plan for that then, we need an implementer now :)

/cc @lwelti

@ericf
Copy link
Collaborator

ericf commented Nov 28, 2014

So we can stage this by first easily adding support for selectordinal arguments, option 1 above. @carystanley do you think that would work to unblock you?

Then we work on the automatic ordinal argument formatting via a new IntlRuleBasedNumberFormat lib, which will take a lot more time and effort for us to implement.

@srl295
Copy link

srl295 commented Nov 28, 2014

By the way, concerning ICU please reach out to us if needed, not so hard to convince, and code does talk :) icu-project.org

@caridy
Copy link
Collaborator

caridy commented Nov 28, 2014

well, they can do that today without anything new:

Go to the {floor, select,
  =0 {ground} 
  one {#st} 
  two {#nd}
  few {#rd}
  other {#th}
} floor.

not ideal, but at least this unblock them.

@caridy
Copy link
Collaborator

caridy commented Nov 28, 2014

@srl295, lets start the conversation about relative time, e.g.: {dateValue, relative}

@srl295
Copy link

srl295 commented Nov 28, 2014

@caridy relative time sounds good to me, but probably best started at http://bugs.icu-project.org/trac/newticket . Apologies if you knew this, but the select format in ICU was itself a Yahoo! contribution. Actually there's this ticket (note: follow the trail of 'xref' fields to find related tix) that might be interesting.

edit on consideration, I think a new ticket would be best, and reference any relevant ones you dig up, or even this thread. This is a great time to suggest changes in msgformat.

@caridy
Copy link
Collaborator

caridy commented Dec 5, 2014

ICU ticket for relative time in messages: http://bugs.icu-project.org/trac/ticket/11409

@srl295
Copy link

srl295 commented Dec 5, 2014

@caridy 👍 . added a backlink here and an xref

@srl295
Copy link

srl295 commented Dec 11, 2014

@caridy and, the ICU ticket was moved to unscheduled. Is someone interested in contributing a C++ and Java design and implementation?

@caridy
Copy link
Collaborator

caridy commented Dec 19, 2014

@srl295 we will try :)

@lwelti, do we have someone from your team that can work with us on this effort?

@ericf
Copy link
Collaborator

ericf commented Feb 13, 2015

I realized that we do not have that data to support selectordinal as I mentioned above. We could get this data from the make-plural.js project which would give us basic ordinal support without needing to implement RBNF.

@ericf
Copy link
Collaborator

ericf commented Feb 13, 2015

@caridy what you wrote in #84 (comment) is not actually correct — select argument types use exact matches. We currently have the cardinal pluralization rules, but we also need the ordinal ones, and with those we can support the selectordinal argument type option #1.

@ericf
Copy link
Collaborator

ericf commented Feb 13, 2015

Update

I feel we should add basic ordinal support to this project by adding support for selectordinal arguments, option #1 above. Here the tasks to implement this:

ericf added a commit to formatjs/intl-messageformat-parser that referenced this issue Feb 15, 2015
This adds support for parsing `selectordinal` arguments, which have
similar semantics to `plural` arguments but use ordinal pluralization.

Relates to: formatjs/intl-messageformat#84
See: formatjs/intl-messageformat#84 (comment)
@ericf ericf self-assigned this Mar 3, 2015
ericf added a commit to ericf/intl-messageformat that referenced this issue Mar 6, 2015
This upgrades to intl-messageformat-parser@1.1.0 and adds support for
`selectordinal` arguments; e.g.:

```
This is my {year, selectordinal,
    one {#st}
    two {#nd}
    few {#rd}
    other{#th}
} birthday.
```

The locale data has also been vastly improved in the following ways:

* Added `pt-PT` plural rule function, which differs from `pt`'s.

* Properly de-duplicate data for all CLDR locales by correctly
  traversing a locale's hierarchy of ancestor locales.

* Added data for the following languages:
  aa, agq, bas, bh, ckb, dav, dje, dsb, dua, dv, dyo, ebu, ewo, guw,
  guz, hsb, ia, in, iu, iw, jbo, ji, jv, jw, kaj, kam, kcg, khq, ki,
  kln, kok, ksf, ku, lb, lu, luo, luy, mer, mfe, mgh, mo, mua, nah,
  nmg, no, nqo, nus, ny, pap, prg, qu, rn, rw, sbp, sh, sma, smi, smj,
  smn, sms, swc, syr, tk, tl, twq, vai, wa, wo, yav, yi, zgh

----

These changes also include improvements for how locales are resolved.
Here are some details of these changes:

* If no extra locale data is loaded, the locale will _always_ resolved
  to `en`.

* If locale data is missing for a leaf locale like `fr-FR`, but there
  _is_ data for the root, `fr` in this case, then its root will be
  used.

* If there's data for the specified locale, then that locale will be
  resolved; i.e.,

    var mf = new IntlMessageFormat('', 'en-US');
    assert(mf.resolvedOptions().locale === 'en-US'); // true

* The resolved locales are now normalized; e.g., `en-us` will resolve
  to: `en-US`.

Fixes formatjs#84
@ericf
Copy link
Collaborator

ericf commented Mar 6, 2015

PR #102 Implements these selectordinal arguments, plus vast improvements to the locale data used by this package.

@ericf ericf closed this as completed in #102 Mar 9, 2015
@piuccio
Copy link

piuccio commented Jan 26, 2018

@ericf sorry to dig up this old issue again but the current selectordinal only works for numbers up to 20

{rank, selectordinal,
  one {#st} 
  two {#nd}
  few {#rd}
  other {#th}
}

with {rank: 21} generates 21th which should instead be 21st. Same goes for all numbers ending with 1, 2, 3 bigger than 20.

I'm not sure if you want to track this problem somehow.

@MartinDawson
Copy link

MartinDawson commented Feb 6, 2018

@piuccio I tried numbers going up to 40. All work as expected. 21 generates 21st.

I'm using latest react-intl, don't know if you are of if that makes a difference.

Here's my code so you can try and see what's different:

export const floorMessages = (positionLowestFloor, positionHighestFloor) => {
  const ordinals = 'selectordinal, one {#st} two {#nd} few {#rd} other {#th}';

  return defineMessages({
    singleFloor: { id: 'Floor.singleFloor', defaultMessage: `{positionLowestFloor, ${ordinals} } floor`, values: { positionLowestFloor } },
  });
};

@piuccio
Copy link

piuccio commented Feb 6, 2018 via email

longlho pushed a commit to formatjs/formatjs-old that referenced this issue May 14, 2019
This adds support for parsing `selectordinal` arguments, which have
similar semantics to `plural` arguments but use ordinal pluralization.

Relates to: formatjs/intl-messageformat#84
See: formatjs/intl-messageformat#84 (comment)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants