Как заставить NSLocalizedString использовать определенный язык

На iPhone NSLocalizedString возвращает строку на языке iPhone. Можно ли заставить NSLocalizedString использовать определенный язык, чтобы приложение отображало язык, отличный от языка устройства?


person CodeFlakes    schedule 03.11.2009    source источник
comment
Пожалуйста, обратитесь к этому: stackoverflow.com/a/48187049/6665075 Работает как шарм   -  person Ankit Kumar Gupta    schedule 10.01.2018


Ответы (27)


NSLocalizedString() (и его варианты) получают доступ к клавише «AppleLanguages» в NSUserDefaults, чтобы определить настройки пользователя для предпочтительных языков. Это возвращает массив языковых кодов, первый из которых установлен пользователем для своего телефона, а последующие используются в качестве запасных, если ресурс недоступен на предпочтительном языке. (на рабочем столе пользователь может указать несколько языков с произвольным порядком в Системных настройках)

Вы можете переопределить глобальную настройку для своего собственного приложения, если хотите, используя метод setObject: forKey: для установки вашего собственного списка языков. Это будет иметь приоритет над глобально установленным значением и будет возвращено любому коду в вашем приложении, которое выполняет локализацию. Код для этого будет выглядеть примерно так:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate

Это сделает немецкий предпочтительным языком для вашего приложения, а английский и французский - запасными. Вы могли бы вызвать это когда-нибудь на раннем этапе запуска вашего приложения. Вы можете узнать больше о предпочтениях языка / локали здесь: Темы интернационализации программирования: получение текущего языка и локали

person Brian Webster    schedule 03.11.2009
comment
У меня это не работает, он будет использовать язык по умолчанию, несмотря ни на что. - person quano; 22.02.2010
comment
У меня это не сработало, поэтому я использовал [[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects: @el, nil] forKey: @AppleLanguages]; - person Panagiotis Korros; 08.03.2010
comment
У меня тоже не сработало, но [[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects: @el, nil] forKey: @AppleLanguages]; сделал. (NB. Вам необходимо перезапустить приложение, чтобы оно вступило в силу) - Спасибо, Панайотис Коррос! [[NSUserDefaults standardUserDefaults] removeObjectForKey: @AppleLanguages]; отменить и вернуться к языку по умолчанию - person William Denniss; 10.03.2010
comment
Деннисс; Кажется, будет лучше, если вы установите языковые предпочтения до запуска приложения. Я делаю это в функции main () до вызова UIApplicationMain (). После того, как он действительно запущен, он не изменит используемый язык, а просто установит предпочтения на следующий раз. - person geon; 02.09.2010
comment
Вы должны установить язык перед инициализацией UIKit, и вы должны указать полный язык + региональную локаль - посмотрите полный пример blog.federicomestrone.com/2010/09/15/ - person fedmest; 21.04.2011
comment
работает для NSLocalizedString, но для изображений у меня не работает - person AmineG; 09.05.2012
comment
Клавиатура не локализована, я все еще получаю английскую версию. Может ли кто-нибудь помочь с этим. - person satish; 12.10.2012
comment
@geon и @Brian Webster, большое спасибо. У меня есть все, что нужно для тестирования моего приложения для разных языковых настроек без необходимости проходить через настройки интернационализации. - person Jason TEPOORTEN; 17.03.2013
comment
установка AppleLanguages ​​изменит язык во время выполнения, если это сделано в main () - true! но ... В ПЕРВЫЙ РАЗ, когда приложение установлено, nsuserdefaults инициализируются ПОСЛЕ вызова UIApplicationMain (), который проигнорирует ранее установленные AppleLanguages ​​и потребует уродливого принудительного перезапуска приложения, чтобы увидеть нужный язык. - person JohnPayne; 09.09.2013
comment
Также не забудьте удалить ключ AppleLanguages ​​сразу ПОСЛЕ вызова UIApplicationMain (), то есть в applicationDidEnterBackground в AppDelegate. Это позволит пользователю позже изменить язык вручную! - person Sunkas; 19.11.2014
comment
Я делаю тот же код, что и выше, также реинформировал UIviews, но язык приложения не отражается мгновенно. Если нажать HOME и снова запустить приложение, язык также не изменится. Если приложение запускается в другой раз из xcode, значит, оно работает. Чего не хватает? - person sn86; 19.12.2014
comment
Похоже, ни одно из этих решений не изменит макет представлений для языков rtl без перезапуска. правильно? - person hasan; 12.01.2015
comment
Как вы узнали, как это сделать ??! Удивительный. В любом случае, перевод на Swift здесь: stackoverflow.com/a/33685575/8047 - person Dan Rosenstark; 13.11.2015
comment
а в swift нет main.h? - person Van Du Tran; 02.12.2015
comment
Это не работает с элементами множественного числа, определенными в Localizable.stringsdict. Есть идеи, есть ли возможное исправление? - person Mihai Fratu; 09.12.2015
comment
симулятор зависает - person Hogdotmac; 26.09.2017
comment
Избегайте ключевых языков AppleLanguages. Ключ используется внутри Xcode для целей отладки и может выйти из строя с новыми выпусками SDK. Начиная с iOS 13 используйте предпочтительные языки: reddit.com/r/iOSBeta/comments / bxfkzm / Если вы поддерживаете версии до iOS 13, предпочтите индивидуальное решение, в котором поведение можно проверить и не полагаться на частные реализации. - person Botond Magyarosi; 12.04.2020

