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

时间:2021-08-21 12:42:22

Is there a way to set a default language to be used when the device UI language is not supported by an app?

是否有一种方法可以设置当应用程序不支持设备UI语言时使用的默认语言?

Example: My app is localized into English and German:

我的应用程序本地化为英语和德语:

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

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

Now, if I run the app on a device with UI language set to Italian the app will use the key strings POWER_TO_THE_PEOPLE_BTN and POWER_PLUG_BTN.

现在,如果我在一个设备上运行这个应用程序,它的UI语言设置为意大利语,应用程序将使用关键字符串POWER_TO_THE_PEOPLE_BTN和POWER_PLUG_BTN。

There must be a way to specify a default (fallback) language to be used by the application in such a case.

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

From the above example it should be clear that using the English string as a key will not work.

从上面的示例中可以清楚地看到,使用英语字符串作为键将不起作用。

The only option I see right now is to use NSLocalizedStringWithDefaultValue instead of NSLocalizedString.

我现在看到的唯一选项是使用NSLocalizedStringWithDefaultValue而不是NSLocalizedString。

8 个解决方案

#1


13  

Perhaps this should help? -- iPhone: localization / internationalization default strings file

也许这应该帮助吗?——iPhone:本地化/国际化默认字符串文件

It should fallback to English by default. I've just switched my phone to a language into which my app is not localized, and the text was all in English, as expected.

在默认情况下,它应该回退到英语。我刚刚把手机换成了一种语言,我的应用程序没有本地化,文字都是英文的,这是意料之中的。

Important: as @hyperspasm commented : To expand on/rephrase this, the fallback language is the language which was most recently chosen by the user in the device Settings, that is also represented in the app's bundle.

重要提示:正如@hyperspasm评论的那样:要扩展/重述这个,回退语言是用户最近在设备设置中选择的语言,在应用程序的包中也有表示。

#2


18  

To avoid all those lengthy syntax and more having more descriptive var name for translators, I derived my own helper method L() for translation and falling back to English

为了避免所有这些冗长的语法,以及为翻译人员提供更多描述性的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;
}

My Localizable.strings would look like this

我的定位。弦是这样的

"SOME_ACTION_BUTTON" = "Do action";

So in my code, i would use L(@"SOME_ACTION_BUTTON") to get the correct string

在我的代码中,我将使用L(@"SOME_ACTION_BUTTON")来获得正确的字符串

Though sometime the key is longer than the translation itself HELP_BUTTON_IN_NAV_BAR = 'Help' but it saves me a lot of time explaining what it is to whoever is helping me doing the translation

虽然有时键比翻译本身要长,但它为帮助我翻译的人节省了很多时间

#3


15  

You need to make sure that the value of CFBundleDevelopmentRegion in your Info.plist is the language region that you would like to fallback to. (e.g. "en")

您需要确保在您的信息中包含CFBundleDevelopmentRegion的值。plist是您希望退回到的语言区域。(如。“en”)

#4


2  

My solution thanks to https://*.com/a/25928309/3664461

我的解决方案要感谢https://*.com/a/25928309/3664461

Global.h

Global.h

NSString * LString(NSString * translation_key);

Global.m

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

Usage:

用法:

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

This solution doesn't take the users preference order into consideration. Instead, it will always fallback to what you have under Base if the users first language is not localized. Also if a specific key is not localized for the current language, but it exists in the base localication, you will get the base localization.

此解决方案不考虑用户优先顺序。相反,如果用户的第一语言不是本地化的,那么它将始终返回到您在Base中的内容。另外,如果一个特定的键没有为当前语言本地化,但是它存在于base localication中,您将获得基本本地化。

Update:

更新:

Since iOS 9, region is included in the language locales. I updated the code to handle that.

自从ios9以来,区域就包含在语言环境中。我更新了代码来处理它。

#5


2  

A fast way to do this without replacing any methods is "overriding" the NSLocalizedString define and using the methods that Apple uses for this define to replace it and add the additional fallback logic in the "overridden" method.

不替换任何方法的快速方法是“覆盖”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;
}

#6


1  

I've created category NSBundle+FallbackLanguage to support fallback language, you can check it out on the github folder. You only need to specify the array of supported languages in the implementation.

我已经创建了类别NSBundle+FallbackLanguage来支持回退语言,您可以在github文件夹上查看它。您只需要在实现中指定受支持的语言的数组。

NSBundle+FallbackLanguage.h

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

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


1  

@Bogus answer in Swift 4, works like a charm on iOS 11.1:

@ fake answer in Swift 4,就像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)
}

#8


