web-dev-qa-db-fra.com

Comment forcer NSLocalizedString à utiliser un langage spécifique

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

257
CodeFlakes

NSLocalizedString() (et ses variantes) accédez à la touche "AppleLanguages" dans NSUserDefaults pour déterminer les paramètres définis par l'utilisateur pour les langues préférées. Cela retourne un tableau de codes de langue, le premier étant celui défini par l'utilisateur pour son téléphone, et les suivants utilisés comme solutions de secours 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 de votre propre application si vous le souhaitez en utilisant la méthode setObject: forKey: pour définir votre propre liste de langues. Cela aura priorité sur la valeur définie globalement et sera renvoyé à tout code de votre application qui effectue la localisation. Le code pour cela ressemblerait à quelque chose comme:

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

Cela ferait de l'allemand la langue préférée pour votre application, avec l'anglais et le français comme substituts. Vous voudrez peut-être appeler cela tôt dans le démarrage de votre application. Vous pouvez en savoir plus sur les préférences de langue/paramètres régionaux ici: Sujets de programmation pour l’internationalisation: Obtenir la langue et les paramètres régionaux actuels

254
Brian Webster

J'ai eu le même problème récemment et je ne voulais pas démarrer et mettre à jour ma totalité NSLocalizedString, ni forcer l'application à redémarrer pour que la nouvelle langue fonctionne. Je voulais que tout fonctionne tel quel.

Ma solution consistait à modifier de manière dynamique la classe du bundle principal et à y charger le bundle approprié:

fichier d'en-tête

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

Mise en oeuvre

#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 configuration, appelez-la simplement à nouveau:

[NSBundle setLanguage:@"fr"];

Pour revenir aux valeurs par défaut du système, il suffit de passer nil:

[NSBundle setLanguage:nil];

Prendre plaisir...

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)
    }
}
142
Gilad Novik

Je le fais habituellement de cette façon, 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
137
Mauro Delrio

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

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

Placez 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:

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

Pour définir l'utilisation de la langue:

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

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, @""));
41
Tudor

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

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

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

31
Frédéric Feytons

L'astuce pour utiliser un langage spécifique en le sélectionnant dans l'application consiste à forcer le NSLocalizedString à utiliser un ensemble spécifique en fonction de la langue sélectionnée.

voici le post que j'ai écrit pour cela apprentissage de la localisation avancée dans les applications ios

et voici le code d'un exemple d'application localisation avancée dans les applications ios

31
object2.0

Comme Brian Webster le mentionne, la langue doit être définie "tôt dans le démarrage de votre application". Je pensais que applicationDidFinishLaunching: of AppDelegate devrait être un endroit approprié pour le faire, car c'est là que je fais toutes les autres initialisations.

Mais, comme le mentionne William Denniss, cela ne semble avoir un effet que après l'application est relancée, ce qui est un peu inutile.

Cela semble fonctionner correctement si je mets le code dans la fonction principale, cependant:

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Force language to Swedish.
    [[NSUserDefaults standardUserDefaults]
     setObject:[NSArray arrayWithObject:@"sv"]
     forKey:@"AppleLanguages"];

    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

J'apprécierais vos commentaires à ce sujet.

12
geon

Que pensez-vous de cette solution pour Swift 3?

extension String {

    func localized(forLanguage language: String = Locale.preferredLanguages.first!.components(separatedBy: "-").first!) -> String {

        guard let path = Bundle.main.path(forResource: language == "en" ? "Base" : language, ofType: "lproj") else {

            let basePath = Bundle.main.path(forResource: "Base", ofType: "lproj")!

            return Bundle(path: basePath)!.localizedString(forKey: self, value: "", table: nil)
        }

        return Bundle(path: path)!.localizedString(forKey: self, value: "", table: nil)
    }
}

Utilisation simple:

"report".localized(forLanguage: "pl") //forced language
"report".localized() //default language selected by user in settings, in case when your app doesnt support selected lanaguage, the default one is selected, here is an english.
12

NSLocalizedString() lit la valeur de la touche AppleLanguages à partir des valeurs utilisateur par défaut ([NSUserDefaults standardUserDefaults]). Il utilise cette valeur pour choisir une localisation appropriée parmi toutes les localisations existantes au moment de l'exécution. Lorsque Apple crée le dictionnaire par défaut de l'utilisateur au lancement de l'application, il recherche la clé de langue préférée dans les préférences système et copie la valeur à partir de celle-ci. Cela explique également, par exemple, pourquoi la modification des paramètres de langue dans OS X n’a aucun effet sur les applications en cours d’exécution, mais uniquement sur les applications lancées par la suite. Une fois copiée, la valeur n'est pas mise à jour simplement parce que les paramètres changent. C'est pourquoi iOS redémarre toutes les applications si vous changez de langue.

