Sur iPhone NSLocalizedString
renvoie la chaîne dans la langue de l'iPhone. Est-il possible de forcer NSLocalizedString
à utiliser une langue spécifique pour que l'application soit dans une langue différente de celle de l'appareil?
NSLocalizedString()
(et ses variantes) accédez à la touche "AppleLanguages" dans NSUserDefaults
pour déterminer les paramètres définis par l'utilisateur pour les langues préférées. Cela retourne un tableau de codes de langue, le premier étant celui défini par l'utilisateur pour son téléphone, et les suivants utilisés comme solutions de secours si une ressource n'est pas disponible dans la langue préférée. (sur le bureau, l'utilisateur peut spécifier plusieurs langues avec une commande personnalisée dans les Préférences Système)
Vous pouvez remplacer le paramètre global de votre propre application si vous le souhaitez en utilisant la méthode setObject: forKey: pour définir votre propre liste de langues. Cela aura priorité sur la valeur définie globalement et sera renvoyé à tout code de votre application qui effectue la localisation. Le code pour cela ressemblerait à quelque chose comme:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
Cela ferait de l'allemand la langue préférée pour votre application, avec l'anglais et le français comme substituts. Vous voudrez peut-être appeler cela tôt dans le démarrage de votre application. Vous pouvez en savoir plus sur les préférences de langue/paramètres régionaux ici: Sujets de programmation pour l’internationalisation: Obtenir la langue et les paramètres régionaux actuels
J'ai eu le même problème récemment et je ne voulais pas démarrer et mettre à jour ma totalité NSLocalizedString, ni forcer l'application à redémarrer pour que la nouvelle langue fonctionne. Je voulais que tout fonctionne tel quel.
Ma solution consistait à modifier de manière dynamique la classe du bundle principal et à y charger le bundle approprié:
fichier d'en-tête
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
Mise en oeuvre
#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
Donc, en gros, lorsque votre application démarre et avant de charger votre premier contrôleur, appelez simplement:
[NSBundle setLanguage:@"en"];
Lorsque votre utilisateur change sa langue préférée dans votre écran de configuration, appelez-la simplement à nouveau:
[NSBundle setLanguage:@"fr"];
Pour revenir aux valeurs par défaut du système, il suffit de passer nil:
[NSBundle setLanguage:nil];
Prendre plaisir...
Pour ceux qui ont besoin d'une version 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)
}
}
Je le fais habituellement de cette façon, mais vous DEVEZ avoir tous les fichiers de localisation dans votre projet.
@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
Ne pas utiliser sur iOS 9. Ceci renvoie nil pour toutes les chaînes qui y sont passées.
J'ai trouvé une autre solution qui vous permet de mettre à jour les chaînes de la langue, sans redémarrer l'application et compatible avec genstrings:
Placez cette macro dans le fichier Prefix.pch:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
et partout où vous avez besoin d'une chaîne localisée, utilisez:
NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")
Pour définir l'utilisation de la langue:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
Fonctionne même avec des sauts de langue consécutifs comme:
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, @""));
Comme dit précédemment, il suffit de faire:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
Mais pour éviter de devoir redémarrer l'application, placez la ligne dans la méthode principale de main.m
, juste avant UIApplicationMain
(...).
L'astuce pour utiliser un langage spécifique en le sélectionnant dans l'application consiste à forcer le NSLocalizedString
à utiliser un ensemble spécifique en fonction de la langue sélectionnée.
voici le post que j'ai écrit pour cela apprentissage de la localisation avancée dans les applications ios
et voici le code d'un exemple d'application localisation avancée dans les applications ios
Comme Brian Webster le mentionne, la langue doit être définie "tôt dans le démarrage de votre application". Je pensais que applicationDidFinishLaunching:
of AppDelegate
devrait être un endroit approprié pour le faire, car c'est là que je fais toutes les autres initialisations.
Mais, comme le mentionne William Denniss, cela ne semble avoir un effet que après l'application est relancée, ce qui est un peu inutile.
Cela semble fonctionner correctement si je mets le code dans la fonction principale, cependant:
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;
}
J'apprécierais vos commentaires à ce sujet.
Que pensez-vous de cette solution pour 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)
}
}
Utilisation 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.
NSLocalizedString()
lit la valeur de la touche AppleLanguages
à partir des valeurs utilisateur par défaut ([NSUserDefaults standardUserDefaults]
). Il utilise cette valeur pour choisir une localisation appropriée parmi toutes les localisations existantes au moment de l'exécution. Lorsque Apple crée le dictionnaire par défaut de l'utilisateur au lancement de l'application, il recherche la clé de langue préférée dans les préférences système et copie la valeur à partir de celle-ci. Cela explique également, par exemple, pourquoi la modification des paramètres de langue dans OS X n’a aucun effet sur les applications en cours d’exécution, mais uniquement sur les applications lancées par la suite. Une fois copiée, la valeur n'est pas mise à jour simplement parce que les paramètres changent. C'est pourquoi iOS redémarre toutes les applications si vous changez de langue.
Cependant, toutes les valeurs du dictionnaire des paramètres utilisateur par défaut peut être remplacé par des arguments de ligne de commande. Voir la documentation NSUserDefaults
sur le NSArgumentDomain
. Cela inclut même les valeurs chargées à partir du fichier de préférences d'application (.plist). C'est vraiment bon à savoir si vous voulez changer une valeur une fois pour le test.
Donc, si vous voulez changer la langue juste pour le test, vous ne voudrez probablement pas modifier votre code (si vous oubliez de supprimer ce code plus tard ...), mais demandez à Xcode de démarrer votre application avec des paramètres de ligne de commande ( par exemple, utiliser la localisation en espagnol):
Pas besoin de toucher votre code du tout. Créez simplement des schémas différents pour différentes langues et vous pouvez démarrer rapidement l'application une fois dans une langue et une fois dans une autre en basculant simplement le schéma.
J'aime la meilleure méthode de Mauro Delrio. J'ai aussi ajouté ce qui suit dans mon Project_Prefix.pch
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
Ainsi, si vous souhaitez utiliser la méthode standard (qui utilise NSLocalizedString), vous pouvez effectuer une substitution de syntaxe rapide dans tous les fichiers.
Je suis venu avec une solution qui vous permet d'utiliser NSLocalizedString
. Je crée une catégorie de NSBundle
appel NSBundle+RunTimeLanguage
. L'interface est comme ça.
// 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 mise en œuvre est comme ça.
// 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
Il suffit ensuite d’ajouter import NSBundle+RunTimeLanguage.h
dans les fichiers utilisant NSLocalizedString
.
Comme vous pouvez le voir, je stocke mon languageCode dans une propriété de AppDelegate
. Cela pourrait être stocké où vous le souhaitez.
La seule chose que je n'aime pas à ce sujet est un avertissement que NSLocalizedString
marco redéfini. Peut-être que quelqu'un pourrait m'aider à réparer cette partie.
Version rapide:
NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()
La première chose à faire est de localiser votre application en au moins deux langues (anglais et français dans cet exemple).
Dans votre code, au lieu d'utiliser NSLocalizedString(key, comment)
, utilisez une macro MYLocalizedString(key, comment)
définie comme suit: #define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
Ce singleton MYLocalizationSystem
:
Lorsque l'utilisateur change de langue d'application en français, appelez [[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];
}
Dans cet exemple , cette méthode définit le bundle localisé sur fr.lproj
Une fois que vous avez défini le paquet localisé, vous pourrez obtenir la bonne chaîne localisée auprès de lui avec cette méthode:
- (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];
}
J'espère que cela vous aidera.
Vous trouverez plus de détails dans cet article de NSWinery.io
Swift 3 extensions:
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
}
}
tilisation:
Locale.preferredLanguage = "uk"
label.text = "localizedKey".localized
Peut-être devriez-vous compléter avec ceci (sur le fichier .pch après #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]
Dans le fichier . Pch pour définir:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
Swift 3 solution:
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")
Donné quelques exemples de codes de langue qui peuvent être utilisés. J'espère que cela t'aides
Vous pouvez créer un sous-ensemble avec l'ensemble de chaînes localisées avec lesquelles vous souhaitez effectuer cette opération, puis utiliser NSLocalizedStringFromTableInBundle()
pour les charger. (Je suppose qu'il s'agit d'un contenu distinct de la localisation de l'interface utilisateur normale que vous pourriez effectuer sur l'application.)
pour mon cas j'ai deux fichier localisé, ja et en
et je voudrais le forcer à en si la langue préférée dans le système ni en ni ja
je vais éditer le fichier main.m
je vérifierai si la première langue préférée est en ou ja, sinon, je changerai la deuxième langue préférée en 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]));
}
}
Basé sur réponse de Tudorizer pour changer de langue sans quitter ou redémarrer l'application.
Au lieu d'une macro, utilisez une classe pour accéder à la langue préférée afin de vérifier si un code de langue spécifique est présent.
Vous trouverez ci-dessous une classe utilisée pour obtenir le groupe de langues actuel qui fonctionne pour 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
Utilisez la classe ci-dessus pour référencer un fichier chaîne/image/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")
Changez de langue en ligne comme ci-dessous ou mettez à jour la méthode "changeCurrentLanguage" de la classe ci-dessus pour prendre un paramètre de chaîne faisant référence à la nouvelle langue.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
Vous pouvez faire quelque chose comme ça:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
Dans Swift 4, je l'ai résolu sans qu'il soit nécessaire de redémarrer ou d'utiliser des bibliothèques.
Après avoir essayé de nombreuses options, j’ai trouvé cette fonction dans laquelle vous passez la chaîne stringToLocalize (de Localizable.String, le fichier de chaînes) que vous voulez traduire, ainsi que la langue dans laquelle vous voulez la traduire et la valeur renvoyée. cette chaîne que vous avez dans le fichier Strings:
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)
}
Tenant compte de cette fonction, j'ai créé cette fonction dans un fichier 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!)!
}
}
Pour accéder à l'ensemble de l'application et à chaque chaîne du reste de ViewControllers, au lieu de mettre:
NSLocalizedString ("StringToLocalize", comment: “")
Je l'ai remplacé par
let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()
NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
Je ne sais pas si c'est le meilleur moyen, mais j'ai trouvé cela très simple et cela fonctionne pour moi, j'espère que cela vous aide!
Je voulais ajouter une prise en charge pour une langue qui n'est pas officiellement prise en charge par iOS (non répertoriée dans la section Langue sous les paramètres système). En suivant le didacticiel d’internationalisation d’Apple et quelques conseils de Brian Webster et de Geon, j’ai créé ce morceau de code (mettez-le dans 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]));
}
}
Cela fonctionne bien pour le code Storyboard et le code NSLocalizedString. Le code suppose que l'utilisateur aura la possibilité de changer manuellement de langue ultérieurement dans l'application.
Bien sûr, n'oubliez pas d'ajouter les traductions appropriées de Storyboard et de Localizable.strings (voir le lien vers la page Apple ci-dessus pour savoir comment procéder).
Cette fonction essaiera d’obtenir la chaîne localisée pour la langue courante et si elle n’est pas trouvée, elle l’utilisera en anglais.
- (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;
}
Voici une solution décente pour ce problème, et il ne nécessite pas de redémarrage de l'application.
https://github.com/cmaftuleac/BundleLocalization
Cette implémentation fonctionne en peaufinant l'intérieur de NSBundle. L'idée est que vous substituez la méthode localizedStringForKey sur l'instance de l'objet NSBundle, puis appelez cette méthode sur un groupe différent avec un langage différent. Simple et élégant, entièrement compatible avec tous les types de ressources.
quoi que vous fassiez, le meilleur moyen est de prendre le nom court pour la langue spécifiée, c'est-à-dire: fr, en, nl, de, it, etc ... et d'affecter la même chose à une valeur globale.
faites apparaître une vue de sélecteur sous forme de menu déroulant (combinaison d’un bouton au clic duquel apparaît une vue de sélecteur avec une liste de langues) et sélectionnez la langue de votre choix. laissez le nom abrégé être stocké en interne. créez un fichier .h + .m nommé LocalisedString.
Définissez la valeur globale de short_name sur la valeur obtenue dans LocalisedString.m. Lorsque la langue requise est sélectionnée, affectez NSBundlePath afin de créer des sous-répertoires de projet pour la langue requise. par exemple, nl.proj, en.proj.
Lorsque le dossier proj particulier est sélectionné, appelez la chaîne localisée correspondant à la langue et modifiez-la de manière dynamique.
pas de règles brisées.
Pour Swift, vous pouvez remplacer le fichier main.Swift
et définir la chaîne UserDefaults avant l’exécution de l’application. De cette façon, vous n'avez pas à redémarrer l'application pour voir l'effet souhaité.
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))
couplé avec la suppression de @UIApplicationMain
dans votre fichier AppDelegate.Swift
.