Su iPhone NSLocalizedString
restituisce la stringa nella lingua dell'iPhone. È possibile forzare NSLocalizedString
l'uso di una lingua specifica per avere l'app in una lingua diversa da quella del dispositivo?
Su iPhone NSLocalizedString
restituisce la stringa nella lingua dell'iPhone. È possibile forzare NSLocalizedString
l'uso di una lingua specifica per avere l'app in una lingua diversa da quella del dispositivo?
Risposte:
NSLocalizedString()
(e relative varianti) accedono alla chiave "AppleLanguages" NSUserDefaults
per determinare quali sono le impostazioni dell'utente per le lingue preferite. Ciò restituisce un array di codici lingua, il primo è quello impostato dall'utente per il telefono e i successivi utilizzati come fallback se una risorsa non è disponibile nella lingua preferita. (sul desktop, l'utente può specificare più lingue con un ordine personalizzato nelle Preferenze di Sistema)
È possibile sovrascrivere l'impostazione globale per la propria applicazione, se lo si desidera, utilizzando il metodo setObject: forKey: per impostare il proprio elenco di lingue. Ciò avrà la precedenza sul valore impostato a livello globale e verrà restituito a qualsiasi codice nell'applicazione che sta eseguendo la localizzazione. Il codice per questo sarebbe simile a:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
Ciò renderebbe il tedesco la lingua preferita per la tua applicazione, con inglese e francese come riserva. Dovresti chiamarlo prima o poi all'avvio della tua applicazione. Puoi leggere ulteriori informazioni sulle preferenze di lingua / locale qui: Internazionalizzazione Argomenti di programmazione: ottenere la lingua e le impostazioni internazionali correnti
Ho avuto lo stesso problema di recente e non volevo avviare e patchare il mio intero NSLocalizedString né forzare il riavvio dell'app affinché la nuova lingua funzionasse. Volevo che tutto funzionasse così com'è.
La mia soluzione era cambiare dinamicamente la classe del bundle principale e caricare lì il bundle appropriato:
File di intestazione
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
Implementazione
#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
Quindi, in pratica, quando la tua app si avvia e prima di caricare il tuo primo controller, chiama semplicemente:
[NSBundle setLanguage:@"en"];
Quando il tuo utente cambia la sua lingua preferita nella schermata delle impostazioni, richiamala semplicemente di nuovo:
[NSBundle setLanguage:@"fr"];
Per ripristinare le impostazioni predefinite del sistema, passare semplicemente a zero:
[NSBundle setLanguage:nil];
Godere...
Per chi necessita di una versione 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)
}
}
Di solito lo faccio in questo modo, ma DEVI avere tutti i file di localizzazione nel tuo progetto.
@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
Non utilizzare su iOS 9. Questo restituisce zero per tutte le stringhe passate attraverso di esso.
Ho trovato un'altra soluzione che ti consente di aggiornare le stringhe della lingua, senza riavviare l'app e compatibile con le stringhe gens:
Metti questa macro nel Prefix.pch:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
e dove mai hai bisogno di una stringa localizzata usa:
NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")
Per impostare la lingua utilizzare:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
Funziona anche con salti di lingua consecutivi come:
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, @""));
Come detto prima, basta fare:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
Ma per evitare di dover riavviare l'app, metti la riga nel metodo principale di main.m
, appena prima UIApplicationMain
(...).
NSAutoreleasePool * pool ..
o alcuni oggetti rilasciati automaticamente potrebbero fuoriuscire.
[[NSBundle mainBundle] URLForResource:withExtension:]
prima.
Il trucco per utilizzare una lingua specifica selezionandola dall'app è forzare l' NSLocalizedString
uso di un pacchetto specifico a seconda della lingua selezionata,
ecco il post che ho scritto per questo localizzazione avanzata di apprendimento nelle app ios
ed ecco il codice di una localizzazione anticipata di un'app di esempio nelle app ios
Come menzionato da Brian Webster, la lingua deve essere impostata "all'inizio dell'avvio dell'applicazione". Ho pensato applicationDidFinishLaunching:
di AppDelegate
dovrebbe essere un luogo adatto per farlo, dal momento che è dove faccio tutti gli altri inizializzazione.
Ma come menziona William Denniss, ciò sembra avere effetto solo dopo il riavvio dell'app, il che è un po 'inutile.
Tuttavia, sembra funzionare bene se inserisco il codice nella funzione principale:
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;
}
Apprezzerei qualsiasi commento su questo.
[[NSUserDefaults standardUserDefaults] synchronize];
dopo aver chiamatosetObject:forKey:
Cosa ne pensate di questa soluzione per 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)
}
}
Utilizzo semplice:
"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()
legge il valore per la chiave AppleLanguages
dalle impostazioni predefinite dell'utente standard ( [NSUserDefaults standardUserDefaults]
). Utilizza quel valore per scegliere una localizzazione appropriata tra tutte le localizzazioni esistenti in fase di esecuzione. Quando Apple crea il dizionario predefinito dell'utente all'avvio dell'app, cerca la chiave della lingua preferita nelle preferenze di sistema e copia il valore da lì. Questo spiega anche, ad esempio, perché la modifica delle impostazioni della lingua in OS X non ha alcun effetto sull'esecuzione delle app, ma solo sulle app avviate successivamente. Una volta copiato, il valore non viene aggiornato solo perché le impostazioni cambiano. Ecco perché iOS riavvia tutte le app se cambi la lingua.
Tuttavia, tutti i valori del dizionario di default dell'utente possono essere sovrascritti dagli argomenti della riga di comando. Vedere la NSUserDefaults
documentazione su NSArgumentDomain
. Ciò include anche quei valori caricati dal file delle preferenze dell'app (.plist). È davvero utile sapere se si desidera modificare un valore solo una volta per il test .
Quindi, se vuoi cambiare la lingua solo per il test, probabilmente non vuoi modificare il tuo codice (se dimentichi di rimuovere questo codice in seguito ...), dì invece a Xcode di avviare la tua app con i parametri della riga di comando ( ad es. usa la localizzazione spagnola):
Non c'è bisogno di toccare il tuo codice. Basta creare schemi diversi per lingue diverse e puoi avviare rapidamente l'app una volta in una lingua e una volta in un'altra semplicemente cambiando schema.
Options
come con le versioni più recenti di Xcode Apple lo offre anche.
Mi piace di più il metodo di Mauro Delrio. Ho anche aggiunto quanto segue nel mio Project_Prefix.pch
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
Quindi, se vuoi usare il metodo standard (che usa NSLocalizedString) puoi fare una rapida sostituzione della sintassi in tutti i file.
Ho trovato una soluzione che ti permette di usare NSLocalizedString
. Creo una categoria di NSBundle
chiamata NSBundle+RunTimeLanguage
. L'interfaccia è così.
// 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
L'implementazione è così.
// 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
Invece di aggiungere semplicemente l'importazione NSBundle+RunTimeLanguage.h
ai file che utilizzano NSLocalizedString
.
Come puoi vedere memorizzo il mio languageCode in una proprietà di AppDelegate
. Questo potrebbe essere memorizzato ovunque desideri.
L'unica cosa che non mi piace è un Avvertimento che NSLocalizedString
Marco ha ridefinito. Forse qualcuno potrebbe aiutarmi a riparare questa parte.
#undef NSLocalizedString
appena prima #define
per disabilitare l'avviso
La prima cosa che devi fare è localizzare la tua app con almeno due lingue (inglese e francese in questo esempio).
Nel tuo codice, invece di usare NSLocalizedString(key, comment)
, usa una macro MYLocalizedString(key, comment)
definita in questo modo:
#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
Questo MYLocalizationSystem
singleton:
Quando l'utente ha cambiato la lingua dell'applicazione in francese, chiama [[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];
}
In questo esempio, questo metodo imposta il bundle localizzato su fr.lproj
Dopo aver impostato il bundle localizzato, sarai in grado di ottenere la stringa localizzata corretta da lui con questo metodo:
- (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];
}
Spero che questo ti possa aiutare.
Troverai maggiori dettagli in questo articolo da NSWinery.io
Estensioni 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
}
}
Utilizzo:
Locale.preferredLanguage = "uk"
label.text = "localizedKey".localized
Nel file .pch da definire:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
Forse dovresti completare con questo (sul file .pch dopo #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]
Soluzione 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")
Ha fornito alcuni esempi di codici di lingua che possono essere utilizzati. Spero che sia di aiuto
In swift 4, l'ho risolto senza bisogno di riavviare o utilizzare le librerie.
Dopo aver provato molte opzioni, ho trovato questa funzione, dove si passa la stringaToLocalize (di Localizable.String, il file di stringhe) che si desidera tradurre e la lingua in cui si desidera tradurla, e ciò che restituisce è il valore per quella stringa che hai nel file di stringhe:
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)
}
Tenendo conto di questa funzione, ho creato questa funzione in un file 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!)!
}
}
Per accedere dall'intera app e in ogni stringa del resto di ViewControllers, invece di inserire:
NSLocalizedString ("StringToLocalize", comment: “")
L'ho sostituito con
let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()
NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
Non so se sia il modo migliore, ma l'ho trovato molto semplice, e per me funziona, spero ti aiuti!
È possibile creare un sub-bundle con l'insieme di stringhe localizzate con cui si desidera eseguire questa operazione e quindi utilizzarle NSLocalizedStringFromTableInBundle()
per caricarle. (Presumo che questo sia un contenuto separato dalla normale localizzazione dell'interfaccia utente che potresti eseguire sull'app.)
per il mio caso ho due file localizzati, ja e en
e vorrei forzarlo a en se la lingua preferita nel sistema non è né en né ja
ho intenzione di modificare il file main.m
controllerò se la prima lingua preferita è en o ja, altrimenti cambierò la seconda lingua preferita in 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]));
}
}
Puoi fare qualcosa del genere:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
Ecco una soluzione decente per questo problema e non richiede il riavvio dell'applicazione.
https://github.com/cmaftuleac/BundleLocalization
Questa implementazione funziona modificando all'interno di NSBundle. L'idea è di sovrascrivere il metodo localizedStringForKey sull'istanza dell'oggetto NSBundle e quindi chiamare questo metodo su un bundle diverso con una lingua diversa. Semplice ed elegante completamente compatibile con tutti i tipi di risorse.
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
Basato sulla risposta di Tudorizer per cambiare lingua senza uscire o riavviare l'applicazione.
Invece di una macro, utilizza una classe per accedere alla lingua preferita per verificare se è presente un codice lingua specifico.
Di seguito è riportata una classe utilizzata per ottenere il pacchetto di lingue corrente che funziona per 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
Usa la classe sopra per fare riferimento a un file di stringa / immagine / video / ecc:
// 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")
Cambia la lingua in linea come sotto o aggiorna il metodo "changeCurrentLanguage" nella classe sopra per accettare un parametro stringa che fa riferimento alla nuova lingua.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
Questa funzione proverà a ottenere una stringa localizzata per la lingua corrente e se non viene trovata la otterrà utilizzando la lingua inglese.
- (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;
}
Volevo aggiungere il supporto per una lingua che non è ufficialmente supportata da iOS (non elencata nella sezione Lingua nelle impostazioni di sistema). Seguendo il Tutorial sull'internazionalizzazione di Apple e alcuni suggerimenti qui di Brian Webster e Geon, sono arrivato a questo pezzo di codice (mettilo in 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]));
}
}
Funziona bene sia per il codice Storyboard che per il codice NSLocalizedString. Il codice presuppone che l'utente avrà la possibilità di cambiare manualmente la lingua all'interno dell'app in un secondo momento.
Ovviamente, non dimenticare di aggiungere le traduzioni corrette dello Storyboard e Localizable.strings (vedi il link alla pagina Apple sopra per come farlo).
qualunque cosa facciate, il modo migliore è prendere lo short_name per la lingua specificata, cioè: fr, en, nl, de, it, ecc ... e assegnare lo stesso a un valore globale.
fai apparire una vista di selezione come un menu a discesa (combinazione di un pulsante al clic di cui appare una vista di selezione dal basso con un elenco di lingue) e seleziona la lingua che desideri. lascia che il nome breve venga memorizzato internamente. creare un file .h + .m denominato LocalisedString.
Impostare il valore globale di short_name in modo che sia uguale al valore ottenuto in LocalisedString.m Quando viene selezionata la lingua richiesta, assegnare NSBundlePath per creare sottodirectory del progetto per la lingua richiesta. ad esempio, nl.proj, en.proj.
Quando viene selezionata la cartella del progetto particolare, chiamare la stringa localizzata per la rispettiva lingua e cambiare la lingua dinamicamente.
nessuna regola infranta.
Per Swift puoi sovrascrivere il main.swift
file e impostare la stringa UserDefaults lì prima che l'app venga eseguita. In questo modo non è necessario riavviare l'App per vedere l'effetto desiderato.
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))
accoppiato con la rimozione di @UIApplicationMain
nel AppDelegate.swift
file.