Advanced Topics in Internationalization

Session 201 WWDC 2014

Making your app appealing to customers around the world requires more than basic localization. See how to tackle the complex aspects of making your app truly world-ready. Learn about the latest developments with internationalization on iOS and OS X, and learn from case studies illustrating common pitfalls to avoid and simple and effective techniques. Find out how to give your users a great experience no matter what language they speak or where they live.

All right.

Good morning, everyone.

Good to see you all here bright and early.

We're here today to talk to you about internationalization.

Now if you've been following along with our previous years' talks on international support then you know that the App Store is available in many, many countries worldwide, more than 150 by last count.

So I'm sure you've all made your apps localizable, so you can send them out to localizers and make them available in multiple languages.

Is that sufficient though?

Well, not necessarily.

You need to take some care with regard to internationalization, otherwise you might end up with complaints like say, half of the contact names show up backwards in their app.

Or, the dates in this application are unreadable.

Or, my text is all messed up.

Working in this area we've seen problems like this occur many, many times, and we're here today to tell you how to fix them.

What we're going to do is, first of all, we'll run through what we have that's new in international support in Yosemite and iOS 8.

Then we'll go into detail about language and locale when you use what.

And then we're going to run through a number of case studies, problems that we've seen in internationalization and how to fix them.

So let's start off with what's new in internationalization and the latest releases of our operating systems.

We have a number of nice, new features, both at the user level and in APIs at the developer level.

So at the user level we have for iOS, a number of new localizations and some new keyboards.

We've redone the iOS language and region settings.

And we have some new improvements to lunar Calendar support.

Then in API at the developer level, we have an API for string encoding detection.

We have some interesting new formatters and something new called formatting context, which I'll go into in a few minutes.

So let's start with the new localizations and keyboards we have for iOS.

We have new localizations for Hindi, for Indian English, Canadian French, and Hong Kong Chinese, and some new keyboards.

First of all, for three Indic languages, Bengali, Marathi and Urdu, to go along with our existing Hindi and Tamil keyboards.

And we also have keyboards for Indian English, Filipino and Slovenian.

And there are a number of other new things like new fonts for various scripts worldwide.

Second, so you may recall that in Mavericks we redid the language and region settings for OS X.

Well this time around, it's the turn of iOS.

And in iOS 8, we've redone the language and region settings, and they look something like this now.

So you can still as always specify the primary language for localization.

But now in addition, in iOS you can also specify, users can specify the whole list of their preferred languages in order.

So one thing this allows you to do is to localize your apps into localizations for which Apple does not provide a primary OS localization simply because the users can specify those ahead of one of the localizations that Apple provides, and then your app will run in those languages for the users who need that.

There also is an advanced setting that allows specifying the language of the region format independently of the localization.

We make them the same by default, but users can change them if they like.

And we'll go into that in more detail later on.

We have some improvements to our support for lunar calendars.

So in our Calendar applications, we now have the support for turning on, as an overlay, lunar calendar dates in addition to Gregorian dates.

We also have a couple of new Calendar options.

These are variants on the Islamic calendar.

Let's take a little closer look at what the, so this is Calendar app with Chinese calendar, lunar calendar dates, turned on.

You see, they show up as an overlay underneath the Gregorian dates here.

It's very useful for Chinese customers.

And here's what this looks like in OS X.

And see here the Gregorian dates on the right and the lunar calendar dates on the left.

At the API level, these are APIs available at the foundation level on both iOS and OS X.

So you may recall from some previous years' text sessions, we talked about the unfortunate situation that can occur when you have a TXT file or some other chunk of external text and you don't happen to know what encoding it's in.

Well, in that case, you may have no other option but to try to guess the encoding from the text.

We now have a specific API to do that automatically for you based on all the evidence that's available from the text.

And it's very handy.

There are lots of options.

You can have it do the whole conversion for you once, or just tell you what it thinks the encoding is.

You can have lossy or non-lossy conversion.

And if you happen to think you known what encoding it's likely to be in, you can specify those, or you can require it to be one of a certain list of encodings.

We also have a number of nice, new formatters.

So NSDateFormatter is great if the thing you're trying to format is a date, a particular moment in time.

But what if what you're trying to format is more like an amount of time, extent, or an interval.

