Localizing iPhone Apps – Part 1

It is very important to localize your iPhone applications, since the app can be used in more then 70 countries. Users want to see information, which is formatted according to their native country or region.

Introduction
A Locale is not a language, it is a representation of data like the currency, units, decimal separator or date and time format. A Locale’s identifier is represented as languagecode_regioncode_variant. The naming convention is defined by ICU (International Components for Unicode). The variant is not required and the locale identifier looks like “en_US” for english in USA and “en_GB” for english in Great Britain”. A user can set his/her locale in the iPhone by going to Settings -> General -> International -> Region Format. In this tutorial, we will look at how to display data (like currency, date and time…) in the user’s set region or country.

Formatters
We generally work with the user’s current locale object, instead of working with a specific locale. The locale object is used with some other objects, usually formatters. With Cocca, we have NSNumberFormatter and NSDateFormatter. The classes is locale sensitive, which means when you create an instance it uses the user’s current locale, which makes it very easy to work with. NSLocale is a class, which we use to get the user’s locale or to create new ones.

To get the current locale, the code would look something like this

NSLocale *currentUsersLocale = [NSLocale currentLocale];
NSLog(@"Current Locale: %@", [currentUsersLocale localeIdentifier]);

//Output
Current Locale: en_US

We get the current locale by passing currentLocale message to the class and we get the locale identifier(string representation) by passing localeIdentifier message. The output will be en_US if the region is set to United States.

Working with NSNumberFormatter
The code is very easy and it does not take a long time to learn eveything about formatters, we just create new one’s and set some properties and use it with the NSNumber class. Below is some code with some sample numbers and different formatters, where the output is displayed on the debugger console.

//Get the current user locale.
NSLocale *currentLocale = [NSLocale currentLocale];
NSLog(@"Current Locale: %@", [currentLocale localeIdentifier]);

NSLog(@"Test numbers: 4.0, 0.4, 4.6, -64");

NSNumber *number40 = [NSNumber numberWithFloat:4.0];
NSNumber *number04 = [NSNumber numberWithFloat:0.4];
NSNumber *number46 = [NSNumber numberWithFloat:4.6];
NSNumber *number64 = [NSNumber numberWithInt:-64];

