web-dev-qa-db-ja.com

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

アプリを再起動することなく、アプリ内で言語を変更できるアプリもあるようですが、どのように実装されているのでしょうか。

たとえば、NSLocalizedStringを使用する場合、AppDelegateが初期化されていないときに、main.mの実行時に言語を設定できることはわかっていますが、一度初期化されると(特にView Controllerが作成されます) )、次のrestartまで有効にならない変更

[[NSUserDefaults standardUserDefaults] 
    setObject:[NSMutableArray arrayWithObjects:language, nil] 
    forKey:@"AppleLanguages"];

アプリを再起動せずに、これらの動的な言語の変更を行う方法を知っている人はいますか?

29
Ryan

ここでは、他のアプローチ、特に通知ベースのアプローチについて説明します。

iOS:アプリを再起動せずにプログラムでアプリの言語を変更する方法

私の見解では、実際には3つのタスクがあります。(1)nibsから自動的にロードされたリソースの再ローカリゼーション。 (たとえば、nibから別のカスタムUIViewを動的にインスタンス化する場合、「古い」言語の文字列と設定(画像、テキストの方向)がロードされます)(2)画面に現在表示されている文字列の再ローカライズ。 (3)開発者(あなた)がプログラムコードに挿入した文字列の再ローカライズ。

(3)から始めましょう。定義を探すと、NSLocalizedStringがマクロであることがわかります。したがって、既存のコードをあまり変更したくない場合は、おそらく新しいヘッダーファイルを作成することで(3)の問題を解決できます。そのヘッダーファイルでは、#undefその後、再#define NSLocalizedString適切な場所からローカライズされた文字列を選択します。iOSのデフォルトではなく、グローバル変数(アプリデリゲートivarなど)で追跡する文字列です。 NSLocalizedStringを再定義したくないが、それでも独自の代替を作成する場合は、おそらく#undef NSLocalizedString将来の開発者が、置換するマクロの代わりに誤って呼び出すことを望まない場合。理想的なソリューションではありませんが、おそらく最も実用的なソリューションです。

(1)については、Interface Builderでローカライズを行っていないが、viewDidLoadなどで動的に行っている場合は問題ありません。先ほど説明したのと同じ動作(つまり、変更されたNSLocalizedStringなど)を使用できます。それ以外の場合は、(a)上記のリンクで説明されているように通知システムを実装する(複雑な)か、(b)ローカリゼーションをIBからviewDidLoadに移行することを検討するか、(c)initWithNibName:そして、古い言語リソースでロードされたオブジェクトを、新しい言語リソースでロードされたオブジェクトと交換します。これは、この議論の一番下でMohamedが言及したアプローチでした: http://learning-ios.blogspot.ca/2011/04/advance-localization-in-ios-apps.html 。彼はそれが問題を引き起こすと主張しています(viewDidLoadは呼び出されません)。動作しない場合でも、試してみると、動作する何かを示す可能性があります。

最後に、(2)はおそらく最も簡単なタスクです。現在のビューを削除して再追加するだけです(場合によっては再描画するだけです)。

5
Merk

アイデアは、別の特定のバンドルから翻訳を取得するかどうかを確認するNSLocalizedStringのような新しいマクロを作成することです。

method 2 in this article でその方法を正確に説明しています。この特定のケースでは、作成者は新しいマクロを使用しませんが、直接カスタムクラスを設定します _[NSBundle mainBundle]_の場合。

@holexがこれを読んでいる問題を理解することを願っています。

2
Matteo Gobbi

私の実装では、クラスを使用して言語を変更し、現在の言語バンドルにアクセスします。これは一例であるため、私とは異なる言語を使用する場合は、メソッドを変更して正確な言語コードを使用してください。

このクラスは、NSLocaleから優先言語にアクセスし、使用されている言語である最初のオブジェクトを取得します。

@implementation OSLocalization

