NSLocalizedStringが特定の言語を使用するように強制する方法


263

iPhone NSLocalizedStringでは、文字列をiPhone の言語で返します。NSLocalizedString特定の言語を使用して、デバイスとは異なる言語でアプリを強制することは可能ですか?


これを参照してください:stackoverflow.com/a/48187049/6665075作品を魔法のように
Ankitクマールグプタ

回答:


261

NSLocalizedString()(およびそのバリアント)で「AppleLanguages」キーにアクセスして、NSUserDefaults優先言語のユーザー設定を確認します。これは、言語コードの配列を返します。最初のコードはユーザーが自分の電話用に設定したものであり、リソースが優先言語で使用できない場合、後続のコードはフォールバックとして使用されます。(デスクトップでは、ユーザーはシステム環境設定でカスタム注文で複数の言語を指定できます)

必要に応じて、setObject:forKey:メソッドを使用して独自の言語リストを設定することにより、独自のアプリケーションのグローバル設定をオーバーライドできます。これは、グローバルに設定された値よりも優先され、ローカライズを実行しているアプリケーションのコードに返されます。このためのコードは次のようになります。

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate

これにより、ドイツ語がアプリケーションの優先言語になり、英語とフランス語がフォールバックになります。アプリケーションの起動の早い段階でこれを呼び出す必要があります。言語/ロケールの設定について詳しくは、こちらをご覧ください:国際化プログラミングトピック:現在の言語とロケールの取得


4
これは私にとっては機能しません。何があってもデフォルトの言語を使用します。
quano

50
デニス; アプリを起動する前に言語設定を行った方がうまくいくようです。UIApplicationMain()が呼び出される前に、main()関数でそれを行います。実際に実行されると、使用される言語は変更されませんが、次回の設定が変更されます。
geon

3
あなたはのUIKitを初期化する前に、言語を設定する必要があり、あなたは完全な言語+地域ロケールを指定しなければなりません-完全な例のために、このアウトをチェックblog.federicomestrone.com/2010/09/15/...
fedmest

18
AppleLanguagesを設定すると、main()で実行すると実行時に言語が変更されます-true!しかし...アプリが最初にインストールされたとき、nsuserdefaultsが初期化された後、UIApplicationMain()が呼び出されます。これにより、以前に設定されたAppleLanguagesが無視され、目的の言語を表示するためにアプリを強制的に再起動する必要があります。
JohnPayne 2013

3
これは、Localizable.stringsdictで定義された複数のアイテムでは機能しません。可能な修正がある場合、何か考えはありますか?
Mihai Fratu

147

最近同じ問題が発生し、NSLocalizedString全体を開始してパッチを適用したくありませんでしたたり、アプリを強制的に再起動して新しい言語を機能。私はすべてが現状のままで機能することを望んでいました。

私の解決策は、メインバンドルのクラスを動的に変更し、適切なバンドルをそこにロードすることでした。

ヘッダーファイル

@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end

実装

#import <objc/runtime.h>

static const char _bundle=0;

@interface BundleEx : NSBundle
@end

@implementation BundleEx
-(NSString*)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    NSBundle* bundle=objc_getAssociatedObject(self, &_bundle);
    return bundle ? [bundle localizedStringForKey:key value:value table:tableName] : [super localizedStringForKey:key value:value table:tableName];
}
@end

@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        object_setClass([NSBundle mainBundle],[BundleEx class]);
    });
    objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

したがって、基本的に、アプリが起動したとき、最初のコントローラーをロードする前に、次のコードを呼び出すだけです。

[NSBundle setLanguage:@"en"];

ユーザーが設定画面で優先言語を変更した場合は、もう一度呼び出すだけです。

[NSBundle setLanguage:@"fr"];

システムのデフォルトにリセットするには、nilを渡すだけです。

[NSBundle setLanguage:nil];

楽しい...

Swiftバージョンが必要な場合:

var bundleKey: UInt8 = 0

class AnyLanguageBundle: Bundle {

