iOS 国际化 - 阿拉伯语的RTL 踩坑心得

屏幕快照 2019-02-28 上午10.45.28.png

iOS,移动开发,国际化,RTL,阿拉伯语
公司项目因为要适配中东市场,也算是做了不少RTL了,但是每次基本上开发结束后都会遇到或多或少的RTL问题...,以下聊些遇到的坑和踩坑记录

  1. 普通适配
    iOS 针对 RTL做过自动兼容的,前提是要使用对约束,不要用 frame,用 frame 苹果不会自动适配的!!!
    app 约束建议使用 Leading以及Trailing两个约束条件而不是Left和Right,这样苹果会针对约束自动进行左右转换.
  2. 针对 iOS9以上
    首先,建议根据语言判断一下,是否需要RTL
+ (BOOL)isRTLLayout{   //是否要重右到左布局    
   if([[iOSUtil getLanguage] isEqualToString:@"ar"] || [[iOSUtil getLanguage] isEqualToString:@"he"]){    
return YES;   
}else{    
return NO;  
 }
}

iOS9 后可以设置强制转换模式
OC: [UIView appearance].semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
swift: view.semanticContentAttribute = .forceRightToLeft
对应的 xib ,sb 设置为


屏幕快照 2019-02-28 上午11.00.37.png
  1. 针对于 collectionView 的国际化设置
    一般情况下,collectionView 是可以RTL 的,当然,一般情况并不是所有情况,因为真的去测试的时候,会发现可能同样的一套代码, 在 iOS12, iOS11,iOS10, iOS9上,居然可以有分别不同的表现形式... 😀 比如


    屏幕快照 2019-02-28 上午11.06.38.png

解决方案1.
修改CollectionViewFlowLayout
extension HorizontalCollectionViewFlowLayout { open override var flipsHorizontallyInOppositeLayoutDirection: Bool { return true }}
flipsHorizontallyInOppositeLayoutDirection是指开启 一个布尔值,指示水平坐标系是否在适当的时间自动翻转。 这个属性是默认关闭的 如果发生无法反转的话,我们需要这样打开
解决方案2. 重写 layout 判断单个 cell 的 x 位置进行反转

class HorizontalCollectionViewFlowLayout: UICollectionViewFlowLayout {
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributes_super : [UICollectionViewLayoutAttributes] = super.layoutAttributesForElements(in: rect) ?? [UICollectionViewLayoutAttributes]()
        let layoutAttributes:[UICollectionViewLayoutAttributes] = NSArray(array: layoutAttributes_super, copyItems:true)as! [UICollectionViewLayoutAttributes]
        var layoutAttributes_t : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()
        
        if PhoneUtil.isRTLLayout() {
            if let firstAttr = layoutAttributes.first,
               let lastAttr = layoutAttributes.last {
                if firstAttr.frame.origin.x >= lastAttr.frame.origin.x {
                    return layoutAttributes // 阿语下从右至左正常排列,直接返回
                }
            }
            let cellCount:Int = self.collectionView?.numberOfItems(inSection: 0) ?? 0
            var nowWidth:CGFloat = self.sectionInset.right
            
            for index in (0...cellCount).reversed() {
                if let currentAttr:UICollectionViewLayoutAttributes = layoutAttributes[safe:index] {
                 var nowFarme:CGRect = currentAttr.frame
                 nowFarme.origin.x = nowWidth
                 currentAttr.frame = nowFarme;
                 nowWidth += nowFarme.size.width + self.minimumInteritemSpacing
                 layoutAttributes_t.append(currentAttr)
                }
            }
            return layoutAttributes
        }
        return layoutAttributes
    }
}

  1. 关于 初始位置异常
collectionView.scrollToItem(at: IndexPath.init(row: 0, section: 0), at: .left, animated: false) 

滚动一下, 如果滚动后出现位置异常,可能需要 关闭一下 bounce

  1. UILabel 文字异常 Unicode字符串
    Unicode字符串由于阅读习惯的差异(阿拉伯语从右往左阅读,其他语言从左往右阅读),所以字符的排序是不一样的,普通语言左边是第一个字符,阿拉伯语右边是第一个字符。
    如果是单纯某种文字,不管是阿拉伯语还是英文,系统都是已经帮助我们做好适配了的。然而混排的情况下,系统的适配是有问题的。对于一个string,系统会用第一个字符来决定当前是LTR还是RTL。
    那么坑来了,假设有一个这样的字符串@"小明بدأ في متابعتك"(翻译过来为:小明关注了你),在阿拉伯语的情况下,由于阅读顺序是从右往左,我们希望他显示为@"بدأ في متابعتك小明"。然而按照系统的适配方案,是永远无法达到我们期望的。
    如果"小明"放前面,第一个字符是中文,系统识别为LTR,从左往右排序,显示为@"小明بدأ في متابعتك"。
    如果"小明"放后面,第一个字符是阿拉伯语,系统识别为RTL,从右往左排序,依然显示为@"小明بدأ في متابعتك"。
    为了适配这种情况,可以在字符串前面加一些不会显示的字符,强制将字符串变为LTR或者RTL。
    在字符串前面添加"\u202B"表示RTL,加"\u202A"LTR。为了统一适配刚刚的情况,我们hook了UILabel的setText:方法
BOOL isRTLString(NSString *string) {
if ([string hasPrefix:@"\u202B"] || [string hasPrefix:@"\u202A"]) {
return YES;
}
return NO;
}
NSString *RTLString(NSString *string) {
if (string.length == 0 || isRTLString(string)) {
return string;
}
if (isRTL()) {
string = [@"\u202B" stringByAppendingString:string];
} else {
string = [@"\u202A" stringByAppendingString:string];
}
return string;
}
@implementation UILabel (HTSRTL)
+ (void)load
{
RTLMethodSwizzling(self, @selector(setText:), @selector(rtl_setText:));
}
- (void)rtl_setText:(NSString *)text
{
[self rtl_setText:RTLString(text)];
}
@end

这种方法虽然能适配RTL,但是由于修改了原来字符串,虽然不会显示出来,但是毕竟多加了字符,会改变原来各个字符的range位置,当我们有特殊逻辑要使用各种range的时候,可能会有问题,对于这种特殊的情况,无法做到统一适配,所以只能具体情况具体处理
文章内容部分引用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容