Skip to content

Commit bb16ec8

Browse files
feat(mf2): Always isolate when u:dir is set (unicode-org/message-format-wg#942)
1 parent 6b2d1a6 commit bb16ec8

File tree

5 files changed

+24
-6
lines changed

5 files changed

+24
-6
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { MessageExpressionPart } from './formatted-parts.js';
2+
3+
export const BIDI_ISOLATE = Symbol('bidi-isolate');
4+
5+
export interface MessageValue {
6+
readonly type: string;
7+
readonly source: string;
8+
readonly locale: string;
9+
readonly dir?: 'ltr' | 'rtl' | 'auto';
10+
readonly options?: Readonly<object>;
11+
selectKey?: (keys: Set<string>) => string | null;
12+
toParts?: () => MessageExpressionPart[];
13+
toString?: () => string;
14+
valueOf?: () => unknown;
15+
[BIDI_ISOLATE]?: boolean;
16+
}

mf2/messageformat/src/messageformat.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
string,
1616
time
1717
} from './functions/index.js';
18-
import type { MessageValue } from './message-value.js';
18+
import { BIDI_ISOLATE, type MessageValue } from './message-value.js';
1919
import { formatMarkup } from './resolve/format-markup.js';
2020
import type { MessageFunctionContext } from './resolve/function-context.js';
2121
import { resolveExpression } from './resolve/resolve-expression.js';
@@ -136,7 +136,7 @@ export class MessageFormat {
136136
if (typeof mv.toString === 'function') {
137137
if (
138138
this.#bidiIsolation &&
139-
(this.#dir !== 'ltr' || mv.dir !== 'ltr')
139+
(this.#dir !== 'ltr' || mv.dir !== 'ltr' || mv[BIDI_ISOLATE])
140140
) {
141141
const pre = mv.dir === 'ltr' ? LRI : mv.dir === 'rtl' ? RLI : FSI;
142142
res += pre + mv.toString() + PDI;
@@ -176,7 +176,7 @@ export class MessageFormat {
176176
const mp = mv.toParts();
177177
if (
178178
this.#bidiIsolation &&
179-
(this.#dir !== 'ltr' || mv.dir !== 'ltr')
179+
(this.#dir !== 'ltr' || mv.dir !== 'ltr' || mv[BIDI_ISOLATE])
180180
) {
181181
const pre = mv.dir === 'ltr' ? LRI : mv.dir === 'rtl' ? RLI : FSI;
182182
parts.push({ type: 'bidiIsolation', value: pre }, ...mp, {

mf2/messageformat/src/resolve/function-context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class MessageFunctionContext {
3636
const dir = String(resolveValue(ctx, dirOpt));
3737
if (dir === 'ltr' || dir === 'rtl' || dir === 'auto') {
3838
this.dir = dir;
39-
} else {
39+
} else if (dir !== 'inherit') {
4040
const msg = 'Unsupported value for u:dir option';
4141
const optSource = getValueSource(dirOpt);
4242
ctx.onError(new MessageResolutionError('bad-option', msg, optSource));

mf2/messageformat/src/resolve/resolve-function-ref.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
import { MessageError } from '../errors.js';
88
import type { Context } from '../format-context.js';
99
import { fallback } from '../functions/fallback.js';
10+
import { BIDI_ISOLATE } from '../message-value.js';
1011
import { MessageFunctionContext } from './function-context.js';
1112
import { getValueSource, resolveValue } from './resolve-value.js';
1213

@@ -24,7 +25,7 @@ export function resolveFunctionRef(
2425
}
2526
const msgCtx = new MessageFunctionContext(ctx, source, options);
2627
const opt = resolveOptions(ctx, options);
27-
const res = rf(msgCtx, opt, ...fnInput);
28+
let res = rf(msgCtx, opt, ...fnInput);
2829
if (
2930
res === null ||
3031
(typeof res !== 'object' && typeof res !== 'function') ||
@@ -36,6 +37,7 @@ export function resolveFunctionRef(
3637
`Function :${name} did not return a MessageValue`
3738
);
3839
}
40+
if (msgCtx.dir) res = { ...res, dir: msgCtx.dir, [BIDI_ISOLATE]: true };
3941
if (msgCtx.id && typeof res.toParts === 'function') {
4042
return {
4143
...res,

0 commit comments

Comments
 (0)