it-swarm.com.de

Ändern Sie die Sprache im laufenden Betrieb, indem Sie iOS programmgesteuert ausführen

Ich habe stundenlang gestapelt und gegoogelt. Und ich bin jetzt irgendwie verzweifelt ... Ich möchte die Sprache meiner Anwendung in der App nicht nur mit der Standardsprache ändern.

Von dem, was ich ausprobiert habe, blieb ich beim Neustart wie jeder. Das heißt, Äpfel zwingen Sie, die App manuell neu zu starten. Das bedeutet, dass Sie die App beenden und dann erneut starten müssen.

Nun, nach dem Googeln versuchte ich, einen Alarm einzurichten und zwang die App später dazu, mit zu beenden

exit(0);

Mein schlechtes, Apple scheint das nicht zu mögen und den Entwickler daran zu hindern, es zu benutzen ... Ich denke, ich habe nicht die richtige Richtung.

Schließlich könnte ich mich trotz aller Probleme treffen und darüber diskutieren.

Irgendwelche Hinweise?


BEARBEITEN, Infos von Apple

Im Allgemeinen sollten Sie das .__ nicht ändern. iOS-Systemsprache (über die Verwendung des Präferenzschlüssels AppleLanguages) innerhalb von Ihre Bewerbung. Das geht gegen das grundlegende iOS-Benutzermodell zum Wechseln von Sprachen in der Einstellungen-App und verwendet auch einen Präferenzschlüssel, der nicht .__ ist. dokumentiert, was bedeutet, dass irgendwann In Zukunft könnte der Schlüsselname ändern, was Ihre .__ zerbrechen würde. Anwendung.

Wenn Sie in .__ die Sprache wechseln möchten. Ihre Bewerbung können Sie über Manuelles Laden von Ressourcendateien in dein Bundle Sie können .__ verwenden. NSBundle: pathForResource: ofType: inDirectory: forLocalization: zu diesem Zweck, aber denken Sie daran dass Ihre Bewerbung wäre verantwortlich für das Laden von lokalisierte Daten. 

Bezüglich der Frage zum Beenden (0): Apple DTS kann die App-Genehmigung nicht kommentieren verarbeiten. Sie sollten sich mit In Verbindung setzen. [email protected], um eine Antwort zu erhalten für diese Frage.

Nun, ich muss mich so weit entscheiden.

30
gabrielstuff

Dies ist eine ziemlich alte Frage, aber ich hatte gerade mit dem gleichen Problem zu kämpfen und fand diese Lösung:

http://aggressive-mediocrity.blogspot.com/2010/03/custom-localization-system-for-your.html

Was genau das tut, was Sie brauchen (und könnte für andere hilfreich sein, die das gleiche Problem haben :)

21
Swissdude

Der folgende Link hat eine nette Implementierung der benutzerdefinierten Sprache in der Anwendung.

manuelle Sprachauswahl in einer iOS-App (iPhone und iPad)

Eine Swift-Version wurde hier gefunden LanguageSettings_Swift

 LanguageChange

-anoop

5
anoop4real

ja, ich hatte das gleiche Problem, dann habe ich es mit meiner eigenen Spracheinstellung in meinem prefFile geschafft, wo ich eine Variable für die Spracheinstellung eingestellt habe:

// write a new value in file and set the var
- (void)changeLangInPrefFile:(NSString *)newLanguage {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"myPreference.plist"];
    NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
    //here add elements to data file and write data to file
    [data setObject:newLanguage forKey:@"language"];
    [data writeToFile:path atomically:YES];
    [data release];

// NSString *chosenLang; <- declared in .h file
    if (chosenLang != nil){
        [chosenLang release];
        chosenLang = nil;
    }
    chosenLang = [[NSString alloc] initWithString:(@"%@",newLanguage)];

}

// read the language from file and set the var:
- (void)readFromFileInBundleDocuments {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"myPreference.plist"];
    NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile:path];

    NSString *chosenLangTemp = [savedStock objectForKey:@"language"];
    NSLog (@"read in file: %@", chosenLangTemp);
    if (chosenLang != nil){
        [chosenLang release];
        chosenLang = nil;
    }
    chosenLang = [[NSString alloc] initWithString:(@"%@",chosenLangTemp)];
    [savedStock release];
}

