Skip to content

Commit eb9a0b2

Browse files
feat(mf2)!: Drop the notation, compactDisplay, & numberingSystem options (unicode-org/message-format-wg#1015)
1 parent 77b6369 commit eb9a0b2

File tree

3 files changed

+75
-71
lines changed

3 files changed

+75
-71
lines changed

mf2/messageformat/src/functions/currency.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { MessageError, MessageResolutionError } from '../errors.js';
22
import type { MessageFunctionContext } from './index.js';
3-
import { type MessageNumber, number, readNumericOperand } from './number.js';
3+
import {
4+
type MessageNumber,
5+
type MessageNumberOptions,
6+
getMessageNumber,
7+
readNumericOperand
8+
} from './number.js';
49
import { asPositiveInteger, asString } from './utils.js';
510

611
/**
@@ -17,22 +22,15 @@ export function currency(
1722
const { source } = ctx;
1823
const input = readNumericOperand(operand, source);
1924
const value = input.value;
20-
const options: Intl.NumberFormatOptions &
21-
Intl.PluralRulesOptions & { select?: 'exact' | 'cardinal' } = Object.assign(
22-
{},
23-
input.options
24-
);
25+
const options: MessageNumberOptions = Object.assign({}, input.options);
2526

2627
options.style = 'currency';
2728
for (const [name, optval] of Object.entries(exprOpt)) {
2829
if (optval === undefined) continue;
2930
try {
3031
switch (name) {
31-
case 'compactDisplay':
3232
case 'currency':
3333
case 'currencySign':
34-
case 'notation':
35-
case 'numberingSystem':
3634
case 'roundingMode':
3735
case 'roundingPriority':
3836
case 'trailingZeroDisplay':
@@ -109,5 +107,5 @@ export function currency(
109107
throw new MessageResolutionError('bad-operand', msg, source);
110108
}
111109

112-
return number(ctx, {}, { valueOf: () => value, options });
110+
return getMessageNumber(ctx, value, options);
113111
}

mf2/messageformat/src/functions/datetime.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ export const date = (
111111
res[name] = asBoolean(value);
112112
break;
113113
case 'calendar':
114-
case 'numberingSystem':
115114
case 'timeZone':
116115
res[name] = asString(value);
117116
}
@@ -149,7 +148,6 @@ export const time = (
149148
res[name] = asBoolean(value);
150149
break;
151150
case 'calendar':
152-
case 'numberingSystem':
153151
case 'timeZone':
154152
res[name] = asString(value);
155153
}

mf2/messageformat/src/functions/number.ts

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ export interface MessageNumberPart extends MessageExpressionPart {
3737
parts: Intl.NumberFormatPart[];
3838
}
3939

40+
export type MessageNumberOptions = Intl.NumberFormatOptions &
41+
Intl.PluralRulesOptions & { select?: 'exact' | 'cardinal' | 'ordinal' };
42+
4043
const INT = Symbol('INT');
4144

4245
export function readNumericOperand(
@@ -65,6 +68,57 @@ export function readNumericOperand(
6568
return { value, options };
6669
}
6770

71+
export function getMessageNumber(
72+
{ dir, locales, source }: MessageFunctionContext,
73+
value: number | bigint,
74+
options: MessageNumberOptions
75+
): MessageNumber {
76+
let locale: string | undefined;
77+
let nf: Intl.NumberFormat | undefined;
78+
let cat: Intl.LDMLPluralRule | undefined;
79+
let str: string | undefined;
80+
return {
81+
type: 'number',
82+
source,
83+
get dir() {
84+
if (dir == null) {
85+
locale ??= Intl.NumberFormat.supportedLocalesOf(locales, options)[0];
86+
dir = getLocaleDir(locale);
87+
}
88+
return dir;
89+
},
90+
get options() {
91+
return { ...options };
92+
},
93+
selectKey(keys) {
94+
const str = String(value);
95+
if (keys.has(str)) return str;
96+
if (options.select === 'exact') return null;
97+
const pluralOpt = options.select
98+
? { ...options, select: undefined, type: options.select }
99+
: options;
100+
// Intl.PluralRules needs a number, not bigint
101+
cat ??= new Intl.PluralRules(locales, pluralOpt).select(Number(value));
102+
return keys.has(cat) ? cat : null;
103+
},
104+
toParts() {
105+
nf ??= new Intl.NumberFormat(locales, options);
106+
const parts = nf.formatToParts(value);
107+
locale ??= nf.resolvedOptions().locale;
108+
dir ??= getLocaleDir(locale);
109+
return dir === 'ltr' || dir === 'rtl'
110+
? [{ type: 'number', source, dir, locale, parts }]
111+
: [{ type: 'number', source, locale, parts }];
112+
},
113+
toString() {
114+
nf ??= new Intl.NumberFormat(locales, options);
115+
str ??= nf.format(value);
116+
return str;
117+
},
118+
valueOf: () => value
119+
};
120+
}
121+
68122
/**
69123
* `number` accepts a number, BigInt or string representing a JSON number as input
70124
* and formats it with the same options as
@@ -79,23 +133,17 @@ export function number(
79133
exprOpt: Record<string | symbol, unknown>,
80134
operand?: unknown
81135
): MessageNumber {
82-
const { locales, source } = ctx;
83-
const options: Intl.NumberFormatOptions &
84-
Intl.PluralRulesOptions & { select?: 'exact' | 'cardinal' | 'ordinal' } = {
85-
localeMatcher: ctx.localeMatcher
86-
};
87-
const input = readNumericOperand(operand, source);
136+
const input = readNumericOperand(operand, ctx.source);
88137
const value = input.value;
89-
Object.assign(options, input.options);
138+
const options: MessageNumberOptions = Object.assign(
139+
{ localeMatcher: ctx.localeMatcher },
140+
input.options
141+
);
90142

91143
for (const [name, optval] of Object.entries(exprOpt)) {
92144
if (optval === undefined) continue;
93145
try {
94146
switch (name) {
95-
case 'locale':
96-
case 'style': // https://github.com/unicode-org/message-format-wg/pull/988
97-
case 'type': // used internally by Intl.PluralRules, but called 'select' here
98-
break;
99147
case 'minimumIntegerDigits':
100148
case 'minimumFractionDigits':
101149
case 'maximumFractionDigits':
@@ -111,13 +159,17 @@ export function number(
111159
options[name] = strval === 'never' ? false : strval;
112160
break;
113161
}
114-
default:
115-
// @ts-expect-error Unknown options will be ignored
162+
case 'roundingMode':
163+
case 'roundingPriority':
164+
case 'select': // Called 'type' in Intl.PluralRules
165+
case 'signDisplay':
166+
case 'trailingZeroDisplay':
167+
// @ts-expect-error Let Intl.NumberFormat construction fail
116168
options[name] = asString(optval);
117169
}
118170
} catch {
119171
const msg = `Value ${optval} is not valid for :number option ${name}`;
120-
ctx.onError(new MessageResolutionError('bad-option', msg, source));
172+
ctx.onError(new MessageResolutionError('bad-option', msg, ctx.source));
121173
}
122174
}
123175

@@ -126,51 +178,7 @@ export function number(
126178
? Math.round(value as number)
127179
: value;
128180

129-
let locale: string | undefined;
130-
let dir = ctx.dir;
131-
let nf: Intl.NumberFormat | undefined;
132-
let cat: Intl.LDMLPluralRule | undefined;
133-
let str: string | undefined;
134-
return {
135-
type: 'number',
136-
source,
137-
get dir() {
138-
if (dir == null) {
139-
locale ??= Intl.NumberFormat.supportedLocalesOf(locales, options)[0];
140-
dir = getLocaleDir(locale);
141-
}
142-
return dir;
143-
},
144-
get options() {
145-
return { ...options };
146-
},
147-
selectKey(keys) {
148-
const str = String(num);
149-
if (keys.has(str)) return str;
150-
if (options.select === 'exact') return null;
151-
const pluralOpt = options.select
152-
? { ...options, select: undefined, type: options.select }
153-
: options;
154-
// Intl.PluralRules needs a number, not bigint
155-
cat ??= new Intl.PluralRules(locales, pluralOpt).select(Number(num));
156-
return keys.has(cat) ? cat : null;
157-
},
158-
toParts() {
159-
nf ??= new Intl.NumberFormat(locales, options);
160-
const parts = nf.formatToParts(num);
161-
locale ??= nf.resolvedOptions().locale;
162-
dir ??= getLocaleDir(locale);
163-
return dir === 'ltr' || dir === 'rtl'
164-
? [{ type: 'number', source, dir, locale, parts }]
165-
: [{ type: 'number', source, locale, parts }];
166-
},
167-
toString() {
168-
nf ??= new Intl.NumberFormat(locales, options);
169-
str ??= nf.format(num);
170-
return str;
171-
},
172-
valueOf: () => num
173-
};
181+
return getMessageNumber(ctx, num, options);
174182
}
175183

176184
/**

0 commit comments

Comments
 (0)