messageformat 包:在 JS 里跑 MF2
MF2 目前不是浏览器内置 API(ECMA-402 的 Intl.MessageFormat 仍在提案阶段),在 JS 里用它要装 messageformat 包(v4,实现 LDML 48 与 TC39 提案)。本页这些 demo 的输出全部由打包进来的真实引擎实时产生。核心就一个 MessageFormat 类,外加一组数据模型工具函数。
1 · 安装与构造
日期 / 货币等 DRAFT 函数不在默认注册表,需经 functions 选项传 DraftFunctions 开启:
构造一个 formatter
import { MessageFormat } from 'messageformat';
import { DraftFunctions } from 'messageformat/functions';
const mf = new MessageFormat(
'en', // locales: string | string[] | undefined
'Hello {$name}, today is {$d :date length=long}',
{ functions: DraftFunctions } // options (可选)
);
| 构造选项 | 作用 |
|---|---|
functions |
注册自定义 / DRAFT 函数,扩展默认注册表 |
bidiIsolation |
'default'(默认,隔离插值)/ 'none'(不加隔离符) |
dir |
显式指定基准方向 'ltr' / 'rtl' / 'auto',默认按 locale 推断 |
localeMatcher |
多 locale 时的协商算法 'best fit' / 'lookup' |
2 · format() 与 formatToParts()
构造好后,format(values?, onError?) 出字符串;formatToParts(values?, onError?) 出零件数组(拿来做富文本 / 拆分样式 / 处理 markup)。改下面的源与值,两个出口同时看:
第二参 onError 回调捕获运行期错误;不传时引擎默认把错误以 console.warn 打出,并仍返回 回退结果(不会中断整条消息)。本系列的封装把错误收集起来显示在红框里。注意 v4 的 MessageFormat 没有
resolvedOptions()。
3 · 自定义函数
functions 选项里登记的每个函数签名是 (ctx, options, operand) => MessageValue。返回的 MessageValue 至少要能 toString()(供 format)与 toParts()(供 formatToParts);若还想参与 .match,再实现
selectKey(keys)。下例加一个 :uppercase:
自定义 :uppercase 函数
const uppercase = (ctx, options, operand) => {
const out = String(operand ?? '').toUpperCase();
return {
type: 'string',
toString: () => out,
toParts: () => [{ type: 'string', value: out }]
};
};
const mf = new MessageFormat('en', 'WARNING: {$msg :uppercase}',
{ functions: { uppercase } });
mf.format({ msg: 'disk full' });
4 · 数据模型:parseMessage / stringifyMessage / validate
除了「源串 → 输出」,包还暴露数据模型层:parseMessage(src) 把消息解析成结构化对象树(可程序化改写、做 lint / 提取),stringifyMessage(model) 反向序列化,validate(model) 返回消息用到的 functions 与
variables 集合。写一条消息看它的树:
包里还有一组类型守卫(isExpression / isLiteral / isMarkup / isSelectMessage …)与遍历器 visit(model, visitors),配合数据模型做静态分析 / 转换。子路径 messageformat/cst 还提供更底层的具体语法树(保留空白 /
注释,适合写编辑器、格式化器)。