xcode 如何在应用程序中设置本地化方向?(RTL 如果用户选择阿拉伯语,LTR 选择的语言是英语)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31877140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How Can I set Localised Direction within application?(RTL if user select arabic, LTR is selected language is English)
提问by Kanjariya-IOS
My Application must support Arabic(right to left direction) and English(left to right direction) language, I need to set UI and based on user select language from my application.
我的应用程序必须支持阿拉伯语(从右到左方向)和英语(从左到右方向)语言,我需要设置 UI 并根据用户从我的应用程序中选择语言。
I will implement UI with NSLayoutConstraint so it can update UI automatically, based on leading and trailing constraints.
我将使用 NSLayoutConstraint 实现 UI,以便它可以根据前导和尾随约束自动更新 UI。
Now My Question is how can i achieve this? As My device language is say English and from my application user select Arabic(limited to my app only), So my Flow,UI,Animations etc should be right to left.
现在我的问题是我怎样才能做到这一点?由于我的设备语言是英语,并且我的应用程序用户选择阿拉伯语(仅限我的应用程序),所以我的 Flow、UI、Animations 等应该从右到左。
here are the sample snap for ui Direction
Thanks
谢谢
回答by hasan
Bottom line you can change the language from inside the app. But, an extra work is needed. I am listing a background on limitations for each iOS version and then providing the solution. because while explaining the solution you need to understand the reason behind it.
最重要的是,您可以从应用程序内部更改语言。但是,需要额外的工作。我列出了每个 iOS 版本的限制背景,然后提供了解决方案。因为在解释解决方案时,您需要了解其背后的原因。
Update (iOS 9+)
更新(iOS 9+)
Solution Key: semanticContentAttribute
解决方案关键: semanticContentAttribute
Some says that this way is not official and may cause efficiency problems.
有人说这种方式不是官方的,可能会导致效率问题。
UI direction can be forced now without closing the app:
现在可以在不关闭应用程序的情况下强制 UI 方向:
UIView.appearance().semanticContentAttribute = .forceRightToLeft
Note, bars in iOS 9 can't be forced to RTL (Navigation and TabBar). While it get forced with iOS 10.
请注意,iOS 9 中的栏不能强制为 RTL(导航和 TabBar)。虽然它在 iOS 10 中被强制使用。
The only remaining thing that can't be forced RTL in iOS 10 is the default back button.
在 iOS 10 中唯一不能强制 RTL 的是默认的后退按钮。
Changing app the language along with forcing the layout doesn't automatically forces the system to use the localized string file associated with the language.
更改应用程序语言以及强制布局不会自动强制系统使用与语言关联的本地化字符串文件。
Below iOS 9
iOS 9 以下
Short answer:
简答:
Changing the app language will not force the layout direction according to the selected language without an app restart.
在不重启应用程序的情况下,更改应用程序语言不会根据所选语言强制布局方向。
Apple's guide line:
苹果的指导方针:
Apple doesn't provide that because they don't prefere to allow the user to change language from inside the app. Apple pushes the developers to use the device language. and not to change it from inside the app at all.
Apple 没有提供,因为他们不希望允许用户从应用程序内部更改语言。Apple 敦促开发人员使用设备语言。并且根本不要从应用程序内部更改它。
Workarwound:
解决办法:
Some apps that supports Arabic language notes the user, in the settings page where the user can change the language, that the layout will not take effect without an app restart. store link for sample app
一些支持阿拉伯语的应用程序会在用户可以更改语言的设置页面中提示用户,如果不重启应用程序,布局将不会生效。示例应用程序的商店链接
Example code to change app language to arabic:
将应用程序语言更改为阿拉伯语的示例代码:
[[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:
解决方案是提供您自己的本地化解决方案:
- Use Base Internationalizationbut don't localize storyboards.
- Create one strings file and localise it to all languages and base for (english).
- Place the change language feature in a
ViewController
that starts before any otherViewController
even before your main one. ORuse anunwindSegue
to go back to the root view controller after changing the language. - Set strings for your views in
viewDidLoad
method for all view controllers.
- 使用基本国际化,但不要本地化故事板。
- 创建一个字符串文件并将其本地化为所有语言和基础(英语)。
- 将更改语言功能放在一个甚至在您的主要功能
ViewController
之前开始的任何其他功能ViewController
之前。或者unwindSegue
在更改语言后使用 an返回到根视图控制器。 - 在
viewDidLoad
所有视图控制器的方法中为您的视图设置字符串。
Don't satisfy points 5 and 6 if you are not supporting below iOS 9
如果您不支持低于 iOS 9,请不要满足第 5 点和第 6 点
Set the constraints for your views in
viewDidLoad
method for all view controllers.When you set the constraints use right/leftaccording to the language selected instead of leading/trailing.
在
viewDidLoad
方法中为所有视图控制器设置视图的约束。当您设置约束时,根据选择的语言使用right/left而不是leading/trailing。
Language class sample (Swift):Initialise an object of this class in your singlton class.
语言类示例(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: "")
}
}
Language class sample (Objective-c):Swift sample provides full solution. sorry you need to convert it yourself.
语言类示例(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
回答by Shahzaib Maqbool
Use this line of code it will do your magic and will change layout without closing application. From right to left
使用这行代码,它会发挥你的魔力,并在不关闭应用程序的情况下更改布局。从右到左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
UIView.appearance().semanticContentAttribute = .forceRightToLeft
And for Right to Left Flip
对于从右到左翻转
UIView.appearance().semanticContentAttribute = .forceLeftToRight
and if you want to change textfield layout or text change then use this code because i faced this issue . textfield's texts was not changning layout. check this code to change layout of textfield text.
如果您想更改文本字段布局或文本更改,请使用此代码,因为我遇到了这个问题。文本字段的文本没有改变布局。检查此代码以更改文本字段文本的布局。
extension UITextField {
open override func awakeFromNib() {
super.awakeFromNib()
if UserDefaults.languageCode == "ar" {
if textAlignment == .natural {
self.textAlignment = .right
}
}
}
}
回答by MAhipal Singh
use Directional Layout Margins(iOS 11.0+)
使用定向布局边距(iOS 11.0+)
and set Views to
并将视图设置为
Right To Left
右到左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
Left To Right
左到右
UIView.appearance().semanticContentAttribute = .forceLeftToRight
回答by inigo333
@ashwin, I was trying to do the exact same thing as you were.
@ashwin,我试图做和你完全一样的事情。
I was hoping to find I could turn my app into a RTL language (right to left) just by changing something in the info.plist, appdelegate or who knows what. The idea is that someone with a LTR device can have my app in RTL, changing it within the app and with no need to restart it.
我希望发现我可以通过更改 info.plist、appdelegate 或谁知道什么来将我的应用程序变成 RTL 语言(从右到左)。这个想法是,拥有 LTR 设备的人可以在 RTL 中使用我的应用程序,在应用程序中更改它,而无需重新启动它。
Looks like there is not such a thing (I'll be glad to hear if anyone disagrees with this). However, I've found some options that are not that bad.
看起来没有这样的事情(如果有人不同意,我会很高兴听到)。但是,我发现了一些还不错的选择。
It turns out you can force a specific view to be LTR or RTL. Thus you can set this property on every view of your app. The way you do it is up to you.
self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
事实证明,您可以将特定视图强制为 LTR 或 RTL。因此,您可以在应用程序的每个视图上设置此属性。你怎么做取决于你。
self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
Reference: UISemanticContentAttribute
- You can always flip views horizontally until you get the desired setup.
- 您始终可以水平翻转视图,直到获得所需的设置。
[view setTransform:CGAffineTransformMakeScale(1, 1)];
[view setTransform:CGAffineTransformMakeScale(1, 1)];
Here's some code that might help you.
这是一些可能对您有所帮助的代码。
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)];
}];
}
So if you were to change a UIViewController to be in RTL you can make all the setup so that it would suffice to:
因此,如果您要将 UIViewController 更改为处于 RTL 中,您可以进行所有设置,以便满足以下条件:
reloadRTLViewAndSubviews(self.view);
Note: this is not the way it should be and Apple's guidelines say that the language should be change from the iOS settings. But this solution works if the language must be changed within the app and a language direction change between LTR and RTL is involved. And no app reset needed either.
注意:这不是它应该的方式,Apple 的指导方针说语言应该从 iOS 设置中更改。但是,如果必须在应用程序内更改语言并且涉及 LTR 和 RTL 之间的语言方向更改,则此解决方案有效。也不需要重置应用程序。
I hope it helped.
我希望它有所帮助。