web-dev-qa-db-fra.com

Localisation des chaînes dans iOS: langue par défaut (de secours)?

Existe-t-il un moyen de définir une langue par défaut à utiliser lorsque la langue de l'interface utilisateur de l'appareil n'est pas prise en charge par une application?

Exemple: mon application est localisée en anglais et en allemand:

// en.lproj:
"POWER_TO_THE_PEOPLE_BTN" = "Power";
"POWER_PLUG_BTN" = "Power";

// de.lproj:
"POWER_TO_THE_PEOPLE_BTN"  = "Macht";
"POWER_PLUG_BTN" = "Spannung";

Maintenant, si j'exécute l'application sur un appareil dont la langue de l'interface utilisateur est définie sur Italian l'application utilisera les chaînes de clés POWER_TO_THE_PEOPLE_BTN et POWER_PLUG_BTN.

Il doit exister un moyen de spécifier une langue par défaut (de secours) à utiliser par l'application dans un tel cas.

D'après l'exemple ci-dessus, il doit être clair que l'utilisation de la chaîne anglaise comme clé ne fonctionnera pas.

La seule option que je vois en ce moment est d'utiliser NSLocalizedStringWithDefaultValue au lieu de NSLocalizedString.

39
Volker Voecking

Peut-être que cela devrait aider? - iPhone: fichier de chaînes par défaut de localisation/internationalisation

Il devrait revenir à l'anglais par défaut. Je viens de passer mon téléphone dans une langue dans laquelle mon application n'est pas localisée et le texte était entièrement en anglais, comme prévu.

Important: comme l'a commenté @hyperspasm: Pour développer/reformuler cela, la langue de secours est la langue qui a été la plus récemment choisie par l'utilisateur dans les paramètres de l'appareil , qui est également représenté dans le bundle de l'application.

17
Sea Coast of Tibet

Pour éviter toute cette longue syntaxe et plus d'avoir un nom var plus descriptif pour les traducteurs, j'ai dérivé ma propre méthode d'assistance L() pour la traduction et revenir à l'anglais

NSString * L(NSString * translation_key) {
    NSString * s = NSLocalizedString(translation_key, nil);
    if (![[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:@"en"] && [s isEqualToString:translation_key]) {
    NSString * path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
    NSBundle * languageBundle = [NSBundle bundleWithPath:path];
    s = [languageBundle localizedStringForKey:translation_key value:@"" table:nil];
    }
    return s;
}

Mon Localizable.strings Ressemblerait à ceci

"SOME_ACTION_BUTTON" = "Do action";

Donc, dans mon code, j'utiliserais L(@"SOME_ACTION_BUTTON") pour obtenir la chaîne correcte

Bien que parfois la clé soit plus longue que la traduction elle-même HELP_BUTTON_IN_NAV_BAR = 'Help' Mais cela me fait gagner beaucoup de temps en expliquant ce que c'est à quiconque m'aide à faire la traduction

19
Kent Nguyen

Vous devez vous assurer que la valeur de CFBundleDevelopmentRegion dans votre Info.plist est la région linguistique que vous souhaitez utiliser. (par exemple "en")

17
Pattrawoot S.

@Bogus answer in Swift 4, fonctionne comme un charme sur iOS 11.1:

public func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String {
    let fallbackLanguage = "en"
    guard let fallbackBundlePath = Bundle.main.path(forResource: fallbackLanguage, ofType: "lproj") else { return key }
    guard let fallbackBundle = Bundle(path: fallbackBundlePath) else { return key }
    let fallbackString = fallbackBundle.localizedString(forKey: key, value: comment, table: nil)
    return Bundle.main.localizedString(forKey: key, value: fallbackString, table: nil)
}
3
Makalele

Un moyen rapide de le faire sans remplacer aucune méthode consiste à "remplacer" la définition de NSLocalizedString et à utiliser les méthodes que Apple utilise pour que cette définition la remplace et ajoute la logique de secours supplémentaire dans la méthode "remplacée".

#undef NSLocalizedString
#define NSLocalizedString(key, comment) [self localizedStringForKey:(key) replaceValue:(comment)]

+ (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment {
    NSString *fallbackLanguage = @"en";
    NSString *fallbackBundlePath = [[NSBundle mainBundle] pathForResource:fallbackLanguage ofType:@"lproj"];    
    NSBundle *fallbackBundle = [NSBundle bundleWithPath:fallbackBundlePath];
    NSString *fallbackString = [fallbackBundle localizedStringForKey:key value:comment table:nil];    
    NSString *localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:fallbackString table:nil];

    return localizedString;
}
3
Bogus

Ma solution grâce à https://stackoverflow.com/a/25928309/3664461

Global.h

NSString * LString(NSString * translation_key);

Global.m

NSString *LString(NSString *translation_key) {
  NSString *lString = nil;
  NSString *languageCode = nil;

  if ([UIDevice currentDevice].systemVersion.floatValue >= 9) {
    NSString *localeIdentifier = [[NSLocale preferredLanguages] objectAtIndex:0];
    NSDictionary *localeDic = [NSLocale componentsFromLocaleIdentifier:localeIdentifier];
    languageCode = [localeDic objectForKey:@"kCFLocaleLanguageCodeKey"];
  } else {
    languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
  }

  NSString *path = [[NSBundle mainBundle] pathForResource:languageCode ofType:@"lproj"];
  if (path != nil) {
    lString = NSLocalizedStringFromTableInBundle(translation_key, @"Localizable",
                                             [NSBundle bundleWithPath:path], @"");
  }

   path = [[NSBundle mainBundle] pathForResource:@"Base" ofType:@"lproj"];
   lString = NSLocalizedStringFromTableInBundle(translation_key, @"Localizable",
                                             [NSBundle bundleWithPath:path], @"");
  }
  return lString;
}