Недавно у меня была такая же проблема, и я не хотел ни запускать, ни исправлять всю мою 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)
    }
}
person Gilad Novik    schedule 28.11.2013
comment
Есть опыт работы с этим? Это работает? Гилад, ты все еще успешно пользуешься этим? - person Wirsing; 25.03.2014
comment
Привет, @Wirsing, пока у меня все отлично работает. Я даже загрузил одно приложение в магазин, и от Apple никаких претензий нет. - person Gilad Novik; 25.03.2014
comment
Это отличное решение, я также упоминал об этом здесь: medium.com/ios-apprentice/905e4052b9de < / а> - person James Tang; 06.05.2014
comment
Привет @JamesTang, Спасибо за ссылку и ваш пост - я нашел там много полезной информации по локализации. - person Gilad Novik; 07.05.2014
comment
@Gilad, ваш метод идеально подходит для динамических строк (строк, которые я определил в localizable.strings), но что касается кнопок раскадровки и меток, он работает только с основным методом. Итак, можете ли вы расширить свой ответ, включив локализацию элементов управления пользовательского интерфейса? я имею в виду, как обновить (не закрывая) раскадровку после вызова [NSBundle setLanguage: @ ??] ;? - person Jawad Al Shaikh; 14.05.2014
comment
Что касается XIB / раскадровки: вам нужно убедиться, что вы вызываете этот метод ДО загрузки представления. Что касается обновления представлений в реальном времени: в моем случае я просто перезагрузил контроллер представления (я поместил его в контроллер навигации и просто заменил контроллер. После перезагрузки он получил новые переведенные строки). Я работаю над кокоаподом для него, наверное, я тоже включу туда пример. Быть в курсе... - person Gilad Novik; 15.05.2014
comment
@Gilad отлично работает со строками, но проблема возникает при использовании локализованного представления xib !! - person mohammad alabid; 15.05.2014
comment
на основе опубликованной ссылки @JamesTang: обновление раскадровки через контроллер можно выполнить с помощью: включая appDelegate.h, затем: appDelegate * delg = [UIApplication sharedApplication] .delegate; delg.window.rootViewController = [self.storyboard instantiateInitialViewController]; две вышеупомянутые строки сбрасывают раскадровку в режим ожидания, поэтому убедитесь, что при этом не происходит никаких действий, также вам нужно где-то хранить текущий язык вместо того, чтобы использовать en по умолчанию при каждой загрузке приложения ... - person Jawad Al Shaikh; 15.05.2014
comment
@mohammadalabid действительно нет необходимости загружать язык вручную - я успешно использовал этот код и с XIB. Моя уловка заключалась в том, чтобы использовать корневой контроллер как UINavigationController, и сразу после изменения языка я использую его свойство viewControllers для перезагрузки XIB. rootNavigationController.viewControllers = @ [[экземпляр раскадровкиViewControllerWithIdentifier: @main]]; Я скоро выложу пример на github. - person Gilad Novik; 15.05.2014
comment
Привет, Гилад, вы уже разместили пример на github? Спасибо! - person neowinston; 21.06.2014
comment
Привет, это здорово. Это работает для меня. Но для имиджа это не работает. Я спросил здесь. Кто-нибудь может мне помочь? stackoverflow.com/questions/25379056/ - person Khant Thu Linn; 19.08.2014
comment
Привет, Гилад, спасибо за отличное решение, но в моем случае это изменение текста, но не выравнивание с LTR на RTL при выборе арабского языка. Работа с правильным AutoLayout и выравниванием RTL работает, когда пользователь изменяет язык своего устройства в настройках устройства. - person Muhammad Saad Ansari; 08.04.2015
comment
Он работает, но он не устанавливает тот текст, который задается с помощью didfinishlaunching ?? - person Ravi Ojha; 02.12.2015
comment
Это не работает с элементами множественного числа, определенными в Localizable.stringsdict. Есть идеи, есть ли возможное исправление? - person Mihai Fratu; 09.12.2015
comment
Есть идеи, как это сделать быстро? @gilad - person royherma; 18.07.2016
comment
Это не работает для локализованных UIImages. Есть ли способ использовать локализованные изображения с помощью NSBundle, которые динамически перезагружаются без необходимости убивать ваше приложение? - person dvp.petrov; 26.07.2016
comment
Это работает. Для новичков в Swift просто создайте для этого заголовок моста и используйте. Прекрасно работает. - person Harsha; 05.08.2016
comment
@Gilad, когда я меняю его на другой язык во время выполнения в моем приложении и возвращаюсь к просмотру контроллера ... ничего не влияет ... так что любая идея, почему это так ??? - person EI Captain v2.0; 15.08.2016
comment
@ EICaptainv2.0: вам необходимо перезагрузить контроллер (проверьте один из моих предыдущих комментариев, объясняющих эту проблему). При перезагрузке контроллера - он перезагрузит вид (из новой связки) - person Gilad Novik; 16.08.2016
comment
@ Гилад весь день бился головой о стену. Ваш вариант кажется подходящим, но я не могу заставить мою раскадровку загружать локализованную раскадровку. Несмотря ни на что, он остается на языке по умолчанию. Я сделал паузу в setLanguage, который вызывается один раз в AppDelegate и один раз для смены языка, прежде чем я загружу свою раскадровку. Я также сделал перерыв в localizedStringForKey, но он никогда не вызывается. Будет ли это работать, только если мой код вручную вызывает localizeStringForKey? Я надеялся, что это сработает для самого процесса загрузки раскадровки. - person Chuck Krutsinger; 18.08.2016
comment
@ChuckKrutsinger вам необходимо перезагрузить раскадровку (шаблон по умолчанию загружает ее один раз и сохраняет в делегате приложения) - вам необходимо перезагрузить ее после изменения языка, чтобы она использовала новую раскадровку (с правильным языком). - person Gilad Novik; 18.08.2016
comment
@ Гилад - Спасибо, что вернулся. Я уже менял язык перед загрузкой раскадровки. Проблема в том, что UIStoryboard не вызывает localizedStringForKey при загрузке этих локализованных раскадровок. Похоже, что он вызывает + storyboardWithName: bundle:, передавая пакет, содержащий локализованную раскадровку. Я собираюсь использовать этот механизм и в своей ситуации. - person Chuck Krutsinger; 18.08.2016
comment
@Gilad - придумал простой способ выполнить то, что мне нужно, на основе расширения вашего решения одной дополнительной функцией: [UIStoryboard storyboardWithName: storyboardName bundle: [NSBundle localizedBundle]] с использованием + (NSBundle ) localizedBundle {NSBundle bundle = objc_getAssociatedObject ([собственный mainBundle], & _bundle); вернуть пакет? комплект: [собственный mainBundle]; } В локализованном пакете есть локализованные раскадровки построителя интерфейса. - person Chuck Krutsinger; 19.08.2016
comment
@ChuckKrutsinger, не могли бы вы объяснить, как использовать ваш код ..? - person Majid Bashir; 09.09.2016
comment
@magid Сначала я локализовал раскадровки, используя Interface Builder, но НЕ базовую локализацию. - person Chuck Krutsinger; 10.09.2016
comment
@magid Сначала я локализовал раскадровки, используя Interface Builder, но НЕ базовую локализацию. Когда я программно запускаю раскадровку, мне нужно сказать UIStoryboard, чтобы он посмотрел в локализованный пакет, на который указывает ответ Гилада выше для NSBundle + Language. Код для получения локализованной раскадровки: UIStoryboard * aStoryboard = [UIStoryboard storyboardWithName: tStoryboardName bundle [NSBundle localizedBundle]] Надеюсь, что это поможет. - person Chuck Krutsinger; 10.09.2016
comment
Я не мог заставить это работать .. Хотя я вызываю настройки setLanguage в моем файле main.m .. - person Aks; 09.08.2017
comment
не удалось заставить это работать на iOS 11. Кто-нибудь еще сталкивается с такой же проблемой? - person user3752049; 03.11.2017

