Internationalization Tutorial for iOS [2014 Edition]

Ali Hafizji
Me Gusta Internationalization!

Me Gusta Internationalization!

Update 23 April 2014: Original post by Sean Berry, now fully updated for iOS 7 by Ali Hafizji.

Creating a great iOS app is no small feat, yet there is much more to it than great code, gorgeous design and intuitive interaction. Climbing the App Store rankings requires well-timed product marketing, the ability to scale up along with the user base, and utilizing tools and techniques to reach as wide of an audience as possible.

International markets are an afterthought for a lot of devs, but thanks to the painless global distribution provided by the App Store, any iOS dev can release their app in over 150 countries with a single click. Asia and Europe alone represent a continually growing pool of potential customers, many of whom are not native English speakers, but in order to capitalize on the global market potential of your app, you’ll need to at least be conversational in the language of app internationalization.

This tutorial will guide you through the basics concepts of internationalization by taking a simple app called iLikeIt and adding internationalization support. This simple app has a label and a You Like? button. Whenever the user taps You Like?, some optimistic sales data and accompanying image fades in below the button.

But currently, the app is English only – os vamos a traducir!

Note: Another important aspect of internationalization is using Auto Layout, due to changing text sizes. However, to keep this tutorial simple we will not be focusing on Auto Layout, as we have other tutorials for that.

Internationalization vs Localization

Before you start working your way through the tutorial, it is important to know the difference between internationalization and localization, as these concepts are often confused.

Simply put, internationalization is the process of designing your app for international compatibility. For example:

  • Handle text input, output processing in the user’s native language.
  • Handle different date, time and number formats.
  • Utilize the appropriate calendar and time zone for processing data.

Internationalization is an activity that you, the developer, perform by utilizing the system provided APIs and making additions and modifications to your code to make your app as good in Chinese or Arabic as it is in English.

By contrast, localization is merely translating the app’s user interface and resources into different languages, which is something you can and should offload to someone else, unless you happen to be fluent in every language your app will support :)

Getting Started

The first step is to download the iLikeIt starter project you will use throughout this tutorial.

Open the project in Xcode 5 and run the app on the simulator. You should see the following appear after you tap ‘You like?':

Starter product screenshot

As you can see from the screenshot, you will need to localize 4 items:

  • UI Element: ‘Hello’ label
  • UI Element: ‘You Like?’ button
  • Sales Data Text: ‘Yesterday you sold 1000000 apps’
  • Image Text: ‘I LIKE IT’

Take a moment to browse the files and folders to familiarize yourself with the project structure. Main.storyboard contains a single screen which is an instance of the ViewController class.

Separating text from code

Currently, all of the text displayed by the app exists as hard-coded strings within Main.storyboard and ViewController.m. In order to localize these strings, you need to put them into a separate file. Then, rather than hard-coding them within your methods, you will simply reference the strings using the file in your bundle.

Xcode uses files with the “.strings” file extension to store and retrieve all of the strings used within the app, for each supported language. A simple method call in your code will lookup and return the requested string based on the current language in use on the iOS device.

Let’s try this out. Go to File > New > File. Choose Strings File unders the Resource subsection as shown below:

Choose strings file

Click Next, name the file Localizable.strings, then click Save.

Note: Localizable.strings is the default filename iOS uses for localized text. Resist the urge to name the file something else, otherwise you will have to type the name of your .strings file every time you reference a localized string.

Now that you’ve created the Localizable.strings file, you need to add all of the text that is currently hardcoded into the app. You need to follow a specific, but fairly simple, format like this:

"KEY" = "CONTENT";

These key/content pairs function just like an NSDictionary, and convention is to use the default language translation of the content as the key: e.g. for “You Like?” you would write:

"You like?" = "You like?";

Key/content pairs can also contain format strings:

"Yesterday you sold %@ apps" = "Yesterday you sold %@ apps";

Now switch to ViewController.m, and find the viewDidLoad method. Currently, the app sets the text for the likeButton and salesCountLabel as shown below:

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

Instead, you will need to read in the strings from the Localizable.strings file you created earlier. Change both lines to use a macro called NSLocalizedString as shown below:

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

Macros wrap up a longer snippet of code into a more manageable size, and are created using the #define directive.
If you’re curious what the NSLocalizedString macro does, control-click on NSLocalizedString where it is defined as follows:

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

The NSLocalizedString macro uses 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.

Note: This 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 you’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 display the same text on the main screen as before, but where’s the Spanish? Now that your app is set up for localization, adding translations is 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).

Adding Spanish

The next screen asks you which files you want to localize. Keep them all selected and click Finish. Note: Localizable.strings will not show up in this list, so don’t panic!

Select files to localize

At this point, Xcode has set up some directories, behind the scenes, containing separate versions of InfoPlist.strings and Main.storyboard for each language you selected. To see this for yourself, open your project folder using Finder, and you should see the following:

New project structure

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

‘en’ is the localization code for English, and ‘es’ is the localization code for Spanish. For other languages, see the full list of language codes.

From now on, when your app wants to get the English version of a file, it will look in en.lproj, and 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 the file using 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.

Localize button

Now the File Inspector panel will show which languages this file belongs to. Currently, as you can see, the file is only localized for English. Add Spanish localization by checking that box to the left of Spanish.

Select spanish button

Go back to the left panel and click on the arrow next to Localizable.strings, so it shows the sub-elements. You now have two versions of this file: one for English and the other for Spanish:

Localization files

To change the text for Spanish, select Localizable.strings (Spanish) and replace its contents with the following:

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

Congratulations, your app is now bilingual!

To test it out and verify everything worked, change the display language on your simulator/device to Spanish by launching the Settings app and choosing:

General -> International -> Language -> Espanol.

If you are still running the Xcode debugger, click Stop in Xcode, then click Build & Run and you should see:

Spanish version

Locale vs Language

1 million is a pretty impressive sales number; let’s make it look even better by adding some formatting.

Open ViewController.m and replace the line that sets the text for _salesCountLabel with the following:

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

Build and Run the app and the number should now be a lot easier to read.

Number formatted

This looks great to an American, but in Spain 1 million is written as “1.000.000” not “1,000,000”. Run the app in Espanol and you’ll see commas used to separate the zeroes. In iOS, number formatting is based on the region/locale, not the language, so in order to see how someone in Spain will view the sales number, open Setting.app and change the locale by navigating to:

General -> International -> Region Format -> Spanish -> Spain

Spanish region format

Build and Run the app again and you should now see the properly formatted number like this:

Spain number formatting

For a little extra work up-front, NSNumberFormatter automatically formats your numbers for the appropriate region. Whenever possible, resist the urge to re-invent the wheel, because on iOS, it usually pays to do things the Apple way.

Internationalizing Storyboards

UI elements in your storyboard such as labels, buttons and images can be set in your code or directly in the storyboard. You have already learned how to support multiple languages when setting text programmatically, but the “Hello” label at the top of the screen has no IBOutlet and only has its text set within Main.storyboard.

You could add an IBOutlet, connect it to the label in Main.storyboard, then set its text property using NSLocalizedString as with the likeButton and the salesCountLabel, but there is a much easier way to localize storyboard elements, without the need for additional code.

Open the disclosure triangle to the left of Main.storyboard and you should see Main.storyboard (Base) and Main.storyboard (Spanish). Clicking on Main.storyboard (Spanish) opens the editor with the localizable text in your storyboard. You should already have an entry for the Hello label which will look something like this:

/* Class = "IBUILabel"; text = "Hello"; ObjectID = "pUp-yc-27W"; */
"pUp-yc-27W.text" = "Hello";

Replace the two occurrences of “Hello” with the Spanish translation, “Hola” like this:

/* Class = "IBUILabel"; text = "Hola"; ObjectID = "pUp-yc-27W"; */
"pUp-yc-27W.text" = "Hola";

Note: Never directly change the auto-generated ObjectID. Also, do not copy and paste the lines above, as the ObjectID for your label may be different from the one shown above.

Internationalizing Images

Since the app uses an image that contains english text, you will need to localize the image itself, as having bits and pieces of English in a mostly Spanish app not only makes your app look amateur, but also detracts from the overall usability and market potential.

To localize the image, first download this Spanish version of the image (right-click -> Save Image As… on most browsers):

Me Gusta

Open Images.xcassets and add the image to the asset catalog by dragging and dropping the newly downloaded megusta.png into the list of images on the left. Asset catalogs cannot be internationalized, so you wil need to use a simple work-around to localize the image.

Open Localizable.strings (English) and add the following to it:

"imageName" = "ilike";

Similarly add the following to the Localizable.strings (Spanish) file:

"imageName" = "megusta";

From now on, you will use the imageName key to retrieve the name of the localized version of the image. Open ViewController.m and add the following line of code to the viewDidLoad method:

[_imageView setImage:[UIImage imageNamed:NSLocalizedString(@"imageName", nil)]];

If needed, switch your simulator/device to Espanol, then Build & Run and you will see the localized version of the image displayed:

Spanish image

Congrats! You now have all the tools required to localize your apps for multiple different languages.

Note: This is just one way to do things, useful if you have different filenames per language. A perhaps better way of doing this is to localize a resources folder, as described in this article.

Gratuitous Bonus

For a final bonus, let’s localize the name of the app itself. Your Info.plist has a special file (InfoPlist.strings) in which you can put string overrides for other languages. To give the app a different name in Spanish, open Supporting Files > InfoPlist.strings (Spanish) and insert the following:

"CFBundleDisplayName" = "Me Gusta";