0  

Based on Bodus solution (thx btw.) I created this category because you need the "fallbackString" too. So I have to check the current selected language of the device and compare it with my languages I want to support. Just import the header and you can use apples default macro

基于Bodus解决方案(thx btw)我创建了这个类别,因为您也需要“fallbackString”。因此,我必须检查设备当前选择的语言,并将其与我想支持的语言进行比较。只要导入header,就可以使用苹果默认宏

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

Works fine on iOS 9.x and 11.1.

适用于iOS 9。11.1 x和。

NSString+Helper.h

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

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

#1


13  

Perhaps this should help? -- iPhone: localization / internationalization default strings file

也许这应该帮助吗?——iPhone:本地化/国际化默认字符串文件

It should fallback to English by default. I've just switched my phone to a language into which my app is not localized, and the text was all in English, as expected.

在默认情况下,它应该回退到英语。我刚刚把手机换成了一种语言,我的应用程序没有本地化,文字都是英文的,这是意料之中的。

Important: as @hyperspasm commented : To expand on/rephrase this, the fallback language is the language which was most recently chosen by the user in the device Settings, that is also represented in the app's bundle.

重要提示:正如@hyperspasm评论的那样:要扩展/重述这个,回退语言是用户最近在设备设置中选择的语言,在应用程序的包中也有表示。

#2


18  

To avoid all those lengthy syntax and more having more descriptive var name for translators, I derived my own helper method L() for translation and falling back to English

为了避免所有这些冗长的语法,以及为翻译人员提供更多描述性的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;
}

My Localizable.strings would look like this

我的定位。弦是这样的

"SOME_ACTION_BUTTON" = "Do action";

So in my code, i would use L(@"SOME_ACTION_BUTTON") to get the correct string

在我的代码中,我将使用L(@"SOME_ACTION_BUTTON")来获得正确的字符串

Though sometime the key is longer than the translation itself HELP_BUTTON_IN_NAV_BAR = 'Help' but it saves me a lot of time explaining what it is to whoever is helping me doing the translation

虽然有时键比翻译本身要长,但它为帮助我翻译的人节省了很多时间

#3


15  

You need to make sure that the value of CFBundleDevelopmentRegion in your Info.plist is the language region that you would like to fallback to. (e.g. "en")

您需要确保在您的信息中包含CFBundleDevelopmentRegion的值。plist是您希望退回到的语言区域。(如。“en”)

#4


2  

My solution thanks to https://*.com/a/25928309/3664461

我的解决方案要感谢https://*.com/a/25928309/3664461

Global.h

Global.h

NSString * LString(NSString * translation_key);

Global.m

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

Usage:

用法:

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

This solution doesn't take the users preference order into consideration. Instead, it will always fallback to what you have under Base if the users first language is not localized. Also if a specific key is not localized for the current language, but it exists in the base localication, you will get the base localization.

此解决方案不考虑用户优先顺序。相反,如果用户的第一语言不是本地化的,那么它将始终返回到您在Base中的内容。另外,如果一个特定的键没有为当前语言本地化,但是它存在于base localication中,您将获得基本本地化。

Update:

更新:

Since iOS 9, region is included in the language locales. I updated the code to handle that.

自从ios9以来,区域就包含在语言环境中。我更新了代码来处理它。

#5


2  

A fast way to do this without replacing any methods is "overriding" the NSLocalizedString define and using the methods that Apple uses for this define to replace it and add the additional fallback logic in the "overridden" method.

不替换任何方法的快速方法是“覆盖”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;
}

#6


1  

I've created category NSBundle+FallbackLanguage to support fallback language, you can check it out on the github folder. You only need to specify the array of supported languages in the implementation.

我已经创建了类别NSBundle+FallbackLanguage来支持回退语言,您可以在github文件夹上查看它。您只需要在实现中指定受支持的语言的数组。

NSBundle+FallbackLanguage.h

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

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


1  

@Bogus answer in Swift 4, works like a charm on iOS 11.1:

@ fake answer in Swift 4,就像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)
}

#8


0  

Based on Bodus solution (thx btw.) I created this category because you need the "fallbackString" too. So I have to check the current selected language of the device and compare it with my languages I want to support. Just import the header and you can use apples default macro

基于Bodus解决方案(thx btw)我创建了这个类别,因为您也需要“fallbackString”。因此,我必须检查设备当前选择的语言,并将其与我想支持的语言进行比较。只要导入header,就可以使用苹果默认宏

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

Works fine on iOS 9.x and 11.1.

适用于iOS 9。11.1 x和。

NSString+Helper.h

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

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