Localization

Internationalization – 1

So, I’ve been thinking of some of the more useful things I’ve inkearned as I’ve developed iOS applications and one of the most useful must be internationalization.  “You mean localization?” you ask.  Well, partially.  I’ve never actually needed to translate an app into any other language (localization), but I have made a habit of internationalizing my applications (preparing an app for localization). The process of internationalization has helped me to better understand the MVC paradigm. So, for the next few posts I’m going to be covering internationalization and discussing how easy Apple has made it for us developers to do! So with out further adieu:

The what, when, why, how

Apple puts it very nicely in their introduction to Internationalization and Localization:

Localization is the process of translating your app into multiple languages. But before you can localize your app, you internationalize it. Internationalization is the process of making your app able to adapt to different languages, regions, and cultures. Because a single language can be used in multiple parts of the world, your app should adapt to the regional and cultural conventions of where a person resides. An internationalized app appears as if it is a native app in all the languages and regions it supports.

So, localization is translating the app, while internationalization is the preparing the app for localization. Internationalization is usually the part that most concerns developers.  We need to prepare the UI and code base to accept localization.

In a broad sense we can prepare an application for internationalization by capturing any instance of user facing text. I say text since that is what is usually the most applicable, though any portion of an app may be subject to localization, such as images, sounds, etc. But in all cases, the process is essentially the same. But I digress. So, we capture user facing text and separate the user facing text (UFT) from the string value we have in code. Apple outlines six steps for internationalizing your app:

  1. Use base internationalization to separate user-facing text from your .storyboard and .xib files.
  2. In Interface Builder, use Auto Layout so views adjust to the localized text.
  3. Separate other user-facing text from your code.
  4. Use standard APIs to handle the complexity of different writing systems and locale formats.
  5. Adhere to the user’s settings when formatting, sorting, searching, and parsing data.
  6. If the app supports right-to-left languages, mirror the user interface and change the text direction as needed.

In order to keep my posts relatively short, I’ll cover each of these steps in a separate post.

 

Use base internationalization to separate user-facing text from your .storyboard and .xib files.

Our first step in internationalization is to prepare the text in our .storyboard and .xib files. This is actually fairly straightforward.  Lets say we have a simple login UI with a username and password UITextFields and a LogIn button:

So it looks nice, but how do we prepare it for translation into, say Ukrainian? I can’t just change the placeholder text and compile again. But here is an idea.  What if we could take the text in the UI and translate it on the fly? “Pfffft!” you scoff. “Thats impossible!” Nothing is impossible for the intrepid developer!

First, lets think about a dictionaries. A dictionary in Swift is a storage device that utilizes key-value pairs.  You input a key, and the dictionary gives you the value for that key. Localization in iOS happens in the same way. You give the string you want localized and it spits out the value that you previously encoded for that ‘key’.  These key-value translations are all stored in special .strings files. Lets see how to generate some .strings files that are tied to our UI.

First, open a new project in Xcode and select “Single View App” as your template. Next open the Main.storyboard file and add the UITextFields and UIButton to your view controller.  Edit the properties of these items to make them look like our view above.  Next open up the File Inspector (its the file icon on the right hand side, or just ⌥⌘1). About half way down is a section called…(Wait for it….) Localization:

Now, note the two listed localizations, “Base” and then an unchecked “English”.  “Base” is referring to whatever language you are coding in, be it English, Spanish, or simply programmer lingo. It is what is currently in the UI. Now lets see what happens after we check the “English” box. (Did you do it?).  OK, I’m assuming you did. The first think you might have noticed (or not) is that your Main.storyboard file now has a disclosure icon to its left:

Lets expand it and see what wonderful things have happened:

So our Main.storyboard now has a couple of files connected to it:

  1. Main.storyboard (Base)
  2. Main.strings (English)

The image above shows us what is in the .strings file.  Examining the comments and the words helps us to understand what is going on. The comment on line 2 indicates a UITextField, that has an objectID of “GU8-dk-kKo” whose placeholder text is “Username”. (PS to see any object’s objectID: select it, and open the Identity Inspector, ⌥⌘3, its shown in the Document section). But what is the next line? Being clever programmers we realize that this is a code of sorts. What we have (in very general terms) is this:

"GU8-dk-kKo.placeholder" = "Username";

//....Or, more generally...

"objectID.objectPropertyName" = "DesiredValue";

Neat! But what does this really mean, or do? Quiet simply, this is our “dictionary”. The LHS is the Key and the RHS is the Value.  Thus if we change the RHS, we change the value that is returned when a lookup is preformed. And that means that the text shown to our users will be different. Go on! Give it a try! Change the word “Username” to something else (I chose “Call Sign”) and hit run, if your local is set to English, then whatever you changed you text to will show up instead!

What is going on, is pretty much as described earlier.  When the UI goes to render, it checks to see if there are any .strings files for the local the phone is set to.  If not, it just uses the base values. But if it does have one, then it looks up the “Key”.  If the “Key” exists, then it returns its “value” (translation).  If it doesn’t, it defaults to the Base value once more.

Adding Translations

Now that we’ve started down this internationalization road, how do we add a translation for, say Ukrainian? Well, that’s easy! To add a translation navigate to your project file in the project navigator. Next select the project info file. In the info section, you will see the localizations connected to this project:

As you may have guessed (since you are clever), simply click the ‘+’ button to add a localization.  This will give you a list of languages to choose from:

Selecting Ukrainian (or your language of choice) and hitting next on the dialog, adds to the list in the Project file, as well as creates and additional .strings file inside our storyboard files (and our LaunchScreen and Main).  Note, localizing .xib files works the same way.

 

TL;DR

  1. To internationalize .storyboard and .xib files, select ‘Localize…’ inside the File Inspector for each file.
  2. To add a language for localization, select the Project file, and go to the info for the project (not a target) and add to the localizations list.

Sources

https://www.objc.io/issues/9-strings/string-localization/

https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/Introduction/Introduction.html#//apple_ref/doc/uid/10000171i-CH1-SW1

https://medium.com/lean-localization/ios-localization-tutorial-938231f9f881