Localization 101 | iOS vs Android

Morgan Collino
The Startup
Published in
7 min readApr 26, 2020

Localization is the process of making your app support multiple languages.

The first language handled by your app is more likely the primary language of the market you are trying to get in.

There are many cases where you might be motivated to localize your app, here are a few:

  • You want to make your app available for another market (eg: French market), therefore you will need to add French as supported language on your app
  • You want to make you app available for others languages spoken in your country.
  • In the US, you might want to add Spanish as other supported language
  • In Switzerland, it may also be Italian, German and French.

This is also valuable for your business goals. The more languages your app handle, the more users you can attract.

What is it like for iOS and Android

Well, The process of localizing your app is a bit tedious. 😑

So the sooner you start localizing your app, the easier/faster it will be ready when the business needs it!

Localization for iOS

Fortunately or unfortunately, not a lot has changed with iOS since its beginning.

(Yeah back Objective-C non-ARC time kind of beginning 👴🏻)

For iOS, localized content are located in two separate type of file:

  • File extending with strings will gather single strings and formats.
  • File extending with stringsdict will gather plurals/contextualized variables. (Technically an Apple version of xml)

Localization for Android

For Android, it’s in a xml format which can contains both plurals and single strings.

Android is actually a bit smoother than iOS (and that’s coming from an iOS guy uh).

Why? Android build system automatically generate helper functions/variables to access the localized resources strings via R.

At contrary to iOS, where there are no code generation for the resources. You have to do it yourself. SwiftGen can generate those resources on iOS for you.

Demo

Let’s start with an example

I have a screen I want to translate to French.

Just by looking at the design, I can clearly there are about 4 texts.
A title, a description, a call to action button text and a dismiss button text.

Title: “Playlist of the day”
Description: “Hello Morgan, there are 42 of your favorite songs in the playlist Party2020. Would you like to listen to it?”

We can can see the content has few parameters:

  • username
  • number of songs (plural)
  • playlist name

This end up a format like such:

  • “Hello [username], there are [number of songs] in the playlist [playlist name]. Would you like to listen to it?”

Call to action: “Listen”
Call to action dismissing: “dismiss”

Now, let’s create those translation files

iOS

For iOS you will need to create two directories within your project where the resources files will be located per language. In this example, my default language is English (identifier: “en”).

The directory should be composed such as: [Language identifier].lproj
So in our case, it would look like this:

  • en.lproj/
  • fr.lproj/

This can be located anywhere in your project. I personally put it under a directory named localization.

The first file I’m creating is the .strings file, I will put in there 3 of my texts and one format string for the 4th text.

en.lproj/Popup.strings

fr.lproj/Popup.strings

The .stringsdict file will have the plural variable. In this case, the variable numberOfSongs. This is an integer (d) variable, where I preset the values for one and other cases. Other will be used if the content should be pluralized else, it will choose one since it’s singular. (this is the case for English)

en.lproj/Popup.stringsdict

fr.lproj/Popup.stringsdict

Android

For Android, you will need to add your resource files under the directory src/{module}/res.

Watch-out for single quotes or special character, they will need to escaped.

The single strings are define under a <string> xml wrapper. Plurals are under <plurals>

src/main/res/values-en/popup.xml

src/main/res/values-fr/popup.xml

Now how do we implement the localized content?

First, let’s create an helper struct to help us do the heavy-lifting to get the localizations on iOS.

Then the implementation in the view:

I used the function NSLocalizedString(_ key: String, tableName: String, bundle: Bundle, comment: String) for a very specific reason.

Your code might move into a different location than the main project (eg: framework / resource bundle), using this function will give you less or no refactoring to do to when you decide to move those strings away. As long as the swift file is in the same bundle of the resources used, it will find them.

On Android, it’s pretty straightforward and you’ll be able to use the resources if its shared with your component (aka module).

R is generated via the build system. It allows you to access resources in your project.

Now, let’s try to change the language from English to French

On iOS, this can be done pretty quickly by editing your app scheme:

  • Edit Scheme > Run > Options

Modify the value of Application Language to French.

Android, you have two possibilities to see your app with a different language.

  • The first possibility would be to use the preview panel to see one or multiple views with the language you select on the dropdown menu.
  • The second possibility would be to change the language on the emulator directly. After changing language, if you launch back the app, it will automatically update with the newly selected language if supported by your project of course.

Mayday, we got a problem monsieur!

Pardon my French, but something doesn’t look right.
It looks like our French translation got mixed up in translation.

The parameter orders in the French format is different than the English one.

  • English format order: 1. userName, 2. numberOfSongs, 3. playlistName
  • French format order: 1. userName, 2. playlistName, 3. numberOfSongs

The code gives the order as below:

  1. userName
  2. numberOfSong
  3. playlistName

To fix this issue, it’s actually easy. You need to tell the order of the parameters within the format.

iOS

en.lproj/Popup.strings

fr.lproj/Popup.strings

Android

values-en/popup.xml

values-fr/popup.xml

Voila!

The content is now localized in French and ordered correctly.

Conclusion

It is up to you to start preparing your app to be localized in the eventuality of supporting multiple languages. Something I would recommend when starting a new project is to always put your contents into your system language files (eg: strings / stringsdict / xml), so later when you have to localize for another languages, you will only need to add the system language files for the new language you want to support.

The contrary would add you a lot of refactoring work you sincerely don’t want.

Time is 💰

Things to watch out

Few rules are also to follow during localization:

Never use business logic to dictate the plural strings.

For example, your user has a list of products. You may want to show a specific text if the users has no account, one, multiple…

  • zero: “Open an account”
  • other: “Open another account”

This works with iOS (surprisingly), not for Android due to CLDR Unicode language restrictions.

  • In the case of English on Android, zero variants are discarded due to be same has many. Other is then took as default.
  • In the case of French on Android, zero variants are replaced by the one variant if passed since they are the same in French.

Avoid static data representation in your strings.

Example, you have a single string like this: “Register for only $5.99 per month”

You may want to have the amount portion to be a parameter since the formatting of the price could change based on different countries.

  • US: “$5.99”
  • FR: “5,99€”
  • UK: “£5.99”

Same idea for dates in a text like this: “Register by 10/21/2020”

Like the price, date formatting is also depending on the location.

  • US: “10/21/2020”
  • FR: “21/10/2020”
  • UK: “21/10/2020”

The process to format those components into their proper locale is called Internationalization. (i18n)

Glossary

Android:

iOS:

Check out the sample project on my Github.

If you have any questions, feel free to let me know in the comments or on Twitter!

--

--