    override func localizedString(forKey key: String,
                                  value: String?,
                                  table tableName: String?) -> String {

        guard let path = objc_getAssociatedObject(self, &bundleKey) as? String,
              let bundle = Bundle(path: path) else {

            return super.localizedString(forKey: key, value: value, table: tableName)
            }

        return bundle.localizedString(forKey: key, value: value, table: tableName)
    }
}

extension Bundle {

    class func setLanguage(_ language: String) {

        defer {

            object_setClass(Bundle.main, AnyLanguageBundle.self)
        }

        objc_setAssociatedObject(Bundle.main, &bundleKey,    Bundle.main.path(forResource: language, ofType: "lproj"), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

7
こんにちは@Wirsing、これは今のところ私にとってはうまくいきます。私はストアに1つのアプリをアップロードしましたが、Appleからの不満はありません。
Gilad Novik 2014年

7
これは素晴らしいソリューションです。ここでも参照しています。medium.com
James Tang

1
こんにちは@JamesTang、リファレンスとあなたの投稿をありがとう-私はローカライズに関して多くの有用な情報をそこで見つけました。
Gilad Novik 2014年

3
@Giladメソッドは動的文字列(localizable.stringsで定義した文字列)に最適ですが、ストーリーボードボタンとラベルはメインメソッドでのみ機能します。答えを拡張して、UIコントロールのローカリゼーションを含めることができますか?[NSBundle setLanguage:@ "??"];を呼び出した後、ストーリーボードを(閉じることなく)更新する方法を意味します。
Jawad Al Shaikh 2014年

2
XIB /ストーリーボードについては、ビューをロードする前にこのメソッドを呼び出す必要があります。これまでのビューの更新について:私の場合は、ビューコントローラーをリロードしました(ナビゲーションコントローラーに入れてコントローラーを交換しました。リロードすると、新しい翻訳された文字列が取得されました)。私はそのためのココアポッドに取り組んでいます。おそらくそこにも例を含めます。
引き続きご期待ください

137

私は通常、この方法でこれを行いますが、プロジェクトにはすべてのローカリゼーションファイルが必要です。

@implementation Language

static NSBundle *bundle = nil;

+(void)initialize 
{
    NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
    NSArray* languages = [defs objectForKey:@"AppleLanguages"];
    NSString *current = [[languages objectAtIndex:0] retain];
    [self setLanguage:current];
}

/*
  example calls:
    [Language setLanguage:@"it"];
    [Language setLanguage:@"de"];
*/
+(void)setLanguage:(NSString *)l
{
    NSLog(@"preferredLang: %@", l);
    NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:@"lproj" ];
    bundle = [[NSBundle bundleWithPath:path] retain];
}

+(NSString *)get:(NSString *)key alter:(NSString *)alternate 
{
    return [bundle localizedStringForKey:key value:alternate table:nil];
}

@end

1
+1。これは私が他のどこにも見たことがない本当に素晴らしいトリックです。ローカリゼーションフォルダーの1つから「サブバンドル」を作成することにより、NSLocalizedStringをここで迂回するものでラップする限り、文字列を正常に機能させることができます。
Ben Zotto

4
素晴らしいマウロ。私はそれがあなたのプロジェクトからのファイルのためにも働くことができることに気づきました。(私の場合のように)何らかの理由で、ネットワークから文字列ファイルをダウンロードし、それらを 'Documents'ディレクトリに保存する必要があります(フォルダー構造Documents / en.lproj / Localizable.strings、Documents / fr.lproj /を使用) Localizable.strings、...)。NSBundleを作成することもできます。パスにこのコードを使用するだけです:NSString * path = [NSHomeDirectory()stringByAppendingPathComponent:[NSString stringWithFormat:@ "/ Documents /%@。lproj"、l、nil]];
アルノーデル。

1
これは、以下のアレッサンドロからの貢献とともに、これが最良のアプローチであると私には思われます。それはそれほど煩わしくなく、再起動を必要とすべきではありません。
PKCLsoft

1
何が悪いのですか?NSObjectを継承する言語クラスを作成し、これを実装に入れ、メソッド名を.hに入れてから、[Language setLanguage:@ "es"]を入れました。私の言語変更ボタンでは、コードは実行されます(ボタンメソッドが呼び出され、言語クラスに移動します)が、何もしません。localizable.strings(スペイン語)もセットアップしました。しかし、それは他の多くの人々のために働いているようです。誰かが私のためにそれを馬鹿にしてください。
SirRupertIII、2012年

1
@KKendallは次のように呼び出します:[Language setLanguage:@ "es"]; NSString * stringToUse = [Language get:@ "Your Text" alter:nil];
ミクラスヤ2013

41

iOS 9では使用しないでください。これは、渡されたすべての文字列に対してnilを返します。

アプリを再起動せずにgenstringsと互換性のある言語文字列を更新できる別のソリューションを見つけました。

このマクロをPrefix.pchに配置します。

#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]

ローカライズされた文字列の使用が必要な場合:

NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")

言語の使用を設定するには:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];

