266 votes

Comment forcer NSLocalizedString à utiliser une langue spécifique ?

Sur l'iPhone NSLocalizedString renvoie la chaîne dans la langue de l'iPhone. Est-il possible de forcer NSLocalizedString d'utiliser une langue spécifique pour que l'application dans une langue différente de celle de l'appareil ?

0 votes

Veuillez consulter ce : stackoverflow.com/a/48187049/6665075 Fonctionne comme un charme

263voto

Brian Webster Points 7516

NSLocalizedString() (et ses variantes) accèdent à la clé " AppleLanguages " dans NSUserDefaults pour déterminer quels sont les paramètres de l'utilisateur en matière de langues préférées. Cela renvoie un tableau de codes de langue, le premier étant celui défini par l'utilisateur pour son téléphone, et les suivants étant utilisés comme solutions de repli si une ressource n'est pas disponible dans la langue préférée. (sur le bureau, l'utilisateur peut spécifier plusieurs langues avec une commande personnalisée dans les préférences système).

Vous pouvez remplacer le paramètre global pour votre propre application si vous le souhaitez en utilisant la méthode setObject:forKey : pour définir votre propre liste de langues. Cette liste sera prioritaire par rapport à la valeur définie globalement et sera renvoyée à tout code de votre application qui effectue la localisation. Le code de cette méthode ressemblerait à quelque chose comme :

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate

Ainsi, l'allemand serait la langue préférée de votre application, avec l'anglais et le français comme langues de repli. Il est préférable d'appeler cette option au début du démarrage de votre application. Pour en savoir plus sur les préférences de langue/locale, cliquez ici : Sujets relatifs à la programmation de l'internationalisation : Obtenir la langue et le locale actuels

4 votes

Cela ne fonctionne pas pour moi, il utilisera la langue par défaut quoi qu'il arrive.

2 votes

