it-swarm.com.ru

Изменить язык приложения в iOS без перезапуска приложения

Мне кажется, некоторые приложения могут изменить язык внутри приложения без необходимости перезапуска приложения, мне интересно, как они реализованы.

Например, для нас, использующих NSLocalizedString, я знаю, что можно установить язык во время выполнения на main.m, когда ваш AppDelegate не инициализирован, но как только он будет инициализирован (в частности, создан ваш контроллер представления), изменение не будет действовать до следующего запустить снова

[[NSUserDefaults standardUserDefaults] 
    setObject:[NSMutableArray arrayWithObjects:language, nil] 
    forKey:@"AppleLanguages"];

Кто-нибудь имеет представление, как эти динамические изменения языка могут быть сделаны без перезапуска приложения?

29
Ryan

Здесь обсуждаются другие подходы, в частности подход, основанный на уведомлениях:

iOS: Как программно изменить язык приложения БЕЗ перезапуска приложения?

На мой взгляд, здесь действительно три задачи: (1) перераспределение ресурсов, автоматически загружаемых из перьев. (например, если вы динамически создаете другой пользовательский UIView из пера, «старые» языковые строки и настройки (изображения, направление текста) все равно будут загружены) (2) повторная локализация строк, отображаемых в данный момент на экране. (3) повторная локализация строк, вставленных разработчиком (вами) в программный код.

Начнем с (3). Если вы посмотрите на определение, вы заметите, что NSLocalizedString является макросом. Поэтому, если вы не хотите слишком сильно изменять существующий код, вы можете решить проблему (3), создав новый заголовочный файл. В этом заголовочном файле #undef, а затем повторно -#define NSLocalizedString, чтобы выбрать локализованную строку из соответствующего места - не того, к которому по умолчанию применяется iOS, а того, которое вы отслеживаете в некоторой глобальной переменной (например, в делегате приложения ivar) , Если вы не хотите переопределять NSLocalizedString, но по-прежнему создаете свою собственную альтернативу, вам, вероятно, следует по-прежнему использовать #undef NSLocalizedString, если вы не хотите, чтобы будущие разработчики случайно вызывали его вместо макроса, которым вы его заменили. Не идеальное решение, но, возможно, самое практичное.

Что касается (1), если вы не выполнили свою локализацию в Интерфейсном Разработчике, а сделали это динамически в viewDidLoad и т.д., Нет проблем. Вы можете использовать то же поведение, которое только что обсуждалось (то есть, модифицированный NSLocalizedString и т.д.). В противном случае вы можете (а) внедрить систему уведомлений, как описано в приведенной выше ссылке (сложно), или (б) рассмотреть возможность перемещения локализации из IB в viewDidLoad, или (в) попробовать переопределить initWithNibName: и заменить объект, загруженный старым языком ресурсы, один из которых загружен новыми языковыми ресурсами. Это был подход, упомянутый Мохамедом в самом конце этой дискуссии: http://learning-ios.blogspot.ca/2011/04/advance-localization-in-ios-apps.html . Он утверждает, что это вызывает проблемы (viewDidLoad не вызывается). Даже если это не сработает, попытка это может указать вам на то, что работает.

Наконец, (2), вероятно, является самой простой задачей: просто удалите и повторно добавьте текущее представление (или, в некоторых случаях, просто перерисовайте его).

5
Merk

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

В метод 2 в этой статье объясняется, как именно это сделать . В данном конкретном случае автор не использует новый макрос, а непосредственно устанавливает пользовательский класс для [NSBundle mainBundle].

Я надеюсь, что @holex поймет проблему, читая это.

2
Matteo Gobbi

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

Этот класс получит доступ к предпочитаемым языкам из NSLocale и возьмет первый объект, который является используемым языком.

@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» в классе выше, чтобы получить строковый параметр, ссылающийся на новый код языка.

// Change the preferred language to Spanish
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
1
Antonioni

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


вы должны установить все тексты с помощью NSLocalizableString(...) для UI для текущего языка в методе -viewWillAppear: для каждого UIViewController.

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


Конечно, я использую стандартную архитектуру локализации Apple.

ОБНОВЛЕНИЕ (24 октября 2013 г.)

Я видел, что метод –viewWillAppear: не будет выполняться для реального представления, когда приложение выходит на передний план; чтобы решить эту проблему, я также фиксирую процедуру (см. выше), когда я получаю уведомление UIApplicationWillEnterForegroundNotification в представлении.

1
holex

Я застрял в той же проблеме, мое требование было «Пользователь может выбрать язык из выпадающего списка, и приложение должно работать в соответствии с выбранным языком (английский или арабский)». Что я сделал, я создал два XIB и получил XIB и текст в соответствии с выбранным языком. Таким образом, пользователь может выбрать язык. Я использовал NSBundle для того же. лайк 

Для XIB

self.homeScreen =  [[HomeScreen alloc] initWithNibName:@"HomeScreen" bundle:[CommonData sharedCommonData].languageBundle];

Для текста 

_lblHeading.text = [self languageSelectedStringForKey:@"ViewHeadingInfo"];

/**
 This method is responsible for selecting language bundle according to user's selection. 
 @param: the string which is to be converted in selected language. 
 @return: the converted string.
 @throws:
 */

-(NSString*) languageSelectedStringForKey:(NSString*) key

{

    NSString* str=[[CommonData sharedCommonData].languageBundle localizedStringForKey:key value:@"" table:nil];

    return str;

}
0
Mangesh