Search code examples
swiftswiftuilocalizationstring-catalog

LocalizedStringResource and LocalizedStringKey, which one should I use for custom SwiftUI View?


Recently I want to add other language support to my app. In WWDC23: Discover String Catalogs, Apple recommended using LocalizedStringResource to represent and pass around localizable strings. But LocalizedStringKey is widely used in SwiftUI. For some views, there goes the following error if I directly give LocalizedStringResource.

struct MyView: View {
    var title: LocalizedStringResource
    
    var body: some View {
        VStack {
            Text(title)
            Button(title) { }    // Error
                .help(title)     // Error
        }
    }
}
Initializer 'init(_:action:)' requires that 'LocalizedStringResource' conform to 'StringProtocol'

I know I can solve it naively by String(localized:), but it's wired because of the extra code.

Button(String(localized: title)) { }
    .help(String(localized: title))

Should I always do the conversion manually? Is there a better way?

Should I use LocalizedStringKey to pass the value? But Apple recommends LocalizedStringResource. What's the trade off?


Solution

  • LocalizedStringResource is more flexible, you can specify the table name and bundle of the string resource, and even a default value. Quote from the WWDC,

    LocalizedStringResource is the recommended type for representing and passing around localizable strings. It not only supports initialization using a string literal, but can also be provided with a comment, table name, or even a default value that's different from the string key.

    LocalizedStringKey is just the key part of a string resource. There is no table name or bundle associated with it. If you do want to specify the table name and bundle for a LocalizedStringKey, you need to pass those to the Text initialiser that takes those parameters.

    So if you are just writing your own app and you are only ever going to have one table and/or bundle, then using LocalizedStringKey is not really that different.

    For SwiftUI, you should not use String(localized:) to convert a LocalizedStringResource. It does not respect SwiftUI's locale environment value, and Text would not display the string as markdown.

    You should just create a Text out of the LocalizedStringResource:

    struct MyView: View {
        var title: LocalizedStringResource
        
        var body: some View {
            VStack {
                Text(title)
                Button {
                    
                } label: {
                    Text(title)
                }
                .help(Text(title))
            }
        }
    }