App国际化过程中遇到的RTL相关问题总结

目录

  1. 需要单独适配的原因
  2. 适配须知
    1. RTL语言有以下6种
    2. 数字:
    3. 字符类型
  3. 需要进行的修改
    1. 控件的显示
    2. 数字的格式化
      1. 1)localizeString(String str)
      2. 2)localizeNumber(String number)
      3. 3)localizeDigit(String str, boolean isNeedLTR)
    3. 双向字符集
  4. 参考

需要单独适配的原因

包括中文、英文、+-等各种符号,都是从左往右显示,而阿拉伯语、波斯语等则是从右往左显示,等等问题都需要进行本地化适配。

适配须知

RTL语言有以下6种

阿拉伯语 ar Arbic العربية
波斯语 fa Persian فارسی
希伯来语 iw Hebrew עברית
乌尔都语(印度、巴基斯坦) ur Urdu اردو
维吾尔语 Uyghur

数字:

西阿拉伯数字:(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
东阿拉伯数字:(٠‎ - ١‎ - ٢‎ - ٣‎ - ٤‎ - ٥‎ - ٦‎ - ٧‎ - ٨‎ - ٩‎)
波斯数字:(۰ - ۱ - ۲ - ۳ - ۴ - ۵ - ۶ - ۷ - ۸ - ۹)
其他有一些语言也有自己的数字.

字符类型

强字符:具有明确方向的字符,这种类型字符的例子包括大多数字母字符、音节字符、汉语表意文字、非欧洲或非阿拉伯数字,以及这些语言脚本的标点。
弱字符:具有模糊方向的字符,这种类型字符的例子包括欧洲数字、中东阿拉伯-印度数字、算术符号和货币账号。许多语言脚本中的标点符号,如冒号、逗号。
中性字符:不根据上下文就无法确定方向性,例如段落分隔符、制表符和大多数其他空格字符。

需要进行的修改

控件的显示

“+8618310002000”这类号码会被显示成“8618310002000+”,就是因为阿拉伯语是从右往左显示的,所以加号显示在了最右边。

设置控件的textDirection属性即可,控制组件的文字对齐方式:

1
2
3
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账号“abc@10.239.224.22”,需要使用\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号码123@10.238.24.140,@和阿拉伯语一样属于强字符,因此显示为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


本站地址:http://nomasp.com/

欢迎交流,转载请联系本人,多谢🙏