web-dev-qa-db-ja.com

アプリケーション内でローカライズされた方向を設定するにはどうすればよいですか?

私のアプリケーションはアラビア語(右から左方向)および英語(左から右方向)言語をサポートする必要があります。UIを設定し、アプリケーションからユーザーが選択した言語に基づいて設定する必要があります。

NSLayoutConstraintでUIを実装して、先行制約と後続制約に基づいてUIを自動的に更新できるようにします。

さて、私の質問はどうすればこれを達成できるのですか?デバイスの言語は英語で、アプリケーションユーザーからアラビア語を選択するので(私のアプリのみに制限されます)、フロー、UI、アニメーションなどは右から左になります。

これは、ui方向のサンプルスナップです enter image description hereenter image description here

ありがとう

20
Kanjariya-IOS

結論として、アプリ内から言語を変更できます。ただし、追加の作業が必要です。各iOSバージョンの制限の背景を記載し、ソリューションを提供しています。解決策を説明する間、その背後にある理由を理解する必要があるからです。

アップデート(iOS 9以降)

ソリューションキー:semanticContentAttribute

この方法は公式ではなく、効率の問題を引き起こす可能性があると言う人もいます。

アプリを閉じることなく、UIの方向を強制できるようになりました。

UIView.appearance().semanticContentAttribute = .forceRightToLeft

IOS 9のバーをRTL(ナビゲーションとTabBar)に強制することはできません。 iOS 10で強制されている間。

IOS 10でRTLを強制できない残りの唯一のものは、デフォルトの戻るボタンです。

アプリの言語を変更してレイアウトを強制しても、言語に関連付けられたローカライズされた文字列ファイルをシステムが自動的に使用することはありません。

IOS 9の下

短い答え:

アプリの言語を変更しても、アプリを再起動せずに、選択した言語に従ってレイアウトの方向が強制されることはありません。

アップルのガイドライン:

Appleは、ユーザーがアプリ内から言語を変更できるようにしたくないので、それを提供していません。 Appleは、開発者にデバイス言語を使用するように要求し、アプリ内からまったく変更しないようにします。

Workarwound:

アラビア語をサポートする一部のアプリは、ユーザーが言語を変更できる設定ページで、アプリを再起動しないとレイアウトが有効にならないことをユーザーに通知します。 サンプルアプリのストアリンク

アプリの言語をアラビア語に変更するコードの例:

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

再起動しないと有効になりません


アプリを再起動せずにアプリの言語を変更する方法

ソリューションは、独自のローカリゼーションソリューションを提供することです。

  1. Base Internationalizationを使用しますが、ストーリーボードはローカライズしません。
  2. 1つの文字列ファイルを作成し、それをすべての言語およびローカライズ(英語)にローカライズします。
  3. 言語の変更機能は、メインの機能の前であっても、他のViewControllerよりも前に始まるViewControllerに配置します。 [〜#〜]または[〜#〜]unwindSegueを使用して、言語を変更した後でルートView Controllerに戻ります。
  4. すべてのビューコントローラーのviewDidLoadメソッドでビューの文字列を設定します。

iOS 9以下をサポートしていない場合は、ポイント5および6を満たさないでください

  1. すべてのビューコントローラーのviewDidLoadメソッドでビューの制約を設定します。

  2. 制約を設定するときは、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
33
hasan

このコード行を使用すると、あなたの魔法がかかり、アプリケーションを閉じることなくレイアウトが変更されます。右から左へ

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
        }
    }
}
}
2

@ashwin、私はあなたとまったく同じことをしようとしていました。

Info.plist、appdelegate、またはだれが何を知っているかを変更するだけで、自分のアプリをRTL言語(右から左)に変えることができると思っていました。アイデアは、LTRデバイスを持っている人がRTLで私のアプリを持ち、アプリ内でそれを変更でき、再起動する必要がないということです。

そのようなことはないようです(誰かがこれに同意しない場合は私が聞いて喜んでいます)。ただし、それほど悪くないオプションをいくつか見つけました。

  1. 特定のビューを強制的にLTRまたはRTLにできることがわかりました。したがって、アプリのすべてのビューでこのプロパティを設定できます。それを行う方法はあなた次第です。

    self.view.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;

リファレンス: ISemanticContentAttribute

  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);

注:これは本来あるべき姿ではなく、Appleのガイドラインによると、言語はiOSの設定から変更する必要があります。ただし、アプリ内で言語を変更する必要があり、LTRとRTLの間で言語の方向が変更される場合は、このソリューションが機能します。また、アプリのリセットも必要ありません。

お役に立てば幸いです。

1
inigo333

Directional Layout Marginsを使用(iOS 11.0以降)

enter image description here

そして、ビューを

右から左

 UIView.appearance().semanticContentAttribute = .forceRightToLeft

左から右

 UIView.appearance().semanticContentAttribute = .forceLeftToRight
0
MAhipal Singh