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/fix-9-2-3-lookupmatcher-algorithm.md.
  • 简体中文
  • Fix 9.2.3 LookupMatcher algorithm S0

    中文标题:修复 9.2.3 LookupMatcher 算法

    提案概览
    提案速览

    该提案旨在修复 ECMA-402 中的 LookupMatcher 算法,该算法目前无法正确将 az-IRzh-AU 等区域设置解析为正确的语言/脚本变体。问题在于当前算法过于激进地截断子标签,导致错误的回退。

    Note

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

    更新

    阶段 0

    Ecma-402 中有一个关于查找匹配(Lookup Matching)的规范,由 LookupMatcher(9.2.3)和 BestAvailableLocale(9.2.2)描述。它基于 RFC 4647 第 3.4 节中描述的查找算法。但是,Ecma-402 规范和 RFC 4647 算法在某些情况下都无法执行该任务。例如:

    • az-IR 映射到 azaz-Latn-AZ 的默认值),而不是正确的 az-Arab-IR
    • en-Latn-GBen-Latn-IN 映射到 enen-Latn-US 的默认值),而不是分别正确的 en-GBen-IN
    • ha-CMha-SD 映射到 haha-Latn-NG 的默认值),而不是正确的 ha-Arab-*
    • kk-CNkk-IRkk-MN 映射到 kkkk-Cyrl-KZ 的默认值),而不是正确的 kk-Arab-*
    • sr-MEsr-ROsr-RUsr-TR 映射到 srsr-Cyrl-RS 的默认值),而不是正确的 sr-Latn-*
    • uz-AF 映射到 uzuz-Latn-UZ 的默认值),而不是正确的 uz-Arab-AF
    • zh-AUzh-BNzh-GBzh-GFzh-IDzh-MOzh-MYzh-PAzh-PFzh-PHzh-SRzh-THzh-USzh-VN 映射到 zhzh-Hans-CN 的默认值),而不是正确的 zh-Hant-*

    影响

    错误的规范可以在当今的实现中观察到。

    // 以下两个错误都发生在最新的 Firefox 和 Chrome 上。
    
    new Intl.NumberFormat("az").format(NaN); // "NaN" (符合预期)
    new Intl.NumberFormat("az-IR").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    
    new Intl.NumberFormat("en-IN").format(123456789); // "12,34,56,789" (符合预期)
    new Intl.NumberFormat("en-Latn-IN").format(123456789); // "123,456,789" (绕过了 en-IN)
    
    new Intl.DateTimeFormat("en-GB").format(new Date()); // "13/01/2015" (符合预期)
    new Intl.DateTimeFormat("en-Latn-GB").format(new Date()); // "1/13/2015" (绕过了 en-GB)
    
    new Intl.NumberFormat("ha-CM").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    new Intl.NumberFormat("ha-SD").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    
    new Intl.NumberFormat("kk-AF").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    new Intl.NumberFormat("kk-CN").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    new Intl.NumberFormat("kk-IR").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    
    new Intl.DateTimeFormat("sr", {month: "long"}).format(new Date()); // "фебруар" (符合预期)
    new Intl.DateTimeFormat("sr-Latn", {month: "long"}).format(new Date()); // "februar" (符合预期)
    new Intl.DateTimeFormat("sr-ME", {month: "long"}).format(new Date()); // "februar" (符合预期)
    new Intl.DateTimeFormat("sr-ME", {month: "long"}).format(new Date()); // "фебруар" (错误,预期为拉丁语)
    new Intl.DateTimeFormat("sr-RO", {month: "long"}).format(new Date()); // "фебруар" (错误,预期为拉丁语)
    new Intl.DateTimeFormat("sr-RU", {month: "long"}).format(new Date()); // "фебруар" (错误,预期为拉丁语)
    new Intl.DateTimeFormat("sr-TR", {month: "long"}).format(new Date()); // "фебруар" (错误,预期为拉丁语)
    
    new Intl.NumberFormat("uz").format(NaN); // "NaN" (符合预期)
    new Intl.NumberFormat("uz-AF").format(NaN); // "NaN" (错误,预期为阿拉伯语)
    
    new Intl.NumberFormat("zh").format(NaN); // "NaN" (符合预期)
    new Intl.NumberFormat("zh-AU").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-BN").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-CN").format(NaN); // "NaN" (符合预期)
    new Intl.NumberFormat("zh-GB").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-GF").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-HK").format(NaN); // "非數值" (符合预期)
    new Intl.NumberFormat("zh-ID").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-MO").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-MO").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-MY").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-PA").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-PF").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-PH").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-SR").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-TH").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-TW").format(NaN); // "非數值" (符合预期)
    new Intl.NumberFormat("zh-US").format(NaN); // "NaN" (错误,预期为繁体中文)
    new Intl.NumberFormat("zh-VN").format(NaN); // "NaN" (错误,预期为繁体中文)

    原因

    指定的算法过于简单。它基本上指示实现执行子标签截断,直到找到区域设置,这是错误的。相关问题和更多细节可以在以下地方找到:

    修复

    根据 Mark Davis 的说法,"推荐的捆绑包查找方法是使用语言匹配"。因此,有两个选项:

    1. 遵循 Unicode 技术标准 #35 指定的 Language Matching 算法。
    2. 遵循 [cldrjs 中更快的算法][],该算法在考虑 100% 分数阈值的情况下产生与语言匹配相同的结果。