Smartling / ios-i18n

The ios-i18n library provides seamless integration of plurals into iOS 6 apps.
http://www.smartling.com
Apache License 2.0
205 stars 36 forks source link

cachedLocales issue #14

Closed weibel closed 10 years ago

weibel commented 10 years ago

For Cocoapod v. 1.0.5 cahcedLocales seems to have different behaviour between iOS6 and 7.

Method is:

- (NSArray *)cachedLocales
{
    static const NSString *kSLBundleCachedLocales = @"kSLBundleCachedLocales";
    NSMutableArray *locales = objc_getAssociatedObject(self, (__bridge const void *)(kSLBundleCachedLocales));
    if (!locales) {
        locales = [NSMutableArray arrayWithArray:self.preferredLocalizations];
        if (self.developmentLocalization && ![[locales lastObject] isEqualToString:self.developmentLocalization]) {
            [locales addObject:self.developmentLocalization];
        }
        objc_setAssociatedObject(self, (__bridge const void *)(kSLBundleCachedLocales), locales, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return locales;
}

In

NSMutableArray *locales = objc_getAssociatedObject(self, (__bridge const void *)(kSLBundleCachedLocales)); 

locales can sometimes be nil in iOS7 and an initialized but otherwise empty dictionary in iOS6. iOS7 behavior seems to be correct.

paiv commented 10 years ago

Hi @weibel , thank you for reporting this, but I could not reproduce it. Can you provide a simple project code that have this issue, so it could be reliably reproduced?

weibel commented 10 years ago

We're using an instance of NSBundle (not main bundle) and for some reason self.preferredLocalizations is coming back nil on iOS6 .

The bundle is instantiated like this

    NSString* path =
        [[NSBundle mainBundle] pathForResource:language
                                        ofType:@"lproj"];
    _bundle = [NSBundle bundleWithPath:path];
weibel commented 10 years ago

I have shared a sample project with you

weibel commented 10 years ago

It seems like the easiest fix to avoid this is to set kSLBundleCachedLocales right after initialization of the NSBundle

    NSString* path =  [[NSBundle mainBundle] pathForResource:language ofType:@"lproj"];
    _bundle = [NSBundle bundleWithPath:path];
    // If on iOS 6, set preferredLanguages to avoid bug
    if ([[[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."].firstObject integerValue] < 7) {
        objc_setAssociatedObject(_bundle, (__bridge const void *)(@"kSLBundleCachedLocales"), [NSLocale preferredLanguages], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
paiv commented 10 years ago

@weibel , when bundle is loaded from lproj, we have no info about its locale. Bundle preferredLocalizations has no meaning in this case. Your patch is working for you since you only have two localizations that happens to have the same pluralization rules (one, other). If you add Slavic or Arabic localization, it would not work.

paiv commented 10 years ago

I've added another pluralizedStringWithKey with additional parameter forLocalization. Call this method instead, and pass the language value that you used to load lproj bundle with.

- (NSString *)pluralizedStringWithKey:(NSString *)key
                         defaultValue:(NSString *)defaultValue
                                table:(NSString *)tableName
                          pluralValue:(float)pluralValue
                      forLocalization:(NSString *)locale NS_FORMAT_ARGUMENT(1);
weibel commented 10 years ago

OK, thx. I'll let you know how it goes.