I'm making an iOS app which supports multiple languages but not in the built-in localized way. In iOS, for localization to work, the user has to change the device's language. But in the app I'm working on, the user needs to be able to choose the language to effect only this app. So for example, I can have the device's language set to English but the user can choose Spanish to be set as the language within the app.
I took some concepts from iOS localization and added some things on my own. First I created plists to contain strings for each language I support.
English
Spanish
Next I created a singleton which handles the setting on the chosen language and serving the strings based on that selected language. I use a third-party library called SwiftyPlist for easier manipulation of plists.
enum Language: String {
case english = "en"
case spanish = "es"
}
class LanguageManager {
static let shared = LanguageManager()
private var plist: Plist!
// Get/Set the language of choice
var language: Language? {
set {
UserDefaults.standard.set(newValue?.rawValue, forKey: "Language")
reloadPlist()
}
get {
if let code = UserDefaults.standard.object(forKey: "Language") as? String {
return Language(rawValue: code)
} else {
return nil
}
}
}
private init() {
reloadPlist()
}
// Reload the corresponding plist
private func reloadPlist() {
if language == nil || language! == .english {
let dict = NSDictionary(contentsOfFile: Bundle.main.path(forResource: "English", ofType: "plist")!)
plist = Plist(plistObject: dict)
} else if language! == .spanish {
let dict = NSDictionary(contentsOfFile: Bundle.main.path(forResource: "Spanish", ofType: "plist")!)
plist = Plist(plistObject: dict)
}
}
var name: String {
return plist["YOUR_NAME"]!.string!
}
}
Now I can set the chosen language like this.
LanguageManager.shared.language = .spanish
And I can simply access the strings like so.
LanguageManager.shared.name
I feel like this is a good, scalable approach to my requirement. But I'd like to see if it has room to improvement.