包括中文、英文、+-等各种符号,都是从左往右显示,而阿拉伯语、波斯语等则是从右往左显示,等等问题都需要进行本地化适配。
2.1)RTL语言有以下6种:
阿拉伯语 | ar | Arbic | العربية |
波斯语 | fa | Persian | فارسی |
希伯来语 | iw | Hebrew | עברית |
乌尔都语(印度、巴基斯坦) | ur | Urdu | اردو |
维吾尔语 | Uyghur |
2.2)数字:
西阿拉伯数字:(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
东阿拉伯数字:(٠ - ١ - ٢ - ٣ - ٤ - ٥ - ٦ - ٧ - ٨ - ٩)
波斯数字:(۰ - ۱ - ۲ - ۳ - ۴ - ۵ - ۶ - ۷ - ۸ - ۹)
其他有一些语言也有自己的数字.
2.3)
强字符:具有明确方向的字符,这种类型字符的例子包括大多数字母字符、音节字符、汉语表意文字、非欧洲或非阿拉伯数字,以及这些语言脚本的标点。
弱字符:具有模糊方向的字符,这种类型字符的例子包括欧洲数字、中东阿拉伯-印度数字、算术符号和货币账号。许多语言脚本中的标点符号,如冒号、逗号。
中性字符:不根据上下文就无法确定方向性,例如段落分隔符、制表符和大多数其他空格字符。
一、控件的显示
“+8618310002000”这类号码会被显示成“8618310002000+”,就是因为阿拉伯语是从右往左显示的,所以加号显示在了最右边。
设置控件的textDirection属性即可,控制组件的文字对齐方式:
android:textAlignment="viewStart"
.setTextDirection(View.TEXT_DIRECTION_LTR);
.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
此外还有layoutDirection属性来设置组件的布局排列方式。
二、数字的格式化
比如,将西阿拉伯数字改成东阿拉伯数字。
西阿拉伯数字:(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
东阿拉伯数字:(٠ - ١ - ٢ - ٣ - ٤ - ٥ - ٦ - ٧ - ٨ - ٩)
这类问题又细分为以下几种:
1)纯数字,可以使用 Character.getNumericValue来转换,给控件设置LTR属性即可。
2)带有“+”,“,”等中性字符、弱字符符号,比如前者用在+86,后者用在分机号,可以给控件设置LTR属性,也可以通过BidiFormatter.getInstance().unicodeWrap(),它会根据上下文来添加LTR属性。
3)带有“@”等强字符符号,比如SIP账号“[email protected]”,需要使用\u202A等标记来强制改变方向。同时空格等中性符号,如果在阿拉伯语环境下会显示成RTL,例如将号码“183 1000 2000”显示成“2000 1000 183”,因此也需要使用此类符号。
同时在场景中又细分为以下几种:
1)直接进行转换的数字:控件中展示给用户的数字,如“1秒、2秒”
2)用户的输入但是需要转换的数字:比如在联系人中输入号码10086,则转换成١٠٠٨٦
3)不应该转换的数字:收到短信中包含数字,联系人名字中包含的数字(验证过iOS中也是处理)
同时记录另一个问题,在某些只能输入数字的情况下,iOS的键盘能够输入多种数字,Android目前看到的都只能输入西阿拉伯数字。
我针对上述情况拆分出以下3个方法。
1)localizeString(String str)
将字符串中的数字进行翻译,但不改变方向)。
例如10086,10010等共2人,会被翻译成“人2共等10086,10010”,(由于wiki本身RTL支持不好,我复制过来顺序都显示的错的,所以举例中只改了方向,数字文字都不变,下文同理)。
数字本身是LTR的,先翻译10086,逗号是弱性字符,跟着左边,再往后才是10010(这里应该让10086显示在右边比较好,但是考虑到这个场景问题不大,暂不处理),接下来是阿拉伯语,因此后面的方向是RTL的。
2)localizeNumber(String number)
localizeNumber(String number, boolean nameIsNumber)
对号码中的数字进行翻译,默认nameIsNumber为true,当为false时表示为name,因此不翻译。
2.1)中性字符,例如加号
例如+8618310002000,当为阿拉伯语环境时,第一个+号显示出来之后根据上下文环境判断是RTL,因此号码显示在+号左边,最终是8618310002000+。此时使用View.TEXT_DIRECTION_LTR即可。
例如+86 183 1000 2000,当为阿拉伯语环境时,同上+号第一个显示,86紧随+号,同时空格也是中性字符,在RTL环境下也是继续往左显示,最终显示为2000 1000 183 86+。但此时添加View.TEXT_DIRECTION_LTR只能让+号显示正确,空格并不生效,原因尚不清楚。
2.2)弱字符:例如冒号、逗号
例如播分机号时10086,1,1,它会继承前面的顺序,因此顺序不变还是10086,1,1。如果是10086\u202B,1:2,这里的\u202B是RTL的属性,首先是10086,然后逗号前有RTL标记,因此其之后改变方向为RTL,所以最终是100861:2,。
2.3)强字符:例如@等符号
例如SIP号码[email protected],@和阿拉伯语一样属于强字符,因此显示为10.238.24.140@123,这次需要使用\u202A标记来将方向改成LTR。
3)localizeDigit(String str, boolean isNeedLTR)
这个方法是最终用来处理的,因为处理有前提,不推荐外部调用,所以设置成了private。
当前需要改成LTR且环境是RTL时,才添加\202A标记,减少不必要的操作同时降低风险。
三、双向字符集
这类问题比较复杂,原生系统中也大量存在。
没有发现什么特别好的办法,加标记是可行的,但是很麻烦。比如使用\u200f和\202A等标记,具体就不展开讲了,核心内容在上一节已经举例讲过了。
string-concatenation-containing-arabic-and-western-characters
Universal_Character_Set_characters
en.wikipedia.org/wiki/Bi-directional_text