Copyright © 2017-2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本文档描述了识别 Web 上所用字符串的语言和方向的最佳实践。
本节描述本文档在发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。
我们欢迎对本文档提出意见,但为了便于跟踪,请针对每条意见分别提交议题,并使用 URL 指向您所评论的章节。
本文档由国际化 工作组使用 推荐标准 流程发布为 首次公开工作草案。
发布为 首次公开工作草案并不意味着 W3C 及其成员认可本文档。
本文档是一份草案,可能随时由其他文档更新、取代或废止。除非将其作为 一项正在进行的工作,否则不宜引用本文档。
本文档由一个依据 W3C 专利 政策 运作的工作组编制。 W3C 维护了一份 公开的专利 披露列表, 其中列出了与该工作组交付成果相关的所有专利披露; 该页面还包含 专利披露说明。任何实际 知晓其认为包含 必要权利要求 的专利的个人,都必须依照 W3C 专利政策第 6 节披露相关信息。
本文档受 2025年8月18日 W3C 流程文档管辖。
本文档是国际化工作组对一系列基于 JSON、WebIDL 和其他非标记数据语言的格式规范进行审查并加以观察后形成的成果。与 XML 等标记格式不同,这些数据语言通常不提供可扩展属性,并且在设计之初也没有内置语言或方向元数据。
只要 Web 上使用字符串,本文档中的概念就适用,无论这些字符串是正式数据结构的一部分,还是仅来自 JavaScript 脚本或任何已存储的字符串列表。
Web 上的自然语言 信息依赖语言和方向元数据,并可从中受益。除了支持 Unicode 之外,在为 Web 开发新格式和技术时,提供相应机制以包含并指定文本范围的块方向和 自然 语言,是关键的国际化注意事项之一。
HTML 和 XML 等标记格式以及 CSS 和 XSL 等相关样式语言已经相当成熟,并通过内置功能支持世界各地语言的交换和呈现。字符串和基于字符串的数据格式也需要类似的机制, 以确保对世界各地语言和文化提供完整且一致的支持。
在本文档中,[RFC2119] 规定的斜体大写 关键字具有其通常含义。我们还使用以下样式约定:
定义以不同的背景色和装饰显示,如下所示。
最佳实践以不同的背景色和装饰显示,如下所示。
本节简要定义理解本文档内容所必需的关键术语。此处的大多数术语取自 [I18N-GLOSSARY],为方便起见在此重复列出。
如果您不熟悉双向文本或从右到左文本,可在此处阅读基础 介绍。它将帮助您初步了解 Unicode 双向 算法的工作原理,以及它与块方向 之间的相互作用,从而为阅读本文档奠定良好基础。更多资料可在国际化工作组的面向规范 开发者的最佳实践中找到。
元数据是关于数据的数据: 它是包含在数据结构中,用于提供额外上下文、含义或呈现方式的信息。在本文档中,元数据的作用是表达有关方向和 语言的信息。[I18N-GLOSSARY]
生产者是创建自然 语言字符串数据以供以后存储、处理或交换的任何过程。[I18N-GLOSSARY]
消费者是接收 自然语言字符串以进行显示或处理的任何过程。[I18N-GLOSSARY]
序列化约定是生产者与消费者之间对于 字符串元数据序列化方式的共同理解,包括如何理解、序列化、读取、传输、移除这些元数据等。[I18N-GLOSSARY]
Unicode 双向算法 [UAX9](也称为 UBA)定义了段落方向的概念。这是 “段落”的初始基础方向,其值可解析为从左到右或 从右到左。“段落”一词在 UBA 内部具有特定含义。在 本文档的上下文中,该术语可能引起误解,因为 Web 上的字符串和其他数据通常不是某种文档格式中的 “文本段落”。本文档通常使用以下两个更具体的术语:
块方向。文本块的初始基础方向,可解析为 从左到右或从右到左。块是指作为整体的文本单元,例如文档中的段落或数据文件中的字符串。 选择“块”这一名称是为了与行内方向形成对比。Unicode 将此值称为段落 方向。[I18N-GLOSSARY]
字符串方向。特定字符串的整体方向,它表示 字符串内部各方向游程的呈现顺序。通过各种数据结构传输的字符串通常会被插入某个块中(例如段落)。在 这种情况下,字符串方向需要作为字符串双向隔离的一部分。
本文档关注如何识别整个字符串的字符串方向, 以及在各种上下文中显示字符串时如何传输和应用字符串方向。本文档不讨论如何确定字符串内部文本游程的方向或显示方式。
双向 算法主要根据字符属性来排列相邻字符。块方向规定:(a) 具有强方向类型的 LTR 和 RTL 字符游程的视觉顺序和显示方向; 以及 (b) 对于标点符号等弱方向或中性字符,这些项目相对于其他内容的位置。
不能脱离上下文来考虑处理字符串元数据的各种替代方案:我们需要建立一个用于讨论字符串处理和数据格式的框架。
字符串可以通过多种方式创建,包括内容作者在纯文本编辑器、短信或编辑工具中输入字符串;脚本从网页抓取文本; 或从其他应用程序或存储库获取现有字符串集合。在本文档所考虑的数据格式中,许多字符串来自后端数据存储库或 各种类型的数据库。字符串来源可能提供接口、API 或元数据,其中包含有关数据的字符串方向和语言的信息。有些来源还会 在未提供或未指定方向或语言时提供适当的默认值。在本文档中,字符串的生产者是创建或提供 字符串以供存储或传输的来源,无论它是人还是某种机制。
创建字符串时,有必要:(a) 检测或捕获应与该字符串关联的适当语言和字符串方向;以及 (b) 在需要时采取措施,以能够存储和传达该语言及字符串方向的方式设置字符串。
例如,对于从 HTML 表单中提取的字符串,可以从表单字段的计算值中检测字符串方向。此值可能继承自更早的元素,例如 html 元素,也可能通过 input
元素自身的标记或样式设置。用户还可以通过使用
键盘快捷键更改表单字段的方向,从而设置文本方向。dirname
属性提供了一种随表单提交自动传达该值的方法。
同样,HTML 表单中的语言信息通常继承自 html 标签上的 lang 属性,或树中具有 lang 属性的祖先元素。
如果字符串生产者从某个由另一生产者存储字符串的位置接收该字符串,并且字符串的字符串方向和语言已确定,则生产者需要了解 语言和字符串方向已经设置,并了解如何为其消费者转换或编码这些信息。
消费者是接收字符串进行处理,并且可能将其放入会向用户公开的上下文中的应用程序或过程。出于显示目的,它 必须确保在该上下文中正确地将字符串的块方向和语言应用于字符串。出于处理目的,它至少必须保留 语言和方向,并且可能需要使用语言和方向数据来执行特定于语言的操作。
正确显示字符串需要通过应用附加标记、添加控制代码或设置显示属性,将字符串 方向和语言提供给渲染文档或过程。这会向渲染软件指明在当前显示上下文中应应用于 字符串的字符串方向或语言,以使字符串正确显示。对于语言和 方向,都必须明确语言所适用的文本范围边界。对于文本方向,还必须将嵌入字符串与周围文本隔离, 以避免双向算法的溢出效应 [UAX9]。
请注意,一种文档格式的消费者可能是另一种文档格式的生产者。
任何生产者与消费者之间, 都需要就文档格式包含的内容以及每个字段或属性中的数据含义达成约定。每当字符串生产者采取特殊步骤来收集并 传达该字符串的字符串方向或语言信息时, 它都必须预期字符串消费者能够理解生产者如何编码这些信息。
如果生产者未采取任何操作,消费者仍必须决定应遵循哪些规则,以确定适当的字符串方向和语言, 即使只是提供某种默认值。
在某些系统或文档格式中,字符串生产者和消费者的必要行为已被完整规定。在其他系统或格式中则没有此类约定; 用户需要自行约定如何编码、传输以及随后解码必要的语言或方向信息。JSON 等底层规范默认不提供字符串元数据 结构,因此任何基于这些规范的文档格式都需要自行提供这种“约定”。
Web 使用字符串和字符序列对大多数数据进行编码。除去不同的数据类型
(例如数字、时间值或 base64 等二进制数据序列化)后,仍有一些值被定义为使用字符串数据类型,
但并不打算用作自然
语言数据值。例如,规范定义的句法内容,如 CSS
中的保留关键字或 WebIDL 文档中各种定义的名称,并不是其各自文档格式或协议中的可本地化文本的一部分。
许多规范还允许用户在给定命名空间或文档格式中提供用户提供的值。例如,Wifi 网络上的 SSID 由用户定义,CSS 样式表中的类名也是如此。大多数规范允许(并被鼓励允许)这些名称使用广泛的 Unicode 字符。大多数用户会选择可识别为某种自然语言单词的值,因为这样更便于使用这些值。然而,即使 这些字符串由自然语言单词组成,这些类型的字符串也不被视为可本地化 文本,无需附加与语言或字符串方向有关的额外元数据。它们通常只是让 计算机能够匹配值的标识符。
一种有时很有用的判断方法是:如果将标识符替换为
tK0001.37B 之类的任意字符串后仍然被允许、能够正常工作且属于“正常”情况,那么它就不是可本地化
文本。
例如,在下面的基础示例中,JSON 文档中的所有键
(id、title、authors、language、
publisher 等)都是句法内容。ISBN、语言标签和发布日期等数据值也是句法内容。只有实际书名、
作者姓名和出版商名称是自然语言数据值,因此属于可本地化
文本。
本节包含国际化(I18N)工作组针对在 Web 数据格式中识别语言和字符串方向而制定的一组最佳实践。在某些情况下, 现有标准存在缺口,I18N 工作组的建议需要额外标准化,或者可能存在阻碍全面采用的障碍。
主要问题是如何在数据值的生产者与消费者之间建立共同的序列化约定,使双方都知道如何编码、查找和解释 每个数据字段的语言及字符串方向。 使用元数据为自然语言字符串字段同时提供语言和字符串方向, 可确保必要信息存在,并能以最少处理量提供和提取这些信息,且无需生产者或消费者扫描或修改数据。
国际化工作组在每项规范中都会检查的最基本最佳实践是:
本节介绍字符串值的四种序列化方法。规范应将这些方法结合使用,以形成在文档格式和协议中管理语言与方向元数据的完整解决方案。
避免为非语言字段 (即包含非人类语言数据的字符串)分配或要求语言或方向元数据。请注意,这包括应用程序内部数据 值 [INTERNATIONAL-SPECS]。
虽然句法内容项或 用户提供的值通常会 使用对人类具有含义的类似单词的词元(例如帮助调试),但在向用户呈现这些值时,始终需要使用可本地化的显示字符串 将其包装起来。
对于以单一语言出现的可本地化文本字段,
使用数据结构表示该值。推荐的表示形式是包含三个字段的对象。value 字段包含实际
字符串。lang 字段包含有效的 [BCP47]
语言标签。dir
字段包含字符串的字符串方向(值为
ltr、rtl 或 auto 之一)。
使用启发式方法确定语言或字符串方向在某些情况下总会失败, 因此必须有一种方法为这些字符串提供正确结果。分配元数据(无论作为资源范围的默认值, 还是字符串特定标签)是一项有意行为,可免除通过启发式方法猜测结果的需要。
优先使用元数据表示块方向, 因为这样可避免要求消费者使用首个强字符等方法推断方向,也无需使用 必须修改数据本身的方法(例如插入 RLM/LRM 标记或双向控制符)。
对于由 [WebIDL] 定义的数据结构,将每个可本地化文本
(自然语言文本)字段定义为“Localizable”。
这会将语言和方向元数据结合起来。如果得到一致采用,就能简化不同格式之间的交换。不同规范和文档格式之间的一致性 使字符串数据能够轻松交换。通过以相同方式命名字段属性并采用相同语义,不同规范可以更轻松地从其他数据来源的 资源中提取值或向其中添加值。
当资源包含多个自然语言字符串时(尤其当这些字符串都使用同一种语言时),使用上述本地化字符串表示形式可能会变得 低效。为了降低这些字符串的编码复杂度,规范可以为语言和字符串 方向建立资源级默认值。它们是两个独立的值,因为语言并不隐含方向。仍应能够使用 上述表示形式,为任意给定字符串值覆盖语言或方向。
资源范围的默认值是在 资源级或文档级指定的值,可以应用于该资源包含的任何未标记值。
规范可以定义一种机制,为给定资源中的所有字符串提供 默认语言和默认字符串 方向。但是,规范不得假定资源范围的默认值已经足够。即使提供了 资源范围的设置,也必须能够使用字符串特定元数据覆盖该默认值。
如果您的规范定义了自己的文档级默认值,请提供两个可选字段:
默认值始终可能存在例外,因此用户必须能够逐个字符串覆盖默认值。
使用元数据从外部设置方向时,不会对字符串应用首个强字符启发式方法。即使在字符串前添加了 
U+200F RIGHT-TO-LEFT MARK
之类具有强方向性的字符,
资源范围的默认元数据也可能以产生溢出效应的方式覆盖字符串的呈现。
因此,对于字符串方向与资源范围默认值不匹配的字符串,内容需要能够提供字符串级元数据来覆盖默认值。
对于可以使用 [JSON-LD] @context 机制的规范,
使用 @language 和 @direction 字段提供文档级默认值。
使用语言映射在文档中存储单个字段的多个语言版本。对于由 [WebIDL] 定义的数据结构,使用LanguageMap定义该字段。
世界并非只使用一种语言。如果文档只能包含单一语言,则为了本地化内容,需要为每种语言分别提供多个文档版本。 请求内容时还可能需要进行语言协商。
解决此问题的一种方法是允许文档内的每个可本地化文本字段 使用多语言值。
语言选择并不只是将语言标签字符串值与用户首选区域设置进行精确匹配。对象表示形式通常用于表示可本地化文本字段, 但需要反序列化该对象后才能发现与值关联的语言标签。如果给定文件中包含许多值,这种方式可能效率低下。 在这种情况下,最佳实践是使用语言映射来组织可本地化文本值。 此类映射会公开语言标签以供选择,但映射的值侧仍使用对象表示形式,因为给定字符串值可能需要覆盖语言、方向或两者。
规定在没有其他信息时,默认方向和默认语言均为未知。
如果存在显式元数据,就无需应用启发式方法。这是合理的,因为启发式方法本身无法可靠推断出必要方向, 而显式提供元数据则表明该元数据旨在作为权威信息。
消费者必须知道语言和方向是未知值,才能知道何时对数据应用回退策略(这可能包括语言检测或 用于方向的首个强字符启发式方法)。特别是,默认方向不应设置为 LTR,因为这样会覆盖 首个强字符检测的必要性,而对于使用 RTL 文字书写的字符串,首个强字符检测更为适当。
如果元数据不可用,字符串消费者应使用启发式方法检测字符串的基础方向,最好使用 Unicode 标准的首个强字符检测算法。
首个强字符算法会查找字符串中的第一个强方向字符 (跳过某些前置子字符串),并假定该字符代表整个字符串的字符串方向。但是,第一个 强方向字符并不总是与整个字符串的实际或预期字符串方向一致,因此在需要时应能够 提供元数据来解决此问题。
如果依赖首个强字符启发式方法,应允许内容开发者在需要强制指定特定基础方向时, 在字符串开头使用 RLM/LRM,但不要在现有字符串前添加这些字符。
在大多数情况下,不要依赖 RLM/LRM 格式字符可用。
如果字符串数据由用户或内容开发者通过 Web 表单或其他简单环境提供,用户可能无法输入这些格式字符。 实际上,大多数用户可能根本不知道这些字符存在,也不知道如何使用。如果 Web 表单为输入设置了 块方向(它应该这样做),则表单可使用户在即时检查内容时无需使用这些字符。
并非所有资源都会使用可用的元数据机制。当其他数据不可用时,语言标签的文字子标签(或基于 [BCP47] 和 [LDML] 推断的“可能”文字子标签) 有时可用于推断块方向或字符串方向。使用 语言信息是“最后手段”,规范不应该将其用作指明块方向的主要方式:应尽力提供 元数据。
包含自然语言文本值的文档格式或协议规范需要定义数据字段或属性,以存储每个自然语言内容值的块方向。这些定义需要在整个 Web 中保持一致以确保 互操作性,因为一种文档格式的消费者需要将其接收值的块方向映射到它们生成的字段,或在 显示内容时控制每个字符串的字符串方向。本节介绍如何提供此类定义以及应使用的具体 内容。
定义内容方向有两种常见用例:(i) 定义方向元数据字段,以便将字符串方向作为数据结构中的字段进行存储和传输;或 (ii) 定义方向属性,将块方向与给定自然语言内容相关联。
方向元数据字段。方向元数据字段(简称 方向字段)是数据结构中的字段,用于将字符串方向与给定自然语言字符串字段或数据值相关联。
方向属性。方向属性是一种 字段或值,通常由标记语言中的属性表示,用于提供相关自然语言字符串内容的字符串方向。
数据值首选名称 direction。名称 dir
也是可接受的替代名称。
对于标记语言中的属性,首选名称 dir。
不建议属性使用 direction,因为它较长,而且在此用例中相对少见。
请注意,[HTML] 和
[XML10] 都具有内置
dir 属性。dir
属性应在文档中具有作用域,并应被定义为提供双向隔离。
ltr 值表示从左到右的方向,其含义与CSS 书写
模式 [CSS-WRITING-MODES-4] 所表示的方式完全相同。
rtl 值表示从右到左的方向,其含义与CSS 书写
模式 [CSS-WRITING-MODES-4] 所表示的方式完全相同。
auto 值表示用户代理使用 [HTML] 为 auto
定义的算法来确定块方向(“段落方向”)。
此启发式方法会查找第一个具有强方向性的字符,其方式类似于双向算法 [UAX9] 中确定段落级别的方式。
当 auto 应用于多个字段或整个文档时,意味着应分别为每个字段推导方向
(对于无法自动确定的情况,由字符串特定元数据覆盖)。当大多数字符串的字符串方向
可使用首个强字符启发式方法可靠确定时,它可用于标记一组方向混合的字符串。只要可能,应存储或交换单个字符串的
实际字符串方向(ltr 或 rtl),而不是
auto。当该值确实未知时,最好省略方向字段。
文档格式或协议的规范通常包含示例。示例必然会包含自然语言文本字段。
在规范中创建示例时,对于包含自然语言文本的字段, 始终使用本文档中规定的序列化方式和最佳实践。如果格式或协议支持资源范围的默认值, 请在示例中展示如何设置该默认值。如果格式或协议不支持文档级默认值,或者展示默认值不方便, 请在示例中使用单语言可本地化文本字段或语言映射。
内容生产者 (包括实现本文档所述各种语言和方向元数据机制的规范实现者)对于如何实现此处的最佳实践具有一定选择余地。 例如,如果文档格式同时提供资源范围的默认值和单语言可本地化文本字段,用户应该优先使用哪一种?
例如,如果文档资源范围的语言是 en-US
(美国英语),则文档资源范围的方向可能应为 LTR,
因为从左到右是与该语言关联的方向。
例如,如果资源范围的默认值为
fr(法语),而字符串关联的语言为 fr-FR(法国法语),则生产者应使用更具体的
fr-FR 标签生成字符串特定元数据。
同样,如果语言完全不同,例如 de(德语),生产者也应生成
字符串特定元数据。
如果语言标签 包含更多子标签,则该标签更具体。
许多字符串仅由与整体字符串方向一致的强方向字符组成。当此方向与 资源范围的默认值不一致(且默认值存在)时, 需要包含字符串方向,以便消费者无需 检查字符串本身即可确定方向,并且过滤和选择等过程不会误判内容的方向。
收集、序列化和传输语言及字符串 方向元数据的目的,是让消费者能够使用这些元数据正确显示和 处理字符串数据。
消费者在处理或显示相关字符串值时,应该使用 文档格式或协议提供的任何语言元数据。
当字符串显示在文档中或插入文档时,消费者应该在方向上将其与周围文本隔离。
使用双向隔离包装插入的字符串值不会造成问题,并且能够防止溢出效应,从而获得最佳结果。
将字符串插入文档时,消费者应该向字符串应用语言元数据。 使用相关文档属性或 API,将任何可用的语言元数据应用于字符串。
为了在呈现(例如字体选择)或文本处理(例如断字)中获得最佳结果,应在文档或处理文本的 API 中设置
插入文本的语言。在 [HTML] 中,这是通过设置 lang 属性完成的。
在 [XML] 中,这是通过
设置 xml:lang 属性完成的。
消费者可以规范化语言标签,以帮助确保互操作性。
例如,许多实现会使用 [CLDR] 中语言标签 转换规定的规范化方式。除其他操作外,此规范化会替换已废弃的子标签并按字母顺序排列变体。
同时也是生产者的消费者应该注意将语言和方向元数据传递给 其下游消费者。
对于使用 JSON-LD 的文档格式,[JSON-LD] 包含一些有助于向字符串集合(包括整个
资源)分配语言元数据(但不包括段落方向元数据)的数据结构。值得注意的是,它定义了所谓的
“字符串国际化”,其形式是限定于上下文的 @language
值,该值可与 JSON 块或单个对象相关联。它没有定义基础方向,因此
@context 机制目前尚不能解决本文档提出的所有问题。
某些数据类型已经存在,例如 [RDF-PLAIN-LITERAL], 它们允许将语言元数据作为字符串值的一部分进行序列化。
对于已知包含可本地化文本,
但底层格式无法提供语言元数据的字符串值和字符串字段,规范应该规定内容的语言未知,并建议将语言标签
und(“未确定”)与每个字符串相关联。
在适当情况下,规范可以允许使用启发式方法,或作为最后手段根据其他字段值推断语言。
许多协议或格式使用旨在让人类可理解、但并不打算作为自然语言文本的值。 这使人们能够使用这些值,例如用于调试。其中可能包括人们预期查看并与之交互的常见协议元素。
常见示例包括域名和电子邮件地址。随着 Unicode 在这些值空间中得到更广泛支持, 这些值在不同系统和环境中的显示方式可能不同。例如,字体选择可能因语言而异, 在使用不同默认区域设置的系统上也可能不同。
某些规范会与现有协议或格式定义的字符串值交互。这些字符串通常不与语言或方向元数据相关联, 或者不提供这些元数据。例如,许多 HTTP 标头定义其内容时,就好像这些内容不是可本地化文本, 即使这些内容预期为自然语言文本。作为这些字符串值消费者或生产者的规范 无法发现其语言或方向元数据,也没有机制附加这些元数据。
规范不应该使用 Unicode“语言标签”
字符(码位 U+E0000 至 U+E007F)识别语言。
[Unicode] 表示,“强烈不建议使用标签字符来 传达语言标签”,并且强烈不建议使用字符 U+E0001 LANGUAGE TAG。
换一种说法:不要要求实现修改流经它们的数据。Unicode 双向控制字符可能已存在于 特定字符串内容中,因为生产者或数据来源使用它们使文本正确显示。也就是说,它们可能已经是数据的一部分。 实现不应干扰所发现的任何控制符,但也不应被要求自行生成额外控制符。
当同一值可以使用多种语言提供Localizable
字符串时,规范应该建议使用语言索引。
生产者有时 需要为同一内容项或数据记录提供多种语言值(参见本地化 注意事项)。这种做法的一个用途是由消费者执行语言 协商。
请阅读文章 Web 上双向文本 和语言元数据的用例,了解详细用例,其中清楚展示了溢出或基于区域设置的 渲染等问题。本节总结了该文档中的一些要点,以及与语言和方向元数据需求相关的内容。
出于多种原因,在处理和呈现可本地化 文本时,内容的语言信息十分重要。如果缺少语言信息,由此造成的外观或功能退化可能使用户感到沮丧、 使内容难以理解,或导致重要功能无法使用。受影响的过程包括:
同样,方向元数据对 Web 也很重要。当字符串包含使用从右到左(RTL)书写的文字时,该字符串最终到达 最终用户时必须能够正确显示。为此,需要确定应将什么字符串方向 应用于整个字符串。仅查看字符串并不总能推断出适当的字符串 方向;即使可以推断,字符串的生产者和消费者也需要使用相同的启发式方法来解释方向。
Web 页面正文或电子书内容等静态内容,通常由文档格式或作为内容元数据的一部分提供语言或方向信息。 Web 上的数据格式通常不提供这些元数据。Microformats、WebIDL 和 JSON 等基础规范往往将自然语言文本 存储在字符串对象中,而不附加其他元数据。
这给应用程序作者和数据格式设计者带来了负担,要求他们主动提供元数据。如果标准化格式没有解决由此产生的问题, 结果可能是数据虽然完整到达,但其处理方式或呈现方式却无法完全恢复。
在分布式 Web 中,任何消费者也可以成为其他过程或系统的生产者。 因此,给定消费者可能需要将语言和方向元数据从一种文档格式(并使用一种序列化约定)传递给使用另一种文档格式的消费者。 序列化约定中表示语言和方向元数据的方式缺乏一致性,会威胁互操作性,并阻碍一致实现。
假设您正在构建一个 Web 页面,用于显示客户的电子书库。这些电子书存在于数据目录中, 并包含常见的数据值。单个条目的 JSON 文件可能如下所示:
{
"id": "978-111887164-5",
"title": "HTML و CSS: تصميم و إنشاء مواقع الويب",
"authors": [ "Jon Duckett" ],
"language": "ar",
"pubDate": "2008-01-01",
"publisher": "مكتبة",
"coverImage": "https://example.com/images/html_and_css_cover.jpg",
// etc.
},
上述每项内容都是某个数据库中的数据字段。其中甚至还包含该书使用何种语言的信息: ("language": "ar")。
国际化良好的目录还会在上述内容之外包含其他元数据。也就是说,对于每个包含可本地化文本的字段, 例如 title 和 authors 字段,都应将语言和字符串方向信息作为元数据存储。(还可能存在其他值, 例如用于对东亚语言信息进行排序的发音元数据。)数据消费者使用这些元数据值来影响处理,并以各种方式显示这些项目。 由于 JSON 数据结构没有可存储或交换这些值的位置,因此构建国际化应用程序会更加困难。
一种变通方法可能是混合使用 HTML 和 Unicode 双向控制符来编码这些值,使数据值可能如下所示:
// following examples are NOT recommended
// contains HTML markup
"title": "<span lang='ar' dir='rtl'>HTML و CSS: تصميم و إنشاء مواقع الويب</span>",
// contains LRM as first character
"authors": [ "\u200eJon Duckett" ],
但是 JSON 是一种数据交换格式:内容最终未必会在 HTML 上下文中显示 title 字段。上述 JSON 很可能被用于填充本地数据存储,而该数据存储使用原生控件显示标题,并会将 HTML 视为字符串内容。 数据的生产者和消费者可能不会预期检查数据,以便提供或移除额外数据,或将其公开为元数据。 大多数 JSON 库并不了解它们所序列化内容的结构。生产者希望直接从数据库等本地数据存储中生成 JSON 文件。 消费者希望存储或检索该值以供使用,而无需额外考虑每个字符串的内容。此外,生产者或消费者还可能具有其他限制, 例如字段长度限制,而插入额外控制符或标记会影响这些限制。上述每项考虑都会给实现者带来额外负担, 要求他们创建任意方式来序列化、反序列化、管理和交换必要元数据,而互操作性则会在此过程中受到损害。
(顺便指出,上述示例中的标记实际上是必要的,它能使标题以及插入的标记在浏览器中正确显示。)
[Unicode] 及其字符编码(例如 UTF-8)是 Web 及其格式的关键组成部分。它们能够在整个互联网中一致地编码和交换任何语言的文本。但是,即使 Unicode 能够保证完美交换,它本身也不能保证自然语言文本获得完美的 呈现和处理。
Unicode 的若干功能有时被认为是提供语言和方向元数据的解决方案的一部分。具体而言,有人建议使用 Unicode
双向控制符处理方向元数据。此外,Unicode 的 U+E0000
区块中还有一些“标签”字符,最初用于表示语言标签(尽管现在已弃用这种用法)。
在交换格式的数据中添加字符并不是一个好主意,原因有很多,包括:
最后一项考虑尤其值得强调:文档格式通常使用多层代码构建和序列化。通用 JSON 库等库应该忠实地存储和检索传递给它们的数据。更高层的实现通常也关注忠实地序列化和反序列化 传递给它们的值。任何修改数据本身的过程都会引入不希望出现的差异。例如,考虑某个应用程序的单元测试, 它检查从文档返回的字符串是否与用于生成该文档的数据目录中的字符串相同。如果插入、移除或更改了 双向控制符、HTML 标记或 Unicode 语言标签,则这些字符串比较时可能不相等,即使预期它们应该相同。
根据双向文本的用例可以明显看出,消费者不能在没有进行额外处理或准备的情况下, 直接将字符串插入目标位置。首先需要确定所插入字符串的适当字符串方向,其次需要在字符串周围应用双向隔离。
这要求字符串周围存在标记或 Unicode 格式控制符。如果字符串的实际方向与其插入内容的方向相反, 标记或控制代码需要紧密包装该字符串。彼此相邻插入的字符串都需要分别包装,以避免上一节中看到的溢出问题。
[HTML]
在任何行内元素使用 dir 属性,或使用 bdi
元素时,都会提供基础方向控制和隔离。将字符串插入纯文本环境时,
需要使用具有隔离作用的 Unicode 格式字符。(遗憾的是,Unicode 标准建议将隔离字符作为纯文本或非标记应用程序的
默认方式,但目前对这些字符的支持仍不普遍。)
关键在于确保标记或控制字符提供的方向信息反映字符串的字符串方向。
双向文本值的根本问题是,当字符串最终显示给用户时,字符串的消费者如何知道应为该字符串使用什么字符串方向。请注意,其中一些识别或估算方向的方法 在特定应用程序中很有用,并且已在 [HTML] 等不同规范中使用。 此处的问题在于,哪些方法适合普遍采用,并规定为文档格式中的最佳实践。
不建议单独使用此方法,但建议将其与其他方法结合用作回退方式。
生产者无需执行任何操作。
字符串按原样存储。
消费者必须在字符串中查找第一个具有强 Unicode 方向属性的字符,并将字符串方向设置为与其匹配。然后采取适当措施, 确保字符串按需要显示。这并不像表面看起来那么简单,原因如下:
只有在所需字符串 方向尚未知时,才需要进行首个强字符检测。如果通过字符串特定元数据或资源范围声明 指定了字符串方向,则不应调用首个强字符启发式方法。例如,对于 “HTML و CSS: تصميم و إنشاء مواقع الويب”这样的字符串, 首个强字符启发式方法会产生错误结果。可以使用元数据进行纠正;使用元数据表示经过了解后的明确意图, 因此无需也不应应用会使结果变得错误的启发式方法。
但是,如果没有应用元数据的机制,或者存在此类机制但内容开发者没有使用,那么首个强字符启发式方法
在许多情况下(尽管并非所有情况下)有助于确定基础方向。
应用具有强方向性的格式字符有助于使刚才所述的纯文本字符串示例产生正确结果,但并非始终能够使用这些字符
(参见4.3 通过插入
RLM/LRM 标记增强首个强字符
方法)。
在此方法可靠的情况下,无需修改字符串,也无需支持带外元数据所需的约定和结构, 即可获得有关方向的信息。
此方法的主要问题是,它会在以下情况下产生错误结果:
span 等标记开头,因为第一个强字符始终会是 LTR。如果整个字符串以 RLI/LRI/FSI...PDI 格式字符开头和结尾,则无法通过遵循 Unicode 双向算法检测第一个强字符。这是因为该算法要求在检测时排除经过双向隔离的文本。
如果字符串中没有找到强方向字符,可能应该假定方向为 LTR,并由消费者据此操作。不过,此行为尚未经过充分测试。
如果字符串包含会被消费者解析为标记的内容,则还会存在其他问题。在查找第一个强方向字符时, 还必须跳过字符串开头的所有此类标记。
如果字符串中可解析的标记包含有关字符串预期方向的信息
(例如 HTML 中值为 rtl 的
dir
属性),则应使用该信息,而不是依赖首个强字符启发式方法。
这在以下几个方面存在问题:(a) 它假定字符串消费者理解标记的语义;如果所有参与方都约定只使用
HTML 标记,这可能可以接受,但例如处理任意 XML 词汇表时就会有问题;以及 (b) 消费者必须能够识别并处理
只有字符串开头部分具有标记的情况,即标记只应用于文本的行内范围,而不是整个字符串。
尚不清楚下一段中链接失效的示例位于何处,或者以前位于何处。
但是,如果尖括号内容旨在作为标记的示例,而不是真正的标记,则不能跳过这些标记; 尝试在 RTL 上下文中显示标记源代码会产生非常令人困惑的结果!不过,目前尚不清楚字符串消费者 如何始终区分示例和可解析字符串。
尽管 Unicode 双向算法(UBA)[UAX9] 概述了首个强字符检测, 但它并不是该算法为估算字符串方向而提到的唯一高层协议。例如,X(以前称为 Twitter)和 Facebook 目前使用不同的默认启发式方法猜测文本的基础方向;两者都不只使用简单的首个强字符检测, 并且其中一个使用完全不同的方法。
建议使用此方法。
这里所说的“元数据”是指在数据格式中与特定字符串或一组字符串关联的基于字段的信息, 或内置于字符串数据类型中的信息(另请参见4.7 创建新的双向数据类型)。
例如:
{
"title": "HTML و CSS: تصميم و إنشاء مواقع الويب",
"direction": "rtl",
"language": "ar",
},
还可以使用适当字段设置元数据,以指明资源中所有字符串的默认方向。
生产者确定字符串的字符串方向,并将其添加到 与字符串一起存储或传输的元数据字段中。
使用元数据有以下几种方法:
auto 值。如果一次存储或传输一组字符串,为整个资源设置一个全局默认字符串方向字段会很有帮助, 资源中的所有字符串都可以继承该值。请注意,除了全局字段外,在字符串的字符串方向与默认值不同时, 仍需要能够附加字符串特定元数据字段。单个字符串上设置的字符串方向必须始终覆盖默认值。
消费者需要了解如何读取随字符串发送的元数据,并且在没有元数据时需要应用首个强字符启发式方法。
对于基于 JSON 的文档格式中的单个值,建议使用 Localizable 字典结构,因为它结合了语言和方向元数据, 如果得到一致采用,可以使不同格式之间的交换更加容易。
将元数据作为与字符串分离的数据值传递,可以在不影响字符串实际内容的情况下, 以简单、有效且高效的方式传达预期的字符串 方向。
如果为每个字符串标记了方向,或者通过应用全局设置和所有字符串特定差异即可确定所有字符串的方向, 就无需检查每个字符串并运行启发式方法来确定其字符串 方向。
带外信息需要与字符串相关联并始终随字符串保留。对于不属于已定义框架的某些字符串数据集合, 这可能会有问题。
特别是,JSON-LD 不允许像关联语言那样,将方向与单个字符串相关联。
此方法并不适用于所有情况。
生产者确定字符串的字符串方向,并在字符串开头添加 一个标记字符,即 U+200F RIGHT-TO-LEFT MARK(RLM)或 U+200E LEFT-TO-RIGHT MARK(LRM)。该标记本身不具有功能, 即它不会自动为字符串应用可供消费者使用的基础方向,而只是一个标记。
可能的方法包括:
消费者应用首个强字符启发式方法,检测字符串的字符串 方向。RLM 和 LRM 字符在方向上属于强类型,因此应使检测结果得到适当的基础方向。
如4.1 首个强字符属性检测中所述,如果通过元数据提供方向信息, 此方法就不适用。
只要生产者能够可靠地应用标记,它就能提供一种可靠方式来指明基础方向。
理论上,只要在字符串前添加正确的 RLM/LRM,就应该更容易识别以标记开头的字符串中的首个强字符。
如果生产者是人,理论上可以在创建字符串时应用其中一个字符来指明方向性。
这种方法的一个重大问题(尤其是在移动设备上)是输入 RLM/LRM 字符的可用性或不便性。 移动设备的键盘通常不提供 RLM/LRM 字符键。或许更重要的是,由于这些字符不可见,而且 Unicode 双向文本很复杂,用户可能难以知道如何有效使用这些字符。实际上,很大一部分用户根本不知道 这些字符是什么或有什么作用。
此外,如果用户在 RTL 页面上的 HTML 表单中输入信息,或使用快捷键设置表单字段的方向,
字符串无需添加 RLM/LRM 就会正确显示。但是,在该上下文之外使用时,除非字符串与所需块方向的信息相关联,否则字符串会显示错误。
同样,从 html 元素上设置了 dir=rtl 的网页中抓取的字符串,在 HTML 中通常不会在字符串开头包含
或需要 RLM/LRM 字符。
生产者使用的步骤可能可以检查字符串的原始上下文以获取方向信息 (例如测试 HTML 表单字段的计算方向),然后在必要时自动在字符串开头插入 RLM/LRM 标记。 此方法的问题在于,它会改变字符串的值和标识。这也可能给字符串长度或指针位置的处理带来问题, 尤其是在某些生产者添加标记而其他生产者不添加标记的情况下。
如果方向信息包含在会被消费者解析为标记的内容中
(例如 HTML 中的 dir=rtl),
字符串生产者需要理解该标记,才能适当地决定是否设置 RLM/LRM 字符。
如果生产者始终在此类字符串开头添加 RLM/LRM,则消费者应知道这一点。
如果生产者依赖消费者理解标记,则消费者也应理解该标记。
字符串生产者不应自动在字符串开头应用 RLM 或 LRM,而应该测试是否需要这样做。 例如,如果文本中已经存在 RLM,就无需再添加一个。如果首个强字符启发式方法能够正确传达上下文, 也无需添加额外字符。不过请注意,只有在生产者能够访问字符串的原始上下文,并且知道自己能够访问该上下文时, 才能测试是否需要此类补充方向信息。许多文档格式由远离原始上下文的数据生成。例如,上述原始示例中的图书目录与输入双向文本的用户是分离的。
不建议使用此方法。
生产者确定字符串的字符串方向,并在字符串开头添加 一个方向格式字符,即 U+2066 LEFT-TO-RIGHT ISOLATE(LRI)、U+2067 RIGHT-TO-LEFT ISOLATE(RLI)、 U+2068 FIRST STRONG ISOLATE(FSI)、 U+202A LEFT-TO-RIGHT EMBEDDING(LRE)或 U+202B RIGHT-TO-LEFT EMBEDDING(RLE),并在字符串末尾添加 U+2069 POP DIRECTIONAL ISOLATE(PDI)或 U+202C POP DIRECTIONAL FORMATTING(PDF)。
可能的方法包括:
理论上,消费者只需将字符串插入其显示位置,并依靠格式代码管理方向性。不过,实际情况并没有这么简单 (见下文)。
成对格式字符有两种类型。原始控制符集能够为 Unicode 双向算法添加额外的双向“嵌入”级别。 后来,Unicode 又添加了一组互补的“隔离”控制符。隔离控制符用于包围字符串。字符串内部被视为 自身独立的双向序列,并受到保护,不会受到周围文本相关溢出效应的影响。外层字符串将整个被包围的 字符串视为一个整体,并在双向重新排序时忽略它。此问题在此处说明。
| 码位 | 缩写 | 说明 | 码位 | 缩写 | 说明 |
| U+200A | LRE | 从左到右嵌入 | U+2066 | LRI | 从左到右隔离 |
| U+200B | RLE | 从右到左嵌入 | U+2067 | RLI | 从右到左隔离 |
| U+2068 | FSI | 首个强字符隔离 | |||
| U+200C | 弹出方向格式(结束嵌入) | U+2069 | PDI | 弹出方向隔离(结束隔离) |
如果使用成对格式字符,则应使用隔离字符,即以 RLI、LRI 或 FSI 开头,而不是以 RLE 或 LRE 开头。
使用此方法没有真正的优点。
只有在可以接受改变字符串值的情况下,此方法才适用。除了可能改变字符串长度或指针位置等问题外, 此方法还存在一个真实且严重的风险:成对字符中的一个可能因处理错误、文本截断等原因丢失。
字符串的生产者和消费者需要能够识别并处理以下情况:字符串以成对格式字符开头,但没有以其结尾, 因为格式字符只描述字符串的一部分。
Unicode 对有效嵌入层数规定了限制,并且嵌入可能随时间累积并超过该限制。
消费应用程序需要识别并正确处理隔离格式字符。目前对 RLI/LRI/FSI 的支持远未普及。
如果不理解此方法的消费者使用 UBA 首个强字符启发式方法,则此方法会使字符串无法适用该方法,因为 Unicode 双向算法无法确定 以 RLI/LRI/FSI 开头并以 PDI 结尾的字符串的基础方向。这是因为该算法会跳过隔离序列, 并将其视为中性字符。在这种情况下,字符串的消费者必须采取特殊步骤 来定位首个强字符。
仅建议在无法使用元数据的情况下,将此方法作为变通方案。
生产者 为字符串提供语言元数据,并在需要时指定所使用的文字。
可能的方法包括:
消费者 从与每个字符串关联的语言标签中提取文字子标签,并根据需要计算字符串的字符串方向。与 RTL 文字关联的文字子标签 用于向其相关字符串分配 RTL 方向。
语言信息必须使用 [BCP47] 语言标签。语言标签中携带该信息的部分是
文字子标签,而不是主要语言子标签。例如,阿塞拜疆语可以使用拉丁字母或西里尔字母从左到右书写,
也可以使用阿拉伯字母从右到左书写。因此,子标签 az
不足以明确预期的块方向。但是,
az-Arab(使用阿拉伯文字书写的阿塞拜疆语)之类的语言标签,
通常可以可靠地表示块方向应为 RTL。
无需检查或更改字符串本身。
当首个强字符不能表示字符串所需的字符串 方向时,此方法可避免与首个强字符检测相关的问题,也可避免与标记解释相关的问题。
请注意,以设置字符串文本内容语言的标记开头的字符串
(例如 <cite lang="zh-Hans">)在此处不会造成问题,
因为该语言声明并不应参与设置字符串方向。
如果上述元数据方法可用,它是一种更好的方法。这种与文字相关的方法仅用于因旧有原因而无法使用元数据方法的情况。
许多字符串并不特定于某种语言,但为了正确使用,它们绝对需要与特定块方向相关联。
例如,插入 RTL 上下文中的 MAC 地址需要使用整体 LTR 基础方向显示,并且还需要与周围文本隔离。
尚不清楚如何以一种可行的方式将这些情况与其他情况区分开来(即使使用方向元数据时也是如此)。
zxx(非语言)等特殊语言标签可用于识别此类内容,但此类数据字段通常
会完全省略语言信息,因为语言信息并不适用。
将来可能会增加文字子标签列表。在这种情况下,所有表示默认 RTL 方向的子标签都需要添加到 字符串消费者使用的列表中。
在一些罕见情况下,无法根据文字子标签识别适当的段落方向, 但这些情况实际上仅限于古代文本用法。例如,第二次世界大战前的日文和中文文本通常从右到左书写, 而不是从左到右。使用埃及象形文字或提非纳字母书写的语言,以前既可以从左到右书写,也可以从右到左书写, 不过学术研究中的默认方向往往是从左到右。
此处所述的方法只适用于声明与字符串关联的整体字符串方向信息。我们不建议使用语言数据 指明字符串内部的文本方向,因为这些使用模式不能互换。
不建议使用此方法,除非序列化约定明确要求仅交换 HTML 或 XML 标记数据。
生产者确保所有字符串都以标记开头和结尾,并由标记指明该字符串的适当基础方向。
这要求生产者检查字符串。如果字符串没有由包含方向信息的标记限定边界,生产者必须使用具有
dir 或 its:direction
[ITS20]
属性的元素,或者适合给定 XML 应用程序的其他标记来包装字符串。如果字符串已经
由标记限定,但该标记是 HTML h1 元素等内容,
则生产者需要向现有标记中加入方向信息,而不是简单地使用 span 包围字符串。
此示例使用 HTML 标记。(为了使示例更易阅读,它按照文本内容应显示的方式显示字符串, 而不是按照字符存储顺序显示。)
随后,消费者依靠标记在显示字符串文本内容时设置其周围的基础方向。 (请注意,除非提供额外元数据,否则消费者在将字符串集成到目标位置之前不能移除标记, 因为它无法判断哪些标记由生产者添加,哪些标记原本就存在。不过一般来说,此类附加标记无害。)
对于已经使用标记的内容,此方法的好处很明显。内容已经提供了显示和处理文本所需的完整标记, 或者可以从源页面上下文中提取这些标记。HTML 和 XML 处理器已经知道如何处理这些标记, 并能直接进行验证。
对于 HTML,dir 属性会在双向文本方面将内容与周围文本隔离,
从而消除溢出冲突。这可减少消费者的工作量。
标记还可用于表示字符串内部的方向信息,而这是仅使用字符串方向无法解决的。
实际上,实现堆栈的所有层级都必须参与理解标记,或者至少确保不会造成破坏。
如果系统端到端都使用 HTML,则适当的标记已经可用,而且其语义可以被理解
(即 dir 属性以及 bdi 和 bdo 元素)。
但是,对于 XML 应用程序,没有用于支持双向文本的标准标记。此类标记需要先行定义,
然后由生产者和消费者共同理解。
此方法的一个主要缺点是,许多数据值只是字符串。与添加 Unicode 标签或 Unicode 双向控制符一样, 向字符串中添加标记会改变原始字符串内容。改变内容长度可能会给执行任意长度限制的过程带来问题, 或给通过转义尖括号等 HTML/XML 不安全字符来“清理”内容的过程带来问题。
另一个问题是,生产者检查字符串并按需添加标记需要大量工作和较高复杂度。
Unicode 双向算法允许的嵌入层数有限。消费者在将字符串嵌入更广泛的上下文时, 需要确保不会超过该限制。
添加标记还要求消费者防范标记插入通常会带来的问题,例如 XSS 攻击。
此方法已添加到 [JSON-LD] 1.1 中。
这与前面讨论的随字符串发送元数据的思路类似,但元数据既不是存储在完全独立的字段中
(如4.2 元数据),
也不是插入字符串本身(如4.3 通过插入
RLM/LRM 标记增强首个强字符
方法),而是作为字符串序列化格式的一部分与字符串相关联。
某些数据类型已经存在,例如 [RDF-PLAIN-LITERAL], 它们允许将语言元数据作为字符串值的一部分进行序列化。但是,它们没有考虑方向。 可以通过定义新的数据类型(或扩展现有数据类型)来解决此问题,使文档格式能够使用它序列化 同时包含语言和方向元数据的自然语言字符串。
[JSON-LD] 1.1 添加了 i18n
命名空间,使 JSON 文档能够将语言和方向元数据直接与字符串值一起序列化。
对于需要 RDF 的规范,它还提供了反序列化为 RDF 的方式。
请注意,最后一个字符串没有包含语言信息,因为它是内部数据值,但它确实包含方向信息, 因为此类字符串必须按照 LTR 顺序呈现。
对于未使用此方法或不包含字符串方向的字符串, 每个消费者都应使用 首个强字符启发式方法。随后,只有当首个强字符方法会产生错误结果时, 生产者才添加字符串方向信息。这可能简化字符串管理并减少 需要传输的数据量,因为需要元数据的字符串数量相对较少。
消费者 会检查字符串是否有关联的元数据;如果有,则设置所指明的字符串方向。否则,它会使用首个强字符启发式方法 确定字符串的字符串方向。
如果向 JSON 添加新的数据类型以支持自然语言字符串,则规范可以轻松规定在文档格式中使用该类型。 由于格式已经标准化,生产者和消费者 在编码方向或语言信息后无需进行猜测。
除了此方法目前无法工作之外,添加数据类型的缺点还在于 JSON 已被广泛实现,其中包括许多临时实现。 任何新的序列化形式都可能破坏这些现有实现,或造成互操作性问题。JSON 并不是设计为具有“版本”的格式。 所使用的任何序列化形式都需要对现有 JSON 处理器保持透明,因此可能向现有字符串和格式中引入 不需要的数据或造成数据损坏。
本节讨论确定或传达字符串值语言的不同方法。
建议使用此方法。
生产者 确定字符串的语言(通常根据上游提供的元数据),并将此信息包含在随字符串一起存储或传输的 元数据字段中。
一次存储或传输一组字符串时,为整个资源提供一个语言字段会很有帮助,资源中的所有字符串都可以继承 该语言。请注意,除了全局字段外,在字符串语言与默认语言不同时,仍需要能够附加字符串特定 元数据字段。在单个字符串上设置的语言必须覆盖所有资源级值。
消费者需要 了解如何读取与字符串关联的元数据,并将其应用于自身生成的显示内容、处理过程或数据结构。 请注意,这可能包括在序列化或交换单个值时应用资源级默认语言。
使用一致且定义明确的数据结构,可以提高不同标准相互组合并无缝协作的可能性。
可以在不影响内容本身的情况下提供元数据。
元数据不可用时,可以将其省略。
消费者和生产者无需在正常处理之外检查数据。
使用该字典及其数据值的序列化文件会包含额外字段,因此可能更难阅读。
对于现有文档格式,它意味着对所交换值的更改。
不建议使用此方法,除非在特殊情况下,预期交换的内容由给定标记语言中的 字面值组成,并且仅限于这些值。
当文档预期由 HTML 或 XML 片段组成,并且严格在标记上下文中进行处理和显示时,生产者可以使用标记来传达
内容的语言,即使用具有 lang 或 xml:lang 属性的元素
包装字符串。
此方法及其优点实际上与本节所述内容相同。
参见上文。
不建议使用此方法。
生产者将 Unicode 标签字符插入数据中,以便使用语言标记字符串。
消费者 处理 Unicode 标签字符,并使用这些字符分配语言。
Unicode 定义了可用作语言标签的特殊字符。这些字符属于“默认可忽略字符”,不应具有任何视觉外观。 Unicode 标签应按以下方式工作:
每个标签都是一个字符序列。该序列以标签标识字符开头。目前唯一定义的标识字符是
U+E0001,它用于标识 [BCP47] 语言标签。通过私有约定,也可以定义其他类型的标签。
Unicode 区块中用于构成标签的其余部分与可打印 ASCII 字符相对应。也就是说,
U+E0020 表示空格(对应 U+0020),
U+E0041 表示大写字母 A(对应 U+0041),依此类推。
在标签标识字符之后,生产者使用各个标签字符,通过大小写字母、数字和连字符拼写
[BCP47] 语言标签。由 ASCII 字母、数字和连字符组成的
给定源语言标签,可以通过将每个字符的码位加上 0xE0000 转换为标签。
还可以使用逗号或分号等其他字符构建语言优先级列表等附加结构
(参见 [RFC4647]),不过 Unicode 并未定义,甚至不一定允许这种做法。
标签的作用域在字符串末尾结束,也可以使用取消标签字符 U+E007F 显式表示结束。
该字符可以单独使用(取消所有标签),也可以放在语言标签标识字符 U+E0001
之后使用(即使用序列 <U+E0001,U+E007F>,仅结束语言标签)。
因此,标签最少包含三个字符,并且很容易达到 12 个或更多字符。此外,这些字符属于补充字符。
也就是说,在 UTF-8 中,每个字符使用 4 个字节编码;在 UTF-16 中,它们被编码为代理对
(两个 16 位代码单元)。Java 和 JavaScript 等内部使用 UTF-16 的语言,需要使用代理对
在字符串类型中编码这些字符。使用代理对会使字符串在一定程度上难以理解。例如,
U+E0020 在 UTF-16 中编码为 0xDB40.DC20,在 UTF-8 中编码为
字节序列 0xF3.A0.80.A0。
这些语言标签字符可以作为普通 Unicode 文本的一部分使用,无需修改文档格式的结构。
Unicode 联盟强烈反对使用 Unicode 标签字符识别语言,因此这种用法已被弃用。这些标签字符最初旨在 用于纯文本上下文中的语言标记,并且经常被建议用作提供带内非标记语言标记的替代方法。 我们不了解有任何实现将它们用作语言标签。
将这些字符视为未知 Unicode 字符的应用程序会将其显示为豆腐块(空心方框替代字符),并且可能将其计入 长度限制等。因此,只有当应用程序或交换机制完全了解这些字符,并能够适当地移除或忽略它们时, 这些字符才有用。尽管这些字符不应显示,也不应对文本处理产生任何影响,但实际上它们可能会干扰 文本截断、换行、断字和拼写检查等正常文本处理。
按照设计,[BCP47] 语言标签对 ASCII 大小写不敏感。 处理 Unicode 标签字符的应用程序也必须应用类似的大小写不敏感规则,以确保正确识别语言。 (Unicode 数据没有为这些字符指定大小写转换配对,这使使用标签字符编码的语言标签值更难处理和匹配。)
此外,为了符合 [BCP47],语言标签需要由有效的子标签构成。 有效子标签保存在 IANA 注册表中,并且会定期添加新子标签,因此处理此类标签的应用程序需要始终 根据注册表的最新版本检查每个子标签。
语言标签字符不允许嵌套语言标签。例如,如果字符串包含两种语言,如英语句子中包含法语引文, Unicode 标签字符只能指明一种语言从何处开始。为了指明嵌套语言,标签需要嵌入文本内部, 而不能只添加在文本开头。
尽管从未得到实现,但还可以使用 Unicode 标签字符将其他类型的标签嵌入字符串或文档中。 这些标签可能与使用语言标签标记的文本范围重叠。
最后,Unicode 最近“重新利用”这些字符来构成次区域旗帜,例如苏格兰旗帜(🏴), 它由以下序列组成:
上述功能是 2017 年 6 月在 Unicode 10.0(UTR#51 的 5.0 版)中添加的 新表情符号功能。能否正确显示取决于您的系统是否采用了此版本。
不建议使用此方法。
生产者无需执行 任何操作。
消费者运行 语言检测算法来确定文本的语言。这些算法通常是基于统计的启发式方法,例如使用某种语言中的 n 元语法频率,并且可能与其他数据结合使用。
此方法没有根本性的优点。
扫描的文本越长、越具有代表性,启发式方法就越准确。短字符串可能无法得到良好的检测结果。
语言检测仅限于拥有相应检测器的语言。
包含其他语言或文字的人名或品牌名称等内容,可能会干扰检测结果。
语言检测往往较慢,并且可能占用大量内存。简单的消费者可能无法承担确定语言所需的复杂性。
有时,生产者可以 通过在生产者与消费者之间执行某种语言 协商,为给定内容项或数据记录提供本地化值。随后,生产者使用协商得到的语言选择要返回的 内容,从而完成本地化。由于只需返回消费者所需的一种或多种语言, 此方法可以减小影响延迟的文件大小,并降低复杂度。
但是,由于这种方式并非始终可行,规范有时允许为给定字段返回多个不同语言的值。这可能是为了支持运行时本地化, 也可能是因为生产者具有多个不同语言的值, 但无法预先适当地选择它们。
在这些情况下,内容项的本地化方式是由生产者返回该项目的多个语言表示形式, 并由消费者选择要显示的值。当生产者无法协商语言 (例如生成的文件被缓存以供多个用户使用),并且语言数量相对较少时,此方法很有帮助。 大量语言集合可能会导致文档过大,难以处理。
语言
索引是一种使用语言标签组织给定字段的不同
语言版本的策略,以便消费者选择最合适的值。
规范可以使用LanguageMap
等数据结构,为给定字段提供多个语言版本。给定字段的值被定义为映射。映射中的键是语言
标签。与每个语言标签关联的值是字符串,理想情况下则是LanguageEntry 对象。
使用语言标签
作为映射中各个值的键,可以快速选择适合给定请求的正确值。请注意,当与语言标签关联的值是LanguageEntry 时,可以在该值中重复指定
(或覆盖)语言。由于该值中的LanguageTag 是可选的,
因此并不要求这样做。(除非它能提供额外价值,否则不要包含它。)
例如,如果请求的语言是美国英语(en-US),此格式可以更轻松地
匹配并提取最合适的标题对象 {"value": "Learning Web Design"}。另一个潜在优点是,索引语言标签可以
独立于实际数据值的语言标签,指明该值的目标受众。例如,可以使用语言范围 [RFC4647]。如下例所示,可以使用不太具体的语言标签包装
更具体的语言值。在此示例中,内容使用特定语言标签(de-DE)进行标记,但同样适用于使用其他德语变体的用户,例如
de-CH 或 de-AT:
一种不太常见的情况是,系统为某个索引语言标签提供使用另一种“错误”语言的特定值, 这可能是因为实际的翻译值缺失:
此方法的主要问题是,需要从内容中提取索引语言标签,以便生成索引。生产者可能还需要与消费者就索引语言标签是否会以某种方式
规范化达成序列化约定。例如,语言标签 cel-gaulish 是
[BCP47]
中的一个祖父级语言标签。
某些实现(例如遵循 [CLDR] 规则的实现)会倾向于在语言协商中
将此标签替换为现代等效标签(在此情况下为 xtg-x-cel-gaulish)。
[JSON-LD]
定义了一种语言索引的具体实现,
该实现依赖 @context 结构。此结构不支持使用LanguageEntry
值
(仅支持字符串或字符串数组),因此需要进行更改,才能在 [JSON-LD] 文档中允许上述某些功能。
本节包含上文主文档中所述各种结构的 WebIDL 定义。
为确保有效性,规范作者应始终使用相同的格式和数据结构,使大多数数据格式能够互操作 (换言之,使数据能够在多种格式之间复制,而无需进行额外处理)。我们建议将 Localizable 用于 单语言可本地化文本字段,并将 LanguageMap 用于语言映射。
通过以 WebIDL 字典形式定义语言和方向,规范可以简洁地为给定字符串值加入语言和方向元数据。 实现可以直接复用该字典的实现。
WebIDLtypedef DOMString LanguageTag;
LanguageTag typedefDOMString。WebIDLdictionary Localizable {
DOMString value;
LanguageTag lang;
TextDirection dir = "auto";
};
value 成员lang 成员
dir 成员WebIDLtypedef record<DOMString,LanguageEntry> LanguageMap;
LanguageMap recordLanguageTag,值为LanguageEntry,其中包含与该键关联的
本地化字符串值以及所有覆盖元数据。WebIDLdictionary LanguageEntry {
DOMString value;
LanguageTag? lang; // Optional property for language tag
TextDirection? dir; // Optional property for text direction
};
value 成员lang 成员LanguageTag,用于覆盖
或补充 LanguageMap 中某个LanguageEntry 的
lang 成员。此字段很少使用。
dir
成员TextDirection。WebIDLenum TextDirection {
"auto",
"ltr",
"rtl"
};
文本方向值如下,它们表示人类可读成员的值默认采用:
autoltrrtl国际化(I18N)工作组谨此感谢 以下为本文档作出贡献的人士: Mati Allouche、 David Baron、 Ivan Herman、 Tobie Langel、 Emil Lundberg、 Sangwhan Moon、 Felix Sasaki、 Najib Tounsi, 以及其他许多人。
以下页面构成了本文档最初的基础:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: