@@ -328,43 +328,103 @@ describe('Multi-selector messages (unicode-org/message-format-wg#119)', () => {
328
328
} ) ;
329
329
} ) ;
330
330
331
- const maybe = process . version > 'v12' ? test : test . skip ;
332
- maybe ( 'List formatter (unicode-org/message-format-wg#36)' , ( ) => {
333
- function LIST (
334
- locales : string [ ] ,
335
- options : FunctionOptions ,
336
- ...args : ( string | string [ ] ) [ ]
337
- ) {
338
- let list : string [ ] = [ ] ;
339
- for ( const arg of args ) list = list . concat ( arg ) ;
340
- // @ts -ignore
341
- const lf = new Intl . ListFormat ( locales , options ) ;
342
- return lf . format ( list ) ;
343
- }
344
- const runtime : Runtime = {
345
- select : fluentRuntime . select ,
346
- format : Object . assign ( { LIST } , fluentRuntime . format )
347
- } ;
331
+ const maybe = process . version > 'v14' ? describe : describe . skip ;
332
+ maybe ( 'List formatting' , ( ) => {
333
+ test ( 'Intl.ListFormat, combine/flatten inputs (unicode-org/message-format-wg#36)' , ( ) => {
334
+ function LIST (
335
+ locales : string [ ] ,
336
+ options : FunctionOptions | undefined ,
337
+ ...args : ( string | string [ ] ) [ ]
338
+ ) {
339
+ let list : string [ ] = [ ] ;
340
+ for ( const arg of args ) list = list . concat ( arg ) ;
341
+ // @ts -ignore
342
+ const lf = new Intl . ListFormat ( locales , options ) ;
343
+ return lf . format ( list ) ;
344
+ }
345
+ const runtime : Runtime = {
346
+ select : fluentRuntime . select ,
347
+ format : Object . assign ( { LIST } , fluentRuntime . format )
348
+ } ;
348
349
349
- const src = source `
350
+ const src = source `
350
351
plain = { LIST($list) }
351
352
and = { LIST($list, style: "short", type: "conjunction") }
352
353
or = { LIST($list, style: "long", type: "disjunction") }
353
354
or-other = { LIST($list, "another vehicle", type: "disjunction") }
354
355
` ;
355
- const res = compileFluent ( src , { id : 'res' , locale : 'en' } ) ;
356
- const mf = new MessageFormat ( 'en' , runtime , res ) ;
357
- const list = [ 'Motorcycle' , 'Bus' , 'Car' ] ;
356
+ const res = compileFluent ( src , { id : 'res' , locale : 'en' } ) ;
357
+ const mf = new MessageFormat ( 'en' , runtime , res ) ;
358
+ const list = [ 'Motorcycle' , 'Bus' , 'Car' ] ;
359
+
360
+ const plainMsg = mf . format ( 'res' , [ 'plain' ] , { list } ) ;
361
+ expect ( plainMsg ) . toBe ( 'Motorcycle, Bus, and Car' ) ;
362
+
363
+ const andMsg = mf . format ( 'res' , [ 'and' ] , { list } ) ;
364
+ expect ( andMsg ) . toBe ( 'Motorcycle, Bus, & Car' ) ;
358
365
359
- const plainMsg = mf . format ( 'res' , [ 'plain ' ] , { list } ) ;
360
- expect ( plainMsg ) . toBe ( 'Motorcycle, Bus, and Car' ) ;
366
+ const orMsg = mf . format ( 'res' , [ 'or ' ] , { list } ) ;
367
+ expect ( orMsg ) . toBe ( 'Motorcycle, Bus, or Car' ) ;
361
368
362
- const andMsg = mf . format ( 'res' , [ 'and' ] , { list } ) ;
363
- expect ( andMsg ) . toBe ( 'Motorcycle, Bus, & Car' ) ;
369
+ const otherMsg = mf . format ( 'res' , [ 'or-other' ] , { list } ) ;
370
+ expect ( otherMsg ) . toBe ( 'Motorcycle, Bus, Car, or another vehicle' ) ;
371
+ } ) ;
364
372
365
- const orMsg = mf . format ( 'res' , [ 'or' ] , { list } ) ;
366
- expect ( orMsg ) . toBe ( 'Motorcycle, Bus, or Car' ) ;
373
+ test ( 'List formatting with grammatical inflection on each list item (unicode-org/message-format-wg#3)' , ( ) => {
374
+ const runtime : Runtime = {
375
+ select : fluentRuntime . select ,
376
+ format : Object . assign ( { dative, LIST } , fluentRuntime . format )
377
+ } ;
367
378
368
- const otherMsg = mf . format ( 'res' , [ 'or-other' ] , { list } ) ;
369
- expect ( otherMsg ) . toBe ( 'Motorcycle, Bus, Car, or another vehicle' ) ;
379
+ function dative ( locales : string [ ] , _options : unknown , arg : string ) {
380
+ if ( locales [ 0 ] !== 'ro' ) throw new Error ( 'Only Romanian supported' ) ;
381
+ const data : Record < string , string > = {
382
+ Maria : 'Mariei' ,
383
+ Ileana : 'Ilenei' ,
384
+ Petre : 'lui Petre'
385
+ } ;
386
+ return data [ arg ] || arg ;
387
+ }
388
+
389
+ function LIST (
390
+ locales : string [ ] ,
391
+ options : FunctionOptions | undefined ,
392
+ ...args : ( string | string [ ] ) [ ]
393
+ ) {
394
+ let list : string [ ] = [ ] ;
395
+ for ( const arg of args ) list = list . concat ( arg ) ;
396
+ if ( typeof options ?. each === 'string' ) {
397
+ const fn = runtime . format [ options . each ] ;
398
+ if ( typeof fn !== 'function' )
399
+ throw new Error ( `list each function not found: ${ options . each } ` ) ;
400
+ list = list . map ( li => fn ( locales , undefined , li ) ) ;
401
+ }
402
+ // @ts -ignore
403
+ const lf = new Intl . ListFormat ( locales , options ) ;
404
+ return lf . format ( list ) ;
405
+ }
406
+
407
+ const src = source `
408
+ msg = { $count ->
409
+ [one] I-am dat cadouri { LIST($list, each: "dative") }.
410
+ *[other] Le-am dat cadouri { LIST($list, each: "dative") }.
411
+ }
412
+ ` ;
413
+ const res = compileFluent ( src , { id : 'res' , locale : 'ro' } ) ;
414
+ const mf = new MessageFormat ( 'ro' , runtime , res ) ;
415
+
416
+ const list1 = [ 'Petre' ] ;
417
+ const msg1 = mf . format ( 'res' , [ 'msg' ] , {
418
+ count : list1 . length ,
419
+ list : list1
420
+ } ) ;
421
+ expect ( msg1 ) . toBe ( 'I-am dat cadouri lui Petre.' ) ;
422
+
423
+ const list3 = [ 'Maria' , 'Ileana' , 'Petre' ] ;
424
+ const msg3 = mf . format ( 'res' , [ 'msg' ] , {
425
+ count : list3 . length ,
426
+ list : list3
427
+ } ) ;
428
+ expect ( msg3 ) . toBe ( 'Le-am dat cadouri Mariei, Ilenei și lui Petre.' ) ;
429
+ } ) ;
370
430
} ) ;
0 commit comments