//Working with number 4.0 and representing as No Style
NSNumberFormatter *noStyleFormatter = [[NSNumberFormatter alloc] init];
[noStyleFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[noStyleFormatter setNumberStyle:NSNumberFormatterNoStyle];

//Decimal Style
NSNumberFormatter *decimalStyle = [[NSNumberFormatter alloc] init];
[decimalStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[decimalStyle setNumberStyle:NSNumberFormatterDecimalStyle];
[decimalStyle setRoundingMode:NSNumberFormatterRoundFloor];
[decimalStyle setRoundingIncrement:[NSNumber numberWithInt:1]];

//Currency Style
NSNumberFormatter *currencyStyle = [[NSNumberFormatter alloc] init];
[currencyStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyStyle setNumberStyle:NSNumberFormatterCurrencyStyle];

//Percent Style
NSNumberFormatter *percentStyle = [[NSNumberFormatter alloc] init];
[percentStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[percentStyle setNumberStyle:NSNumberFormatterPercentStyle];

//Scientific Style
NSNumberFormatter *scientificStyle = [[NSNumberFormatter alloc] init];
[scientificStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[scientificStyle setNumberStyle:NSNumberFormatterScientificStyle];

//Spell Out Style
NSNumberFormatter *spellOutStyle = [[NSNumberFormatter alloc] init];
[spellOutStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[spellOutStyle setNumberStyle:NSNumberFormatterSpellOutStyle];

NSLog(@"Locale of noStyle formatter: %@", [[noStyleFormatter locale] localeIdentifier]);
NSLog(@"Locale of decimal style formatter: %@", [[decimalStyle locale] localeIdentifier]);
NSLog(@"Locale of currency style formatter: %@", [[currencyStyle locale] localeIdentifier]);
NSLog(@"Locale of percent style formatter: %@", [[percentStyle locale] localeIdentifier]);
NSLog(@"Locale of scientific style formatter: %@", [[scientificStyle locale] localeIdentifier]);
NSLog(@"Locale of spell-out style formatter: %@", [[spellOutStyle locale] localeIdentifier]);
NSLog(@"---------------------------------------");

//Display Results
NSLog(@"Different formatting results for NSNumber 4.0 with Locale: %@", [currentLocale localeIdentifier]);
NSLog(@"---------------------------------------");
NSLog(@"Formatting 4.0 with No Style: %@", [noStyleFormatter stringFromNumber:number40]);
NSLog(@"Formatting 4.0 with Decimal Style: %@", [decimalStyle stringFromNumber:number40]);
NSLog(@"Formatting 4.0 with Currency Style: %@", [currencyStyle stringFromNumber:number40]);
NSLog(@"Formatting 4.0 with Percent Style: %@", [percentStyle stringFromNumber:number40]);
NSLog(@"Formatting 4.0 with Scientific Style: %@", [scientificStyle stringFromNumber:number40]);
NSLog(@"Formatting 4.0 with Spell Out Style: %@", [spellOutStyle stringFromNumber:number40]);
NSLog(@"---------------------------------------");

NSLog(@"Different formatting results for NSNumber 0.4 with Locale: %@", [currentLocale localeIdentifier]);
NSLog(@"---------------------------------------");
NSLog(@"Formatting with No Style: %@", [noStyleFormatter stringFromNumber:number04]);
NSLog(@"Formatting with Decimal Style: %@", [decimalStyle stringFromNumber:number04]);
NSLog(@"Formatting with Currency Style: %@", [currencyStyle stringFromNumber:number04]);
NSLog(@"Formatting with Percent Style: %@", [percentStyle stringFromNumber:number04]);
NSLog(@"Formatting with Scientific Style: %@", [scientificStyle stringFromNumber:number04]);
NSLog(@"Formatting with Spell Out Style: %@", [spellOutStyle stringFromNumber:number04]);
NSLog(@"---------------------------------------");

NSLog(@"Different formatting results for NSNumber 4.6 with Locale: %@", [currentLocale localeIdentifier]);
NSLog(@"---------------------------------------");
NSLog(@"Formatting with No Style: %@", [noStyleFormatter stringFromNumber:number46]);
NSLog(@"Formatting with Decimal Style: %@", [decimalStyle stringFromNumber:number46]);
NSLog(@"Formatting with Currency Style: %@", [currencyStyle stringFromNumber:number46]);
NSLog(@"Formatting with Percent Style: %@", [percentStyle stringFromNumber:number46]);
NSLog(@"Formatting with Scientific Style: %@", [scientificStyle stringFromNumber:number46]);
NSLog(@"Formatting with Spell Out Style: %@", [spellOutStyle stringFromNumber:number46]);
NSLog(@"---------------------------------------");

NSLog(@"Different formatting results for NSNumber -64 with Locale: %@", [currentLocale localeIdentifier]);
NSLog(@"---------------------------------------");
NSLog(@"Formatting with No Style: %@", [noStyleFormatter stringFromNumber:number64]);
NSLog(@"Formatting with Decimal Style: %@", [decimalStyle stringFromNumber:number64]);
NSLog(@"Formatting with Currency Style: %@", [currencyStyle stringFromNumber:number64]);
NSLog(@"Formatting with Percent Style: %@", [percentStyle stringFromNumber:number64]);
NSLog(@"Formatting with Scientific Style: %@", [scientificStyle stringFromNumber:number64]);
NSLog(@"Formatting with Spell Out Style: %@", [spellOutStyle stringFromNumber:number64]);
NSLog(@"---------------------------------------");

All the code does is, create a bunch of formatters based on different styles and we see how the data looks like. The formatters behavior is set to NSNumberFormatterBehavior10_4, telling the formatter to behave since Mac OS X 10.4. We display the number by passing stringFromNumber message to the formatter. With NSNumberFormatter, you can set the currency symbol, set positive/negative symbols and it lets you do change many default settings. Click here to get a list of all the methods and properties which you can work with.

Working with NSDateFormatter
Just like NSNumberFormatter, NSDateFormatter is also locale sensitive. This is some sample code, showing how to use the NSDateFormatter

//Date Formatters.
[NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehavior10_4];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
NSDate *date = [NSDate date];

NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSLog(@"Formatted date string for locale %@: %@", [[dateFormatter locale] localeIdentifier], formattedDateString);

//Custom Date Formatter.
NSDateFormatter *customDateFormatter = [[NSDateFormatter alloc] init];

//When setting the date format, do not set the date and time format style.
//Only one of the two can be set if not, the latter setting will take precedence.
[customDateFormatter setDateFormat:@"'The time is' hh:mm 'on' EEEE MMMM d"];

NSLog(@"%@", [customDateFormatter stringFromDate:date]);

NSDateFormatter lets you do many things, set months symbol, set the time zone, set the AM/PM symbols, click here to find out all the methods and properties you can use with NSDateFormatter.

Conclusion
Always use a formatter when display currency, units and datetime so it is always displayed in the user’s current locale. I know, this article was pretty simple and the code propably does not a whole lot, but I hope it helped you a little bit.

Happy Programming,
iPhone SDK Articles


Attachments

Leave a Reply

Your email address will not be published.