Обычно я делаю это таким образом, но в вашем проекте ДОЛЖНЫ быть все файлы локализации.

@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
person Mauro Delrio    schedule 17.11.2009
comment
Красиво, работает отлично. Я изменил метод инициализации, чтобы просто сделать bundle = [NSBundle mainBundle]; вместо. Таким образом, вам не нужно иметь все файлы локализации в вашем проекте. - person quano; 23.02.2010
comment
+1. Это действительно хороший трюк, которого я больше нигде не видел. Создав дополнительный пакет из одной из папок локализации, вы можете заставить строковый материал нормально работать, если вы оберните NSLocalizedString чем-то, что здесь обходится. - person Ben Zotto; 28.06.2010
comment
Думаю, лучший подход - использовать [NSLocale preferredLanguages]. - person nonamelive; 17.01.2012
comment
Превосходный Мауро. Я заметил, что он также может работать с файлами из вашего проекта. Если по какой-то причине (как в моем случае) вам нужно загрузить файлы строк из сети и сохранить их в каталоге «Документы» (со структурой папок Documents / en.lproj / Localizable.strings, Documents / fr.lproj / Localizable.strings, ...). Вы даже можете создать NSBundle. Просто используйте этот код для пути: NSString * path = [NSHomeDirectory () stringByAppendingPathComponent: [NSString stringWithFormat: @ / Documents /% @. Lproj, l, nil]]; - person arnaud del.; 07.02.2012
comment
Мне кажется, что это лучший подход, наряду с вкладом Алессандро ниже. Это не так навязчиво и не требует перезагрузки. - person PKCLsoft; 29.02.2012
comment
Что я делаю неправильно? Я создал класс Language, унаследовав NSObject, поместил его в реализацию, поместил имена методов в .h, затем поместил [Language setLanguage: @es]; в моей кнопке смены языка код запускается (вызывается метод кнопки и переходит в класс языка), но ничего не делает. У меня тоже настроены мои localizable.strings (испанский). Но, похоже, это работает для многих других людей. Пожалуйста, сделай мне глупость. - person SirRupertIII; 20.11.2012
comment
@KKendall вы называете это так: [Language setLanguage: @es]; NSString * stringToUse = [Language get: @Your Text alter: nil]; - person Mikrasya; 28.09.2013
comment
связанный вопрос в основном как сделать то же самое с локализованными раскадровками - person abbood; 20.08.2014
comment
Это не работает с элементами множественного числа, определенными в Localizable.stringsdict. Есть идеи, есть ли возможное исправление? - person Mihai Fratu; 09.12.2015
comment
Как его использовать, я не понимаю, или он не работает в симуляторе - person Mohammed Hussain; 25.01.2017
comment
У меня есть файл Localizable.string, но он все еще не работает на iOS 10.2. - person Biranchi; 07.02.2017

