Reputation: 856
I have been searching for hours and I have not been able to find an answer. I'm making an app which uses multiple languages which the user can change during runtime, this is necessary for the product. Now I have been able to change the language with the following code:
userDefaults.setObject(["\(cc)"], forKey: "AppleLanguages")
userDefaults.synchronize()
This code works great. If I change the language setting from Dutch to English it does actually change. The underlying code that is. My app makes use of a server and when I try to logon to the english or dutch service with different credentials it recognises them and lets me login. However the view does not change until after a restart. I tried making it change with this:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
check.text = NSLocalizedString("currentLangauge", comment: "Just a check")
}
And the check label has been declared as:
@IBOutlet weak var check: UILabel!
After a restart it updates just fine but not during runtime and I know it should be possible because I have seen apps do it. I found some examples in Objective-C that use NSBundle but I am not familiar with Objective-C and I do not know how to convert this to Swift.
One of the examples in Objective-C: iOS Change app Language doesn't take effect
Does anybody has any experience with this?
Upvotes: 0
Views: 3858
Reputation: 856
Eventhough "P-double" gave a very good suggestion on how to work around this. I couldn't really figure out a way to really implement this so I went with a different solution that may just take a tad bit more. Instead of just using the "Localizable.strings" file, I decided to just make a new strings file for each langauge and call them by the language identification (eg. mexico = es-MX, english = en).
Instead of rewriting NSLocalizedString, I opted to add the "tableName" option which can then default to the right .strings file. So when I change language now I do it like so:
cc = currentCell.langString
userDefaults.setObject(api, forKey: "api")
userDefaults.setObject(["\(cc)"], forKey: "AppleLanguages")
defaultTable = cc
userDefaults.synchronize()
And when I ask for a localized string I do it simply like so:
check.text = NSLocalizedString("currentLangauge", tableName: defaultTable, comment: "Just a check")
I can use this for everything that I can show on my storyboard, the only thing I have to do extra is really define every single object that is on the storyboard so I can adjust the text. With this "solution" you do not need to localize your storyboard anymore. Only the code.
Upvotes: 1
Reputation: 4351
You need to manually manage the process unfortunately. You'll need to write your own replacement of NSLocalizedString class, that checks user defaults and reads the language, then loads the string from the correct strings file.
You'll also need a mechanism to notify labels / text views / buttons that they should re-render their titles when the user changes language, as when the setting is changed, it's likely there will be a fair few views displaying text in memory. A crude solution is to subclass the foundation classes, initialise them with a string key, with which they perform their own text lookup. Then have them respond to a language changed notification that you fire when the user changes language. They can then perform another string lookup with your NSLocalizedString replacement class.
It's actually not as much effort as it sounds, but it is an effort. It's probably worth understanding string localisation as much as possible. Here are a couple of good resources.
http://nshipster.com/nslocalizedstring/
http://www.objc.io/issue-9/index.html
Upvotes: 1