Localization Tutorial for iOS

Sean Berry

This post is also available in: Chinese (Simplified), Russian

This is a guest post by Sean Berry, a developer of math apps for iPhone, iPad, and iPod Touch.

Me Gusta Localization!

Me Gusta Localization!

Although the English-speaking App Store market is the largest, there are still plenty of other iPhone users in the world and you can greatly increase their user experience by supporting their native language.

The good news is Apple has made it very easy to make your apps work with multiple languages through some API calls and built-in Xcode support. The process of doing this is called localization, and that’s what I’ll be showing you how to do!

In this localization tutorial, you will be localizing a sample app I prepared called iLikeIt which was inspired by the rage comics in Ray’s post about in-app purchases. The app is very simple – it displays some ideal sales data, and when you tap ‘You like?’ a face appears, scales up, and fades away.

But right now it’s English only – so vamos a traducir!

This localization tutorial will be using Xcode 4.6.1, so if you haven’t upgraded already, why not use this as an excuse to do so?


Getting Started

The first step is to download the iLikeIt starter project that we’ll be localizing in this iPhone app tutorial.

Build and Run the app, and you should see the following appear after you tap ‘You like?’:

iLikeIt Start

We have 3 things to localize here:

  • Text: sales data
  • UI Element: ‘You like?’ button
  • and finally the image (it has text!)

Separating text from code

Like most projects, this project has some hardcoded strings in the code. We need to pull all of these hardcoded strings into a separate file so we can localize them.

The way you do this in Xcode is create a “.strings” file to contain all of the strings your projects needs. Then you’ll replace the hardcoded strings with a function call to look up the appropriate string from the “.strings” file based on the current language.

Let’s try this out. Go to File\New\New File. Choose iOS\Resource\Strings File, and click Next, as shown in the screenshot below. Name the new file Localizable.strings, and click Save.

New strings file

Note that Localizable.strings is the default filename iOS looks for when dealing with localized text. If you don’t use this, you’ll have to specify the name of our .strings file every time.

The format for the strings file is:

"KEY" = "CONTENT";

So for our ‘Yesterday you sold %@ apps’ and ‘You like?’ text add in:

"Yesterday you sold %@ apps" = "Yesterday you sold %@ apps";
 
"You like?" = "You like?";

Now switch to ViewController.m, and find the viewDidLoad method. Right now it sets the text as:

self.numAppsLabel.text = [NSString stringWithFormat:@"Yesterday you sold %@ apps", @(1000000)];
 
[self.likeButton setTitle:@"You like?" forState:UIControlStateNormal];

We want it to instead read from our .strings file. To do that, change the current line to use a macro called NSLocalizedString as shown below:

self.numAppsLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Yesterday you sold %@ apps", nil), @(1000000)];
 
[self.likeButton setTitle:NSLocalizedString(@"You like?", nil) forState:UIControlStateNormal];

If you’re curious what the NSLocalizedString macro does, control-click on NSLocalizedString and choose Jump to Definition. You’ll find that it’s defined as follows:

#define NSLocalizedString(key, comment) \
    [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]

So basically, it’s using the localizedStringForKey method to look up the string for the given key, in the current language. It passes nil for the table name, so it uses the default strings filename (Localizable.strings). For full details, check out Apple’s NSBundle Class Reference.

One other thing to note. The macro takes a comment as a parameter, but seems to do nothing with it! This is because instead of manually typing in each key/value pair into Localizable.strings like we’ve been doing, you can use a tool that comes with the iPhone SDK called genstrings to do this automatically (which can be quite convenient for large projects).

If you use this method, you can put a comment for each string that will appear next to the default strings as an aid for the translator. For example, you could add a comment indicating the context where the string is used.

Enough background info – let’s try it out! Build and run your project, and it should say the same text on the main screen just as before. But where’s the Spanish? Now that we’re set up it’s a cinch.

Adding a Spanish Localization

To add support for another language, click on the blue iLikeIt project folder on the left pane, select the Project in the next pane (NOT the Target), and under the Info tab you’ll see a section for Localizations. Click the + and choose Spanish (es).

Add Localization 1

You’ll see another screen asking you which files you want to localize, keep them all selected and click Finish. It’s ok that you don’t see Localizable.strings yet! We’ll get to it soon.

Add Localization 2

At this point, Xcode has set up some directories containing a separate version of InfoPlist.strings and MainStoryboard.storyboard for each language you selected, behind the scenes. To see this for yourself, open your project folder in Finder, and you’ll see the following:

Add Localization 3

See en.lproj and es.lproj? They contain our language-specific versions of files.

‘en’ is the localization code for English, and ‘es’ is the localization code for Spanish. If you’re curious, here’s the full list of language codes.

When iOS wants to get the English version of a file, it will look in en.lproj, but when it wants the Spanish version of a file it will look in es.lproj.

It’s that simple! Put your resources in the appropriate folder and iOS will do the rest.

But wait, what about Localizable.strings? To let Xcode know you want it localized, select it on the left pane, and open the File Inspector in the right pane. There you will see a button labeled Localize, click it, choose English (because it’s currently in English), and finally click Localize.

Add Localization 4

Now on that right File Inspector panel it shows which languages this file belongs to, add it to the Spanish localization by checking that box to the left of Spanish.

