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
.
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.
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
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")
@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)
}
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;
}
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.
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
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: "")
}
}
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