Internationalization Best Practices

Session 201 WWDC 2016

Following some simple practices when writing your app can help make it world-ready. Learn about what's new, how to take greater advantage of existing frameworks, and review some common pitfalls and how to avoid them. Hear some ideas for going one step further and optimizing your app for different countries.

[ Music ]

Okay.

Hello.

[ Foreign Language Spoken ]

So hello and welcome everyone to WWDC.

Looks like it's your first session this morning.

If you didn't understand what I said at the beginning of the talk, you're at the right talk.

So let's talk a little bit about internationalization.

So as you might know, Apple ships its products all over the world.

And two-thirds of Apple's users are outside the U.S.

Which is why it's really important to make sure that the linguistic experience is right in your apps.

So we have users all over the place from San Francisco to Milan and Dubai and from New Delhi to Hong Kong.

And of course these users are most likely to be using your apps and Apple's apps in their native languages.

They're also likely to be using these apps in languages you didn't expect that aren't related to that region.

For example, English, you might be surprised is a fairly global language.

So today I'd like to talk to you about what's new, what we've been up to for the last year in the space of internationalization.

Some fundamentals about getting started with localization and internationalizing your app.

Then some quick fixes that you can make in your code to make it a great app for a worldwide audience.

And lastly, some things to keep in mind from a design and mentality standpoint when you go about making your app.

So let's get started with what's new.

I'm really excited to talk about the multilingual keyboards that we've added in iOS 10.

Now if you look around you, just to your left or right, you're probably sitting next to or are a person who speaks more than one language.

The U.S. is an extremely multilingual place and California especially so.

And with iOS 10 we embraced this by offering you multilingual keyboards.

So you can choose from a mix of any of the two languages.

Or any two of the languages here on screen, and you can type them on the same layout without having to switch the globe key and you'll get autocorrections and predictions for both those languages.

Another enhancement we've made is the addition of Latin American Spanish.

And this comes to iOS, watchOS, and tvOS.

And this is the first time that your app might encounter a language variant that is not for specific country.

And I'll talk about how that's important at the code level in a bit.

Another great enhancement is the new measurement formatter that is added in foundation.

And this will take care of unit conversions in a language and region aware manner for you all under the hood, and it already supports more than 20 different units like temperature, energy, pressure, you name it.

Now, I won't be going into depth about this here, but there's a whole session dedicated to this on Friday.

So please check that out.

We've also localized the keyboard number pads this year.

And so when you request the number pad keyboard type, you're automatically going to get a keyboard that supports different numbering systems, such as those used in Arabic and Hindi.

And when you're in this state, you're going to see a 123 key in the bottom left of the keyboard to let you switch between these different numbering systems.

Now in some cases, you might want to specify ASCII capable number pad instead when you're sure that the input that you have needs to be restricted to ASCII digits.

Some examples of this are credit card numbers and IP addresses.

They're edge cases, but things that you should be aware of.

One of the huge new features in macOS Sierra is native right-to-left support for languages like Arabic and Hebrew.

And macOS has been redesigned with right-to-left languages in mind.

And of course, macOS joins our existing family of products like iOS and watchOS which already support right-to-left languages natively.

Again, this is a huge topic, and I won't go into this in detail.

And again, there's a dedicated talk, What's New in International User Interfaces on Friday at 9 a.m.

that you should definitely check out.

So let's get started with some of the fundamentals that you need to know about internationalization.

Let's take a look at an app that comes with iOS, the Clock app.

It's been re-themed, but probably still looks familiar to you.

So what are the various aspects that you would need to internationalize here for this app to work in different languages and countries?

First of all, you need to localize the strings.

So this is basically any button or tab or view that has a string in it, you need to make sure that it's translated into all the different languages you're going to be supporting.

Then there's another category of string that needs to be localized but it is formatted content and so you should use formatters to achieve that.

And this will save you a lot of work.

And lastly, you need to internationalize the layout so that it will work well for right-to-left languages.

And for languages that have longer or shorter translations than the language you're starting with.