Не использовать на 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, @""));
person Tudor    schedule 28.10.2011
comment
@ powerj1984: нет, он изменит только строки в ваших исходных файлах. Если вы хотите изменить языки xib, вам необходимо вручную перезагрузить xib из пакета выбранного вами языка. - person gklka; 24.01.2014
comment
@gklka Я выполнил шаги, данные Tudozier, но мои XIB не меняют язык, как вы сказали, перезагрузить XIB вручную, что на самом деле означает перезагрузка XIB? - person Dk Kumar; 22.02.2014
comment
@DkKumar: вы должны сделать что-то подобное: stackoverflow.com/questions/21304988/ - person gklka; 22.02.2014
comment
@gklka Ваш ответ кажется правильным, и я выполнил те же шаги, которые вы описали в своем ответе, но проблема заключается в том, что если мы изменим путь к пакету, он найдет весь ресурс (т.е. файл .png, используемый в XIB) в тот же пакет, поэтому мы должны скопировать папку изображений во всех пакетах, таких как en.lproj, es.lproj и т. д., что повлияет на увеличение размера IPA, так есть ли способ решить эту проблему? как вы сказали в своем посте, позвольте мне попробовать это и дать вам больше об этом Спасибо за то, что помогли мне в том же - person Dk Kumar; 24.02.2014
comment
@gklka Я проверил, что он работает, но есть 2 основные проблемы: # 1 вам нужно инициализировать XIB каждый раз, # 2 размер моего IPA увеличивается с 16,5 - ›195 МБ, это большое изменение, я думаю, потому что есть много изображений там в моем приложении - person Dk Kumar; 24.02.2014
comment
@DkKumar: да, у этого метода известны эти побочные эффекты. Есть еще одно: вы должны изменить все свои раскадровки одну за другой, если что-то изменится. Пожалуйста, дайте мне знать, если найдете что-нибудь получше! - person gklka; 24.02.2014
comment
Это ужасно нарушено в iOS 9, возвращая нуль для всех строк. - person Alex Zavatone; 14.10.2015
comment
Верно. iOS 9 больше не поддерживает это. - person Tudor; 14.10.2015

