На iPhone NSLocalizedString
возвращает строку на языке iPhone. Можно ли заставить NSLocalizedString
использовать определенный язык, чтобы приложение отображало язык, отличный от языка устройства?
Как заставить NSLocalizedString использовать определенный язык
Ответы (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
Это сделает немецкий предпочтительным языком для вашего приложения, а английский и французский - запасными. Вы могли бы вызвать это когда-нибудь на раннем этапе запуска вашего приложения. Вы можете узнать больше о предпочтениях языка / локали здесь: Темы интернационализации программирования: получение текущего языка и локали
Недавно у меня была такая же проблема, и я не хотел ни запускать, ни исправлять всю мою 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.m
непосредственно перед _3 _ (...).
NSAutoreleasePool * pool ..
или нескольких автоматически выпущенных объектов.
- person pt2ph8; 18.07.2011
[[NSBundle mainBundle] URLForResource:withExtension:]
раньше.
- person Kof; 30.07.2013
UIApplicationMain(argc
, но все же изменение языка вступает в силу только после перезапуска. Есть ли способ избежать этого?
- person user3752049; 23.06.2017
Уловка для использования определенного языка, выбирая его из приложения, заключается в том, чтобы заставить 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:
- person Ben Baron; 01.02.2013
Мне больше всего нравится метод Мауро Дельрио. Я также добавил следующее в свой 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. это тоже.
- person Mecki; 02.08.2017
Я придумал решение, позволяющее использовать 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. Возможно, кто-нибудь поможет мне исправить эту деталь.
#undef NSLocalizedString
непосредственно перед #define
, чтобы отключить предупреждение.
- person beryllium; 03.05.2014
Быстрая версия:
NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()
В двух словах :
Локализуйте свое приложение
Первое, что вам нужно сделать, это локализовать свое приложение как минимум на два языка (английский и французский в этом примере).
Переопределить 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
Расширения 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
В 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
Я не знаю, лучший ли это способ, но я нашел его очень простым, и он работает для меня, надеюсь, он вам поможет!
В файле .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")
Приведены примеры языковых кодов, которые можно использовать. Надеюсь это поможет
Вы можете создать вложенный пакет с набором локализованных строк, с которыми вы хотите это сделать, а затем использовать _ 1_, чтобы загрузить их. (Я предполагаю, что это контент, отдельный от обычной локализации пользовательского интерфейса, которую вы, возможно, делаете в приложении.)
в моем случае у меня есть два локализованных файла, 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):
Вот достойное решение этой проблемы, не требующее перезапуска приложения.
https://github.com/cmaftuleac/BundleLocalization
Эта реализация работает путем настройки внутри NSBundle. Идея состоит в том, что вы переопределяете метод localizedStringForKey в экземпляре объекта NSBundle, а затем вызываете этот метод в другом пакете с другим языком. Простой и элегантный, полностью совместим со всеми типами ресурсов.
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
- person eonil; 12.04.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"];
Эта функция попытается получить локализованную строку для текущего языка и, если она не найдена, получит ее на английском языке.
- (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]));
}
}
Это хорошо работает как для кода раскадровки, так и для кода NSLocalizedString. Код предполагает, что позже у пользователя будет возможность вручную изменить язык внутри приложения.
Конечно, не забудьте добавить правильные переводы раскадровки и переводы Localizable.strings (см. Ссылку на страницу Apple выше, чтобы узнать, как это сделать).
Что бы вы ни делали, лучший способ - взять short_name для указанного языка, например: 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
файле.