在Xcode中,如何显示混合英语和阿拉伯语并以阿拉伯语开头的文本?

16

我想给一个字符串设置标签:"خخخ just bought: Disguise Kit.",但是当我运行测试时,标签显示为".just bought: Disguise Kit خخخ"?

如果文本不以阿拉伯语开头,则会按照我设置的方式显示。 问题出在哪里?

有谁知道如何处理这个问题吗?


这是RTL问题吗?你能鼓励阿拉伯语显示LTR吗? - James Webster
@JamesWebster 我不这么认为。如果这是RTL问题,为什么只出现在以阿拉伯语单词开头的情况下呢? - user1300503
因为这个句子将从右到左开始(خخخ 从右侧开始),然后似乎会切换到从左到右以绘制剩余的单词。 - James Webster
@JamesWebster,你能举个例子来说明如何修复吗?因为如果你设置Label.textAlignment = UITextAlignmentRight; 它只会将文本右对齐,而不是反转字符串顺序。 - user1300503
很抱歉,我不知道如何修复它。我只是意识到可能是这个问题。我并没有真正使用过RTL语言。 - James Webster
3个回答

43

首先,阅读Cal Henderson杰出的 "Understanding Bidirectional (BIDI) Text in Unicode."

不管你相信与否,UILabel 是按照你要求的方式进行布局的。你提供了一个从右到左的字符串(从阿拉伯语开始)。它从右到左开始显示。然后你嵌入了一个从左到右的英文字符串,它会从左到右进行布局。然后,它看到了句号,并由于这是一个包含一些英文的阿拉伯字符串(尽可能地由UILabel判断),所以它进行了从右到左的布局。

你想要的是一个从左到右的包含阿拉伯字符的字符串。这意味着你必须用从左到右的字符开始字符串。有两个选项:在开头添加一些英文或使用零宽度的从左到右标记(U+200E,LRM)将字符串的开头锚定到LTR模式。

Objective-C:

self.label.text = @"\u200eكتب just bought: Disguise Kit.";

Swift:

->

Swift:

self.label.text = "\u{200E}كتب just bought: Disguise Kit."

关于 U+200E 的好消息是,在显示之前,您可以安全地将其添加到每个 LTR 字符串中。您甚至可以安全地将其放在 LTR 语言的本地化字符串的开头。如果它是冗余的,则不会造成任何损害。

还有几件事情需要注意:永远不要使用ككك测试这些内容,而应该始终使用كتب(就像每个好学生一样:D),或者最好像الو这样完全相反的东西。否则,你无法判断阿拉伯语是否以反向方式布局。我喜欢 الو,因为反过来看完全不同。

另外,在测试时,请注意 Xcode 不知道如何布局阿拉伯语。所以,如果您在代码中编写任何静态字符串,它们将在编辑器中以反向方式显示,但在 UI 中将正确显示。这让我发疯。


请务必查看 guru_meditator 的答案,了解 iOS 10+/macOS 10.12 中添加的有用相关功能。


非常感谢,这就是我想要的! - user1300503
4
我必须使用\U200E(大写的U和E)才能从Localizable.strings文件中使Obj-C代码正常运行。 - Austin Borden
1
有零宽度的从右到左标记吗? - Johny D Good
5
是的,U+200F是从右到左标记。 - Rob Napier
1
@RobNapier 是个时间救星,非常感谢 \U200F :D - Konstantinos Natsios

5
自iOS 10(和macOS 10.12)起,String localizedStringWithFormat在占位符周围插入Unicode隔离符号。这是一种更高级的字符串格式化方式,可混合使用多种语言方向,无需手动插入方向标记。
String.localizedStringWithFormat("%@ just bought: Disguise Kit.", "خخخ")
// "⁨خخخ⁩ just bought: Disguise Kit."

与之比较:

String(format: "%@ just bought: Disguise Kit.", "خخخ")
// ".just bought: Disguise Kit خخخ"

为了了解localizedStringWithFormat的作用:
let scalars = String.localizedStringWithFormat("%@ just bought: Disguise Kit.", "خخخ")
    .unicodeScalars.map { "U+\(String(format: "%04X", $0.value))" }
print(scalars)
// ["U+2068", "U+062E", "U+062E", "U+062E", "U+2069", "U+0020", ...

U+2068代表首个强制隔离符,U+2069代表弹出方向隔离符。有关隔离符的更多信息,请参阅: https://www.unicode.org/reports/tr9/tr9-41.html#Explicit_Directional_Isolates

此功能是在WWDC 2016 232国际用户界面的新功能中引入的。


localizedStringWithFormat 像魔法一样好用。谢谢。 - user3305074

0
实际上,任何符号都可以插入字符串文字中。
  1. 添加“Unicode 十六进制输入”(系统偏好设置 -> 键盘 -> 输入源 -> + -> Unicode 十六进制输入)。
  2. 在文本编辑器中将光标移动到要插入符号的位置。
  3. 将输入源切换为“Unicode 十六进制输入”。
  4. 按住 Option 键并键入 200E。
  5. 符号应该被插入,字符串应该看起来像你期望的那样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接