multi - Localizar cadenas en iOS: ¿lenguaje predeterminado(alternativo)?
xcode add localization (8)
¿Hay alguna manera de establecer un idioma predeterminado para usar cuando el idioma de la interfaz de usuario del dispositivo no es compatible con una aplicación?
Ejemplo: mi aplicación está traducida al inglés y al alemán:
// en.lproj:
"POWER_TO_THE_PEOPLE_BTN" = "Power";
"POWER_PLUG_BTN" = "Power";
// de.lproj:
"POWER_TO_THE_PEOPLE_BTN" = "Macht";
"POWER_PLUG_BTN" = "Spannung";
Ahora, si ejecuto la aplicación en un dispositivo con el idioma de la interfaz de usuario configurado en Italian
la aplicación utilizará las cadenas de teclas POWER_TO_THE_PEOPLE_BTN
y POWER_PLUG_BTN
.
Debe haber una forma de especificar un idioma predeterminado (de respaldo) para ser utilizado por la aplicación en tal caso.
En el ejemplo anterior, debe quedar claro que usar la cadena en inglés como clave no funcionará.
La única opción que veo ahora es usar NSLocalizedStringWithDefaultValue
lugar de NSLocalizedString
.
@Bogus answer en Swift 4, funciona como un encanto en 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)
}
Basado en la solución de Bodus (por cierto, por cierto). Creé esta categoría porque también necesitas la "cadena de respaldo". Así que tengo que verificar el idioma seleccionado actual del dispositivo y compararlo con mis idiomas que quiero admitir. Solo importa el encabezado y puedes usar manzanas macro por defecto
NSString *myString = NSLocalizedString(@"My Ub0rstring", nil);
Funciona bien en iOS 9.xy 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
Debe asegurarse de que el valor de CFBundleDevelopmentRegion en Info.plist sea la región de idioma a la que le gustaría recurrir. (por ejemplo, "en")
Mi solución gracias a https://.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;
}
Uso:
#import "Global.h"
printf(LString(@"MyKey").UTF8String);
Esta solución no tiene en cuenta el orden de preferencia de los usuarios. En lugar de eso, siempre será una alternativa a lo que tienes en Base si el primer idioma de los usuarios no está localizado. Además, si una clave específica no está localizada para el idioma actual, pero existe en la ubicación básica, obtendrá la localización base.
Actualizar:
Desde iOS 9, la región está incluida en las configuraciones regionales de idioma. Actualicé el código para manejar eso.
Para evitar toda esa sintaxis larga y tener un nombre var más descriptivo para los traductores, obtuve mi propio método auxiliar L()
para traducirlo y volver al inglés.
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;
}
Mi Localizable.strings
se vería así
"SOME_ACTION_BUTTON" = "Do action";
Entonces en mi código, usaría L(@"SOME_ACTION_BUTTON")
para obtener la cadena correcta
Aunque en algún momento la clave es más larga que la traducción en sí HELP_BUTTON_IN_NAV_BAR = ''Help''
pero me ahorra mucho tiempo explicar lo que es para quien me está ayudando a hacer la traducción
Tal vez esto debería ayudar? - iPhone: archivo de cadenas por defecto de localización / internacionalización
Debería retroceder al inglés por defecto. Acabo de cambiar mi teléfono a un idioma en el que mi aplicación no está traducida, y el texto estaba en inglés, como se esperaba.
Importante: como @hyperspasm comentó: para expandir / reformular esto, el idioma alternativo es el idioma que el usuario eligió más recientemente en la Configuración del dispositivo, que también está representado en el paquete de la aplicación.
Una forma rápida de hacerlo sin reemplazar ningún método es "anular" la definición de NSLocalizedString y usar los métodos que usa Apple para definir para reemplazarlo y agregar la lógica de repliegue adicional en el método "reemplazado".
#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;
}
NSBundle+FallbackLanguage
categoría NSBundle+FallbackLanguage
para admitir el lenguaje alternativo, puedes consultarlo en la carpeta github . Solo necesita especificar la matriz de idiomas admitidos en la implementación.
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