We have NSDateComponentsFormatter for displaying durations or amounts of time, number of hours or minutes or weeks or what have you.

You can specify the amount of time either as a start and an end date or a time interval, or you can specify all of the components individually if you like.

Then you can specify how it's supposed to be formatted with one of a list of date and time styles.

And you can also get to specify exactly which of the components you want displayed.

And there are some interesting things too.

You can turn on, in a locale-sensitive way, you can add language to it that says "about" a certain amount of time, if this is an approximate time.

Or the locale-sensitive way of saying "remaining".

For example, if this is a sort of countdown of some sort.

So here are some examples of this in various languages.

You can as I say, choose various styles, either a lengthy spell-out kind of style, something shorter, something very short and numerical only.

And the last line shows the "about" option.

Now one thing I want you to notice here is that some of these have their first word capitalized.

Well that's appropriate since they're showing up in the table here.

But there are other contexts where you might want these not to have the first word capitalized, say if they were showing up in the middle of a sentence.

And I'll talk about that more in just a minute.

Another new formatter, NSDateIntervalFormatter, if what you're trying to display is a range of times from some beginning time or date to some end time or date, you might want in this case to say, not to shown only once the pieces that are common to the start and end date.

NSDateIntervalFormatter will do that for you.

You provide the start date and the end date.

You can specify again any of a list of date or time styles or a template for full control over which pieces get displayed.

So here are some examples of this.

And again, in various languages, so you can see it can show a range of dates, or a range of times, or a range of dates and times, and appropriately the pieces that are common to the start and end are only shown once.

We also have some specific formatters for particular kinds of quantities: energy, length and mass.

That's NSEnergyFormatter, NSLengthFormatter, NSMassFormatter.

This is very useful, for example, if you're working with HealthKit and you're trying to display, say, the number of calories a person has consumed, or how tall they are, how far they run, or how much they weigh.

And it will show these numeric parts plus a localized unit.

You can specify the exact unit you want, or you can request locale-appropriate unit, whatever's standard in that particular locale.

There's a number formatter attached to it, so you can use all the number formatter options for formatting the numeric part.

And there's a special option you can check if that mass is particularly for a person's weight or if the energy is particularly for food because there may be particular standards for displaying those.

So here are some examples of that in various languages.

You can see that the units vary, and the numbers, you can choose an appropriate format for those.

Finally, formatting context.

Now remember as I mentioned before, you may need to have a piece of text that's formatted.

You might want to capitalize differently depending on where it's showing up.

And for some languages there are other transformations that may need to apply depending on where it shows up in your UI.

So we have a new property of formatting context available for date and number formatter and date components formatter and byte count formatter currently.

It's the formatting context property.

It's one of an enumerated set of values to specify where this formatted thing is supposed to end up so it can be capitalized or otherwise appropriately changed for its context.

You can choose the standalone context, for example, if it's going to appear by itself in a field.

So that might be capitalized.

The list item context, say, if it's going to be in a menu or something like that.

The beginning of sentence context, again usually capitalized.

And the middle of the sentence context probably will not be capitalized.

But, it may happen that your formatted result is going to show up, it's going to be inserted into a localized string, and you don't know a priority without having that localized string yet whether it's going to be at the start or somewhere in the middle.

So we have another value, the dynamic value.

You just specify that and then once it's inserted into that format string, it gets automatically, it automatically detects whether it's a start or in the middle, and it will capitalize it or otherwise change it appropriately automatically.

So that's what new.

And now I'm going to bring up my colleague, Deborah Goldsmith to go into detail about languages and locales.

Thanks, Doug.

Hi, everybody.

Today we're going to talk about languages and locales, the differences between them, and how to use them.

So Doug just showed us the new language and region settings in iOS 8.

Here you can see an example.

On the left there's the language settings.

And you can see there's a list of three languages, English, simplified Chinese, and traditional Chinese.

On the right, you see the Region or Locale setting, and that's showing a region of United States which, together with English, makes a locale of U.S. English.

So, why are there two preferences?

What are they used for?

Well, the language setting keeps track of which languages the user prefers to use.

The Region or Locale setting keeps track of which regional conventions they want to follow.

It's worth pointing out that neither of these indicates the language that users use in documents.

That might be the same language, but it might be something completely different.

And we'll talk more about that a little later on.

