web-dev-qa-db-ja.com

iOSで文字列をローカライズする:デフォルト(フォールバック)言語?

デバイスのUI言語がアプリでサポートされていない場合に使用するデフォルトの言語を設定する方法はありますか?

例:私のアプリは英語とドイツ語にローカライズされています:

// en.lproj:
"POWER_TO_THE_PEOPLE_BTN" = "Power";
"POWER_PLUG_BTN" = "Power";

// de.lproj:
"POWER_TO_THE_PEOPLE_BTN"  = "Macht";
"POWER_PLUG_BTN" = "Spannung";

ここで、UI言語がItalianに設定されたデバイスでアプリを実行すると、アプリはキー文字列POWER_TO_THE_PEOPLE_BTNおよびPOWER_PLUG_BTNを使用します。

このような場合にアプリケーションが使用するデフォルト(フォールバック)言語を指定する方法が必要です。

上記の例から、英語の文字列をキーとして使用しても機能しないことは明らかです。

私が今目にする唯一のオプションは、NSLocalizedStringWithDefaultValueの代わりにNSLocalizedStringを使用することです。

39
Volker Voecking

おそらくこれは役立つでしょうか? - iPhone:ローカリゼーション/国際化デフォルト文字列ファイル

デフォルトでは英語にフォールバックするはずです。スマートフォンを、アプリがローカライズされていない言語に切り替えたところ、予想どおり、テキストはすべて英語でした。

重要:@hyperspasmのコメント:展開/言い換えると、フォールバック言語は、デバイスの設定でユーザーが最後に選択した言語です、それもアプリのバンドルに含まれています。

17

これらすべての長い構文を避け、翻訳者にわかりやすいvar名を持たせるために、翻訳用に独自のヘルパーメソッドL()を派生させ、英語にフォールバックしました

_NSString * L(NSString * translation_key) {
    NSString * s = NSLocalizedString(translation_key, nil);
    if (![[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:@"en"] && [s isEqualToString:translation_key]) {
    NSString * path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
    NSBundle * languageBundle = [NSBundle bundleWithPath:path];
    s = [languageBundle localizedStringForKey:translation_key value:@"" table:nil];
    }
    return s;
}
_

私の_Localizable.strings_は次のようになります

_"SOME_ACTION_BUTTON" = "Do action";
_

したがって、私のコードでは、L(@"SOME_ACTION_BUTTON")を使用して正しい文字列を取得します

キーが翻訳自体よりも長い場合がありますが_HELP_BUTTON_IN_NAV_BAR = 'Help'_ですが、翻訳を手伝ってくれている人にそれが何であるかを説明するのに多くの時間を節約できます

19
Kent Nguyen

Info.plistのCFBundleDevelopmentRegionの値が、フォールバック先の言語リージョンであることを確認する必要があります。 (例: "en")

17
Pattrawoot S.

Swift 4の@Bogusの答えは、iOS 11.1の魅力のように機能します。

public func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String {
    let fallbackLanguage = "en"
    guard let fallbackBundlePath = Bundle.main.path(forResource: fallbackLanguage, ofType: "lproj") else { return key }
    guard let fallbackBundle = Bundle(path: fallbackBundlePath) else { return key }
    let fallbackString = fallbackBundle.localizedString(forKey: key, value: comment, table: nil)
    return Bundle.main.localizedString(forKey: key, value: fallbackString, table: nil)
}
3
Makalele

メソッドを置き換えずにこれを行う高速な方法は、NSLocalizedString定義を「オーバーライド」し、この定義に Appleが使用する のメソッドを使用してそれを置き換え、「オーバーライドされた」メソッドに追加のフォールバックロジックを追加することです。

#undef NSLocalizedString
#define NSLocalizedString(key, comment) [self localizedStringForKey:(key) replaceValue:(comment)]

+ (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment {
    NSString *fallbackLanguage = @"en";
    NSString *fallbackBundlePath = [[NSBundle mainBundle] pathForResource:fallbackLanguage ofType:@"lproj"];    
    NSBundle *fallbackBundle = [NSBundle bundleWithPath:fallbackBundlePath];
    NSString *fallbackString = [fallbackBundle localizedStringForKey:key value:comment table:nil];    
    NSString *localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:fallbackString table:nil];

    return localizedString;
}
3
Bogus

https://stackoverflow.com/a/25928309/3664461 のおかげで私の解決策

Global.h

NSString * LString(NSString * translation_key);

Global.m

NSString *LString(NSString *translation_key) {
  NSString *lString = nil;
  NSString *languageCode = nil;

  if ([UIDevice currentDevice].systemVersion.floatValue >= 9) {
    NSString *localeIdentifier = [[NSLocale preferredLanguages] objectAtIndex:0];
    NSDictionary *localeDic = [NSLocale componentsFromLocaleIdentifier:localeIdentifier];
    languageCode = [localeDic objectForKey:@"kCFLocaleLanguageCodeKey"];
  } else {
    languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
  }

  NSString *path = [[NSBundle mainBundle] pathForResource:languageCode ofType:@"lproj"];
  if (path != nil) {
    lString = NSLocalizedStringFromTableInBundle(translation_key, @"Localizable",
                                             [NSBundle bundleWithPath:path], @"");
  }

   path = [[NSBundle mainBundle] pathForResource:@"Base" ofType:@"lproj"];
   lString = NSLocalizedStringFromTableInBundle(translation_key, @"Localizable",
                                             [NSBundle bundleWithPath:path], @"");
  }
  return lString;
}