次のような連続した言語ホッピングでも機能します:

NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"fr"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"it"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));

2
@ powerj1984:いいえ、ソースファイルの文字列のみが変更されます。xib言語を変更する場合は、選択した言語のバンドルからxibを手動でリロードする必要があります。
gklka 2014年

@gklka私はTudozierによって与えられた手順に従いましたが、手作業でXIBをリロードするように言ったように、私のXIBは言語を変更していません。
Dk Kumar 14

@DkKumar:あなたはこれに似た何かをする必要があります:stackoverflow.com/questions/21304988/...
gklka

@gklkaあなたの答えは正しいようで、あなたが答えで説明したのと同じ手順を実行しましたが、バンドルパスを変更すると、すべてのリソース(つまり、XIBで使用される.pngファイル)が見つかるので問題は同じバンドルなので、en.lproj、es.lprojなどのすべてのバンドルのimagesフォルダーを上書きコピーする必要があります。IPAサイズの増加に影響するため、この問題を解決する方法はありますか?あなたの投稿で言ったように、これを試してみましょう。これについて詳しく教えてください。同じことを手伝ってくれてありがとう
Dk Kumar

1
これはiOS 9ではひどく壊れており、すべての文字列に対してnullを返します。
Alex Zavatone、2015年

32

前に述べたように、次のようにします。

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

ただし、アプリを再起動する必要がないように、その行をのメインメソッドのmain.m直前UIApplicationMain(...)に配置します。


2
非常に役立つ回答です。PS初心者には明らかなように聞こえるかもしれませんがNSAutoreleasePool * pool ..、自動解放されたオブジェクトがリークした後にその行を挿入する必要があります。
pt2ph8

1
重要:[[NSBundle mainBundle] URLForResource:withExtension:]以前に電話をかけた場合、これは機能しません。
Kof 2013

3
Swiftを使用している場合、main.mはありませんか?
2015年

@turingtestedは、迅速かつストーリーボードで試したことがありますか?
iDevAmit 2016

こんにちは、サーバーから送られてくる動的テキストをローカライズする方法、私のアプリケーションではすべてのテキストを簡体字中国語で表示する必要がありますが、英語で送られるテキストを中国語で表示する方法。助けて。
Mahesh Narla 2017年

31

アプリから選択して特定の言語を使用するコツは、 NSLocalizedString、選択した言語に応じて特定のバンドルを使用することことです。

これは私がiOSアプリでこのローカリゼーションのローカリゼーションを学ぶために書いた投稿 です

そして、これはiOSアプリでの1つのサンプルアプリ事前ローカリゼーションのコードです


これはiOS7でも機能します。iOSが再度言語オプションをオーバーライドするように思われるため、ブライアンのソリューションからこれに切り替える必要があるため、初めての言語設定のままにしました。あなたの解決策は魅力のように機能します!
haxpor 2013

14

Swift 3のこのソリューションについてどう思いますか?

extension String {

    func localized(forLanguage language: String = Locale.preferredLanguages.first!.components(separatedBy: "-").first!) -> String {

        guard let path = Bundle.main.path(forResource: language == "en" ? "Base" : language, ofType: "lproj") else {

            let basePath = Bundle.main.path(forResource: "Base", ofType: "lproj")!

            return Bundle(path: basePath)!.localizedString(forKey: self, value: "", table: nil)
        }

        return Bundle(path: path)!.localizedString(forKey: self, value: "", table: nil)
    }
}

