Changing language on the fly in swift

前端 未结 3 769
闹比i
闹比i 2020-12-14 03:39

Now I know that apple does not recommend this.

In general, you should not change the iOS system language (via use of the AppleLanguages pref key) from

相关标签:
3条回答
  • 2020-12-14 03:53

    As answered by "vikingosegundo" above was having category in Objective c So here is Swift extension version

    import ObjectiveC
    
    private var associatedLanguageBundle:Character = "0"
    
    class PrivateBundle: Bundle {
        override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
            let bundle: Bundle? = objc_getAssociatedObject(self, &associatedLanguageBundle) as? Bundle
            return (bundle != nil) ? (bundle!.localizedString(forKey: key, value: value, table: tableName)) : (super.localizedString(forKey: key, value: value, table: tableName))
    
        }
    }
    
    extension Bundle {
        class func setLanguage(_ language: String) {
            var onceToken: Int = 0
    
            if (onceToken == 0) {
                /* TODO: move below code to a static variable initializer (dispatch_once is deprecated) */
                object_setClass(Bundle.main, PrivateBundle.self)
            }
            onceToken = 1
            objc_setAssociatedObject(Bundle.main, &associatedLanguageBundle, (language != nil) ? Bundle(path: Bundle.main.path(forResource: language, ofType: "lproj") ?? "") : nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    

    remains code will same as mentioned by "vikingosegundo"

    Corrections are always welcome :)

    0 讨论(0)
  • 2020-12-14 04:00

    Use this line of code it will change layout without closing application. From right to left

    UIView.appearance().semanticContentAttribute = .forceRightToLeft
    

    And for Left to Right Flip

    UIView.appearance().semanticContentAttribute = .forceLeftToRight
    

    and if you want to change textfield layout or text change then use this code because i faced this issue . textfield's texts was not changning layout. check this code to change layout of textfield text.

    extension UITextField {
      open override func awakeFromNib() {
    super.awakeFromNib()
      if UserDefaults.languageCode == "ar" {
        if textAlignment == .natural {
            self.textAlignment = .right
        }
      }
     }
    }
    
    0 讨论(0)
  • 2020-12-14 04:12

    Basically you have to teach you bundle how to switch languages by loading different bundle files.

    I translated my Objective-C code to Swift — with leaving the NSBundle category untouched.

    enter image description here

    The result is a view controller class that offers a languageDidChange() method for overriding.


    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 associatedLanguageBundle=0;
    
    @interface PrivateBundle : NSBundle
    @end
    
    @implementation PrivateBundle
    -(NSString*)localizedStringForKey:(NSString *)key
                                value:(NSString *)value
                                table:(NSString *)tableName
    {
        NSBundle* bundle=objc_getAssociatedObject(self, &associatedLanguageBundle);
        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],[PrivateBundle class]);
        });
    
        objc_setAssociatedObject([NSBundle mainBundle], &associatedLanguageBundle, language ?
                                 [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    @end
    

    AppDelegate.swift

    import UIKit
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
    
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "languageWillChange:", name: "LANGUAGE_WILL_CHANGE", object: nil)
    
            let targetLang = NSUserDefaults.standardUserDefaults().objectForKey("selectedLanguage") as? String
    
            NSBundle.setLanguage((targetLang != nil) ? targetLang : "en")
            return true
        }
    
        func languageWillChange(notification:NSNotification){
            let targetLang = notification.object as! String
            NSUserDefaults.standardUserDefaults().setObject(targetLang, forKey: "selectedLanguage")
            NSBundle.setLanguage(targetLang)
            NSNotificationCenter.defaultCenter().postNotificationName("LANGUAGE_DID_CHANGE", object: targetLang)
        }    
    }
    

    BaseViewController.swift

    import UIKit
    
    
    
    class BaseViewController: UIViewController {
    
        @IBOutlet weak var englishButton: UIButton!
        @IBOutlet weak var spanishButton: UIButton!
    
        deinit{
            NSNotificationCenter.defaultCenter().removeObserver(self)
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "languageDidChangeNotification:", name: "LANGUAGE_DID_CHANGE", object: nil)
            languageDidChange()
    
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        @IBAction func switchLanguage(sender: UIButton) {
    
            var localeString:String?
            switch sender {
            case englishButton: localeString = "en"
            case spanishButton: localeString = "es"
            default: localeString = nil
            }
    
    
            if localeString != nil {
                NSNotificationCenter.defaultCenter().postNotificationName("LANGUAGE_WILL_CHANGE", object: localeString)
            }
        }
    
    
        func languageDidChangeNotification(notification:NSNotification){
            languageDidChange()
        }
    
        func languageDidChange(){
    
        }
    
    
    }
    

    ViewController.swift

    import UIKit
    
    class ViewController: BaseViewController {
    
        @IBOutlet weak var helloLabel: UILabel!
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func languageDidChange() {
            super.languageDidChange()
            self.helloLabel.text = NSLocalizedString("Hello", comment: "")
    
        }
    }
    

    instead of using subclasses of BaseViewController, your viewcontrollers could also post "LANGUAGE_WILL_CHANGE" and listen for "LANGUAGE_DID_CHANGE"

    I pushed the complete project here: ImmediateLanguageSwitchSwift

    0 讨论(0)
提交回复
热议问题