Как было сказано ранее, просто сделайте:

[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];

Но чтобы избежать перезапуска приложения, поместите строку в основной метод main.m непосредственно перед _3 _ (...).

person Frédéric Feytons    schedule 25.06.2010
comment
Очень полезный ответ! P.S. Для новичков это может показаться очевидным, но вы должны вставить эту строку после NSAutoreleasePool * pool .. или нескольких автоматически выпущенных объектов. - person pt2ph8; 18.07.2011
comment
ВАЖНО: это не сработает, если вы позвоните [[NSBundle mainBundle] URLForResource:withExtension:] раньше. - person Kof; 30.07.2013
comment
А если использовать Swift, то main.m нет? - person turingtested; 24.11.2015
comment
@turingtested пробовали ли вы Swift и раскадровку, это работает? - person iDevAmit; 22.12.2016
comment
Привет, как локализовать динамический текст, который поступает с сервера, в моем приложении каждый текст, который я должен отображать на упрощенном китайском языке, но как отображать текст на китайском языке, который идет на английском языке. Помоги мне. - person Mahesh Narla; 28.03.2017
comment
Я добавил это перед UIApplicationMain(argc, но все же изменение языка вступает в силу только после перезапуска. Есть ли способ избежать этого? - person user3752049; 23.06.2017

Уловка для использования определенного языка, выбирая его из приложения, заключается в том, чтобы заставить NSLocalizedString использовать определенный пакет в зависимости от выбранного языка,

вот сообщение, которое я написал для этого продвинутого обучения локализация в приложениях для ios

и вот код одного примера приложения расширенной локализации в приложениях ios

person object2.0    schedule 01.05.2011
comment
Он работает и на iOS7, мне нужно переключиться с решения Брайана на это, поскольку похоже, что iOS снова переопределяет параметр языков, поэтому я застрял на первоначальной настройке языка. Ваше решение работает как шарм! - person haxpor; 28.12.2013

Что вы думаете об этом решении для 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.
person Bartłomiej Semańczyk    schedule 13.12.2016
comment
Привет, как локализовать динамический текст, который поступает с сервера, в моем приложении каждый текст, который я должен отображать на упрощенном китайском языке, но как отображать текст на китайском языке, который идет на английском языке. Помоги мне. - person Mahesh Narla; 28.03.2017
comment
Это блестящий ответ;) - person Bartłomiej Semańczyk; 12.04.2019
comment
отличный ответ. помог мне - person Dilip Tiwari; 26.09.2019

Как упоминает Брайан Вебстер, язык необходимо установить «на раннем этапе запуска вашего приложения». Я подумал, что 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;
}

Буду признателен за любые комментарии по этому поводу.

