web-dev-qa-db-fra.com

Changer de langue à la volée rapidement

Maintenant, je sais que Apple ne le recommande pas.

En règle générale, vous ne devez pas modifier la langue du système iOS (via l'utilisation de la clé pref AppleLanguages) dans votre application. Cela va à l'encontre du modèle d'utilisateur iOS de base pour changer de langue dans l'application Paramètres et utilise également une clé de préférence non documentée, ce qui signifie que le nom de la clé pourrait changer à l'avenir, ce qui endommagerait votre application.

Cependant, c'est une application qui change la langue à la volée est logique, faites-moi confiance à ce sujet. Je sais aussi que cette question a été posée ici: Changer de langue à la volée, sous iOS, par programme . Cependant, cela vieillit et je me demandais s’il existe des moyens plus récents, meilleurs ou plus faciles de le faire. Actuellement dans mon application, j'ai un écran de choix de langue. En cliquant sur l'un des boutons de cette vue, vous appelez la fonction suivante avec la langue à laquelle le bouton est associé: 

 func changeLang(language: String) {

    if language != (currentLang as! String?)! {
        func handleCancel(alertView: UIAlertAction!)
        {

        }
        var alert = UIAlertController(title: NSLocalizedString("language", comment: "Language"), message: NSLocalizedString("languageWarning", comment: "Warn User of Language Change Different Than Defaults"), preferredStyle: UIAlertControllerStyle.Alert)

        alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler:handleCancel))
        alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler:{ (UIAlertAction) in

            NSUserDefaults.standardUserDefaults().setObject([language], forKey: "AppleLanguages")
            NSUserDefaults.standardUserDefaults().synchronize()
            println(self.currentLang)

            let alert = UIAlertView()
            alert.title = NSLocalizedString("language", comment: "Sign In Failed")
            alert.message = NSLocalizedString("languageChangeNotification", comment: "Notify of language change")
            alert.addButtonWithTitle(NSLocalizedString("ok", comment: "Okay"))
            alert.show()

            self.performSegueWithIdentifier("welcome", sender: AnyObject?())


        }))
        self.presentViewController(alert, animated: true, completion: {
        })
    } else {
        self.performSegueWithIdentifier("welcome", sender: AnyObject?())
    }

}

Exemple:

@IBAction func english(sender: UIButton) {
        changeLang("en")

    }

Si l'utilisateur choisit une langue différente de la sienne, il reçoit une alerte de confirmation, puis il lui est demandé de redémarrer son appareil. C'est ce que je veux changer. Il semble que cette section de NSUSerDefaults n’est pas synchronisée avant le redémarrage de l’application. Preuve:

let currentLang: AnyObject? = NSLocale.preferredLanguages()[0]
println(currentLang)
// Prints english
changeLang("zh-Hans")
println(currentLang)
// Prints english still until restart 

Le système d'internationalisation actuel d'Apple est excellent et je prévois de l'utiliser. Cependant, comment puis-je changer la langue à la volée, peut-être en forçant une mise à jour de NSUSerDefaults?

Edit: Je recommande d'utiliser cette bibliothèque pour le faire maintenant. Bonne chance!

10
modesitt

En gros, vous devez apprendre à votre groupe comment changer de langue en chargeant différents fichiers.

J'ai traduit mon code Objective-C en Swift - en laissant intacte la catégorie NSBundle. 

enter image description here

Le résultat est une classe de contrôleur de vue qui offre une méthode languageDidChange() pour le remplacement. 


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: "")

    }
}

au lieu d'utiliser des sous-classes de BaseViewController, vos contrôleurs de vue peuvent également publier "LANGUAGE_WILL_CHANGE" et écouter "LANGUAGE_DID_CHANGE". 

J'ai poussé le projet complet ici: ImmediateLanguageSwitchSwift

24
vikingosegundo

pour moi, la bibliothèque " Swift Localize " a résolu le changement de langue à la volée.

Comme répondu par "vikingosegundo" ci-dessus avait la catégorie dans Objective C Voici donc la version Swift extension

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)
    }
}

reste le code sera le même que celui mentionné par "vikingosegundo"

Les corrections sont toujours les bienvenues :)

3
singh.jitendra

Utilisez cette ligne de code, il va changer la disposition sans fermer l'application. De droite à gauche

UIView.appearance().semanticContentAttribute = .forceRightToLeft

Et pour le flip de gauche à droite

UIView.appearance().semanticContentAttribute = .forceLeftToRight

et si vous voulez changer la disposition du champ de texte ou le texte, utilisez ce code car je suis confronté à ce problème. Les textes de textfield ne changeaient pas de disposition. Cochez ce code pour changer la disposition du texte du champ de texte.

extension UITextField {
  open override func awakeFromNib() {
super.awakeFromNib()
  if UserDefaults.languageCode == "ar" {
    if textAlignment == .natural {
        self.textAlignment = .right
    }
  }
 }
}
0
Shahzaib Maqbool