Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
410 views
in Technique[技术] by (71.8m points)

localization - Multiple Localized .strings Files in iOS App Bundle

I have a fairly complicated project, consisting of several large localized sub-projects.

Most of my sub-projects are localized through a single Localizable.strings file. This file is copied into a SubProjectName.bundle target, which is used in conjunction with a SubProjectName.a static library in the main project. This works fine.

However, one of my sub-projects contains many localized .strings files. This project fails to read strings in any language other than English, regardless of how the device (or simulator) is configured.

For example, this line of code always returns the English string:

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

Where MyTable corresponds to a MyTable.strings file localized into several languages. When I peek into the .app package, all the localizations are there, sitting inside the "MyBundle.bundle" resource within the app.

The following code, however, correctly finds the translations for a given string in all localizations:

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

So when the bundle is the actual MyBundle.bundle/<LanguageCode>.lproj folder, the string lookup works. But obviously this defeats the purpose of the automatic lookup provided by iOS.

(Note that [NSBundle myResourcesBundle] above is simply a static convenience method to fetch my custom bundle for the sub-project).

--

Edit: I've been experimenting with this some more, and if I delete the en.lproj folder from my sub-project's bundle, then it correctly uses the locale of the device or simulator.

For example, I have:

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

When I set the simulator (or device) to Chinese Simplified it looks up strings in en.lproj even though the locale is zh-Hans. If I delete the en.lproj folder and restart the app it correctly uses the zh-Hans localization.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I was able to reproduce and fix the issue, though the solution does imply there's a bug in NSBundle.

I reproduced it with the following bundle structure:

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

and code:

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

With the locale set to fr_FR (i.e. French) the bundle picked the string from the English strings table - even the string "can't find it" doesn't appear.

Without changing the code, I was able to get the French string using the following structure for the bundle instead:

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

It looks like NSBundle still expects the old Mac OS X bundle structure instead of what iOS is supposed to use. So a simple change of bundle structure should solve the problem...


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...