簡単な使い方:

"report".localized(forLanguage: "pl") //forced language
"report".localized() //default language selected by user in settings, in case when your app doesnt support selected lanaguage, the default one is selected, here is an english.

こんにちは、サーバーから送られてくる動的テキストをローカライズする方法、私のアプリケーションではすべてのテキストを簡体字中国語で表示する必要がありますが、英語で送られるテキストを中国語で表示する方法。助けて。
Mahesh Narla 2017年

これは素晴らしい答えです。)
BartłomiejSemańczyk19年

すばらしいanswer.helped
ディリップ

13

Brian Websterが述べているように、言語は「アプリケーションの起動の早い時期」に設定する必要があります。私は考えましapplicationDidFinishLaunching:AppDelegate、私は他のすべての初期化を行う場所、それはだから、それを行うために適した場所でなければなりません。

しかし、William Dennissが言及しているように、それはアプリが再起動されたにのみ効果があるようで、それは一種の役に立たないです。

ただし、コードをmain関数に配置すると問題なく動作するようです。

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Force language to Swedish.
    [[NSUserDefaults standardUserDefaults]
     setObject:[NSArray arrayWithObject:@"sv"]
     forKey:@"AppleLanguages"];

    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

これについてのコメントをいただければ幸いです。


私の実装では、これはユーザーが設定できるものです。そのため、再起動する必要があることを伝えるダイアログをポップアップします:)
William Denniss

ローカライズされたDefault.png画像を除いて、ほとんどすべての場合に機能します。
Lukasz、2010年

2
ユーザーに言語の設定を許可してからアプリを再起動するように指示している場合は、再起動が速すぎるとNSUserDefaultsが保存されない可能性があることに注意してください。ほとんどのユーザーはこれほど速くはありませんが、アプリをテストしていると、速すぎて結果として一貫性のない動作が見られる場合があります。私の言語切り替えが機能する場合と機能しない場合がある理由を理解するのに2時間かかりました。
arlomedia 2013年

3
これは問題ではありません。[[NSUserDefaults standardUserDefaults] synchronize];電話をかけてから使用してくださいsetObject:forKey:
Ben Baron

11

私はマウロデルリオの方法が一番好きです。Project_Prefix.pchにも以下を追加しました

#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]

したがって、(NSLocalizedStringを使用する)標準メソッドを使用したい場合は、すべてのファイルで簡単な構文置換を行うことができます。


1
私はまた、彼の方法のように、私は、負荷PNG画像にメソッドを追加:+(UIImage )imageNamed:(NSStringの*)imageFileName {NSStringのをフルパス= [バンドルpathForResource:imageFileName ofType:@ "PNG"]。UIImage * imageObj = [[UIImage alloc] initWithContentsOfFile:fullPath]; return [imageObj autorelease]; }
Jagie

11

NSLocalizedString()キーの値をAppleLanguages標準ユーザーのデフォルト([NSUserDefaults standardUserDefaults])から読み取ります。この値を使用して、実行時にすべての既存のローカリゼーションの中から適切なローカリゼーションを選択します。Appleがアプリの起動時にユーザーデフォルト辞書を作成するとき、システム設定で優先言語キーを検索し、そこから値をコピーします。これは、たとえば、OS Xで言語設定を変更しても、実行中のアプリに影響を与えず、その後起動したアプリにのみ影響する理由も説明します。一度コピーすると、設定が変更されただけでは値は更新されません。そのため、言語を変更すると、iOSがすべてのアプリを再起動します。

ただし、ユーザーデフォルト辞書のすべての値は、コマンドライン引数で上書きできます。のNSUserDefaultsドキュメントを参照してくださいNSArgumentDomain。これには、アプリの設定(.plist)ファイルから読み込まれた値も含まれます。これは本当に知っておくと良いです、テストのために一度だけ値を変更したいどうかのにです

