-
Notifications
You must be signed in to change notification settings - Fork 4k
Fixed toLocaleOrdinal by using Intl.PluralRules instead of fixed rules #98265
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| /** | ||
| * Per-locale ordinal rendering, keyed by the CLDR plural category that | ||
| * `Intl.PluralRules(locale, {type: 'ordinal'})` selects for a given number. | ||
| * | ||
| * This lives outside the `src/languages/*.ts` files on purpose. Those are typed as | ||
| * `TranslationDeepObject<typeof en>`, which forces every locale to declare the exact same keys as | ||
| * English. Ordinals do not work that way: English needs four categories, Italian two, and eight of | ||
| * our locales need only `other`. Keeping the data here lets each locale declare exactly the | ||
| * categories its grammar can actually select. | ||
| * | ||
| * Each entry renders the complete string rather than just a suffix, because some locales form | ||
| * ordinals with a prefix (Japanese and Chinese use 第1, not 1第) which a suffix cannot express. | ||
| */ | ||
| import type {Locale} from '@src/CONST/LOCALES'; | ||
| import {LOCALES} from '@src/CONST/LOCALES'; | ||
|
|
||
| /** Renders the full ordinal for a number, e.g. `1st`, `1.`, `第1` */ | ||
| type OrdinalRenderer = (count: number) => string; | ||
|
|
||
| /** | ||
| * `other` is required because it is the fallback for any category a locale does not declare, which | ||
| * keeps a missing entry from producing an empty string. | ||
| */ | ||
| type LocaleOrdinals = Partial<Record<Intl.LDMLPluralRule, OrdinalRenderer>> & {other: OrdinalRenderer}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB Minor type cleanup: diff --git a/src/languages/localeOrdinalMap.ts b/src/languages/localeOrdinalMap.ts
index 4eecc665dd7..61477fff882 100644
--- a/src/languages/localeOrdinalMap.ts
+++ b/src/languages/localeOrdinalMap.ts
@@ -14,6 +14,8 @@
import type {Locale} from '@src/CONST/LOCALES';
import {LOCALES} from '@src/CONST/LOCALES';
+import type {SetRequired} from 'type-fest';
+
/** Renders the full ordinal for a number, e.g. `1st`, `1.`, `第1` */
type OrdinalRenderer = (count: number) => string;
@@ -21,7 +23,7 @@ type OrdinalRenderer = (count: number) => string;
* `other` is required because it is the fallback for any category a locale does not declare, which
* keeps a missing entry from producing an empty string.
*/
-type LocaleOrdinals = Partial<Record<Intl.LDMLPluralRule, OrdinalRenderer>> & {other: OrdinalRenderer};
+type LocaleOrdinals = SetRequired<Partial<Record<Intl.LDMLPluralRule, OrdinalRenderer>>, 'other'>;
const localeOrdinalMap: Record<Locale, LocaleOrdinals> = {
/** Categories: one, two, few, other. The only locale here needing all four. */
|
||
|
|
||
| const localeOrdinalMap: Record<Locale, LocaleOrdinals> = { | ||
| /** Categories: one, two, few, other. The only locale here needing all four. */ | ||
| [LOCALES.EN]: { | ||
| one: (count) => `${count}st`, | ||
| two: (count) => `${count}nd`, | ||
| few: (count) => `${count}rd`, | ||
| other: (count) => `${count}th`, | ||
| }, | ||
|
|
||
| /** Categories: other. Uses the masculine ordinal indicator. */ | ||
| [LOCALES.ES]: { | ||
| other: (count) => `${count}º`, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB follow-up: figure out how to correctly use the feminine ordinal indicator when appropriate.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @MelvinBot Create a follow-up issue to correctly handle gendered nouns in Spanish, Greek and any other locales that use them (for adjectives, ordinality, and any other grammatical structures you can think of that would be effected by this). Label it Weekly, assign to @shubham1206agra and myself |
||
| }, | ||
|
|
||
| /** Categories: one, other. 1 is written `1er`, everything else takes `e`. */ | ||
| [LOCALES.FR]: { | ||
| one: (count) => `${count}er`, | ||
| other: (count) => `${count}e`, | ||
| }, | ||
|
|
||
| /** Categories: other. German ordinals are the number followed by a period. */ | ||
| [LOCALES.DE]: { | ||
| other: (count) => `${count}.`, | ||
| }, | ||
|
|
||
| /** | ||
| * Categories: other. | ||
| * | ||
| * Greek ordinals inflect for gender. `η` is the feminine form, which agrees with the nouns this | ||
| * is currently used for. A different gender would need a different entry, so this is not safe to | ||
| * reuse for arbitrary nouns without revisiting. | ||
| */ | ||
| [LOCALES.EL]: { | ||
| other: (count) => `${count}η`, | ||
| }, | ||
|
|
||
| /** Categories: many, other. Uses the masculine ordinal indicator. */ | ||
| [LOCALES.IT]: { | ||
| many: (count) => `${count}º`, | ||
| other: (count) => `${count}º`, | ||
| }, | ||
|
|
||
| /** Categories: other. Japanese forms ordinals with a prefix. */ | ||
| [LOCALES.JA]: { | ||
| other: (count) => `第${count}`, | ||
| }, | ||
|
|
||
| /** Categories: other. */ | ||
| [LOCALES.NL]: { | ||
| other: (count) => `${count}e`, | ||
| }, | ||
|
|
||
| /** Categories: other. Polish ordinals are the number followed by a period. */ | ||
| [LOCALES.PL]: { | ||
| other: (count) => `${count}.`, | ||
| }, | ||
|
|
||
| /** Categories: other. */ | ||
| [LOCALES.PT_BR]: { | ||
| other: (count) => `${count}º`, | ||
| }, | ||
|
|
||
| /** Categories: other. Chinese forms ordinals with a prefix. */ | ||
| [LOCALES.ZH_HANS]: { | ||
| other: (count) => `第${count}`, | ||
| }, | ||
| }; | ||
|
|
||
| export default localeOrdinalMap; | ||
Uh oh!
There was an error while loading. Please reload this page.