Change app language at run time - ios

I am trying to change the the lang that I get with NSLocalizedString at run time.
I know that this question as been already asking, but I do not find an answers for Swift 3.
I have try:
UserDefaults.standard.removeObject(forKey: "AppleLanguages")
UserDefaults.standard.set("en", forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
and:
let language = "en"
let path = Bundle.main.path(forResource: language, ofType: "lproj")
let bundle = Bundle(path: path!)
let string = bundle?.localizedString(forKey: "AppleLanguages", value: language, table: nil)
but nothing works....
Thank you for your help!

So at the end, I've used a custom localisator class available on Github, which allow you to switch language from anywhere in the app and even save if for further launches of the app.
It is written in swift 2.2, but Xcode automatically update the code to Swift 3. Just had to change at to places in the Demo:
notification.name == kNotificationLanguageChanged
to:
notification.name.rawValue == kNotificationLanguageChanged
https://github.com/micazeve/iOS-CustomLocalisator

Related

In swift version 5.1.3 How is NSUserDefaults.standardUserDefaults().stringForKey used?

Hi I am learning by watching the video. Since it was an old version, it seemed that you were using NS, but I don’t know how to use it now, so I ask
Youtube video link
https://www.youtube.com/watch?v=PKOswUE731c >> 32:40
let userEmailStored = NSUserDefaults.standardUserDefaults().stringForKey("userEmail")
let userPasswordStored = NSUserDefulats.standardUserDefaults().stringForKey("userPassword")
In the current version, we know that you should use it without NS, but it is not used even if you subtract NS.
Cannot be used
I would appreciate it if you let me know.
You can use UserDefaults now and get the String values like this:
let userEmailStored = UserDefaults.standard.string(forKey: "userEmail")
let userPasswordStored = UserDefaults.standard.string(forKey: "userPassword")
You can use UserDefaults now and set the String values like this:
UserDefaults.standard.set("email", forKey: "userEmail")
UserDefaults.standard.set("password", forKey: "userPassword")

Localisation Settings Not Changing the System Defined Text in Swift 4.2

I have 2 lang support for my app
1) English - en
2) German - de
I have done all the procedures for localization, the only issue is
whenever I change the language from "en" to "de" or vice versa then
after the system text is not changing to the latest lang, but it
reflects when I kill the app and reopen it.
For Example:
The popover Copy-LookUp-Share is not localsied to German Lang. but the other things from .string file are lcoalised properly.
My change lang code:
func setLanguage(languageCode:String) {
var appleLanguages = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
appleLanguages.remove(at: 0)
appleLanguages.insert(languageCode, at: 0)
UserDefaults.standard.set(appleLanguages, forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
if let languageDirectoryPath = Bundle.main.path(forResource: languageCode, ofType: "lproj") {
bundle = Bundle.init(path: languageDirectoryPath)
} else {
resetLocalization()
}
}
func resetLocalization() {
bundle = Bundle.main
}
FYI: Similar thing happens in 'WeChat' iOS application.
Those are UIKit SDK private menu items and you cannot control them, probably they are just created once then kept cached.
The only thing you can try is to force update in the moment of language change, like
UIMenuController.shared.update()
Note: actually using "AppleLanguages" key for that purpose is not documented, so it is kind of hucky. L10N is system settings originated feature, by design.

How can I change app language in app delegate?

I am working on an ios app which currently supports two languages English and Korean. I want to add a condition in the app delegate that If the phone language is supported by the app then the app will open in that language otherwise it will open in the english language. I have tried the following code in app delegate, but it is not working. Can anyone helps me in this.
if UserDefaults.standard.object(forKey: "lang") == nil {
let langCodeString = Locale.current.languageCode
let preferredLanguage = String(Locale.preferredLanguages[0].prefix(2))
if let languageCode = langCodeString {
if languageCode == "ko" && preferredLanguage == "ko" {
UserDefaults.standard.set(["ko"], forKey: "AppleLanguages")
UserDefaults.standard.set("korean", forKey: "lang")
UserDefaults.standard.synchronize()
} else {
UserDefaults.standard.set(["en"], forKey: "AppleLanguages")
UserDefaults.standard.set("english", forKey: "lang")
UserDefaults.standard.synchronize()
}
}
}
Thanks.
Just try to save the preferred language in KeyChain.
Please refer a link.
However, if you prefer API for it and a backend to store translation, that will be a better solution though it will take sometime to load initially.

Set Language in Swift 3 failed [duplicate]

This question already has answers here:
How to force NSLocalizedString to use a specific language
(28 answers)
Closed 5 years ago.
Sir.
I am trying to create an app of multi-language support. I use the abbreviations like zh-Hant, en , jp to save as user default. And change the language of the app. Taking place holder of textfield as an example, if I click the collection view item, the text of place holder of textfield will change. However , I can't do this. The simulator language is English as default
Here is my work in-progress :
Localisation File : Japan (jp)
"User Email"; = "ユーザーメール";
Set Text method
let lcode : String = self.langList[indexPath.item].code
print("You selected cell #\(indexPath.item) and code : \(lcode)")
UserDefaults.standard.setValue(lcode, forKey: "lang")
txtUsername.placeholder = "User Email".localized(lang: lcode)
String exntension
extension String {
func localized(lang:String) ->String {
if let path = Bundle.main.path(forResource: lang, ofType: "lproj") {
if let bundle = Bundle(path: path) {
return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "")
}
}
return "";
}
The language of the app is dependant on the device language. To test the localized string, change your device language. Otherwise, though this is not recommended, you can change your app language on runtime by adding UserDefaults.standard.set("zh", forKey: "AppleLanguages") to your ViewController. But you will have to restart the app to see the language changes.

Force NSLocalizedString to use a specific language using Swift

With swift, how can I force my app to read data from a specific Localizable.strings.
I put this in didFinishLaunchingWithOptions before instantiate the ViewController but it still show me the App in English.
NSUserDefaults.standardUserDefaults().removeObjectForKey("AppleLanguages")
NSUserDefaults.standardUserDefaults().setObject("fr", forKey: "AppleLanguages"
NSUserDefaults.standardUserDefaults().synchronize()
And I tried to pass an Array for the "AppleLanguages" key like this but it still doesn't work:
NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages"
And once this is done, can I call this inside the App and take the changes in consideration without restarting the App?
It's not possible to change app's language immediately by changing the value of AppleLanguages. It requires restarting the app before the change takes effect.
It seems that your problem is accessing the localization strings of different languages rather than changing the app's language, right? If you want your app to support multiple languages, you can just provide the translations and rely on settings.app for the actual change.
If you want to access the localization strings from other than currently used localization, you need to get access to the proper translations bundle. And then just query that bundle for the translations. The following piece of code should do the trick.
let language = "en"
let path = Bundle.main.path(forResource: language, ofType: "lproj")
let bundle = Bundle(path: path!)
let string = bundle?.localizedStringForKey("key", value: nil, table: nil)
With NSLocalizedString you can specify the bundle.
let language = "fr"
let path = Bundle.main.path(forResource: language, ofType: "lproj")!
let bundle = Bundle(path: path)!
let localizedString = NSLocalizedString(key, bundle: bundle, comment: "")
Or with a bundle, you may also call localizedStringForKey:value:table: directly too.
#Radu I also made this working for XCUITests thanks to #Markus' original answer :
You can specify explicitly the path to your MainBundle, it will only work on your Mac with the Simulator, but it is often used in continuous integration platforms so this might be acceptable :
let language: String = "en"
let path = "/Users/{username}/{path_to_your_project}/\(language).lproj"
let bundle = Bundle(path: path)
let string = bundle?.localizedString(forKey: "key", value: nil, table: nil)
In swift 4, I have solved it without needing to restart or use libraries.
After trying many options, I found this function, where you pass the stringToLocalize (of Localizable.String, the strings file) that you want to translate, and the language in which you want to translate it, and what it returns is the value for that String that you have in Strings file:
    func localizeString (stringToLocalize: String, language: String) -> String
    {
        let path = Bundle.main.path (forResource: language, ofType: "lproj")
        let languageBundle = Bundle (path: path!)
        return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
    }
Taking into account this function, I created it as global in a Swift file:
struct CustomLanguage {
func createBundlePath () -> Bundle {
let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
return Bundle(path: path!)!
}
}
To access from the whole app, and in each string of the rest of ViewControllers, instead of putting:
NSLocalizedString ("StringToLocalize", comment: “")
I have replaced it with
let customLang = CustomLanguage() //declare at top
NSLocalizedString("StringToLocalize", tableName: nil, bundle: customLang.createBundlePath(), value: "", comment: “”) //use in each String
I do not know if it's the best way, but I found it very simple, and it works for me, I hope it helps you!

Resources