Cependant, toutes les valeurs du dictionnaire des paramètres utilisateur par défaut peut être remplacé par des arguments de ligne de commande. Voir la documentation NSUserDefaults sur le NSArgumentDomain. Cela inclut même les valeurs chargées à partir du fichier de préférences d'application (.plist). C'est vraiment bon à savoir si vous voulez changer une valeur une fois pour le test.

Donc, si vous voulez changer la langue juste pour le test, vous ne voudrez probablement pas modifier votre code (si vous oubliez de supprimer ce code plus tard ...), mais demandez à Xcode de démarrer votre application avec des paramètres de ligne de commande ( par exemple, utiliser la localisation en espagnol):

enter image description here

Pas besoin de toucher votre code du tout. Créez simplement des schémas différents pour différentes langues et vous pouvez démarrer rapidement l'application une fois dans une langue et une fois dans une autre en basculant simplement le schéma.

11
Mecki

J'aime la meilleure méthode de Mauro Delrio. J'ai aussi ajouté ce qui suit dans mon Project_Prefix.pch

#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]

Ainsi, si vous souhaitez utiliser la méthode standard (qui utilise NSLocalizedString), vous pouvez effectuer une substitution de syntaxe rapide dans tous les fichiers.

11
dnaxxx

Je suis venu avec une solution qui vous permet d'utiliser NSLocalizedString. Je crée une catégorie de NSBundle appel NSBundle+RunTimeLanguage. L'interface est comme ça.

// NSBundle+RunTimeLanguage.h
#import <Foundation/Foundation.h>
@interface NSBundle (RunTimeLanguage)
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:@"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
@end

La mise en œuvre est comme ça.

// NSBundle+RunTimeLanguage.m
#import "NSBundle+RunTimeLanguage.h"
#import "AppDelegate.h"

@implementation NSBundle (RunTimeLanguage)

- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSString *path= [[NSBundle mainBundle] pathForResource:[appDelegate languageCode] ofType:@"lproj"];
    NSBundle *languageBundle = [NSBundle bundleWithPath:path];
    NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
    return localizedString;
}
@end

Il suffit ensuite d’ajouter import NSBundle+RunTimeLanguage.h dans les fichiers utilisant NSLocalizedString.

Comme vous pouvez le voir, je stocke mon languageCode dans une propriété de AppDelegate. Cela pourrait être stocké où vous le souhaitez.

La seule chose que je n'aime pas à ce sujet est un avertissement que NSLocalizedString marco redéfini. Peut-être que quelqu'un pourrait m'aider à réparer cette partie.

10
qman64

Version rapide:

NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()
9
daaniaal

En un mot :

Localisez votre application

La première chose à faire est de localiser votre application en au moins deux langues (anglais et français dans cet exemple).

Ignorer NSLocalizedString

Dans votre code, au lieu d'utiliser NSLocalizedString(key, comment), utilisez une macro MYLocalizedString(key, comment) définie comme suit: #define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

Ce singleton MYLocalizationSystem:

  • Définissez la langue en définissant le droit utilisateur NSBundle localisé qui est demandé
  • Retourne le NSString localisé en fonction de la langue précédemment définie

Définir la langue de l'utilisateur

Lorsque l'utilisateur change de langue d'application en français, appelez [[MYLocalizationSystem sharedInstance] setLanguage:@"fr"];

- (void)setLanguage:(NSString *)lang
{
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj"];
    if (!path)
    {
        _bundle = [NSBundle mainBundle];
        NSLog(@"Warning: No lproj for %@, system default set instead !", lang);
        return;
    }

    _bundle = [NSBundle bundleWithPath:path];
}

Dans cet exemple , cette méthode définit le bundle localisé sur fr.lproj

Retourne la chaîne localisée

Une fois que vous avez défini le paquet localisé, vous pourrez obtenir la bonne chaîne localisée auprès de lui avec cette méthode:

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value
{
    // bundle was initialized with [NSBundle mainBundle] as default and modified in setLanguage method
    return [self.bundle localizedStringForKey:key value:value table:nil];
}

J'espère que cela vous aidera.

Vous trouverez plus de détails dans cet article de NSWinery.io

8
user3465357

Swift 3 extensions:

