一尘不染

如何在应用程序中设置本地化方向?(如果用户选择阿拉伯语,则选择RTL,选择LTR则选择语言为英语) 迅速

swift

我的应用程序必须支持阿拉伯语(从右到左方向)和英语(从左到右方向)语言,我需要设置UI并基于用户
从我的应用程序中选择的语言。

我将使用NSLayoutConstraint实现UI,以便它可以根据前导和尾随约束自动更新UI 。

现在我的问题是我该如何实现?由于我的设备语言是英语,并且从我的应用程序用户中选择阿拉伯语(仅限于我的应用程序),因此我的Flow,UI,动画等应从右到左。


阅读 455

收藏
2020-07-07

共1个答案

一尘不染

最重要的是,您可以在应用程序内部更改语言。但是,需要额外的
工作。我列出了每个iOS
版本的限制背景,然后提供了解决方案。因为在解释
解决方案时,您需要了解其背后的原因。

更新(iOS 9+)
解决方案密钥:semanticContentAttribute

有人说这种方式不是官方的,可能会导致效率问题。

现在可以在不关闭应用程序的情况下强制执行UI方向:

UIView.appearance().semanticContentAttribute = .forceRightToLeft

请注意,iOS 9中的条不能强制为RTL(导航和TabBar)。尽管它
在iOS 10中被强制使用。

iOS 10中唯一不能强制使用RTL的功能是默认的
后退按钮。

更改应用程序的语言以及强制布局不会
自动强制系统使用
与该语言关联的本地化字符串文件。

在iOS 9以下
简短答案:

更改应用程序语言将不会在
不重新启动应用程序的情况下根据所选语言强制布局方向。

苹果的指导方针:

苹果公司不提供这种服务,因为他们不喜欢允许用户
从应用程序内部更改语言。苹果公司要求开发人员使用
设备语言。而不是完全从应用程序内部进行更改。

工作伤口:

某些支持阿拉伯语言的应用程序会在设置页面
(该页面中用户可以更改语言)中向用户提示,如果不
重新启动应用程序,布局将不会生效。存储示例
应用程序的链接

将应用程序语言更改为阿拉伯语的示例代码:

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

That won’t take effect without a restart


How to change app language without an app restart

Solution is to provide your own localization solution:

  1. Use Base Internationalization but don’t localize storyboards.
  2. Create one strings file and localise it to all languages and base for (english).
  3. Place the change language feature in a ViewController that starts before any other ViewController even before your main one. OR use an unwindSegue to go back to the root view controller after changing the language.
  4. Set strings for your views in viewDidLoad method for all view controllers.

Don’t satisfy points 5 and 6 if you are not supporting below iOS 9

  1. Set the constraints for your views in viewDidLoad method for all view controllers.

  2. When you set the constraints use right/left according to the language selected instead of leading/trailing.


Language class sample (Swift): Initialise an object of this class in your
singlton class.

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: "")
    }
}

Language class sample (Objective-c): Swift sample provides full solution.
sorry you need to convert it yourself.

@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
2020-07-07