したがって、テストのためだけに言語を変更したい場合は、おそらくコードを変更したくないでしょう(後でこのコードを削除するのを忘れた場合...)代わりに、Xcodeにコマンドラインパラメーター(例:スペイン語のローカリゼーションを使用):

ここに画像の説明を入力してください

コードに触れる必要はまったくありません。言語ごとに異なるスキームを作成するだけで、スキームを切り替えるだけで、ある言語でアプリをすばやく起動し、別の言語でアプリをすばやく起動できます。


初回のみ機能し、その後再びデバイス設定に読み込まれます。言語..
Aks

@Aksはいつも私のために働く。正しいスキームを開始していること、Xcode内から開始していること(再起動、フォークなどが引数を取得しないこと)を確認し、OptionsAppleが提供する新しいXcodeバージョンと同様に、言語を上書きしないようにしてください。同じように。
Mecki 2017

@Meckiの返信ありがとうございます。私にとっては、xcodeでは機能しませんが、コードで言及すると機能します。ただし、デバイスを他の優先言語で設定している場合は、アプリを再起動して優先言語にロードする必要があります私が引数で渡している言語...
Aks

@Aksデバイスでそれを使用する場合、Xcodeから直接起動した場合にのみ機能します。一部のデバイスでアイコンをタップして再度アプリを起動した場合は機能せず、アプリが強制終了された場合も機能しません(例:バックグラウンドに移行したため)、システムによって再起動されます(この再起動はXcodeによって行われる再起動ではないため)。そのため、iOSが途中でアプリを強制終了する必要がある場合(たとえば、メモリが必要です)。
メッキー2017

10

私はあなたが使用できるようにするソリューションを思いつきましたNSLocalizedStringNSBundle通話のカテゴリを作成しますNSBundle+RunTimeLanguage。インターフェースはこんな感じ。

// NSBundle+RunTimeLanguage.h
#import <Foundation/Foundation.h>
@interface NSBundle (RunTimeLanguage)
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:@"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
@end

実装はこんな感じです。

// NSBundle+RunTimeLanguage.m
#import "NSBundle+RunTimeLanguage.h"
#import "AppDelegate.h"

@implementation NSBundle (RunTimeLanguage)

- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSString *path= [[NSBundle mainBundle] pathForResource:[appDelegate languageCode] ofType:@"lproj"];
    NSBundle *languageBundle = [NSBundle bundleWithPath:path];
    NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
    return localizedString;
}
@end

NSBundle+RunTimeLanguage.h使用するファイルにインポートを追加するだけではありませんNSLocalizedString

ご覧のとおり、languageCodeをのプロパティに格納していますAppDelegate。これは、好きな場所に保存できます。

これについて私が気に入らないのは、NSLocalizedStringマルコが再定義した警告だけです。おそらく、誰かがこの部分の修正を手伝ってくれるでしょう。


1
警告を無効にする#undef NSLocalizedString直前に追加#define
ベリリウム

これはxibファイルのローカリゼーションで機能しますか?特定の言語でUI名を翻訳するための.xibファイルと.stringsがあります。試しましたがXIBでは動作しませんが、正しく実行したかどうかはわかりません
Kong Hantrakool

コングは対応が遅れて申し訳ありません。これは、NSLocalizedStringを使用する場合に機能します。したがって、XIBでは直接機能しません。XIBの文字列へのIBOutletsが必要で、コードで文字列値をプログラムで設定する必要があります。
qman64 2015年

このアプローチは私にとってはうまくいき、言語をその場で変更することができました。「es」、「fr」、「en」などの言語コードは問題なく機能しましたが、「zh」(簡体字中国語の場合)が失敗し、null文字列が返されました。システムで「es.lproj」をグローバル検索して私がアクセスしていたファイルの場所を確認し、そこで "zh.lproj"が実際には "zh-Hans.lproj"であることを発見しました
Gallymon

9

Swiftバージョン:

NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()

8

一言で言えば :

アプリケーションをローカライズする

最初に行う必要があるのは、少なくとも2つの言語(この例では英語とフランス語)でアプリをローカライズすることです。

