it-swarm.com.de

Ändern Sie die App-Sprache in iOS, ohne die App neu zu starten

Ich habe den Eindruck, dass einige Apps die Sprache intern innerhalb der App ändern können, ohne die App neu starten zu müssen. Ich frage mich, wie sie implementiert werden.

Für uns beispielsweise, dass wir NSLocalizedString verwenden, ist es möglich, die Sprache zur Laufzeit um main.m einzustellen, wenn Ihre AppDelegate nicht initialisiert ist. Sobald sie jedoch initialisiert ist (insbesondere Ihr View-Controller wird erstellt), wirkt sich die Änderung erst beim nächsten aus Neustart

[[NSUserDefaults standardUserDefaults] 
    setObject:[NSMutableArray arrayWithObjects:language, nil] 
    forKey:@"AppleLanguages"];

Hat jemand eine Idee, wie diese dynamische Sprachänderung ohne Neustart der App durchgeführt werden kann?

29
Ryan

Es gibt einige Diskussionen über andere Ansätze, insbesondere einen auf Benachrichtigungen basierenden Ansatz:

iOS: Wie kann ich die Sprache der App programmgesteuert ändern, OHNE die App neu starten?

Aus meiner Sicht gibt es hier wirklich drei Aufgaben: (1) Neulokalisierung von Ressourcen, die automatisch aus Spitzen geladen werden. (Wenn Sie beispielsweise eine andere benutzerdefinierte UIView von einer Spitze dynamisch instanziieren, werden die "alten" Sprachzeichenfolgen und Einstellungen (Bilder, Textrichtung) weiterhin geladen.) (2) Neulokalisierung der aktuell auf dem Bildschirm angezeigten Zeichenfolgen. (3) Neulokalisierung von Zeichenfolgen, die vom Entwickler (Sie) in den Programmcode eingefügt wurden.

Beginnen wir mit (3). Wenn Sie nach der Definition suchen, werden Sie feststellen, dass NSLocalizedString ein Makro ist. Wenn Sie also den vorhandenen Code nicht zu sehr ändern möchten, können Sie das Problem (3) wahrscheinlich lösen, indem Sie eine neue Header-Datei erstellen. In dieser Headerdatei #undef und dann erneut -#define NSLocalizedString, um die lokalisierte Zeichenfolge an der entsprechenden Stelle auszuwählen - nicht diejenige, die von iOS standardmäßig verwendet wird, sondern eine, die Sie in einer globalen Variablen nachverfolgen (z. B. in einem Delegatenfeld einer App). . Wenn Sie NSLocalizedString nicht neu definieren möchten, aber dennoch eine eigene Alternative verwenden, sollten Sie wahrscheinlich #undef NSLocalizedString verwenden, wenn zukünftige Entwickler es nicht versehentlich anstelle des Makros möchten, mit dem Sie es ersetzen. Keine ideale Lösung, aber vielleicht die praktischste.

Was (1) betrifft, wenn Sie Ihre Lokalisierung nicht im Interface Builder durchgeführt haben, sondern dynamisch in viewDidLoad usw., kein Problem. Sie können dasselbe Verhalten verwenden, das Sie gerade besprochen haben (d. H. Der modifizierte NSLocalizedString usw.). Ansonsten können Sie entweder (a) ein Benachrichtigungssystem wie oben beschrieben implementieren (kompliziert) oder (b) die Lokalisierung von IB nach viewDidLoad verschieben oder (c) versuchen, initWithNibName: zu überschreiben und das mit der alten Sprache geladene Objekt auszutauschen Ressourcen, wobei eine mit den neuen Sprachressourcen geladen ist. Dieser Ansatz wurde von Mohamed ganz unten in dieser Diskussion erwähnt: http://learning-ios.blogspot.ca/2011/04/advance-localization-in-ios-apps.html . Er behauptet, es verursacht Probleme (viewDidLoad wird nicht aufgerufen). Selbst wenn es nicht funktioniert, können Sie es ausprobieren, wenn Sie es ausprobieren.

Schließlich ist (2) vermutlich die einfachste Aufgabe: Entfernen Sie einfach die aktuelle Ansicht und fügen Sie sie erneut hinzu (oder zeichnen Sie sie in einigen Fällen einfach neu).

5
Merk

die Idee ist, ein neues Makro wie NSLocalizedString zu schreiben, das prüfen soll, ob die Übersetzung aus einem anderen spezifischen Bündel übernommen wird oder nicht.

Die Methode 2 in diesem Artikel erklären genau, wie es geht .. _ In diesem speziellen Fall verwendet der Autor kein neues Makro, sondern direkt set eine benutzerdefinierte Klasse für [NSBundle mainBundle].

Ich hoffe, dass @holex das Problem beim Lesen dieser Datei verstehen wird.