So if we do all this right, then we take this English app and we translate it into a Chinese app, and it looks fantastic.

Notice how in Chinese the a.m.

/p.m. marker goes before the numbers instead of after like it does in English.

It'll also work well for right-to-left languages like Arabic.

Notice how the layout of the entire app is flowing from right-to-left.

And in this case, see how Arabic is using the Arabic-Indic numbers which are different from those used in English.

Again, if you use formatters, you get this for free.

So those are some fundamentals for the development side.

Let's take a look at the fundamentals from the user side as well.

What does a user do when they get a brand new Apple device like an iPhone?

Well, every Apple device that you open up will first ask you to choose a language.

And what's going on under the covers is that every language has a code associated with it, and of course, every region has a code associated with it also.

So let's say a user chooses Spanish, United States.

What that becomes at the end of the day is a language code like es-US.

What you may not know is that language codes are part of hierarchies.

So for example, Spanish, United States actually inherits from Latin American Spanish which then inherits from base Spanish.

This is really important because not every app is going to be localized into Spanish, United States.

So we want to know, okay, what is the next best language that the user would prefer if we don't have their most preferred language available on the system.

Also, this hierarchy is not just for Spanish but even languages like English have a hierarchy.

For example, Indian English has spelling systems that are more close to British English than to American English, and so it is part of the hierarchy in which it inherits from British English.

And English and Spanish are far from the only two languages that have such a hierarchy.

We also have other languages like Chinese, French, and Portuguese that have similar hierarchies.

So I hope you all are taking notes on this, you know, on these aspects because no, of course not.

The reason I'm mentioning this at all is because we're going to help you solve this problem, and you don't need to know anything about this.

So I'm going to show you how to do that in the next section with quick fixes.

So what's the first thing we need to do?

We need to localize the strings.

Now there is a little bit of setup.

It's simple.

But there's some setup involved, and I won't be talking about that in detail because there's a whole there's a lot of documentation, and there's another talk that goes into detail about how to set up your app.

So let's assume that you've got your setup for localization, so you've got some localized strings in your app.

If you're using storyboards with Base Internationalization, you're done.

There's nothing you need to do.

You launch your app.

The strings get loaded.

You're golden.

If you are creating or loading strings in code, then you need to call NSLocalizedString.

NSLocalizedString will use the fantastic logic that I mentioned with all the fallback, and it will load the most appropriate string for you.

Now, note that it's important to provide a comment to your translator because oftentimes words are distinguished by which context they're in and the comment helps clarify that.

Let's move on to slightly more complex scenario.

Let's say you're getting strings from a remote service like a server or another process.

Well, in that case you probably want to let the server or the other process know, hey this is the language my app is launched in, please give me strings that match this.

And in order to do that, you can call preferredLocalizations on the Bundle that you're launched from and get the first language and give that to your remote service.

If you have an even more involved setup and for some reason you have a list of available languages, say, on the server that don't match exactly the list of languages you have on the client.

Let's say you have a larger set on the server, then you can call the class method preferredLocalizations and give it the available set that you have.

And again, it will match you to the right language.

So I mentioned this Bundle's language matching logic multiple times during the last few slides.

So what is all this about?

And what is Bundle doing for you under the hood?

So what Bundle does for you is that it figures out things like, okay user prefers English U.S. We don't have an English U.S. localization.

We do have an English.

So okay, in this case it will give you English.

It figures out things like you want Indian English, but we have British but not Indian, we'll give you that.

And again, with the Spanish Latin America example, if you say I prefer Mexican Spanish, it will figure out that oh the best match for you in the list shown here is Latin American Spanish.

And similarly, for Chinese and many other languages.

This is a lot of complicated locale aware logic that you do not want to be implementing in your apps.

And definitely if you have code that does something like take the language identifier and split it on hyphens or something like that, please go and delete that code because you should not be doing that.

So now you've localized all your strings and used the right APIs.

You want to double check that everything you have done is actually localized.

