На iPhone NSLocalizedString
повертає рядок мовою iPhone. Чи можна змусити NSLocalizedString
використовувати певну мову, щоб програма мала іншу мову, ніж пристрій?
На iPhone NSLocalizedString
повертає рядок мовою iPhone. Чи можна змусити NSLocalizedString
використовувати певну мову, щоб програма мала іншу мову, ніж пристрій?
Відповіді:
NSLocalizedString()
(та їх варіанти) перейдіть до клавіші "AppleLanguages", NSUserDefaults
щоб визначити, які налаштування користувача для бажаних мов. Це повертає масив мовних кодів, причому перший - це той, який встановив користувач для свого телефону, а наступні використовуються як резервні копії, якщо ресурс недоступний на бажаній мові. (на робочому столі користувач може вказати кілька мов із спеціальним замовленням у налаштуваннях системи)
Ви можете змінити глобальний параметр для власної програми, використовуючи метод setObject: forKey: для встановлення власного списку мов. Це матиме перевагу над глобально встановленим значенням і повернеться до будь-якого коду у вашій програмі, який здійснює локалізацію. Код для цього виглядатиме приблизно так:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
Це зробить німецьку мову бажаною для вашої програми, англійською та французькою мовами як резервні копії. Ви хочете зателефонувати це десь на початку запуску програми. Докладніше про налаштування мови / місцевості можна прочитати тут: Теми програмування інтернаціоналізації: Отримання поточної мови та локальної мови
У мене була така ж проблема нещодавно, і я не хотів запускати і виправляти всю свою NSLocalizedString а також не змушувати програму перезавантажуватися для роботи нової мови. Я хотів, щоб все працювало як є.
Моє рішення полягало в тому, щоб динамічно змінити клас основного пакета і завантажити там відповідний пакет:
Файл заголовка
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
Впровадження
#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
Отже, коли ваш додаток запускається і перед завантаженням першого контролера, просто зателефонуйте:
[NSBundle setLanguage:@"en"];
Коли ваш користувач змінить бажану мову на екрані налаштувань, просто зателефонуйте йому ще раз:
[NSBundle setLanguage:@"fr"];
Щоб повернутись до системних значень за замовчуванням, просто перейдіть до нуля:
[NSBundle setLanguage:nil];
Насолоджуйтесь ...
Для тих, кому потрібна версія 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)
}
}
Зазвичай я це роблю таким чином, але ви ОБОВ'ЯЗКОВЕ мати усі файли локалізації у вашому проекті.
@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
Не використовуйте на iOS 9. Це повертає нуль для всіх переданих через нього рядків.
Я знайшов ще одне рішення, яке дозволяє оновлювати мовні рядки, без перезавантаження програми та сумісного з genstrings:
Помістіть цей макрос у Prefix.pch:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
і де вам потрібне використання локалізованих рядків:
NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")
Щоб встановити використання мови:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
Працює навіть із послідовними скачками мови, як:
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, @""));
Як було сказано раніше, просто зробіть:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
Але щоб не перезавантажувати додаток, введіть рядок у основний метод main.m
, безпосередньо перед UIApplicationMain
(...).
NSAutoreleasePool * pool ..
як декілька об'єктів, що вийшли у світ, просочуються.
[[NSBundle mainBundle] URLForResource:withExtension:]
раніше.
Трюк у використанні певної мови, вибравши її з програми, - змусити NSLocalizedString
використовувати певний пакет залежно від обраної мови,
ось посаду, яку я написав для цієї попередньої локалізації навчання в додатках ios
і ось код однієї зразкової попередньої локалізації додатків у додатках ios
Що ви думаєте про це рішення для 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)
}
}
Просте використання:
"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.
Як згадує Брайан Вебстер, мову потрібно встановити "десь рано при запуску програми". Я подумав, що applicationDidFinishLaunching:
це AppDelegate
повинно бути підходящим місцем для цього, оскільки саме там я роблю всі інші ініціалізації.
Але як згадує Вільям Денніс, це, здається, має ефект лише після перезапуску програми, що є марним.
Здається, це добре спрацьовує, якщо я ставлю код в основну функцію, хоча:
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;
}
Буду вдячний за будь-які коментарі з цього приводу.
[[NSUserDefaults standardUserDefaults] synchronize];
після дзвінкаsetObject:forKey:
Мені подобається найкращий метод Мауро Дельріо. Я також додав наступне у свій Project_Prefix.pch
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
Отже, якщо ви хочете використовувати стандартний метод (який використовує NSLocalizedString), ви можете зробити швидку підстановку синтаксису у всіх файлах.
NSLocalizedString()
зчитує значення ключа AppleLanguages
з стандартних стандартних параметрів користувача ([NSUserDefaults standardUserDefaults]
). Це значення використовує для вибору відповідної локалізації серед усіх існуючих локалізацій під час виконання. Коли Apple запускає словник за замовчуванням користувачів під час запуску програми, вони шукають ключ бажаних мов у системних налаштуваннях та копіюють звідти значення. Це також пояснює, наприклад, чому зміна мовних налаштувань в OS X не впливає на запущені програми, лише на додатки, які починаються після цього. Після копіювання значення не оновлюється лише тому, що змінюються налаштування. Ось чому iOS перезапускає всі програми, якщо ви змінюєте мову.
Однак усі значення словника за замовчуванням користувача можуть бути перезаписані аргументами командного рядка. Дивіться NSUserDefaults
документацію на NSArgumentDomain
. Сюди входять навіть ті значення, які завантажуються з файлу налаштувань програми (.plist). Це дійсно добре знати, якщо ви хочете один раз змінити значення для тестування .
Отже, якщо ви хочете змінити мову лише для тестування, ви, ймовірно, не хочете змінювати свій код (якщо згодом ви забудете видалити цей код ...), натомість скажіть Xcode, щоб запустити додаток із параметрів командного рядка ( наприклад, використовуйте іспанську локалізацію):
Не потрібно торкатися коду взагалі. Просто створіть різні схеми для різних мов, і ви можете швидко запустити додаток один раз на одній мові та один раз на іншій, просто переключивши схему.
Options
як у нових версіях Xcode, що Apple пропонує, що також.
Я придумав рішення, яке дозволяє використовувати NSLocalizedString
. Я створюю категорію NSBundle
дзвінків NSBundle+RunTimeLanguage
. Інтерфейс такий.
// 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
Реалізація така.
// 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
Тоді просто додайте імпорт NSBundle+RunTimeLanguage.h
до файлів, які використовують NSLocalizedString
.
Як ви бачите, я зберігаю свій languageCode у властивості AppDelegate
. Це може бути збережене де завгодно.
Це єдине, що мені не подобається в цьому - Попередження, яке NSLocalizedString
Марко переробив. Можливо, хтось міг би допомогти мені виправити цю частину.
#undef NSLocalizedString
лише раніше, #define
щоб відключити попередження
Перше, що вам потрібно зробити, це локалізувати додаток щонайменше двома мовами (англійською та французькою мовами в цьому прикладі).
У своєму коді замість цього NSLocalizedString(key, comment)
використовуйте макрос, MYLocalizedString(key, comment)
визначений так:
#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
Цей MYLocalizationSystem
сингл:
Коли користувач змінив мову програми на французьку, зателефонуйте [[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];
}
У цьому прикладі цей метод встановлює локалізований пакет у fr.lproj
Щойно ви встановите локалізований пакет, ви зможете отримати потрібну локалізовану рядок від нього за допомогою цього методу:
- (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];
}
Сподіваюся, що це вам допоможе.
Більш детальну інформацію ви знайдете в цій статті від NSWinery.io
Розширення 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
}
}
Використання:
Locale.preferredLanguage = "uk"
label.text = "localizedKey".localized
У файлі .pch визначте:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
Можливо, ви повинні доповнити це (у .pch-файлі після #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]
Рішення 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")
Наведіть кілька прикладів мовних кодів, які можна використовувати. Сподіваюсь, це допомагає
Ви можете створити підгрупування з набором локалізованих рядків, з якими потрібно це зробити, а потім використовувати NSLocalizedStringFromTableInBundle()
для їх завантаження. (Я припускаю, що це вміст, окремо від звичайної локалізації інтерфейсу, який ви можете робити у додатку.)
для мого випадку у мене є два локалізовані файли, ja та en
і я хотів би змусити його до en, якщо краща мова в системі ні en, ні ja
Я збираюся редагувати файл main.m
я перевірю, чи є перший бажаний en або ja, якщо ні, то я зміню другу бажану мову на 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]));
}
}
Ви можете зробити щось подібне:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
На основі відповіді Tudorizer змінити мову, не виходячи з програми та не перезавантажуючи програму.
Замість макросу використовуйте клас для доступу до бажаної мови, щоб перевірити, чи є специфічний код мови.
Нижче наведено клас, який використовується для отримання поточного мовного набору, який працює для 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
Використовуйте клас вище для посилання на рядовий файл / зображення / відео / тощо:
// 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")
Змініть мову в рядку, як нижче, або оновіть метод "changeCurrentLanguage" в класі вище, щоб взяти параметр рядка, що посилається на нову мову.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
У швидкому 4 я вирішив це, не потребуючи перезавантаження або використання бібліотек.
Спробувавши багато варіантів, я знайшов цю функцію, де ви передаєте рядокToLocalize (з Localizable.String, файл рядків), який ви хочете перекласти, і мову, якою ви хочете перекласти його, і те, що він повертає, значення для той рядок, який у вас є у файлі 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)
}
Враховуючи цю функцію, я створив цю функцію у файлі 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!)!
}
}
Для доступу з усієї програми та в кожну рядок решти ViewControllers замість того, щоб ставити:
NSLocalizedString ("StringToLocalize", comment: “")
Я його замінив
let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()
NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
Я не знаю, чи це найкращий спосіб, але я знайшов це дуже просто, і це працює для мене, сподіваюся, що це вам допоможе!
Ця функція спробує отримати локалізований рядок для поточної мови, і якщо його не буде знайдено, він отримає його за допомогою англійської мови.
- (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;
}
Мені хотілося додати підтримку мови, яка офіційно не підтримується iOS (не вказана в розділі Мова в системних налаштуваннях). Дотримуючись Навчального посібника з інтернаціоналізації Apple і декількох підказок Брайана Вебстера та geon, я придумав цей фрагмент коду (виклав його в 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]));
}
}
Це добре працює як для Storyboard, так і для NSLocalizedString-коду. Код передбачає, що пізніше користувач матиме можливість вручну змінити мову в додатку.
Звичайно, не забудьте додати належні переклади Storyboard та переклади Localizable.strings (про те, як це зробити, див. Посилання на сторінку Apple вище).
Ось гідне рішення цієї проблеми, і воно не вимагає перезавантаження програми.
https://github.com/cmaftuleac/BundleLocalization
Ця реалізація працює за допомогою налаштування всередині NSBundle. Ідея полягає в тому, щоб ви замінили метод localizedStringForKey на екземплярі об'єкта NSBundle, а потім викликали цей метод в іншому пакеті з іншою мовою. Простий і елегантний повністю сумісний з усіма видами ресурсів.
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
все, що ви робите, найкращий спосіб - це взяти коротке ім'я для вказаної мови, тобто: fr, en, nl, de, it і т. д. і призначити те саме глобальному значенню.
зробіть подання вибору, щоб з'являтися як спадне меню (комбінація кнопки, натисканням якої знизу відображається перегляд вибору, зі списком мов) та виберіть потрібну мову. нехай коротке ім’я зберігається внутрішньо. зробіть .h + .m файл з назвою LocalisedString.
Встановіть глобальне значення short_name рівним отриманому значенню у LocalisedString.m Коли вибрана потрібна мова, призначте NSBundlePath для створення підкаталогів проекту для потрібної мови. наприклад, nl.proj, en.proj.
Коли вибрано конкретну папку proj, викличте локалізований рядок відповідної мови та змініть мову динамічно.
жодних правил не порушено.
Для Swift ви можете змінити main.swift
файл і встановити рядок UserDefaults перед запуском програми. Таким чином, вам не доведеться перезавантажувати додаток, щоб побачити бажаний ефект.
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))
в парі разом із видаленням @UIApplicationMain
у вашому AppDelegate.swift
файлі.