Cela n'a pas fonctionné pour moi, alors j'ai utilisé, [[NSUserDefaults standardUserDefaults] setObject : [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"] ;

1 votes

Cela n'a pas fonctionné pour moi non plus, mais [[NSUserDefaults standardUserDefaults] setObject : [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"] ; a fait . (NB. vous devez redémarrer l'application pour que cela prenne effet)- Merci Panagiotis Korros ! [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"] ; pour annuler, et revenir à la langue par défaut

149voto

Gilad Points 1227

J'ai eu le même problème récemment et je ne voulais pas recommencer et rafistoler tout mon NSLocalizedString ni obliger l'application à redémarrer pour que la nouvelle langue fonctionne. Je voulais que tout fonctionne tel quel.

Ma solution était de changer dynamiquement la classe du bundle principal et d'y charger le bundle approprié :

Fichier d'en-tête

@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end

Mise en œuvre

#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

Donc, en gros, lorsque votre application démarre et avant de charger votre premier contrôleur, appelez simplement :

[NSBundle setLanguage:@"en"];

Lorsque votre utilisateur change sa langue préférée dans votre écran de paramétrage, il suffit de le rappeler :

[NSBundle setLanguage:@"fr"];

Pour revenir aux valeurs par défaut du système, passez simplement nil :

[NSBundle setLanguage:nil];

Profitez-en...

Pour ceux qui ont besoin d'une version Swift :

var bundleKey: UInt8 = 0

class AnyLanguageBundle: Bundle {

    override func localizedString(forKey key: String,
                                  value: String?,
                                  table tableName: String?) -> String {

        guard let path = objc_getAssociatedObject(self, &bundleKey) as? String,
              let bundle = Bundle(path: path) else {

            return super.localizedString(forKey: key, value: value, table: tableName)
            }

        return bundle.localizedString(forKey: key, value: value, table: tableName)
    }
}

extension Bundle {

    class func setLanguage(_ language: String) {

        defer {

            object_setClass(Bundle.main, AnyLanguageBundle.self)
        }

        objc_setAssociatedObject(Bundle.main, &bundleKey,    Bundle.main.path(forResource: language, ofType: "lproj"), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

0 votes

Une expérience dans ce domaine ? Est-ce que ça marche ? Gilad, l'utilisez-vous toujours avec succès ?

7 votes

Bonjour @Wirsing , cela fonctionne très bien pour moi jusqu'à présent. J'ai même téléchargé une application dans le magasin et aucune plainte d'Apple.

7 votes

C'est une excellente solution, je l'ai également référencée ici : medium.com/ios-apprentice/905e4052b9de

137voto

Mauro Delrio Points 943

Je procède généralement de cette manière, mais vous DEVEZ avoir tous les fichiers de localisation dans votre projet.

@implementation Language

static NSBundle *bundle = nil;

+(void)initialize 
{
    NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
    NSArray* languages = [defs objectForKey:@"AppleLanguages"];
    NSString *current = [[languages objectAtIndex:0] retain];
    [self setLanguage:current];
}

/*
  example calls:
    [Language setLanguage:@"it"];
    [Language setLanguage:@"de"];
*/
+(void)setLanguage:(NSString *)l
{
    NSLog(@"preferredLang: %@", l);
    NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:@"lproj" ];
    bundle = [[NSBundle bundleWithPath:path] retain];
}

+(NSString *)get:(NSString *)key alter:(NSString *)alternate 
{
    return [bundle localizedStringForKey:key value:alternate table:nil];
}

@end

0 votes

Joli, fonctionne parfaitement. J'ai modifié la méthode d'initialisation pour faire simplement bundle = [NSBundle mainBundle] ; à la place. De cette façon, vous n'avez pas besoin d'avoir tous les fichiers de localisation dans votre projet.

1 votes

+1. C'est une astuce vraiment sympa que je n'ai vue nulle part ailleurs. En créant un "sub bundle" à partir de l'un des dossiers de localisation, vous pouvez faire fonctionner le truc de la chaîne de caractères sans problème tant que vous enveloppez NSLocalizedString avec quelque chose qui fait un détour ici.

0 votes

Je pense que la meilleure approche consiste à utiliser [NSLocale preferredLanguages].

41voto

Tudorizer Points 2647

Ne pas utiliser sur iOS 9. Cette fonction renvoie nil pour toutes les chaînes qui lui sont passées.

J'ai trouvé une autre solution qui vous permet de mettre à jour les chaînes de langues, sans redémarrer l'application et compatible avec les genstrings :

Mettez cette macro dans le fichier Prefix.pch :

#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]

et partout où vous avez besoin d'une chaîne localisée, utilisez-la :

NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")

Pour définir la langue utilisée :

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];

Cela fonctionne même avec des sauts de langue consécutifs comme :

NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"fr"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"it"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));

2 votes

@powerj1984 : non, cela ne changera que les chaînes de caractères dans vos fichiers sources. Si vous voulez changer les langues des xibs, vous devez recharger les xibs à la main, à partir du bundle de votre langue sélectionnée.

0 votes

@gklka J'ai suivi les étapes données par Tudozier mais mes XIB ne changent pas de langue, comme vous l'avez dit recharger les XIB à la main, que signifie réellement recharger les XIB ?

0 votes

@DkKumar : Vous devez faire quelque chose de similaire à ceci : stackoverflow.com/questions/21304988/

32voto

Comme dit précédemment, il suffit de le faire :

[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];

Mais pour éviter de devoir redémarrer l'application, mettez la ligne dans la méthode principale de main.m juste avant UIApplicationMain (...).

3 votes

Réponse très utile ! P.S. Cela peut sembler évident pour les non-initiés, mais vous devriez insérer cette ligne après NSAutoreleasePool * pool .. ou quelques objets autoreliés vont fuir.

1 votes

IMPORTANT : Cela ne fonctionnera pas si vous appelez [[NSBundle mainBundle] URLForResource:withExtension:] avant.

3 votes

Et si, en utilisant Swift, il n'y a pas de main.m ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X