2
Matteo Gobbi

Meine Implementierung verwendet eine Klasse, um die Sprache zu ändern und auf das aktuelle Sprachpaket zuzugreifen. Dies ist ein Beispiel. Wenn Sie andere Sprachen als ich verwenden würden, ändern Sie die Methoden, um Ihre genauen Sprachcodes zu verwenden.

Diese Klasse greift über NSLocale auf die bevorzugten Sprachen zu und übernimmt das erste Objekt, das die verwendete Sprache ist.

@implementation OSLocalization

+ (NSBundle *)currentLanguageBundle
{
    // Default language incase an unsupported language is found
    NSString *language = @"en";

    if ([NSLocale preferredLanguages].count) {
        // Check first object to be of type "en","es" etc
        // Codes seen by my eyes: "en-US","en","es-US","es" etc

        NSString *letterCode = [[NSLocale preferredLanguages] objectAtIndex:0];

        if ([letterCode rangeOfString:@"en"].location != NSNotFound) {
            // English
            language = @"en";
        } else if ([letterCode rangeOfString:@"es"].location != NSNotFound) {
            // Spanish
            language = @"es";
        } else if ([letterCode rangeOfString:@"fr"].location != NSNotFound) {
            // French
            language = @"fr";
        } // Add more if needed
    }

    return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]];
}

/// Check if preferred language is English
+ (BOOL)isCurrentLanguageEnglish
{
    if (![NSLocale preferredLanguages].count) {
        // Just incase check for no items in array
        return YES;
    }

    if ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:@"en"].location == NSNotFound) {
        // No letter code for english found
        return NO;
    } else {
        // Tis English
        return YES;
    }
}

/*  Swap language between English & Spanish
 *  Could send a string argument to directly pass the new language
 */
+ (void)changeCurrentLanguage
{
    if ([self isCurrentLanguageEnglish]) {
        [[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
    } else {
        [[NSUserDefaults standardUserDefaults] setObject:@[@"en"] forKey:@"AppleLanguages"];
    }
}
@end

Verwenden Sie die Klasse oben, um auf eine String-Datei/image/video/etc zu verweisen:

// Access a localized image
[[OSLocalization currentLanguageBundle] pathForResource:@"my_image_name.png" ofType:nil]
// Access  a localized string from Localizable.strings file
NSLocalizedStringFromTableInBundle(@"StringKey", nil, [OSLocalization currentLanguageBundle], @"comment")

Ändern Sie die Sprache wie unten beschrieben, oder aktualisieren Sie die Methode "changeCurrentLanguage" in der obigen Klasse, um einen String-Parameter zu verwenden, der auf den neuen Sprachcode verweist.

// Change the preferred language to Spanish
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
1
Antonioni

Ich benutze immer diesen Weg, es funktioniert perfekt, es könnte auch Ihnen helfen.


sie sollten alle Texte mit NSLocalizableString(...) für die UI für die aktuelle Sprache in der -viewWillAppear:-Methode Ihrer UIViewController setzen.

auf diese Weise können Sie (ich meine die Benutzer) nicht neu starten die Anwendung nach dem Ändern der Sprache von iOS in den Einstellungen.


natürlich verwende ich die Standard-Lokalisierungsarchitektur von Apple.

AKTUALISIERUNG am (24 Okt 2013)

Ich habe erfahren, dass die –viewWillAppear:-Methode für die tatsächliche Ansicht nicht ausgeführt wird, wenn die Anwendung in den Vordergrund tritt. Um dieses Problem zu lösen, verpflichte ich mich auch zum Verfahren (siehe oben), wenn in der Ansicht eine UIApplicationWillEnterForegroundNotification-Benachrichtigung angezeigt wird.

1
holex

Ich war in derselben Ausgabe stecken geblieben, meine Forderung lautete: "Der Benutzer kann die Sprache aus Dropdown auswählen und die Anwendung muss entsprechend der ausgewählten Sprache (Englisch oder Arabisch) arbeiten." Auf diese Weise kann der Benutzer die Sprache auswählen. Ich habe NSBundle dafür benutzt. mögen 

Für XIB

self.homeScreen =  [[HomeScreen alloc] initWithNibName:@"HomeScreen" bundle:[CommonData sharedCommonData].languageBundle];

Für Text 

_lblHeading.text = [self languageSelectedStringForKey:@"ViewHeadingInfo"];

/**
 This method is responsible for selecting language bundle according to user's selection. 
 @param: the string which is to be converted in selected language. 
 @return: the converted string.
 @throws:
 */

-(NSString*) languageSelectedStringForKey:(NSString*) key

{

    NSString* str=[[CommonData sharedCommonData].languageBundle localizedStringForKey:key value:@"" table:nil];

    return str;

}
0
Mangesh