So, let's look a little more closely at the preferred language list.

What uses it?

Well, probably the most important thing that uses the preferred language list is NSBundle.

It uses that information to pick the localization that your app uses when it runs.

But it's also used by NSString.

NSString has several language-sensitive operations such as localized string comparison or breaking text into words or sentences.

And NSString uses the preferred language list to determine which language to use for that.

It's also used by WebKit.

Every time WebKit sends a request to a web server, it includes in the HTTP header a field called Accept-Language, which is essentially the preferred language list.

The web server looks at that information and uses it to decide which language to use for the page it sends back.

The list is in preference order from the user's most preferred language to the one they want to see last.

Any languages that the user is not interested in don't appear in the list at all.

So, effectively, it's a little more complicated than this, but effectively what apps and websites do is step through the list in order, and they look for the first language that they support.

And then they use that as their localization.

If they don't find a language that they support, then they'll use a default that depends on the particular application or website.

By contrast, NSString will use the very first language in the list always as the language for language-sensitive operations.

It's worth pointing out that when the user changes the language preference, apps don't pick it up until the next time they restart.

So, they'll keep using the old setting until that happens.

So now let's talk about the Locale or Region setting in a little bit more detail and see what it's used for.

Well, most importantly, it's used for the locale, in particular, the current locale.

It determines the properties of that locale, many different properties that determine the regional conventions.

In turn, that controls the behavior of formatters, both the familiar daytime and number formatters that have been around for a while, and also all the new formatters that Doug just talked about.

It controls the behavior of calendars, both the calendar that you're using, for example, you might use the Gregorian calendar in one country or the Thai Buddhist calendar.

But it also controls other calendar aspects such as what's the first day of the week?

Is it Monday, Sunday or something else?

Now in contrast to the language preference, when the user changes the locale preference, apps don't need to restart.

They're supposed to pick up that new setting right away.

And we'll talk a little bit more later on on how to do that.

So, what is the locale anyway?

Earlier we saw one example of the U.S. English locale.

There was a language, and there was a region.

But locales can have many more attributes.

There can be an optional script.

For example, you might need to indicate whether you want to use Arabic or Cyrillic script with a particular language.

There can also be keywords added which fine-tune the behavior of the locale.

So let's look at one hypothetical example.

Let's look at a particular user's current locale and print out its identifier.

There it is.

So, let's pick it apart and see what each part means.

So the first part is the language.

That's Urdu, in this case.

The region is India, so what the user is saying is they want to see their dates, times and so forth in the Urdu language and following the regional conventions of India.

But the user also has some keywords to do some overrides of the default for that particular locale.

For example, the default calendar in India is the Gregorian calendar.

But this user wants to use the Islamic calendar.

Perhaps they do a lot of business with people in the Middle East.

In addition, the default currency for India is the Rupee, but this user says they want to use the U.S. dollar as their default currency.

Again, perhaps because they do a lot of international business.

So locales have a lot of information in them, but you shouldn't get all the information that you need out of the locale.

There are some things you should get from elsewhere.

So, you might think that because there's a region in the locale that that's where the user is located.

But the region just indicates their preference for certain things.

It doesn't mean that that's where they actually are.

I can have my region setting as India.

That doesn't mean that I'm in India.

So if you need to know where the user is located or, more precisely, where their device is located, use CoreLocation.

Again, the locale has a language associated with it.

But that's not necessarily the language that your application is running in.

So if you need to ask localization questions, use NSBundle, not NSLocale.

As I mentioned earlier, the language the user uses in their documents may not be the same languages as either the locale or the localization language.

Typically you don't need to know what language is in a user document but, if you do, you can use NSLinguisticTagger.

Again, the region and the locale is just a preference.

It's not something you should use for regulatory or legal purposes or determining which kind of credit card to use or whatever.

For that you'll have to use other means, probably talking to a server.

Again, if you're doing financial or commercial transactions, they'll be in some particular currency.

But that's not necessarily the currency that's indicated by the current locale.

You should use some other means, probably having your server tell you which currency to use.

Now if you know the currency, if you know the three letter ISO code, you can set that on a number formatter, and it will then format amounts in that currency using the user's preferences.

It won't do conversion between currencies though.

You'll have to handle that yourself.

