This is an old question, but i was developing an helper that notifies me when the language change on the fly.
Take a look at the code of helper:
import Foundation
class LocalizableLanguage {
// MARK: Constants
fileprivate static let APPLE_LANGUAGE_KEY = "AppleLanguages"
/// Notification Name to observe when language change
static let ApplicationDidChangeLanguage = Notification.Name("ApplicationDidChangeLanguage")
// MARK: Properties
/// An array with all available languages as String
static var availableLanguages: [String]? = {
return UserDefaults.standard.object(forKey: APPLE_LANGUAGE_KEY) as? [String]
}()
/// The first element of available languages that is the current language
static var currentLanguageCode: String? = {
return availableLanguages?.first
}()
/// The current language code with just 2 characters
static var currentShortLanguageCode: String? = {
guard let currentLanguageCode = currentLanguageCode else {
return nil
}
let strIndex = currentLanguageCode.index(currentLanguageCode.startIndex, offsetBy: 2)
return currentLanguageCode.substring(to: strIndex)
}()
// MARK: Handle functions
/// This accepts the short language code or full language code
/// Setting this will send a notification with name "ApplicationDidChangeLanguage", that can be observed in order to refresh your localizable strings
class func setLanguage(withCode langCode: String) {
let matchedLangCode = availableLanguages?.filter {
$0.contains(langCode)
}.first
guard let fullLangCode = matchedLangCode else {
return
}
var reOrderedArray = availableLanguages?.filter {
$0.contains(langCode) == false
}
reOrderedArray?.insert(fullLangCode, at: 0)
guard let langArray = reOrderedArray else {
return
}
UserDefaults.standard.set(langArray, forKey: APPLE_LANGUAGE_KEY)
UserDefaults.standard.synchronize()
LocalizableLanguage.refreshAppBundle()
NotificationCenter.default.post(name: ApplicationDidChangeLanguage, object: fullLangCode)
}
}
// MARK: Refresh Bundle Helper
private extension LocalizableLanguage {
class func refreshAppBundle() {
MethodSwizzleGivenClassName(cls: Bundle.self, originalSelector: #selector(Bundle.localizedString(forKey:value:table:)), overrideSelector: #selector(Bundle.specialLocalizedStringForKey(_:value:table:)))
}
class func MethodSwizzleGivenClassName(cls: AnyClass, originalSelector: Selector, overrideSelector: Selector) {
let origMethod: Method = class_getInstanceMethod(cls, originalSelector);
let overrideMethod: Method = class_getInstanceMethod(cls, overrideSelector);
if (class_addMethod(cls, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
class_replaceMethod(cls, overrideSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, overrideMethod);
}
}
}
extension Bundle {
func specialLocalizedStringForKey(_ key: String, value: String?, table tableName: String?) -> String {
let availableLanguages = UserDefaults.standard.object(forKey: LocalizableLanguage.APPLE_LANGUAGE_KEY) as? [String]
let currentLanguageCode = availableLanguages?.first ?? "en-US"
let currentShortLanguageCode = currentLanguageCode.substring(to: currentLanguageCode.index(currentLanguageCode.startIndex, offsetBy: 2))
let path =
Bundle.main.path(forResource: currentLanguageCode, ofType: "lproj") ??
Bundle.main.path(forResource: currentShortLanguageCode, ofType: "lproj") ??
Bundle.main.path(forResource: "Base", ofType: "lproj")
guard
self == Bundle.main,
let bundlePath = path,
let bundle = Bundle(path: bundlePath)
else {
return self.specialLocalizedStringForKey(key, value: value, table: tableName)
}
return bundle.specialLocalizedStringForKey(key, value: value, table: tableName)
}
}
You just need to copy that code and put in your project.
Then, you simple implement the listener like this:
NotificationCenter.default.addObserver(forName: LocalizableLanguage.ApplicationDidChangeLanguage, object: nil, queue: nil) { notification in
guard let langCode = notification.object as? String else {
return
}
self.accountStore.languageCode.value = langCode
}
Note that this line self.accountStore.languageCode.value = langCode
is what i need to refresh when the app language as changed, then i can easily change all strings of my ViewModels in order to change the language to the user immediately.
In order to change the language, you can just call:
LocalizableLanguage.setLanguage(withCode: "en")
Other helper that could be nice to you is:
import Foundation
extension String {
var localized: String {
return NSLocalizedString(self, comment: "")
}
}
So if you have in your localizable files something like that:
main.view.title = "Title test";
You can simple call:
"main.view.title".localized
And you have your string translated.
exit(0)
on apps before AFTER a UIAlertView advising the user that the app was about to qui - never had an issue with approvals with Apple. – Ironhanded