作者简介
本文作者为携程国际事业部的设计和开发团队。
一、背景
随着国际化之路的进一步推进,Trip.com已经在全球多个国家开设了站点,今天的主角是阿拉伯世界。
阿拉伯语是仅次于英语和法语之外最多国家使用的官方语言,流通于中东、北非、非洲等地区。世界上以阿拉伯语为母语的国家有24个之多,人数多达4.22亿,其中旅游热门的埃及便是阿拉伯语使用人数最多的国家,约有5400万人以其为母语。为了更好地服务阿拉伯用户,我们不断学习阿拉伯文化,学习他的书写方式、阅读习惯,学习他的宗教信仰、风俗习惯。力图打造一个专业性强、影响力高的国际化品牌。
目前大部分国家及地区的语言的书写是从左到右的(_left-to-right 以下简称LTR),如汉语、英语。然而由于历史、文化原因,还有部分国家的语言书写是从右到左的(right-to-left _以下简称RTL),如阿拉伯语、波斯语、希伯来语、乌尔都语、维吾尔语等。
举个栗子(如图1),英文和汉字的书写、阅读顺序是从左到右,文本左对齐。而阿拉伯文书写和阅读顺序从右往左,文本右对齐,标点符号在文字的最左侧。
图1 LTR与RTL语言对比
适配阿拉伯语言本质上是对RTL的适配,也就是对从右到左的阅读方式的支持。这个将用户界面从LTR适配到RTL的过程,称之为镜像(如图2所示)。
图2 LTR与RTL界面概览
值得注意的是,镜像不是将页面简单的左右翻转,而是基于RTL的阅读顺序制定的一系列设计规则及适配方案。我们会从设计与技术方案两个方面来详细介绍Trip.com在阿拉伯世界的探索。
Trip.com一直致力于做好本地化设计,也就是基于不同国家或地区的文化背景,提供符合用户行为习惯的产品体验。在设计阿拉伯站的页面时,我们发现LTR与RTL的设计细节差异很大,我们将阿拉伯本地化的设计归为两个要点:
第一,如何做符合阿拉伯用户阅读习惯的设计;
第二,如何做契合当地习俗的情感化设计。
有的人可能会说,为阿拉伯人设计,直接镜像界面就可以了呢?答案是“不是的”。
阿拉伯站不光只包含镜像,还掺杂着许多基于元素含义而不镜像的规则。接下来我们就从需镜像和无需镜像两个方面来展示:
整体布局
设计师要把自己想象成从右到左阅读的用户,这样设计时就可以先把整个页面的布局镜像,如图3所示:
图3 整体布局镜像
操作习惯
和阅读习惯一样,阿拉伯用户对界面的操作习惯也与我们不同。页面之间涉及左右方向的手势,例如右滑退出页面,要变成左滑退出。同理,表示退出的左向箭头会镜像成右向箭头;涉及到左右分布的操作例如按钮,tab,加减器开关都需要镜像,部分规则如图4所示:
图4 操作镜像
部分图标
图标对辅助用户理解文本内容有着重要的意义,因此图标的设计也需要满足阿拉伯用户的阅读习惯。需要注意的是,图标是由图形组合而成,部分图标在镜像的过程不等同于直接左右翻转,而是通过调整元素的设计来满足我们设定的规则。我们整理出的需要镜像的部分图标如下所示:
图5 图标镜像规则
3.1.2 无需镜像
并非所有的图标或者文字都需要镜像,因为有些元素本身就已经符合RTL的阅读习惯,我们称之为无需镜像。规则如下:
无需镜像的图标
图6 图标无需镜像规则
阿拉伯数字与英文字母
阿拉伯数字和英文的展示同样遵循以上规则:属于是国际通用的,展示都无需镜像。例如航司名称,邮箱,网址,电话号码和账号密码:
图7 阿拉伯数字与英文字母
3.2 契合当地习俗的情感化设计
绝大部分阿拉伯人信奉伊斯兰教,有自己的节假日,部分阿拉伯国家对着装、饮食等有一定的要求。由于文化习俗的不同,阿拉伯站与其他站点的设计会有很大的差异。以下本地化设计都是基于对阿拉伯国家深入了解后所得出得设计:
我们调研了阿拉伯当地的日历展示,为其单独设计了一个日历,效果图如下:
经过针对阿拉伯用户的特征和宗教文化的调研,我们发现当前插画库中的部分人物有违背阿拉伯文化禁忌的风险,比如穿着短裙的女性,因此我们决定为阿拉伯站点设计一张中立且具有地域特征的插画。经过多次尝试,最终我们选择了中东地区的代表植物枣椰树以及被称作阿拉伯骆驼的单峰骆驼作为主要元素。
为了让空值页动效更富有生命力,我们在动效设计时,展开了对现实世界中骆驼动态的探索与研究,通过让尾巴具有纵深感的甩动,并结合气泡及枣椰树在二维空间的移动,整个画面更富有生命力和层次感。
除了空值插画,页面内还有一些场景辅助插画,我们也针对阿拉伯站点做了服装的调整:
3.3 设计效果图
基于以上设计要点,最终部分页面的设计效果如下:
系统历史:Android从4.1版本开始提供文本双向展示的支持,但是当RTL和LTR语言混排时,还是无法达到我们的预期,文中也介绍了文本的对齐原理。之后Android 4.2才开始对RTL有了全面的支持。所以如果App支持4.2以下的系统,代码中需要对版本进行判断。
项目支持RTL:
开发预览:Android Studio提供了强大的XML布局文件预览功能,方便在RTL和LTR之间进行切换,可以实时预览效果。
测试调试:在Android 4.4(API 级别 19)或更高版本的设备上,在开发者选项中允许启用强制使用从右到左的布局方向。这样我们可以不用调整手机系统语言也可以看到RTL的效果。
XML布局替换:Android Studio提供了一键替换的功能,右键layout文件夹-> Refactor -> Add Right-to-Left(RTL) support…,本质上是将XML中所有的Left/Right都替换成了Start/End。
代码中布局属性替换: 这里除了需要识别出官方文档中提供的布局属性之外,还有一些没有提到的属性也需要替换。
控件适配:
Android有一些系统控件不支持RTL,如ViewPage需要对手势进行适配,我们使用了 duolingo 的适配方案,详细可以查看引用部分的链接。
自定义控件中如果涉及位置计算(一般出现在onLayout方法中),RTL模式下都需要调整计算方法。
适配控件时,有时候修改数据源也可以起到相同的效果,善用Collections.reverse,可以为我们节省很多适配成本。
系统使用 android:textDirection 控制文字排列方向,android:textAlignment 控制文字对齐方向。其中控件中设置gravity属性需注意,textAlignment的优先级比gravity高。
TextView和EditText默认使用 firstStrong 和 viewStart 作为默认属性。一些由弱方向性字符[4]构成的文本,如电话号码、银行卡等,建议使用 firstStrongLtr (API 23及以上) 以及 anyRtl(API23以下)属性。
如设计部分所述,部分图片/图标区分非阿拉伯站点和阿拉伯站点。参照官方提供的适配方案,在drawable、layout、anim等同层级新增ldrtl目录,放入专为阿拉伯站设计的图片资源。如下所示:
res/ drawable-hdpi/ icon.png drawable-ldrtl-hdpi/ icon.png // same name
另外,drawable目录下的的绘制资源,可添加 android:autoMirrored=”true” 实现镜像。
一种“笨”阿拉伯站转场动画适配方案:调用 applyRtlTransition() 实现进场,applyExitTransition() 实现出场。
一开始我们在anim-ldrtl目录下放置转场动画,期望切换阿拉伯站时系统从中加载阿拉伯的镜像转场。然而,实践发现系统并不会从anim-ldrtl加载转场资源,或许是系统的bug。最终我们选择了上述“笨”方案。
iOS已经对阿拉伯布局提供了相对完善解决方案,在项目的支持语言中添加阿拉伯相关地区,App就会获得相应的适配效果:
布局方向:采用AutoLayout的leading trailing设置左右约束,可获得视图布局的RTL效果;
文本对齐:未显式设置文本对齐方向或段落书写方向,文本的对齐方式也将自适应RTL布局;
图片翻转:使用imageWithHorizontallyFlippedOrientation即可获取图片镜像
但仍有部分系统方案无法涵盖的内容,下面将着重介绍Frame布局的适配方案。
想要使用系统方案,只能使用Autolayout;
出于性能考虑,有些页面使用Frame进行布局。将Frame全部转换成Autolayout工作量不可控;
有些复杂页面“native视图”与“RN视图”组合展示,系统方案力不从心;
以页面为维度,指定各view是否翻转显示;
根据设置的显示方式,设置各view.layer.affineTransform 属性的值,使其达到最终效果。
不需要翻转的View (rtlType=Normal)
特定控件比如UILabel,UIImageIView,UITextField等
采用Autolayout方案适配RTL的View组件
RN视图直接使用自有解决方案适配
需要翻转的View (rtlType=Flip)
控制器的根视图
继承superView翻转方式,父view翻转则子view就翻转
view的显示效果有两个因素决定:
"superView是否翻转展示”
view.layer.affineTransform
superView 是否翻转展示 | view.layer.affineTransform | view是否翻转展示 |
Flip | CGAffineTransformIdentity | Flip |
Flip | CGAffineTransformMakeScale(-1,1) | Normal |
Normal | CGAffineTransformMakeScale(-1,1) | Flip |
Normal | CGAffineTransformIdentity | Normal |
根据 “superView 是否翻转展示” 及 “view是否翻转展示” 可以得到 view.layer.affineTransform 应该设置的值,代码如下。
BOOL shouldFlipSuperview;
BOOL shouldFlipCurrentView;
BOOL shouldSetFlipTransform = shouldFlipSuperview ^ shouldFlipCurrentView;
if (shouldSetFlipTransform) {
self.layer.affineTransform = CGAffineTransformMakeScale(-1,1);
} else {
self.layer.affineTransform = CGAffineTransformIdentity;
}
对需要翻转的 rootView设置rtlType=Flip;
UILabel,UIImageView等设置rtlType=Normal;
hook didMoveToSuperview 及 didMoveToWindow;
计算出shouldFlipSuperview, shouldFlipCurrentView;
计算出self.layer.affineTransform;
递归subView
React Native 自0.33 版本起支持 RTL 布局,组件之间的布局大部分会被自动水平翻转,仅有如下几点需要调整:
图片不会被RN 自动翻转,如果图片带有方向性,如箭头等,需要手动翻转:
或在 RTL 下换其他图片:
Text 组件的默认 textAlign 在 iOS 和 Android 平台上不一致。
iOS 默认值跟随当前语言 bundle,如 英语bundle下为 左对齐, 阿拉伯语bundle 下为右对齐。
Android 默认值跟随Text 的语言, 如英语Text下为 左对齐,阿拉伯语Text下为右对齐: - 如果Text 设置了 textAlign,则该Text会正常显示,无需适配 - 如果Text没有设置textAlign,在英语bundle下显示英语,在阿拉伯语bundle下显示阿拉伯语,则无需适配 - 如果Text没有设置textAlign,在英语bundle下显示英语,在阿拉伯语bundle下依然显示英语(或其他LTR语言),则需要手动设置textAlign。
TextInput组件
单行的TextInput,其value&placeholder&cursor 不能正确的翻转。
多行的TextInput,其 value&placeholder不能正确的翻转。
需要手动设置 textAlign,如下:
I18nManager.isRTL 通过 getConstants 方式从Native 端读取 isRTL 的值,其值仅读取一次,之后不再变化。如果APP 有切换 Locale的功能,切换Locale前后,Native端isRTL的值发生变化,如从en-us 切换到ar-eg,则RN端后续读取的I18nManager.isRTL 均为错误的值。
为此,Native 端需要监听Locale 的变化,并新旧Locale isRTL不同时,Reload所有正在使用的React Context,
iOS:
[RCTBridge reloadWithReason:]
Android:
ReactInstanceManager::recreateReactContextInBackground
在极短的时间内完成阿拉伯语适配规则以及技术方案的落地,不仅依赖Trip.com技术的协作,还有UED、翻译、市场等职能部门的紧密沟通及合作。Trip.com一直致力于极致的用户体验,希望全球的旅游者都能享受到 Trip.com 的专业化、本地化、高质量服务。
[1] Android:
https://developer.android.com/training/basics/supporting-devices/languages
https://android-developers.googleblog.com/2013/03/native-rtl-support-in-android-42.html
https://github.com/duolingo/rtl-viewpager
[2] React Native:
https://reactnative.dev/blog/2016/08/19/right-to-left-support-for-react-native-apps
https://reactnative.dev/docs/native-modules-android#the-toast-module
[3] iOS:
https://github.com/bytedance/AWERTL
[4] 文字方向:
http://www.unicode.org/reports/tr9/#BD1
https://www.w3.org/International/articles/inline-bidi-markup/uba-basics#directionalruns
【推荐阅读】
《携程架构实践》《携程人工智能实践》上市啦!
618满100-50元优惠活动进行中
《携程架构实践》
京东
当当
《携程人工智能实践》
京东
当当
“携程技术”公众号
分享,交流,成长
看到这里的小伙伴,点个“在看”再走吧↓↓↓