+ (NSBundle *)currentLanguageBundle
{
    // Default language incase an unsupported language is found
    NSString *language = @"en";

    if ([NSLocale preferredLanguages].count) {
        // Check first object to be of type "en","es" etc
        // Codes seen by my eyes: "en-US","en","es-US","es" etc

        NSString *letterCode = [[NSLocale preferredLanguages] objectAtIndex:0];

        if ([letterCode rangeOfString:@"en"].location != NSNotFound) {
            // English
            language = @"en";
        } else if ([letterCode rangeOfString:@"es"].location != NSNotFound) {
            // Spanish
            language = @"es";
        } else if ([letterCode rangeOfString:@"fr"].location != NSNotFound) {
            // French
            language = @"fr";
        } // Add more if needed
    }

    return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]];
}

/// Check if preferred language is English
+ (BOOL)isCurrentLanguageEnglish
{
    if (![NSLocale preferredLanguages].count) {
        // Just incase check for no items in array
        return YES;
    }

    if ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:@"en"].location == NSNotFound) {
        // No letter code for english found
        return NO;
    } else {
        // Tis English
        return YES;
    }
}

/*  Swap language between English & Spanish
 *  Could send a string argument to directly pass the new language
 */
+ (void)changeCurrentLanguage
{
    if ([self isCurrentLanguageEnglish]) {
        [[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
    } else {
        [[NSUserDefaults standardUserDefaults] setObject:@[@"en"] forKey:@"AppleLanguages"];
    }
}
@end

上記のクラスを使用して、文字列ファイル/画像/ビデオ/などを参照します。

// Access a localized image
[[OSLocalization currentLanguageBundle] pathForResource:@"my_image_name.png" ofType:nil]
// Access  a localized string from Localizable.strings file
NSLocalizedStringFromTableInBundle(@"StringKey", nil, [OSLocalization currentLanguageBundle], @"comment")

以下のようにインラインで言語を変更するか、上記のクラスの「changeCurrentLanguage」メソッドを更新して、新しい言語コードを参照する文字列パラメーターを取得します。

// Change the preferred language to Spanish
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
1
Antonioni

私は常にこの方法を使用していますが、完璧に機能し、あなたにも役立つかもしれません。


すべてのUIの_-viewWillAppear:_メソッドで、現在の言語のUIViewControllerNSLocalizableString(...)を使用してすべてのテキストを設定する必要があります。

この方法を使用すると(つまり、ユーザー)再起動する必要はありませんSettingsでiOSの言語を変更した後のアプリケーション


もちろん、私はAppleの標準的なローカライズアーキテクチャを使用しています。

更新日(2013年10月24日)

アプリケーションがフォアグラウンドに入ると、実際のビューに対して_–viewWillAppear:_メソッドが実行されないことを経験しました。この問題を解決するために、ビューでUIApplicationWillEnterForegroundNotification通知を受け取ったときに手順(上記を参照)もコミットします。

1
holex

私は同じ問題で立ち往生しました、私の要件は「ユーザーはドロップダウンから言語を選択でき、アプリケーションは選択された言語(英語またはアラビア語)に従って動作する必要がありました」このようにして、ユーザーは言語を選択できます。同じためにNSBundleを使用しました。お気に入り

XIBの場合

self.homeScreen =  [[HomeScreen alloc] initWithNibName:@"HomeScreen" bundle:[CommonData sharedCommonData].languageBundle];

テキスト用

_lblHeading.text = [self languageSelectedStringForKey:@"ViewHeadingInfo"];

/**
 This method is responsible for selecting language bundle according to user's selection. 
 @param: the string which is to be converted in selected language. 
 @return: the converted string.
 @throws:
 */

-(NSString*) languageSelectedStringForKey:(NSString*) key

{

    NSString* str=[[CommonData sharedCommonData].languageBundle localizedStringForKey:key value:@"" table:nil];

    return str;

}
0
Mangesh