dann lade ich den gesamten Inhalt aus verschiedenen Dateien abhängig von der Sprache Zum Beispiel kann ich "an_image_eng.png" oder "an_image_ita.png", laden oder 2 verschiedene .xib-Dateien und den Text haben Um zu laden, verwende ich verschiedene Wörterbuchdateien, eine für jede Sprache, mit allen Wörtern/Ausdrücken, die ich übersetzt habe. Ich lade einfach die ausgewählte aus und lese darin den richtigen Ausdruck für jeden zu ladenden Text (der Code, der geladen werden soll, ist ähnlich dem Die Methode, die ich in diesem Beispiel geschrieben habe, lässt sich einfach so anordnen, dass für jeden Ausdruck das richtige Wort gelesen wird: Schauen Sie sich den Wert für objectForKey in der rechten Wörterbuchdatei an, wobei objectForKey das zu übersetzende Wort ist und dessen Wert das übersetzte Wort ist. ..

3
meronix

Im Allgemeinen wird die Sprache, die der Benutzer sieht, von der Gebietsschemaeinstellung bestimmt. Dies ist eine systemweite Einstellung. Nur der Benutzer kann es ändern. Wenn dies der Fall ist, müssen SpringBoard und jede auf dem Gerät ausgeführte Anwendung neu gestartet werden. Es gibt keine Möglichkeit, dies zu umgehen, da alle System-Apps und -Frameworks davon ausgehen, dass sich das Gebietsschema nicht ändert, sobald sie ausgeführt werden. Wenn Sie die Apps und Frameworks so ändern möchten, dass kein Relaunch erforderlich ist, wäre dies für Apple sehr schwierig. 

Ich vermute, dass Sie entweder die Sprache der Benutzeroberfläche Ihrer App völlig unabhängig von der Systemeinstellung für das System ändern möchten, oder Sie möchten die Systemeinstellung für das System standardmäßig verwenden, dem Benutzer jedoch erlauben, sie nur für Ihre App zu überschreiben. 

Sie können das aktuelle Gebietsschema abrufen und die verschiedenen Werte mit +[NSLocale currentLocale] überprüfen. Um die Benutzeroberfläche Ihrer App in einer Sprache anzuzeigen, die unabhängig von der Ländereinstellung des Systems ist, müssen Sie die Verwendung von NSLocalizedString() vollständig vermeiden und einen benutzerdefinierten Status verwenden, um zu bestimmen, welche Zeichenfolgen dem Benutzer angezeigt werden und wie Ändern Sie die Benutzeroberfläche, um sie an die Sprache Ihrer App anzupassen. Es liegt an Ihnen, den Sprachstatus Ihrer App beizubehalten und die Benutzeroberfläche entsprechend zu ändern.

1
Ryan

Laut Apple guidelines ist dies keine gute Idee, die Sprache programmgesteuert in der App zu ändern. Falls Sie jedoch keine Möglichkeit haben, das gewünschte Verhalten zu ändern, können Sie Folgendes tun:

  1. Bereiten Sie einen Dienst vor, um Ihre Sprache auch nach dem Neustart der App zu verwalten

    enum LanguageName: String {
        case undefined
        case en
        case es
    }
    
    let DynamicLanguageServiceDidDetectLanguageSwitchNotificationKey = "DynamicLanguageServiceDidDetectLanguageSwitchNotificationKey"
    
    func dynamicLocalizableString(_ key: String) -> String {
        return LanguageService.service.dynamicLocalizedString(key)
    }
    
    class LanguageService {
    
        private struct Defaults {
            static let keyAppleLanguage = "AppleLanguages"
            static let keyCurrentLanguage = "KeyCurrentLanguage"
        }
    
        static let service:LanguageService = LanguageService()
    
        var languageCode: String {
            get {
                return language.rawValue
            }
        }
    
        var currentLanguage:LanguageName {
            get {
                var currentLanguage = UserDefaults.standard.object(forKey: Defaults.keyCurrentLanguage)
                if let currentLanguage = currentLanguage as? String {
                    UserDefaults.standard.set([currentLanguage], forKey: Defaults.keyAppleLanguage)
                    UserDefaults.standard.synchronize()
                } else {
                    if let languages = UserDefaults.standard.object(forKey: Defaults.keyAppleLanguage) as? [String] {
                        currentLanguage = languages.first
                    }
                }
                if let currentLanguage = currentLanguage as? String, 
                    let lang = LanguageName(rawValue: currentLanguage) {
                    return lang
                }
                return LanguageName.undefined
            }
        }
    
        func switchToLanguage(_ lang:LanguageName) {
            language = lang
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: DynamicLanguageServiceDidDetectLanguageSwitchNotificationKey), object: nil)
        }
    
        private var localeBundle:Bundle?
    
        fileprivate var language: LanguageName = LanguageName.en {
            didSet {
                let currentLanguage = language.rawValue
    
                UserDefaults.standard.set([currentLanguage], forKey:Defaults.keyAppleLanguage)
                UserDefaults.standard.setValue(currentLanguage, forKey:Defaults.keyCurrentLanguage)
                UserDefaults.standard.synchronize()
    
                setLocaleWithLanguage(currentLanguage)            
            }
        }
    
        // MARK: - LifeCycle
    
        private init() {
            prepareDefaultLocaleBundle()
        }
    
        //MARK: - Private
    
        fileprivate func dynamicLocalizedString(_ key: String) -> String {
            var localizedString = key
            if let bundle = localeBundle {
                localizedString = NSLocalizedString(key, bundle: bundle, comment: "")
            } else {
                localizedString = NSLocalizedString(key, comment: "")
            }
            return localizedString
        }
    
        private func prepareDefaultLocaleBundle() {
            var currentLanguage = UserDefaults.standard.object(forKey: Defaults.keyCurrentLanguage)
            if let currentLanguage = currentLanguage as? String {
                UserDefaults.standard.set([currentLanguage], forKey: Defaults.keyAppleLanguage)
                UserDefaults.standard.synchronize()
            } else {
                if let languages = UserDefaults.standard.object(forKey: Defaults.keyAppleLanguage) as? [String] {
                    currentLanguage = languages.first
                }
            }
    
            if let currentLanguage = currentLanguage as? String {
                updateCurrentLanguageWithName(currentLanguage)
            }
        }
    
        private func updateCurrentLanguageWithName(_ languageName: String) {
            if let lang = LanguageName(rawValue: languageName) {
                language = lang
            }
        }
    
        private func setLocaleWithLanguage(_ selectedLanguage: String) {
            if let pathSelected = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj"),
                let bundleSelected = Bundle(path: pathSelected)  {
                localeBundle = bundleSelected
            } else if let pathDefault = Bundle.main.path(forResource: LanguageName.en.rawValue, ofType: "lproj"),
                let bundleDefault = Bundle(path: pathDefault) {
                localeBundle = bundleDefault
            }
        }
    }
    
  2. Fügen Sie einige Regeln hinzu, um sicherzustellen, dass die UI-Komponenten immer aktualisiert werden:

    protocol Localizable {
        func localizeUI()
    }
    
  3. Implementiere sie

    class LocalizableViewController: UIViewController {
    
        // MARK: - LifeCycle
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            NotificationCenter.default.addObserver(self, selector: #selector(self.localizeUI), name: NSNotification.Name(rawValue:DynamicLanguageServiceDidDetectLanguageSwitchNotificationKey), object: nil)
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            localizeUI()
        }
    
        deinit {
            NotificationCenter.default.removeObserver(self)
        }
    }
    
    extension LocalizableViewController: Localizable {
        // MARK: - Localizable
    
        func localizeUI() {
            fatalError("Must Override to provide inApp localization functionality")
        }
    }
    
  4. Erben Sie einen beliebigen Controller, den Sie zur Anpassung der dynamischen App-Switch-Funktionalität benötigen, und implementieren Sie localizeUI() func

    final class WelcomeTableViewController: LoadableTableViewController
    
  5. Sprache nach Bedarf wechseln:

    LanguageService.service.switchToLanguage(.en)
    
  6. Alle lokalisierbaren Zeichenfolgen sollten wie folgt festgelegt werden:

    label.text = dynamicLocalizableString(<KEY_IN_STRINGS>)
    

