App Frameworks • iOS, macOS, watchOS • 39:17
Building a great international user interface goes beyond just translating your app. Explore new and improved APIs in iOS, macOS, and watchOS, and learn how Xcode 8 makes it easy to provide directional images to build first class apps for RTL languages. Hear from experts on how to fine-tune your international UI to create a seamless bidirectional experience and take your app in a new direction.
Speakers: Joaquim Lobo Silva, Sara Radi
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
[ Applause ]
Thank you for attending this session, my name is Sara Raid, I'm an internationalization software engineer, and today with my colleague, Joaquim Lobo Silva, we're going to talk about international user interfaces. So let's get started. At Apple we support over 40 localizations in our software and every language has its own challenges, but today, in particular, we are going to talk about two specific right to left languages that we support which are Arabic and Hebrew.
So this language has presented a unique challenge in building your apps and that's because of the nature of the writing direction. So why are we talking about these languages specifically? With over 400 million people in the Middle East, this really is a growing market. So just last year, we opened two Apple Stores in the UAE these are images from the opening in Abu Dhabi, Dubai and just few weeks ago, we launched Apple.com in the UAE in Arabic for the first time. This is really, really exciting, but what does it mean to you? As a developer, you have growth opportunities in this market and designing word ready apps for your customers is really important.
So in this session we're mainly going to talk about right to left languages, but if you are interested in learning more about designing word ready apps, check out these two talks: Inclusive App Design, which focuses more on the human interface aspect of it and Internationalization Best Practices if you'd like to learn about internationalization.
Last year, on iOS 9 we extended internationalization support to fully support languages written from right to left. And just after that, we included native Hebrew and Arabic localizations into watchOS 2.1. This year I'm happy to say that we have been working on redesigning macOS for this market. So now, I would like to walk you through some, the agenda to see what we going to cover in this session. So first, Joaquim is going to start with a quick recap of the APIs we introduced last year, then he's going to talk about what's new in iOS X with image handling, and how you can evaluate layout direction.
He will finish up with watchOS support, then, I am going to talk about what's new in macOS, and what's new in text support and how can you handle displaying mixed text correctly in your applications. And with that, I'm going to hand it over to Joaquim, to talk about iOS, Joaquim.
[ Applause ]
Alright, thank you Sara, good morning. Thank you all for coming. So, my name is Joaquim, and I'll get things started by talking about iOS. So as Sara mentioned, last year at WWDC we announced full right to left UISupport on iOS 9 across the entire platform. When your users run their apps in these languages they expect your UI to adapt to the nature of these languages.
UIKit does a lot of the work for you, all of its controls and views do the correct thing when running in a right to left context. Managing the layout between these views can be done using auto layout. And this can either mean high level elements such as UIStack view new in iOS 9, also announced last year, which lets you easily model and maintain your UI in terms of easy to use horizontal and vertical groups that can be nested.
And the nice thing about stack view is that it manages auto layout constraints for you. And in particular, for right to left languages it manages leading and trailing constraints and what these are, are left and right properties that change automatically to right and left when running in a right to left context.
Having said that, it's important to note that just because these languages are written and read from right to left, this doesn't mean that every single control in an aspect of your app should strictly follow the writing direction of these languages. There are nuances and some exceptions even to keep in mind when designing for these languages. So one example up above is playback UI, anything related to playback such as rewind and fast forward, video and audio, timeline scrubbers, these should all stay the same across layout direction.
Another example is something we call spatial UI, this can either refer to clusters of controls that don't have a specific directionality associated to them, things like left and right text alignment which should obviously stay in the same position across all languages. And also the example above which is the compass, so things that have a physical or geographical correspondence should also stay the same, north, east and west don't change in right to left.
On iOS we have semantic content attribute that helps you manage and in turn, determine and fine-tune the layout flow of individual views and their sub views. This exposes an enum it's a property on UIView, like I said before, and it's got all the cases that I just mentioned, so one for playback, one for spatial UI, we have self-explanatory force direction cases as well, in addition to unspecified which is the default value. And this is probably where most of your views will fall into.
So, if you want to look at these in more detail and if you're also new to right to left UI design in general, I highly recommend you check out this talk from last year, New UIKit Ssupport for International UI. It goes into all of these concepts into great detail and also talks about some of the new API, or not new anymore, some of the API we added in iOS 9 for right to left UI. So that's a recap of what we have right now in iOS for layout, and with that I'd like to move on over to images. So images for right to left are interesting because they tend to fall into one of three categories.
The first one is universal images, so these are probably where most of your images will fall into, they're just artwork or icons, and they don't need any special consideration for any language or writing direction. So they just stay the same, this is of course familiar to you as regular UIImage or setting a name on a image view and Interface Builder.
The second category is images that do have the direction associated to them. So whether this is a representation of navigation arrows such as the Back button in navigation bars, or the detail disclosure or disclosure indicator on UITableView cells, or in this case, a simplified representation of text, these should be mirrored in right to left.
And simply flipping the image will produce the correct result for right to left, so in this case I just flip the image, and now bullets are in the correct place. On iOS you can do this using imageFlippedForRightTo LeftLlayoutDirection, we call this method on a UIImage and the object returned by it, when displayed in the UIImage view, does the correct thing automatically if it's running in a right to left context.
Lastly, the third category is images that do have the direction associated to them but, they are relatively complex such that simply flipping them would actually produce an incorrect result for right to left. So in this case I have that same bulleted list, but instead of bullets I have checkmarks and when I flip the image the checkmarks are now in the correct place, but they're also flipped and they should actually stay the same in this example for right to left.
So really what I need here is two separate images entirely, one for each layout direction. So I can fine-tune my image for right to left and now it's displaying correctly, but now I have two different images. And up until now the way you would do this on iOS to display the correct one at runtime is really with a runtime check.
You would use our semantic content attribute API to check for your layout direction and then load the correct image from your bundle at runtime. On iOS X we're changing things up a little bit, and we're starting with the deprecation of image flip for right to left layout direction. And with it we're introducing a new concept that will let you do all three of these things using just regular UIImages or image names in Interface Builder. Introducing, brand new, directional image assets in Xcode 8 for your asset catalogs. Thank you.
[ Applause ]
So, what does this mean? So your image assets, in Xcode, you will now have a new concept and a new property that you can set, it's called direction and the values that you can set echo the concepts that I mentioned in the previous slide. So an image can either have a fixed direction, you can specify also that an image is designed for one layout direction and that it should mirror for the other, either from left to right to right to left or vice versa. Or you can simply specify two different images right in your asset catalogs, one for each direction.
Now these are image assets and you might already be familiar with the technology for other kinds of image specialization such as different pixel densities or for across different platforms. So really this is the same concept and all you have to do is either set an image in Interface Builder or load it using UIImage, image named. And with that, I'd love to show you a demo.
Alright so, so I have here a very simple app and let me just run it once to show you how it looks like. It's called Flags and in true international fashion, of course it's a flag quiz game, yay. So, this is pretty straightforward, it's a lot of fun in groups, and what you can see here is very simple UI.
So I've got here the flag that I should guess and I have a Reveal button down at the top, does anybody know what this one is by any chance? I know it's Friday, early, 9 a.m. yeah? Yeah, alright, I heard, I'm hearing France a lot, that's good, cool. Okay, so thank you. We also have two arrows, so one to go forward for the next question and one to go back.
And this is all done using auto layout constraints and this is a vertical stack view as well. Anybody know what this one is? Oh, wow, okay, awesome, listen to that, okay. Sweet, yeah, that's my home country, Portugal, so, you get the idea, right? So, I'm thinking of adding right to left support to this app. Now I don't speak a word of any language that happens to be written and read in right to left, but if I want to see how my app would look like, I don't have to.
Xcode allows me to simulate a right to left environment right from itself. So all I have to do is go to edit my scheme, so up here and edit the scheme right at the top. So this drops down and with run selected, I have Options tab here at the top.
And over here I have an application language override. So this lists my supported localizations which are just English at the moment but I could also pick a right to left pseudo language. What this is going to do is it's going to run my app in my development language which is English, but it's also going to make the UI think that it's running in a right to left environment. So I can just do that, close, and rerun the app.
Yep. So let me start the game again. So already we're seeing a few things right, the navigation bar is doing the correct thing, it's showing the Back button in the right place. And my UI largely looks the same, except you might have already noticed that the arrows are now pointing at each other which, looks kind of wrong.
They're actually in the correct place, so forward is now on the left, which is correct for right to left. But the images themselves have not adapted, so I need to do that. Now all I have to do in Xcode 8 is go to my image assets, so I'm going to go ahead and select them here.
And you'll notice that I have two different images, one for the back arrow, and one for the forward. And I'm going to go here in the inspector and select this new direction property and instead of it being a fixed image, it's a left to right image that mirrors for the opposite layout direction. I'm going to go do the same for the forward arrow, whoops, just so you can see that, left to right mirrors instead of it being fixed. And now let me just run my app again, and see how it looks like.
Cool, let's start the game. Alright, that's all I had to do to now completely support right to left. This is without an extra single line of code dedicated to right to left UI. Auto layout, stack views and now image assets do the heavy lifting for you at runtime. And by the way, I forgot to mention this is also backed by a page controller that also, manages the gestures for going forward and backwards, so I don't even have to worry about that either. So that's the demo on image assets, let's go back to slides.
Cool. So that's a brief look at image assets in the new direction support. Now you can also do all of this if your images are not directly stored in your bundle and say you're fetching remote content that you know has a particular directionality and you want display on your UI. So this is for images not stored locally, you can associate these images using trait collections in UIKit.
We also have the convenience method on UIImage that lets you specify that one image is a counterpart of another and that it should be mirrored for adding to an image asset. It's called imageWith HorizontallyFlippedOrientation and it's probably simpler if I just show it to you in code. So here it is and all I have to do is create an image asset, in this particular example I'm getting a left to right image from the remote source, like a server. And my right to left image is just that same object but horizontally flipped and I'm using this new method on UIImage. Then just register each image, one for each layout direction using a trait collection for left to right and right to left.
And then really you might already be using or writing code that is similar to this, you just get the image compatible with a trait collection for say an image view. And this probably doesn't even have to change because once again, it's the same concept we just have a new directionality property on top of it.
So that's directional images, new in Xcode 8, iOS X, and also watchOS and macOS. We have a new trait which is, layout direction as you saw before, this is a new UITrait collection in UIKit and because this is a new trait, there are some things to keep in mind when it comes to evaluating layout direction on iOS with this new concept. So let's say just as a very simple example I have a UIView subclass and I'm doing some very custom layout on layout sub views, and it's represented by this very simple blue box.
This is informed by semantic content attribute whether it should be left to right or right to left, and you can use our API for this. Now if this is unspecified, semantic content attribute can defer to your app environment and this can either be part of a trait environment which has a trait collection, or the app's general user interface layout direction.
Now really, your UIView should probably really only care about whether or not it should be left to right or right to left, that's it, right. And this can get pretty complicated real fast. So I'm happy to say that on iOS X, you can do just that by using this new property on UIView, it's a computed property called effectiveUserInterface LayoutDirection and it takes all of these concepts into account and tells you immediately whether you should be laying yourself out in left to right or right to left.
If you're not using UIKit or UIView In particular at all for your drawing, say you have a game using a SceneKit view or a SpriteKit view, but you still want to make use of these view controller concepts. You can with this new class method on UIView that gives you the same, that same layout evaluation relative to a semantic content attribute.
And that's a brief look at what's new in iOS, so we saw brand new directional image assets ready for use with Interface Builder and regular UI images with no extra lines of code needed for right to left support. You can do the same thing with images that are not directly stored in your bundle, and as a result we are deprecating imageFlippedForRightToLeft LayoutDirection in iOS X.
We also just took a look at the new convenience property on UIView for determining layout direction in custom layouts, in addition to a class method that lets you achieve the same thing in other contexts. So that's iOS, and now I'd like to move swiftly on over to watchOS.
So watchOS 2.1 added Arabic and Hebrew as selectable system languages. And what this means for your apps is that watchKit is now right to left aware. So all watchKit elements now do the right thing when running in Arabic or Hebrew. We have an API that's similar to iOS that lets you fine-tune individual group or interface object instances.
And it's important to note also that, having said that, it's natural that it should follow that, a lot of the design concepts that we saw in iOS do apply on the watch. So, the idea of pushing and popping interface controllers in their direction, these should adapt for right to left and you should keep this in mind if you have any UI that reflects this as well.
Any horizontal layout that prioritizes certain things first or has an ordering like showing an image on a table view cell, and then a label, you should also adapt. And, something very particular to the watch, of course, is the idea and concept of time and in particular clockwise and anti-clockwise. And this is going back to those nuances and exceptions, if you have any radial or clockwise and anti-clockwise UI this should stay the same across layout directions, just one of those things to keep in mind in addition to the concepts that we talked about.
So how do you do this using the API? So like I said before, all interface objects now do the right thing when running in right to left, these are your buttons, your sliders and your switches. In addition to that, the concept of direction and alignment also change automatically.
So this means that the direction of horizontal interface groups and their alignment and also alignment for any object in watchKit relative to its parent also changes. So in the example, above I have a very simple app with a horizontal group up at the top with left alignment and direction.
And a vertical group at the bottom with left alignment. When I run this app in Hebrew, all of these change to right, so note the ordering of the elements at the horizontal interface group as well. We have semantic content attribute just like on iOS with the same cases that I talked about to help manage individual interface, interface objects or groups. And seeing this in action is really just as simple as any other property that you would set on a watchKit object.
If you're not using watchKit to draw your UI, say you're using SceneKit or SpriteKit, they're new in watchOS 3, you could still evaluate a layout direction if you have a semantic content attribute in mind. So here I just got the direction using a class method on interface device and once I have that I just check if it's left to right or right to left.
And that's a brief look at what we added in watchOS 2.1. So once again it's the same ideas and principles as iOS. All watchKit elements do the correct thing out of the box with no extra work needed and any custom UI or elements that you have should also reflect this.
Keeping in mind of course, the nuances and exceptions that I mentioned and you can use semantic content attribute to help determine the layout direction at runtime. And with that, I'd like to hand it over back to Sara, to talk to you about macOS and handling bidirectional text, thank you very much, I hope you have a great Friday, thanks.
[ Applause ]
Thank you. So let's talk about macOS. Just like the other platforms, iOS and watchOS, the concepts are exactly the same for macOS. So if you are using standard AppKit controls, you will get the behavior out of the box when you're running your app in a right to left environment. So now I would like to walk you through some examples from our own system to show you how active controls behave.
So let's start with what we call system level controls. So we call these system level controls because the layout follow the system language is running in instead of your app layout direction. But this will make more sense with some visual examples, so let's take a look, at the menu bar here. So I'm running my system in a right to left environment and as you can see here, the upper menu starts from the right edge of the window. Also, the elements inside the menu expand from right to left.
And this concept also applies to NSWindow. So by design we decided to keep window controls always consistent across all apps regardless if your app is localized or not. So if you are doing your own logic and you're doing your own custom controls you will need to take that into consideration and update that logic even if you don't support Arabic or Hebrew localizations.
Next, app level controls. So app level controls here, we follow the app language, your layout direction in your app. So for example, NSTableView, so this is a screenshot from the activity monitor app, we're using a stack table view and as you can see the table view [inaudible] reverse order automatically when I'm running my app in Arabic for example. Another example, NSCollectionView and from the finder app where the collection view flow layout flows from right to left. I will give you one more example.
NSScrollView and the same concept here, so we also switch the position of the scroll bar inside the scroll view. And this also will avoid overlapping with the content of your application. And keep in mind if you are using web views in your apps, so scroll in there works a little bit differently.
So WebKit will look at the content of your webpage and evaluate its HTML attributes and based on that value it will position the scroll bar. So for example here, I'm running Safari in English and I am in Apple.com in English. So looking at the content of my webpage, so I will get, the dir attribute here is set to left to right so we position the scroll bar on the right side.
If I take the exact same configuration, but this time I am in Apple.com in Arabic, so looking at the content. So here my content is in Arabic, looking at the dir attributes here again, it's set to right to left, so we switch the position of the scroll bar. So these are just examples from WebKit controls and AppKit controls, and now I would like to talk to you about API.
So we just saw in the last example that WebKit's controls work a little bit differently from AppKit. So with that we are providing a new API in WebKit called userInterfaceDirectionPolicy. As I mentioned, the default value is set to the content of your webpage, but you can override this value if you want for example your scrollers to follow the system language instead of the content of your webpage. So you can override it to use system instead of content. Next, let's talk about AppKit API.
As a quick recap, if you use standard AppKit controls you don't have to do anything, everything will just work for free. Now you might have a specific design in mind and you want to layout your views by yourself. So in that case we highly recommend that you use StackViews and GridViews. So grid views are new to macOS, and both these tools are really powerful because they will set up auto layouts constraints for you under the hood.
And they also use leading and trailing constraints which will flip your views automatically when you're running in a right to left environment. If you are not using StackViews or GridViews, use auto layout. If you're not familiar with it, there are great sessions from previous years and there is a session this afternoon called What's New in Auto Layout, check it out. Finally, if you're using storyboards in base approach we also take care of flipping the text alignment for you.
In addition to that, we have an API in NSView that will let you get and set the layout direction of your views. So for example here, I have a banner slider that has two values, left and right. So I want my slider to be consistent across all my localizations, because it makes sense left should always stay on the left side and right should always stay on the right side.
So here it will make total sense if I force the layout direction of my slider to be always left to right. So as I mentioned, we have an API in NSView that will let you do that. The default value is set to NSApp.userInterfaceLayout Direction, but you can override it to left or right based on what you want to do in your views. Now let's talk about images.
As we just saw in Joaquim's demo, we introduced directional image assets, in asset catalog. So assets catalogs also exist in macOS and they work exactly the same way as iOS, so I'm not going to go through details here. But again, sometimes you don't have your images in your application bundle but you still want to get them from a remote location, let's say a server. So we also have an API in NSImageRep that will let you do that and register your images in code. So let's go through an example together here, just see how it works.
So as I mentioned, sometimes you have images in another location and you want to register them. So first what you need to do is to create your left to right image by using NSImage API. And once you have that you need to set this layout direction to be left to right. So same thing for your right to left image, but this time you will need to use NSImageRep API.
So once you have both images, so you need to register your right to left image representation with the left to right image and that by using other presentation API. So with that, once you have both images registered we will load the right image for you at runtime, either if you're running your app in a left to right localization or a right to left localization.
Finally, we have new convenience initializers for common AppKit controls. For an accessory for example, it will set the alignment attribute and auto layout attributes correctly for you. And for NSButton, it will flip the image, the checkbox position, and the Radio button positions also for free. So with that, I would like to show you a demo to summarize what we just saw in the section.
Alright. Cool, so I got inspired by Joaquim's demo and I created a scoreboard app so we can track our scores when we are playing the game together. So here I have a simple, app where you can see it in my view controller, I just have a table view, and I already setup my auto layout constraints.
And inside my table view cell I have an image, a text field, and a [inaudible] so pretty simple. So here I'm using StackViews to lay out the elements inside my table view cell, so I didn't even need to worry about setting up auto layout constraint because text view just took care of that for me. And here at the bottom, I have a label where I update my highest score and my best play. So pretty simple.
So what I'm going to do now, I'm going to simulate a right to left environment directly on my app and see how it looks like. Great. So I'm going to go to my scheme editor, to my application language and choose my right to left pseudo language instead of my system language. I'm going to build and run my app again.
And it's building, great. So as you can see here without writing one line of code, just by using storyboard, StackViews, auto layouts, it just works. So that's it, so now that my app looks great in right to left, what I'm going to do, I want to go back to my code and, I'm going to run my app, this time, in my system language instead of right to left pseudo language So this will just run the app in English because my system now is in English.
Now I'm going to run my app again. So why I'm doing this, so I just want to show you another aspect of international user interfaces. So here, so my app looks great in English as well, and now I want to join the game. So I'm going to add a new player.
I'm going to click here, add a new player and here just for fun, I want to write my name in my native language. So I'm going to go ahead and change my keyword to use Arabic instead of English. Alright, so I type my name in Arabic, great. And I'm also really good at guessing flags, so I'm going to win this game, so I'm not going to waste time. So I'm just going to update my score anyway.
So, alright, see what happened here? So just by updating my name, so my label is completely broken because it jumps to the right side and now my label just reads "! has the highest score 12, Sara." That doesn't make any sense. So in the next section I would like to show you how to solve this kind of problem and how can you render by directional text correctly. So let's go back to slides.
So we just saw in the demo app, just by entering my name in Arabic, it broke the rendering of my text. So now let's see how we can fix these kind of problems. So rendering text in your applications is really important. It doesn't matter if you support localization of that specific language, even if you are supporting only English, your users can still read and write content in any other language.
And when it comes to text, it's really important to remember that text alignment and text directionality are two different concepts. So for example here, I have a paragraph in English, it's right aligned, it's fine, it looks great, because you might need to do that by design, so it won't break the text rendering.
But if I take the same example but this time it's left aligned, but I'm forcing the writing direction of it to be right to left, that will break the rendering of your text. As you can see here the exclamation marks are not in the correct position. So let's talk a little bit for that. Lateral alignment is default in all our platforms, so if you don't override that value, so we'll get the right behavior, in most cases. So let's talk about text directionality because it's a little bit more complex.
So here I'm just going to give you a really simplified overview of the text engine by algorithm. But if you want to learn more about Unicode by the algorithm please check out the full specification in Unicode.org. But let's start with the basics. So there are three types of Unicode characters.
So they can be either strong left to right, for example scripts that we are familiar with Latin, Chinese or Japanese. They can be strong right to left characters for example scripts like Arabic, Hebrew, Farsi or Urdu and there are characters that they don't have a directionality at all, and we call these neutral or weak characters. For example spaces.
So how the text engine decides about the directionality of a specific paragraph? So the text engine just look at the first strong Unicode characters, that's it. And if it's a strong right to left, my paragraph would be right to left. If it's strong left to right, my paragraph will have a left to right directionality.
So let's walk through an example together to see how it works. So if I take my label from the demo app, %@ has the highest color. So I have no idea at runtime what my %@ will be replaced by, because my user can write or input anything, use any keyboard. So let's take the simple case here, where my %@ will be replaced with a Latin name.
So here the first character is an A, it belongs to Latin, so it's a strong left to right. So the directionality of my paragraph here is left to right so it renders correctly. Now if my variable is replaced with an Arabic name. So the first strong character here is an Arabic character which give the directionality of my whole paragraph to be right to left. So that's why the, my text rendering was broken, so this is wrong.
So the right behavior here will be something, so I will expect to see something like that, even my name is in Arabic. I want it to be on the left side and the rest of my paragraph will be rendered correctly from left to right. So wouldn't it be great if I had something that will take my variable, will isolate it and give it its own writing direction without affecting the rest of my paragraph? And that's possible with Isolates supports. So Isolates are the latest Unicode [inaudible] characters that were introduced in Unicode 6.3 and that our text engine supports in all our platforms.
So as I mentioned, Isolates will allow some text to be isolated and have the directionality of its first strong character and that's without affecting the surrounding text. And I'm happy to say, you don't need to insert these characters yourself, like in case-by-case because if you use localizedStringWithFormat, we do that for you automatically. So localizedStringWithFormat will isolate %@ automatically and it will do the right thing at runtime. So now, I would like to go back to the demo app and fix the issue we introduce earlier just by one line of code, so let's do that.
Alright, so cool. So now I'm going to go back to, my view controller here and this is where I update my label. So just to save some time I already wrote the code to use localized standard string with format instead of a regular string. So I'm going to go ahead here and comment this regular string and uncomment the line that is using localizedStringWithFormat. I'm going to run my app again, and see if my issue's fixed.
Right, so as you can see here, so my problem is fixed. So my name now is on the left side of my sentence, I can read it correctly. So let's see if it works with English names as well. So see here if I update with, Rana, see if it works. And with Arabic names as well, and that's Isolates support in our platforms. So let's go back to slides.
[ Applause ]
Alright so let's summarize. So in this session we introduced directional image assets. So it's easier now for you to support different images for both your left to right and right to left localizations. We have new APIs for you on iOS, watchOS and macOS. And auto layout is your best friend if you want to lay out your views and support other localizations. And we also improved our text engine by supporting Isolates Unicode characters.
So with all these improvements, it's really easy for you, as a developer, to go ahead and reach new markets. For more information, please visit developer.apple.com to find our session there and thank you so much for coming. And those are related sessions if you didn't watch them already, please check them out, they are good. And have a wonderful day, enjoy the rest of WWDC, thank you so much.