Alright, good morning everyone.
I'm Doug Davidson, and I'm here to talk to you about making your app world ready.
So, the app store is available in more than 150 countries worldwide, and if your application is only targeted at one of them; not only are you missing out, but also a lot of your potential users are being deprived as well.
So, we're going to tell you how with a little additional effort, you can make your app ready for international use.
The steps to go through are fairly simple.
In many cases, we find that what you have to watch out for is assumptions that you may be making; maybe even unconsciously, that just don't hold everywhere in the world.
And, so we'll be talking a lot about that.
Often, it's not things you don't know that will hurt so much, as the things you do know that just aren't so.
Now, there are some genuine challenges here.
Our customers around the world use many different languages, many different writing systems, and they have often significantly different expectations after the presentation of items like dates and times and numbers.
But, fortunately, the frameworks are designed to handle this, if you work with them.
Now, I say frameworks, it's important to note that almost everything we're going talk about here today applies to both iOS and OS X.
Now, we're going to do this in three parts.
The first is about localization.
Localization refers to the language in which you application's user interface is presented.
Your job as a developer is to make sure that your application is localizable, so that you can go to the localizer, who will translate the text in your user interface into any particular language, then all you have to do is decide how many languages you want to do this for.
Second, we'll talk about locale data, and that refers to presenting things like dates and times and numbers in a way that's intelligible to people in that particular region.
And, finally, we'll talk about handling texts and all the different writing systems used around the world.
There are two main settings that are involved here, and this is what they look like on iOS.
The first is the user's language preference, and that's what determines which localization your app will run in, and the second is the user's region preference, which determines what their locale settings will be.
On OS X Mavericks, we have an entirely new pref pane for handling this.
It's designed to streamline it, and make changing the settings simple, and make it all more logical.
It's very similar.
You have the user's language preference again that determines what localizations will be used, and the user region preference that determines the locale settings.
Additionally, on OS X, there is an advanced sheet that allows the user to customize in great detail, if they want to, any of the various settings that are part of their locale preferences.
So, to start off with, we'll talk about localization.
I'll bring up my colleague, Albert Lund to talk about that.
[ Applause ]
Hello, I'm going to be talking about localization, and what localization is, is that it translates your application from its current language to another language, so your app can provide much more exposure and visibility to other markets around the world, leading to more downloads for your app.
It's also about adapting your application to cultural norms in those regions, so you can provide the same level of user experience for all users of your app.
Now, today, I'm going to be talking about how to use our tools and X codes to localize your application, as well as some common mistakes and issues that may occur when localizing.
So, here's your project is structured for localization.
You have your single binary, which is your header files, your implementation files, and libraries you call, and you only have one set of these files.
You also have localization folders alongside your binary, and these are folders called L proj folders, or your language specific project folders.
Each localization is placed into one of these folders, and it's abbreviated by the language.
So, for example, the English location is EN, French is FR, Spanish is ES and so on.
All of these localizations are then placed into your single app bundle, and one of these will get loaded at runtime.
Whichever one gets loaded at run time is determined by what the user selected system language is.
So, if the user's language is Spanish, the Spanish localization gets loaded.
So, here's how your project is structured.
You can see that the L proj folders are alongside your implication files and your localizers or your translators just have to modify these folders only; they don't need to touch anything else.
These folders contain things such as your strings files, which contains things such as your user visible text, as well as any resource files, such as images and anything else you might want to use for localization.
So, let's get started on how to localize things such as your interface files or your nib files or storyboards.
The old way to do this, and you can still do this today, is to make a copy of every single nib file for every single localization you have.
Your localizers then just open and modify the specific interface file for that specific localization, modify the text so it's localized, and make sure that everything surrounding it looks good and works for this interface.
Like I said, while these work today, if you want to localize this way, you can see this gets very cumbersome, and can be very time consuming for you and your localizers, so we highly recommend you use this method called base internationalization.
With base internationalization, you only need to modify one set of storyboards and nib files, so you don't have to worry about localization when it comes to your interface.
Every single time you create a new localization, a strings file, which basically takes all of the user visible text out of your nib file, is then placed into those specific language folders, and your localizer just has to modify those, the text only.
They don't need to touch your interface at all.
Now, it's highly recommended that you should use auto layout for base internationalization, and I'll explain what auto layout is in a moment.
But, here's an example how base internationalization works.
I have my one nib file here, and this is my base internationalization file.
As a developer, I only need to modify this one file, and every single time I create a new localization, a strings file is then generated for every single one.
From there on, my localizers then do not touch anything involving my interface.
They only need to modify the strings, and that's really convenient.
So, what's auto layout.
Auto layout is a way to define the constraints between text and anything surrounding your text, such as text views, UIImageViews, and pretty much anything that surrounds the text.
It is a way to appropriately resize everything depending on the length of the text, which is crucial for localization; the reason being is that when you translate your application from one language to another, some translated strings may be significantly longer or shorter, and you want to be able to dynamically adjust these, so your interface looks good.
And, to learn more about auto layout, I highly recommend you check out the video for "Taking Control of Auto Layout in X Code 5".
That was held yesterday.
So, let's get started on how to use base internationalization.
So in my project window for X code, I have this checkbox here called used space internationalization.
I check this box, and then X code will then ask me which files do I want to use for my base internationalization.
It will then move all of these interface files and any file I want into the base.Lproj folder, and anytime I want to create a new localization, I then push this plus button here.
Any interface files then that are placed in the base.Lproj folder will then generate their own strings files.
And, then again, my localizer just has to go into these strings file only, and have nothing to do with the interface, which is great.
Now, when you make an update to your interface, you also want to make sure that your interface is also localized as well.
And, we have a command line tool in OS X; we call it IB12, which will generate a strings file for you.
So, in this example here in my base.Lproj folder, I just pass in the nib file that I have changed, and run IB12 on it, and it will generate a new strings file containing all of the strings that were originally in this interface file.
I then go in and open this new strings file, copy and paste everything that has changed, or anything that I have updated or added, and paste it into every single strings file that has this interface file here, so it's very good to update.
Now, some issues that can come up with using auto layout, is that you may use the fixed width for auto layout.
This entirely defeats the purpose of auto layout, since you want to make sure that all text is resized automatically, and you don't want your interface to look bad on certain localization because you decided to have a fixed width between text and UITextView or something.
And, as always, it's good to prefer an intrinsic content size instead and as always if you, you should always try out your layouts in every single localization and test, so your app in those localizations.
Because what's works in one language, and what constraints may work in one language, may not necessarily work in another.
So, let's talk about the strings file.
The strings file contains the user visible text that will get localized and displayed in your app.
The strings file is placed into a key value table, and what happens is, is that the left side of the table is your key.
The key is what the application is going to be looking for to display what localized text should be displayed to the user.
So, in this example here, I have three localized strings files that are placed in three separate localizations; the English, simplified Chinese, and Spanish.
At run time, depending on what localization my user is in, one of these will get loaded, and one of these will get displayed.
So, if my application is looking for a name key, it will look in the name field for that specific localization, and display whatever is in the user visible text.
Now, you will also have some strings in your code or some user visible text in your code that you want localized as well.
To do this, you should use NSLocalizedString and use NSLocalizedString everywhere where you have user visible text, and NSLocalizedString has many variants that pretty much can do what you want it to do, so check out more details for NSLocalizedString in the release notes.
Here's an example of NSLocalizedString used in its most common case.
It takes in two parameters; one is a key, which what will get mapped to the localized text that you want, as well as a comment to the localizer, which I'll talk about later.
Once you localize your strings in your code, you want to make sure that you create a strings file that will have all these NSLocalizedStrings in one place.
You can do this manually, but there is a script that will do this for you, and it's highly recommended you use.
It's called gen strings, and it's highly scriptable and customizable.
You can add it to all of your X code billing phases, and to learn about gen strings, you just check out the amend page.
So, here's an example of how gen strings is invoked.
What happens here is that I look in the local directory for all files that end in .m, and run gen streams of every single one; meaning that it will go into all .m files, search for NSLocalizedString, and place a localizable .strings file into the English localization folder in this case.
So, I have a case here when I've run gen streams on two separate localization, my .m file contained this one NSLocalizedString, and I placed the strings file in the English localization and the Japanese localization.
You can see that the comments and the key have been placed in the appropriate positions, and now my localizer or my translators just have to modify the right side of the table to localize it to whatever language that this is in, and this is done right here.
Some issues that can come up with using NSLocalizedString is that you overload your keys, meaning you have one key that maps to many different places.
Let's say in your application, you ask the user if they want to save, and you have two buttons; one for yes and one for no.
You also have another button asking if they want to subscribe to the super popular catfacts, with a button for yes and a button for no.
You have one NSLocalizedString that maps to both of these, and this seems to work perfectly fine for your application.
However, later on in your development process, you start to realize that yes and no aren't very clear, and should be possibly save and cancel, but in doing so, you replace the string and you inherently break the other part of your application, and save and cancel doesn't really make any sense.
So, it's very important that you make sure that all user visible text has its own unique key, so you don't run into this issue where one part of your application inherently breaks another.
Also notice here that when I made the change to NSLocalizedString, the comments were also updated appropriately to reflect what was going on, which leads me to the second issue.
You provide no comments to the localizer or insufficient comments, it is your localizer's worst nightmare, and possibly like will hate you for this, if you add no comment provided, and yes equals yes, or not enough context.
While in English, for example, yes can mean many different things, in some languages, such as Chinese, the word yes has many different possible translations, and without any context or knowing exactly what's going on in your application, your localizer will pretty much be able to translate this part of your app.
So, it's very important that you provide enough context to the translators, so they know exactly how to translate your application properly.
The third issue is composing phrases together, which is something we as engineers do quite often; the reason being is that if you compose phases together, some languages have these conjugation rules and some grammatical rules that depend on other parts of a phrase or sentence, and without knowing the previous parts of your sentence, it will be grammatically incorrect.
So, for example here, I have three strings here, one for go to next blank, chapter, and then page.
In English, this seems to work perfectly fine, since go to next chapter and go to next page are valid and grammatically correct.
However, if I'm a Spanish localizer, and I try to translate this, I see go to next and then chapter.
Since chapter is a masculine noun, and I must have a masculine article in order to agree with chapter, this is going to work perfectly fine.
When it comes to page, since page is a feminine noun, the article must be feminine, but if I've already made it masculine, then this is inherently broken, and this localization is broken for Spanish.
So, it's very important to make sure again that your user visible text each has their own unique key, and you compose things in a sentence wise, or else, you're going to run into grammatical issues.
There are going to be some cases, however, when you are going to have to dynamically create strings, such as when it comes to the case of pluralization.
This is cases where if I want to display to the user I have 0 of something remaining, one of something, or more than one of something, and in some languages, this can get very complicated, where there's a different string for two to five of something or 10-14 of something and so on.
There is a new feature in OS X Mavericks and iOS 7 called strings dict, which a localized P list that essentially handles all these cases of pluralization for you.
You as a developer do not need to call any new API's, since strings dict will be called automatically, if it's available, and your localizers then just have to fill out this P list, and will handle all these cases for you.
To learn more about this in complete technical detail, check out the foundation release notes, but if you want to learn how to get the setup and have a brief tutorial about this, check out the "What's New in Cocoa Video" for the session that was held two days ago.
So, here's an example of strings dict on two separate localizations; one for English and one for Russian.
You can see that the English localization has very simple case with one and anything but one, and the Russian case can get very, very complicated.
Now, aside from text, which is the most localizing you'll probably be doing, you can localize other things as well, such as your images, your sound files, and pretty much anything can be localized.
To do this, you create a localized version of this file, and place it into the respective localization folder that you wish to load for this specific localization.
The API's you called to call for these specific files will automatically call the localized version.
So, there is no need for any extra code to handle for localization.
So, let's say I have an image here that I want to localize.
I push this localize button here, right there, and X code will then ask me where do I want to place this localization file.
In this case, I want to move this image file to the English localization, so this file will get loaded for the English localization.
Any single time I want to create a new localized file for this specific image here, I just have to create a file with the same name, and just place it into the specific localized folder that I want, so for example here, I have an RTF file that has been localized to several different languages, and all of these RTF files are placed into their respective L.proj folders.
Now some issues that can come up is that you have some text in your image.
While it's okay to have text in your image, be aware that your localizers will have trouble translating text in your image, as opposed to just translating text itself, since it requires a bit more effort to translate text in your image.
The other issue is having an image or something to convey a meaning to the user, since some images may not necessarily work in other languages.
So, for example I have a keyword search, and I use a key to denote a keyword search.
In English, this seems to work perfectly fine, since I see a key, I can think of keyword, since, you know, there's the same word, but in other languages, the word keyword doesn't necessarily translate to a key at all, since you'd come out to head word or focus word or indicative word, and your users will pretty much have no idea why you have a key for keyword, so the idea is completely lost in translation.
Another issue is having a cultural reference, or something that's specific to a specific culture, and this may run into some issues.
So, for example, in Japan, this image here is placed onto the back of all cars for anyone who is inexperienced or a beginner driver to alert other drivers that she should probably get out of the way.
Some Japanese developers sometimes use this to show that this is a tutorial or a beginner's guide to something, and if someone isn't well versed in the Japanese culture, or doesn't know anything about Japan, they pretty much have no idea what this icon is, and they'll get lost in your application.
So, make sure that any images that you have that display a meaning or try to convey a meaning to the user, is workable for all the localizations you want to support.
Now once you've localized your application, you'll want to test this out, and the most accurate way to do this, and to see exactly what your user is going to see, is to change the system language inside of your system to the language you want.
Also, the other reason is, is that some system services may not work in that localization until you explicitly send the language to that localization.
However, if you want to quickly check whether or not a string has been localized or a file loads correctly, you can run your application in X code using the dash Apple language as argument.
And, in this example here, no matter what language my system is in, it's going to run in the Korean localization.
A really cool way to check whether or not if your application has been localized, and to test out whether your interface will work for longer strings, longer strings, is to use pseudo localization.
So, what's pseudo localization?
Pseudo localization is a way, well, if you have your strings files, you can run a script through the user visible text in your string to modify it and distort it, such that it is longer than what's originally there, and will distort it to the point where if you were looking in your application to check whether or not some strings have been localized, you can obviously tell whether you're missing some parts or you forget to localize something.
And, with that, I'd like to bring back Doug up to show us a demo on how localization works.
[ Applause ]
Thanks Albert so in order to demo this out, we wrote a tiny little application.
So, what this application does is it lets me type in some brief little notes, and then it shows them in a scrolling list, really simple.
And, so the first version of this application that we have here is not localized at all.
Notice, it's not using base internationalization; that's turned off.
The only localization that's there is English, and if I look at my nib file, it's all in English, and if I take a look at my code, I notice that there are some user visible strings in here; for example when I'm creating an alert, they're just static explicit strings, and for setting the title of the window to reflect the number of notes, I have switched between one note or multiple notes, so it's all in English.
So, what that means is that if I go in and change my system into say German, and then run the app again, nothing changes at all, it's not localized.
So, the next thing to do is to create a new version of this application, and we turned on base internationalization.
What that does is create a base localization, and that's where our nib file goes, and then we added an additional German localization to this app.
So, if we take a look at our nib file, it has not changed at all.
The only thing that happened to it is that it moved from the English localization into the base, and in addition, we get a strings file associated with it that contains the translations; we added a rough and ready German translation here, to the various strings that appear in that nib file, and then we run the app in German, these will automatically be substituted into that nib, in place of all the places where the English text appears.
In addition in code, we took these explicit strings, and replaced them calls to NSLocalizedString with suitable keys and suitable comments for the localizer, and then for the title that reflects the number of notes, we're going to use a string sticks, to get appropriate localization of plurals in whatever language we're translating this into.
So, we ran gen strings on this, and the result is that we have localizable string files for English, and then for German, where we put in appropriate translations for each of the keys that appear in our NSLocalizedString, and created string sticks for details on the format string sticked file.
You can again, take a look at the foundation of these styles.
If explains it all in detail, but the business part of it, has these lines that describe what to do for, when the number is one, and what to do when the number is other than one.
So, for English, we chose a very simple set of rules.
For German, it got a little more complicated.
We have rules for 0, one or anything else.
And, let's see what happens when this ends up in our built application.
So, here we're taking a look inside the app bundle.
In the resources we have a base L.proj that contains our nib file, so there's only one copy of that, and then in German L.proj, we have just the strings file, the strings dict, and that credits file that X code wants to create for us, and when we run this, then the main menu.strings contents should be automatically substituted into our nib.
So, let's try that out.
And, we see one right now, the whole interface is in German.
We got our strings sticks has given us a proper title for 0 items, and even our menus are localized.
Even the Apple menu stuff, this comes from outside our app, all localized properly, and our localized strings show up in the alert.
So, that is the basic process of localizing an app.
Let me go back to the slides.
And next, I want to bring up my colleague, Nat, to talk about dealing with locale data.
[ Applause ]
Okay, hello, hello.
Thank you, Doug.
So, my name is Nat Hillard, and for this section, we will be going over locale data.
So, another critical aspect of making your app world ready, is presenting numbers, dates, times, and symbols in a manner that is appropriate for your users.
Now, to do this isn't just a stylistic issue.
It can have practical usability complications and implications as well, and ultimately, you can conceive of this process as translating between machine readable data and user readable strengths.
Now, interestingly, this is not a one to one mapping.
Things can get pretty complicated.
Now, luckily, we provided a set of API's for you that do a lot of the heavy lifting for you.
So, in this section, I'll be going over the first five in this table, and Doug will cover NSString in more detail in the next.
So, first of all, what is a locale?
In an abstract sense, it's a collection of user preferences with regard to formatting.
The users will set this, as Doug mentioned, in the region format preference on iOS or on OS X in the languages and format preference pane.
In a concrete sense, it is represented in Cocoa with the NSLocale API.
Usually as a programmer, you will not be dealing with the NSLocale object directly.
Instead, interacting with it at the class level or passing it in as argument to other API's.
So, important to keep in mind, however, is the distinction between a local and a localization.
Locale represents the formatting standards for a particular user.
These are informed by their region, their language, and their script.
On the other hand, localization refers to the language of the user interface.
Now, these can often be the same, but for a given user, they may differ.
As an example of using locale information to present, or locale data to present information to your users, let's take a look at formatting dates.
So, for this, we've provided the NSDateFormatter.
This converts between NS date machine readable data and a string representation for a particular user.
Often, you'll be working with this and explicitly attaching it to a text field within your nib file.
On the other hand, if you need to use it in code, you can call localized string from date; passing in your NSDate, as well as a date style and a time style.
So, what do these date and time styles look like?
Well, they differ in the amount of information they're presenting to the user about your NSDate object.
Here, they can vary from anything as short as a short style, where you're simply presenting numbers, to the full style where you spell everything out.
As well, as if you need to suppress either one of these, you can use no style.
So, to see what this looks like, we call localized string from date on the NS date formatter class.
We pass in our date, and we pass in medium style for date and short style for time.
Now, keep in mind this will do the heavy lifting for us, and present this information in a locale appropriate manner for our given user.
So, here we have three locales, English as used in the US, French as used in France, and Chinese as used in China.
Here we have the out of the box representation of a single NSDate object.
Here we have June 6, 2013, a presentation familiar in US English.
On the other hand in France, this API has done the work of presenting first the day number, followed by the month, followed by the year, and without a coma.
Also, in Chinese, we presented the year number first, followed by the character for year, followed by the month number, character for month, and day number, followed by character for day.
Likewise with times, we present AM in the United States.
We don't provide either AM or PM for France, which traditionally uses 24 hour time, and in China, we present the characters for morning, followed by our single time object.
So, this is the preferred way to work with NSDate.
Out of the box, calling a class method, localized string from date, you've gotten three very different representations from the same object.
If on the other hand, you want to present a custom view of this same NSDate object, you have to go beyond the certain present packaged styles.
Keep in mind that the medium style will always present the month, the day, and the year.
Let's say for instance though that you wanted to only present the month and the day.
So, when the default styles don't meet your needs, you create an instance of the NSDateFormatter class.
From there, you create a format string.
This is done with date format from template, a class method on interstate formatter.
To this, you pass a format string.
Now, for more information on this, you can check Unicode standard 35, which has a lot of information on this.
Suffice it to say, we've said here that we want the day number, followed by an abbreviated form of the month.
This can go into a lot of detail.
These format strings can present everything from given variance of abbreviations, as well as fully spelled out or number variance.
Also critically, we pass here the locale, NSLocale, current locale.
So, this is the correct to do it, but, there is, oh, sorry, finally, we set the date format on our date formatter instance.
Now, this is the correct way to do it.
However, there is an incorrect and naive way to do it.
Let's say you've read Unicode standard 35, and you've explicitly set date format to a string that you've read about here.
You want the month, followed by the day, followed by the year.
Notice though that we haven't got through the template object.
The template does the work for us of rearranging the components, so they're appropriate for a given locale.
Consequently though, when we call from string from date, we get a representation that is the same for all three of these very different locales.
So, this is not the correct way to do this.
Instead, going through the intermediary of date format from template, it will do the rearranging for us.
Consequently, if we pass in lower case d, capital MMM, day and number, basically indicating that we wish to convey day number and month, and then call a string from date, we get the appropriate representation for a given locale.
We have the month name followed by number in the US, the vice versa in France, and in China, we have month number, followed by month character, day, day character.
Likewise though, with NS dates, let's take a look at number formatting.
This is another area in which there's a great degree of variation around the world.
To help you with this, we have NSNumberFormatter, which is meant to mirror an estate formatter.
As an example of the type of variation you may come across, you'll have everything from the separator between the thousands digit and the decimal digit.
Likewise, even the digits themselves, something we may take for granted, can vary.
On the right, we have an aerobic Egyptian representation of this same digit number.
Currency can differ in the symbol, as well as the separators.
Percentage size itself can differ, as well again, we see the digits differing, and even numbers that are not numbers, so not a number can come up differently in different locales.
Again though one thing to avoid is providing explicit format strings, so those of you coming from C world will be familiar with the print F style C format strings.
Here we call string from format on NSString, saying that we want a floating point number with three digits.
Consequently though, we get the same number for all three of these very different locales.
This is not the correct way to do it.
So, one way to do a very simple in place fix, is to instead called localized string of format on your NSString.
This is only for a code that exists already, and is a simple in place fix.
However, if you're making code that will be used going forward, we prefer using the NSNumberFormatter.
Here you call localized string with number, pass in your NSNumber, and pass in again, an explicit format string.
And, this will do the heavy lifting for you in presenting a number in a locale appropriate manner for a given user.
So, like NSDateFormatter, we have explicit preset styles.
Here's what these look like.
Let's start with an NSNumber literal, denoted by the at sign, followed by the number, 1234.56, decimal style will do the correct thing.
Here on this table we have, the left column is US English, and on the right are variants you may encounter around the world.
Again, see in Italy, we have the period and the coma have flipped.
Currency style is different in China.
Percentage style differs in these two aspects again, and even scientific style can differ in that it uses the comma to separate out the significant digits.
Finally, the spell out style itself can be dramatically different between both locales.
So, let's go into more detail about the NSLocale object itself.
Traditionally, the standard API's will do, take into account this information for you.
To give it as an information, sorry, to give it as an argument to an NSNumberFormatter and NSDateFormatter, you can call current locale the class method or auto updating current locale, which will listen for notification that indicates that the user has changed your locale as your app is running.
From there, if you want even more detail, you can create an instance of the NSLocale class.
From there, you can call object for key with various keys to get more information.
For instance, let's say you want to see if a given user uses the metric system.
This information is stored in an instance of the NSLocale class.
You call object for key with uses metric system.
Likewise, you can get the currency symbol, or for a slightly more detailed example, you can get the beginning and end quotation marks for a given locale.
All this is available from an instance of NSLocale class.
So, here, let's see what this looks like in a real example, where you call a string from format, and pass in our previously obtained beginning quote string and end quote.
As a result, we have the appropriate quotation marks for China, France, and Japan.
We have the angle brackets for France and the square brackets for Japan.
Keep in mind though, the distinction between a locale and a localization.
To get a given user's localization, that is to say, the user interface language that the user is running your app within, you call preferred localizations on an instance of the NSBundle class.
On the other hand, to get the locale you call current locale on the locale object.
This is what you'll be passing into the formatting objects in order to obtain the appropriate representation.
So, one final area in which you'll see a lot of variation around the world is in the presentation of calendars.
We may take for granted that this is the year 2013, or year 2011, and you can see that in fact, this is simultaneously also the year 1432, 2554, 5771.
Likewise, this era is AD or CE here, but in Japan, it's the Hassay era.
The number of months per year, length of the months, the day of the week itself can vary, and even the transition of years.
Now, here we have a transition between the Showa period and the Hassay period in Japan, which happened as recently as 1989.
So, to interact with calendars, we use the NSCalendar object.
This allows us to do calculations in a more intelligent way.
It also, it allows us to obtain the information we saw in the previous table, the number of days in the month, weeks in the year, etc. It also allows us to get components from the date, that then we can add on to additional NSDate objects to get dates in the future.
Likewise, as I said, you can do delta computations between two NSDate objects.
So, keep in mind though that NS date itself is an abstract point in time.
You must interpret this NS date object through the lens of an NSCalendar if you're presenting it to the user.
If you're using a code internally, of course it's still fine to use the NSDate object.
So, let's see an example of getting the components of a date that may be of interest to you.
We here, call components from date, passing in our NSDate object, and passing in the individual units that we wish to obtain.
Keep in mind here, you'll only obtain these units that you explicitly specify that are returned in the form of an NSDateComponents object.
From there, you can call day, month, year, and era to get this information out of the object that you've just created.
You can then this NS date components object onto an additional NSCalendar method to add these components to an existing NSDate, and obtain a date in the future.
Now, this is important because calendar computations can be complicated.
The common thing to keep in mind is that, let's say we do some simple arithmetic and we say, well a day is 60 x 60 x 24 seconds.
So, if I go 86,400 seconds into the future, I will be at this time tomorrow.
However, keep in mind that on the border between daylight savings time and non-daylight savings time, this is not the case.
Likewise, one month is not always 30 days in the future.
One year is not always 525,600 minutes, despite what the song may say.
So, for more information on this, you can see tomorrow's presentation, date and time challenges.
I assure you its quite complicated, but they'll go into a lot of information about this.
So, with that, I'll pack to Doug, and we'll do a demo of seeing this in real life.
[ Applause ]
Alright. So, let me go back to my first crude unlocalized application, and notice that it prints a little header in front of each of my notes that shows an index number; I've started with a thousand, just so I can illustrate some things, and a date.
Unfortunately, the format I've chosen for this is pretty crude.
Let's see what that looks like in code.
So, I'm just creating using string with format from the NSNumber and NSDate attached to my note object.
Now, that's the sort of thing that I might want to use for an internal machinery for full representation, but it's not the sort of thing I want to present to my users.
I really want to give them locale appropriate presentations of the number and the date.
So, let me go and see what that looks like in my updated, properly localized application.
So, what I've chosen to do here is to create an NSDateFormatter and an NSNumberFormatter to format these two objects.
Once I have those, it's just a simple matter of replacing the index number and date in my string with format with the properly formatted results of calling string from number and string from date using my number formatter and date formatter objects.
So, to do that, I have to create the date formatter and the number formatter, which is pretty simple.
I've chosen to use a custom format for my date formatter, so I create a date format from template, with a simple template, month, day, hour and minute, and then I set that date format that I got on my date formatter, and it's ready to go for my number formatter.
I just create it, and I set an appropriate style on it.
There are also, if you want to customize your number formatter, there are many, many different options, so you can control all the various pieces of number formatting.
The only thing I'm doing here is saying I don't want floats.
So, I set that up at the beginning of my application, and then I have my date formatter and number formatter that I can use whenever I have to format one of these headers.
Now, one thing I did want to keep in mind is that the user might change their locale while my app is running, and if they do that, then I'm stuck with this number formatter or date formatter that I created for the old locale.
So, I want to listen to a notification, a little further down, I'm going to add myself as an observer to the locale that changed notification, and when I get that notification, I'm just going to recreate my formatters with whatever the new locale is.
So, now my app should be ready.
Let's try running it in English, and I see that I got properly formatted numbers and dates for English.
I also note that my title of the window is changing appropriately with my using string stick to give appropriate representations for the proper pluralization, and so my numbers are formatted using the appropriate thousand separator for English, and I get a suitable date format and number format for English showing first the month name and day, followed by the time in 12 hour format.
So, now if I go into the system preferences, I change my primary language to English, and my region from English to German, and my region format also to Germany.
Let's try running the app again in German.
Of course, the interface is localized to German, let's see, and now we can see that I get appropriately formatted for German with the right thousand separator, rather than a comma, and appropriately formatted dates with a day number, month name, and using 24 hour format for the hours.
And, we can see also that are string stick is giving us appropriately pluralized titles as the number of notes changes.
So, that's using date and number formatters to get properly formatted user representations of dates and numbers.
Now, let me go back to the slides, and let me talk about text.
Now, there are many applications that deal with text in one form or another.
Maybe your app is representing text to the user that it got from some external source, or maybe you're dealing with text that the user entered themselves, but in either case, you need to deal with all the kinds of writing systems that the users are going to want to see.
I have some examples here.
These are all writing systems for which we have font and input method support on both iOS and OS X.
You want to be able to handle them all.
Well, here's some simple rules for doing that.
The first one is, use Unicode and in particular, the NSString class, which is our standard representation of the Unicode string for representing text.
A second one is that when you want to analyze this text, going into or do something to it, iterate through it, search for a substring, sort it, etc., use some of the standard NSString API's, which are all Unicode savvy, and will deal with text in many in many different writing systems, and as much as possible, use the standard system views and controls for displaying that text or for accepting input.
Let me go into that in some more detail.
So, Unicode is a standard that allows us to encode essentially all of the world's living writing systems, most of its date blocks in a single strength, we use NSString as our standard Unicode containing object, and it exposes the contents using the UTF 16 and coding format.
The thing I want you to remember about using Unicode to represent text, is that you cannot treat what the user sees as a character as being something that is fixed length in memory.
That's true no matter what encoding form you're using or what normalization form you're using.
It's just a fundamental property of Unicode.
So, what we recommend that you do is not deal with individual characters in a string.
Instead, work with ranges of characters in a string or substrings of a string.
Let me give you some examples.
So, here I have a Chinese character, a Korean syllable, and a couple of emogies.
And their representations numerically in UTF 16 or UTF 32, you can see that they all have different lengths no matter what encoding formats you've used.
So, to avoid dealing with all this complexity, you can use standard API's, like range of composed character sequence at index, so this will give you the range within a string of what is effectively user visible character, what we call a composed character sequence or sometimes a character cluster for short.
So we use this API, it will give you the range that corresponds to what the user is seeing as a character and respect that range, so you don't split these things up, and end up with broken text.
If you need to go through a string; maybe you need to through it by character cluster or by word or by sentence or by paragraph, we have a standard API for that.
Innumerate substrings and range options using block.
Depending on what options you pass in, you can through it by character cluster, by word sentence, etc., and then you give it a block, and your block gets called with the range of each individual component.
For example, if you're going through it by user visible characters, character clusters, you use the NSString enumeration by composed character sequences options, and then your block will be called successively with the range and the string corresponding to this character, whatever it may be, whether it's short or long.
Likewise, if you're going through it by words, use NSString enumeration by words, and your block will be called successfully with the range of each word and the text notice that words are not necessarily going to be separated by punctuation or white space.
If you need to search for a substring within a string, there's a standard API for that too.
Range of string options, range locale.
There are a number of different options you can pass in for case and sensitive searching, die printing and sensitive searching, if you're searching for something user provider, there's a good change you may want to use both of those.
You can search forwards or backwards.
There's the also the anchored search option.
If you pass that in, you're not looking for the next instance of the substring, you're looking to see whether it's present or not at the given location you start at, which is often useful too.
If you need to sort strings in such a way as to present them to the user in sorted order, you have to keep in mind that each different language; not just language, but each country or region, may have a different standard, sort order, in which they like to see strings presented.
Some die critics are sensitive, important, sometimes not, even what constitutes a letter for sorting may change, and if you don't put things in the right order, people are not going to be able to find what they're looking for.
Now, there are a couple of API's that you might look at for this.
NSString has a standard compare method and a localized standard compare, so the difference is that the compare method is that locale and variant for internal machinery purposes for sorting.
That's not what you want to use for user presentation of text.
For user presentation of text, use localized standard compare.
That will be locale sensitive.
It will give you the order that users expect.
It will match, for example, the order of files that are sorted in the finder.
So, let me give you a few examples.
Here is a set of strings.
Here's the order that you would get them if you sorted them according to the locale independent internal compare method.
If we change this to localized standard compare for let us say, the US English locale, you notice that the order changes a fair bit.
If we were using Danish sort order, it changes even still further, or we're using a Chinese sort order, it changes quite a bit again.
So, use the standard API, and you'll get the sort order users expect; whatever it may happen to be.
For displaying text, keep in mind that the characters as they appear in the string are not necessarily directly correlated with what gets shown on the screen.
So, what gets shown on the screen is a sequence of glifs.
A glif is the smallest unit from a font that can be displayed.
It may represent one character or more than one character or a part of a character.
The mapping between the characters in memory and the glifs that are shown is not necessarily simple and general, it can mean many to many, and even the ordering of glifs within a line can become complex.
Now, our standard views and controls use the text system to get proper Unicode layout and display, so use them as much as possible.
If you need to go beyond that and do custom display, use text API's.
Now it used to be, this was more difficult on iOS than on OS X, because on iOS, you had to go down all the way to the core text level to do it.
With the iOS 7, we have text kit API's, and there are some excellent sessions on this.
There was an introductory session yesterday.
There is a more advanced session this afternoon that will tell you exactly how they keep track of the mapping between the characters and the glifs that display them.
Here's an example; I got this from a developer.
This is some English text with some Hebrew in the middle.
So, English goes left to right.
Hebrew goes right to left.
You put them together, you have bidirectional text.
This is the proper order for displaying the text, but the way it shows up in memory is very different.
It starts off with the English on the left, flowing from left to right, then the Hebrew in logical order flows for the first character, which shows up as the right-most one and so on.
Then this exclamation point; it's a bit ambiguous whether the explanation point goes with the Hebrew or the English.
Here it goes with Hebrew.
In order to specify that, there are some Unicode control characters that are included in this text and these are things that may show up in text that you get.
Text that you get from an external source or from your localizers, or sometimes text from formatters in bidirectional text languages.
It may include these to specify certain cases that are otherwise ambiguous.
And again, the text API's and the standard system controls and fields will handle this properly, and give you the appropriate Unicode sensitive bidirectional layout of this text.
Text input; it's important to keep in mind that it's not always a matter of pressing a key and getting a letter in the text.
For languages that use complex input methods like Chinese and Japanese, usually what will happen is that the user types a representation; a phonetic representation perhaps of the text they want, that gets preliminarily inserted into the text.
Then the system shows them some options of choices, and they pick the one they actually want, and after that gets confirmed, and that's the final text that goes in.
So, in this case, the text on the left has been confirmed.
The underlying text; it's called marked text, is preliminary only, and then they'll pick one, and again, this is what it looks like OS X.
This is what is looks like on iOS; the same text.
It's not just for Chinese and Japanese too.
On OS X, if you press and hold to get accenting characters, it's the same, your preliminary character gets insert, then the user picks the final one.
So, if you're dealing with text as its input, keep in mind, it's not just a simple matter of being inserted letter by letter, there may be this preliminary marked test that shows up in your text view first.
If you're dealing with text as it changes, deal with it change by change, not keystroke by keystroke, and you probably want to notice that text views will tell you if there's marked text from where it is.
You probably don't want to operate on that, because it's only preliminary, it's not the final text.
One last thing to mention is that names, addresses, and phone numbers vary quite a bit around the world.
Names use many different writing systems; sometimes a user will have their family name first, and first name last.
Sometimes they may not have a family name or not have a personal name.
Phone number formats differ widely.
The number of digits used and the punctuation that goes between them, and there are many different address formats around the world.
So, try as much as possible to avoid making assumptions about these formats.
Do it only as your app needs to for its own purposes.
One thing that can help sometimes is data detectors, which can detect phone numbers and addresses in many different international formats, so you can add this to some views, and it will detect these things, and even make them into links.
There is also NSDataDetector at the foundation level for doing this protomatically [assumed spelling].
So, we have a lot of documentation for all this stuff on line, both conceptual documentation, tutorials, and there are a number of relevant sessions that you might be interested in, including sessions about auto layout, many sessions about text kit and text handling, and tomorrow's very interesting session on date and time.
So, the most important things to take away; for localization, you job is to make your interfaces localizable, preferably by using base localization with auto layout, and for your strings and code, use NSLocalizedString and gen strings.
For locale data, be sure to use formatters; date formatters and number formatters when you're presenting these things to the user.
With the constants or templates, if necessary, customize them, and then as calendar for calendrical calculations.
For text, use Unicode and NS string, and the NSString API's for iteration, searching, sorting, and so forth, and as much as possible, use the standard views and controls for input and display.
If you have to go beyond those, use the text system API's to do so, and get proper Unicode aware layout and display.
Thanks everyone, have a great conference.
[ Applause ]