Skip to content

Commit df3b997

Browse files
committed
feat(mf2)!: Follow new datetime function spec (unicode-org/message-format-wg#1078, unicode-org/message-format-wg#1083)
1 parent 436da6b commit df3b997

File tree

5 files changed

+414
-234
lines changed

5 files changed

+414
-234
lines changed

mf2/icu-messageformat-1/src/functions.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,22 @@ function currency(
3030
return DraftFunctions.currency(ctx, options, operand);
3131
}
3232

33-
function datetime(
33+
function date(
3434
ctx: MessageFunctionContext,
3535
options: Record<string, unknown>,
3636
operand?: unknown
3737
): MessageDateTime {
3838
checkArgStyle(ctx, options);
39-
return DraftFunctions.datetime(ctx, options, operand);
39+
return DraftFunctions.date(ctx, options, operand);
40+
}
41+
42+
function time(
43+
ctx: MessageFunctionContext,
44+
options: Record<string, unknown>,
45+
operand?: unknown
46+
): MessageDateTime {
47+
checkArgStyle(ctx, options);
48+
return DraftFunctions.time(ctx, options, operand);
4049
}
4150

4251
function duration(
@@ -149,10 +158,16 @@ export let MF1Functions = {
149158
'mf1:currency': currency,
150159

151160
/**
152-
* A wrapper around {@link DraftFunctions.datetime},
153-
* used for formatting `date` and `time` placeholders.
161+
* A wrapper around {@link DraftFunctions.date},
162+
* used for formatting `date` placeholders.
163+
*/
164+
'mf1:date': date,
165+
166+
/**
167+
* A wrapper around {@link DraftFunctions.time},
168+
* used for formatting `time` placeholders.
154169
*/
155-
'mf1:datetime': datetime,
170+
'mf1:time': time,
156171

157172
/**
158173
* Formats a duration expressed as seconds.

mf2/icu-messageformat-1/src/mf1-to-message-data.ts

Lines changed: 39 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import {
2-
getDateTimeFormatOptions,
3-
parseDateTokens
4-
} from '@messageformat/date-skeleton';
51
import {
62
getNumberFormatOptions,
73
parseNumberPattern,
@@ -54,27 +50,6 @@ function findSelectArgs(tokens: AST.Token[]): SelectArg[] {
5450
return args;
5551
}
5652

57-
function parseDateTimeArgStyle(argStyle: string): MF.Options {
58-
const options: MF.Options = new Map();
59-
const onError = () =>
60-
options.set('mf1:argStyle', { type: 'literal', value: argStyle });
61-
const tokens = parseDateTokens(argStyle.substring(2));
62-
const dtfOpt = getDateTimeFormatOptions(tokens, onError);
63-
loop: for (let [key, value] of Object.entries(dtfOpt)) {
64-
switch (key) {
65-
case 'dayPeriod':
66-
onError();
67-
continue loop;
68-
case 'hourCycle':
69-
key = 'hour12';
70-
value = String(value === 'h11' || value === 'h12');
71-
break;
72-
}
73-
options.set(key, { type: 'literal', value });
74-
}
75-
return options;
76-
}
77-
7853
function parseNumberArgStyle(argStyle: string): MF.FunctionRef {
7954
let name = 'number';
8055
const options: MF.Options = new Map();
@@ -155,36 +130,27 @@ function tokenToFunctionRef(token: AST.FunctionArg): {
155130

156131
switch (token.key) {
157132
case 'date': {
158-
let options: MF.Options;
159-
if (argStyle.startsWith('::')) {
160-
options = parseDateTimeArgStyle(argStyle);
161-
} else {
162-
const month: MF.Literal = { type: 'literal', value: 'short' };
163-
options = new Map([
164-
['year', { type: 'literal', value: 'numeric' }],
165-
['month', month],
166-
['day', { type: 'literal', value: 'numeric' }]
167-
]);
168-
switch (argStyle) {
169-
case 'full':
170-
month.value = 'long';
171-
options.set('weekday', { type: 'literal', value: 'long' });
172-
break;
173-
case 'long':
174-
month.value = 'long';
175-
break;
176-
case 'short':
177-
month.value = 'numeric';
178-
break;
179-
case '':
180-
case 'medium':
181-
break;
182-
default:
183-
options.set('mf1:argStyle', { type: 'literal', value: argStyle });
184-
}
133+
const options: MF.Options = new Map();
134+
switch (argStyle) {
135+
case '':
136+
break;
137+
case 'full':
138+
options.set('fields', {
139+
type: 'literal',
140+
value: 'year-month-day-weekday'
141+
});
142+
options.set('length', { type: 'literal', value: 'long' });
143+
break;
144+
case 'long':
145+
case 'medium':
146+
case 'short':
147+
options.set('length', { type: 'literal', value: argStyle });
148+
break;
149+
default:
150+
options.set('mf1:argStyle', { type: 'literal', value: argStyle });
185151
}
186152
return {
187-
functionRef: { type: 'function', name: 'mf1:datetime', options },
153+
functionRef: { type: 'function', name: 'mf1:date', options },
188154
attributes
189155
};
190156
}
@@ -223,32 +189,28 @@ function tokenToFunctionRef(token: AST.FunctionArg): {
223189
}
224190

225191
case 'time': {
226-
let options: MF.Options;
227-
if (argStyle.startsWith('::')) {
228-
options = parseDateTimeArgStyle(argStyle);
229-
} else {
230-
options = new Map([
231-
['hour', { type: 'literal', value: 'numeric' }],
232-
['minute', { type: 'literal', value: 'numeric' }]
233-
]);
234-
switch (argStyle) {
235-
case 'full':
236-
case 'long':
237-
options.set('second', { type: 'literal', value: 'numeric' });
238-
options.set('timeZoneName', { type: 'literal', value: 'short' });
239-
break;
240-
case 'short':
241-
break;
242-
case '':
243-
case 'medium':
244-
options.set('second', { type: 'literal', value: 'numeric' });
245-
break;
246-
default:
247-
options.set('mf1:argStyle', { type: 'literal', value: argStyle });
248-
}
192+
const options: MF.Options = new Map();
193+
switch (argStyle) {
194+
case 'full':
195+
options.set('precision', { type: 'literal', value: 'second' });
196+
options.set('timeZoneName', { type: 'literal', value: 'long' });
197+
break;
198+
case 'long':
199+
options.set('precision', { type: 'literal', value: 'second' });
200+
options.set('timeZoneName', { type: 'literal', value: 'short' });
201+
break;
202+
case '':
203+
case 'medium':
204+
options.set('precision', { type: 'literal', value: 'second' });
205+
break;
206+
case 'short':
207+
options.set('precision', { type: 'literal', value: 'minute' });
208+
break;
209+
default:
210+
options.set('mf1:argStyle', { type: 'literal', value: argStyle });
249211
}
250212
return {
251-
functionRef: { type: 'function', name: 'mf1:datetime', options },
213+
functionRef: { type: 'function', name: 'mf1:time', options },
252214
attributes
253215
};
254216
}

mf2/icu-messageformat-1/src/mf1.test.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -384,22 +384,6 @@ export const testCases: Record<string, TestCase[]> = {
384384
}
385385
],
386386

387-
'Datetime skeletons': [
388-
{
389-
src: 'At {1,time,::jmm} on {1,date,::dMMMM}',
390-
exp: [[{ 1: 978484385000 }, /^At \d\d?:\d\d\s(AM|PM) on January \d$/]]
391-
},
392-
{
393-
src: "{1, date, ::EEE, MMM d, ''yy}",
394-
exp: [
395-
[
396-
{ 1: 978484385000 },
397-
{ res: 'Wed, Jan 3, 2001', errors: ['bad-option'] }
398-
]
399-
]
400-
}
401-
],
402-
403387
'Unsupported formatters': [
404388
{
405389
src: '{N, spellout}',

0 commit comments

Comments
 (0)