1- import { Message , Parameter , PatternElement , Selector , StringLiteral , Variant } from "./model.js" ;
1+ import {
2+ IntegerLiteral ,
3+ Message ,
4+ Parameter ,
5+ PatternElement ,
6+ Selector ,
7+ StringLiteral ,
8+ Variant ,
9+ } from "./model.js" ;
210import { REGISTRY } from "./registry.js" ;
3- import { BooleanValue , NumberValue , RuntimeValue , StringValue } from "./runtime.js" ;
11+ import { BooleanValue , NumberValue , PluralValue , RuntimeValue , StringValue } from "./runtime.js" ;
412
513// Resolution context for a single formatMessage() call.
614
@@ -56,41 +64,25 @@ export class FormattingContext {
5664 }
5765
5866 selectVariant ( variants : Array < Variant > , selectors : Array < Selector > ) : Variant {
59- interface ResolvedSelector < T > {
60- value : T | null ;
61- string : string | null ;
67+ interface ResolvedSelector {
68+ value : RuntimeValue < unknown > ;
6269 default : string ;
6370 }
6471
65- let resolved_selectors : Array < ResolvedSelector < unknown > > = [ ] ;
72+ let resolved_selectors : Array < ResolvedSelector > = [ ] ;
6673 for ( let selector of selectors ) {
67- if ( selector . expr === null ) {
68- // A special selector which only selects its default value. Used in the
69- // data model of single-variant messages.
70- resolved_selectors . push ( {
71- value : null ,
72- string : null ,
73- default : selector . default . value ,
74- } ) ;
75- continue ;
76- }
77-
7874 switch ( selector . expr . type ) {
7975 case "VariableReference" : {
80- let value = this . vars [ selector . expr . name ] ;
8176 resolved_selectors . push ( {
82- value : value . value ,
83- string : value . formatToString ( this ) ,
77+ value : this . vars [ selector . expr . name ] ,
8478 default : selector . default . value ,
8579 } ) ;
8680 break ;
8781 }
8882 case "FunctionCall" : {
8983 let callable = REGISTRY [ selector . expr . name ] ;
90- let value = callable ( this , selector . expr . args , selector . expr . opts ) ;
9184 resolved_selectors . push ( {
92- value : value . value ,
93- string : value . formatToString ( this ) ,
85+ value : callable ( this , selector . expr . args , selector . expr . opts ) ,
9486 default : selector . default . value ,
9587 } ) ;
9688 break ;
@@ -101,15 +93,36 @@ export class FormattingContext {
10193 }
10294 }
10395
104- // TODO(stasm): Add NumberLiterals as keys (maybe).
105- function matches_corresponding_selector ( key : StringLiteral , idx : number ) {
106- return (
107- key . value === resolved_selectors [ idx ] . string ||
108- key . value === resolved_selectors [ idx ] . default
109- ) ;
96+ function matches_corresponding_selector ( key : StringLiteral | IntegerLiteral , idx : number ) {
97+ let selector = resolved_selectors [ idx ] ;
98+ switch ( key . type ) {
99+ case "StringLiteral" : {
100+ if ( key . value === selector . value . value ) {
101+ return true ;
102+ }
103+ break ;
104+ }
105+ case "IntegerLiteral" : {
106+ let num = parseInt ( key . value ) ;
107+ if ( selector . value instanceof NumberValue ) {
108+ if ( num === selector . value . value ) {
109+ return true ;
110+ }
111+ } else if ( selector . value instanceof PluralValue ) {
112+ if ( key . value === selector . value . value || num === selector . value . count ) {
113+ return true ;
114+ }
115+ }
116+ break ;
117+ }
118+ }
119+
120+ return key . value === selector . default ;
110121 }
111122
112123 for ( let variant of variants ) {
124+ // When keys is an empty array, every() always returns true. This is
125+ // used single-variant messages to return their only variant.
113126 if ( variant . keys . every ( matches_corresponding_selector ) ) {
114127 return variant ;
115128 }
0 commit comments