Usage:

#import "Global.h"
printf(LString(@"MyKey").UTF8String);

Cette solution ne prend pas en compte l'ordre de préférence des utilisateurs. Au lieu de cela, il reviendra toujours à ce que vous avez sous Base si la première langue des utilisateurs n'est pas localisée. De plus, si une clé spécifique n'est pas localisée pour la langue actuelle, mais qu'elle existe dans la localisation de base, vous obtiendrez la localisation de base.

Mettre à jour:

Depuis iOS 9, la région est incluse dans les paramètres régionaux de langue. J'ai mis à jour le code pour gérer cela.

2
Siamaster

J'ai créé la catégorie NSBundle+FallbackLanguage pour prendre en charge la langue de secours, vous pouvez le vérifier sur le dossier github . Il vous suffit de spécifier le tableau des langues prises en charge dans l'implémentation.

NSBundle + FallbackLanguage.h

#import <Foundation/Foundation.h>

#undef NSLocalizedString
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] localizedStringForKey:(key) replaceValue:(comment)]

@interface NSBundle (FallbackLanguage)

- (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment;

@end

NSBundle + FallbackLanguage.m

#import "NSBundle+FallbackLanguage.h"

@implementation NSBundle (FallbackLanguage)

- (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment {        
    NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
    NSString *localizedString;

    if ([@[@"en", @"de", @"fr"] containsObject:language]){
        localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil];
    }
    else{
        NSString *fallbackLanguage = @"en";
        NSString *falbackBundlePath = [[NSBundle mainBundle] pathForResource:fallbackLanguage ofType:@"lproj"];
        NSBundle *fallbackBundle = [NSBundle bundleWithPath:falbackBundlePath];
        NSString *fallbackString = [fallbackBundle localizedStringForKey:key value:comment table:nil];
        localizedString = fallbackString;
    }

    return localizedString;
}

@end
1
beryllium

Ancien problème, mais toujours persistant.

Nous voici avec un Swift 4.2 solution rapide pour forcer l'application sur un WHATEVER_THE_FALLBACK_LANGUAGE_WE_WANT_IT_TO_BE se retirer.

L'exemple force à "en"

extension String {

  var localized: String {

    var preferred = "-"
    if let pl = NSLocale.preferredLanguages.first, let pref = pl.split(separator: "-").first { preferred = String(pref) } //<- selected device language or "-"

    guard let _ = Bundle.main.path(forResource: preferred, ofType: "lproj") else {
        //PREFERRED ISN'T LISTED. FALLING BACK TO EN
        guard let en_path = Bundle.main.path(forResource: "en", ofType: "lproj"), let languageBundle = Bundle(path: en_path) else {
            //EN ISN'T LISTED. RETURNING UNINTERNATIONALIZED STRING
            return self
        }
        //EN EXISTS
        return languageBundle.localizedString(forKey: self, value: self, table: nil)
    }
    //PREFERRED IS LISTED. STRAIGHT I18N IS OKAY
    return NSLocalizedString(self, comment: "")
  }

}
0
Dome Santoro

Basé sur la solution Bodus (thx btw.), J'ai créé cette catégorie car vous avez également besoin de la "fallbackString". Je dois donc vérifier la langue actuellement sélectionnée de l'appareil et la comparer avec mes langues que je souhaite prendre en charge. Importez simplement l'en-tête et vous pouvez utiliser la macro par défaut des pommes

NSString *myString = NSLocalizedString(@"My Ub0rstring", nil);

Fonctionne très bien sur iOS 9.x et 11.1.

NSString + Helper.h

#import <Foundation/Foundation.h>

#undef NSLocalizedString
#define NSLocalizedString(key, comment) [NSString localizedStringForKey:(key) replaceValue:(comment)]

@interface NSString (Helper)

+ (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment;

@end


NSString + Helper.m

#import "NSString+Helper.h"

@implementation NSString (Helper)

+ (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment
{
    NSString *fallbackLanguage      = @"en";
    NSString *fallbackBundlePath    = [[NSBundle mainBundle] pathForResource:fallbackLanguage ofType:@"lproj"];
    NSBundle *fallbackBundle        = [NSBundle bundleWithPath:fallbackBundlePath];
    NSString *fallbackString        = [fallbackBundle localizedStringForKey:key value:comment table:nil];
    NSString *localizedString       = [[NSBundle mainBundle] localizedStringForKey:key value:fallbackString table:nil];

    NSString *language              = [[NSLocale preferredLanguages] firstObject];
    NSDictionary *languageDic       = [NSLocale componentsFromLocaleIdentifier:language];
    NSString *languageCode          = [languageDic objectForKey:@"kCFLocaleLanguageCodeKey"];

    if ([languageCode isEqualToString:@"de"] || [languageCode isEqualToString:@"en"]) {
        return localizedString;
    }
    else {
        return fallbackString;
    }
}

@end
0
Rikco