你的阿拉伯语标题没有乱码——是商店在按另一个方向读它

8 分钟阅读每个数字都有出处

当一个阿拉伯语、波斯语或乌尔都语标题到达商店时,括号跑到了另一侧、「feat.」署名被推到最远端,或者目录号飘到了不该在的位置——这些都不是数据被破坏了。你打进去的字节,几乎总是到达那一端的字节。变化的是文本被绘制进的那个框的基准方向,而这由商店的页面决定,不由你的标题决定。本文把这个机制讲得足够精确,好让你在交付之前就能预测自己哪些标题会出问题。

有一件事要先说在前面,因为这是诚实的立场:我们不知道业内任何地方发表过关于阿拉伯字母元数据错误率的测量。 这个问题人人都遇到,却完全没有被量化。下文不会出现任何数字,因为没有数字可给。

逻辑顺序和显示顺序是两回事

Unicode 以逻辑顺序存储文本——也就是你说它、打它、读出它的顺序。显示顺序是在渲染时由此计算出来的,依据的是 Unicode Standard Annex #9 (UAX #9) 所定义的 Unicode 双向算法。该附件对这一区分说得很直白:「The Unicode Standard prescribes a memory representation order known as logical order」,以及「When working with bidirectional text, the characters are still interpreted in logical order—only the display is affected.」

就这一句话,解释了那个让阿拉伯字母音乐人以为自己的元数据闹鬼的现象:存储的字符串可以完全正确而显示是错的,也可以在视觉上正确而存储的字节是错的——而在屏幕上,这两种失败长得一模一样。 你没法靠看来审核这件事。你的发行商的客服也没法。

为什么 RTL 字符串里的拉丁字符串会跑位

UAX #9 给每个字符一个双向类型。阿拉伯语、波斯语和乌尔都语字母是 AL(从右至左的阿拉伯字母)。拉丁字母是 L。ASCII 数字是 EN(欧洲数字),阿拉伯-印度数字是 AN(阿拉伯数字)。空格和大多数标点——包括圆括号、方括号、连字符和句点——是中性的,意思是它们自身没有方向,要从周围继承一个。

有两组规则在制造麻烦。

段落方向,规则 P2–P3。 算法扫描出第一个强方向性字符,并据此设定基准方向。一个以拉丁词开头的标题会得到从左至右的基准方向,哪怕它后面全是波斯语。

中性字符的解析,规则 N1–N2。 规则 N1:「A sequence of [neutrals] takes the direction of the surrounding strong text if the text on both sides has the same direction.」规则 N2:无法达成一致的中性字符取段落方向。随后规则 L2 为显示重排——「reverse any contiguous sequence of characters that are at that level or higher.」

把这些放在一起,失败就是确定性的,而不是随机的。一个拉丁字符串——某位混音师的名字、feat.Vol. 2、一个目录号、一个年份——与周围的阿拉伯语处在不同的嵌入层级上。它边界上的中性字符(空格、左括号)一侧是阿拉伯语、另一侧是拉丁语,于是 N1 找不到一致,N2 就把段落方向交给它们。一个在你的从右至左文本编辑器里按一种方式解析的括号,在从左至右的商店页面上会按另一种方式解析,于是括号脱离原位并翻转过去。

所以 نام آهنگ (Nima Remix) 并没有坏。它是同一个字符串在两种上下文里被解析。基准方向取决于上下文而非内容,而商店的上下文不是你的。

有一件事你绝对不能做

不要靠把字符倒着打、直到预览看起来对了,来「修好」显示。

那会产生一个逻辑顺序上错误、只在恰好一种渲染环境里正确、而在其他所有地方都是坏的字符串——包括搜索、排序、艺人匹配,以及任何页面基准方向与你修它时所用工具不同的商店。你会把一个可挽回的显示问题,变成一个不可挽回的数据问题。

UAX #9 确实定义了用于显式控制这件事的字符:隔离符 LRI、RLI、FSI 和 PDI,以及标记 LRM、RLM 和 ALM。它们是技术上正确的解法。它们同时也是不可见的格式字符,而许多交付管线会在不告诉你的情况下剥除不可见的格式字符。在元数据字段里,请把它们当作不可靠。

结构性的解法:把拉丁字符串从中间挪出去

在每一种渲染器里都有效、且不依赖不可见字符的缓解办法是结构性的。按优先级排列:

  • 只要数据模型提供了独立字段,就用独立字段,而不是混合方向的字符串。 特邀艺人属于艺人角色层级,不属于标题。Music Biz 的 Music Metadata Style Guide 建议在艺人角色层级署明特邀艺人,不要把这项数据加进单曲或专辑的发行标题;Spotify 的公开指引是「You shouldn't include any artists' names in your track or release titles.」版本信息属于版本字段,而该字段的全部职责就是区分共用同一标题的两个录音。你每把一个拉丁字符串挪进它自己的字段,就消掉了一个双向边界。
  • 任何无法避免的拉丁字符串都别放在首位。 首位在 P2–P3 下决定段落方向。一个以拉丁词开头的波斯语标题,是一个包含波斯语的从左至右段落,而那不是你的本意。
  • 避免在方向边界上使用装饰性标点。 破折号、斜杠、竖线和层层叠叠的括号都是中性字符,而它们所在的位置恰恰是算法信息最少的地方。