Now we've discussed some of the differences between languages and locales.

So how do you read those preferences?

Well, typically you don't have to.

The system handles this for you.

All of the formatter objects, including the new ones, calendars, locale objects-they'll all use the user's locale preference by default.

You don't have to do anything.

If you're doing localization, use NSBundle, and that will use the user's preferences for you.

You don't need to read them directly.

And again, if you're doing language-sensitive operations using NSString, like localized comparisons for sorting or searching, NSString will do the right thing by default.

But you say, "I have some application in mind.

I have some kind of decision I need to make about behavior of my application.

Or I need to get localized resources that are elsewhere.

So I really need to read these preferences."

Well, even in that case, you don't need to quite often.

So for example, you might think you need the language that your application is running in in order to control behavior.

Say you wanted to do something when it's running in English, but you don't want it to do that when it's running in Japanese.

Well you don't need to read the preference for that.

You can use NSBundle to make this decision for you.

If you wanted to do something when it's running in English but not Japanese, put a localized resource in your bundle, which has the value "yes" for English but "no" for Japanese, and your application will pick up the right behavior automatically.

Now if you are getting localized information from outside your application, then you might need to know the language you're running in, and we'll talk about that in a little bit.

Similarly, if you have a set of language resources from elsewhere, say, they're stored on a server and you need to pick the right one, you might think you'd need to read the user's preferred languages.

But NSBundle can handle this for you.

There's a class method, preferredLocalizationsFromArray.

You hand it an array, which is a list of language identifiers which represent your localized resources, and it will match that against the user's preferences and pick the right one for you to use.

You don't need to read the preferences directly.

And this will use the same logic that NSBundle uses when picking localized resources out of a bundle.

And again, if you need to know the language content of a document, which is unusual but sometimes necessary, you can use NSLinguisticTagger.

One thing to keep in mind is that a single document can have more than one language.

And in fact, you can have different languages appearing even in the same paragraph or sentence.

So, suppose you do need to get some localized information from outside your application's bundle.

How do you go about doing that?

Well, the first thing you need to know is what language your application is running in right now.

That's actually pretty straightforward.

You just get your main bundle.

You ask it for its preferred localizations, and the first object in that array will be the language code for the language your application is using right now.

So, what's an example of something you might use that for?

Say your application displays the names of currencies.

You could ask your localizers to localize the names of all the currencies for you and put it in your application bundle.

But that's unnecessary, and NSLocale has that information.

So you can ask a locale for the localized name of a currency, but if you do that with the current locale, you'll get it in the language of the current locale which may not be the same language that your application is running in.

And then you'll have a mismatch where the UI of your app is in one language, but the currency names are showing up in another.

So to avoid that, what we do is we make a locale using the language ID that we computed in the previous slide.

So we take the language ID our app is running in.

We make a locale from it.

And then we ask that locale what the localized name of a currency is.

So here's an example of what you'll get for three different localizations for the ISO currency code CNY: English, French and Chinese.

Similarly, NSLocale can give you localized beginning and end quotes.

And if you want those quotes to match the language that your application is running in, again, you make a locale using that language and then query it for the beginning and end quotes.

If you wanted the quotes to match a different language, say you've retrieved a webpage and you want to insert quote marks in it, then you would use that language to create the locale and query it for the quote marks.

So here again is an example of what you'll get for three different localizations: English, French and Japanese.

So I mentioned a few slides back that the user can change their locale preference, their Region setting, and apps don't need to restart for that to take effect.

Apps are supposed to react to it.

So let me show you what a lot of apps do when the user changes the locale.

Well, unfortunately, they don't react to it.

And the user is forced to quit the app and restart it in order for the change to take effect.

So let's talk about how we're supposed to handle this.

So the first thing you need to do is listen for the notification which is NSCurrentLocaleDid ChangeNotification.

. If you have objects around that use the locale like formatters or locale objects, you'll need to update their locale property.

But there's a workaround for this.

If you set up the object in the first place to use the auto-updating variant of the current locale, you don't need to do anything.

They'll be updated automatically.

But there's still some work that needs to be done.

If you have a date formatter, for example, that is using template formats, you'll need to regenerate those based on the new locale.

And, of course, any strings that you formatted using your formatters need to be created again to reflect the new locale.

