如何在应用程序中设置本地化方向?(RTL 如果用户 select 阿拉伯语,LTR 是 selected 语言是英语)
How Can I set Localised Direction within application?(RTL if user select arabic, LTR is selected language is English)
我的应用程序必须支持阿拉伯语(从右到左方向)和英语(从左到右方向)语言,我需要设置 UI 并基于我的应用程序中的用户 select 语言。
我将使用 NSLayoutConstraint 实现 UI,以便它可以根据前导和尾随约束自动更新 UI。
现在我的问题是我怎样才能做到这一点?由于我的设备语言是英语,而我的应用程序用户 select 阿拉伯语(仅限于我的应用程序),所以我的流程、UI、动画等应该从右到左。
这里是 ui 方向的示例快照
谢谢
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 9+)
解决方案关键:semanticContentAttribute
有人说这种方式不是官方的,可能会造成效率问题
UI现在可以在不关闭应用程序的情况下强制执行方向:
UIView.appearance().semanticContentAttribute = .forceRightToLeft
请注意,iOS 9 中的栏不能强制为 RTL(导航和 TabBar)。虽然它被强制 iOS 10.
iOS10 中唯一不能强制 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.
低于iOS9
简答:
Changing the app language will not force the layout direction according to the selected language without an app restart.
Apple的引导线:
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.
解决方法:
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
将应用语言更改为阿拉伯语的示例代码:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"ar", @"en", nil] forKey:@"AppleLanguages"];
重启不生效
如何在不重启应用程序的情况下更改应用程序语言
解决方案是提供自己的本地化解决方案:
- 使用 Base Internationalization 但不本地化故事板。
- 创建一个字符串文件并将其本地化为所有语言和(英语)基础。
- 将更改语言功能放在
ViewController
中,该功能在任何其他 ViewController
之前开始,甚至在您的主要功能之前。 或在更改语言后使用unwindSegue
返回到根视图控制器。
- 在所有视图控制器的
viewDidLoad
方法中为您的视图设置字符串。
如果你不支持以下就不要满足第5点和第6点iOS 9
在所有视图控制器的 viewDidLoad
方法中设置视图的约束。
设置约束时根据所选语言使用right/left而不是leading/trailing.
语言 class 示例 (Swift):
在你的 singlton class.
中初始化这个 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: "")
}
}
语言 class 示例 (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
@ashwin,我正在尝试做与您完全相同的事情。
我希望发现我可以将我的应用程序变成 RTL 语言(从右到左),只需更改 info.plist、appdelegate 或谁知道什么。这个想法是,拥有 LTR 设备的人可以在 RTL 中使用我的应用程序,在应用程序中更改它而无需重新启动它。
好像没有这样的事情(如果有人不同意,我会很高兴听到)。但是,我发现了一些还不错的选项。
事实证明,您可以将特定视图强制为 LTR 或 RTL。因此,您可以在应用的每个视图上设置此 属性。怎么做取决于你。
self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
- 您始终可以水平翻转视图,直到获得所需的设置。
[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 之间的语言方向更改,则此解决方案有效。也不需要重置应用程序。
希望对您有所帮助。
使用这行代码,它会发挥您的魔力,并且会在不关闭应用程序的情况下更改布局。
从右到左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
从右到左翻转
UIView.appearance().semanticContentAttribute = .forceLeftToRight
如果您想更改文本字段布局或文本更改,请使用此代码,因为我遇到过这个问题。 textfield 的文本不是 changning 布局。
检查此代码以更改文本字段文本的布局。
extension UITextField {
open override func awakeFromNib() {
super.awakeFromNib()
if UserDefaults.languageCode == "ar" {
if textAlignment == .natural {
self.textAlignment = .right
}
}
}
}
使用Directional Layout Margins (iOS 11.0+)
并将视图设置为
从右到左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
从左到右
UIView.appearance().semanticContentAttribute = .forceLeftToRight
我的应用程序必须支持阿拉伯语(从右到左方向)和英语(从左到右方向)语言,我需要设置 UI 并基于我的应用程序中的用户 select 语言。
我将使用 NSLayoutConstraint 实现 UI,以便它可以根据前导和尾随约束自动更新 UI。
现在我的问题是我怎样才能做到这一点?由于我的设备语言是英语,而我的应用程序用户 select 阿拉伯语(仅限于我的应用程序),所以我的流程、UI、动画等应该从右到左。
这里是 ui 方向的示例快照
谢谢
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 9+)
解决方案关键:semanticContentAttribute
有人说这种方式不是官方的,可能会造成效率问题
UI现在可以在不关闭应用程序的情况下强制执行方向:
UIView.appearance().semanticContentAttribute = .forceRightToLeft
请注意,iOS 9 中的栏不能强制为 RTL(导航和 TabBar)。虽然它被强制 iOS 10.
iOS10 中唯一不能强制 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.
低于iOS9
简答:
Changing the app language will not force the layout direction according to the selected language without an app restart.
Apple的引导线:
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.
解决方法:
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
将应用语言更改为阿拉伯语的示例代码:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"ar", @"en", nil] forKey:@"AppleLanguages"];
重启不生效
如何在不重启应用程序的情况下更改应用程序语言
解决方案是提供自己的本地化解决方案:
- 使用 Base Internationalization 但不本地化故事板。
- 创建一个字符串文件并将其本地化为所有语言和(英语)基础。
- 将更改语言功能放在
ViewController
中,该功能在任何其他ViewController
之前开始,甚至在您的主要功能之前。 或在更改语言后使用unwindSegue
返回到根视图控制器。 - 在所有视图控制器的
viewDidLoad
方法中为您的视图设置字符串。
如果你不支持以下就不要满足第5点和第6点iOS 9
在所有视图控制器的
viewDidLoad
方法中设置视图的约束。设置约束时根据所选语言使用right/left而不是leading/trailing.
语言 class 示例 (Swift): 在你的 singlton class.
中初始化这个 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: "")
}
}
语言 class 示例 (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
@ashwin,我正在尝试做与您完全相同的事情。
我希望发现我可以将我的应用程序变成 RTL 语言(从右到左),只需更改 info.plist、appdelegate 或谁知道什么。这个想法是,拥有 LTR 设备的人可以在 RTL 中使用我的应用程序,在应用程序中更改它而无需重新启动它。
好像没有这样的事情(如果有人不同意,我会很高兴听到)。但是,我发现了一些还不错的选项。
事实证明,您可以将特定视图强制为 LTR 或 RTL。因此,您可以在应用的每个视图上设置此 属性。怎么做取决于你。
self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
- 您始终可以水平翻转视图,直到获得所需的设置。
[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 之间的语言方向更改,则此解决方案有效。也不需要重置应用程序。
希望对您有所帮助。
使用这行代码,它会发挥您的魔力,并且会在不关闭应用程序的情况下更改布局。 从右到左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
从右到左翻转
UIView.appearance().semanticContentAttribute = .forceLeftToRight
如果您想更改文本字段布局或文本更改,请使用此代码,因为我遇到过这个问题。 textfield 的文本不是 changning 布局。 检查此代码以更改文本字段文本的布局。
extension UITextField {
open override func awakeFromNib() {
super.awakeFromNib()
if UserDefaults.languageCode == "ar" {
if textAlignment == .natural {
self.textAlignment = .right
}
}
}
}
使用Directional Layout Margins (iOS 11.0+)
并将视图设置为
从右到左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
从左到右
UIView.appearance().semanticContentAttribute = .forceLeftToRight