iOS App Bundle中的多个本地化.strings文件

我有一个相当复杂的项目,由几个大型本地化子项目组成。

我的大部分子项目都是通过一个Localizable.strings文件本地化的 。 该文件被复制到一个SubProjectName.bundle目标中,该目标与主项目中的一个SubProjectName.a静态库一起使用。 这工作正常。

但是,我的一个子项目包含许多本地化的.strings文件。 无论设备(或模拟器)如何configuration, 该项目都无法读取除英语以外的任何语言的string

例如,这行代码总是返回英文string:

 [[NSBundle myResourcesBundle] localizedStringForKey:@"MY_TEST_STRING" value:@"" table:@"MyTable"] 

其中MyTable对应于本地化为多种语言的MyTable.strings文件。 当我浏览.app包时,所有的本地化都在那里,坐在应用程序中的“MyBundle.bundle”资源中。

但是,以下代码正确地查找了所有本地化中给定string的翻译:

 for (NSString *language in [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"]) { NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle myResourcesBundle] pathForResource:language ofType:@"lproj"]]; NSLog(@"%@: %@", language, NSLocalizedStringFromTableInBundle(@"MY_TEST_STRING", @"MyTable", bundle, nil)); } 

所以,当这个包是实际的MyBundle.bundle/<LanguageCode>.lproj文件夹时,string查找工作。 但是显然,这打破了iOS提供的自动查找的目的。

(请注意,上面的[NSBundle myResourcesBundle]只是一个静态方便的方法来获取我的自定义的子项目的包)。

编辑 :我一直在试验这一些,如果我从我的子项目的捆绑删除en.lproj文件夹,然后它正确地使用设备或模拟器的区域设置。

例如,我有:

 MyApp.app/ | - MyResources.bundle/ | - en.lproj/ | - zh-Hans.lproj/ 

当我将模拟器(或设备)设置为简体中文时,即使语言环境是zh-Hans也会在en.lproj查找string 。 如果我删除了en.lproj文件夹,并重新启动应用程序,它正确使用zh-Hans本地化。

我能够重现和解决这个问题,虽然解决scheme确实意味着在NSBundle中存在一个错误。

我使用下面的包结构重现它:

 MyApp.app/ | - MyResources.bundle/ | - en.lproj/ | - fr.lproj/ 

和代码:

  NSLog(@"A key: %@", NSLocalizedString(@"A key", nil)); NSBundle *bundle = [NSBundle bundleWithPath: [[NSBundle mainBundle] pathForResource: @"MyResources" ofType: @"bundle"]]; NSLog(@"Current locale: %@", [[NSLocale currentLocale] localeIdentifier]); NSLog(@"Bundle localizations: %@", [bundle localizations]); NSLog(@"Key from bundle: %@", [bundle localizedStringForKey: @"A key" value: @"Can't find it." table: nil]); NSLog(@"Key using bundle macro: %@", NSLocalizedStringFromTableInBundle(@"A key", nil, bundle, nil)); 

将区域设置设置为fr_FR(即法语),捆绑包从英文string表中选取string – 即使string“找不到”也不会出现。

在不更改代码的情况下,我能够使用以下结构来获取法文string:

 MyApp.app/ | - MyResources.bundle/ | - Resources/ | - en.lproj/ | - fr.lproj/ 

它看起来像NSBundle仍然期望旧的Mac OS X捆绑结构,而不是iOS应该使用的。 所以一个简单的束结构变化应该可以解决这个问题。

加上大卫·多伊尔所说的话。

确保在包和应用程序本身中的项目的信息部分中设置可用的语言。 例如,如果您在应用程序中支持法语和英语,请确保您的应用程序包和您的应用程序在您的项目的可用本地化中定义了法语和英语语言。

我现在有一个hacky解决scheme,但将不胜感激,如果有人有一个更好的答案(或解释为什么上述不起作用)。

我扩展了我的NSBundle类别,以包含一个首选的语言资源:

 @interface NSBundle (MyBundle) + (NSBundle*) myResourcesBundle; + (NSBundle*) myPreferredLanguageResourcesBundle; @end 

履行

 @implementation NSBundle (MyBundle) + (NSBundle*) myResourcesBundle { static dispatch_once_t onceToken; static NSBundle *myLibraryResourcesBundle = nil; dispatch_once(&onceToken, ^ { myLibraryResourcesBundle = [NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"MyResources" withExtension:@"bundle"]]; }); return myLibraryResourcesBundle; } + (NSBundle*) myPreferredLanguageResourcesBundle { static dispatch_once_t onceToken; static NSBundle *myLanguageResourcesBundle = nil; dispatch_once(&onceToken, ^ { NSString *language = [[[NSBundle myResourcesBundle] preferredLocalizations] firstObject]; myLanguageResourcesBundle = [NSBundle bundleWithPath:[[NSBundle myResourcesBundle] pathForResource:language ofType:@"lproj"]]; if( myLanguageResourcesBundle == nil ) { myLanguageResourcesBundle = [NSBundle myResourcesBundle]; } }); return myLanguageResourcesBundle; } @end 

然后我有一个简单的macros来获取我的本地化的string:

 #define MyLocalizedDocumentation(key, comment, chapter) \ NSLocalizedStringFromTableInBundle((key),(chapter),[NSBundle myPreferredLanguageResourcesBundle],(comment)) 

这个解决scheme只是从NSLocale获取首选的语言代码,然后检查是否存在该语言的包。 如果没有,它会回落到主资源包(也许它应该遍历NSLocale preferredLanguage指数来检查一个包是否存在?有人知道吗?)

不清楚你的问题,但我使用这个macros来使用多个本地化的string文件:

 #define CustomLocalizedString(key, comment) \ [[[NSBundle mainBundle] localizedStringForKey:(key) value:nil table:nil] isEqualToString:(key)] ? \ [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:@"MyTable"] : \ [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil] 

或者你可以尝试

 [[NSBundle mainBundle] localizedStringForKey:(key) value:[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:@"MyTable"] table:nil] 

这将首先检查Localizable.strings ,如果该键不存在,它将返回键本身,然后检查并使用MyTable.strings 。 当然,你最好用一个前缀命名你的密钥。 例如"KYName" = "Name";

如果这是你想要的,随时检查我以前问过的这个问题。 ;)

我有另一个解决scheme。

 #define localizedString(key) [NSLocalizedString(key, nil) isEqualToString:key] ? \ [[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"]] localizedStringForKey:key value:@"" table:nil] : \ NSLocalizedString(key, nil) 

所以例如,如果我们要find一个关键“标题”=“经理”; 在Localizable.strings(fr)中,如果没有,那么关键“标题”的结果将与关键字相同。

在这种情况下,我们可以在localizable.string(en)中find关键字“title”,但是如果可以在(fr)中find,我们可以使用它。