如何在应用程序中设置本地化的方向?(RTL,如果用户select阿拉伯语,selectLTR语言是英语)

我的应用程序必须支持阿拉伯语(从右到左的方向)和英语(从左到右的方向)语言,我需要设置用户界面,并根据用户从我的应用程序中select语言。

我将使用NSLayoutConstraint实现UI,以便根据前后约束自动更新UI。

现在我的问题是我怎么能做到这一点? 由于我的设备语言是说英语,从我的应用程序用户select阿拉伯语(仅限于我的应用程序只),所以我的stream量,UI,animation等应该是从右到左。

这里是方向的示例捕捉 在这里输入图像说明 在这里输入图像说明

谢谢

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

更新(iOS 9+)

解决scheme关键: semanticContentAttribute

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

用户界面的方向可以被迫现在不closures应用程序:

 UIView.appearance().semanticContentAttribute = .forceRightToLeft 

请注意,iOS 9中的横条不能强制为RTL(导航和TabBar)。 虽然它被迫与iOS 10。

iOS 10中唯一不能强制RTL的东西是默认的后退button。

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

在iOS 9以下

简短的回答:

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

苹果指南:

苹果公司并没有提供,因为他们不允许用户从应用程序内更改语言。 苹果推动开发者使用设备语言。 而不是从应用程序内部改变它。

Workarwound:

一些支持阿拉伯语言的应用程序在用户可以更改语言的设置页面中logging用户的注意事项,即在没有重新启动应用程序的情况下,布局不会生效。 存储示例应用程序的链接

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

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

没有重新启动,这将不会生效


如何更改应用程序语言,而无需重新启动应用

解决scheme是提供自己的本地化解决scheme:

  1. 使用基地国际化,但不要本地化故事板。
  2. 创build一个string文件并将其本地化为所有语言,并以(英文)为基础。
  3. 将更改语言function放置在任何其他ViewController之前的ViewController甚至在主要之前。 或者在更改语言之后使用unwindSegue返回到根视图控制器。
  4. 在所有视图控制器的viewDidLoad方法中为您的视图设置string。

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

  1. 在所有视图控制器的viewDidLoad方法中为您的视图设置约束。

  2. 当您根据select的语言设置约束时,使用右/左而不是前导/尾随


语言类示例(Swift):在你的单例类中初始化这个类的一个对象。

 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示例提供了完整的解决scheme。 对不起,你需要自己转换它。

 @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 

@ashwin,我正在试着做和你一样的事情。

我希望能够通过改变info.plist,appdelegate或谁知道什么,我可以把我的应用变成RTL语言(从右到左)。 这个想法是,有LTR设备的人可以在RTL中使用我的应用程序,在应用程序中更改它,而不需要重新启动它。

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

  1. 事实certificate,你可以强制一个特定的视图是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); 

注意:这不是应该的方式,苹果公司的指导方针认为应该从iOS设置改变语言。 但是,如果必须在应用程序中更改语言,并且涉及LTR和RTL之间的语言方向更改,则此解决scheme可以正常工作。 也不需要重置应用程序。

我希望它有帮助。