And, finally, if you want the change in the locale to be reflected on the display, you need to invalidate any views that are showing that kind of information.

So here's a very simple example.

First, we set up a listener for the NSCurrentLocaleDid ChangeNotification.

. And when the user changes their preference, here's what we do.

So assume there's a date formatter.

The first thing I'm going to do is update the locale property with the new value of the current locale.

Now again, if I set that locale property with the auto-updating current locale, I could skip this step.

This particular date formatter is using a date format generated from a template.

And since that generation depends on the locale, I have to do it over again.

So I call the class method on NSDateFormatter, pass it the new locale of the formatter and regenerate the date format.

Finally, I mark myView dirty so that everything gets redisplayed.

And in this case, I'm assuming that the draw method of the view will call the formatters to regenerate all the strings for dates, times and so on.

And now I'd like to ask Karan Misra to come up to talk about some case studies.

Karan.

Thank you, Debbie.

Hello. I'm Karan Misra and I'd like to talk to you a little bit about making your app work for international customers.

Now this is a very normal looking time string.

And this is a time that's appropriately formatted for U.S. English.

What you might not have seen before is that iOS and OS actually support dates and times in many different languages.

And here are just a few of them to show you the variety.

So some of the differences are, of course, you might not even have an AM/PM marker because it is 24-hour time.

But, of course, even if that marker is there, it can take many different shapes and sizes and go in different places.

So what do you need to keep in mind about this?

Well, let's take two examples.

On the left, you have U.S. English.

And, on the right, you have simplified Chinese as spoken in mainland China.

This is a common problem that we see in many apps, which is that a format for U.S. English is applied to Chinese.

To a Chinese user, this looks very wrong.

Similarly, here's a perfectly formatted date for U.S. English.

This is not a perfectly formatted date in Chinese.

In fact, it looks like nonsense.

The date on the right is what a Chinese user would expect to see instead.

And, just to turn the tables around, here's a date that's well formatted for Chinese with the day, month and year.

Of course, in Chinese, it's year, month, day.

And here's what happens if you take that order and apply it to an English date.

As you can see, what you would expect to see is something on the right-hand side.

And when you see something on the left, it doesn't just look wrong, it looks blatantly wrong like it's broken.

So how do we avoid making these faux pas?

Well, the first thing is, don't use a fixed format.

Fixed formats will work for a fixed language and not work for all the languages.

So, now you might look at the English UK example in the second row and say, "Well, that looks fine.

It's English and it makes sense".

But what you might not imagine is, even if you just cross the Atlantic, the formats change pretty drastically.

So in UK English, for example, it's 3 June instead of June 3, and they use 24-hour time by default, so you don't have the AM/PM marker.

So what's the right way to do this at the API level?

Well, localizedStringFromDate is going to get you a date that is properly formatted for the current locale.

And you pass in a dateStyle and a timeStyle, and that determines how succinct or verbose you want your dates and times to be.

And it formats the date appropriately for all your locales.

Now you might come back to me and say, "Well, that's not working for me.

I need something more custom."

So, the first step on your journey to custom dates should be looking at dateFormatFromTemplate.

Now this allows you to specify a template and, within the template, the template contains information about exactly what elements of the date and time you want to show.

And then you pass in a locale so that the template, it gives you a format back from the template.

And then that format is appropriately, is appropriate for the locale that you passed in.

And then finally you set that format on the formatter to get your dates and times.

Now of course, you might still come back to me and say, "Well, none of the preset styles work for me, and none of the template formats they work for me.

So what should I do?"

Well, it becomes a little more complicated as you can see.

But the basic idea is you might have a custom format but you probably have not considered every possible locale in the world.

So, don't apply your custom format to every possible locale in the world.

If you have a custom format for U.S. English, check for English U.S. and apply just to English U.S..

And, of course, if you have custom formats for other locales, check for those specific locales and make sure to fall back to the default in your else case.

And that's all there is to dates and times.

Next, let's move on to names.

Now very similar to dates and times, names come in many different languages and scripts and formats.

And here is what happens if you apply a name format intended for Chinese to an English name.

It doesn't look very good.

And believe me that this Chinese name looks just as awkward to a Chinese user because it's using an English name format.

So, what's wrong here?

Well, most commonly what we see is that a fixed format has been hard coded.