NSLocalizedStringをオーバーライドする

コードではNSLocalizedString(key, comment)、を使用する代わりに、マクロを使用しますMYLocalizedString(key, comment)次のように定義され。 #define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

このMYLocalizationSystemシングルトンは:

  • 適切にローカライズされたNSBundleを設定して言語を設定するユーザーが要求
  • この以前に設定された言語に従ってローカライズされたNSStringを返します

ユーザー言語を設定する

ユーザーがフランス語でアプリケーションの言語を変更した場合は、 [[MYLocalizationSystem sharedInstance] setLanguage:@"fr"];

- (void)setLanguage:(NSString *)lang
{
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj"];
    if (!path)
    {
        _bundle = [NSBundle mainBundle];
        NSLog(@"Warning: No lproj for %@, system default set instead !", lang);
        return;
    }

    _bundle = [NSBundle bundleWithPath:path];
}

この例では このメソッドはローカライズされたバンドルをfr.lprojに設定します

ローカライズされた文字列を返す

ローカライズされたバンドルを設定すると、次のメソッドを使用して、ローカライズされた正しい文字列を彼から取得できるようになります。

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value
{
    // bundle was initialized with [NSBundle mainBundle] as default and modified in setLanguage method
    return [self.bundle localizedStringForKey:key value:value table:nil];
}

これがお役に立てば幸いです。

詳細については、NSWinery.ioのこの記事をご覧ください。


回答の中でソリューションにリンクするだけでなく、リンクはいつか機能しなくなる可能性があります。回答からリンクを削除する必要はありませんが、回答を編集して、リンクされた記事の関連セクションの概要を含めるようにしてください。
Oblivious Sage

7

Swift 3拡張:

extension Locale {
    static var preferredLanguage: String {
        get {
            return self.preferredLanguages.first ?? "en"
        }
        set {
            UserDefaults.standard.set([newValue], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
        }
    }
}

extension String {
    var localized: String {

    var result: String

    let languageCode = Locale.preferredLanguage //en-US

    var path = Bundle.main.path(forResource: languageCode, ofType: "lproj")

    if path == nil, let hyphenRange = languageCode.range(of: "-") {
        let languageCodeShort = languageCode.substring(to: hyphenRange.lowerBound) // en
        path = Bundle.main.path(forResource: languageCodeShort, ofType: "lproj")
    }

    if let path = path, let locBundle = Bundle(path: path) {
        result = locBundle.localizedString(forKey: self, value: nil, table: nil)
    } else {
        result = NSLocalizedString(self, comment: "")
    }
        return result
    }
}

使用法:

Locale.preferredLanguage = "uk"

label.text = "localizedKey".localized

ありがとう。うまくいきました。
Krunal Nagvadia

5

定義するファイル.pch内

#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]


#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")

警告「ovverride ...」を取り除くにはどうすればよいですか?
Idan Moshe、

1
簡単な解決策は私が必要とするすべてを行います。私の問題を解決するためのガイドとしてこれを使用することができました ローカリゼーションファイルがないためにpathForResourceがnilを返す場合は、pathForResource:@ "Base"を使用します。これは、ベースローカリゼーションから文字列を取得しようとしたためです。ありがとうございました。
GRW

これはハックであり(他のすべての回答もそうです)、私が書いたユニットテストで実装するのが最も簡単でした。
最大

4

多分これで補完する必要があります(#importの後の.pchファイルで):

extern NSBundle* bundle; // Declared on Language.m

#ifdef NSLocalizedString
    #undef NSLocalizedString
    // Delete this line to avoid warning
    #warning "Undefining NSLocalizedString"
#endif

#define NSLocalizedString(key, comment) \
    [bundle localizedStringForKey:(key) value:@"" table:nil]

/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31:宣言されていない識別子 'bundle'の使用
pengwang

4

Swift 3ソリューション:

let languages = ["bs", "zh-Hant", "en", "fi", "ko", "lv", "ms", "pl", "pt-BR", "ru", "sr-Latn", "sk", "es", "tr"]
UserDefaults.standard.set([languages[0]], forKey: "AppleLanguages")

使用できる言語コードの例をいくつか示しました。お役に立てれば


3

これを実行するローカライズされた文字列のセットでサブバンドルを作成し、それを使用NSLocalizedStringFromTableInBundle()してそれらをロードすることができます。(これは、アプリで行う可能性のある通常のUIローカリゼーションとは別のコンテンツであると想定しています。)


3

私の場合、私は2つのローカライズされたファイル、jaとenを持っています

システムの優先言語がenでもjaでもない場合は、強制的にenにしたい

main.mファイルを編集します

最初の優先言語がenかjaかを確認し、そうでない場合は2番目の優先言語をenに変更します。

int main(int argc, char *argv[])
{

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults] synchronize];

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

