On iPhoneNSLocalizedString
は、文字列を iPhone の言語で返します。特定の言語を強制的NSLocalizedString
に使用して、アプリをデバイスとは異なる言語にすることはできますか?
28 に答える
NSLocalizedString()
(およびその亜種) は、"AppleLanguages" キーにアクセスしてNSUserDefaults
、優先言語に対するユーザーの設定を判断します。これは、言語コードの配列を返します。最初のコードはユーザーが自分の電話に設定したもので、後続のコードは優先言語でリソースが利用できない場合にフォールバックとして使用されます。(デスクトップでは、ユーザーはシステム環境設定のカスタム順序で複数の言語を指定できます)
必要に応じて、setObject:forKey: メソッドを使用して独自の言語リストを設定することにより、独自のアプリケーションのグローバル設定をオーバーライドできます。これは、グローバルに設定された値よりも優先され、ローカライズを実行しているアプリケーション内のすべてのコードに返されます。このコードは次のようになります。
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
これにより、ドイツ語がアプリケーションの優先言語になり、英語とフランス語が代替言語になります。アプリケーションの起動の早い段階でこれを呼び出す必要があります。言語/ロケール設定の詳細については、こちらを参照してください:国際化プログラミングのトピック: 現在の言語とロケールの取得
私は通常、この方法でこれを行いますが、プロジェクトにはすべてのローカライズ ファイルが必要です。
@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
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, @""));
アプリから選択して特定の言語を使用するトリックはNSLocalizedString
、選択した言語に応じて特定のバンドルを強制的に使用することです。
これは、iOSアプリでの高度なローカリゼーションの学習のために私が書いた投稿 です
これは、iOS アプリでの 1 つのサンプル アプリの高度なローカリゼーションのコードです。
前述のように、次のようにします。
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
ただし、アプリを再起動する必要がないように、(...)のmain.m
直前に, のメイン メソッドに行を挿入します。UIApplicationMain
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.
Brian Webster が言及しているように、言語は「アプリケーションの起動の早い段階で」設定する必要があります。他のすべての初期化を行う場所であるため、それを行うのに適した場所であるapplicationDidFinishLaunching:
と考えました。AppDelegate
しかし、William Denniss が言及しているように、それはアプリが再起動された後にのみ効果があるようで、これは役に立たない.
ただし、コードをメイン関数に入れるとうまくいくようです:
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;
}
これについてコメントをいただければ幸いです。
NSLocalizedString()
AppleLanguages
標準のユーザー デフォルト ( ) からキーの値を読み取ります[NSUserDefaults standardUserDefaults]
。その値を使用して、実行時にすべての既存のローカライズから適切なローカライズを選択します。Apple がアプリの起動時にユーザー デフォルト辞書を作成するとき、システム設定で優先言語キーを検索し、そこから値をコピーします。これは、たとえば、OS X で言語設定を変更しても実行中のアプリには影響せず、その後起動したアプリにのみ影響する理由も説明しています。コピーすると、設定が変更されたという理由だけで値が更新されることはありません。そのため、言語を変更すると、iOS はすべてのアプリを再起動します。
ただし、ユーザー デフォルト ディクショナリのすべての値は、コマンド ライン引数で上書きできます。NSUserDefaults
のドキュメントを参照してくださいNSArgumentDomain
。これには、アプリの設定 (.plist) ファイルから読み込まれた値も含まれます。テストのために一度だけ値を変更したい場合は、これを知っておくと便利です。
したがって、テストのためだけに言語を変更したい場合は、おそらくコードを変更したくないでしょう (後でこのコードを削除するのを忘れた場合...)。代わりに、コマンド ライン パラメーターを使用してアプリを起動するように Xcode に指示します (例: スペイン語のローカライズを使用):
コードに触れる必要はまったくありません。言語ごとに異なるスキームを作成するだけで、スキームを切り替えるだけで、ある言語で 1 回、別の言語で 1 回、アプリをすばやく起動できます。
私はマウロ・デルリオの方法が一番好きです。Project_Prefix.pch に以下も追加しました
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
したがって、標準の方法 (NSLocalizedString を使用する) を使用したい場合は、すべてのファイルで簡単な構文置換を行うことができます。
を使用できるようにするソリューションを思いつきましたNSLocalizedString
。NSBundle
callのカテゴリを作成します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
再定義した警告です。おそらく、誰かがこの部分を修正するのを手伝ってくれるでしょう。
ファイル.pchで次を定義します。
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
たぶん、これを補完する必要があります( #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]
これを実行するローカライズされた文字列のセットを使用してサブバンドルを作成し、NSLocalizedStringFromTableInBundle()
それらをロードするために使用できます。(これは、アプリで実行している可能性のある通常のUIローカリゼーションとは別のコンテンツであると想定しています。)
私の場合、ja と en の 2 つのローカライズされたファイルがあります。
システムの優先言語が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]));
}
}
次のようなことができます。
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
この関数は、現在の言語のローカライズされた文字列を取得しようとします。見つからない場合は、英語を使用して取得します。
- (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;
}
iOS で公式にサポートされていない言語のサポートを追加したかった (システム設定の [言語] セクションにリストされていない)。Apple の Internationalization Tutorialと、Brian Webster と 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]));
}
}
これは、Storyboard と NSLocalizedString コードの両方でうまく機能します。このコードは、ユーザーが後でアプリ内の言語を手動で変更するオプションを持っていることを前提としています。
もちろん、適切な Storyboard 翻訳と Localizable.strings 翻訳を追加することを忘れないでください (方法については、上記の Apple ページへのリンクを参照してください)。
何をするにせよ、最善の方法は、指定された言語の short_name を取得することです。つまり、fr、en、nl、de、it など... をグローバル値に割り当てます。
ピッカー ビューをドロップ ダウン メニューのようにポップアップするようにし (クリックするとピッカー ビューが下から表示されるボタンと言語のリストを組み合わせたもの)、目的の言語を選択します。短い名前を内部に保存します。LocalizedString という名前の .h + .m ファイルを作成します。
short_name のグローバル値を、LocalisedString.m で取得した値と等しくなるように設定します。必要な言語を選択したら、NSBundlePath を割り当てて、必要な言語のプロジェクト サブディレクトリを作成します。たとえば、nl.proj、en.proj です。
特定の proj フォルダーを選択すると、それぞれの言語のローカライズされた文字列が呼び出され、言語が動的に変更されます。
規則違反はありません。