And when you use a fixed format, it's only going to work for some names.

So clearly, this is not the right approach.

Now what might not be super intuitive is that even using a format obtained from the current localization will not give you the right formatting every time.

Why? Now, if you're living in the US, most of your contacts might be in English.

But a lot of customers, especially those in Asia, most often have contacts in at least two languages, if not more.

Say Chinese and English or Japanese and English.

So with the fixed format obtained from the current localization, you might format, say, all Chinese names right.

But you might then get all the English names wrong.

So that's just not a good experience.

So what should you do?

Well, there's a great API called ABRecordCopyCompositeName.

You pass it a record from Address Book.

It'll give you back the name to display.

It's that simple.

There's no code underneath.

And this API, of course, it encapsulates a lot of logic that we have designed that takes into account the language of the contact, the user settings, and of course it has a lot of language-specific logic to then find the right format to show the contact in.

But you don't need to worry about that.

Just use this API.

Of course you might say, my contacts don't come from the Address Book, they come from somewhere else.

That's fine.

You can take the name information that you get from another source, create a temporary ABRecord, assign these values, and then ask for the display name again.

And of course, if you're using OS X, then there's a displayName API there too.

And that's really all there is to names.

Just use these APIs, and it'll be all right.

Next, I'd like to talk to you about right-to-left text.

So, first of all, don't think that just because you don't have a right-to-left localization, like Arabic or Hebrew, that you can stop listening.

This is important even if you localize just in English.

So what's different about these languages?

Well, they run right-to-left.

That's what's different.

And that actually causes a lot of issues.

So, there are two main topics here.

One is alignment, and the other is directionality.

Let me talk about alignment first.

This looks like a perfectly innocuous line of code, set alignment left.

I mean, what's the alignment for if not for setting it?

Well, it works fine for English text.

But if you set Arabic text in left alignment, it's kind of like setting English text in right alignment.

You might do it for a heading or for some special cases, but you don't format entire paragraphs of text in right alignment for English.

So that text is not very easy to read.

What's the answer?

Well, the answer is you should use natural alignment.

Now this lets the underlying frameworks determine what the appropriate alignment is left to right depending on the language and use.

And if you use this, you'll get nice left alignment for English and other left-to-right languages.

And you'll get nice right alignment for Arabic and other right-to-left languages.

So that's easy.

Let's move on to something less easy, directionality.

Now, directionality, in contrast to alignment, determines what the logical order and the visual order of the words is within a given run of text, like within a single sentence.

So what we see most commonly going wrong is that someone is trying actually to be helpful, and they take the fact that the app is running in Arabic or Hebrew, and they hard-code the base writing direction to right-to-left.

Why is this wrong?

Well, this is wrong because user content can be in any language, as Debbie mentioned before.

And you cannot assume the language of user content.

Now this is a sentence that's supposed to be in English, with one Urdu word in the middle.

So it's supposed to say, "WWDC is a fun conference."

It's not really saying that right now because it's using right-to-left text directionality, and that doesn't make sense.

So, what should you do?

Well, for any text view or text field in which you expect the user to type content, set the writing direction to natural.

Now again, that lets the underlying frameworks determine what a good best guess for the writing direction is.

In this case, it will take a look at the first few letters of the string, which is WWDC, and since those are left-to-right characters, it will take a guess that this string should go left-to-right.

And in this case, that produces the expected sentence, which is, "WWDC is a must conference."

So, of course, as I mentioned, it's a best guess.

And so you might have a sentence like this.

Now since you saw it animate in, you can see the order.

So you can see it one more time.

So Safari first, then [foreign language] in Arabic, and then Mac.

So, you might be able to tell, if you saw it being typed, that the user wants to say, "Safari on Mac."

But because it started with Latin letters that would go left-to-right, the directionality was assumed as left-to-right.

And so, you have the opposite sentence, "Mac on Safari."

So how do you fix this?

Well, this is the sentence you want to get.

And in order to get this order of the words, what you need to do is you need to insert a right-to-left mark at the beginning of the sentence.

This is an invisible character that you insert to control the directionality of the string.

And, of course, you might have a case that is the opposite, in fact, in which you start with, say, an Arabic word, which is right-to-left, and the OS will guess that the whole sentence is supposed to flow from right-to-left.

