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.
I now have a hacky solution to this, but would appreciate if someone has a better answer (or explanation for why the above doesn't work).
I expanded my NSBundle category to include a preferred language resource:
Header
@interface NSBundle (MyBundle)
+ (NSBundle*) myResourcesBundle;
+ (NSBundle*) myPreferredLanguageResourcesBundle;
@end
Implementation
@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
I then have a simple macro for getting my localized strings:
#define MyLocalizedDocumentation(key, comment, chapter) \
NSLocalizedStringFromTableInBundle((key),(chapter),[NSBundle myPreferredLanguageResourcesBundle],(comment))
This solution simply gets the preferred language code from NSLocale
and then checks to see if a bundle exists for that language. If not, it falls back to the main resource bundle (perhaps it should iterate through the NSLocale preferredLanguage indices to check if a bundle exists? Does anyone know?)