2

I'm working on a notification page where inputs are mostly come from a JSON file and I need to combine them with localized strings. This is how it should look:

Sketch design

As can be predicted colored parts come from the JSON file and rest of it comes from Localizable.strings. This is what comes from Localizable file:

"%@ has joined %@"

If I use String(format: String, [...]) I have a plain black text and I cant specify the parts needs to be colored.

I need the same feature for NSAttributedString but it doesn't have this method.

So how can I format attributed strings?

3
  • It depends on what kind of effects you want to apply, but the easiest way is is to use HTML tags on the localizaed value. Commented Sep 26, 2017 at 18:34
  • @Larme I want to change color and make bold the formatted parts, check the example screenshot. Does UILabel apply HTML tags automatically? Commented Sep 26, 2017 at 18:42
  • 1
    I checked the sample, but you may want more effects. You can init NSAttributedString from HTML Text (all tags are not translated, but just the bold/color are managed): stackoverflow.com/questions/39248092/… So adding <b> and others should do the trick. Commented Sep 26, 2017 at 18:43

3 Answers 3

3

Check following example:

var myMutableString = NSMutableAttributedString()

myMutableString = NSMutableAttributedString(string: "Your full label textString")

myMutableString.setAttributes([NSFontAttributeName : UIFont(name: "HelveticaNeue-Light", size: CGFloat(17.0))!
        , NSForegroundColorAttributeName : UIColor(red: 232 / 255.0, green: 117 / 255.0, blue: 40 / 255.0, alpha: 1.0)], range: NSRange(location:12,length:8)) // What ever range you want to give

yourLabel.attributedText = myMutableString

Or another way:

To change the colour of a length of text you need to know the start and end index of the coloured-to-be characters in the string e.g.

var main_string = "Hello World"
var string_to_color = "World"

var range = (main_string as NSString).rangeOfString(string_to_color)

Then you convert to attributed string and use 'add attribute' with NSForegroundColorAttributeName:

var attributedString = NSMutableAttributedString(string:main_string)
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor() , range: range)
Sign up to request clarification or add additional context in comments.

3 Comments

rangeOfString() returns the first range only. If both values of the placeholders (in "%@ has joined %@") are the same, it won't work.
rangeOfString have been renamed to range(of: String) since Swift 3
There is also an issue if you use "$1, $2", to place items (not all languages keep the same order). That's why on my project I used HTML Tags instead. But that's more for information than anything. Your solution could work.
1

My two localised strings:

"welcome message" = "%@ has joined %@";
"welcome message" = "انضم %@ إلى %@";

Results
enter image description here

enter image description here


extension String {

 func localisedAttributedString(_ replacements: CVarArg..., attributes: [NSAttributedString.Key : Any], replacementAttributes: [[NSAttributedString.Key : Any]?] ) -> NSAttributedString {
        

        let message = String.init(format: NSLocalizedString(self, comment: ""), arguments: replacements)
        
        let attributedString =  NSMutableAttributedString(string: message, attributes: attributes)
       
        
        for (i, replacement) in replacements.enumerated() {
            
            if let att = replacementAttributes[i] {
                
                let range = (attributedString.string.range(of: "\(replacement)".localized)?.nsRange(in: attributedString.string)) ?? NSRange(location: 0, length: 0)
                attributedString.addAttributes(att as [NSAttributedString.Key : Any], range: range)
            }
            
        }
        
        return attributedString
    }

}

HOW TO USE

//General attr: Applied to the entire string
let generalAttributes = [NSAttributedString.Key.font:  UIFont.getFont(.regular, size: 20)]


//Additional attrs applied to the replacement / dynamic bits. You can pass nil too
let nameAttributes = [ NSAttributedString.Key.backgroundColor: UIColor.red]
let companyAttributes = [ NSAttributedString.Key.foregroundColor: UIColor.blue]
        
myLabel.attributedText = "welcome message".localisedAttributedString("adam".localized, "space".localized, attributes: generalAttributes, replacementAttributes: [nameAttributes, companyAttributes] )

Comments

0

Try the below code and update your logic accordingly.

    let localizableStr = "%@ has joined %@"
    let localisedStr = NSLocalizedString(localizableStr, comment: "")

    let components = localizableStr.components(separatedBy: "%@")

    let formatterStr = components.count > 2 ? components[1] : "has joined"

    let evaluatedStr = NSString(format: localisedStr as NSString, "Rishi ", "Stack OVerflow")

    let attributedStr = NSMutableAttributedString(string: evaluatedStr as String)
    attributedStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.brown, range: NSMakeRange(0, attributedStr.length))

    let formatterStrRange = evaluatedStr.range(of: formatterStr, options: .caseInsensitive)
    attributedStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.black, range: formatterStrRange)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.