Creating Attributed Strings with Markdown
You can create an attributed string by passing a standard String or Data instance that contains Markdown to initializers like init(markdown:options:baseURL:). The attributed string creates attributes by parsing the markup in the string.
do {
let thankYouString = try AttributedString(
markdown:"**Thank you!** Please visit our [website](https://example.com)")
} catch {
print("Couldn't parse: \(error)")
}
Localized strings that you load from strings files with initializers like init(localized:options:table:bundle:locale:comment:) can also contain Markdown to add styling. In addition, these localized attributed string initializers can apply the replacementIndex attribute, which allows you to determine the range of replacement strings, whose order may vary between languages.
Further Explanation
Why not to use the LocalizedStringKey init
The behavior where LocalizedStringKey effectively works as markdown is undocumented, and so we probably should not use LocalizedStringKey inits as this is not a guaranteed pattern. Future updates might change this, and so it's better to use the more appropriate component AttributedString.
You can check apple's documentation on this to see for yourself, but LocalizedStringKey documentation does not mention markdown.
Basically, we probably shouldn't do this:
Text(.init(dynamicString))
Text(LocalizedStringKey(markdownStr))
Why using AttributedString is the right answer
As a few people mentioned, using AttributedString(markdown: dynamicString) for dynamic strings is the right answer.
Using Text with a static string (i.e. Text("[Apple Link](http://www.apple.com)")) will work fine, but dynamic strings need to be typed to properly parse as markdown. @kgaidis explains this well.
Important Detail To Add
try! AttributedString(markdown: dynamicString) will strip the string of \n characters. In order to preserve these characters, you can pass options in the init like so:
try! AttributedString(
markdown: dynamicString,
options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace)
// \n will be stripped unless this option is added.
)