私のアプリケーションはアラビア語(右から左方向)および英語(左から右方向)言語をサポートする必要があります。UIを設定し、アプリケーションからユーザーが選択した言語に基づいて設定する必要があります。
NSLayoutConstraintでUIを実装して、先行制約と後続制約に基づいてUIを自動的に更新できるようにします。
さて、私の質問はどうすればこれを達成できるのですか?デバイスの言語は英語で、アプリケーションユーザーからアラビア語を選択するので(私のアプリのみに制限されます)、フロー、UI、アニメーションなどは右から左になります。
ありがとう
結論として、アプリ内から言語を変更できます。ただし、追加の作業が必要です。各iOSバージョンの制限の背景を記載し、ソリューションを提供しています。解決策を説明する間、その背後にある理由を理解する必要があるからです。
ソリューションキー:semanticContentAttribute
この方法は公式ではなく、効率の問題を引き起こす可能性があると言う人もいます。
アプリを閉じることなく、UIの方向を強制できるようになりました。
UIView.appearance().semanticContentAttribute = .forceRightToLeft
IOS 9のバーをRTL(ナビゲーションとTabBar)に強制することはできません。 iOS 10で強制されている間。
IOS 10でRTLを強制できない残りの唯一のものは、デフォルトの戻るボタンです。
アプリの言語を変更してレイアウトを強制しても、言語に関連付けられたローカライズされた文字列ファイルをシステムが自動的に使用することはありません。
短い答え:
アプリの言語を変更しても、アプリを再起動せずに、選択した言語に従ってレイアウトの方向が強制されることはありません。
アップルのガイドライン:
Appleは、ユーザーがアプリ内から言語を変更できるようにしたくないので、それを提供していません。 Appleは、開発者にデバイス言語を使用するように要求し、アプリ内からまったく変更しないようにします。
Workarwound:
アラビア語をサポートする一部のアプリは、ユーザーが言語を変更できる設定ページで、アプリを再起動しないとレイアウトが有効にならないことをユーザーに通知します。 サンプルアプリのストアリンク
アプリの言語をアラビア語に変更するコードの例:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"ar", @"en", nil] forKey:@"AppleLanguages"];
再起動しないと有効になりません
ソリューションは、独自のローカリゼーションソリューションを提供することです。
ViewController
よりも前に始まるViewController
に配置します。 [〜#〜]または[〜#〜]unwindSegue
を使用して、言語を変更した後でルートView Controllerに戻ります。viewDidLoad
メソッドでビューの文字列を設定します。iOS 9以下をサポートしていない場合は、ポイント5および6を満たさないでください
すべてのビューコントローラーのviewDidLoad
メソッドでビューの制約を設定します。
制約を設定するときは、leading/trailingの代わりに、選択した言語に従ってright/leftを使用します。
言語クラスのサンプル(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サンプルは完全なソリューションを提供します。申し訳ありませんが、自分で変換する必要があります。
@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
このコード行を使用すると、あなたの魔法がかかり、アプリケーションを閉じることなくレイアウトが変更されます。右から左へ
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
}
}
}
}
@ashwin、私はあなたとまったく同じことをしようとしていました。
Info.plist、appdelegate、またはだれが何を知っているかを変更するだけで、自分のアプリをRTL言語(右から左)に変えることができると思っていました。アイデアは、LTRデバイスを持っている人がRTLで私のアプリを持ち、アプリ内でそれを変更でき、再起動する必要がないということです。
そのようなことはないようです(誰かがこれに同意しない場合は私が聞いて喜んでいます)。ただし、それほど悪くないオプションをいくつか見つけました。
特定のビューを強制的にLTRまたはRTLにできることがわかりました。したがって、アプリのすべてのビューでこのプロパティを設定できます。それを行う方法はあなた次第です。
self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
リファレンス: ISemanticContentAttribute
[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の間で言語の方向が変更される場合は、このソリューションが機能します。また、アプリのリセットも必要ありません。
お役に立てば幸いです。
Directional Layout Marginsを使用(iOS 11.0以降)
そして、ビューを
右から左
UIView.appearance().semanticContentAttribute = .forceRightToLeft
左から右
UIView.appearance().semanticContentAttribute = .forceLeftToRight