使用法:

#import "Global.h"
printf(LString(@"MyKey").UTF8String);

このソリューションでは、ユーザーの優先順位は考慮されません。代わりに、ユーザーの第一言語がローカライズされていない場合は、Baseの下にあるものに常にフォールバックします。また、特定のキーが現在の言語にローカライズされていないが、基本ローカリゼーションに存在する場合は、基本ローカリゼーションを取得します。

更新:

IOS 9以降、地域は言語ロケールに含まれています。それを処理するようにコードを更新しました。

2
Siamaster

カテゴリを作成しましたNSBundle+FallbackLanguageフォールバック言語をサポートするには、 github folder でチェックアウトできます。実装でサポートされている言語の配列を指定するだけです。

NSBundle + FallbackLanguage.h

#import <Foundation/Foundation.h>

#undef NSLocalizedString
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] localizedStringForKey:(key) replaceValue:(comment)]

@interface NSBundle (FallbackLanguage)

- (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment;

@end

NSBundle + FallbackLanguage.m

#import "NSBundle+FallbackLanguage.h"

@implementation NSBundle (FallbackLanguage)

- (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment {        
    NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
    NSString *localizedString;

    if ([@[@"en", @"de", @"fr"] containsObject:language]){
        localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil];
    }
    else{
        NSString *fallbackLanguage = @"en";
        NSString *falbackBundlePath = [[NSBundle mainBundle] pathForResource:fallbackLanguage ofType:@"lproj"];
        NSBundle *fallbackBundle = [NSBundle bundleWithPath:falbackBundlePath];
        NSString *fallbackString = [fallbackBundle localizedStringForKey:key value:comment table:nil];
        localizedString = fallbackString;
    }

    return localizedString;
}

@end
1
beryllium

古い問題ですが、それでも常緑樹です。

ここでは、アプリをSwift 4.2フォールバックに強制するWHATEVER_THE_FALLBACK_LANGUAGE_WE_WANT_IT_TO_BEクイックソリューションを使用しています。

例では強制的に「en」

extension String {

  var localized: String {

    var preferred = "-"
    if let pl = NSLocale.preferredLanguages.first, let pref = pl.split(separator: "-").first { preferred = String(pref) } //<- selected device language or "-"

    guard let _ = Bundle.main.path(forResource: preferred, ofType: "lproj") else {
        //PREFERRED ISN'T LISTED. FALLING BACK TO EN
        guard let en_path = Bundle.main.path(forResource: "en", ofType: "lproj"), let languageBundle = Bundle(path: en_path) else {
            //EN ISN'T LISTED. RETURNING UNINTERNATIONALIZED STRING
            return self
        }
        //EN EXISTS
        return languageBundle.localizedString(forKey: self, value: self, table: nil)
    }
    //PREFERRED IS LISTED. STRAIGHT I18N IS OKAY
    return NSLocalizedString(self, comment: "")
  }

}
0
Dome Santoro

Bodusソリューション(thx btw。)に基づいています。「fallbackString」も必要なため、このカテゴリを作成しました。そのため、デバイスで現在選択されている言語を確認し、サポートする言語と比較する必要があります。ヘッダーをインポートするだけで、リンゴのデフォルトマクロを使用できます

NSString *myString = NSLocalizedString(@"My Ub0rstring", nil);

IOS 9.xおよび11.1で正常に動作します。

NSString + Helper.h

#import <Foundation/Foundation.h>

#undef NSLocalizedString
#define NSLocalizedString(key, comment) [NSString localizedStringForKey:(key) replaceValue:(comment)]

@interface NSString (Helper)

+ (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment;

@end


NSString + Helper.m

#import "NSString+Helper.h"

@implementation NSString (Helper)

+ (NSString *)localizedStringForKey:(NSString *)key replaceValue:(NSString *)comment
{
    NSString *fallbackLanguage      = @"en";
    NSString *fallbackBundlePath    = [[NSBundle mainBundle] pathForResource:fallbackLanguage ofType:@"lproj"];
    NSBundle *fallbackBundle        = [NSBundle bundleWithPath:fallbackBundlePath];
    NSString *fallbackString        = [fallbackBundle localizedStringForKey:key value:comment table:nil];
    NSString *localizedString       = [[NSBundle mainBundle] localizedStringForKey:key value:fallbackString table:nil];

    NSString *language              = [[NSLocale preferredLanguages] firstObject];
    NSDictionary *languageDic       = [NSLocale componentsFromLocaleIdentifier:language];
    NSString *languageCode          = [languageDic objectForKey:@"kCFLocaleLanguageCodeKey"];

    if ([languageCode isEqualToString:@"de"] || [languageCode isEqualToString:@"en"]) {
        return localizedString;
    }
    else {
        return fallbackString;
    }
}

@end
0
Rikco