But what you intended was for the sentence to flow from left-to-right.

And, if you have a translation app, you might actually have already encountered a case like this.

And, in this case, the solution is to insert a left-to-right mark.

So, what you're probably thinking is, "Well, that's great, but who's supposed to insert these marks into the strings?"

because you might not have heard about them.

So the answer is, well it is you.

But, probably not exactly you.

What you need to do is to talk to your localizers.

Your localizers, and not just your right-to-left language localizers like localizers for Arabic and Hebrew, all of your localizers need to understand how these marks work.

Because they need to insert these in, for example, if there's a localizable string that starts with a format argument.

Now, when the user content comes in, that format argument could be replaced by an English word or an Arabic word or a Hebrew word or a French word, so you don't know at compile time what it's going to be.

So you need to insert, if you're in a left-to-right localization like English or French or German, you need to have a left-to-right mark there to tell it that even if an Arabic word comes in, I want the sentence to flow left-to-right.

And the same and the opposite for right-to-left localizations.

Of course, this is just a brief introduction to handling right-to-left text, or actually, mixed text I should say, and you should check our internationalization and localization guide for more details about handling more advanced cases.

Lastly, for right-to-left, I should mention that Xcode 6 has a great new feature which lets you simulate a right-to-left localization so you can run in English but in right-to-left and see how your layout flows in a right-to-left localization.

And of course, I highly encourage you to attend the Localizing with Xcode session which is later today to learn more about Xcode 6 and what it brings for localization.

Next, let me talk about the keyboard.

Now this is the U.S. English keyboard.

And, as you probably know from yesterday, we now have predictive typing.

So, what does this mean for you as a developer?

Well, even more than before, you need to keep track of the height and size of the keyboard.

So, I first of all hope that none of you have hard-coded the size of the keyboard anywhere in your apps.

And now, of course, if you do that, you're going to get a lot of one star ratings.

So, first of all notice that even when predictive typing is off, like on the left, there's still a thin bar on top of the keyboard.

So the height of the keyboard is still different from what it used to be.

But, not all the keyboards on iOS are predictive typing enabled.

So you still might have a keyboard like the Bengali keyboard, which is new in iOS 8, which does not have even the thin bar on top.

So already you have three different sizes.

Then we also have keyboards like Japanese and Chinese in which, before the user starts typing, it's the short height.

And, once they start typing, there's a bar on top and it becomes a tall height.

So, your app needs to accommodate these size changes on the fly.

And, of course, users will switch back and forth between these keyboards.

Not only that, but this is something you're probably aware of for sure is that when the keyboard comes up, your UI needs to move away if you don't want it to get hidden behind the keyboard.

So how do we do all of this?

Well, helpfully, the keyboard lets you know when it's coming in, going out, or changing size.

So all you need to do is watch for those notifications.

Now, what can you do with these?

Well, here's an example of Safari.

When the keyboard comes in, as you can see, the search field shrinks.

And I'll play it again so you can see that these two animations are actually happening in tandem.

So how do you make this happen in your apps?

Well, the keyboard will show, notification actually contains a lot of information.

First of all, it contains information about the frame, where the keyboard will start and where the keyboard will end its animation.

It also contains information about the animation duration and curve.

So actually you can use these two pieces of information together and make sure that your UI moves away from the keyboard and also moves in tandem with the keyboard so it gives a very smooth experience to the user.

We also have hardware keyboards.

So, iOS, any iOS device can attach to a hardware keyboard if you have Bluetooth.

And of course if you want to simulate it, there's an optional Simulator to do that as well.

So what does this mean for your apps?

Well, if you have an app like this, which has a toolbar above the keyboard, the important thing to keep in mind is that there's functionality like Choose Font in this case, which you don't want the user to lose when they attach a hardware keyboard.

So, this is not what you want when a hardware keyboard is attached.

What you want is this in which the toolbar at the bottom remains, even though a hardware keyboard is attached.

So how do you make this happen?

Well, if you do have a view that just goes on top of the keyboard, it's a one line code change, which is, to use inputAccessoryView.

inputAccessoryView allows you to specify the view, and that view is stuck on top of the keyboard.

And the keyboard takes care of animating it in, animating it out, and making sure it docks at the bottom when the hardware keyboard is attached.

