Cambia la configuration regional actual del simulador de iOS en time de ejecución

Al desarrollar un set de cálculos de dates y reglas de idioma para convertir valores numéricos y dates en cadenas, estoy escribiendo testings que afirman el resultado del método de formateo de cadenas. Una afirmación imaginaria para esto podría verse así:

NSAssert([dateString isEqualToString:@"Three days, until 6:00 PM"], @"Date string should match expectation"); 

Sin embargo, como la aplicación está localizada para varios idiomas y mis compañeros desarrolladores también pertenecen a diferentes lugares que yo, puede suceder que su dispositivo o simulador esté configurado en una configuration regional distinta a la que se está escribiendo las testings. En un escenario como este, el contenido de dateString podría ser algo así como:

 @"Drie dagen, tot 18:00" // the assertion fails @"Drei Tage, bis 18 Uhr" // the assertion also fails 

Esto puede o no ser la notación de date correcta para estos locales, pero la parte de la cual trata mi pregunta es cómo poder ejecutar testings en un entorno local específico, cuando el código subyacente hace uso de la API de Apple de esta manera:

 [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterShortStyle]; 

Me encantaría cubrir dos o más idiomas en mis afirmaciones, con algo como esto:

 [NSSomething actionToSetTheLocaleTo:@"en_US"]; dateString = ...; // the formatting NSAssert([dateString isEqualToString:@"Three days, until 6:00 PM"], @"match en_US"); [NSSomething actionToSetTheLocaleTo:@"nl_NL"]; dateString = ...; // the formatting NSAssert([dateString isEqualToString:@"Drie dagen, tot 18:00"], @"match nl_NL"); 

¿Quién sabe cómo lograr este efecto?

Notas:

  • Cambiar el idioma preferido no lo networkinguce, también debe influir en el comportamiento NSDateFormatter y NSNumberFormatter.
  • Debido a que esto es solo para propósitos de testings unitarias, estaría contento con el uso de API privada. Sin embargo, para el beneficio de otras personas que tropiezan con esta publicación, se prefiere la API pública.
  • Pasar un entorno local personalizado a todas las API de formatting de date o número podría ser una consideración final, pero estoy publicando esta pregunta con la esperanza de evitar volver a esas medidas extremas. Si, sin embargo, sabe que es la única solución, proporcione alguna reference y no perderé más time

Enlaces sobre el tema:

  • Buen artículo de Ray Lillywhite en i18n y l10n
  • Artículo NSHipster sobre NSLocale

@ Desmond señaló una solución funcional. Hasta que él ponga una respuesta aquí para poner esta información, permítanme resumir lo que terminé haciendo con un poco de código.

La solución, resulta, es "tan fácil" como dar vueltas a los methods que los methods de class usan internamente:

 beforeEach(^{ [NSBundle ttt_overrideLanguage:@"nl"]; [NSLocale ttt_overrideRuntimeLocale:[NSLocale localeWithLocaleIdentifier:@"nl_NL"]]; }); afterEach(^{ [NSLocale ttt_resetRuntimeLocale]; [NSBundle ttt_resetLanguage]; }); 

Los methods ttt_... que ve arriba usan las categorías en NSObject, NSLocale y NSBundle para verificar en time de ejecución si debería usar los methods originales o devolver algo más. Este método funciona sin problemas al escribir sus testings, y aunque técnicamente no utiliza ninguna API privada, sugiero que solo use esto en la configuration de testing, no para nada que envíe a App Store para su revisión.

En este aspecto, encontrarás las categorías Objective-C que agregué al objective de testing de mi aplicación para lograr el comportamiento requerido.

Como esto está en una testing de unidad, ¿ha intentado establecer la configuration regional en NSDateFormatter ? No debería tener que establecer la configuration regional en todo el simulador, puede convertirlo en un parámetro de sus testings. La mayoría de los methods de cocoa que dependen de la configuration local pueden tomarlo como un parámetro o propiedad.

Algo como:

 NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en-US"]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setLocale:locale]; [formatter setDateStyle: NSDateFormatterNoStyle]; [formatter setTimeStyle: NSDateFormatterShortStyle]; [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; thing = [formatter stringForObjectValue:date]; 

El método localizedStringFromDate: dateStyle: timeStyle: está utilizando aquí , y es bastante explícito sobre todo less la configuration regional. Por lo tanto, puede seguir los mismos pasos, pero establezca la configuration regional en algo distinto a la configuration regional actual del sistema, siguiendo los pasos descritos anteriormente.

La única manera que ve es lo que él ha mencionado. Sin embargo, mencionaste que existe en muchos lugares.

En lugar de volver a escribir todo tu código actual, en tu PC podrías hacer algo elegante como

 #import "UnitTestDateFormatter.h" #define NSDateFormatter UnitTestDateFormatter 

Y luego simplemente crea una subclass para manejarlo:

 @implementation UnitTestDateFormatter - (id) init { self = [super init]; if(self != nil) { [self setLocale:...]; } return self; } @end 

Al less, su código puede permanecer sin cambios.