[Stable Formatting] stable-formatting ?
中文标题:稳定格式化
- 阶段: 未分阶段
- 状态: 进行中
- ECMAScript 版本: —
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案为 Intl 格式化器引入 zxx 区域设置,以提供稳定、与实现无关的格式化输出,解决当前 Intl 行为缺乏稳定性的问题。它定义了 zxx 在各种 Intl API 中的具体格式化行为,例如日期使用 ISO-8601,并添加了 Intl.STABLE 属性以便使用。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
稳定格式化
一个 TC39 提案,旨在为 ECMAScript 带来稳定的、受 Intl 启发的格式化选项。
阶段: 2
提案推动者: Eemeli Aro
审阅者: Richard Gibson, Dan Minor
演示文稿:
动机
Intl 格式化器以及 ECMA-402 定义的其他接口高度依赖实现,并且可能随时间发生变化。这意味着这些函数的输出不应被依赖,因为它们仅旨在提供“尽力而为”的结果,供立即向用户展示。
然而,这并未阻止用户依赖字符串格式化器具有精确的输出结构,尤其是使用 en-US 区域设置的日期格式化。最近的例子可见于 2022年6月 和 2022年11月。在 2023年6月 TC39-TG2 的此演示文稿中可以了解更多。
缺乏稳定性也使得测试 Intl API 或依赖 Intl API 的网站和应用变得具有挑战性,因为实现差异可能导致不同环境中产生不同的结果。
另外,有时需要为国际受众格式化值,或出于其他原因使用不特定于某个区域设置的格式。Intl 格式化器目前对此支持不佳。例如,StackOverflow 上关于如何使用 ISO-8601 格式格式化日期的最高票建议是使用瑞典语作为区域设置。
提议的解决方案
在 ECMA-402 中定义每种格式化器在 zxx 区域设置下的行为。此区域设置标识符(表示“无语言内容;不适用”)是 ISO 639.2 中定义的有效 BCP 47 主要语言标签,但其行为在其他方面并未得到很好的定义。
为便于使用,添加值为 "zxx" 的 Intl.STABLE 属性。
在可能的情况下,zxx 区域设置将使用有明确定义的标准行为,例如对日期格式化使用 ISO-8601。
zxx 的“本地化”输出将避免在输出中包含实际本地化文本,例如完整写出的单位名称或月份名称。
对于接受自然语言输入而不仅仅是产生自然语言输出的 Intl API(Collator、Segementer、String.prototype.toLocale{Lower,Upper}Case),我们不容易保证有用的稳定行为。目前不建议为它们提供 zxx 支持。
Intl.DateTimeFormat
当使用 zxx 区域设置时,格式化输出与 Temporal 使用的输出匹配。为实现这一点,应用以下默认选项值:
在格式化输出中,适当时使用输入值的 RFC 9557 序列化,例如 2006-01-02、15:04:05、2006-01-02T15:04:05.999+01:00[Europe/Paris]。仅使用时间和日期值的数字表示,如下所示:
hour12 和 hourCycle 选项会被验证但忽略,并且格式化始终如同设置了 hour12: false 一样进行。
dayPeriod、weekday、era 选项会被验证但忽略。
month 选项的值 'long' 和 'short' 被视为等同于其 '2-digit' 值,'narrow' 被视为等同于其 'numeric' 值。
如果 timeZoneName 选项具有有效值,则无论选项值如何,都会使用规范的 IANA 时区标识符作为时区。
如果 dateStyle 选项具有有效值,则格式化输出始终以格式如 2006-01-02 的日期开头。
如果 timeStyle 选项具有有效值,则格式化输出始终以如下格式的时间结尾:
'full'或'long':15:04:05+01:00[Europe/Paris]'medium':15:04:05'short':15:04
如果同时设置了 dateStyle 和 timeStyle 选项,则格式化输出由格式化后的日期、后跟 T (U+0054)、再后跟格式化后的时间组成。
Intl.DisplayNames
当 zxx 区域设置与有效格式化选项一起使用时,使用结构上有效的输入调用 of(code) 方法将表现为没有匹配的显示名称可用,并根据 fallback 选项返回请求的代码或 undefined。
Intl.DurationFormat
当 zxx 区域设置与有效格式化选项一起使用时,格式化的持续时间是 '{number} {unit}' 条目的串联,由 ', ' 分隔,例如 2 year、2 hour, 30 minute 或 5 day, 1 millisecond,或者使用 style: 'digital' 时是以 : 分隔的时间值。
Intl.ListFormat
当使用 zxx 区域设置时,type 选项值会被验证但忽略,输出由 style 选项决定:
'long'或'short':列表项由逗号后跟空格,(U+002C U+0020) 分隔'narrow':列表项由空格 (U+0020) 分隔
Intl.Locale
对于 zxx 区域设置,所有字段和访问器返回其默认/回退值,除了 .getCalendars(),它返回 ['iso8601'] 而不是 ['gregory']。
Intl.NumberFormat
当使用 zxx 区域设置时,格式化输出的数值部分始终满足 StrNumericLiteral 语法符号。在区域设置选项中,'latn' 用作 numberingSystem 选项的默认值。
当与 style: 'currency' 选项一起使用时,输出包括数值、后跟一个空格 (U+0020)、再后跟 ISO 货币代码。currencyDisplay 选项值会被验证但忽略。如果 intl-currency-display-choices 提案被接受,则使用 currencyDisplay: 'never' 选项会从输出中省略除数值之外的所有内容。
当与 style: 'percent' 选项一起使用时,输出包括数值后跟 U+0025 百分号字符。
当与 style: 'unit' 选项一起使用时,输出由 unitDisplay 选项决定:
'short':数值、后跟一个空格 (U+0020)、再后跟短单位标识符'narrow':数值、后跟短单位标识符'long':数值、后跟一个空格 (U+0020)、再后跟长单位标识符
“长单位标识符”是 unit 选项值。
“短单位标识符”是一个与语言环境无关的字符串,由 unit 选项值派生而来,需要根据 SI 单位等显式定义,例如 litre 的 l 和 terabyte 的 TB。复合单位通过将 -per- 替换为斜杠 / (U+002F) 并将单位部分分别映射到其短单位标识符来形成。
当与 notation: 'compact' 选项一起使用时,输出包括数值后跟适当的 SI 前缀:
- 1012:
T(U+0054) - 109:
G(U+0047) - 106:
M(U+004D) - 103:
k(U+006B)
compactDisplay 选项会被验证但忽略。
useGrouping 选项会被验证但忽略,并且分组分隔符永远不会包含在输出中。
Intl.PluralRules
当 zxx 区域设置与有效格式化选项一起使用时,使用结构上有效的输入调用 select(number) 和 selectRange(startRange, endRange) 方法将始终返回 'other'。
Intl.RelativeTimeFormat
当 zxx 区域设置与有效格式化选项一起使用时,格式化的相对时间是 ISO 8601-2 持续时间,其第一个字符为加号 + (U+002B) 或连字符减 - (U+002D),例如 +P2Y(2年后)、-P1D(昨天)或 +PT10S(10秒后)。
季度以月表示。
Array.prototype.toLocaleString
当使用 zxx 区域设置时,数组项以逗号 , (U+002C) 作为分隔符进行连接。
备选方案
向 ECMA-262 格式化器添加选项
更改
Date.prototype.toString()21.4.4.41Number.prototype.toString([radix])21.1.3.6BigInt.prototype.toString([radix])21.2.3.3
以包含一个新的可选 options 参数:
Date.prototype.toString([options])Number.prototype.toString([radix] [, options])BigInt.prototype.toString([radix] [, options])
并指定这三个函数应如何读取选项并不同地创建格式化结果字符串
Date.prototype.toString 读取和尊重的选项将只是 toLocaleString 方法接受的选项的子集。例如,它不会读取 "localeMatcher"、"calendar"、"numberingSystem"、"hour12"、"dateStyle" 和 "timeStyle",但会读取 "hourCycle"、"timeZone"。提案可以决定是否读取 表 7 中列出的选项。
Number.prototype.toString 和 BigInt.prototype.toString 读取和尊重的选项将只是 toLocaleString 方法接受的选项的子集。例如,它们不会读取 "localeMatcher"、"numberingSystem"、"style"、"currency"、"currencyDisplay"、"currencySign"、"unit"、"unitDisplay",但会读取 表 12 中列出的其他选项。
Number 和 BigInt 方法也可以允许 options 参数替换 radix 参数,根据该参数的类型确定行为。
这种方法不会包含 Intl 格式化器的 formatToParts 方法的任何等价物。
添加“未确定”区域设置
此提案的早期版本使用了“未确定”的 und 区域设置而不是 zxx。这也是一个有效的 ISO 639.2 语言标识符,但它被用作 CLDR 中的规范根区域设置标识符,例如在 java.util.Locale 中具有明确定义的行为。
und 区域设置目前也被 Safari 支持为 en-US-u-va-posix 的别名,并且被 Chrome 和 Node.js 认可用于 Intl.Locale。
添加新的 ECMA-262 格式化方法
与其修改 Date、Number 和 BigInt 现有的 toString 方法,不如为每个添加新的方法 toFormattedString,并带有如上定义的 options 参数。