Nat! bio photo

Nat!

Senior Mull

Twitter Github Twitch

Localizing library code, the right way ?

Lets say I have a method that needs to emit a localized string:

- (NSString *) errorMessage
{
   return( NSLocalizedString( @"system failure", @"your system has failed somehow"));
}

I would put “system failure” = “Das System ist kaputt”; in a unicode file de.lproj/Localizable.stringsand it will just work. Maybe.

What does the app say ?

If you are an app and link against the library, you put Localizable.strings into your Resources folder and it works.

What does the framework say ?

When you put the strings file into the Resources folder of the framework, it doesn’t work, because NSLocalizedString uses [NSBundle mainBundle] to locate the translation table.

You will have to use NSLocalizedStringWithDefaultValue with your framework bundle as the search bundle. You get the framework bundle by calling something like [NSBundle bundleWithIdentifier:@"com.foo.framework.whatever"].

It’s tempting to use [NSBundle bundleWithClass:[self class]] throughout, but this will fail in categories.

Unfortunately this ties the code to being in a framework (with that particular identifier).

A somewhat better solution

A generally better solution is to use the mainBundle as a fallback, if the lookup in the framework fails. This also allows an app to supplement new languages, if they do not exist in the framework.

NSString   *_MulleLocalizedFrameworkString( NSString *key, NSString * framework)
{
   NSBundle   *bundle;
   
   bundle = [NSBundle bundleWithIdentifier:framework];
   return( [bundle localizedStringForKey:key
                                   value:nil
                                   table:nil]);
}


NSString   *MulleLocalizedFrameworkString( NSString *key, NSString *comment, NSString *framework)
{
   NSBundle   *bundle;
   NSString   *s;

   s = _MulleLocalizedFrameworkString( key, framework);

   if( ! s)
   {
      bundle = [NSBundle mainBundle];
      s      = [bundle localizedStringForKey:key
                                       value:nil
                                       table:nil];
   }
   return( s ? s : key);
}

It may become a little unwieldy to always specify the framework identifier, but that can be fixed with another small function, that you would specify in a private header of each Framework:

static inline NSString   *MyFrameworkLocalizedString( NSString *a, NSString *b)
{
    return( MulleLocalizedFrameworkString( a, b, "com.foo.framework.my"));
}

TODO

Adapt mulle-genstrings to use user-supplied localization function names.


Post a comment

All comments are held for moderation; basic HTML formatting accepted.

Name:
E-mail: (not published)
Website: