На 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"];
Чтобы вернуться к системным настройкам по умолчанию, просто введите nil:
[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 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
Свифт 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
Используйте приведенный выше класс для ссылки на строковый файл / 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")
Измените язык в строке, как показано ниже, или обновите метод «changeCurrentLanguage» в вышеприведенном классе, чтобы получить строковый параметр, ссылающийся на новый язык.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
В Swift 4 я решил это без необходимости перезапуска или использования библиотек.
Перепробовав много вариантов, я нашел эту функцию, где вы передаете stringToLocalize (Localizable.String, файл строк), который вы хотите перевести, и язык, на который вы хотите перевести его, и что он возвращает, это значение для та строка, которая у вас есть в файле строк:
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 по интернационализации и нескольким советам Брайана Вебстера и Джона, я разработал этот фрагмент кода (поместите его в 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
файле.