restore-format-js-ast

在 intl-messageformat 中,对于插值占位符有这么一段描述:

Usage no npm install needed!

<script type="module">
  import restoreFormatJsAst from 'https://cdn.skypack.dev/restore-format-js-ast';
</script>

README

还原 FormatJS ICU AST

intl-messageformat 中,对于插值占位符有这么一段描述:

A value must be supplied for every argument in the message pattern the instance was constructed with.

白话就是:如果你没有传入插值参数,intl-messageformat 在 format 时会抛出异常

Error: The intl string context variable "插值参数" was not provided to the string "ICU 格式文案"

而它常常被用于 JS Runtime,抛出一个未被捕获的异常很危险

这时我们希望用某些 默认值 进行兜底,如果需要用 ICU 原格式,则需要将 FormatJS 提供的 AST 进行还原

安装

npm:

npm install restore-format-js-ast

yarn:

yarn add restore-format-js-ast

使用

const { default: IntlFormatMessage } = require('intl-messageformat');
const { RestoreFormatJsAst } = require('restore-format-js-ast');

const intl = new IntlFormatMessage('I have {catNum, number} cat(s)');
const ast = intl.getAst();

const data = new RestoreFormatJsAst(ast).restore();

console.log(data.interpolationParams); // { catNum: '{catNum, number}' }
console.log(data.resource); // 'I have {catNum, number} cat(s)'

// 0.0.1-beta.2 支持
console.log(data.shortInterpolationParams); // { catNum: '{catNum}' }

// 0.0.1-beta.3 支持
console.log(data.dateTimeParams); // { dateTime: '' }

更多

RestoreFormatJsAst

restore-format-js-ast 对外暴露的一个 JS class constructor,里面有一些开箱即用的方法:

constructor

constructor(ast: MessageFormatElement[], options?: RestoreFormatJsAstOptions) {}

构造器,至多可接受两个参数:

  • ast: FormatJS 提供的抽象语法树,详见 getast-methodIntl MessageFormat Parser
  • options: 可选参数,详细配置如下:
    • shortedStr: optional,boolean,如果为 true 则最后的 resource 结果内部插值只取 参数名称,默认 false
    • dateTimeSkeleton: optional,number | string | Date | null,影响 restore 中 dateTimeParams 的占位,如果传入一个非法日期,将会用空字符串兜底

这个方法可能会抛出异常,当且仅当你传入的 AST 不符合规范时

restore

type InterpolationParams = {
  [k: string]: string; // k 对应插值参数名称
};

type RestoreReturn = {
  interpolationParams: InterpolationParams; // 插值解析结果
  shortInterpolationParams: InterpolationParams; // 插值解析结果(缩略版)
  resource: string; // ICU 句子(受 shortedStr 参数影响)
  dateTimeParams: { [k: string]: number || '' }; // 0.0.1-beta.3 支持,这个 AST 中所有 Date & Time 类型节点插值参数
};

restore(): RestoreReturn {}

这个方法可能会抛出异常,当且仅当通过 constructor 或 setAst 传入的 AST 不符合规范时

注意:以下 AST 节点在还原后不能 100% 复现原先结果

  • 所有 selectordinal 类型,例如 {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}},这只是 plural 类型的变体,在 AST 中也是表现为 PluralElement 类型的节点
  • 所有 Quoting 格式,例如 haha '{name}',在 AST 中表现为 LiteralElement,且 value 对应为 haha {name}
  • 所有转义字符,例如 isn''t,在 AST 中表现为 LiteralElement,且 value 对应为 isn't

restore 方法在第一次执行后会存储缓存,直到你改变 AST 或者 options 时,这意味着你可以用一个实例去解析不同的 AST

clearCache

clearCache(): void {}

清除缓存,下一次调用 restore 时将会重新计算

setAst

setAst(newAst: MessageFormatElement[]): void;

为 Restore 实例设置新的 AST,这个方法将默认调用 clearCache

