Я использую одиночную локализованную раскадровку для своего приложения. Приложение должно иметь возможность менять язык "на лету". До сих пор я выяснял, как изменить язык, который используется во время запуска приложения:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
И удалось перезагрузить все мое приложение, удалив все подпрограммы в ключевом окне, перезагрузив исходный контроллер представлений из раскадровки и сделав его новым контроллером корневого представления. (У него есть некоторые проблемы, такие как управление открытыми ресурсами, но это можно сделать.)
Единственное, что я не мог понять, это как заставить iOS перезагрузить раскадровку на новом языке? Кажется, что раскадровки так или иначе кэшированы, а -UIStoryboad:stroyboardWithName:fromNib
не перезагружает его полностью, поэтому он появляется на последнем языке.
Я уже рассмотрел два других варианта:
-
с разными файлами раскадровки для каждого языка (это неприменимо, я не хочу этого делать)
-
используя прослушиватели событий во всех моих контроллерах представления, которые реагируют на изменение языка и устанавливают новые строки в пользовательском интерфейсе (который также должен вызываться каждый раз, когда какой-либо элемент интерфейса получает экземпляр из раскадровки). Это решение требует больше времени, чем мы хотели бы потратить на это, а также сильно увеличивает вероятность ошибок.
Есть ли еще более умный способ? Я не хочу сохранять текущее состояние своего приложения, поэтому перезапуск его, как будто он был убит, а реальная работа - разумное разрешение.
Ответ 1
Итак, я обнаружил, что проблема связана с базовым переводом моей раскадровки, что означает, что у меня был только один файл раскадровки и один файл .strings на один язык для него. Это не может быть сделано с использованием базовых переводов, Apple не поддерживает его.
Итак, моим обходным решением было следующее:
-
Преобразуйте базовые переводы на один раскадровки на каждый язык (вы можете сделать это в Xcode, когда вы нажимаете раскадровку и устанавливаете тип в Storyboard из строк). Вы можете удалить базу в конце.
-
Переведите строки в ваших раскадровки
-
В обработчике кнопок вашей кнопки изменения языка выполните следующие действия:
(Я использую контроллер табуляции в качестве корневого контроллера, вы должны изменить его на свой тип корневого контроллера.)
[[NSDefaults standardDefaults] setObject:[NSArray arrayWithObject:@"hu"] forKey:@"AppleLanguages"];
[[NSDefaults standardDefaults] synchronize];
GKAppDelegate *appDelegate = (GKAppDelegate *)[[UIApplication sharedApplication] delegate];
UITabBarController* tabBar = (UITabBarController *)appDelegate.window.rootViewController;
// reload the storyboard in the selected language
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:appDelegate.lang ofType:@"lproj"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:bundle];
// reload the view controllers
UINavigationController *placesTab = (UINavigationController *)[storyBoard instantiateViewControllerWithIdentifier:@"placesTab"];
UINavigationController *informationTab = (UINavigationController *)[storyBoard instantiateViewControllerWithIdentifier:@"informationTab"];
// set them
NSArray *newViewControllers = @[placesTab, informationTab];
tabBar.viewControllers = newViewControllers;
- этого недостаточно. После этого строки формы Storyboard должны менять язык, но строки из кода этого не делают. Для этого вам нужно это сделать:
В вашем файле appname.pch
:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
И вы должны изменить все это:
NSLocalizedString(@"key", @"comment")
:
NSLocalizedStringFromTableInBundle(@"key", nil, currentLanguageBundle, @"");
Обратите внимание, что я удалил второй параметр, комментарий. Похоже, что комментарии с буквами, отличными от ASCII, могут вызвать проблемы, поэтому лучше избегать их в этот момент.
- теперь каждая строка должна работать нормально. Осталось только одно: изображения, которые вы установили на своих раскадренных страницах, исчезают, когда вы меняете язык, потому что iOS не находит их в комплекте. Решением для этого является локализация всех из них (с помощью кнопки "Локализовать..." в Инспекторе файлов). Это явно дублирует изображения, но не волнуйтесь, не повлияет на ваш размер .ipa, потому что ZIP обрабатывает дубликаты очень хорошо. (У меня есть только удаленный размер 800 → 850k.)
Причины этого метода:
-
вы можете использовать системные инструменты для сбора строк в файлах .strings
-
Пользовательский интерфейс не будет мерцать при смене языка
-
вам не нужно писать много кода или использовать много торговых точек
-
код изменения языка должен запускаться только один раз, когда пользователь нажимает кнопку
Надеюсь, это поможет, и, возможно, вы сможете улучшить свое решение.
Ответ 2
У меня есть приложение с изменением языка на лету, и я просто всплываю весь контроллер и повторно инициализирую навигационный контроллер.