Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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


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

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


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

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

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

Ответ 4

Я застрял в одной и той же проблеме, мое требование: "Пользователь может выбрать язык из раскрывающегося списка, а приложение должно работать по выбранному языку (на английском или арабском)" Что я сделал, я создал два XIB и выбрал XIB и Text в соответствии с выбранными язык. Таким образом, пользователь может выбрать язык. Для этого я использовал 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 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;

}

Ответ 5

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

Этот класс получит доступ к привилегированным языкам из 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

Используйте вышеприведенный класс для ссылки на строковый файл/изображение/видео/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"];

Ответ 6

Вам нужно загрузить другой пакет, как это (где @ "en" может быть нужным вам в локали):

NSString *path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
NSBundle *languageBundle = [NSBundle bundleWithPath:path];

и создайте макросы/функции, такие как NSLocalizedString, которые используют ваш загруженный пакет или используют методы на этом узле прямо как это

[languageBundle localizedStringForKey:key value:value table:tableName];

[[NSBundle mainBundle] localizations] перечислены все локализации приложений (включая "Base" ).

Также я написал вспомогательный класс, который делает это (обратите внимание, что он имеет ReactiveCocoa как зависимость). Он позволяет изменять язык без перезагрузки приложения и отправляет текущий язык при каждом изменении.