phrase / ios-sdk

Phrase Over the Air iOS SDK
https://phrase.com
Other
14 stars 3 forks source link

Planning for OTA SwiftUI support? #44

Closed bill-florio closed 1 year ago

bill-florio commented 2 years ago

Hi! I would like to ask it there any planning to support SwiftUI? Currently I have a workaround like this:

    let text: LocalizedStringKey?
    let string: String?

   @ViewBuilder
     private var sharedText: some View {
         if let text = text {
             Text(text)
         } else if let string = string {
             Text(string)
         } else {
             Text("")
         }
     }

But my App have hundreds of Texts and Buttons to change and it is not practical.

winkelsdorf commented 2 years ago

Hello @bill-florio,

thank you for your question about using the Phrase iOS SDK together with SwiftUI.

I think I need to elaborate a bit more:

We can provide the translation for the Main Bundle in the SDK as we change the Main Bundle. This works because Bundle inherits from NSObject and the methods are virtually accessible. Keyword Dynamic Dispatch.

Apple has decided to use structs for SwiftUI (@frozen) that do not offer this possibility. This also applies here to LocalizedStringKey, Text(:) and Label(:) etc. - expect for experimental compiler flags which are not meant for productive use. I know that iOS 16 will introduce LocalizedStringResource but due to the lack of documentation, I am unsure if this is going to help us here.

So the way to use LocalizedStringKey or another SwiftUI constructor directly and without further work on the developer side is unfortunately not open to us or any other developer.

That said, let's focus on what is currently possible.

Your code example seems to provide some fallback logic?

Depending if you are using the aforementioned Bundle injection there are several ways to translate inside of SwiftUI after you successfully downloaded the translation.

E.g.

struct ContentView: View {

    var body: some View {
        VStack {
            Text(Phrase.shared.localizedString(forKey: "layouts.application.about", value: nil, table: nil))
                .padding()

            Text(Bundle.main.localizedString(forKey: "layouts.application.about", value: nil, table: nil))
                .padding()

            Text(NSLocalizedString("layouts.application.about", comment: ""))
                .padding()
        }
    }
}

All of them basically do the same, as they use the Main Bundle (if the proxy is enabled, otherwise only the first method will work).

A suggestion to reduce your boilerplate code: You might consider using a String extension which invokes the method for you, something like:

extension String {

    var localized: String {
        return NSLocalizedString(self, comment: "")
    }

}

This allows you to improve readability on the call site to something like Text("layouts.application.about".localized).

In many projects I saw different approaches for collecting translation keys, from enum to ViewModel Properties. That's a matter of choice and your current project architecture.

Working directly using the new LocalizedStringKeys is sadly not supported, as Apple seems to not be using any public API method at all.

Hope this help!

bill-florio commented 2 years ago

Thanks for your detailed answer. There will be quite a lots of Text/Button and etc in my project already using LocalizedKey.

winkelsdorf commented 2 years ago

You are welcome! I can understand that this is not a very satisfactory answer, unfortunately. If this changes, we will of course be happy to inform you.