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

Как установить локализованное направление в приложении? (RTL, если пользователь выбирает арабский язык, LTR выбран на английском языке)

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

Я буду реализовывать интерфейс с NSLayoutConstraint, чтобы он мог обновлять пользовательский интерфейс автоматически, основываясь на ведущих и конечных ограничениях.

Теперь мой вопрос: как я могу это достичь? Поскольку на моем языке устройства говорят по-английски, и из моего приложения пользователь выбирает арабский (только для моего приложения), поэтому мой поток, пользовательский интерфейс, анимация и т.д. Должны быть справа налево.

вот пример привязки для ui Direction введите описание изображения здесь введите описание изображения здесь

Спасибо

4b9b3361

Ответ 1

В нижней строке вы можете изменить язык внутри приложения. Но, необходима дополнительная работа. Я перечисляю фон об ограничениях для каждой версии iOS и затем предоставляю решение. потому что, объясняя решение, вам нужно понять причину этого.

Обновление (iOS 9 +)

Ключ решения: semanticContentAttribute

Некоторые говорят, что этот способ не является официальным и может вызвать проблемы с эффективностью.

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

UIView.appearance().semanticContentAttribute = .forceRightToLeft

Примечание. В IOS 9 нельзя отключить RTL (Navigation и TabBar). Пока он заставляют работать с iOS 10.

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

Изменение языка наряду с форсированием макета не автоматически заставляет систему использовать локализованный строковый файл связанных с языком.

Ниже iOS 9

Короткий ответ:

Изменение языка приложения не приведет к форматированию макета в соответствии с выбранным языком без перезагрузки приложения.

Линия Apple:

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

Workarwound:

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

Пример кода для изменения языка приложения для арабского:

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

Это не вступит в силу без перезагрузки


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

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

  • Использовать базовую интернационализацию, но не локализовать раскадровки.
  • Создайте один файл строк и локализуйте его на всех языках и базе (английский).
  • Поместите функцию языка изменений в ViewController, которая запускается перед любым другим ViewController еще до вашего основного. ИЛИ используйте unwindSegue, чтобы вернуться к контроллеру корневого представления после изменения языка.
  • Установите строки для ваших представлений в методе viewDidLoad для всех контроллеров представлений.

Не удовлетворяйте точкам 5 и 6, если вы не поддерживаете ниже iOS 9

  1. Задайте ограничения для ваших представлений в методе viewDidLoad для всех контроллеров представления.

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


Пример класса языка (Swift): Инициализируйте объект этого класса в своем классе singlton.

class LanguageDetails: NSObject {

    var language: String!
    var bundle: Bundle!
    let LANGUAGE_KEY: String = "LANGUAGE_KEY"

    override init() {
        super.init()

        // user preferred languages. this is the default app language(device language - first launch app language)!
        language = Bundle.main.preferredLocalizations[0]

        // the language stored in UserDefaults have the priority over the device language.
        language = Common.valueForKey(key: LANGUAGE_KEY, default_value: language as AnyObject) as! String

        // init the bundle object that contains the localization files based on language
        bundle = Bundle(path: Bundle.main.path(forResource: language == "ar" ? language : "Base", ofType: "lproj")!)

        // bars direction
        if isArabic() {
            UIView.appearance().semanticContentAttribute = .forceRightToLeft
        } else {
            UIView.appearance().semanticContentAttribute = .forceLeftToRight
        }
    }

    // check if current language is arabic
    func isArabic () -> Bool {
        return language == "ar"
    }

    // returns app language direction.
    func rtl () -> Bool {
        return Locale.characterDirection(forLanguage: language) == Locale.LanguageDirection.rightToLeft
    }

    // switches language. if its ar change it to en and vise-versa
    func changeLanguage()
    {
        var changeTo: String
        // check current language to switch to the other.
        if language == "ar" {
            changeTo = "en"
        } else {
            changeTo = "ar"
        }

        // change language
        changeLanguageTo(lang: changeTo)

        Log.info("Language changed to: \(language)")
    }

    // change language to a specfic one.
    func changeLanguageTo(lang: String) {
        language = lang

        // set language to user defaults
        Common.setValue(value: language as AnyObject, key: LANGUAGE_KEY)

        // set prefered languages for the app.
        UserDefaults.standard.set([lang], forKey: "AppleLanguages")
        UserDefaults.standard.synchronize()

        // re-set the bundle object based on the new langauge
        bundle = Bundle(path: Bundle.main.path(forResource: language == "ar" ? language : "Base", ofType: "lproj")!)

        // app direction
        if isArabic() {
            UIView.appearance().semanticContentAttribute = .forceRightToLeft
        } else {
            UIView.appearance().semanticContentAttribute = .forceLeftToRight
        }

        Log.info("Language changed to: \(language)")
    }

    // get local string
    func getLocale() -> NSLocale {
        if rtl() {
            return NSLocale(localeIdentifier: "ar_JO")
        } else {
            return NSLocale(localeIdentifier: "en_US")
        }
    }

    // get localized string based on app langauge.
    func LocalString(key: String) -> String {
        let localizedString: String? = NSLocalizedString(key, bundle: bundle, value: key, comment: "")
//        Log.ver("Localized string '\(localizedString ?? "not found")' for key '\(key)'")
        return localizedString ?? key
    }