person geon    schedule 01.09.2010
comment
в моей реализации это настраивается пользователем, поэтому я просто открываю диалоговое окно, сообщающее им, что им нужно будет перезапустить :) - person William Denniss; 04.09.2010
comment
Это работает почти для всех, кроме локализованного изображения Default.png. - person Lukasz; 30.11.2010
comment
Если вы позволяете пользователям устанавливать язык, а затем говорите им перезапустить приложение, просто помните, что NSUserDefaults может не сохраниться, если они перезапустятся слишком быстро. Большинство пользователей не так быстро, но когда вы тестируете приложение, вы можете быть слишком быстрыми и в результате увидеть непоследовательное поведение. Мне потребовалось несколько часов, чтобы понять, почему мой языковой переключатель иногда работает, а иногда нет! - person arlomedia; 04.01.2013
comment
Это не проблема, просто используйте [[NSUserDefaults standardUserDefaults] synchronize]; после вызова setObject:forKey: - person Ben Baron; 01.02.2013

Мне больше всего нравится метод Мауро Дельрио. Я также добавил следующее в свой Project_Prefix.pch

#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]

Поэтому, если вы когда-нибудь захотите использовать стандартный метод (который использует NSLocalizedString), вы можете произвести быструю замену синтаксиса во всех файлах.

person dnaxxx    schedule 27.01.2011
comment
Мне также нравится его метод, и я добавляю метод для загрузки изображений png: + (UIImage ) imageNamed: (NSString *) imageFileName {NSString fullPath = [bundle pathForResource: imageFileName ofType: @png]; UIImage * imageObj = [[распределение UIImage] initWithContentsOfFile: fullPath]; return [imageObj autorelease]; } - person Jagie; 11.07.2011

NSLocalizedString() считывает значение ключа AppleLanguages из стандартных пользовательских значений по умолчанию ([NSUserDefaults standardUserDefaults]). Это значение используется для выбора подходящей локализации среди всех существующих локализаций во время выполнения. Когда Apple создает пользовательский словарь по умолчанию при запуске приложения, они ищут ключ предпочитаемого языка (ов) в системных настройках и копируют значение оттуда. Это также объясняет, например, почему изменение языковых настроек в OS X не влияет на запущенные приложения, только на приложения, запущенные после этого. После копирования значение не обновляется только из-за изменения настроек. Вот почему iOS перезапускает все приложения, если вы меняете язык.

Однако все значения пользовательского словаря по умолчанию могут быть перезаписаны аргументами командной строки. См. NSUserDefaults документацию на NSArgumentDomain. Сюда входят даже те значения, которые загружаются из файла настроек приложения (.plist). Это действительно полезно знать, если вы хотите изменить значение только один раз для тестирования.

Поэтому, если вы хотите изменить язык только для тестирования, вы, вероятно, не захотите изменять свой код (если вы забудете удалить этот код позже ...), вместо этого скажите Xcode запустить ваше приложение с параметрами командной строки ( например, используйте испанскую локализацию):

введите описание изображения здесь

Не нужно вообще трогать ваш код. Просто создайте разные схемы для разных языков, и вы сможете быстро запустить приложение один раз на одном языке и один раз на другом, просто переключив схему.

person Mecki    schedule 10.09.2014
comment
Работает только 1 раз, после чего снова загружается в устройство pref. язык .. - person Aks; 01.08.2017
comment
@Aks У меня работает каждый раз. Убедитесь, что вы запускаете правильную схему, убедитесь, что вы начинаете из Xcode (перезапуски, вилки и т. Д. Не получат аргумент) и убедитесь, что вы не переопределяете язык в Options, как в более новых версиях Xcode, которые предлагает Apple. это тоже. - person Mecki; 02.08.2017
comment
Спасибо за ваш ответ @Mecki .. Для меня он не работает в xcode, но когда я упоминаю в коде, он работает .. Но все же, если я настроил свое устройство на некоторые другие предпочтительные языки, ему необходимо перезапустить приложение, чтобы загрузить его в предпочтительный язык, который я передаю в аргументах .... - person Aks; 02.08.2017
comment
@Aks При использовании этого на устройстве он будет работать только при запуске непосредственно из Xcode, он не будет работать, когда вы снова запустите приложение, нажав его значок на каком-либо устройстве, и он также не будет работать, когда приложение будет убито (например, потому что он перешел в фоновый режим) и перезапускается системой (поскольку этот перезапуск не является перезапуском, выполняемым Xcode), поэтому переключение на другое приложение и обратно может не сработать, если iOS должна убить ваше приложение в промежутке (например, потому что оно нужна память). - person Mecki; 03.08.2017
comment
Вы можете объединить этот проход аргумента с изменением в StandardUserDefaults, и он будет работать как шарм каждый раз - person L33MUR; 08.07.2020

