问题
Hello iam trying to change localization string file with out restart the application , after change the language i need to restart the application to see new language this is how i am changing the application language but i need to restart application to see change using this library https://github.com/marmelroy/Localize-Swift i need to set all label values programmatically which is headache i don't want to this like this way
var selectedLanguage:Languages
let preferredLanguage : String = Bundle.main.preferredLocalizations.first!
print("app langugage \(preferredLanguage)")
if(preferredLanguage == "en") {
// Localize.setCurrentLanguage("de")
selectedLanguage = .de
LanguageManger.shared.setLanguage(language: selectedLanguage)
}
else {
// Localize.setCurrentLanguage("en")
selectedLanguage = .en
LanguageManger.shared.setLanguage(language: selectedLanguage)
}
LanguageManger.shared.setLanguage(language: selectedLanguage)
// return to root view contoller and reload it
let transition: UIViewAnimationOptions = .transitionFlipFromLeft
let rootviewcontroller: UIWindow = ((UIApplication.shared.delegate?.window)!)!
rootviewcontroller.rootViewController = self.storyboard?.instantiateViewController(withIdentifier: "rootnav")
let mainwindow = (UIApplication.shared.delegate?.window!)!
mainwindow.backgroundColor = UIColor(hue: 0.6477, saturation: 0.6314, brightness: 0.6077, alpha: 0.8)
UIView.transition(with: mainwindow, duration: 0.55001, options: transition, animations: { () -> Void in
}) { (finished) -> Void in
}
回答1:
Make a new class NSBundle+Language.h, NSBundle+Language.m. And don't forget to add bridging header.
NSBundle+Language.h
#import <Foundation/Foundation.h>
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
NSBundle+Language.m
#import "NSBundle+Language.h"
#import <objc/runtime.h>
static const char _bundle=0;
@interface BundleEx: NSBundle
@end
@implementation BundleEx
-(NSString*)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
NSBundle* bundle=objc_getAssociatedObject(self, &_bundle);
return bundle ? [bundle localizedStringForKey:key value:value table:tableName]: [super localizedStringForKey:key value:value table:tableName];
}
@end
@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
object_setClass([NSBundle mainBundle],[BundleEx class]);
});
objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]]: nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
After this use this language manager to change the language:-
class LanguageManager: NSObject {
//MARK: Set language preference
class func setSelectedLanguage(dictionary: [String: String]) {
let userDefaults = UserDefaults.standard
userDefaults.set(dictionary, forKey: kSelectedLanguageDetails)
userDefaults.synchronize()
}
class func getSelectedLanguage() -> [String: String]? {
let userDefaults = UserDefaults.standard
return userDefaults.value(forKey: kSelectedLanguageDetails) as? [String: String]
}
class func getSelectedLangaugeCode() -> String{
if let selectedLanguageDetails = LanguageManager.getSelectedLanguage() {
if let languageCode = selectedLanguageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
return languageCode.lowercased()
}
else {
let languageDetails = [LocalizationKeys.kLanguageCode.rawValue:"EN", LocalizationKeys.kLanguageName.rawValue:"English", LocalizationKeys.kLanguageID.rawValue:"1"]
LanguageManager.setSelectedLanguage(dictionary: languageDetails)
if let languageCode = languageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
return languageCode.lowercased()
}
}
}
else {
let languageDetails = [LocalizationKeys.kLanguageCode.rawValue:"EN", LocalizationKeys.kLanguageName.rawValue:"English", LocalizationKeys.kLanguageID.rawValue:"1"]
LanguageManager.setSelectedLanguage(dictionary: languageDetails )
if let languageCode = languageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
return languageCode.lowercased()
}
}
return "en"
}
/// Checks for the Language preferences selected by user
class func checkLanguagePreferenceAndSetToDefaults() {
if let selectedLanguageDetails = LanguageManager.getSelectedLanguage() {
if let languageCode = selectedLanguageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
}
else {
let languageDetails = [LocalizationKeys.kLanguageCode.rawValue:"EN", LocalizationKeys.kLanguageName.rawValue:"English", LocalizationKeys.kLanguageID.rawValue:"1"]
LanguageManager.setSelectedLanguage(dictionary: languageDetails)
if let languageCode = languageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
}
}
}
else {
let languageDetails = [LocalizationKeys.kLanguageCode.rawValue:"EN", LocalizationKeys.kLanguageName.rawValue:"English", LocalizationKeys.kLanguageID.rawValue:"1"]
LanguageManager.setSelectedLanguage(dictionary: languageDetails )
if let languageCode = languageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
}
}
}
//MARK: Get Language Code
/// Return apple specific language code
///
/// - parameter languageCode: language code string
///
/// - returns: apples language code
static func getAppleLanguageCode(languageCode:String) -> String{
switch languageCode.lowercased() {
case "en":
return "en"
case "es":
return "es"
case "fr":
return "fr"
case "de":
return "de"
case "it":
return "it"
default:
return languageCode
}
}
}
Define the language options as bellow:-
let KlanguageOptionArray: [[String:String]] = [
[
"LanguageCode": "EN",
"Name": "English",
"LanguageID": "1"
],
[
"LanguageCode": "ES",
"Name": "Español",
"LanguageID": "2"
],
[
"LanguageCode": "FR",
"Name": "Français",
"LanguageID": "3"
],
[
"LanguageCode": "DE",
"Name": "Deutsch",
"LanguageID": "4"
],
[
"LanguageCode": "IT",
"Name": "Italiano",
"LanguageID": "5"
]
]
Change the selected language with bellow code
let selectedLanguageDetails = self.languageOptionArray[indexPath.row]
LanguageManager.setSelectedLanguage(dictionary: selectedLanguageDetails)
if let languageCode = selectedLanguageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
NotificationCenter.default.post(name: NSNotification.Name(rawValue: NotificationCenterTypes.ReloadTableOnLanguageChangeNotification), object: nil)
}
And don't forget to add this on every launch
if let selectedLanguageDetails = LanguageManager.getSelectedLanguage() {
if let languageCode = selectedLanguageDetails[LocalizationKeys.kLanguageCode.rawValue] {
Bundle.setLanguage(LanguageManager.getAppleLanguageCode(languageCode: languageCode.lowercased()))
}
else {
}
}
Hope this helps you
回答2:
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!
来源:https://stackoverflow.com/questions/51153785/how-to-change-localization-language-without-restart-application-swift4