En iPhone, NSLocalizedString
devuelve la cadena en el idioma del iPhone. ¿Es posible forzar el NSLocalizedString
uso de un idioma específico para tener la aplicación en un idioma diferente al del dispositivo?
En iPhone, NSLocalizedString
devuelve la cadena en el idioma del iPhone. ¿Es posible forzar el NSLocalizedString
uso de un idioma específico para tener la aplicación en un idioma diferente al del dispositivo?
Respuestas:
NSLocalizedString()
(y sus variantes) acceda a la clave "AppleLanguages" NSUserDefaults
para determinar cuáles son las configuraciones del usuario para los idiomas preferidos. Esto devuelve una serie de códigos de idioma, siendo el primero el establecido por el usuario para su teléfono y los siguientes utilizados como retrocesos si un recurso no está disponible en el idioma preferido. (en el escritorio, el usuario puede especificar varios idiomas con un pedido personalizado en Preferencias del sistema)
Puede anular la configuración global para su propia aplicación si lo desea utilizando el método setObject: forKey: para configurar su propia lista de idiomas. Esto tendrá prioridad sobre el valor establecido globalmente y se devolverá a cualquier código en su aplicación que esté realizando la localización. El código para esto se vería así:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
Esto haría que el alemán sea el idioma preferido para su aplicación, con inglés y francés como respaldo. Debería llamar a esto en algún momento temprano en el inicio de su aplicación. Puede leer más sobre las preferencias de idioma / idioma aquí: Temas de programación de internacionalización: Obtener el idioma y el idioma actuales
Tuve el mismo problema recientemente y no quería comenzar y parchear todo mi NSLocalizedString ni forzar la aplicación a reiniciarse para que el nuevo idioma funcione. Quería que todo funcionara como está.
Mi solución fue cambiar dinámicamente la clase del paquete principal y cargar el paquete apropiado allí:
Archivo de cabecera
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
Implementación
#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
Básicamente, cuando su aplicación se inicia y antes de cargar su primer controlador, simplemente llame:
[NSBundle setLanguage:@"en"];
Cuando su usuario cambie su idioma preferido en la pantalla de configuración, simplemente vuelva a llamarlo:
[NSBundle setLanguage:@"fr"];
Para restablecer los valores predeterminados del sistema, simplemente pase nil:
[NSBundle setLanguage:nil];
Disfrutar...
Para aquellos que necesitan una versión 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)
}
}
Normalmente hago esto de esta manera, pero DEBES tener todos los archivos de localización en tu proyecto.
@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
No lo use en iOS 9. Esto devuelve nulo para todas las cadenas pasadas a través de él.
He encontrado otra solución que le permite actualizar las cadenas de idioma, sin reiniciar la aplicación y compatible con cadenas genéricas:
Pon esta macro en el Prefix.pch:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
y donde sea que necesite un uso de cadena localizado:
NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")
Para configurar el uso del idioma:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
Funciona incluso con saltos de idioma consecutivos como:
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, @""));
Como se dijo anteriormente, solo haz:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
Pero para evitar tener que reiniciar la aplicación, coloque la línea en el método principal de main.m
, justo antes UIApplicationMain
(...).
NSAutoreleasePool * pool ..
filtren algunos objetos que se liberen automáticamente.
[[NSBundle mainBundle] URLForResource:withExtension:]
antes.
El truco para usar un idioma específico seleccionándolo desde la aplicación es forzar el NSLocalizedString
uso de un paquete específico dependiendo del idioma seleccionado,
Aquí está la publicación que he escrito para esta localización de avance de aprendizaje en aplicaciones ios
y aquí está el código de una localización de avance de aplicación de muestra en aplicaciones ios
¿Qué opinas sobre esta solución para 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)
}
}
Uso 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.
Como menciona Brian Webster, el idioma debe establecerse "en algún momento temprano en el inicio de su aplicación". Pensé applicationDidFinishLaunching:
de la AppDelegate
que debería ser un lugar adecuado para hacerlo, ya que es donde hago todos los demás inicialización.
Pero como menciona William Denniss, eso parece tener efecto solo después de que se reinicia la aplicación, lo cual es inútil.
Sin embargo, parece funcionar bien si pongo el código en la función principal:
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;
}
Agradecería cualquier comentario sobre esto.
[[NSUserDefaults standardUserDefaults] synchronize];
después de llamarsetObject:forKey:
Me gusta más el método de Mauro Delrio. También he agregado lo siguiente en mi Project_Prefix.pch
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
Entonces, si alguna vez desea usar el método estándar (que usa NSLocalizedString), puede hacer una sustitución rápida de sintaxis en todos los archivos.
NSLocalizedString()
lee el valor de la clave AppleLanguages
de los valores predeterminados estándar del usuario ( [NSUserDefaults standardUserDefaults]
). Utiliza ese valor para elegir una localización adecuada entre todas las localizaciones existentes en tiempo de ejecución. Cuando Apple crea el diccionario predeterminado del usuario en el inicio de la aplicación, busca la clave de idioma (s) preferido en las preferencias del sistema y copia el valor desde allí. Esto también explica, por ejemplo, por qué cambiar la configuración de idioma en OS X no tiene ningún efecto en la ejecución de aplicaciones, solo en las aplicaciones iniciadas a partir de entonces. Una vez copiado, el valor no se actualiza solo porque la configuración cambia. Es por eso que iOS reinicia todas las aplicaciones si cambia el idioma.
Sin embargo, todos los valores del diccionario predeterminado del usuario pueden sobrescribirse mediante argumentos de línea de comandos. Ver NSUserDefaults
documentación en el NSArgumentDomain
. Esto incluso incluye aquellos valores que se cargan desde el archivo de preferencias de la aplicación (.plist). Es realmente bueno saber si desea cambiar un valor solo una vez para la prueba .
Entonces, si desea cambiar el idioma solo para las pruebas, probablemente no quiera alterar su código (si olvida eliminar este código más adelante ...), en su lugar, dígale a Xcode que inicie su aplicación con parámetros de línea de comando ( por ejemplo, use la localización en español):
No es necesario tocar su código en absoluto. Simplemente cree diferentes esquemas para diferentes idiomas y puede iniciar rápidamente la aplicación una vez en un idioma y otra en otro simplemente cambiando el esquema.
Options
como en las versiones más nuevas de Xcode que Apple ofrece que también.
Se me ocurrió una solución que te permite usar NSLocalizedString
. Creo una categoría de NSBundle
llamada NSBundle+RunTimeLanguage
. La interfaz es así.
// 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 implementación es así.
// 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
Que simplemente agregar importación NSBundle+RunTimeLanguage.h
en los archivos que usan NSLocalizedString
.
Como puede ver, guardo mi languageCode en una propiedad de AppDelegate
. Esto podría almacenarse en cualquier lugar que desee.
Lo único que no me gusta es una Advertencia que NSLocalizedString
redefinió el marco. Quizás alguien podría ayudarme a arreglar esta parte.
#undef NSLocalizedString
justo antes #define
para deshabilitar la advertencia
Es lo primero que debe hacer es localizar su aplicación con al menos dos idiomas (inglés y francés en este ejemplo).
En su código, en lugar de usar NSLocalizedString(key, comment)
, use una macro MYLocalizedString(key, comment)
definida como esta:
#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
Este MYLocalizationSystem
singleton hará lo siguiente:
Cuando el usuario cambió el idioma de la aplicación en francés, llame al [[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];
}
En este ejemplo, este método establece el paquete localizado en fr.lproj
Una vez que haya configurado el paquete localizado, podrá obtener la cadena localizada correcta de él con este método:
- (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];
}
Espero que esto te ayudará.
Encontrará más detalles en este artículo de NSWinery.io
Extensiones Swift 3:
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
}
}
Uso:
Locale.preferredLanguage = "uk"
label.text = "localizedKey".localized
En el archivo .pch para definir:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
Tal vez debería complementar con esto (en el archivo .pch después de #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]
Solución Swift 3:
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")
Dio algunos ejemplos de códigos de idiomas que se pueden usar. Espero que esto ayude
Puede crear un subpaquete con el conjunto de cadenas localizadas con las que desea hacer esto y luego usarlo NSLocalizedStringFromTableInBundle()
para cargarlas. (Supongo que este es un contenido separado de la localización normal de la interfaz de usuario que podría estar haciendo en la aplicación).
para mi caso tengo dos archivos localizados, ja y en
y me gustaría forzarlo a que sea si el idioma preferido en el sistema no es ni ja
voy a editar el archivo main.m
comprobaré si el primer preferido es en o ja, de lo contrario, cambiaré el segundo idioma preferido a 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]));
}
}
Puedes hacer algo como esto:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
Basado en la respuesta de Tudorizer para cambiar el idioma sin salir o reiniciar la aplicación.
En lugar de una macro, use una clase para acceder al idioma preferido para verificar si hay un código de idioma específico.
A continuación se muestra una clase utilizada para obtener el paquete de idioma actual que funciona para 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
Use la clase anterior para hacer referencia a un archivo de cadena / imagen / 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")
Cambie el idioma en línea como se muestra a continuación o actualice el método "changeCurrentLanguage" en la clase anterior para tomar un parámetro de cadena que haga referencia al nuevo idioma.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
En swift 4, lo resolví sin necesidad de reiniciar o usar bibliotecas.
Después de probar muchas opciones, encontré esta función, donde pasa el stringToLocalize (de Localizable.String, el archivo de cadenas) que desea traducir, y el idioma en el que desea traducirlo, y lo que devuelve es el valor para esa cadena que tienes en el archivo de cadenas:
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)
}
Teniendo en cuenta esta función, creé esta función en un archivo 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!)!
}
}
Para acceder desde toda la aplicación, y en cada cadena del resto de ViewControllers, en lugar de poner:
NSLocalizedString ("StringToLocalize", comment: “")
Lo he reemplazado con
let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()
NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
No sé si es la mejor manera, pero lo encontré muy simple y funciona para mí, ¡espero que te ayude!
Esta función intentará obtener una cadena localizada para el idioma actual y, si no se encuentra, la utilizará en inglés.
- (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;
}
Quería agregar soporte para un idioma que no es oficialmente compatible con iOS (no aparece en la sección Idioma en la configuración del sistema). Siguiendo el Tutorial de internacionalización de Apple y algunos consejos aquí de Brian Webster y geon, se me ocurrió este código (póngalo en 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]));
}
}
Esto funciona bien tanto para Storyboard como para el código NSLocalizedString. El código supone que el usuario tendrá una opción para cambiar manualmente el idioma dentro de la aplicación más adelante.
Por supuesto, no olvide agregar las traducciones adecuadas de Storyboard y las traducciones de Localizable.strings (consulte el enlace a la página de Apple anterior para saber cómo hacerlo).
Aquí hay una solución decente para este problema, y no requiere reiniciar la aplicación.
https://github.com/cmaftuleac/BundleLocalization
Esta implementación funciona ajustando dentro de NSBundle. La idea es que anule el método localizedStringForKey en la instancia del objeto NSBundle, y luego llame a este método en un paquete diferente con un idioma diferente. Simple y elegante totalmente compatible con todo tipo de recursos.
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
haga lo que haga, la mejor manera es tomar el nombre_corto para el idioma especificado, es decir: fr, en, nl, de, it, etc. y asignarlo a un valor global.
cree una vista de selector para que aparezca como un menú desplegable (combinación de un botón al hacer clic en el que aparece una vista de selector desde abajo con una lista de idiomas) y seleccione el idioma que desee. deje que el nombre corto se almacene internamente. cree un archivo .h + .m llamado LocalisedString.
Establezca el valor global de short_name para que sea igual al valor obtenido en LocalisedString.m Cuando se selecciona el idioma requerido, asigne NSBundlePath para crear subdirectorios de proyecto para el idioma necesario. por ejemplo, nl.proj, en.proj.
Cuando se selecciona la carpeta de proyecto particular, llame a la cadena localizada para el idioma respectivo y cambie el idioma dinámicamente.
No hay reglas rotas.
Para Swift, puede anular el main.swift
archivo y establecer la cadena UserDefaults allí antes de que se ejecute la aplicación. De esta manera, no tiene que reiniciar la aplicación para ver el efecto deseado.
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))
emparejado junto con la eliminación de @UIApplicationMain
en su AppDelegate.swift
archivo.