    // get localized string for specific language
    func LocalString(key: String, lan: String) -> String {
        let bundl:Bundle! = Bundle(path: Bundle.main.path(forResource: lan == "ar" ? lan : "Base", ofType: "lproj")!)
        return NSLocalizedString(key, bundle: bundl, value: key, comment: "")
    }
}

Пример класса языка (Objective-c): Образец Swift предоставляет полное решение. жаль, что вам нужно его самостоятельно преобразовать.

@implementation LanguageDetails

@synthesize language;
@synthesize bundle;

#define LANGUAGE_KEY @"LANGUAGE_KEY"

// language var is also the strings file name ar or en

- (id)init
{
    if (self = [super init]) {

        language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];

        if (![language isEqualToString:@"ar"])
            language = @"en";

        language = [Common valueForKey:LANGUAGE_KEY defaultValue:language];

        bundle = [NSBundle mainBundle];
    }
    return  self;
}

- (BOOL)rtl {
    return [NSLocale characterDirectionForLanguage:language] == NSLocaleLanguageDirectionRightToLeft;
}

- (void)changeLanguage
{
    if ([language isEqualToString:@"ar"])
        language = @"en";
    else
        language = @"ar";

    [Common setValue:language forKey:LANGUAGE_KEY];
}

- (void)changeLanguageTo:(NSString *)lang
{
    language = lang;

    [Common setValue:language forKey:LANGUAGE_KEY];
}

- (NSString *) LocalString:(NSString *)key {
    return NSLocalizedStringFromTableInBundle(key, language, bundle, nil);
}

@end

Ответ 2

@ashwin, я пытался сделать то же самое, что и вы.

Я надеялся найти, что могу превратить свое приложение в RTL-язык (справа налево), просто изменив что-то в info.plist, appdelegate или кто знает что. Идея заключается в том, что у кого-то с устройством LTR может быть мое приложение в RTL, изменение его в приложении и без необходимости его перезапуска.

Похоже, что такого не бывает (я буду рад услышать, если кто-то не согласен с этим). Тем не менее, я нашел некоторые параметры, которые не так уж плохи.

  • Оказывается, вы можете заставить конкретное представление быть LTR или RTL. Таким образом, вы можете установить это свойство во всех представлениях вашего приложения. То, как вы это делаете, зависит от вас.

    self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;

Ссылка: UISemanticContentAttribute

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

[view setTransform:CGAffineTransformMakeScale(1, 1)];

Вот код, который может вам помочь.

void reloadRTLViewAndSubviews(UIView *view)
{
    reloadRTLViews(@[view]);
    reloadRTLViews([view subviews]);
}

void reloadRTLViews(NSArray *views)
{
    if (isRTL())
    {
        [views enumerateObjectsUsingBlock:^(UIView* view,
                                            NSUInteger idx,
                                            BOOL * stop)
         {
             [view setTransform:CGAffineTransformMakeScale(-1, 1)];
         }];
    }
    else
    {
        [views enumerateObjectsUsingBlock:^(UIView* view,
                                            NSUInteger idx,
                                            BOOL * stop)
         {
             [view setTransform:CGAffineTransformMakeScale(1, 1)];
         }];
    }
}

BOOL isRTL()
{
    return isRTL_app();
}

BOOL isRTL_device()
{
    BOOL isRTL = ([NSLocale characterDirectionForLanguage:[[NSLocale preferredLanguages] objectAtIndex:0]] == NSLocaleLanguageDirectionRightToLeft);

    return isRTL;
}

BOOL isRTL_scheme()
{
    BOOL isRTL = ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:[UIView new].semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft);

    return isRTL;
}

BOOL isRTL_app()
{
    NSString *languageIdentifier = [AppDataManager sharedManager].languageIdentifier;
    NSArray *rtl_languages = @[@"ar"];

    BOOL isRTL;

    if ((languageIdentifier == nil) || (languageIdentifier.length == 0))
    {
        isRTL = (isRTL_device() || isRTL_scheme());
    }
    else if ([rtl_languages containsObject:languageIdentifier])
    {
        isRTL = YES;
    }
    else
    {
        isRTL = NO;
    }

    return isRTL;
}

BOOL deviceLanguageDirectionEqualAppLanguageDirection()
{
    if ((isRTL_device() || isRTL_scheme()) && isRTL())//All RTL
    {
        return YES;
    }
    else if (!(isRTL_device() || isRTL_scheme()) && !isRTL())//All LTR
    {
        return YES;
    }

    return NO;//RTL-LTR or LTR-RTL
}

void transformViews(NSArray *views)
{
    [views enumerateObjectsUsingBlock:^(UIView* view,
                                        NSUInteger idx,
                                        BOOL * stop)
     {
         [view setTransform:CGAffineTransformMakeScale(-1, 1)];
     }];
}

Итак, если вы хотите изменить UIViewController в RTL, вы можете сделать все настройки так, чтобы было достаточно:

reloadRTLViewAndSubviews(self.view);

Примечание. Это не так, как должно быть, и в руководствах Apple говорится, что язык должен быть изменен из настроек iOS. Но это решение работает, если язык должен быть изменен в приложении, и это связано с изменением направления языка между LTR и RTL. И не требуется приложение reset.

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