phrase / ios-sdk

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

Two languages being returned when using "localeOverride" #42

Closed mihai-honceriu closed 1 year ago

mihai-honceriu commented 2 years ago

Short summary of our setup:

To reproduce the issue, I have to: 1) Set language in iOS Settings -> Our app to anything other than "English" 2) Set in-app language (localeOverride) to "en" Result is: most of the strings are in english, but some of them will use the language in iOS Settings instead of the localeOverride.

I am properly settings the localeOverride and updating the translations using updateTranslations and then reloading the UI, but i cannot get it to work.

A suggestion i got from Phrase support was to use NSLocalizedString("", comment: "") instead of NSLocalizedString("", bundle: hostingBundle, comment: "")

but unfortunately this would not be a solution for us as we cannot and would not like to change the Rswift code.

Even so, I did a test using a breakpoint and using the method without the bundle would still return the translation in the wrong language, so i believe it would actually not solve the issue? I attached a screenshot.

Screenshot 2022-04-28 at 16 33 47

We really want to release our in-app language picker to synchronize the language with the other platforms and our backend, but this issue is really blocking us! We have been on with support for like a month now with no solution. Please let me know if this is a known issue or if you need more details.

theSoenke commented 2 years ago

Hi @mihai-honceriu, you are already using version 4.0.1 correct? @winkelsdorf Could you maybe take a look at what might be the cause for the reported issue here?

winkelsdorf commented 2 years ago

Hi @mihai-honceriu. Thank you for your valuable feedback regarding using R.Swift together with the Phrase SDK.

As @theSoenke said, could you please confirm the version of the Phrase SDK you are using? Best together with your R.Swift Version, the Xcode Version (which gives us a hint about the used Swift Version) and the minimum supported target iOS Version?

I think we need to separate this into two parts.

1) First we have R.Swift with multiple bundles from what I see. Multiple bundles is something we currently don't support (see https://github.com/phrase/ios-sdk/issues/25 for a similar request).

This is due to the fact that our SDK cannot swizzle different bundles safely without knowledge about them and their implementation. Even without swizzling using Phrase.shared.localizedString(:) to translate, it would need a major logic change in the SDK and the OTA to support different bundles (beside other issues, translations would get merged for different bundles).

2) R.Swift uses NSLocalizedString() which is only supported for the main bundle from our SDK. I think this interferes here. From what I read a known issue, but there may be workaround. See https://github.com/mac-cain13/R.swift/issues/466, https://github.com/mac-cain13/R.swift/issues/219 and especially the merged PR https://github.com/mac-cain13/R.swift/pull/553.

That said, I think we should investigate your issue and try to find a working solution? @theSoenke

mihai-honceriu commented 2 years ago

Hey and thank you for the swift answer!

I am using: Phrase: 4.0.1-rc.1, Rswift: 6.1.0, Xcode: 13.3, Swift 5, Min iOS 13

From what I understand from https://github.com/mac-cain13/R.swift/pull/553 , using the preferredLanguages of R.swift would actually bring us to the issue number 1. Depending on the preferredLanguage passed to R, it will use a bundle other than the main bundle. I have tried using the preferredLanguage of R.swift and the OTA would simply not work, the app would use only the local strings files.

When not passing a preferredLanguage, R.swift uses the hostingBundle (as you can see in the generated code above). I made a new screenshot printing the hostingBundle which I believe is always the main bundle:

fileprivate static let hostingBundle = Bundle(for: R.Class.self)

Screenshot 2022-05-05 at 11 13 35

Initially I believed it was working. I had my iOS set to "English" so the app was also automatically set to "English". This way, changing the language using Phrase's localeOverride worked without problems: it would fully use whatever language i select in-app after doing a Phrase updateTranslations and reloading the UI.

What might be interesting to notice is that issues appear only when I select:

e.g: iOS Settings: German, localeOverride: English. Result: Some translations are in german, while others in english iOS Settings: French, localeOverride: English. Result: Some translations are in french (always the same strings as above, so somehow it's not random strings, always the same ones) iOS Settings: Italian, localeOverride: English: Result: Some translations are in italian (same ones as above) etc.

but for iOS Settings: English, localeOverride: Any language : All strings in "Any language" iOS Settings: Any language, localeOverride: Any language other than English : All strings in localeOverride language

theSoenke commented 2 years ago

Thanks @winkelsdorf. I would say we should then investigate how we could handle this. Would be great if you could look into this

mihai-honceriu commented 2 years ago

Hello, is there any update on this issue? We are still not being able to deliver our in-app language change and cross-platform language sync because of it.

winkelsdorf commented 2 years ago

Hello @mihai-honceriu,

sorry for the late reply, this is very tricky to reproduce. Thank you for your valuable and informative feedback. From my initial tests R.swift works fine, even in a mixed language setup. I used the 4.0.1-rc.1 for this:

image

I agree that hostingBundle should be the main bundle here, as long as R.generated.swift is included in the main project (and not in any linked framework or Pods if you use CocoaPods).

Also you are right about not providing a preferredLanguage to R.swift helper methods. If you do, as you correctly see in R.generated.swift it will try to run its own language logic. We don't want that here, we want that line to be called to have the Phrase SDK internally take care of:

      static func layoutsApplicationAbout(preferredLanguages: [String]? = nil) -> String {
        guard let preferredLanguages = preferredLanguages else {
          return NSLocalizedString("layouts.application.about", bundle: hostingBundle, comment: "") // this seems right
        }

It seems to me that the overhead with the translation logic of R.swift is also somewhat problematic here, as there can be many kinds of conflicts as a result - as both try to take care of localization. Maybe there is a way to configure the code generator to only call NSLocalizedString("xyz", bundle: hostingBundle, comment: "")? But that's something out of scope here.

That said, I think we have to look at other sources of this issue. My educated guess is that some keys are probably missing somewhere else. If you don't know how to find the exact simulator directories, you could use a tool like SimSim (https://github.com/dsmelov/simsim) to find the data directory of your App in the iOS Simulator. If you have a look into Library\Application Support\com.phrase.phraseSDK\Translations you should be able to find the Localizable.strings for your selected language.

Can you please double check that the values for the mentioned keys are correct in your downloaded files? And that everything is included? E.g. you should find all german translations in a subfolder like de.lproj and all english translations in en.lproj. If your OTA distribution is correctly setup, it should have the same amount of lines.

Depending on your fallback language in the OTA settings you might receive wrong translations.

@theSoenke It might be helpful to verify that the backend configuration is correct here. I am currently unable to reproduce this for our iOS SDK.

In parallel let me try to reproduce your exact environment (device language other than english) and give you some feedback on this asap.

winkelsdorf commented 2 years ago

I tried your failing setup, e.g. iOS Settings: German, localeOverride: English. All of the delivered keys were correctly translated using R.swift to my set localeOverride.

See this example:

image

As a general setup suggestion can you please check that your App supports the needed languages from the iOS side? Like this under Localizations:

image

From what I can tell now, after evaluating usage with R.swift, I think it's a problem with the OTA setup, not the iOS SDK. I am very curious what your manual check of the downloaded files will return.

mihai-honceriu commented 2 years ago

Hello @winkelsdorf and thank you very much for your look into this.

As we have moved our priority on other topics for the moment, please excuse my very delayed response.

I understand the overhead that R.generated.swift can bring, but looking at the issue, it seems to me that it might not be related to it.

I still could not get the hang of it. I have a branch with the setup done in such a way that the problem reproduces 100% of the times,

I have followed your advice and checked the Localizable.strings in the simulator files and everything seems to be right. The "en" file is present there with all the correct strings. There are some other things that I noticed, I try to attach helpful screenshots:

Here is a screenshot with an attempt to demonstrate what I see Screenshot 2022-07-05 at 14 42 03

Screenshot 2022-07-05 at 14 48 42

Here is a screenshot with local translation files in "de" and "en" for one of the strings that shows up wrong Screenshot 2022-07-05 at 14 51 14

Here is the Phrase string for german "Search colleagues" Important: notice how the string displayed in the app is not the string from Phrase. Somehow these "wrong" strings showing up in the different language are using the local "Localizable.strings" files (see above)

Screenshot 2022-07-05 at 14 51 18

I tried changing one of the english strings and create a release using OTA and it updated in the app after a short time and a restart, so OTA is working for the other (english) strings.

Interestingly it's the same strings for all the languages, if i change the phone/app language from the iOS settings to any other language I see the exact same strings in the wrong language: Screenshot 2022-07-05 at 14 57 17

Here you can see the test at the top "Test123" when i changed it using OTA Simulator Screen Shot - iPhone 12 Pro - 2022-07-05 at 15 00 07

I am not eliminating the possibility of me doing something wrong. I have checked all your suggestions, the setup of the app seems to be done correctly, R.generated.swift is clearly in the correct bundle, hence the NSLocalizedString method should use the Phrase OTA translations for the respective Phrase.shared.configuration.localeOverride yet still, something is wrong with some strings, and I cannot figure out what.

Thanks for taking the time to look into this issue, I hope we could find a solution as I am not sure where to look next. I am not sure if eliminating R would solve anything, but it might be worth a try, although it is something that i would really try to avoid as a solution for this problem, as we are relying on the usage of R. I will try to clone the setup into a new empty project to use our Phrase strings and have the same local files, and do a test with R and one without R. I will let you know the results.

mihai-honceriu commented 2 years ago

I'm sorry i closed the issue as completed by mistake. Could anyone re-open it? Sorry for that 😄

@winkelsdorf @theSoenke

winkelsdorf commented 2 years ago

@mihai-honceriu sure, no problem, reopened! Thank you very much for your detailed answer, I'll have a deeper look into that later too.

winkelsdorf commented 1 year ago

@mihai-honceriu I was unable to find anything related to those issues, not even able to replicate it. Were you able to find the issue?

winkelsdorf commented 1 year ago

Closing: This problem has either been fixed by the developer in the meantime or an update has solved it as a side effect. Please reopen this issue and/or submit a new issue if the problem persists.