Translate attributed string

BennoDual picture BennoDual · Apr 4, 2014 · Viewed 7.9k times · Source

I have a UILabel with an attributed string. Here is a printscreen of it:

enter image description here

Now, I have to translate this attributed string to english and italian. I am searching for a way to do this. Can I build this attributed string in code part by part? I have only found a solution where the whole string is set and then the attributes are set by range. But when I translate the string, I don't know the range anymore, because the words are longer or smaller.

Answer

alex-i picture alex-i · Apr 29, 2015

Another option is to create localized .rtf files from which to create NSAttributedStrings:

NSAttributedString *attributedStr = [[NSAttributedString alloc] initWithData:data options:@{NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType} documentAttributes:nil error:nil];

To use dynamic formatting (e.g. set colors, fonts specific to some app settings), I'm using some html-like formatting, with 1-char tags for which I afterwards apply the format from inside the app.

// NSMutableAttributedString category method
/**
 * Updates the attributes of xml elements (where the xml tags are formed of 1 single char) with the passed attributes from param `tagsAttributes`
 * Current version doesn't support recursive tags (tags in tags)
 * All tags of form '<char>' or '</char>' will be used as formatting (the resulting string should not be expected to have any tags of this form)
 * @param tagsAttributes - list of attribute dictionaries, where the key is the tag name */
-(void)formatCharXMLTagsUsingAttributes:(NSDictionary *)tagsAttributes {
    int strippedLength = 0;

    NSString *str = [[self string] copy];
    NSScanner *scanner = [NSScanner scannerWithString:str];
    while (![scanner isAtEnd]) {
        NSString *tag = nil;
        do {
            [scanner scanUpToString:@"<" intoString:nil];
            [scanner scanString:@"<" intoString:nil];
            if (scanner.scanLocation + 2 < [str length] && [str characterAtIndex:scanner.scanLocation + 1] == '>') {
                [scanner scanUpToString:@">" intoString:&tag];
                [scanner scanString:@">" intoString:nil];
            }
        } while (!tag && ![scanner isAtEnd]);

        if ([scanner isAtEnd]) {
            break;
        }

        NSString *endTag = [NSString stringWithFormat:@"</%@>", tag];
        NSString *tmpString;
        [scanner scanUpToString:endTag intoString:&tmpString];
        [scanner scanString:endTag intoString:nil];
        NSRange range;
        strippedLength += 7; // start tag + end tag length
        range.location = scanner.scanLocation - [tmpString length] - strippedLength;
        range.length = [tmpString length] + 7;
        [self replaceCharactersInRange:range withString:tmpString];
        range.length -= 7;
        [self addAttributes:tagsAttributes[tag] range:range];
    }
}

The method could afterwards be used like this:

NSDictionary* highlightAttributes = @{NSForegroundColorAttributeName: [UIColor blueColor],
                                 NSFontAttributeName: [UIFont boldSystemFontOfSize:16]};
NSDictionary *xmlTagsAttributes = @{@"b": highlightAttributes};
[attrStr formatCharXMLTagsUsingAttributes:xmlTagsAttributes];

Where attrStr may be @"Press <b>Next</b> button to ...".