WWDC2015 Session 227

Transcript

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