这个方法可能会抛出异常,当且仅当你传入的 AST 不符合规范时

setOptions

setOptions(newOptions: RestoreFormatJsAstOptions): void;

为 Restore 实例设置新的配置项,这个方法将默认调用 clearCache


ENGLISH

Restore formatjs ICU AST

In intl-messageformat, there is a description of the interpolation placeholder:

A value must be supplied for every argument in the message pattern the instance was constructed with.

To put it simply: if you don't pass in the interpolation parameter, intl-messageformat will throw an exception in the format method

Error: The intl string context variable "Interpolation parameters" was not provided to the string "ICU text"

But it's often used in JS runtime, and it's dangerous to throw an uncapped exception

At this time, we want to use some default values to fallback. If we need to use the original format of ICU, we need to restore the AST provided by FormatJS

Install

npm:

npm install restore-format-js-ast

yarn:

yarn add restore-format-js-ast

Use

const { default: IntlFormatMessage } = require('intl-messageformat');
const { RestoreFormatJsAst } = require('restore-format-js-ast');

const intl = new IntlFormatMessage('I have {catNum, number} cat(s)');
const ast = intl.getAst();

const data = new RestoreFormatJsAst(ast).restore();

console.log(data.interpolationParams); // { catNum: '{catNum, number}' }
console.log(data.resource); // 'I have {catNum, number} cat(s)'

// support after 0.0.1-beta.2
console.log(data.shortInterpolationParams); // { catNum: '{catNum}' }

// support after 0.0.1-beta.3
console.log(data.dateTimeParams); // { dateTime: '' }

More

RestoreFormatJsAst

restore-format-js-ast will exposed a JS class constructor to the public. There are some methods out-of-the-box:

constructor

constructor(ast: MessageFormatElement[], options?: RestoreFormatJsAstOptions) {}

Constructor, which can accept at most two parameters:

  • ast: For the abstract syntax tree provided by formatjs, see getast-method and Intl MessageFormat Parser
  • options: Optional parameters, the detailed configuration is as follows:
    • shortedStr: optional,boolean,If it is true, only the parameter name is used for the internal interpolation of the last resource result, and the default value is false
    • dateTimeSkeleton: optional, number | string | Date | null, Affect the placeholder of dateTimeParams in restore. If an illegal date is passed in, an empty string will be used to cover it

This method may throw an exception if and only if the ast you pass in does not conform to the specification

restore

type InterpolationParams = {
  [k: string]: string; // k corresponds to the name of the interpolation parameter
};

type RestoreReturn = {
  interpolationParams: InterpolationParams; // Interpolation analysis result
  shortInterpolationParams: InterpolationParams; // Interpolation analysis results (abbreviated version)
  resource: string; // ICU sentence (affected by the shortedStr parameter)
  dateTimeParams: { [k: string]: number || '' }; // 0.0.1-beta.3 support, all Date & Time type node interpolation parameters in this AST
};

restore(): RestoreReturn {}

this method may throw an exception if and only if the ast passed through constructor or setast does not conform to the specification

Note: the following ast nodes cannot reproduce the original results 100% after restoration

  • All selectordinal types, such as {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} are only variants of the plural type, and are also nodes of the PluralElement type in AST
  • All Quoting formats, such as haha '{name}', are represented as LiteralElement in AST, and value corresponds to haha {name}
  • All escape characters, such as isn''t, are represented as LiteralElement in AST, and value corresponds to isn't

The restore method stores the cache after the first execution until you change the ast or options, which means that you can use an instance to parse different asts

clearCache

clearCache(): void {}

Clear the cache. It will be recalculated the next time restore is called

setAst

setAst(newAst: MessageFormatElement[]): void;

Set a new ast for the restore instance this method will call clearcache by default

This method may throw an exception if and only if the ast you pass in does not conform to the specification

setOptions

setOptions(newOptions: RestoreFormatJsAstOptions): void;

Set a new configuration item for the restore instance, this method will call clearcache by default