ручной выбор языка в iOS-приложении (iPhone и iPad)



мой вопрос:



Как мое iPhone-приложение может сообщить iOS, что пользователь выбрал язык в настройках приложений, который отличается от языка, установленного в общих настройках?



другая формулировка того же вопроса:



Как я могу сказать системе, что NSLocalizedString (@"text", @"comment"); должен ли доступ не к выбранному в системе языку, а к выбранному в приложении языку?



фон, пример:



пожалуйста, возьмите эту ситуацию в качестве примера:
Сын немецких иммигрантов живет на северо-востоке Франции рядом с Люксембургом и Германией. Его родной язык-французский, поэтому он установил язык пользовательских интерфейсов своего iPhone на французский (Настройки- > Общие - > международные - > язык - > Français). Но из-за его культурного происхождения и потому, что регион, где он живет, является двуязычным, он также очень хорошо говорит по-немецки. Но он не произносит и десяти слов Английский. На iPhone (и iPad также) у него нет возможности выбрать второй язык, поэтому телефон знает только, что он распространяет французский. Он не имеет никаких знаний о навыках пользователей на других языках.



теперь приходит мое приложение: я разработал его на английском и немецком языках (немецкий-мой родной язык, а английский-стандартный язык в нем). Я разработал его в соответствии со всеми правилами и лучшими практиками для многоязыковых iOS-приложений. "Первый" язык (язык по умолчанию) моего приложения Английский.



это значит:



Если кто-то выбрал английский или немецкий в своих настройках, пользовательский интерфейс приложения автоматически будет использовать выбранный язык. Пользователь даже не заметит, что есть и другие языки.



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



добавление французского перевода решило бы проблему для нашего франко-немецкого друга, но не для людей, говорящих на двух других языках (таких как итальянский и немецкий), и я не могу поддерживать свое приложение со всеми языками, на которых говорят на этой планете.
Установка языка по умолчанию на немецкий также не является оптимальной, потому что это вызовет ту же проблему для людей говорит по-французски (родной язык) и по-английски (как второй язык).



Так что я думаю, что мое приложение должно иметь возможность вручную выбрать язык, который отличается от предварительно выбранного языка. Добавление выбора языка в панель настроек приложений-это не проблема. Но как я могу сказать системе, что NSLocalizedString (@"text", @"comment"); должен ли доступ не к выбранному в системе языку, а к выбранному в приложении языку?

592   6  

6 ответов:

тем временем я нашел решение своей проблемы на себе:

Я создал новый класс "LocalizeHelper":


Заголовок LocalizeHelper.h

//LocalizeHelper.h

#import <Foundation/Foundation.h>

// some macros (optional, but makes life easy)

// Use "LocalizedString(key)" the same way you would use "NSLocalizedString(key,comment)"
#define LocalizedString(key) [[LocalizeHelper sharedLocalSystem] localizedStringForKey:(key)]

// "language" can be (for american english): "en", "en-US", "english". Analogous for other languages.
#define LocalizationSetLanguage(language) [[LocalizeHelper sharedLocalSystem] setLanguage:(language)]

@interface LocalizeHelper : NSObject

// a singleton:
+ (LocalizeHelper*) sharedLocalSystem;

// this gets the string localized:
- (NSString*) localizedStringForKey:(NSString*) key;

//set a new language:
- (void) setLanguage:(NSString*) lang;              

@end

реализация LocalizeHelper.м

// LocalizeHelper.m
#import "LocalizeHelper.h"

// Singleton
static LocalizeHelper* SingleLocalSystem = nil;

// my Bundle (not the main bundle!)
static NSBundle* myBundle = nil;


@implementation LocalizeHelper


//-------------------------------------------------------------
// allways return the same singleton
//-------------------------------------------------------------
+ (LocalizeHelper*) sharedLocalSystem {
    // lazy instantiation
    if (SingleLocalSystem == nil) {
        SingleLocalSystem = [[LocalizeHelper alloc] init];
    }
    return SingleLocalSystem;
}