    if (![lang isEqualToString:@"en"]  &&  ![lang isEqualToString:@"ja"]){

        NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[NSLocale preferredLanguages]];
        [array replaceObjectAtIndex:1 withObject:@"en"];

        [[NSUserDefaults standardUserDefaults] setObject:array forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults] synchronize];


    }

    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));


    }


}

@ chings228に感謝します。これは私にとって便利ですが、言語ごとに異なるスプラッシュがあるアプリのデフォルトの起動イメージ(スプラッシュ)は変更されません。これを申請する方法を知っていますか?
JERC、2014年

メインプログラムが実行を開始する前にスプラッシュが実行されると思うので、それを上書きする方法がわかりません
。plist

2

あなたはこのようなことをすることができます:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];


NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];

NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):

2

アプリケーションを終了したり再起動たりせずに言語を変更するというTudorizerの回答に基づいています。

マクロの代わりに、特定の言語コードが存在するかどうかを確認するために、優先言語にアクセスするためのクラスを使用します。

以下は、iOS 9で動作する現在の言語バンドルを取得するために使用されるクラスです。

@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」メソッドを更新して、新しい言語を参照する文字列パラメーターを取得します。

[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];

2

Swift 4では、ライブラリを再起動したり、ライブラリを使用したりすることなく解決しました。

多くのオプションを試した後、私はこの関数を見つけました、そこでは翻訳したい(Localizable.Stringの文字列ファイルの)stringToLocalizeと、あなたがそれを翻訳したい言語を渡します、そしてそれが返すものはStringsファイルにあるそのString:

    func localizeString (stringToLocalize: String, language: String) -> String
    {
        let path = Bundle.main.path (forResource: language, ofType: "lproj")
        let languageBundle = Bundle (path: path!)
        return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
    }

この関数を考慮して、この関数をSwiftファイルに作成しました。

struct CustomLanguage {

    func createBundlePath () -> Bundle {
        let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
        let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
        return Bundle(path: path!)!
    }
}

アプリ全体から、および残りのViewControllersの各文字列からアクセスするには、次のように配置するのではなく、

