3
votes

I'm trying to save the content of a UITextView which contains lines of text formatted both RTL and LTR. The problem is that UITextView checks only the first character to format direction. Let's assume I'm in "edit" mode and write this text (__ means spaces):

text1_______________________________________
____________________________________________אקסא      
text2_______________________________________

and after saving we lost RTL for אקסא. Now I'd like to edit this text once again which now looks like:

text1_______________________________________
אקסא      
text2_______________________________________

I'm not able to mix \u200F with \u200E directional characters in one UITextView. How to manage this and save correctly bidirectional text from UITextView?

1

1 Answers

1
votes

Here is a quick proof of concept using NSAttributedString :
- Split the text in paragraphs
- For each paragraph, detect the main language
- Create an attributed text with the correct alignmenent for the corresponding range

// In a subclass of `UITextView`

+ (UITextAlignment)alignmentForString:(NSString *)astring {
    NSArray *rightToLeftLanguages = @[@"ar",@"fa",@"he",@"ur",@"ps",@"sd",@"arc",@"bcc",@"bqi",@"ckb",@"dv",@"glk",@"ku",@"pnb",@"mzn"];

    NSString *lang = CFBridgingRelease(CFStringTokenizerCopyBestStringLanguage((CFStringRef)astring,CFRangeMake(0,[astring length])));

    if (astring.length) {
        if ([rightToLeftLanguages containsObject:lang]) {
            return NSTextAlignmentRight;
        }
    }

    return NSTextAlignmentLeft;
}

- (void)setText:(NSString *)str { // Override
    [super setText:str];

    // Split in paragraph
    NSArray *paragraphs = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];

    // Attributed string for the whole string
    NSMutableAttributedString *attribString = [[NSMutableAttributedString alloc]initWithString:self.text];

    NSUInteger loc = 0;
    for(NSString *paragraph in paragraphs) {

        // Find the correct alignment for this paragraph
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
        [paragraphStyle setAlignment:[WGTextView alignmentForString:paragraph]];

        // Find its corresponding range in the string
        NSRange range = NSMakeRange(loc, [paragraph length]);

        // Add it to the attributed string
        [attribString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range];

        loc += [paragraph length];
    }

    [super setAttributedText:attribString];
}

Also, I recommend reading the Unicode BiDi Algorithm to manage more complex use cases.