Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A lighter way of discovering text writing direction

Tags:

text

ios

arabic

I want to determine the writing direction of a string so that I can render Right-to-Left languages such as Arabic correctly in a CALayer.

so I have this method

+(UITextAlignment)alignmentForString:(NSString *)astring
{
    UITextView *text = [[UITextView alloc] initWithFrame:CGRectZero];
    text.text = astring;

    if ([text baseWritingDirectionForPosition:[text beginningOfDocument] inDirection:UITextStorageDirectionForward] == UITextWritingDirectionRightToLeft) {
        return UITextAlignmentRight;
    }

    return UITextAlignmentLeft;

}

Works fine but feels a little heavy just for the purpose of discovering which way to align my text especially as its been called in drawInContext (although relatively infrequently).

Is there a lighter way of determining the writing direction for a given string or should I just stick with this under the basis of premature optimisation. And its got to be iOS 5 friendly.

like image 338
Warren Burton Avatar asked Apr 29 '13 22:04

Warren Burton


3 Answers

The code in the question although functional is brutally expensive. Run it through a profiler and you will find that it spends close to 80% of the time in UITextView.setText when used in the drawInContext method for a layer.

Most of the answer is here in Detect Language of NSString

a better form is thus...

+(UITextAlignment)alignmentForString:(NSString *)astring
{

    if (astring.length) {

        NSArray *rightLeftLanguages = @[@"ar",@"he"];

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

        if ([rightLeftLanguages containsObject:lang]) {

            return UITextAlignmentRight;

        }
    }

    return UITextAlignmentLeft;

}

As Arabic and Hebrew are the only Right-to-Left languages detectable by CFStringTokenizerCopyBestStringLanguage and should also cover Persian, Urdu and Yiddish though I havent tested that.

see also http://en.wikipedia.org/wiki/Right-to-left

like image 142
Warren Burton Avatar answered Nov 20 '22 13:11

Warren Burton


Swift

For me the .natural textAlignment of UITextView did not work unless I edited the text and line from start.

Based on the great answer to this question and the comment below it.

let text = "..."
let lang = CFStringTokenizerCopyBestStringLanguage(text as CFString, CFRange(location: 0, length: text.characters.count))

if let lang = lang {
    let direction = NSLocale.characterDirection(forLanguage: lang as String)

    if direction == .rightToLeft {
        textView.textAlignment = .right
    }
    else {
        textView.textAlignment = .left
    }
}
like image 37
Ali Momen Sani Avatar answered Nov 20 '22 14:11

Ali Momen Sani


Since UITextAlignment is deprecated, here's an NSString category with NSWritingDirection:

- (NSWritingDirection)alignment{
    if (self.length) {
        NSArray *rightLeftLanguages = @[@"ar",@"he"];
        NSString *lang = CFBridgingRelease(CFStringTokenizerCopyBestStringLanguage((CFStringRef)self,CFRangeMake(0,self.length)));
        if ([rightLeftLanguages containsObject:lang]) {
            return NSWritingDirectionRightToLeft;
        }
    }
    return NSWritingDirectionLeftToRight;

}

like image 2
arsenius Avatar answered Nov 20 '22 14:11

arsenius