This changes the name of the app as it appears on the Springboard.

Exercise: Internationalizing Audio files

If you’ve got this far, you should be comfortable with the basics of internationalization. This is a simple exercise where you’ll test out your newly acquired knowledge by taking two different audio files, one in english and the other on Spanish, and playing the appropriate file based on the user’s selected language.

Here is a brief description of the necessary steps:

  1. Download the sample audio files
  2. Copy box-en.wav first audio file to the project.
  3. Open the file inspector for the audio file and select the localize button, make sure you select english and spanish as the supported languages
  4. Rename the second audio file (box-es.wav) to be the same as the first one (box-en.wav) and copy it to the es.lproj folder.
  5. Make sure you select the “Replace File” option in the Finder prompt.

Where To Go From Here?

Here is the Final Project with all of the code you’ve written in the above tutorial.

Now that you know the basic techniques for internationalizing an iPhone app, add a foreign language to one of your existing apps or when designing your next app. As you have seen, it takes almost no time to implement, you open up your apps to a wider, more diverse audience, and your non-English speaking audience will thank you for it!

For the actual translation, you may be able to get away with using Google’s free translation service at http://www.google.com/translate, but the results are very hit or miss. If you can spare a few bucks, there are several third party vendors listed at the bottom of Apple’s Internationalization and Localization page. Pricing varies from vendor to vendor, but is typically less than 10 cents per word.

If you have any questions, or advice for others, regarding internationalization, please join in on the forum discussion below!

Ali Hafizji

Ali is an independent iOS and Android developer currently focussing on building immersive experiences on mobile devices. He is an avid programmer and loves learning better and faster ways of solving problems. You can follow him on Twitter or github.

User Comments

101 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
  • Storyboard and localization works fine! But when I add some elements on Storyboard, what's the preferred way to get those elements in the localization file? Can I regenerate the storyboard localization file someway?
    kevinboos
  • It works great on a device but not on the simulator for me. Anyone else?

    Xcode 5.1.1 and iOS Simulator 7.1.
    murray
  • Hi Ali, thanks for the great tutorial! Totally agree that localization is a very important step to capitalize on the global market potential.

    I think your tutorial complements a blog post that my colleague has written about how to optimize your app store descriptions in different languages - http://www.oneskyapp.com/blog/global-ap ... marketing/. After all, after localizing your app, you want people to be able to find it :)

    It would be great if you can throw us some thoughts on our blog post :) And would you mind if we share your tutorial on our social media page?
    amandawong
  • How set base internationalization on base projet "empty application" ? Not Work !
    I have not problem for set base international on base projet "single view application" !

    in Empty applicazion I make these stap:
    1) Add Storyboard on projet
    2) Add to storiboard in file inspector "localize"
    3) in info projet add base internationalization .
    4) add language
    5) trasform new add storyboard of localizable string to Interface Builder cocoa application !

    From this moment on, the changes made in view are no longer performed in the simulator!
    Yes, I changed the language settings in the simulator!

    Please Help Help me !
    FrankP2138
  • I'm trying to localize an app for both US and Great Britain (specifying different phone number formats, etc), but for some reason, as per many Stackoverflow questions and research into the Apple documentation, iOS apps only take language into account, not region. Therefore, even though I have en.lproj and en-UK.lproj, the app always defaults to en.lproj due to the language, even when I change the region to United Kingdom in my simulator's settings. I have no clue why, but MacOS apps do it properly, but iOS ones don't. One workaround involves changing main.m and the AppDelegate, but that seems like too "hacky" of a solution.

    Does anyone know a workaround for this problem?
    jsani
  • good job,exactly what i need.Thank you !
    chaoyuan899
  • How to Internationalizing xib files in XCode 5, xib files include labels without outlet and something else,,what i can do?
    Thank you!
    chaoyuan899
  • Great detail. The images and audio were fantastic additions. Way to go thinking beyond the normal text strings. Nicely done.
    brente
  • Thank you for so detailed teaching, I have also written in Chinese.

    http://wp.me/p1my2P-2LD
    HappyMan
  • Hi,Thanks for a tutorial.I am using xcode 6 and iOS 8 when am trying to run app developed by the steps given above,every time it display content in base language i.e english in my case even after changing device language.What should I do to correct this? Thanks for any help.
    dhananjay
[ 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!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Gaming!

    Loading ... Loading ...

Last week's winner: Apple TestFlight Tutorial.

Suggest a Tutorial - Past Results

Hang Out With Us!

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


Coming up in January: WatchKit.

Sign Up - January

Our Books

Our Team

Tutorial Team

  • Matthew Morey
  • Sam Davies

... 60 total!

Update Team

  • Zouhair Mahieddine

... 12 total!

Editorial Team

... 17 total!

Code Team

  • Orta Therox

... 3 total!

Subject Matter Experts

  • Richard Casey

... 4 total!