前途光明 道路曲折 中庸
我上个月在Geelong的linux.conf.au 上看到Moriel Schottlender谈论了这个话题,并请她提交有关此主题的文章。当您观看她的谈话视频并阅读她的文章时,您会明白为什么我不能记下适当的笔记来撰写有关这次谈话的内容,因此我很高兴她可以直接将她的故事贡献给我们。里基·恩德斯利(Rikki Endsley)
英文是从左到右书写的。 希伯来语从右到左书写。 我们知道。 浏览器(大多数情况下)也知道这一点,就像他们知道网页的默认方向是从左到右(LTR)一样,并且如果有一个设置可以明确定义从右到右的方向,左侧,页面应该像镜子一样翻转。 这样的浏览器很聪明。 大多。
但是,即使浏览器在决定混合语言时该怎么做,我的朋友们,这也是解决键入和查看双向文本时真正奇怪问题的良方。
字符和字符串的双向性
在深入研究一些有趣的混合方向性问题示例之前,我应该首先浏览一下浏览器如何全面考虑方向性。
我已经说过,英语被公认是一种“ LTR”语言(从左到右),希伯来语,阿拉伯语,乌尔都语(和其他一些语言)被当作RTL语言(从右到左)。 这些非常清楚,如果您自己键入一个由这些语言组成的字符串,情况可能会好一些(但稍后我会讨论一些问题)
但并非字符串中的所有字符都相等。 **
希伯来语和英语(以及其他几种语言)属于“强”方向性类型,它们不仅具有方向性,而且会影响周围环境。 一些字符具有“弱”的方向性,因为尽管它们内部具有方向性,但它们不会影响周围的字符。 有些角色只是中立的,这意味着他们可以通过周围的环境来获得自己的方向性。 哦,还有一些字符可能(并且确实)根据它们所在的文本在视觉上翻转。
不用担心 我将解释eeeeeeeeeeeeeeeeverything。 好吧,我将尝试,所以继续阅读。
角色定向类型
Unicode是在线上最常见的编码系统, 它将字符组的字符类型方向性定义为strong,weak或neutral。 这些类型控制这些字符在字符串中的显示方式。
在互联网发展的最初阶段,即远古时代,当恐龙在地球上漫游,而阅读这篇文章的你们中的一半可能是在尿布中时,互联网几乎认为一切都是从左到右的。
我记得今天我们大多数人都不愿使用原始HTML构建网页。 确实没有网站,只有静态HTML页面的集合,这些页面通常包含可怕的标签(例如<blink>和<marquee>)以及精选页面,其中一键式全部和背景都被平铺。 啊,祝您一切顺利。
那时,希伯来语实际上是向后打字的。 如果我想写希伯来语单词“שלום”(以希伯来字母“ש”开头),我必须向后键入,以字母“ם”开头并产生“םולש”,因为字母会顺序出现从左到右。 键入一个或两个单词时,这可能是可行的,但是如果您有整个段落或整个文章,它可能会很烦人。
在过去的日子里,您可以下载几种工具来获取文本并翻转文本。 因为那是我们那时回退的方式。
幸运的是,Unicode进来并定义了方向性,尽管Unicode仍然存在问题,但RTL用户至少可以正常键入他们的语言,而不必学习向后编写。 有帮助。
强类型
强类型是具有明确方向性的字符集。 希伯来语总是从右到左。 英文总是从左到右。 **当我键入这些字符集中的任何一个时,我的字符将根据方向性依次出现,一个接一个。 这是单词“ Hello”从左到右出现的方式,而单词“שלום”从右到左出现。
强类型还可以设置它们所处空间的方向性,这意味着如果我在您现在正在阅读的句子中间插入任何具有弱或中性方向性的字符(并且我已经这样做了),它们将假定强类型字符串的方向,在这种情况下为英语。 因此, 强类型不仅涉及角色本身,还涉及其周围环境 。
弱类型
弱类型很有趣。 这些是可能有方向的字符序列,但不会影响周围的环境,并且可以根据周围的文本进行调整。 该组中的字符包括数字,加号和减号,冒号,逗号,句号和其他控制字符。
根据Unicode双向算法规范, 弱类型根据先前的字符解析 。
中性类型
中性类型是最有趣的。 中性字符是可以从右到左或从左到右的字符类型,因此它们完全取决于包围它们的字符串。 这些内容包括换行符,制表符和空格。
根据Unicode双向算法规范, 中性类型会根据周围的文本来解析其方向性。
隐式级别类型:当您键入的内容与获得的内容不完全相同时
因此,我们有强类型,弱类型和中性类型,但这不是我们的方向性双重终结的地方。 实际上,真实的doozies是在RTL或LTR中以不同的方式解析的字符(例如,它们实际上具有不同的形状)。
是的,您没看错:在LTR字符串内部和RTL字符串内部编写时,它们实际上从字面上看非常明显。
最好的例子是括号和(我个人最好的朋友)括号。 这些符号实际上是已经表示方向的图标。 键盘上带有“(”的按钮并不完全是,而是“开放括号”的符号。在英语(从左到右)中,该符号自然是(要打开括号,并)为关闭它们。但在希伯来语和阿拉伯语和其他RTL语言,“开括号”符号是相反的),因为该字符串是从右到左。 因此,根据您在何处键入该符号,该符号将显示在屏幕上(或)。
我知道,对吧?
双向混搭
通常,如果一个人仅在文档中使用一个方向(特别是在线),则问题不会那么明显,因为强类型文本会包围所有其他弱和隐式字符类型,默认情况下使其成为自己的类型。
当我们必须混合语言和方向,或者在用于LTR的块中使用RTL语言时,就会出现问题。 这在网上经常发生-如果HTML文档中的任何地方都没有明确的dir =“ rtl”,则该文档默认为LTR方向性。 页面的方向性(通过使用dir ='rtl'或dir ='ltr'或根本不使用dir =属性,并依靠其默认回退为'LTR')被认为可以显式设置所需文本的方向性。 因此,方向性不明确的任何字符都将采用该属性设置的方向。
例如,如果我尝试在具有dir ='ltr'的页面的文本框中键入RTL语言,则可能会遇到很多烦人的标点符号,句子段位置以及混合语言的问题。强类型。 如果我尝试在RTL设置的文本框中键入LTR语言(例如,英语),则相反。
它会变得非常令人困惑,以至于经常在我试图弄清楚如何在RTL框中键入LTR文本并查看我的文本实际如何组织自身时,我的心态几乎崩溃了。
黄金三镖客
因此,很明显,Unicode的创建要比之前存在的反向键入(以及需要使用多种单独的字体)优越得多。 浏览器倾向于遵循Unicode规则(尽管执行自己呈现的应用有时不这样做,但这是一个不同的问题。)这种Unicode方向性算法在键入不同的方向时为我们提供了很多真正的好东西,但是也有坏事,有时甚至是丑陋的事。
好东西
确实,由于Unicode的双向算法,发生了很多事情。 正如我已经提到的那样,RTL用户可以正常(而不是向后)输入语言这一事实已经是一件好事了(我从经验中知道,因为我在系统没有那么好的功能时就使用了它。)
双向性算法的其他好处是,我们可以在RTL文本中使用数字(弱类型LTR)。 因此,例如,考虑以下文本:
希伯来语09:35希伯来语
从字面上看,这意味着“我们将在09:35在海滩见面”。 但是请注意,即使没有任何方向性修正,数字09和35仍应从左到右,因为这是数字的读取方式,但是当我编写此代码时,我实际上并不需要手动反转输入句子。 浏览器为我做了。
不过,这是一个不错的练习。 选择该句子。 当您这样做时,您可以确切地看到哪个部分具有什么方向性。 这导致我...
坏事
选择项
选择是双向文本问题的主要部分。 从“好东西”的示例中可以看到(我不需要反向键入),还有一个不好的方面,那就是如何选择我的文本。 选择可以是逻辑的或可视的。 光标移动也是如此,我将在稍后介绍。
视觉选择仅仅是视觉的,这意味着选择将文本段视为一个连续的块,而与方向无关。
逻辑选择意味着将文本分为双向部分。 这意味着,如果我在RTL文本的开头(在右侧)开始选择,然后将鼠标拖到其结尾(向左),则选择将在到达数字部分时拆分,因为数字在左边-从右到右。
实际上,这是逻辑上的,因为它是从逻辑开始到逻辑结束,并且因为文本是双向的,所以对于每个部分而言,这两个指针是不同的。 这很有道理,但可能会造成混淆。
光标移动
同样,光标也可以逻辑或视觉上移动。 这可能会造成一些混乱,有时这种行为在各个平台之间是不一致的。 不过,在大多数情况下,这种运动是合乎逻辑的。
因此,这里快速测试了这种行为可能变得很奇怪的地方。 考虑下面的句子。 它在文本框中。 因此您可以选择它并在其中正确移动光标。
或相反:
(为此向Amir Aharoni提示)
让我们仔细看一下该可怕文本框中发生的事情。 首先,第一个文本框的部分问题是该文本框是强制RTL,并且由于其中的大多数文本是英语,因此在奇怪的地方出现了问题。 这是强制为LTR时的句子:
请记住,英语是LTR的强类型,而עברית是RTL的强类型。 将英语ועברית混合在一起时,您可能会得到一些令人惊讶的结果。
但是请注意,文本框问题在相反的情况下也发生了相同的情况,其中文本框是LTR,句子主要是RTL。
使用强制RTL文本框(以及大多数为LTR强烈键入的文本),空格占据了其所包围的文本的方向性,即LTR。 然后,我们在希伯来语中使用了一个强类型的RTL单词,这使其中的空间变成了RTL,但是周围的空白(RTL单词和LTR句子之间的空格)仍然受到周围文本(即LTR)的影响。
如果您仍在这里与我在一起,这可能会帮助您将观点带回家。 本质上,您有:
[ENGLISH_CHUNK 3]希伯来语[ENGLISH_CHUNK 2]希伯来语[ENGLISH_CHUNK 1]
整个句子结构是从右到左的,但是小的英语部分是从左到右的。 总体“块状”方向是RTL。 每个块都有自己的内部方向。 当您阅读该书时,它看起来一团糟-因为它是。
在第二个文本框中,这完全相同(仅相反)。 用LTR代替RTL,反之亦然。
我知道。 我知道。
丑陋的东西
现在,我们移至丑陋的区域,这些东西不仅是困难的行为,而且还会产生视觉上不同的结果。 还记得那些弱类型和隐式级别的类型吗? 那就是这些东西的来源,我告诉你,它们轰轰烈烈地使我们彻底困惑。
空格
空白是隐式级别的类型,这意味着它们是由它们所居住的文本定义的。您现在正在阅读的句子中的空格是隐式LTR,因为它们位于英文文本中。 这里的空白:尽管页面本身是LTR,但它们隐含在RTL中,因为它们位于希伯来语中,因此它们隐含RTL。
这很好,但是也会产生一些奇怪的结果。 考虑一下我在文本中有一组数字的情况。 数字由空格分隔,空格由周围的文本定义。 但是数字本身是“弱”类型的,这意味着它们不会影响自己的周围环境(即使它们内部是LTR)。 空格必须围绕整个数字段的任何单词取其方向性。
听起来很奇怪? 该行为甚至更奇怪。 看到这个,例如:
我故意将这些数字封装在LTR文本中,因此分隔这些数字的空格仍是LTR。 但是,如果我用希伯来语(RTL)替换那些英语单词,您会怎么办? 好吧,这个例子是完全相同的句子和数字序列,以相同的顺序排列,唯一的区别是“开始”和“结束”被预期的希伯来语单词代替。
数字颠倒了! 数字...是...头在旋转吗? 这可能很奇怪,但是很有意义。 现在,空格已封装在RTL文本中,这意味着它们现在是RTL。 RTL句子中的空格是从右到左,因此数字分组从右到左。
但是我认为您的头还不够快。 如果我们在数字分组本身内部添加空格,将会发生什么? 我的意思是,数字在内部是LTR,但空格是RTL,所以我们将添加一个空格以断开组,然后...组将继续旋转?
试试吧。 在下面的数字组中添加空格。
看见? SEEEEEEEEEE吗?
是的 究竟。
括号和括号
正如我在本文前面所讨论的,括号和括号实际上代表“开始”和“结束”,这意味着根据插入位置的不同,它们可能会在屏幕上以不同的方向出现。
因此,如果我按下键盘上有一个漂亮[的按钮(在{下方和P旁边),我会在LTR和RTL中得到不同的结果。
这意味着该代码:
LTR:<span dir="ltr">[</span>RTL:<span dir="rtl">[</span>
变成这样:LTR: [ RTL: [是的,我单击了相同的按钮。 是,我确定。 欢迎您查看源代码。
当需要在RTL文本框中添加一些html <tags>时,这种效果不仅使它变得怪异,而且令人难以置信。 而且,是的,这发生在Wikipedia和RTL Wikipedias中。
尝试在下面的文本段中添加<span style =“ font-size:2em”>。 祝你好运,保持理智,记得呼吸。 如果您特别喜欢冒险,还可以尝试插入一些Wikitext,例如带有希伯来语标题的“ Somewhere”页面的链接(英文链接)。
想变得更疯狂吗? 在希伯来语之后添加一些英语文本,然后尝试从希伯来语字符串开始设置一些<a href="something.html"> </a>,并以英语结尾。
输入所有内容,请勿作弊并复制/粘贴。 真正尝试一下。 继续玩吧。 实验。 让RTL疯狂。
在线文本编辑器和Wikimedia的VisualEditor
现在,我们在网上处理从右到左文本已经历了一系列可怕的有趣挑战,我们可以看到它们如何影响在线文本编辑器的开发工作。 在Wikimedia Foundation中,我们一直在研究VisualEditor,这是一种用于编辑Wikipedia文章的WYSIWYG系统。 它不仅可以将HTML转换为Wikipedia的“ wikitext”语法,而且还必须在多种方向,平台,浏览器和本地化环境中处理多种语言。 基本上,我们需要支持上面讨论的所有案例,然后再支持某些案例。 那有多难?
作为文本编辑器, VisualEditor希望用户输入文字,然后输入。 他们还以多种语言来执行此操作,并且通常在同一篇文章中以多种语言来执行此操作。 混合语言非常普遍,尤其是在Wikipedia中,当需要提供从另一种语言中提取的单词的原始文字或以其原始文字提供的城市名称时,等等。
但是正如我们看到的那样,打字可能很棘手,尤其是当我们混合使用方向时。 我们必须确保允许用户键入内容,同时看到他们将在逻辑上进入页面的结果。 我们还必须确保它们的键入是有意义的,并且如果需要将特定范围的文本描述为不同的方向,则它们可以轻松地做到这一点。 我们必须确保正确解释了他们的输入,RTL在ContentEditable屏幕中正确显示,然后在保存的文章中正确呈现。
另外,从我上面带有[字符的示例中可以看到,HTML代码和结果呈现之间存在差异。 也就是说,我键入了[但得到了],并且[出现在了代码中,但是]出现在了我生成的渲染标记中。 在VisualEditor内部应该发生什么? 预期您输入的内容会被翻转时,所见即所得的情况大不相同。
这些事情不是没有可能解决,但它们具有很大的挑战性,并且通常需要就用户应期望的内容做出决策。 大多数在线(和离线)应用程序在处理LTR / RTL类型时遇到问题,这使这些战略决策更加复杂。 需要根据我们认为的最佳方式来设计行为,而不是RTL用户期望的行为,因为从当前行为可以看出,RTL用户通常期望可怕的行为。
不过,这是一种很好的挑战。 很多人都在关心找到一种好的修复方法。
但是等等,还有更多
双向文本还有很多其他问题,其中一些是在线发布的软件和应用程序中存在的问题,这些问题使RTL'er的生活相当烦人。 我可能会在某个时候写这个,并分享我对RTL的沮丧。 如果您对这些挑战如何转化为日常生活感兴趣,还可以访问http://rtl.wtf并亲自见证RTL用户定期在网上体验到什么。
在本文中,我讨论了LTR盒内RTL字符串的问题,方向性不明确的字符,选择和光标移动以及一般的“哼”的问题。 当然,还有更多的RTL困难,但是这篇文章的目的是作为对主要和最常见的双向性问题的介绍。
希望您喜欢它。 至少,我希望您现在了解程序员(和RTL用户!)必须处理的内容。
侧边栏:
语言和文字
在本文中,我使用术语“语言”来指代英语和希伯来语字母。 实际上,我应该使用术语“脚本”来指代字母和字符本身。 差异主要来自以下事实:尽管希伯来语和英语是语言,但它们各自使用可以在其他语言中使用的字符。 例如,英语使用拉丁语脚本,希伯来语脚本也可以用意第绪语使用。
因此,请考虑到这种情况,并且所使用的LTR或RTL实际字母实际上是“脚本”而不是语言,因为浏览器实际上并不关心您使用这些字面量键入的单词脚本。
但是,为了简单起见并尝试减少混乱,我做出了一个战术决策,将其全部归类为最熟悉的“语言”术语。(感谢MatmaRex指出我至少应该提到这种区别。)
有用的链接
Unicode双向算法: http : ///reports/tr9/ Visual Editor的双向文本要求(由Amir Aharoni提供) /wiki/Visual_editor/Bidirectional_text_requirements VisualEditor:支持从右到左/双向内容跟踪错误: https :///show_bug.cgi?id=33126 从90年代#1高炉: Windows 3.1的希伯来语/英语网络字体 来自90年代的爆炸#2: 在线书写和阅读希伯来语的工具翻译自: /life/16/3/twisted-road-right-left-language-support
前途光明 道路曲折 中庸