在iOS中本地化字符串:默认(后备)语言?

时间:2010-07-16 10:22:41

标签: ios localization internationalization

当应用程序不支持设备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";

现在,如果我在界面设置为Italian的设备上运行该应用,该应用将使用关键字符串POWER_TO_THE_PEOPLE_BTNPOWER_PLUG_BTN

在这种情况下,必须有一种方法来指定应用程序使用的默认(回退)语言。

从上面的例子中可以清楚地看出,使用英文字符串作为键是行不通的。

我现在看到的唯一选择是使用NSLocalizedStringWithDefaultValue代替NSLocalizedString

9 个答案:

答案 0 :(得分:18)

为了避免所有那些冗长的语法,并为翻译人员提供更多描述性的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'更长但是它节省了我很多时间来解释对帮助我做翻译的人来说是什么

答案 1 :(得分:17)

您需要确保Info.plist中CFBundleDevelopmentRegion的值是您想要回退的语言区域。 (例如" en")

答案 2 :(得分:13)

答案 3 :(得分:2)

在不替换任何方法的情况下快速执行此操作是“覆盖”NSLocalizedString定义并使用Apple uses为此定义替换它的方法,并在“重写”方法中添加其他回退逻辑。

#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;
}

答案 4 :(得分:2)

我的解决方案归功于https://stackoverflow.com/a/25928309/3664461

Global.h

 .twoColsVerticalScroll {
    height: 100px;
    width: 400px;
    overflow-y: scroll;
    background-color: red;
    -moz-columns: 2 100px;
    -webkit-columns: 2 100px;
    columns: 2 100px;
}

Global.m

NSString * LString(NSString * translation_key);

用法:

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

此解决方案不考虑用户首选项顺序。相反,如果用户第一语言未本地化,它将始终回退到Base下的内容。 此外,如果特定键未针对当前语言进行本地化,但它存在于基本本地化中,您将获得基本本地化。

更新

自iOS 9以来,区域包含在语言区域设置中。我更新了代码以处理它。

答案 5 :(得分:2)

在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)
}

答案 6 :(得分:1)

我已创建类别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

答案 7 :(得分:0)

基于Bodus解决方案(顺便说一下),我创建了这个类别,因为你也需要“fallbackString”。所以我必须检查设备当前选择的语言,并将其与我想支持的语言进行比较。只需导入标题即可使用apple默认宏

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

答案 8 :(得分:0)

老问题,但仍然是常绿。

在这里,我们有一个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: "")
  }

}