Перезагрузка раскадровки для изменения языка

Я использую одиночную локализованную раскадровку для своего приложения. Приложение должно иметь возможность менять язык "на лету". До сих пор я выяснял, как изменить язык, который используется во время запуска приложения:

[[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

У меня есть приложение с изменением языка на лету, и я просто всплываю весь контроллер и повторно инициализирую навигационный контроллер.