Swift 3: NSAttributedString – localization/translation
- 11.01.2018
If you want to translate an attributed string with XCode, it is not easy.
Normal strings can be translated with NSLocalizedString(key: comment).
However, there is a problem with attributed strings. The attributes must be placed in the correct place in the string and this can vary greatly depending on the language.
One approach I found and which inspired me to my solution was the creation of an RTF (Rich Text Format) file.
The text/string has been designed and localized (in the utility area).
With the function NSAttributedString.init(url: options: documentAttributes) I tried to load the contents of the RTF file. Unfortunately I was not able to load the content, although the RTF file was inside the bundle.
Next I found out that it works with HTML files, too. In principle, I used the same scheme as with RTF files. And this time it worked.
However, I find it difficult to create a separate HTML file for each translation and since HTML is a markup language in contrast to RTF, the consequence was that I tried to extend the normal language files with HTML content and to gain the attributed string from it.
Here is an example:
"BUTTON_TERMS_OF_USE" = "Hello %1$@, by registering you accept our <u>Terms of use> </u>.".; |
For the translation I use a string extension myself:
extension String { var localized: String { return NSLocalizedString(self, comment: "") } } |
This can be used like this: “BUTTON_TERMS_OF_USE”.localized.
If you also have placeholders in the text, you can do this again with
of a string extension:
extension String { func formatted(_ arguments: CVarArg...) -> String { return String(format: self, locale: Locale.current, arguments: arguments) } } |
That would look like this now: “BUTTON_TERMS_OF_USE”.localized.formatted(“Tom”)
Now to the attributed string itself:
extension String { var attributed: NSAttributedString { do { return try NSAttributedString.init( data: self.data(using: String.Encoding.utf8)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil ) } catch { return NSAttributedString.init(string: self) } } } |
To translate it correctly using HTML string:
“BUTTON_TERMS_OF_USE”.localized.formatted(“Tom”).attributed
If you now have to translate strings more often and don’t want to use the storyboard’s own translation or you use attributed strings, then you can extend view classes:
class LocalizedButton : UIButton { @IBInspectable var localizedTitle : String = "" { didSet { self.setTitle(localizedTitle.localized, for: .normal) } } @IBInspectable var attributedTitle : String = "" { didSet { self.setAttributedTitle(attributedTitle.localized.attributed, for: .normal) } } } |
Now you can use the utility editor to enter the translation ID. If there are placeholders in the text, the translation must take place in the swiftcode itself.