To do that, you can use the new static analyzer in Xcode 8, which will actually find any issues that you have with localizability, where you're feeding non-localized strings into the UI.

And that's all there is to localized strings, really.

Next let's talk about formatters.

This is a common kind of app that you see these days with all the delivery services.

And this, however, is not a good thing that you're seeing here.

So it says AM9:41, which to an English user will definitely look like nonsense.

But believe me, I've seen this in a real app.

And similarly, you might see something that is the opposite in Chinese where it puts the a.m.

/p.m. marker after the numbers, which is completely wrong for Chinese.

So how do we avoid bugs like these?

The problem is actually that we're using this method which is formatter.dateFormat setting a fixed format on it.

It seems like the right thing to do.

It looks pretty nice in code, but it's actually the wrong approach.

And although it yields the right result when you try it out for English, so it'll give you 9:41 a.m. you try the same thing out in Chinese, and it gives you the wrong result.

Why? Because it's applying a fixed format to no matter which language you're running in.

The correct approach for this is to just use the predefined short style on the date formatter.

And it's going to give you the right result for English, for Chinese, and for any other language your app might be localized in.

And of course, there are more styles.

So we have the short style that I just showed you.

You can also get a slightly longer style, which has the seconds.

You can have a style which has the time zone or the full time zone name.

There are variety of different styles for different needs.

And of course, not just for times.

For dates, also, we have the whole range of styles going from short to long.

Now you might come back to me and say, "okay, sure but none of those styles is what my designer wants.

They want, you know, just the full year or just this or just that."

That's fine.

So you can use a format.

The important thing is to use it with the setLocalizedDate FormatFrom Template method, which will make sure that it takes your format, interprets it for the current language in question and gives you the correct localized format for that language.

There are also two classes that you might not have used.

They're fairly new, although not new this year, date components, which will let you format, say, a duration like 4 hours and 25 minutes.

Or a date interval like the duration of this talk, 9 to 9:40 a.m. So the advantage to these, again, is that if you use these classes, all the localization is going to get taken care of for you.

Next let's talk about another kind of data type that you can format, names.

Now, if this is how you're going to show the user's name or their friend's name to them when they open your app, they're going to get a really bad impression of your app.

So let's not do that.

Instead, you should show the names in the way that is correct for that given language and script.

So how do we do that?

It's actually really simple.

You create a PersonNameComponents object.

Fill it with some name components, and then just like any other formatter, you just ask for the string from the components for any given style that you want.

And again, we have a variety of styles going from long, which is the full name all the way to abbreviated which you can use for initials.

And of course, it supports multiple languages.

New this year, though, is name parsing support.

So now you can go from a full name to a set of components.

And it's as easy as creating a formatter, giving it a string, and then looking at the components.

If it returns nil, it means it wasn't able to successfully construct components out of it.

The really cool thing, though, is that this is not a static API that's looking at some set of static rules.

It's actually a statistical model so that even if you pass in the name in the opposite order, it knows that in John Appleseed, John is much more likely to be the given name and Appleseed the family name.

And it's still going to parse it correctly.

And of course, it supports multiple languages as well.

So there are a lot of formatters.

I talked about Date and PersonNameComponentsFormatters in detail.

The components and interval formatters for dates, briefly.

And there are some formatters I didn't even mention which are existing formatters that we have in the system.

And there's the brand new measurement formatter that's new in this set of releases.

So be sure to use these formatters wherever you can in your code because they will do the right thing, and you will also save localized strings.

Which you shouldn't be using for these cases.

So that's all about at this point your whole UI is localized in terms of strings.

Now let's take a look at what you need to do in terms of the layout to make sure that the UI actually works well with those strings.

So the key word here is Auto Layout.

It does what it's intended what its name tells you it does, which is it automatically lays things out.

And so whether you're in a left-to-right app, if you use Auto Layout you will get automatically a user interface for a right-to-left language.

And again, Auto Layout is a big topic, and I'm not going to go into detail into how you should use Auto Layout because there are sessions for that both this year and from previous years that go into a fair amount of detail.

