For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/year/pending/proposal-intl-sequence-units.md.
  • 简体中文
  • Intl Sequence Units ?

    中文标题:Intl 序列单位

    提案概览
    提案速览

    本提案解决了 Intl.NumberFormat 中缺乏标准化方式来格式化测量单位序列(例如英尺和英寸)的问题,目前需要手动组合且在不同区域设置下容易出错。它扩展了 Intl.NumberFormat 以接受复合单位标识符(如 'foot-and-inch')和对象输入用于 format/formatToParts,并规定了符号一致性和中间单位为整数的验证规则。DurationFormat 处理的时间单位。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    Intl 序列单位

    本提案规定了在 Intl.NumberFormat 中格式化测量单位序列(例如“英尺和英寸”或“米和厘米”)的机制。

    演示文稿:

    • 第 114 届 TC39 会议(2026 年 5 月):阶段 1 和 2 - 幻灯片 | 笔记
    • 第 115 届 TC39 会议(2026 年 7 月):幻灯片

    动机

    测量系统经常使用多个单位顺序排列来表达单一量值。示例包括:

    • 人的身高:“5 英尺 11 英寸”或“1 米 80 厘米”
    • 质量:“2 磅 4 盎司”

    当前 ECMAScript 实现要求手动组合多个 Intl.NumberFormat 的输出。这种方法引入了与本地化分隔符、单位排序和复数形式一致性相关的风险,这些在不同区域设置中差异很大。本提案通过提供用于多单位格式化的标准化接口来解决这些需求。

    例如,要格式化“5 英尺 11 英寸”,目前开发人员必须编写:

    const feetNf = new Intl.NumberFormat("en", { style: "unit", unit: "foot" });
    const inchNf = new Intl.NumberFormat("en", { style: "unit", unit: "inch" });
    const lf = new Intl.ListFormat("en", { type: "unit" });
    
    lf.format([feetNf.format(5), inchNf.format(11)]);
    // "5 feet, 11 inches"

    虽然这是可行的,但它不够符合人体工程学,并且容易出错:

    • 它需要创建和管理多个 Intl.NumberFormat 实例。
    • 开发人员必须手动确保正确的单位顺序。
    • 它不会自动处理整个序列中的符号显示(例如,仅在第一个单位上显示负号)。

    提议的解决方案

    Intl.NumberFormat 被扩展以支持由 -and- 分隔符连接的复合单位标识符(例如,foot-and-inchmeter-and-centimeterpound-and-ounce)。

    当指定序列单位时,formatformatToParts 接受一个 JavaScript 对象作为输入。对象的每个属性必须对应于序列中标识的子单位。

    示例

    const nf = new Intl.NumberFormat('en-US', {
      style: 'unit',
      unit: 'foot-and-inch',
    });
    
    // "5 feet, 11 inches"
    nf.format({ foot: 5, inch: 11 }); 
    
    // "-5 feet, 11 inches"(只有第一个单位显示负号)
    nf.format({ foot: -5, inch: -11 }); 
    
    const massNf = new Intl.NumberFormat('en-US', {
      style: 'unit',
      unit: 'pound-and-ounce',
      unitDisplay: 'long'
    });
    
    // "2 pounds, 4 ounces"(实际输出取决于区域设置)
    massNf.format({ pound: 2, ounce: 4 });

    技术语义

    序列单位的格式化过程遵循以下步骤:

    1. 验证:序列必须是受支持单位的有效组合,这些单位测量相同的物理量并按量级降序排列。受支持的序列在规范中明确列出(例如,foot-and-inchkilogram-and-gram)。请注意,时间单位被排除在序列单位之外,因为它们由 Intl.DurationFormat 管理。
    2. 提取:根据子单位键从输入对象中获取值。
    3. 组件格式化
      • 中间单位:必须是整数,并按整数格式化。
      • 终端单位:根据配置在 Intl.NumberFormat 实例上的舍入和小数设置进行格式化。
    4. 组合:使用 Intl.ListFormattype: "unit" 和指定的 unitDisplay 样式)连接生成的组件字符串,以确保符合区域设置的连接词和间距。

    错误处理

    formatformatToParts 的输入必须包含单位标识符中定义的每个子单位的值。属性按其在单位标识符序列中出现的顺序读取。如果必需属性为 undefined 或缺失,则立即抛出 TypeError

    读取所有属性并将其转换为数字后,进行两次最终验证:

    1. 混合符号:所有子单位必须具有相同的符号。混合正负值(例如,{ foot: 5, inch: -11 })会抛出 RangeError
    2. 中间整数:所有中间子单位(除最后一个之外的所有子单位)必须是整数。提供非整数中间值(例如,{ foot: 5.5, inch: 6 })会抛出 RangeError
    // 抛出 RangeError:无效的单位序列(不在受支持的组或顺序中)
    new Intl.NumberFormat('en-US', { style: 'unit', unit: 'meter-and-foot' });
    
    const nf = new Intl.NumberFormat('en-US', {
      style: 'unit',
      unit: 'foot-and-inch',
    });
    
    // 抛出 TypeError:缺少 'inch' 属性
    nf.format({ foot: 5 }); 
    
    // 抛出 RangeError:子单位具有混合符号
    nf.format({ foot: 5, inch: -11 });
    
    // 抛出 RangeError:中间子单位不是整数
    nf.format({ foot: 5.5, inch: 6 });

    与 Intl 单位协议的集成

    本提案与 Intl 单位协议 兼容。使用该协议时,value 属性接受将子单位映射到其各自量级的对象:

    const nf = new Intl.NumberFormat('en-US');
    
    nf.format({ 
      unit: "foot-and-inch", 
      value: { foot: 6, inch: 4 } 
    });

    与 Amount 提案的集成

    本提案与 Amount 提案保持一致。为了支持序列单位,Amount 实例封装一个结构化值(一个将子单位映射到量级的对象),而不是标量数值。

    先前工作

    序列单位的格式化要求定义在 Unicode 技术标准 #35(LDML)中,第 单位序列(混合单位) 节。TR35 指定使用本地化的 listPattern 数据来组合这些序列,本提案为 ECMAScript 实现了这一点。

    未来方向

    附加单位

    一些常用于序列的单位,例如 arcminutearcsecond,目前并非 ECMA-402 中的受支持单位。格式化角度测量值,如“5° 30′ 12″”(概念上会使用 degree-and-arcminute-and-arcsecond),需要单独的提案将 arcminutearcsecond 添加到受支持的单单位标识符列表中,然后才能将它们用作序列单位。

    考虑的替代方案

    标量输入与自动分区

    接受单个标量值(例如 6.5)并自动将其分区为序列单位(例如“6 英尺 6 英寸”)的可能性已被评估并拒绝,原因如下:

    • 输入歧义:标量输入并不固有地定义它们代表序列中的哪个子单位(例如,在 foot-and-inch 中,不清楚 6.5 是指英尺还是英寸)。
    • 转换数据不完整:引擎可能不具备所有可能单位组合的转换因子,特别是对于自定义或未来的单位。这排除了可靠的自动分区。
    • 精度和舍入:通过浮点运算进行自动分区可能会引入错误。要求预先分区的输入可确保输出准确反映开发人员的数据。