Moving on to another keyboard topic: keyboard type.

Now keyboard types basically allow you to specify within the same keyboard different, specific, optimized keyboard types.

So for example, here we have the email type which is meant for email addresses, user names, etc. And as you can see, it has the @ and full-stop keys on the first plane to let you easily type those.

Of course, the punctuation planes are also optimized for email address typing.

And so you have more frequently used symbols there.

What you might not know is that in the keyboards for many languages, like simplified Chinese, Arabic, etc. many of the commonly used punctuation symbols for other languages are not the same symbols that are used for email address or URLs.

And so the problem is that, if you expect a certain kind of input in your text field and you don't specify the right type, the user might actually be forced to switch keyboards just to type an email address or username.

And that's not a very good experience.

So, make sure to specify the right keyboard type.

And, of course, we have more than just email.

We have URL, Twitter, NumberPad.

In fact, we have a whole host of different keyboard types.

And another one I would like to call your attention to is ASCIICapable.

Now if you have a textField or textView in which you are expecting content that is only in ASCII, go ahead and specify the ASCIICapable type.

That'll make sure that the user's keyboard is switched, for example, from Chinese to an ASCII keyboard automatically.

And they don't have to manually switch keyboards to do that.

You should also know about the autocorrection type.

So, for some of your textViews and textFields, autocorrection might not be useful.

In fact, it might actually hamper user input.

So, make sure to turn autocorrection off where appropriate.

Similarly, auto-capitalization has four options which are very useful for different contexts.

And these are all also language aware.

So you should use these appropriately depending on what kind of input you're expecting in a certain textView or textField.

And lastly, I want to talk about mark text.

Now you might never have seen this if you've never used a Chinese or Japanese keyboard.

But for these languages, when the user types, they do not directly type the output characters like they do in English.

But they first type usually a phonetic or other kind of input string and then they choose a candidate from the bar below.

Or it's above the keyboard.

So what does this mean for you as a developer?

The important thing to know here is when a textView or textField has marked text in it.

Because when it does have marked text in it, the number one thing you want to make sure is to not edit the content of that textView or textField.

Why? Because if you do that, their marked text will get committed to the document.

Pretty much no user wants that to happen because that is not the text they were trying to type.

And you're going to have some very frustrated users if you do that.

And of course, while the marked text is there, you can use it for other things like autocompletion or showing some predictions to the user.

But what you should remember is that this is not their final text.

And often the marked text is not going to contain meaningful linguistic content because it's just the input codes for that input method.

So, use it for live search if you'd like, but note that it might not be the user's final content.

And that is really all, well, that's not all, but I would say that those are the most common things you should keep in mind.

And let me just reiterate some of the items that we talked about earlier that will help prevent you getting a one-star rating from someone in Asia or the Middle East.

So, first of all, localize your app into tons of languages.

Of course, iOS and OS X both support a lot of languages, and we added new ones for both platforms.

And, starting in iOS 8, you can localize into many languages that Apple doesn't localize into, so don't let us stop you.

Secondly, understand the differences between language and locale and when to use them and when you don't need to use them.

Of course, format dates, times and names correctly.

As you saw, it's really easy to do.

And, note that there are a lot of right-to-left users on both iOS and OS X.

In fact, it's one of the most popular languages for input on iOS and OS X.

So, regardless of whether you localize into Arabic or Hebrew or another right-to-left language or not, make sure that you're not breaking text input for these users.

Keyboards, of course, come in many different shapes and sizes and-well actually, one shape, many sizes-and, of course, they come in new sizes with iOS 8.

So make sure you keep that in mind.

Of course, choose the right keyboard type for the context so that you make the input experience smooth and easy.

And don't touch the marked text if-don't touch the document while there's marked text in the document.

For more information, of course, you can contact Jake who's our App Frameworks Evangelist.

And we also have the Internationalization and Localization Guide that I mentioned previously up on our website that you should really check out.

We also have two sessions that you should definitely check out.

One is Localizing with Xcode 6, which is later this morning.

And, actually, we covered a lot of new material this year and we didn't actually repeat a lot of the material from previous years' internationalization talks, which are actually still relevant for your apps today.

So definitely go ahead and check out Making Your App World-Ready, which is last year's internationalization session.

Thank you very much.

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