What I will tell you is that you should use UIStackView and NSStackView as much as you can because these are very easy to use APIs that leverage Auto Layout and make sure that your views will flip in the right way for right-to-left languages and adjust appropriately when they get long and shorter strings.

So we will have sample code for you that shows you how to implement a version of the Clock app using Stack Views.

Now one thing that you might want to keep in mind for layout is that sometimes you need to get creative.

Now you see this screen in English.

Are you sure you don't want to use an Apple ID?

And you have two options there, Use Apple ID or Don't Use.

Now in some languages you can imagine the translations might be longer than can fit in two side-by-side buttons.

So what do you do?

Well, in this case, you see that the whole view switches to a top-bottom orientation instead of a left-right orientation.

And these kind of creative UI elements are things that you should keep in mind for your apps before you ask a you ask a translator to shorten a string to the point where it might not even be intelligible in that language.

The next thing is vertical flexibility.

And a lot of you may not have realized this before for your apps.

So we have a lot of scripts in the OS for languages like Vietnamese, Thai, Arabic, and Hindi that go much higher or lower or both than the basic Latin alphabet that's used to write English.

And so what happens often is we see this bug, which is that somebody might set clipsToBounds to true on the label.

And what that does is it clips the text often on both side and besides being very ugly and, you know, just looking terrible in that language, you often lose important semantic information like a diacritic mark.

In this case the pronunciation of all of the words on the right is changing when you clip them like this.

So to fix this it's pretty simple.

Don't set clipsToBounds to true if you have a label.

And that should be enough to solve this problem.

More interestingly, though, when you have multi-line labels, you also need to consider interline spacing.

So let's take a look here which has Hindi on the left and English on the right.

And here it's English on the left and Hindi on the right, sorry about that.

But see what happens when we try to squeeze Hindi into the same amount of vertical space as English?

It looks really cramped.

And any Hindi reader will tell you this is really hard to read, and it doesn't look nice.

So what you really need to do is to give each script the room it needs to breathe and to look good on screen and to be easy to read.

The good news is that this is really easy to do.

Any time you have a multi-line label, again, a lot of this is done by default but you just need to be sure when you set a custom font that you do the right thing that you get a preferred font using the UI font API.

Now, you might say, okay I have a custom font and I can't use this.

Well, there is a solution for you, and you should check out the fonts and typography talk on Wednesday that goes into more detail about how you can make sure that a custom font will also adhere to dynamic type.

Next, for table views, we do something really neat, which is that if you have a language with a taller script, we will actually make the table row height larger than it is in other languages like English.

Again, this gives the script the room it needs to breathe, and it just overall looks more natural for those languages.

The way you can take advantage of this code is by using the standard UITableViewCell styles.

And now you might say, okay, sure but I have a custom cell, you know, it's not going to work with this.

I mean, I don't just have a label and you know, it's not as simple as you think it is.

And I'll be like, okay sure.

I agree. But what I found at least in using UITableViewCell is that it is highly customizable.

It has a bunch of overrides that you can use, usually to get exactly the appearance you want.

So try that first before you're implementing a completely custom UITableViewCell.

So that's mostly what I have in terms of small code fixes that will make your app great for an international audience.

Let's talk about some things that are more abstract that are more design based.

And also the mentality you need to keep in mind for making great apps.

First of all, it's the iconography.

Now you know that when you go to the App Store and you're looking for an app one of the first things you're going to notice is that icon.

And oftentimes, at least I've done this, if the icon doesn't look good I don't buy the app because that's going to go on my Home Screen.

And I don't want to have an app there that doesn't look good.

So icons are really important, and it's also important that the icon that you choose works well for different languages and also languages that go in different layout directions like left-to-right or right-to-left.

So photos has a great icon here.

This is a great example of an icon that doesn't have any words or numbers that would tie it to a specific language.

It also doesn't have a directionality like left-to-right or right-to-left.

