1

I want to give a label a text that have multiple fonts in it. This can be accomplished by creating a NSMutableAttributedString. However, I am not sure how I format the following case:

String(format: NSLocalizedString("%@ has replied in '%@'", comment: ""), username, conversationTitle)

I want to give the username and conversation title a separate font. I want to do this in the less buggiest way. What I mean by this:

  • I do not want to find out the username later on in the string by using a substring. This is causing issues when the conversationTitle is the same as the username, or the conversationTitle is in the username etc. etc..
  • I do not want to build up the string, as seen here: https://stackoverflow.com/a/37992022/7715250. This is just bad when creating NSLocalizedString's, I think the translators are going to have a bad time when string are created like that.

Questions like: Making text bold using attributed string in swift, Are there approaches for using attributed strings in combination with localization? and others are mostly string literals without NSLocalizedString or NSLocalizedString with parameters.

J. Doe
  • 12,159
  • 9
  • 60
  • 114
  • I'll use the example of bold, because it's simpler to explain. Use tags, like html: `` or other (markdown, custom, etc.). I also suggest to not have `%@ has replied in '%@'` as a key, but instead: `REPLIED_IN = %1$@ has replied in %2$@;`, because in English it might be in this order, but not necessarly in other languages. You then use `NSAttributedString` to read and parse that string with the tags. – Larme Jan 27 '19 at 12:55

1 Answers1

1

First, you should have in your .strings a much more generic and readble key, something like:

"_REPLIED_IN_" = "%@ has replied in %@";

Do not confuse keys and values as you seem to do in your example. Also, it's easier later to see when there is an hardcoded string not localized in your code.

Now, there is an issue, because in English, it might be in that order, but not necessarily in other languages.

So instead:

"_REPLIED_IN_" = "%1$@ has replied in %$2@";

Now, I'll use the bold sample, because it's easier, but what you could do is use some custom tags to tell you that it needs to be bold, like HTML, MarkDown, etc.

In HTML:

"_REPLIED_IN_" = "<b>%1$@</b> has replied in <b>%$2@</b>";

You need to parse it into a NSAttributedString:

let translation = String(format: NSLocalizedString(format: "_REPLIED_IN_", comment: nil), userName, conversationTitle)
let attributedText = NSAttributedString.someMethodThatParseYourTags(translation)

It's up to you to choose the easiest tag format), according to your needs: easy to understand by translators, and easy to parse (CocoaTouch already has a HTML parser, etc.).

Larme
  • 24,190
  • 6
  • 51
  • 81
  • While not related to the OP's actual question, a lot of people are likely to disagree with your opening statement about the key. Apple's own documentation shows the common usage of `NSLocalizedString` having the key as the actual string in the app's primary language. It makes the code a lot easier to read. In your example, the code only has the key so anyone reading the code has no idea what the string is. More importantly, using `genstrings` on your proposed code results in the strings file having `""_REPLIED_IN_" = ""_REPLIED_IN_";`. That makes it impossible to provide proper translations. – rmaddy Jan 27 '19 at 15:20
  • I'll add, that giving a proper name with context is a good use, but I was missing context. If I remember, I got once an issue with an Apple App, and it was not translated giving: "AppName.Screen.Something.Else". I don't use `genstrings`, so I don't know on that part. – Larme Jan 27 '19 at 18:13