//-------------------------------------------------------------
// initiating
//-------------------------------------------------------------
- (id) init {
    self = [super init];
    if (self) {
        // use systems main bundle as default bundle
        myBundle = [NSBundle mainBundle];
    }
    return self;
}


//-------------------------------------------------------------
// translate a string
//-------------------------------------------------------------
// you can use this macro:
// LocalizedString(@"Text");
- (NSString*) localizedStringForKey:(NSString*) key {
    // this is almost exactly what is done when calling the macro NSLocalizedString(@"Text",@"comment")
    // the difference is: here we do not use the systems main bundle, but a bundle
    // we selected manually before (see "setLanguage")
    return [myBundle localizedStringForKey:key value:@"" table:nil];
}


//-------------------------------------------------------------
// set a new language
//-------------------------------------------------------------
// you can use this macro:
// LocalizationSetLanguage(@"German") or LocalizationSetLanguage(@"de");
- (void) setLanguage:(NSString*) lang {

    // path to this languages bundle
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
    if (path == nil) {
        // there is no bundle for that language
        // use main bundle instead
        myBundle = [NSBundle mainBundle];
    } else {

        // use this bundle as my bundle from now on:
        myBundle = [NSBundle bundleWithPath:path];

        // to be absolutely shure (this is probably unnecessary):
        if (myBundle == nil) {
            myBundle = [NSBundle mainBundle];
        }
    }
}


@end

для каждого языка, который вы хотите поддерживать вас нужен файл с именем Localizable.strings. Это работает точно так же, как описано в документации Apple для локализации. Единственная разница: сейчас вы даже можете использовать такие языки, как хинди или эсперанто, которые не поддерживаются Apple.

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

английский язык

/* English - English */

/* for debugging */
"languageOfBundle" = "English - English";

/* Header-Title of the Table displaying all lists and projects */
"summary" = "Summary";

/* Section-Titles in table "summary" */
"help" = "Help";
"lists" = "Lists";
"projects" = "Projects";
"listTemplates" = "List Templates";
"projectTemplates" = "Project Templates";

немецкий

/* German - Deutsch */

/* for debugging */
"languageOfBundle" = "German - Deutsch";

/* Header-Title of the Table displaying all lists and projects */
"summary" = "Überblick";

/* Section-Titles in table "summary" */
"help" = "Hilfe";
"lists" = "Listen";
"projects" = "Projekte";
"listTemplates" = "Vorlagen für Listen";
"projectTemplates" = "Vorlagen für Projekte";

чтобы использовать локализацию, у вас должны быть некоторые настройки-процедуры в вашем приложении, а в выборе языка вы вызываете макрос:

LocalizationSetLanguage(selectedLanguage);

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

чтобы иметь локализованные тексты, доступные для каждой ситуации, вы никогда не должны писать тексты исправлений в заголовки объектов. Всегда используйте макрос LocalizedString(keyword).

нет:

cell.textLabel.text = @"nice title";

do:

cell.textLabel.text = LocalizedString(@"nice title");

и есть" хороший заголовок " запись в каждой версии локализуется.струны!

просто добавьте следующее на экран с выбором языка:

    NSString *tempValue = //user chosen language. Can be picker view/button/segmented control/whatever. Just get the text out of it
    NSString *currentLanguage = @"";
    if ([tempValue rangeOfString:NSLocalizedString(@"English", nil)].location != NSNotFound) {
        currentLanguage = @"en";
    } else if ([tempValue rangeOfString:NSLocalizedString(@"German", nil)].location != NSNotFound) {
        currentLanguage = @"de";
    } else if ([tempValue rangeOfString:NSLocalizedString(@"Russian", nil)].location != NSNotFound) {
        currentLanguage = @"ru";
    }
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:currentLanguage, nil] forKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults]synchronize];

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

