App Frameworks • iOS, macOS, watchOS • 37:01
With the majority of Apple's market outside of the US, it's critical to learn about the latest advancements in Internationalization support to make your app truly localized. Gain insight into best practices for using formatters to display information correctly, how to easily handle pluralization in any language, how to avoid the most common localization pitfalls, and much more. Whether you are looking to significantly expand your market or want to take advantage of powerful new features for all languages, you don't want to miss this session.
Speaker: Nat Hillard
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
[Applause]
[Nat Hillard]
Good morning, everyone. Now, good morning, or should I say, zao an, dobry den, buenas dias. My name is Nat Hillard. Today I will be going over what is new in internationalization. I will be going over new APIs that we have introduced, as well as improvements to existing APIs that you can use in your apps to make them ready for use all around the world.
To begin with, this is the Earth. There are over 7 billion people on this Earth. To these 7 billion people, Apple has sold over 1 billion iOS devices. Additionally, our install base for Mac OS X is 80 million devices. We have over 450 physical stores located all around the world and your apps, numbering 1.4 million or more, have gone from developers just like you, have gone to users all around the world. So, that's a lot of numbers, but if you only take away one number from today's presentation, let it be this.
69%. 69% of Apple's current revenue comes from international markets. Now this is huge. To see this in perspective, let's look at a graph. Over two-thirds of Apple's revenue is coming from places that are not the United States. Users in these areas have different expectations about how they'll interact with your app. These include linguistic differences, regional differences, and cultural differences that you will have to keep in mind. Now let's break this down even more.
Interestingly, here, is that a combined 41% of your users are coming from China and Japan. Now, I think it's a common misconception that internationalizing your app means making it work in Europe. Now, indeed, this is important, but additionally you have to keep in mind that users in China and Japan present additional challenges. That is to say, they don't use an alphabetic script. There are no spaces to separate words. And, additionally, what may work in your UI will be often a lot terser in Chinese and Japanese.
So, the good news, here, is if you use our APIs we will help you to internationalize your app easily and effortlessly. So, today we will be going over four major areas that you'll have to think about: localization, formatting, handling text, and layout. So, to begin with, let's discuss localization.
Now, by localization, I mean to say making your app speak your customer's language. I mean this both literally, in the sense of translating the words that appear on the screen, as well as more metaphorically, translating linguistic concepts behind the things you wish to translate. So, it might be helpful actually to begin this section with taking a look at how users interact with these settings on our operating systems. On the left, we have OS X, on the right, iOS. These are the language and region preference panes.
So, on the left-hand side here, on the OS X screenshot, you will see the preferred languages list. Now, in fact, it's important here that this is an ordered list of languages. Users can add multiple languages and, if a given language is not available for the display of your UI, it will actually fall back to the language below it.
Here, for instance, the user has chosen Swiss German as their primary language. But Swiss German is, in fact, not a language that we localize into. Therefore, for this UI, we have fallen back to English. Now, these fall backs are, in fact, somewhat common, so you will have to think about this from a developer perspective as well. So, in addition, though, to the language your app is displayed in, we have additional regional preferences.
These are off to the right-hand side of OS X and a little further down on the iOS screenshot. Now, these actually inform the way the given units, as well as times and calendar dates, display in a given locale. So, that is to say that it's not simply the language that you are translating into, but often the concepts behind the things you wish to translate. Now, for a lot more information about the differences between the preferred language and the locale settings, do check out last year's talk, "Advanced Topics in Internationalization," which goes into a lot more detail about this.
So, we provide a lot of settings out of the box, but we additionally allow users to customize these settings if they have individual preferences. So, new in iOS 9 and El Capitan, we have the ability to customize your number system, as you can see here. So let's say we have a user who is an Urdu speaker. They have chosen as their primary language, Urdu, and it has therefore fallen back to English in our operating system display language. By default this user would receive the standard Arabic style numerals.
We allow, though, in iOS 9 and OS X, El Capitan, to go in and customize these settings to override the existing numeric system. A lot of people don't realize, in fact, there are multiple numeric systems in use around the world. On the top we have the Arabic system and below we have the so-called Perso-Arabic numeral system, commonly in use in the Middle East. So a user can choose this setting, and it has interesting repercussions throughout the operating system.
Here, for instance, we have the Weather app. Now, without any additional changes on the part of the developer, all they have called is 'localized string with format' or the NS number formatter APIs; they have gotten these numeric changes for free. On the left, we have a user using the Arabic numeral system, and on the right, the Perso-Arabic numerals.
We noticed that every, every instance of Arabic numerals have changed in this UI, including, in fact, the timestamp at the top of the screen. So, this is interesting, as a developer, simply calling 'localized string of format' you will get this behavior for free. Now, in addition to the language that the user is seeing on the screen, the user is also inputting text into your application.
New in iOS 9 we add five new keyboards for Indic languages. On the right, here, you see the Telugu keyboard. Now, additionally, we've added predictive typing for four existing languages: Korean, Mexican Spanish, Russian, and Turkish. Now, from a developer perspective, it's interesting to realize that, in fact, often these characters are not what we would typically call a character. Here in the Telugu keyboard we have combining mark characters, that, in fact, will combine with other characters to represent a single visible unit. So, we'll get into that a little bit later.
Now, so, we have seen how users can change the settings on your operating system. But, how then do localizers translate the strings that users are seeing? The primary interface for localizers is the .strings file. The .strings file has this format. First you have a comment, in C-style comment syntax, followed by the development language on the left-hand side, and the target language on the right. Here we have a German.strings file. Now, .strings files are stored in lproj directories of your bundle, within the resources directory. English has its own .strings files, as, here, does German.
Now, additionally, we allow you, and we have allowed you since XCode 6, to export localizations in the commonly used XLIFF file format. You can then re-import those as strings files into your project. But for a lot more information about this, I would encourage you to check out last year's talk, "Localizing with XCode 6." So, we have seen how users are changing these settings. We have seen how localizers can then translate the strings that you see on your screen, but, then, how do you as a developer make use of these settings? Here's where NSLocalizedString comes into play.
In Objective-C, this is a macro. In Swift, we promoted this to a first class function. It takes five parameters, three of which have default values. Interestingly, in Swift, we've made it such that the comment argument is non-optional. This is really emphasizing this is a critical argument. It provides context for your translators. A given word may be ambiguous in certain contexts and this comment parameter will allow you to customize that.
So, the key is the string you wish to translate, and the comment is the comment explaining it. Now, this works for simple localized strings, but, additionally, we allow you to get a localized, formatted string, that is to say, a string with variable arguments to be populated. So for that, you call 'localized string with format, passing in a format string with certain format arguments as well as the arguments to populate the variables within that string. And in fact, it's actually very common to use these together. You call 'localized string with format' on the result of having called NSLocalizedString.
Now, to see what this looks like in action, it might be helpful to give a brief demo. So, let's say we wish to translate the string location:X. Now, let's also say that we have a variable location which has been populated by our translators to be the user's physical location.
Here is what our strings files may look like. On the left-hand side is the string to be translated, and on the right is the translated variant. We see here that in fact the translated variant still has a variable string. Percent add is meant to be filled with a string variable. So, this works in English -- we have location, San Francisco -- as well as in Japanese. This is the equivalent string.
So, now that you know this, you may have some certain assumptions that come into your head. One being that the arguments as presented to 'localized string with format' will be in the same order that they are in English. Now, we will see why this is wrong. We call 'localized string with format' here on the result of NSLocalizedString. We wish to translate the string 'copy X is Y' where X is the user name and Y is the thing we wish to copy.
Here, we're passing "hairForce1," which is Craig Federighi's chosen InstaMessage handle, and "photos." In our lproj, in our .strings files within our different lprojs, a developer may assume that the arguments will appear in the same order. While this may work for English, in fact it doesn't work for German.
These arguments need to be reversed to make sense in German. So, here is where a localizer can actually go in and add these positional formatting arguments. This allows what was formerly the second argument to become the first, and vice versa. So, here, then, a developer doesn't have to do anything. They call 'localized string with format' and NSLocalizedString.
But, it's important to keep in mind from a developer perspective that what you think may be the first character may not be. So if you have an operation that operates on the assumption that the arguments will come in in the same order, you may want to rethink that assumption. So, now we know how the .strings files are stored and in which directories they're stored.
But at this point you may be tempted to do something like this. You set the language variable to the first object in your preferred language's array. This corresponds to the UI element we saw before, the preferredLanguages list. Additionally, you append the suffix lproj to this, and you call a 'path for resource.' Let's say we wish to localize a stop sign graphic. So, here, let's say, though, that our individual bundle only has an es.lproj, corresponding to Spanish. But let's say our user's preferred language is Mexican Spanish. Using this particular technique, the user will get nothing back.
Now, why is this? Well, it's because we are not using the standard NSBundle APIs. NSBundle will intelligently fall back to an available localization if one is not currently available. So es-MX will fall back to es. Additionally, we have other smart, fall back logics, such as en-IN, Indian English, falling back to en-GB, the English as used in the United Kingdom.
So if you call, if you call these APIs, you will get back the appropriate resource with the appropriate fall backs. 'Image for resource' will give you the image. 'Path for sound resource' will give you the sound resource. And 'URL for resource,' the most generic, will give you back any given other file format.
So, we are seeing, here, using NSBundle APIs makes it easy to find the resources you are interested in. And, additionally, however, you may think that there are certain things that can only be done in code. Now, how many of you have written code like this? You wish to say, you wish to translate the string 'X days remaining.' We know that in English, if there is only a single day, we use 'X day remaining,' and if there are two or more we say 'blank days remaining.' Now, this may work in English. It works for one day and five days. But other languages don't have the same logic about how things are pluralized, given a given numeric component.
Here in Russian, for instance, we only have, we have one form for one, we also have a form for few, many, and even more than many. So this simply doesn't work for languages that have different pluralization rules. Now, to help you with this, we provide the string stick mechanism. This has been around for a few releases but it's important to emphasize here.
A string stick file is essentially a plist file that you store within your project. It's a localized resource, so it falls within your lproj directory for a given localization. As well, you have a given key. That key, in conjunction with a numeric argument, will then have different realizations, depending on what that numeric argument is.
I realize this is a lot of text, especially when you add the Russian component here. But, that is to say, you know English has one form for one and a different form for other, whereas Russian as one, few, many, and other. Now, to format string stick files I would really encourage you to check out the "Internationalization and Localization Guide." This goes into a lot more detail than we can provide here as to how to format and create these files on your own.
So, using this is in fact super easy from a developer perspective. Again, all you call is a 'localized string with format' on the result of NSLocalizedString. The string that you are passing in is the key to the string stick dictionary. Then you pass a numeric argument which will fill in the variable, from the formatted string which has been returned to you. Therefore, it will do the right thing for English, for one, two, and five days, as well as for Russian. We note here that the form for two and five is different in Russian.
So, more on the topic of string stick. We have a new mechanism in iOS 9 to allow you to make use of string stick for formatting strings on the screen. It's also in El Capitan, I should say. So, to begin that, let's say, this is a common problem, and in your InterfaceBuilder you have set up a string to appear in the center of your screen: "Welcome to the store!" This may work on an iPad Air, but it may not work as well on an iPhone 6, and it may work even worse on an iPod Touch.
Now, one way to solve this is in fact using auto layout and certain constraints. And, often, that's the solution to this problem. We'll get into that later. But in fact, another way to solve this is by using a new mechanism, 'variable width rule type.' This is an entry you can add within your string stick which will provide different realizations depending on the amount of space available to you. On iOS, this refers to the M width available on the screen, that is to say, the visible width of a capital M in the standard system font.
We have three different goal posts here. We define if there are 20Ms available, we present the string "Hi." If they are 25, we give "Welcome." And if there are 50, we say, "Welcome to the store!" To use this, again as the developer, super easy. You call NSLocalizedString on the key within your string stick file. Then you set it to a UI label object.
This works on iPad Air, iPhone 6, and iPod Touch, and the realization is different. Now, interestingly, we have used English for these examples but in fact this has important repercussions for international users as well. Often a translation into another language will be much longer than that in English. So this allows you to flexibly choose from among different translations for a given string in a different language as well, so this is a super useful tool.
On OS X, things are a little bit different. So, on OS X, likewise, you call NSLocalizedString and you pass in the key to your string stick dictionary. Then you call 'variant fitting presentation width.' Now, on OS X, this integer variable is in fact an arbitrary quantity. This can be anything, as long as it's defined relative to other quantities within the string stick.
So calling this with an integer value of 20 will yield "Hi," 25, "Welcome," and 50, "Welcome to the store!" So, in general then we have made it a lot easier for you to translate strings as they appear on the screen in a flexible manner that works for all of the world's languages.
Next up, let's discuss formatting. It's often not enough to simply translate the strings that appear on your screen. Additionally, you will have to think about the way dates, numbers, times, and, new in iOS 9 and El Capitan, names. So, to begin with, there is a right way and a wrong way to format numbers. Let's say we wish to present the constant pi to our users. One naive way to do this would be to initialize a string variable with a format argument percent.3F, that is to say, a 3 precision float argument. This works in English, 3.142.
If you translate, if your user is running in a German localization, however, they get back this string. This may appear correct at first glance, but in fact a German user would read this 3,142, because in German, the decimals digit and the, sorry, the thousands digit and the decimals digit are, in fact, switched, so that is to say, where we would use a period in U.S. English, they use a comma, and vice versa.
So, to take advantage of this fact, you can call 'localized string with format, passing in the same format argument you used before. Now this will have different realizations depending on a user's locale. And this means now the same thing for an English user and a German user. Now, under the hood, 'localized string with format' is using NS number formatter. And we have some improvements to NS number formatter we would like to discuss as well.
New in iOS 9 and El Capitan are different number styles for the NS number formatter. In addition to the already existing 'currency style, we now have 'currency ISO code style, as well 'currency plural style' and 'currency accounting style.' Interestingly here for 'currency accounting style, if you pass it a negative number, it presents it surrounded by parentheses. This is common in accounting circles.
As well, we added an 'ordinal style,' that is to say, how the number would appear in an ordered list. So from 42, you get back 42nd. So, in addition to formatting numbers, another thing that commonly goes wrong is formatting dates. Now here is a very naive way to format a date. We initialize an NS String with this format argument. That is to say, this represents today's date at 9:00 in the morning to a U.S. English speaker.
So in U.S. English we would get back this string, which looks appropriate and correct. But for an Italian user we get back the same string. Now this means something very different in Italy. This is in fact the 6th day of the 12th month, and furthermore, the time itself could be a little more clarified. We'll get to that in a second.
So, one way you could attempt to solve this is by creating an NS date formatter. Indeed, NS date formatter is the correct solution, but this is the incorrect way to use it. Here, we're setting a date format argument. Now, the date format implies an explicit ordering of strings. The exact variables that you provided here will then be expanded in whatever locale you are using, to the exact sequence of characters you see. So, again, we are getting back the incorrect string in Italy.
Now, the easiest way to fix this is in fact by setting a date style and a time style on your NS date formatter. We provide certain out of the box styles for NS date formatter that allow you to specify the amount of space available to you relative to the width of the string.
So here we call, here we set ShortStyle for both date and time style. What we get back in Italy, therefore, is the same string but with the variables flipped. So that is to say, this now reads the 12th day of the 6th month to a user in Italy, which is the same thing would read as an English-US user.
Now, sometimes, though, these date styles and time styles aren't as specific as you may need them to be. For that, new in iOS 9 and El Capitan, we allow you to set 'localized date format from template.' Here you provide a template and the variables are rearranged as appropriate for your given locale.
Now this is when the individual styles out of the box don't provide enough information. Here, for instance, the user wishes to present the second string as well, which doesn't typically come with a short style. So using this template, we have allowed for 24-hour time as well, as well as rearranging the month and day arguments. So, we have looked at how you can format numbers, how you can format dates, but also important is how you format units.
Now, this is in fact a very naive example but one which is very real and we have seen in the real world. Let's say you wish to translate the quantity "6 pounds" to another language. One very naive way to solve this would be in fact to literally translate the string.
You have on the left-hand side, "X pounds.' We have translated this for an Italian user to "X chilogrammi," that is to say the Italian word for the word 'kilogram.' Now, this may be obviously very wrong. In English we have 6 pounds. In Italian we have 6 kilograms. These quantities are not equal. 6 pounds is not equal to 6 kilograms. These quantities are not, in fact, equal. 6 pounds as a unit is not equal to 6 kilograms. So this is a very wrong way to do this.
An easier way is to use NSMassFormatter. Now, NSMassFormatter, as well as NSEnergyFormatter and LengthFormatter, assume that under the hood you are working in metric units. So when you assign a float here to the variable weight, it assumes that you are working with kilograms. So you initialize an NSMassFormatter, you set its unitStyle to long, and then, furthermore, you call 'string from kilograms' on the weight in kilograms. This will return back in English 44.092, which is in fact a conversion of the units into those used in the United States.
Furthermore, in Italian you will get back 20 chilogrammi which is both the correct unit as well as the correct translated term for the amount of weight that you are providing. So using NSMassFormatter makes it super easy to present in units for your user. Now, new in iOS 9, we allow you to format names -- iOS 9 and El Capitan. Now, to see why this is useful, let's take a look at two names side by side.
The first is "Grace Murray Hopper." This is a famous computer scientist from the United States. She coined the term "bug" and invented the first compiler. Additionally, let's look at a Chinese name, "Wang Dongling." Now, this is a famous calligrapher, who does the calligraphy outside of the Hangzhou Apple Store. So, both of these have three parts to them. But the way we interpret them is important and different.
In English we would typically call this the first, the middle, and the last name. We will see what happens when we attempt to apply this concept for a Chinese user. What was formerly the last name is now, spatially speaking, first from left to right. The middle name itself doesn't exist at all. And what's formerly the first name is now, spatially speaking from left to right, the last name. So, we can see here that terminology is important as well as the labels we choose to apply to these concepts.
So we are introducing NS Person Name Components and NS Person Name Components Formatter. We have already gotten the joke that people can't fit this into Tweets. But it's a little long and it's a little difficult to work with, but, that is to say, it's very precise as to what it does. It formats person names.
So here is how you would use it. You initialize an NS Person Name Components object. You populate the given name, the middle name, and the family name fields. Here is how you would do this for an English-US user. For a Russian user, then, you would populate "Fyodor Mikhailovich Dostoyevsky." Likewise, you are populating the same fields.
Here is then how you would format it. You initialize as NS Person Name Components Formatter object. As we've seen with other NS formatters, it has a style component. Here we specify short style. Then you call 'string from person name components' on your Person Name Components object. The result of this call is the following, for our five available styles: default, short, medium, long, and abbreviated, we have done the right thing for each language.
A couple of things to note here, that in fact the short style differs depending on, one, the user's locale, and depending as well on the individual user's override settings within the mail, contacts, and calendar settings. As well, for Russian names, we have determined that abbreviated names in this form with first, middle, and last all shortened to the first character doesn't really exist and so, therefore, we have fallen back to the short style.
So it's really easy out of the box to format names for your users. So that's numbers, dates, times, units, and names. We have looked at how you can translate now, translate the strings in your UI, how you can format the units the users are seeing. Additionally important is how you handle text received from the user.
Now, this involves looking at what a character is, how it changes based on casing, how you search for that character, and, as well, how you transform that into another script, for instance. To begin with, with this section, let's ask a philosophical question. What is a character? To begin with, let's ask, how many characters is this emoticon? This was introduced recently on iOS and it's possible to type this on our keyboards.
The answer here is not immediately straightforward, although visually it constitutes a single unit. Under the hood it's represented by one, two, three, four, five, six, seven, eight individual characters. Now, actually these are Unicode code points and depending on the encoding you are using it may in fact be more than 8. It may be 11, for instance, but, that is to say you shouldn't have to think about this.
Now, one place where this becomes really obvious is in enumerating over a string. Let's say you have a string test followed by the emoji character we just discussed. Now you wish to enumerate over each character within the string and call 'character at index.' This will return the unichars constituting the individual string.
But this isn't what you want. In fact, this presents question mark characters and sometimes three unprintable characters, and there is a heart in the middle for some reason, so it's not, this is definitely the incorrect way to do this. The correct way to enumerate over a string is to call 'enumerate substrings in range.' Additionally, you pass the 'by composed character sequences.' This makes it such that the under the hood representation matches the user's visual representation of the character. Therefore, when we call it on this string, we get back exactly six characters. So this is how you would enumerate over a string. But sometimes you wish to transform that string into a different form.
New in iOS 9 we are providing the ability, iOS 9 and El Capitan, we are providing the ability to transform that string. So let's say your string is "istanbul." A naïve way to capitalize the string would be to simply call the 'capitalize string' property. For English-US users this may look correct. Indeed, this is, for English users, the correct way to capitalize this. But for a speaker of Turkish, the dotted lower case i in fact becomes a dotted upper case I.
To immediately gain the benefit of this, you can simply call 'localized capitalized string' on that string. And, therefore, you will get the appropriate capitalized representation of the string, that is to say, the string with the first character upper cased. Now, in addition to 'localized capitalized string, we are also providing 'localized uppercase string' and 'localized lowercase string.' Here is what these look like.
So you can out of the box make use of these characters by simply using the localized variants of the already existing APIs. So, that's how you transform the case of your string, but let's say you wish to search for a string within another. Here is also where we get back to our question, what is a character? And what are our users expecting when they expect to search for a given string? So, let's say we have the variable here representing the German word "uber." Now this has a capital U, and happens to use an umlaut over the U.
A user might expect, given the way we typically write this word in English, that lower case "uber" will find the string. As a developer you may call 'range of string' to find it, when in fact this will return nil. The correct way to search for this, and new in iOS 9 and El Capitan, is 'localized standard range of string.' This will allow you to search for this string within the other using diacritic insensitivity as well as capitalization insensitivity. Additionally, it provides allowances for a given user's locale. So, here, we've found the lowercase string "uber" within 'capital U-umlaut-ber' by simply calling these new APIs.
So, in addition to searching through the string, sometimes you may wish to transform the entire string. Now, this is where transforms come in. Transforms allow you to translate between an uppercase and a lowercase variant of an entire string. Additionally they allow you to do Unicode normalization. That is to say, they take out the diacritic characters and separate them out, such that A with an umlaut becomes A plus umlaut character. Additionally, we allow you to script-to-script conversion, or transliteration. That is to say, going from Chinese Han characters to their Latin representation. Now, formerly this was available to you only at the Core Foundation level.
New in iOS 9 and El Capitan, we allow you to access this at the Foundation level. You simply call a 'string by applying transform.' Then you provide a string or here a constant, representing how you wish to transform the string. Here, we wish to translate the emoji character or, sorry, transliterate the emoji character "thumbs up" into an XML representation.
To do this, it's as simple as calling 'string by applying transform' and provide 'NS String Transform to XML Hex.' We additionally provide such transforms as Han characters to Latin, and between different European scripts as well. So it's super easy, then, to translate, transliterate your string from one script to another, and provide transforms from your individual characters to different representations. So, that's how you handle text within our operating system as received from the user. Additionally important is the way you lay out visual elements on the screen.
Now, here is where auto layout comes in. Auto layout was released several releases ago and the original intention was to format given UI differently based on the amount of screen real estate available to you. This has become increasingly important as we've released different form factors for our devices both on iOS and OS X. But I should say an additional benefit of auto layout is in localizing the UI of your application.
Here is what a UI would look like. So, let's say, for instance, we wish to add a new calendar to iCloud. Here is what a sample UI may look like in English. This UI may have been worked on meticulously and may work when you test it in different orientations and may work even dynamically with content added at runtime. But if you haven't taken allowances for how this works in other UIs or in other languages, in fact it may break these assumptions that you've had up until now.
So here is the same UI in Greek, and this may work, this may seem to work on first glance. When you take a little closer look, we realize, in fact, this character is now 3.5 characters long. There are additional sections of the UI that have this problem as well.
Now, I should say that it's not necessary to localize your app to test it in a different localization. Thanks to XCode's Skin menu you can test your app using a double-width pseudo-language, as well as a right-to-left pseudo-language, that doesn't require you to have a translation on hand to see how your UI would operate in different contexts.
So, assuming then you are using auto layout and you have set your hugging priorities and your compression resistance priorities correctly, here is what your UI would look like. We have seen what was formerly 3.5 characters is now 12. This is a huge difference. We have allowed our label to expand the available space given to us by specifying not static constraints but rather those that can grow. We say that the constraint is less than or equal to the width to the edge of the screen.
So, for a lot more information about this, I would really encourage you to check out yesterday's talk, "Mysteries of Auto Layout, Part 1 and 2." Those go into a lot more detail about how you can use auto layout to make your app work around the world, as well as for different device orientations.
So, also a thing to keep in mind in laying out your UI is that table cells themselves may change size. This relates to dynamic type. On the left, we have an English-US UI, on the right, we have Hindi. Now, notice that, actually, individual cells are different heights here. This is because the cells are auto resizing. We have allowed the cells to take up the amount of space dictated by the line height of that language.
So if you use standard UI controls and UI views, you will see, you will get this behavior for free. But important to keep in mind from a developer perspective is that you shouldn't assume that a given table cell will be a certain height. It may expand in different locales to take up a different amount of space.
So additionally important and critical in iOS 9 is that we have now provided full support for right-to-left languages. On the left, we have an English UI, and on the right, an Arabic. Now, the changes here are deep. We have gone through the standard controls and views, and switched the overall control flow.
In English, you would go from one menu into a detail menu by going left to right. Now, in right-to-left languages you go to right to left. Note that the chevrons themselves have shifted. The accessory views are on the other side and much of the text itself has been flipped.
Important to keep in mind, though, is not everything in the UI may shift, and may not automatically shift for you. Sometimes you may wish to customize the behavior. As we see here in the 'do not disturb' icon which is, in fact, still left to right, as well as the Latin text which is still left to right as well.
Now, for a lot more information about this, I would really encourage you to check out "New UIKit Support for International Interfaces" which happened yesterday. This goes through how you can use standard controls to make use of and gain the benefit of the full right-to-left support in iOS 9, additionally how you may wish to customize this for your individual app needs.
So, overall, it's important to remember to keep in mind in internationalizing your app, first the localization aspect, how it is that your strings are translated, how it is that the concepts behind the translations are themselves translated to your users. Additionally, formatting, how it is that units, dates, numbers, times, and now names are formatted to your user.
Handling text, how is it that you take the text from the user and perform operations on it. This brings back the eternal question, what is a character? Something you should always keep in mind in processing text. Finally we have layout, how it is that your UI elements appear on the screen to international users. Now, luckily if you're using the localized variants of existing APIs, as well as standard views and controls, you should get all of this behavior for free. Now, if you keep all of this in in mind, you will find internationalization opens the world to your application.
For more information, do check out these slides here, or do check out the documentation here. Contact our developer forums or our App Frameworks Evangelist, Paul Marcos, and also check out these related sessions. These have in fact already happened, so check them out in your app or online. Also, however, we will be offering an internationalization lab today from 11:00 to 1:10 p.m. So do come check us out. I will be there as well as my team to answer questions you have about internationalizing and localizing your apps. So, thank you. [Applause]