Hinweis: Vergessen Sie nicht, Localizable.strings mit den gleichen Codes wie in LanguageName hinzuzufügen.

 enter image description here

0
gbk

Dies ist eine alte Frage, aber ich habe einen Helfer entwickelt, der mich benachrichtigt, wenn sich die Sprache spontan ändert.

Schauen Sie sich den Code des Helpers an:

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

Sie müssen nur den Code kopieren und in Ihr Projekt einfügen.

Dann implementieren Sie den Listener einfach folgendermaßen:

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
        } 

Beachten Sie, dass diese Zeile self.accountStore.languageCode.value = langCode das ist, was ich aktualisieren muss, wenn sich die App-Sprache geändert hat. Dann kann ich problemlos alle Zeichenfolgen meiner ViewModels ändern, um die Sprache sofort dem Benutzer zu ändern.

Um die Sprache zu ändern, rufen Sie einfach an:

LocalizableLanguage.setLanguage(withCode: "en")

Ein anderer Helfer, der nett zu Ihnen sein könnte, ist:

import Foundation

extension String {

    var localized: String {
        return NSLocalizedString(self, comment: "")
    }

}

Wenn Sie also in Ihren lokalisierbaren Dateien so etwas haben:

main.view.title = "Title test";

Sie können einfach anrufen:

"main.view.title".localized

Und du hast deine Saite übersetzt.

0
Pincha