Add Localization 5

Go back to the left panel and click on the arrow next to Localizable.strings so it shows the sub-elements. You’ll see now we’re working with two versions of this file:

Add Localization 6

To change the text for Spanish, select Localizable.strings (Spanish) and change the text to read:

"Yesterday you sold %@ apps" = "Ayer le vendió %@ aplicaciones";
 
"You like?" = "~Es bueno?~";

Your app is worldly now! Let’s make sure it worked…

To make your simulator show Spanish, go into Settings.app and choose General -> International -> Language -> Espanol.

Delete the app and select Project\Clean to get a fresh build and install. When you build and run you should see:

Spanish Text

Locale versus Language

Let’s make that number look better by adding some formatting. Replace this code:

self.numAppsLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Yesterday you sold %@ apps", nil), @(1000000)];

With this:

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
 
NSString *numberString = [numberFormatter stringFromNumber:@(1000000)];
self.numAppsLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Yesterday you sold %@ apps", nil), numberString];

Build and Run and the number will be a lot easier to read.

English Million

But here’s the thing, in Spain they don’t format their numbers like that. They write “1.000.000″ instead of “1,000,000″, but if you change the iOS simulator’s language to Espanol, you’ll still see commas used to separate the zeroes. The reason being is that number formatting is based on the region/locale, not the language. To see how someone in Spain will see that number, go into Settings -> General -> International and change Region Format to Spanish -> Spain.

Select Region

When you open up the app again this is what you should see:

Spanish Million

We got that functionality for free, just for using Apple’s NSNumberFormatter class! It pays to do things Apple’s way, don’t fight it.

Images

Since we have text in our image we need to localize it. Having some English in an otherwise Spanish app would look amateur.

Select ilike.png and add a localization for Spanish (you’re an old pro at this now!) (if you forgot, select it on the left panel, and in the File Inspector panel on the right, click the Localize button. Then after allowing Xcode to place the default copy into en.lproj, check the Spanish box on the right panel.)

Check out the project folder. ilike.png has been added to the English folder (en.lproj) and then copied to the Spanish folder (es.lproj). To make a different image show up for the Spanish version, we simply overwrite the image in the Spanish folder.

Download this image:

Me Gusta

I’ve also included it in the starting project, saved as megusta.png.

Rename it to ilike.png and move it into the Spanish folder (es.lproj), overwriting the copied English version.

Clean and rebuild and you should be done! Switch your simulator to Espanol to see…

iLikeIt Final

Congrats! That’s the bulk of localization.

Gratuitous Bonus

For a final bonus, say you want to translate the name of the app. Your Info.plist has a special file in which you can put string overrides that need to be different from language to language called InfoPlist.strings. So to make the app name different for spanish, localize Supporting Files\InfoPlist.strings and insert the following in the Spanish version:

"CFBundleDisplayName" = "Me Gusta";

That will change the name of the app as it appears on the Springboard.

…which brings up something to consider when localizing. The English version had a prefix of ‘i’ (as a nod to Apple’s naming convention).

When translated to Spanish that joke is lost. However, it was a terrible joke and the Spanish version is better for it!

Gratuitous Bonus Part 2

When you support another language in the App Store, you’ll need to provide separate screenshots in iTunes Connect for each language and for each device. For one of my apps, I’m supporting 10 languages and 3 different screenshot sizes (iPhone 3.5inch, 4inch, and iPad). 10 x 3 x 5 screenshots = 150 screenshots. You know how long that used to take me? Now I use KSScreenshotManager. You can configure it to automatically take your screenshots in the iOS Simulator. If you find yourself overwhelmed with screenshots, I highly recommend it.

Where To Go From Here?

Here is a sample project with all of the code we’ve developed in the above localization tutorial.

Now that you know the basic technique of localizing an iPhone app, try to keep it in mind when designing your next app. It could be quite easy and your non-English speaking audience will be thankful!

For the actual translation, you might be able to get away with using Google’s free translation service at http://www.google.com/translate. But I would only use that for simple words. The more professional options are the third party vendors listed at the bottom of Apple’s Internationalization and Localization page.

If you have any questions, or advice for others localizing their apps, please join in on the forum discussion below!

This is a guest post by Sean Berry, a developer of math apps for iPhone, iPad, and iPod Touch..

User Comments

91 Comments

[ 1 , 2 , 3 , 4 , 5 , 6 , 7 ]
  • So here's a potentially stupid question: why do we even need NSLocalizedString?

    If I have a strings file for the correct language, and the string in question exists in that file with a translation, why can't the OS do this when I load the app? Why doesn't it "just work"?

    Is there something critical I'm missing that implies this has to happen *during* runtime? Are people changing the strings file on the fly? I suspect not.
    Maury Markowitz
[ 1 , 2 , 3 , 4 , 5 , 6 , 7 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in May: Procedural Level Generation in Games with Kim Pedersen.

Sign Up - May

Coming up in June: WWDC Keynote - Podcasters React! with the podcasting team.

Sign Up - June

Vote For Our Next Book!

Help us choose the topic for our next book we write! (Choose up to three topics.)

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

... 55 total!

Editorial Team

... 21 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Myeong Hoon

... 38 total!

Subject Matter Experts

  • Richard Casey

... 4 total!