代码之家  ›  专栏  ›  技术社区  ›  Kanjariya-IOS

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

  •  21
  • Kanjariya-IOS  · 技术社区  · 9 年前

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

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

    现在我的问题是我如何实现这一目标?由于我的设备语言是英语,并且从我的应用程序用户选择阿拉伯语(仅限于我的应用),所以我的流、UI、动画等应该从右到左。

    这是ui方向的示例捕捉 enter image description here enter image description here

    谢谢

    4 回复  |  直到 6 年前
        1
  •  43
  •   hasan    6 年前

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

    更新(iOS 9+)

    解决方案密钥: semanticContentAttribute

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

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

    UIView.appearance().semanticContentAttribute = .forceRightToLeft
    

    注意,iOS 9中的条形图不能强制为RTL(导航和TabBar)。而iOS 10。

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

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

    iOS 9以下

    简短回答:

    如果不重新启动应用程序,更改应用程序语言将不会根据所选语言强制布局方向。

    苹果的指导方针:

    苹果没有提供这一点,因为他们不愿意让用户 从应用程序内部更改语言。苹果推动开发者 使用设备语言。而不是从应用程序内部进行更改。

    工作创伤:

    一些支持阿拉伯语的应用程序在 设置页面,用户可以在其中更改语言,如果不重新启动应用程序,布局将不会生效。 store link for sample app

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

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

    不重新启动就不会生效


    如何在不重新启动应用程序的情况下更改应用程序语言

    解决方案是提供您自己的本地化解决方案:

    1. 使用基本国际化 但不要本地化故事板。
    2. 创建一个字符串文件,并将其本地化为所有语言和基础(英语)。
    3. 将更改语言功能放置在 ViewController 比任何其他人都先开始 视图控制器 甚至在你的主要任务之前。 使用 unwindSegue 更改语言后返回根视图控制器。
    4. 在中为视图设置字符串 viewDidLoad 方法。

    如果您不支持iOS 9以下版本,请不要满足第5点和第6点

    1. 在中设置视图的约束 视图DidLoad 方法。

    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
  •  5
  •   MAhipal Singh mdsmdsdsu    6 年前

    使用 Directional Layout Margins (iOS 11.0+)

    enter image description here

    并将“视图”设置为

    从右到左

     UIView.appearance().semanticContentAttribute = .forceRightToLeft
    

    从左到右

     UIView.appearance().semanticContentAttribute = .forceLeftToRight
    
        3
  •  3
  •   Shahzaib Maqbool    6 年前

    使用这行代码,它将发挥您的魔力,并将在不关闭应用程序的情况下更改布局。 从右到左

    UIView.appearance().semanticContentAttribute = .forceRightToLeft

    对于从右向左翻转

    UIView.appearance().semanticContentAttribute = .forceLeftToRight
    

    如果你想更改文本字段布局或文本更改,请使用此代码,因为我面临这个问题。文本字段的文本没有更改布局。 检查此代码以更改文本字段文本的布局。

    extension UITextField {
      open override func awakeFromNib() {
        super.awakeFromNib()
        if UserDefaults.languageCode == "ar" {
            if textAlignment == .natural {
                self.textAlignment = .right
            }
        }
    }
    }
    
        4
  •  1
  •   inigo333    9 年前

    @阿什温,我想做和你完全一样的事。

    我希望通过改变信息中的某些内容,就能将我的应用程序变成RTL语言(从右到左)。plist、appdelegate或谁知道。想法是,有LTR设备的人可以在RTL中使用我的应用程序,在应用程序中更改它,而无需重新启动它。

    看起来没有这样的事情(如果有人不同意,我会很高兴听到)。然而,我找到了一些没有那么糟糕的选择。

    1. 事实证明,您可以强制特定视图为LTR或RTL。因此,您可以在应用程序的每个视图上设置此属性。你做这件事的方式取决于你。

      self.view。semanticContentAttribute=UIS需求内容属性ForceRightToLeft;

    参考: 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);
    

    注意:这不是应该的方式,苹果的指南说,应该从iOS设置中更改语言。但是,如果必须在应用程序中更改语言,并且涉及LTR和RTL之间的语言方向更改,则此解决方案有效。也不需要重置应用程序。

    我希望这有帮助。