Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RTL & LTR (bidirectional) in UITextView

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?

like image 333
konradowy Avatar asked Jul 01 '26 14:07

konradowy


1 Answers

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.

like image 179
Axel Guilmin Avatar answered Jul 04 '26 04:07

Axel Guilmin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!