надеюсь, что это помогает

здесь готовые и пошаговое руководство о том, как использовать подход Novarg в Swift 3:


Шаг #1: реализация выбора языка

как лучше всего сделать это зависит от вас и зависит от проекта. Но используйте

Bundle.main.localizations.filter({  != "Base" }) // => ["en", "de", "tr"]

и список всех поддерживаемых локалей код языка программно. Также вы можете использовать

Locale.current.localizedString(forLanguageCode: "en") // replace "en" with your variable

в настоящее время язык имя в приложения текущий язык.

в качестве полного примера вы могли бы представьте лист действия popover после нажатия кнопки, как это:

@IBOutlet var changeLanguageButton: UIButton!

@IBAction func didPressChangeLanguageButton() {
    let message = "Change language of this app including its content."
    let sheetCtrl = UIAlertController(title: "Choose language", message: message, preferredStyle: .actionSheet)

    for languageCode in Bundle.main.localizations.filter({  != "Base" }) {
        let langName = Locale.current.localizedString(forLanguageCode: languageCode)
        let action = UIAlertAction(title: langName, style: .default) { _ in
            self.changeToLanguage(languageCode) // see step #2
        }
        sheetCtrl.addAction(action)
    }

    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
    sheetCtrl.addAction(cancelAction)

    sheetCtrl.popoverPresentationController?.sourceView = self.view
    sheetCtrl.popoverPresentationController?.sourceRect = self.changeLanguageButton.frame
    present(sheetCtrl, animated: true, completion: nil)
}

Шаг #2: объясните пользователю, что делать + изменить язык с перезагрузкой

возможно, вы заметили, что код в шаге #1 вызывает метод с именем changeToLanguage(langCode:). Это что Вы тоже должны делать когда пользователь выбирает новый язык, не важно как вы разработали свой выбор. Вот это его реализации, просто скопируйте его в свой проект:

private func changeToLanguage(_ langCode: String) {
    if Bundle.main.preferredLocalizations.first != langCode {
        let message = "In order to change the language, the App must be closed and reopened by you."
        let confirmAlertCtrl = UIAlertController(title: "App restart required", message: message, preferredStyle: .alert)

        let confirmAction = UIAlertAction(title: "Close now", style: .destructive) { _ in
            UserDefaults.standard.set([langCode], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
            exit(EXIT_SUCCESS)
        }
        confirmAlertCtrl.addAction(confirmAction)

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        confirmAlertCtrl.addAction(cancelAction)

        present(confirmAlertCtrl, animated: true, completion: nil)
    }
}

это как спрашивать и информировать пользователя о том, если он хочет изменить и как это сделать. Также он устанавливает язык приложений при следующем запуске с помощью:

UserDefaults.standard.set([langCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize() // required on real device

Шаг #3 (необязательно): локализовать строки

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


Реальный Пример

Я использую эту точную реализацию в приложении targeted для iOS 10, я могу подтвердить, что он работает для меня как на тренажере, так и на устройстве. Приложение на самом деле open source, поэтому вы можете найти приведенный выше код, распределенный по разным классам здесь.

Локализовать-Swift - быстрая дружественная локализация и i18n с переключением языка в приложении

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

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

в настройках iOS, вы можете установить дополнительные языки:

iOS language selection preferences

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

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

Это решит проблему?

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

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"App restart required", @"App restart required") message:NSLocalizedString(@"In order to change the language, the App must be closed and reopened by you.", @"In order to change the language, the App must be closed and reopened by you.") preferredStyle:UIAlertControllerStyleActionSheet];

    [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {


        [self dismissViewControllerAnimated:YES completion:^{


        }];
    }]];

    [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Restart", @"Restart") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"ar", nil] forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults]synchronize];

        exit(EXIT_SUCCESS);


    }]];


    [self presentViewController:actionSheet animated:YES completion:nil];
}

Comments

    Ничего не найдено.