Skip to content

Commit 93ab099

Browse files
feat(mf2): Apply NFC normalization to names and keys (unicode-org/message-format-wg#885)
1 parent cbfa8a9 commit 93ab099

File tree

6 files changed

+19
-9
lines changed

6 files changed

+19
-9
lines changed

mf2/messageformat/src/cst/names.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ export function parseNameValue(
5454
if (!isNameStartCode(cc)) return null;
5555
cc = src.charCodeAt(++pos);
5656
while (isNameCharCode(cc)) cc = src.charCodeAt(++pos);
57-
const name = src.substring(nameStart, pos);
57+
const value = src.substring(nameStart, pos).normalize();
5858
if (bidiChars.has(cc)) pos += 1;
59-
return { value: name, end: pos };
59+
return { value, end: pos };
6060
}
6161

6262
export function isValidUnquotedLiteral(str: string): boolean {

mf2/messageformat/src/cst/parse-cst.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,13 @@ function parseVariant(ctx: ParseContext, start: number): CST.Variant {
142142

143143
if (pos > start && !ws.hasWS) ctx.onError('missing-syntax', pos, "' '");
144144

145-
const key =
146-
ch === '*'
147-
? ({ type: '*', start: pos, end: pos + 1 } satisfies CST.CatchallKey)
148-
: parseLiteral(ctx, pos, true);
145+
let key: CST.CatchallKey | CST.Literal;
146+
if (ch === '*') {
147+
key = { type: '*', start: pos, end: pos + 1 };
148+
} else {
149+
key = parseLiteral(ctx, pos, true);
150+
key.value = key.value.normalize();
151+
}
149152
if (key.end === pos) break; // error; reported in pattern.errors
150153
keys.push(key);
151154
pos = key.end;

mf2/messageformat/src/data-model/parse.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ function variant(): Model.Variant {
9191
keys.push({ type: '*' });
9292
pos += 1;
9393
} else {
94-
keys.push(literal(true));
94+
const key = literal(true);
95+
key.value = key.value.normalize();
96+
keys.push(key);
9597
}
9698
}
9799
return { keys, value: pattern(true) };

mf2/messageformat/src/data-model/resolve-variable.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ function getValue(scope: unknown, name: string): unknown {
4242
return getValue(scope[head], tail);
4343
}
4444
}
45+
46+
for (const [key, value] of Object.entries(scope)) {
47+
if (key.normalize() === name) return value;
48+
}
4549
}
4650

4751
return undefined;

mf2/messageformat/src/functions/string.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ export function string(
3333
input?: unknown
3434
): MessageString {
3535
const str = input === undefined ? '' : String(input);
36+
const selStr = str.normalize();
3637
const [locale] = mergeLocales(locales, input, options);
3738
return {
3839
type: 'string',
3940
source,
4041
locale,
41-
selectKey: keys => (keys.has(str) ? str : null),
42+
selectKey: keys => (keys.has(selStr) ? selStr : null),
4243
toParts: () => [{ type: 'string', source, locale, value: str }],
4344
toString: () => str,
4445
valueOf: () => str

0 commit comments

Comments
 (0)