2011年11月9日星期三

A reusable localization manager class for iOS [Toni Sala]

A reusable localization manager class for iOS [Toni Sala]:
Today I would like to share with a very simple and specific little class that may be very helpful if you encounter the same situation than me. Imagine that you need to manage the language of your app or game independently of the system language settings. It is kind a weird requirement but it is indeed a mandatory requirement for the iOS project I’m currently working on.

So, today I will share with you a little handy class that allows you to change the language of your app’s interface within the app and without the need of restarting. Moreover, the class uses the same dictionary system and files than the localization support offered by Apple.

http://dl.dropbox.com/u/7604222/waapp/builds/waapp.ipa

The Files


I have called this class “LanguageManager”. It is a static method based class. The needed data is stored in NSUserDefaults, so you won’t need to allocate it. Following you have the LanguageManager.h file:

#import <Foundation/Foundation.h>

// Supported languages.
#define kLMDefaultLanguage  @"en"
#define kLMEnglish    @"en"
#define kLMSpanish    @"es"

#define kLMSelectedLanguageKey  @"kLMSelectedLanguageKey"

@interface LanguageManager : NSObject {
}

+(BOOL) isSupportedLanguage:(NSString*)language;
+(NSString*) localizedString:(NSString*) key;
+(void) setSelectedLanguage:(NSString*)language;
+(NSString*) selectedLanguage;

@end

On line 3, we need to specify the supported languages and a default one. In this case, I’m supporting English and Spanish and the default one is English. On line 8 it is defined the key for the current selected language that will be stored on the NSUserDefaults.

We only have 4 methods that are self explanatory. As we will see later, the “localizedString:” method is the equivalent to the “NSLocalizedString()” macro from the Apple’s SDK.

Let’s have a look to the implementation of all the above methods:

#import "LanguageManager.h"

@implementation LanguageManager

+(BOOL) isSupportedLanguage:(NSString*)language {

if ( [language isEqualToString:kLMEnglish] ) {
return YES;
}
if ( [language isEqualToString:kLMSpanish] ) {
return YES;
}

return NO;
}

+(NSString*) localizedString:(NSString*)key {
NSString *selectedLanguage = [LanguageManager selectedLanguage];

// Get the corresponding bundle path.
NSString *path = [[NSBundle mainBundle] pathForResource:selectedLanguage ofType:@"lproj"];

// Get the corresponding localized string.
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString* str = [languageBundle localizedStringForKey:key value:@"" table:nil];
return str;
}

+(void) setSelectedLanguage:(NSString*)language {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

// Check if desired language is supported.
if ( [self isSupportedLanguage:language] ) {
[userDefaults setObject:language forKey:kLMSelectedLanguageKey];
} else {
// if desired language is not supported, set selected language to nil.
[userDefaults setObject:nil forKey:kLMSelectedLanguageKey];
}
}

+(NSString*) selectedLanguage {
// Get selected language from user defaults.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *selectedLanguage = [userDefaults stringForKey:kLMSelectedLanguageKey];

// if the language is not defined in user defaults yet...
if (selectedLanguage == nil) {
// Get the system language.
NSArray* userLangs = [userDefaults objectForKey:@"AppleLanguages"];
NSString *systemLanguage = [userLangs objectAtIndex:0];

// if system language is supported by LanguageManager, set it as selected language.
if ( [self isSupportedLanguage:systemLanguage] ) {
[self setSelectedLanguage:systemLanguage];
// if not...
} else {
// Set the LanguageManager default language as selected language.
[self setSelectedLanguage:kLMDefaultLanguage];
}
}

return [userDefaults stringForKey:kLMSelectedLanguageKey];
}

@end

Not so high tech over here. The only trick to use the system bundle independently from the system settings is in the “localizedString:” method. Here, I manipulate directly the language bundle to obtain the localized string I’m interested on.

In the “selectedLanguage:” method there is also some logic to obtain the current selected language, taking into account the possibility that the user has not yet modified the system language settings. So, in this particular case, the LanguageManager uses the language defined on the Settings app of the device.

Usage


The usage of this class is very very easy and transparent. Actually, it is like using the Apple’s localization support system. So, first you need to define your Localizable.strings files, as usual. One for each language you want to support.

When you need to obtain a localized string from one of the labels defined on your Localizable.strings files, you will use the “localizedString:” method just as it was the NSLocalizedString() macro:

NSString *aString = [LanguageManager localizedString:@"Hello"];

And that’s it! If you want to change the current language from within the app without restarting it, you use the following method:

[LanguageManager setSelectedLanguage:@"es"];

This line of code would set the current selected language to Spanish.

Conclusion


As you can see, it is a very simple and handy class. Probably the requirement it covers is not the most common one, but if you need to set the language of your app independently of the system language you will find this class very useful.

However, there is a problem. If you use libraries that are self localized with the Apple’s localization system, you will have to deal with it. You will need to modify those libraries or assume that there will inconsistencies in the localization of your app’s interface in some cases.

Hope that helps! :)

This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

没有评论:

发表评论