So it really works well, you know, in Japanese, in English, and in Arabic.

Now if you are making a right-to-left localization, and you want to make sure your UI is really good for right-to-left languages.

You should take a look at some of the artwork you're using.

And if you are using artwork that has a directionality to it that would need to change for a right-to-left language, then you would probably need to flip or create dedicated artwork for right-to-left languages.

Now here you see an example of artwork that you can't just flip horizontally.

You need to create dedicated artwork if you're in a right-to-left language.

But if you do have images that just need to be flipped, there is actually API for that and you don't need to create separate artwork.

There's more information about that, again, in the What's New in International Interfaces session on Friday.

But the key is asset catalogues.

Another thing that you might or might not have thought about is your app's name.

Now, when looking at various App Stores around the world, one consistent theme we've seen that doesn't surprise us in the least is that users are more likely to buy apps that work for them in their language.

And that applies to the apps' name as well.

Because if they can if they can understand easily what your app does by looking at the one line name and description, then they're much more likely to tap inside the app to take a look.

And of course, the world is users all over the world are more and more multilingual or at least they're bilingual.

So your app should not make assumptions about the UI language and how it relates to the content that the user will type.

For example, a very common theme you will see all over countries in Asia like India and Southeast Asia is that people will run their phones in English, but they'll have content in their local languages like Hindi in this case.

So when you have an app and you run in English, don't assume that the user's going to type English text, especially make sure to test your app with Chinese and Japanese keyboards to make sure that the experience works well.

And here's an example that I wanted to show you of an app that in our opinion does a really great job at the things I just talked about.

So this is Evernote.

And first of all, you'll see the app icon.

It doesn't have any words or symbols or anything that would associate it with a single language.

So that's great.

However, they have also gone and localized their app name into Chinese.

And this is actually if you're a Chinese speaker, you'll see that they have a great visual pun in there because the Chinese word that they've chosen also contains the character for elephant, which is their icons, which is kind of cool.

You'll also notice that they have localized screenshots.

And there's a lot of attention to detail in those screenshots.

You'll see, for example, that in the localized screenshot in which they're creating a note, you actually have the Chinese keyboard on screen.

So the user is seeing in the screenshots exactly the experience that they're going to get when they download this app.

This is exactly what users expect to see.

So take advantage of the fact that you can upload localized names, descriptions, and screenshots to the App Store.

And lastly, I wanted to talk about surprise and delight.

What you can do to go above and beyond to make a great product for people in the using a specific language or in a specific country.

I'll give a couple of examples.

One is if you have any kind of predefined content such as templates and pages.

You could create different customized content for different languages.

And so for example, in Pages you have custom templates for cards for some languages.

And just one more example I'll give is for more advanced feature, let's say you're supporting you're a calendar app, and you want to have a really great app for the Middle East and also for a lot of Asian countries like China where they use a lunar calendar.

Well, you could support the lunar calendar in your calendar app just like iOS does and iOS and OS X do because this is going to deliver a much richer experience for those users.

Now what your app does is really depends on what your app does.

And so you need to take a look at your own app and see if there's an area where you can deliver a surprise to the user.

That's really all I wanted to talk about today.

So in summary, localize your app.

Use standard system APIs like Formatter and Bundle.

Make sure that the apps' layout is flexible and works well for languages with shorter translations, longer translations, which have normal not normal-sized, English-sized scripts or taller scripts.

When designing the iconography for your app, make sure that it is a world-ready design and doesn't tailor to a specific language too much.

And finally, at the end localize your app's name, if appropriate, and screenshots.

Now for more information, you can follow this link to get some other useful links about internationalization and localization.

There are also some really cool other talks that I mentioned during my presentation.

So for example, there's What's New in International User Interfaces.

And there's also a What's New in Auto Layout.

One talk that I wanted to call out specifically is Inclusive App Design.

It kind of will talk more about some of the things I mentioned at the end about how you can keep an inclusive design in mind for both internationalization and for users that need accessibility support.

And that's all.

Thank you very much.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US