9

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

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

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

例如,这行代码总是返回英文字符串:

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

因此,当捆绑包是实际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 本地化。

4

5 回答 5

14

我能够重现并修复该问题,尽管该解决方案确实暗示 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 应该使用的结构。所以一个简单的bundle结构改变应该可以解决这个问题......

于 2012-12-13T14:44:20.360 回答
10

补充一下大卫·多伊尔所说的话。

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

于 2013-01-04T03:06:18.270 回答
8

我现在对此有一个 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 首选语言索引以检查包是否存在?有人知道吗?)

于 2012-12-09T07:21:48.193 回答
3

不清楚你的问题,但我使用这个宏来使用多个本地化字符串文件:

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

如果这是您想要的,请随时查看我之前提出的这个问题。;)

于 2012-12-12T06:31:18.613 回答
1

我有另一个解决方案。

#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" = "Manager"; 在 Localizable.strings (fr) 中,如果不存在,则键“title”的结果将与键相同。

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

于 2015-11-20T00:43:29.430 回答