[英]Multiple Localized .strings Files in iOS App Bundle
我有一个相当复杂的项目,包括几个大型的本地化子项目。
我的大多数子项目都是通过一个Localizable.strings文件进行本地化的 。 此文件将复制到SubProjectName.bundle
目标中,该目标与主项目中的SubProjectName.a
静态库一起使用。 这很好用。
但是,我的一个子项目包含许多本地化的.strings文件。 无论设备(或模拟器)的配置方式如何, 此项目都无法读取除英语之外的任何语言的字符串 。
例如,这行代码始终返回英文字符串:
[[NSBundle myResourcesBundle] localizedStringForKey:@"MY_TEST_STRING" value:@"" table:@"MyTable"]
其中MyTable
对应于本地化为多种语言的MyTable.strings文件。 当我查看.app包时,所有本地化都在那里,坐在应用程序内的“MyBundle.bundle”资源中。
但是,以下代码在所有本地化中正确查找给定字符串的翻译:
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));
}
因此,当bundle是实际的MyBundle.bundle/<LanguageCode>.lproj
文件夹时,字符串查找起作用。 但显然这违背了iOS提供的自动查找的目的。
(注意,上面的[NSBundle myResourcesBundle]
只是一个静态便捷方法,用于获取子项目的自定义包)。
-
编辑 :我一直在试验这个,如果我从子项目的包中删除了en.lproj
文件夹,那么它正确地使用了设备或模拟器的语言环境。
例如,我有:
MyApp.app/
|
- MyResources.bundle/
|
- en.lproj/
|
- zh-Hans.lproj/
当我将模拟器(或设备)设置为简体中文时, 它会在en.lproj
查找字符串,即使该区域设置是zh-Hans
。 如果我删除en.lproj
文件夹并重新启动应用程序,它会正确使用zh-Hans本地化。
我能够重现并解决问题,尽管解决方案确实意味着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(即法语)时,该包从英语字符串表中选择了字符串 - 即使字符串“找不到它”也不会出现。
在不更改代码的情况下,我能够使用以下结构获取法语字符串:
MyApp.app/
|
- MyResources.bundle/
|
- Resources/
|
- en.lproj/
|
- fr.lproj/
看起来NSBundle仍然期望旧的Mac OS X捆绑结构而不是iOS应该使用的。 所以简单的束结构变化应该可以解决问题......
添加David Doyle所说的内容。
确保在捆绑包和应用程序本身的项目的信息部分中设置可用的语言。 例如,如果您在应用中支持法语和英语,请确保您的应用包和应用都具有在项目的可用本地化中定义的法语和英语语言。
我现在有一个hacky解决方案,但如果有人有更好的答案(或解释为什么上述不起作用),我将不胜感激。
我扩展了我的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
然后我有一个简单的宏来获取我的本地化字符串:
#define MyLocalizedDocumentation(key, comment, chapter) \
NSLocalizedStringFromTableInBundle((key),(chapter),[NSBundle myPreferredLanguageResourcesBundle],(comment))
此解决方案只是从NSLocale
获取首选语言代码,然后检查是否存在该语言的包。 如果没有,它将回退到主资源包(也许它应该遍历NSLocale preferredLanguage索引来检查一个包是否存在?有人知道吗?)
不清楚你的问题,但我使用这个宏来使用多个本地化的字符串文件:
#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";
。
如果这是你想要的,请随时查看我之前问过的这个问题。 ;)
我有另一种解决方案。
#define localizedString(key) [NSLocalizedString(key, nil) isEqualToString:key] ? \
[[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"]] localizedStringForKey:key value:@"" table:nil] : \
NSLocalizedString(key, nil)
所以,例如,如果我们要找到一个关键的“title”=“经理”; 在Localizable.strings(fr)中,如果不存在,那么键“title”的结果将与键相同。
在这种情况下,我们可以在localizable.string(en)中找到关键字“title”,但如果可以在(fr)中找到,我们就可以使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.