NSLocalizedString ("StringToLocalize", comment: ")

に置き換えました

let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()

NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String

それが最善の方法であるかどうかはわかりませんが、非常にシンプルであることがわかりました。それでうまくいきます。


1

この関数は、現在の言語にローカライズされた文字列を取得しようとし、見つからない場合は英語を使用して取得します。

- (NSString*)L:(NSString*)key
{
    static NSString* valueNotFound = @"VALUE_NOT_FOUND";
    static NSBundle* enBundle = nil;

    NSString* pl = [NSLocale preferredLanguages][0];
    NSString* bp = [[NSBundle mainBundle] pathForResource:pl ofType:@"lproj"];
    NSBundle* b = [NSBundle bundleWithPath:bp];

    NSString* s = [b localizedStringForKey:key value:valueNotFound table:nil];
    if ( [s isEqualToString:valueNotFound] ) {
        if ( !enBundle ) {
            bp = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
            enBundle = [NSBundle bundleWithPath:bp];
        }
        s = [enBundle localizedStringForKey:key value:key table:nil];
    }

    return s;
}

1

iOSで公式にサポートされていない言語のサポートを追加したかった(システム設定の[言語]セクションにリストされていない)。Appleの国際化チュートリアルと、ブライアンウェブスターとgeonによるいくつかのヒントに従って、次のコードを思いつきました(main.mに入れてください)。

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // Grab regional settings locale, for Slovenian this is either sl_SI or en_SI
        NSLocale *locale = [NSLocale currentLocale];
        NSString *ll = [locale localeIdentifier]; // sl_SI

        // Grab the first part of language identifier
        NSArray *comp = [ll componentsSeparatedByString:@"_"];
        NSString *ll1 = @"en";
        if (comp.count > 0) {
            ll1 = comp[0]; // sl, en, ...
        }
        // Check if we already saved language (user can manually change it inside app for example)
        if (![[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"]) {
            //   Slovenian (Slovenia),            Slovenia
            if ([ll isEqualToString:@"sl_SI"] || [ll isEqualToString:@"en_SI"]) {
                ll1 = @"sl-SI"; // This is the part of localized path for Slovenian language that Xcode generates
            }
            // Add more unsupported languages here...

            [[NSUserDefaults standardUserDefaults] setObject:ll1 forKey:@"SelectedLanguage"]; // Save language
        }
        else {
            // Restore language as we have previously saved it
            ll1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"];
        }
        // Overwrite NSLocalizedString and StoryBoard language preference
        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:ll1, @"en", @"fr", nil] forKey:@"AppleLanguages"];
        // Make sure settings are stored to disk
        [[NSUserDefaults standardUserDefaults] synchronize];

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

これは、ストーリーボードとNSLocalizedStringコードの両方でうまく機能します。コードは、ユーザーが後でアプリ内の言語を手動で変更するオプションがあることを前提としています。

もちろん、適切なStoryboard翻訳とLocalizable.strings翻訳を追加することを忘れないでください(その方法については、上のAppleページへのリンクを参照してください)。


スロベニア語の問題にも直面しているようです:) iOSでサポートされていない言語のこの回答を改善するために、アプリのシステム制御に使用されるローカライズ可能なカスタム文字列を設定できるかどうか考えましたか(編集、完了、その他、 ...)?
miham 2016

1

この問題の適切な解決策を次に示します。アプリケーションを再起動する必要はありません。

https://github.com/cmaftuleac/BundleLocalization

この実装は、NSBundle内を調整することで機能します。考え方は、NSBundleオブジェクトのインスタンスでメソッドlocalizedForForKeyをオーバーライドしてから、このメソッドを別の言語の別のバンドルで呼び出すというものです。シンプルでエレガント、あらゆるタイプのリソースと完全に互換性があります。


プロジェクトからのこのコードは私に大いに役立ちました。特定の言語コードのバンドルを見つける方法---NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
Eonil '12

このクラスは正常に動作していますが、言語を別の言語に変更した後、影響はありません。
Anilkumar iOS ReactNative 16

0

何をするにせよ、最善の方法は、指定された言語のshort_nameを取得することです。つまり、fr、en、nl、de、itなどです。これをグローバル値に割り当てます。

ドロップダウンメニューのようにポップアップするピッカービューを作成し(クリックすると、ピッカービューが下から言語のリストとともに表示されるボタンの組み合わせ)、目的の言語を選択します。短縮名を内部に保存します。LocalisedStringという名前の.h + .mファイルを作成します。

short_nameのグローバル値をLocalisedString.mで取得した値と等しくなるように設定します。必要な言語が選択されたら、NSBundlePathを割り当てて、必要な言語のプロジェクトサブディレクトリを作成します。たとえば、nl.proj、en.proj。

特定のprojフォルダーを選択すると、それぞれの言語にローカライズされた文字列が呼び出され、言語が動的に変更されます。

ルール違反はありません。


0

Swiftの場合は、main.swiftアプリを実行する前に、ファイルを上書きしてUserDefaults文字列を設定できます。この方法では、目的の効果を確認するためにアプリを再起動する必要はありません。

import Foundation
import UIKit

// Your initialisation code here
let langCultureCode: String = "LANGUAGE_CODE"

UserDefaults.standard.set([langCultureCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()

UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))

ファイル@UIApplicationMain内のの削除とペアになっていAppDelegate.swiftます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.