Я придумал решение, позволяющее использовать 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

Затем просто добавьте import NSBundle+RunTimeLanguage.h в файлы, которые используют NSLocalizedString.

Как видите, я храню свой languageCode в свойстве AppDelegate. Его можно хранить где угодно.

Единственное, что мне не нравится в этом, - это предупреждение, которое NSLocalizedString переопределил marco. Возможно, кто-нибудь поможет мне исправить эту деталь.

person qman64    schedule 30.04.2014
comment
Добавьте #undef NSLocalizedString непосредственно перед #define, чтобы отключить предупреждение. - person beryllium; 03.05.2014
comment
Это работает при локализации для файла xib? У меня есть файл .xib и .strings для перевода имени пользовательского интерфейса на определенный язык. Я пробовал, и он не работает с XIB, но я не уверен, правильно ли я все сделал. - person Kong Hantrakool; 01.03.2015
comment
Конг извините за задержку с ответом. Это работает везде, где вы используете NSLocalizedString. Таким образом, он не будет работать напрямую в XIB. Вам понадобятся IBOutlets для строк в XIB, а затем придется программно устанавливать строковые значения в коде. - person qman64; 13.10.2015
comment
Этот подход сработал для меня, и я мог менять языки на лету. Обратите внимание, что языковые коды, такие как es, fr и en, работали нормально. Но zh (для упрощенного китайского) не удалось и вернул мне нулевые строки. Я произвел глобальный поиск es.lproj в своей системе, чтобы увидеть, где находятся файлы, к которым я обращался, и обнаружил, что zh.lproj на самом деле zh-Hans.lproj. - person Gallymon; 23.07.2018

Быстрая версия:

NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()
person daaniaal    schedule 28.12.2014

В двух словах :

Локализуйте свое приложение

Первое, что вам нужно сделать, это локализовать свое приложение как минимум на два языка (английский и французский в этом примере).

Переопределить NSLocalizedString

В вашем коде вместо использования NSLocalizedString(key, comment) используйте макрос MYLocalizedString(key, comment), определенный следующим образом: #define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

Этот MYLocalizationSystem синглтон будет:

  • Установите язык, указав правильный локализованный NSBundle, который запрашивает пользователь
  • Возвращает локализованную строку NSString в соответствии с этим ранее установленным языком.

Установить язык пользователя

Когда пользователь изменил язык приложения на французский, позвоните [[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

person jgodon    schedule 22.04.2015
comment
Мы просим вас не просто ссылаться на решение в своем ответе; ссылка может когда-нибудь перестать работать. Хотя вам не нужно удалять ссылку из своего ответа, мы просим вас отредактировать свой ответ, включив в него краткое изложение соответствующего раздела связанной статьи. - person Oblivious Sage; 22.04.2015

Расширения 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
person ChikabuZ    schedule 26.07.2017
comment
Спасибо. Работает хорошо. - person Krunal Nagvadia; 07.05.2019
comment
Да, он работает, но приложение необходимо перезапустить, чтобы изменить язык. - person Hasan Can Gunes; 27.02.2021

В 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

Я не знаю, лучший ли это способ, но я нашел его очень простым, и он работает для меня, надеюсь, он вам поможет!

person ainareta685    schedule 13.05.2019
comment
Этот ответ великолепен, потому что он также работает, например, в Swift Package, работающем в Linux. - person Rémi B.; 30.09.2020

В файле .pch определить:

#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]


#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
person MrPiliffo    schedule 13.03.2013
comment
Как мне избавиться от предупреждения "ovverride ..."? - person Idan Moshe; 19.02.2014
comment
Простое решение делает все, что мне нужно. Смог использовать это как руководство для решения моей проблемы. Если pathForResource возвращает nil, потому что у меня нет файла локализации, я использую pathForResource: @Base, поскольку ничто другое, что я пробовал, не извлекает строки из базовой локализации. Спасибо. - person GRW; 19.09.2014
comment
Это хакерский (как и все остальные ответы), и его было проще всего реализовать в модульном тесте, который я писал. - person Max; 11.12.2019

Возможно, вам стоит дополнить это (в файле .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]
person D33pN16h7    schedule 04.08.2011
comment
/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31: использование необъявленного идентификатора 'bundle' - person pengwang; 12.03.2013

Решение 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")

Приведены примеры языковых кодов, которые можно использовать. Надеюсь это поможет

person Jeremy Bader    schedule 23.06.2017

Вы можете создать вложенный пакет с набором локализованных строк, с которыми вы хотите это сделать, а затем использовать _ 1_, чтобы загрузить их. (Я предполагаю, что это контент, отдельный от обычной локализации пользовательского интерфейса, которую вы, возможно, делаете в приложении.)

person Sixten Otto    schedule 03.11.2009

в моем случае у меня есть два локализованных файла, 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]));


    }


}
person chings228    schedule 02.04.2014
comment
Спасибо @ chings228, это полезно для меня, но это не меняет изображение запуска по умолчанию (заставку) для приложения. У меня есть разные заставки для каждого языка. вы знаете, как подать заявку на это ?? - person JERC; 04.06.2014
comment
Я думаю, что заставка запускается до запуска основной программы, поэтому я не знаю, как ее переопределить, может быть, plist может помочь, но он может сработать в следующий раз, когда приложение откроется - person chings228; 05.06.2014

