Custom SwiftUI view with localization support similar to the SwiftUI Text view

I'd like to create a custom SwiftUI view that supports extracting its title string along with the localization comment into a string catalog. Like the SwiftUI Text view does. I have a view with an init similar to the localization init of Text. But it looks like I'm missing something obvious.

Two questions:

  1. How do I get the actual localized string using a LocalizedStringKey?

  2. Why is the comment not picked up and added to the string catalog?

// 1) My custom view with localization support:
// I'd like to build a view which supports extraction of strings into a string catalog like the SwiftUI `Text` view does.
struct MyLocalizableView: View {
private var localizedTitle: String
init (_ titleKey: LocalizedStringKey, table: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil) {
// PROBLEM I:
// The following line does not work. I is a fantasy call. It depicts my idea how I would expect it to work.
// My question is: How do I get the actual localized string using a `LocalizedStringKey`?
self.localizedTitle = String(localizedKey: titleKey, table: table, bundle: bundle, comment: comment)
}
var body: some View {
// At this point I want to do an operation on an actual string and not on a LocalizedStringKey. So I can't just pass the LocalizedStringKey value along.
// Do `isEmpty` or some other operation on an actual string:
if localizedTitle.isEmpty {
Text("Show one thing")
} else {
Text("Show another thing")
Text("** \(localizedTitle) **")
}
}
}
// 2) The call site:
struct ContentView: View {
var body: some View {
// PROBLEM II: "My title key" is picked up and is extracted into the string catalog of the app. But the comment is NOT!
MyLocalizableView("My title key", comment: "The title of the view...")
.padding()
}
}
Answered by Developer Tools Engineer in 828908022

Hi there! I'll answer the second question first.

The comment is not picked up because:

  1. the string extraction process doesn't look at plain String parameters, unless they are declared via String(localized:)
  2. the comment is in a separate parameter from the titleKey (i.e. from your LocalizedStringKey), so the string extraction process doesn't know to associate the two

You can associate the key and the comment by using a LocalizedStringResource instead, which has the bundle, table, and comment baked into the type. The string extraction process looks at these and knows to associate the comments with the keys. For example:

struct MyLocalizableView: View {
let localizedTitle: LocalizedStringResource
var body: some View {
Text(localizedTitle)
}
}
struct ContentView: View {
var body: some View {
MyLocalizableView(localizedTitle: LocalizedStringResource("My title key", comment: "My comment"))
}
}

You can read up on LocalizedStringResource on its documentation page.

Another alternative to this, of course, would be to add the comments manually inside of your String Catalog (or .strings and .stringsdict files), instead of in code.

As for your first question: you can evaluate the contents of a LocalizedStringResource by using the String(localized:) initializer, like so:

struct MyLocalizableView: View {
let localizedTitle: LocalizedStringResource
var body: some View {
if String(localized: localizedTitle).isEmpty {
Text("Show one thing")
} else {
Text("Show another thing")
Text("** \(localizedTitle) **")
}
}
}

Although, depending on your situation, you may want to instead consider making your localizedTitle a LocalizedStringResource? instead of a LocalizedStringResource, and checking to see if the localizedTitle is nil.

Accepted Answer

Hi there! I'll answer the second question first.

The comment is not picked up because:

  1. the string extraction process doesn't look at plain String parameters, unless they are declared via String(localized:)
  2. the comment is in a separate parameter from the titleKey (i.e. from your LocalizedStringKey), so the string extraction process doesn't know to associate the two

You can associate the key and the comment by using a LocalizedStringResource instead, which has the bundle, table, and comment baked into the type. The string extraction process looks at these and knows to associate the comments with the keys. For example:

struct MyLocalizableView: View {
let localizedTitle: LocalizedStringResource
var body: some View {
Text(localizedTitle)
}
}
struct ContentView: View {
var body: some View {
MyLocalizableView(localizedTitle: LocalizedStringResource("My title key", comment: "My comment"))
}
}

You can read up on LocalizedStringResource on its documentation page.

Another alternative to this, of course, would be to add the comments manually inside of your String Catalog (or .strings and .stringsdict files), instead of in code.

As for your first question: you can evaluate the contents of a LocalizedStringResource by using the String(localized:) initializer, like so:

struct MyLocalizableView: View {
let localizedTitle: LocalizedStringResource
var body: some View {
if String(localized: localizedTitle).isEmpty {
Text("Show one thing")
} else {
Text("Show another thing")
Text("** \(localizedTitle) **")
}
}
}

Although, depending on your situation, you may want to instead consider making your localizedTitle a LocalizedStringResource? instead of a LocalizedStringResource, and checking to see if the localizedTitle is nil.

Custom SwiftUI view with localization support similar to the SwiftUI Text view
 
 
Q