如果合同确实要求把署名放进标题里,那么惯例是固定的,值得严格照做。Music Biz 关于「feat.」和「with」:「when included in the title are generally lowercase and in English.」Apple 的风格指南:「Formatting of 'feat.' and 'with' must be lowercase, in English, not localized, and in parentheses or brackets.」那句「not localized」在这里是真的在起作用——不要把标题字段里的「feat.」翻译成阿拉伯语、波斯语或乌尔都语。它是一个机器可读的记号,不是一个词。

数字,以及你的数字为什么可能不是你以为的那套

这里有三套数字在流通:

数字集码位使用于双向类
ASCII0–9各处EN
阿拉伯-印度数字U+0660–U+0669 (٠١٢٣٤٥٦٧٨٩)阿拉伯语AN
扩展阿拉伯-印度数字U+06F0–U+06F9 (۰۱۲۳۴۵۶۷۸۹)波斯语、乌尔都语EN

这些不是风格变体。它们是不同的码位,而且按 Unicode 字符数据库,它们连双向类都不相同。UAX #9 的规则 W2 会在最近的前置强字符是阿拉伯字母时,把欧洲数字重新归类为阿拉伯数字,所以在波斯语文本内部,两者在显示时可能表现一致——但在排序、搜索或字符串比较中永远不会一致,因为它们是不同的字符。用扩展阿拉伯-印度数字 ۲ 打出的「Vol. 2」和用 ASCII 2 打出的「Vol. 2」,是两个看上去几乎相同的不同字符串。

一个曲库只选一套数字,并且永远不要在同一个字符串里混用。

怎么检查你实际打进去了什么

显示不可信,所以要查字节。每次交付前有三件事值得做:

  1. 把字符串当作码位来读,不要当作字形。 任何能给你看 U+ 值的工具,都会立刻告诉你那是波斯语的 ی (U+06CC) 还是阿拉伯语的 ي (U+064A),是波斯语的 ک (U+06A9) 还是阿拉伯语的 ك (U+0643)——这个区别被多数字体抹平,没有任何校对者看得出来。同理还有一个游离的 tatweel (U+0640),任何 Unicode 规范化形式都不会移除它,以及被表单字段悄悄吃掉的零宽不连字符 (U+200C)。
  2. 把标题分别粘进一个从左至右的环境和一个从右至左的环境里对比。 如果标点在两者中落点不同,那你手上就是一个混合方向的字符串,以及一个本该放进自己字段里的拉丁字符串。
  3. 和你上一次发行逐字符对比,不要靠眼看。 阿拉伯字母的曲库被拆开,几乎总是由一个看不见的差异造成的:一次发行是在波斯语键盘布局上打的,下一次是在阿拉伯语布局上打的。

Mazufa 的工具完全在你的浏览器中运行——不上传任何音频,也不上传任何文本——并且在标题是从右至左时自动设置 dir="rtl",这样你打字时看到的,就与该字符串所面向的上下文一致。mazufa.com 上还有一个免费的元数据检查器,它在你自己的设备上运行,并标出若干不可见的情况:混用的数字集、tatweel、多余或缺失的 ZWNJ、阿拉伯语与波斯语的 yeh 和 kaf,以及非 NFC 的字符串。

交付前该做什么

拿出你下一次发行的标题和艺人名,做四件事。把每一个能挪的拉丁字符串挪进它自己的字段——特邀艺人挪到艺人角色,版本挪到版本字段。确认没有任何内容以拉丁词开头。统一你的数字集并移除所有 tatweel。然后把字符串当作码位读一次,并把这个确切的字符串存为规范写法,以后每次发行都复用它,不要重新打一遍。

如果某个标题实在必须在中间带一个拉丁字符串,那就交付它,并接受它在不同地方会呈现得不一样。那是一个显示结果,不是损坏。字符串是对的。为了让某一个预览看起来正确而把它倒着重打一遍,才是让它真正变错的唯一方式。

参考来源

  • Unicode Standard Annex #9, Unicode Bidirectional Algorithm (Revision 51, Unicode 17.0.0, 2025-08-13) — https://www.unicode.org/reports/tr9/
  • Unicode Standard Annex #15, Unicode Normalization Forms (Version 57, Unicode 17.0.0, 2025-07-30) — https://www.unicode.org/reports/tr15/
  • Unicode Character Database —— 字符属性:双向类、分解映射 — https://www.unicode.org/ucd/
  • Music Business Association, Music Metadata Style Guide v2.1 — https://www.musicbiz.org/wp-content/uploads/2016/04/MusicMetadataStyleGuide_V2.1.pdf
  • Apple Music Style Guide — https://help.apple.com/itc/musicstyleguide/en.lproj/static.html
  • Spotify for Artists, Music metadata guidelines — https://support.spotify.com/us/artists/article/metadata-formatting-guidelines/

语料为上述文档给出了版本与修订日期(如上所列),并未为它们记录单独的阅读日期。

免费工具

Mazufa 做的每一个工具都在你的浏览器中运行,不收费,也不需要账户。

打开工具箱 ⇥