swiftuilocalestring-catalog

SwiftUI update LocalizedStringResource interpolated value after change of environment(\.locale


I'm trying to change a locale on a fly, but it doesn't work for interpolated strings:

//this struct is mandatory
struct Constants {
    static let download = LocalizedStringResource("Download", table: "General")
    static let items = LocalizedStringResource("%lld item", table: "General")
}

struct ContentView: View {
    @State private var language: String = "uk"

    var body: some View {
        ZStack {
            Rectangle().foregroundStyle(.white)
            VStack {

                Text(Constants.download)
                Text(String(format: String(localized:Constants.items), 13))
                
            }
            .padding()
        }
        .onTapGesture {
            language = (language == "en") ? "uk" : "en"
        }
        .environment(\.locale, .init(identifier: language))
        .id(language) //try to force reload UI..
    }
}

Result:

enter image description here

Also, please note, if you change a scheme language parameter:

enter image description here

Then it will load string and interpolation will work for selected language:

enter image description here

But after that, still, changing a locale doesn't update language value with interpolation.

Looks like a SwiftUI internal logic problem? Or is there maybe could be some workaround for this?

My General.xcstrings translated:

enter image description here


Solution

  • This happens because String(localized:) doesn't care about SwiftUI's environment. It only looks at the locale of the LocalizedStringResource, which will be the system locale.

    Rather than static lets in Constants, you should make the interpolated strings functions, so that you can format them in place:

    static func items(_ n: Int) -> LocalizedStringResource {
        LocalizedStringResource("\(n) Items", table: "General")
    }
    

    Usage:

    Text(Constants.items(13))
    

    This work because you are directly giving the resource to Text, and Text can localise it using SwiftUI's environment.

    I'm not sure why you are using LocalizedStringResource instead of LocalizedStringKey. Unless you do need specific functionalities from LocalizedStringResource, use LocalizedStringKey instead.