extension Locale {
    static var preferredLanguage: String {
        get {
            return self.preferredLanguages.first ?? "en"
        }
        set {
            UserDefaults.standard.set([newValue], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
        }
    }
}

extension String {
    var localized: String {

    var result: String

    let languageCode = Locale.preferredLanguage //en-US

    var path = Bundle.main.path(forResource: languageCode, ofType: "lproj")

    if path == nil, let hyphenRange = languageCode.range(of: "-") {
        let languageCodeShort = languageCode.substring(to: hyphenRange.lowerBound) // en
        path = Bundle.main.path(forResource: languageCodeShort, ofType: "lproj")
    }

    if let path = path, let locBundle = Bundle(path: path) {
        result = locBundle.localizedString(forKey: self, value: nil, table: nil)
    } else {
        result = NSLocalizedString(self, comment: "")
    }
        return result
    }
}

tilisation:

Locale.preferredLanguage = "uk"

label.text = "localizedKey".localized
6
ChikabuZ

Peut-être devriez-vous compléter avec ceci (sur le fichier .pch après #import):

extern NSBundle* bundle; // Declared on Language.m

#ifdef NSLocalizedString
    #undef NSLocalizedString
    // Delete this line to avoid warning
    #warning "Undefining NSLocalizedString"
#endif

#define NSLocalizedString(key, comment) \
    [bundle localizedStringForKey:(key) value:@"" table:nil]
4
D33pN16h7

Dans le fichier . Pch pour définir:

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


#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
4
MrPiliffo

Swift 3 solution:

let languages = ["bs", "zh-Hant", "en", "fi", "ko", "lv", "ms", "pl", "pt-BR", "ru", "sr-Latn", "sk", "es", "tr"]
UserDefaults.standard.set([languages[0]], forKey: "AppleLanguages")

Donné quelques exemples de codes de langue qui peuvent être utilisés. J'espère que cela t'aides

3
Jeremy Bader

Vous pouvez créer un sous-ensemble avec l'ensemble de chaînes localisées avec lesquelles vous souhaitez effectuer cette opération, puis utiliser NSLocalizedStringFromTableInBundle() pour les charger. (Je suppose qu'il s'agit d'un contenu distinct de la localisation de l'interface utilisateur normale que vous pourriez effectuer sur l'application.)

3
Sixten Otto

pour mon cas j'ai deux fichier localisé, ja et en

et je voudrais le forcer à en si la langue préférée dans le système ni en ni ja

je vais éditer le fichier main.m

je vérifierai si la première langue préférée est en ou ja, sinon, je changerai la deuxième langue préférée en en.

int main(int argc, char *argv[])
{

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults] synchronize];

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

    if (![lang isEqualToString:@"en"]  &&  ![lang isEqualToString:@"ja"]){

        NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[NSLocale preferredLanguages]];
        [array replaceObjectAtIndex:1 withObject:@"en"];

        [[NSUserDefaults standardUserDefaults] setObject:array forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults] synchronize];


    }

    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));


    }


}
3
chings228

Basé sur réponse de Tudorizer pour changer de langue sans quitter ou redémarrer l'application.

Au lieu d'une macro, utilisez une classe pour accéder à la langue préférée afin de vérifier si un code de langue spécifique est présent.

Vous trouverez ci-dessous une classe utilisée pour obtenir le groupe de langues actuel qui fonctionne pour iOS 9:

@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

Utilisez la classe ci-dessus pour référencer un fichier chaîne/image/video/etc:

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

Changez de langue en ligne comme ci-dessous ou mettez à jour la méthode "changeCurrentLanguage" de la classe ci-dessus pour prendre un paramètre de chaîne faisant référence à la nouvelle langue.

[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
2
Antonioni

Vous pouvez faire quelque chose comme ça:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];


NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];

NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
2
JERC

Dans Swift 4, je l'ai résolu sans qu'il soit nécessaire de redémarrer ou d'utiliser des bibliothèques.

Après avoir essayé de nombreuses options, j’ai trouvé cette fonction dans laquelle vous passez la chaîne stringToLocalize (de Localizable.String, le fichier de chaînes) que vous voulez traduire, ainsi que la langue dans laquelle vous voulez la traduire et la valeur renvoyée. cette chaîne que vous avez dans le fichier Strings:

    func localizeString (stringToLocalize: String, language: String) -> String
    {
        let path = Bundle.main.path (forResource: language, ofType: "lproj")
        let languageBundle = Bundle (path: path!)
        return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
    }

Tenant compte de cette fonction, j'ai créé cette fonction dans un fichier Swift:

struct CustomLanguage {

    func createBundlePath () -> Bundle {
        let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
        let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
        return Bundle(path: path!)!
    }
}

Pour accéder à l'ensemble de l'application et à chaque chaîne du reste de ViewControllers, au lieu de mettre:

NSLocalizedString ("StringToLocalize", comment: “")

Je l'ai remplacé par

let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()

NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String

Je ne sais pas si c'est le meilleur moyen, mais j'ai trouvé cela très simple et cela fonctionne pour moi, j'espère que cela vous aide!

1
ainareta685

Je voulais ajouter une prise en charge pour une langue qui n'est pas officiellement prise en charge par iOS (non répertoriée dans la section Langue sous les paramètres système). En suivant le didacticiel d’internationalisation d’Apple et quelques conseils de Brian Webster et de Geon, j’ai créé ce morceau de code (mettez-le dans main.m):

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // Grab regional settings locale, for Slovenian this is either sl_SI or en_SI
        NSLocale *locale = [NSLocale currentLocale];
        NSString *ll = [locale localeIdentifier]; // sl_SI

        // Grab the first part of language identifier
        NSArray *comp = [ll componentsSeparatedByString:@"_"];
        NSString *ll1 = @"en";
        if (comp.count > 0) {
            ll1 = comp[0]; // sl, en, ...
        }
        // Check if we already saved language (user can manually change it inside app for example)
        if (![[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"]) {
            //   Slovenian (Slovenia),            Slovenia
            if ([ll isEqualToString:@"sl_SI"] || [ll isEqualToString:@"en_SI"]) {
                ll1 = @"sl-SI"; // This is the part of localized path for Slovenian language that Xcode generates
            }
            // Add more unsupported languages here...

            [[NSUserDefaults standardUserDefaults] setObject:ll1 forKey:@"SelectedLanguage"]; // Save language
        }
        else {
            // Restore language as we have previously saved it
            ll1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"];
        }
        // Overwrite NSLocalizedString and StoryBoard language preference
        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:ll1, @"en", @"fr", nil] forKey:@"AppleLanguages"];
        // Make sure settings are stored to disk
        [[NSUserDefaults standardUserDefaults] synchronize];

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

Cela fonctionne bien pour le code Storyboard et le code NSLocalizedString. Le code suppose que l'utilisateur aura la possibilité de changer manuellement de langue ultérieurement dans l'application.

Bien sûr, n'oubliez pas d'ajouter les traductions appropriées de Storyboard et de Localizable.strings (voir le lien vers la page Apple ci-dessus pour savoir comment procéder).

1
frin

Cette fonction essaiera d’obtenir la chaîne localisée pour la langue courante et si elle n’est pas trouvée, elle l’utilisera en anglais.

- (NSString*)L:(NSString*)key
{
    static NSString* valueNotFound = @"VALUE_NOT_FOUND";
    static NSBundle* enBundle = nil;

    NSString* pl = [NSLocale preferredLanguages][0];
    NSString* bp = [[NSBundle mainBundle] pathForResource:pl ofType:@"lproj"];
    NSBundle* b = [NSBundle bundleWithPath:bp];

    NSString* s = [b localizedStringForKey:key value:valueNotFound table:nil];
    if ( [s isEqualToString:valueNotFound] ) {
        if ( !enBundle ) {
            bp = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
            enBundle = [NSBundle bundleWithPath:bp];
        }
        s = [enBundle localizedStringForKey:key value:key table:nil];
    }

    return s;
}
1
Cherpak Evgeny

Voici une solution décente pour ce problème, et il ne nécessite pas de redémarrage de l'application.

https://github.com/cmaftuleac/BundleLocalization

Cette implémentation fonctionne en peaufinant l'intérieur de NSBundle. L'idée est que vous substituez la méthode localizedStringForKey sur l'instance de l'objet NSBundle, puis appelez cette méthode sur un groupe différent avec un langage différent. Simple et élégant, entièrement compatible avec tous les types de ressources.

1
Corneliu Maftuleac

quoi que vous fassiez, le meilleur moyen est de prendre le nom court pour la langue spécifiée, c'est-à-dire: fr, en, nl, de, it, etc ... et d'affecter la même chose à une valeur globale.

faites apparaître une vue de sélecteur sous forme de menu déroulant (combinaison d’un bouton au clic duquel apparaît une vue de sélecteur avec une liste de langues) et sélectionnez la langue de votre choix. laissez le nom abrégé être stocké en interne. créez un fichier .h + .m nommé LocalisedString.

Définissez la valeur globale de short_name sur la valeur obtenue dans LocalisedString.m. Lorsque la langue requise est sélectionnée, affectez NSBundlePath afin de créer des sous-répertoires de projet pour la langue requise. par exemple, nl.proj, en.proj.

Lorsque le dossier proj particulier est sélectionné, appelez la chaîne localisée correspondant à la langue et modifiez-la de manière dynamique.

pas de règles brisées.

0
Abhijeet

Pour Swift, vous pouvez remplacer le fichier main.Swift et définir la chaîne UserDefaults avant l’exécution de l’application. De cette façon, vous n'avez pas à redémarrer l'application pour voir l'effet souhaité.

import Foundation
import UIKit

// Your initialisation code here
let langCultureCode: String = "LANGUAGE_CODE"

UserDefaults.standard.set([langCultureCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()

UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))

couplé avec la suppression de @UIApplicationMain dans votre fichier AppDelegate.Swift.

0
Andreas