WWDC2014 Session 201

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> 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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.