Вы можете сделать что-то вроде этого:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];


NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];

NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
person JERC    schedule 17.11.2014

Вот достойное решение этой проблемы, не требующее перезапуска приложения.

https://github.com/cmaftuleac/BundleLocalization

Эта реализация работает путем настройки внутри NSBundle. Идея состоит в том, что вы переопределяете метод localizedStringForKey в экземпляре объекта NSBundle, а затем вызываете этот метод в другом пакете с другим языком. Простой и элегантный, полностью совместим со всеми типами ресурсов.

person Corneliu Maftuleac    schedule 16.04.2015
comment
Этот код из проекта мне очень помог. Как найти комплект для кода конкретного языка --- NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ]; - person eonil; 12.04.2016
comment
Этот класс работает нормально, но после изменения языка на другой это не влияет. - person Anilkumar iOS - ReactNative; 04.08.2016

На основе ответа 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"];
person Antonioni    schedule 28.10.2015

Эта функция попытается получить локализованную строку для текущего языка и, если она не найдена, получит ее на английском языке.

- (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;
}
person Cherpak Evgeny    schedule 17.06.2013

Я хотел добавить поддержку языка, который официально не поддерживается 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]));
    }
}

Это хорошо работает как для кода раскадровки, так и для кода NSLocalizedString. Код предполагает, что позже у пользователя будет возможность вручную изменить язык внутри приложения.

Конечно, не забудьте добавить правильные переводы раскадровки и переводы Localizable.strings (см. Ссылку на страницу Apple выше, чтобы узнать, как это сделать).

person frin    schedule 09.10.2013
comment
Я вижу, что вы также сталкиваетесь с проблемами со словенским языком :) Чтобы улучшить этот ответ для языков, не поддерживаемых iOS, вы выяснили, можем ли мы установить настраиваемые локализуемые строки, которые будут использоваться для системных элементов управления в приложении (Edit, Done, More, ...)? - person miham; 18.07.2016

Что бы вы ни делали, лучший способ - взять short_name для указанного языка, например: fr, en, nl, de, it и т. д., и присвоить его глобальному значению.

сделайте окно выбора всплывающим, как раскрывающееся меню (комбинация кнопки, при нажатии которой снизу появляется окно выбора со списком языков) и выберите желаемый язык. пусть короткое имя хранится внутри. создайте файл .h + .m с именем LocalisedString.

Установите глобальное значение short_name равным полученному значению в LocalisedString.m. Когда выбран требуемый язык, назначьте NSBundlePath для создания подкаталогов проекта для необходимого языка. например, для nl.proj, en.proj.

Когда выбрана конкретная папка proj, вызовите локализованную строку для соответствующего языка и измените язык динамически.

правила не нарушены.

person Abhijeet    schedule 12.08.2011

Для 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 файле.

person Andreas    schedule 01.07.2019