New Localization Workflows in Xcode 10

Session 404 WWDC 2018

The localization process in Xcode 10 has been updated to aid you through the lifecycle of exporting, importing, and testing localized content in your apps. See new functionality added in Xcode 10 and learn how the new localization catalog helps you build world-class, localized apps.

[ Music ]

[ Applause ]

Good morning, everyone.

Thank you so much for coming to our session.

My name is Sara Radi.

I'm a software engineer in the Localization Team at Apple and today we'll be joined by my colleagues, Vivian and Chris, to talk about new location workflows with Xcode 10.

So first I would like to start with a quick overview of how the localization process used to work before Xcode 10.

Then I will introduce the Xcode Localization Catalog, which is the new format for exports and imports in your localizations in Xcode 10.

Finally, Chris will talk about Finally, Chris will talk about how to localize Siri Shortcuts by using an Intent definition file which is a new file format we introduced this year as well in Xcode 10.

So let's get started with a quick overview.

So before Xcode 10, if you had a project that contains localizations that your application supports, we look for strings base localizable resources in your project.

So these strings can be defined in your source code, your storyboard files, your strings files, or your strings dictionaries.

So once we identify these resources, we extract strings from them and we export them in an XLIFF format.

So XLIFF is an industry standard and most localizers are already familiar with.

So that's what you will be sending over for translations.

So once you get your XLIFF files back translated on imports, we add them to localizable resources in your Xcode projects with the new translations that are provided in the XLIFF files.

are provided in the XLIFF files.

So that is pretty straightforward process.

Now, the XLIFF format provides a lot of benefits for you as a developer.

First, it helps you to extract the localization work from your code so you don't have to make any language assumptions in your source code.

XLIFF files also holds the content to be localized from your development language along with the translations so your translators can do their work right in the XLIFF files that you have provided.

In addition to that, instead of handing over multiple file types and keep track of them, XLIFF is a really nice tool that consolidates strings from different resources and different file types into one single document.

But what XLIFF does not provide your localizers, it does not give them that visual and functional context.

It does not provide the resource data like assets in your project.

For example, a storyboard file For example, a storyboard file will be very helpful for your localizers to picture how your UI is laid out in your development language.

It also does not provide with the custom metadata about the generated XLIFF.

And finally, the XLIFF we generate today does not have size and length restrictions attributes and that might be very helpful for your localizers to know if a given string will be showing on a Watch screen or an iPhone screen or an iPad screen to make decisions about the length of the translation.

So why is context important for your localizers?

So if we take a look at this example from a travel app that we will be showing you later in our demo, so if you look at the string that says "Book" on the right corner of the Navigation bar, it's kind of clear to all of us here in the room that "book" refers to something related to travels because we have that visual context right have that visual context right in front of us that says start day and dates, number of travelers and the price.

But if you send your translators an XLIFF files, the only thing they see there is just the string "Book" and that don't have that visual context that we were looking at earlier.

So Book can refer to two different things.

It can be a noun in the context of reading a book or it can be a verb in the context of booking a hotel room somewhere or a flight ticket or travel in general.

I actually asked our Russian translator if he can translate the word "book" for me without giving him any additional context and he came up with all these different options.

So without giving him that extra context, it would be very difficult for him to decide which string to show in the UI for Russian users, for example.

Context can also be important for your localizers to decide about the length of the translations they are using.

So if we take a look at this So if we take a look at this example, so I have this phrase that says, "Booking confirmed" in English and it fits just fine on a Watch screen, but in French, for example, it truncates.

So first of all, when it truncates, it doesn't look that nice in the UI and sometimes the truncation can change the meaning of the word.

It can even be offensive for your users.

It can be like funny, like in this example, like the phase does not say that your booking was confirmed anymore.

It says our booking was stupid which is not what I really wanted.

So we see that context is very important to provide to your customers or to your localizers to ship high-quality localization.

So now I would like to introduce the Xcode Localization Catalog, which is the new format for exporting and importing your localizations in Xcode 10.

So what is an Xcode Localization So what is an Xcode Localization Catalog?

It is a new type of localization artifact that has that .xcloc extension.

It is produced by the export localization command in Xcode, so it's the same command that used to export XLIFF files before Xcode 10.

And it is consumed by the import localization command.

And the main thing about the Localization Catalog is that it supports all of your localizable assets, which means anything that you mark as localizable in Xcode projects, it will be supported by Localization Catalog and that is beyond strings files.

[ Applause ]

Another important thing about the Localization Catalog is that it provides that additional contextual information for your localizers.

So we built the Xcode Localization Catalog on top of Localization Catalog on top of the XLIFF format.

So if we take a look at our example earlier, so all of our strings base localizable resources will be extracted in an XLIFF format and anything else that you have marked as localizable in your project will be supported by the Localization Catalog and exported in an xcloc along with the XLIFF files that contains the strings.

So let's take a look closely at what is inside a Localization Catalog.

So inside your xcloc, you will find a contents.json file, which contains metadata about the exported Localization Catalog.

So it has information like the development language of your application, the target language of the exported Localization Catalog.

It has information about the tool that generated that Localization Catalog.

In this case, it's Xcode, so you will find information like the version number and the build number of Xcode.

And finally, it has the version number of the exported Localization Catalog.

Next inside the generated xcloc, you will find Localized Contents directory.

And Localized Contents contains all of your localizable resources in the project and this is the main directory where your localizers will be doing their work in.

So inside Localized Contents, as I mentioned, you will find an XLIFF document that has all the project localized strings as well as non-strings localizable assets like images, for example, if you want to localize those.

So those assets will be organized into the same file system hierarchy as your Xcode projects inside the Localization Catalog.

And your localizers can also use Localized Content to override any resources specifically for the language like interface builder files, for example.

builder files, for example.

Next, inside the Localization Catalog, we generate a Source Contents directory and this is mainly provided for context.

So Source Contents contains assets that were used to produce the Localized Contents like storyboards for example that will be helpful for your localizers to see how your UI is laid out in your development language so they can make decisions about the length of the translations.

So even if your localized strings are coming from your source code, we do not generate your source code inside the Source Contents.

So those assets that are mainly provided for context will be also organized into the same file system hierarchy are your Xcode project inside the Localization Catalog and, as I mentioned, this is mainly provided for context even if your localizers go and change your source context on import, Xcode will just ignore them and will not import these resources will not import these resources back into your projects.

Finally, inside your Localization Catalog, you will find a Notes directory and this is mainly provided for you to give any additional contextual information for your localizers.

That can be screenshots data from your UI Attachments for example.

It can be a Readme file or a movie that explains information about your app or anything really you think that will be important for your localizers.

So that was the Xcode Localization Catalog structure.

And we have been also working on updating the Xcode build command line tools.

So now on exports, we generate an Xcode Localization Catalog.

And on imports, the imports command is backwards compatible.

So if you still have those old XLIFF files, you can still important them back into your project or you can import back the new Localization Catalog.

the new Localization Catalog.

And with that, I would like to hand it over to Vivian to give you a demonstration about the Localization Catalog.

Thank you so much.

[ Applause ]

Thanks, Sara.

Alright, so we've been working on a travel app and what makes this special is it's the first app to let you plan vacations to other planets.

So we call it Vacation Planet.

Let's take a look.

Alright, so on the splash screen we have this lovely logo with the name of our app.

And I'm just going to click Browse here.

Alright, so we can book a flight, an expedition, a cruise, or an entire vacation package.

Let's go to Mars.

Okay, now I need to choose where on Mars to go and I think we should check in on the NASA Curiosity Rover.

So let's go to Gale Creator.

We should definitely go after the conference.

And let's go for a month.

It's a really fast spaceship.

I'm going to take Sara and Chris with me, so three travelers.

That's a really cheap trip to Mars.

Alright, here's that Book button you saw earlier.

And great, our booking is confirmed.

Now, of course, there's people all over Earth who would love to visit Mars and they don't all use their iOS devices in English.

So we're going to need to localize the app.

Let's go into Xcode and do that.

Alright, so I just need to select my project here.

And under Info, under Localizations, click Plus, and we're going to add French for starters.

Okay. So my storyboards are localizable by default, so they're already checked.

And a have a localizable stringsdict that I also already marked localizable.

So I just need to click Finish.

Alright, at this point, Xcode has created the fr.lproj in my has created the fr.lproj in my project and for by storyboards has created strings files with copies of my English strings.

So also copy my image because I have not marked it localizable.

So let's do that.

Over the right, just lick Localize.

There's no content shared between the languages in this file.

So I need to put it in English because that's my development language.

Click Localize and check French to make that copy.

Alright, there it is.

Okay, now I'm ready to export for localization.

I'll just select my project, go to Editor, Export for Localization.

Alright, I'm going to call this vacationplanetloc, so I don't have to type out localization, and double check that I'm exporting for French and click Save.

So now Xcode generates that Xcode Localization Catalog for me and we can go into Finder and me and we can go into Finder and look at it.

Alright, here we go.

Here is my French Xcode Localization Catalog with that .xcloc extension.

And inside, as Sara said, there's the contents.json with metadata about my Xcode Localization Catalog.

Next, we have Localized Contents.

So in here, I have an XLIFF, the same as if I had used Xcode 9.

You can see here it has all of my strings and here we can see highlighted in red the untranslated copies of the English.

And also in Localized Contents mimicking the file hierarchy of my project, I have that logo image.

So next let's look at Source Contents.

This likewise mimics the file hierarchy of my Xcode project.

So I have my storyboards that are in base and I have the English for my info plist strings, my localizable.strings strings, my localizable.strings for the strings defined in code, my localizable stringsdict and the English version of the image.

So the last part of Xcode Localization Catalog is the Notes folder.

And Xcode doesn't put anything in here, but yesterday, I ran my XCUI tests, which are a really easy way to create screenshots.

And all my screenshots are saved as attachments to my test.

So we can go back and look at my test results, see them.

So for instance, I have my splash screen added as an attachment here.

There we go.

Alright, so I'm just going to pull these up in Finder and copy them into the Notes folder.

So select Show in Finder.

Alright, Show Package Contents, look at Attachments.

There they are.

Copy and Paste.

Copy and Paste.

And I think this Travel Details one is going to be particularly helpful because it has that troublesome Book button in it.

Alright, now I'm ready to send my entire Xcode Localization Catalog off to my localizers.

Now the great thing is they're really fast and they're already done.

So we can go ahead and import those translations.

Just going to go back to my project.

Make sure I have the project selected.

And as before, go to Editor and this time choose Import Localizations.

Okay? So I'm going to pick my Return to Xcode Localization Catalog.

Click Open.

And now I get a comparison view the same as in Xcode 9 that shows me any warnings, errors, and changes regarding my strings.

So here, it's just warning me I didn't get any translations for my infoplist.strings.

But that's okay.

I didn't ask for those translations, so I'm just going to ignore this warning.

to ignore this warning.

I can also check on what's changing.

So here if we look at the storyboard, we can see I'm getting real French translations to replace those copies of the English in the strings.

So I'm just going to click Import.

And just like that, all of the translations for my strings and non-strings resources are in the right place in my project.

[ Applause ]

Alright, so let's double check on that.

I'll just do spot check of a couple files.

Okay, main.strings.

That looks like French to me.

I don't actually speak it.

Let's check the image.

Yes, that's also in French.

Okay, so let's run through the app one more time in French and make sure everything looks good.

So to do that, I'm going to select my Active Scheme, choose Edit Scheme.

Set the application language to French and the application French and the application region to France.

Now I'm ready to run.

We're going to stop the English from running.

Okay? So in just a moment here, we should get our app entirely in French.

Okay, looks good so far.

I'm just going to go through really fast so I can go check on that Book button.

Alright, Browse, let's go to Mars again.

I really like Gale Creator.

Okay, great.

That Book button was translated correctly.

It was probably really helpful that I included screenshot of this part.

If we check on the dates here, alright, I did not have to send a list of months to my translators.

Instead, I used this nice date picker that in turn uses a formatter and I got these localizations for free.

And likewise, by using a formatter for the price, I got the correct number formatting and the price given in Euros.

Alright, so that was super easy to get my strings and non-string resources all in French as resources all in French as easily as I would've done with just the string resources in Xcode 9.

So with that, let's go back to the slides and wrap up our discussion of Xcode Localization Catalog.

[ Applause ]

Alright, so we have introduced the Xcode Localization Catalog as Xcode's new standard for localization export and import.

It provides more flexibility for your translators and allows you to conveniently provide more visual and functional context to better help them generate high-quality translations the first time.

It has increased file type support, so you can export and import your non-string resources as easily as you've been doing with your string based resources.

We've also updated Xcode build to use the Xcode Localization Catalog for continuous integration support.

And if you have content out for localization right now, don't worry, you can still import those XLIFFs when they come back to you both Xcode and Xcode Build are backwards compatible.

Alright, so with that, I'm going to hand it over to Chris to talk to you about localizing intent definition files for the creation of Siri Shortcuts.

[ Applause ]

Thank you, Vivian.

Wow, that's really awesome.

I'm really looking forward to that trip to Mars.

So I'm going to be showing you how to localize Siri Shortcuts by localizing your intent definitions.

And your intent definitions are created in intent definition files in Xcode.

And these are what you use to define your custom intents for Siri Shortcuts.

They're just files with an intent definition extension that have a custom editor in Xcode.

And we've designed them to take advantage of base localization so when you go to translate your intents, you don't have a bunch of different intent definition files, one per language, you just use strings files to localize the strings that are in your intent definitions.

And, of course, we also support stringsdict files for a variety of cases like pluralization rules and variable-width strings.

And if you haven't yet, I strongly encourage you to check out the Introduction to Siri Shortcuts Session that happened yesterday and that's available for streaming.

Now let's take a quick walk through the Intent Definition Editor.

Here we have an intent definition for our Vacation Planet application and we have an intent for booking a vacation.

Of course, one of the things that you'll want to localize in your intent is the title and the your intent is the title and the description of the intent itself.

But most of what you're going to be localizing for your intent definition are the shortcut types that are composed together from the intents parameters.

And of course, when an intent is invoked, it produces a response as well and these can also be customized with Response Templates and these Response Templates are localized in exactly the same way as your shortcut types.

Now let's take a deeper look at the actual structure of an intent and what's localizable within it.

An intent is really a collection of parameters that have a variety of types.

So they can have types like integer or string and you saw yesterday that they also support custom objects and they support enumerations that are defined right in your intent definition.

And these parameters are And these parameters are combined together into different shortcut types that have a nice human readable title.

And of course, responses are also collections of properties that have well understood types again like string or integer and can also have types from your enumerations.

And when you go to localize your intent definition, the things that you're going to be localizing the most are your shortcut types and your response templates.

And for the most part, what we're going to talk about today is how to localize your shortcut types because you localize your response templates in exactly the same way.

So here's an example from our Vacation Planet app.

This is the shortcut type for booking a trip and that type of trip there is actually a placeholder for one of our enumerations.

enumerations.

This enumeration lets you book a flight or it lets you book a cruise, or it lets you book a vacation package.

And when Xcode goes to localize your intent definition file, when you press that localize button that Vivian showed you, what's going to happen is Xcode will produce one each of its strings for the members of that enumeration.

And that happens to work because of the particular words we chose.

Because our template says "Book a flight" and uses that indefinite article, we can or "Book a type" and uses that indefinite article, we can book a flight, book a cruise, or book a vacation package because they all start with consonants because that's the rule in English.

But what happens if I add a new value to my enumeration to represent booking an expedition, say to Mars?

Well, Xcode is just going to generate in its strings file "Book a expedition" which isn't really very grammatical.

Fortunately, though, these strings files are keyed by well-defined IDs and stable IDs so you can just go into the strings file and change it so that it's properly grammatical.

Now English isn't the only language that has this kind of grammatical agreement.

Different languages, of course, have different grammatical agreement.

So you'll need to do the same kind of thing say in French, where you'll need to make the gender of the article agree with the gender of the noun that it's referring to.

Now let's take a quick look at a more complex example.

Here we have a shortcut type for booking a vacation for some number of people and once again, number of people and once again, when generating that strings file, Xcode, well, it's going to combine together the template with the values from the enumeration.

However, it's not going to generate one string for every possible integer as well.

Instead, it's going to leave the strings that it generates with a placeholder in them that the shortcut system will replace at runtime.

And once again, this looks like it should be reasonable.

Right? it says, you know, book a vacation or book a flight for some number of people.

And in our strings file, we get that generated ID and that string that says, oh, book a cruise for some number of people with that placeholder still in there; however, when I go to book a cruise for just myself to celebrate a great WWDC, what's going to be shown as an actual shortcut is the string "Book a shortcut is the string "Book a cruise for 1 people" which isn't grammatical English.

However, these support stringsdict files as well so you can do all of the pluralization that you need and have the system take care of it for you.

Here in the stringsdict file, we have the dictionary itself keyed by that string that I showed you from the strings file.

You can either use that or you can use the ID as the key.

And then we've produced another string that is what is actually going to be shown in the user interface.

And here, we're referring to another variable which can then be substituted for either the one or other cases based on English's pluralization rules.

And to learn more about And to learn more about stringsdict files, you should see our session from last year Localizing with Xcode 9 that's available in the WWDC application.

Here, if I go to book my cruise now, this operating system will say, oh, I'm booking for one person, so let's use the case for one and I get a properly grammatical phrase.

And similarly, if I want to book a cruise for all of us, you know, after all I'm not the only one up here, the system will say "Book a cruise for 3 people."

Now let's talk about intents that are created in code.

If you're creating an intent in code to donate it to the system, that isn't necessarily the point at which a shortcut will be displayed.

That can be displayed far off at That can be displayed far off at some point in the future based on the user's actions.

So we have a new API that creates a deferred localizable string that will be localized at the point where the string is presented to the user.

And this is necessary because donating an intent to the system is really telling the system, hey, the user performed some action in my application that you might want to offer them again at some other point.

And, fortunately, this API is extremely simple to use.

It's just one call added to NS String that you can use to wrap the string that you're going to assign to that intent you created in code.

So let's talk quickly about what we've seen.

We've seen that Xcode combines your shortcut types with the enumerations that you've defined enumerations that you've defined in your intent definition when it's generating the strings files.

And you can use both strings and stringsdict files to localize your shortcuts.

And if you're creating an intent in code to donate it to the system, to inform the system of a user action that might be repeated, you can use deferred Localized Intents String to wrap that string in such a way that it'll be localized when it's presented to the user, not at the point where it's created in your application.

So if the user changes their phone's language in between when you've donated that intent, and when a shortcut is displayed, it still follows the user's phone language.

Now when you define strings in a stringsdict file, they are actually going to be preferred at runtime.

That means you can do the majority of your localization in your strings files for all of your strings files for all of the cases where you don't need things like plural agreement and then you can just provide a strings file or a stringsdict file with the same name as your intent definition as an override.

And when you create that stringsdict file, you can use either the strings themselves or the strings IDs that Xcode assigns as keys in your strings file as the Localized String Key and string somewhat measure of stability in case you actually decide to change things in your intent definition.

So now, I'd like to bring Vivian back up to show you exactly how to do this, how this whole process works in Xcode.

[ Applause ]

Thanks, Chris.

Alright, so once you go to Mars once, you're probably going to want to go again and again and again because those trips are really cheap, as we saw.

And it would be nice if our app could suggest additional trips to these frequent fliers and give them a shortcut to book the next vacation.

So with that in mind, I've added an intent definition to our project.

Let's go look at it.

Okay, here's our intent definition.

So we have a custom intent called "Book Item," has a title, a description, and down here is the actual suggestion.

So it is book a type for travelers, people.

Like Chris said, it's a combination of parameters.

So we can see travelers is an integer and type is defined in this enum here, so we can see it can be a flight, a cruise, a can be a flight, a cruise, a vacation package, or an expedition.

Now if our user follows through with a suggestion and books another trip, we need to give them some kind of feedback.

So for that we have a response and there's just a success or a failure message as to whether we could book their trip.

And this is likewise a combination of parameters.

Now, of course, since we have user facing strings, we need to localize them.

So let's do that.

Just like I did for the image, I just go to the right here, click Localize.

Now intent definition files are going to be like interface builder files where we have one intent definition and all of our translations in strings files.

So I want to put it in base.

Click Localize.

Okay. And I want to check French.

Okay, so at this point, Xcode has created a strings file for the French translations to be put in.

And here we go.

Alright, and you can see as I scroll through, it has every possible string given the possible values for the parameters defined in enums.

This is great because, again, I don't speak French but I know from the slides that flight and cruise have different grammatical gender, they're going to need different forms of the word for "a."

Alright, but there's still some grammar problems I can fix and those are the ones in English, the case of one person and an expedition.

So to do that, I need, or at least to fix the plural case, I'm going to add a stringsdict file with the same name as my intent definition.

So just go over here to my project.

Create new file.

And I'm going to use the stringsdict template that was added in Xcode 9.

Click Next.

Alright, here's the important part.

I need to make sure I get the I need to make sure I get the name exactly right.

Intents. Okay.

Create. Now I don't need to go into my French strings file to find the ID for my intent.

I can actually go into the intent definition file because these are required to be unique.

I can actually copy directly from here, alright, copy, and go my stringsdict, and paste.

Alright, you can see here Xcode actually formatted the parameters for me when I pasted so that this is already ready for Siri Shortcuts.

Okay, so at this point, I'm ready to fill in the rest of my plural dictionary.

I'm only going to need one and other because I'm doing English.

So I have singular and plural.

But like any good cooking show, I have the finished file ready.

So I'm going to swap that in.

So I'm going to swap that in.

Alright, say goodbye to this guy.

And let's go find the finished one.

There we go.

Yes, Xcode, I want to make a copy.

There we go.

Alright, let's look at it.

So we're going to look at a case where I fixed two problems at once.

So if we check Book Expedition, the string here is "Book a expedition" but then in the plural dictionary, I have the case of one person or any other number of people.

What I also did here was fix that a/an situation so the string is actually displayed we'll use an.

Okay. So I have the finished version of the app running on my phone.

So let's run through it and So let's run through it and check the shortcut that's created.

Alright, I'm just going to go to the same place as before.

I really like Gale Creator.

Okay, Browse, Mars, Gale Creator, and let's not go for a day.

We'll go Sure, that'll work.

Okay, this time I'm going to go by myself because I want to check the one case.

There. When I tap Book, that actually created the shortcut and donated it.

So now we can go look at it.

you can find these under Settings, Siri & Search.

There. Book an expedition for one person.

[ Applause ]

Alright, so this is great for English.

I fixed it.

but I'm still going to need to localize this into French.

And the great thing is, it's just as easy as the first demo.

just as easy as the first demo.

So we can go back to Xcode.

Alright. I'm going to make sure I localize my stringsdict because I didn't do that yet.

English, yes.

Check French.

Otherwise, it won't be exported.

Okay, so now I just select my project again.

Go to Editor.

Export for Localization.

I'm going to call this vacation plan loc2 since it's the second round of localization.

Double check, yes, I'm doing French again.

Click Save.

And now Xcode creates another Xcode Localization Catalog.

So if we go look at it, okay, let's check localized contents.

If we look at the XLIFF, you can see here highlighted in red are all the new strings from the intent definition but we also have all the translations I imported the first time.

So you can have an incremental localization process where you localization process where you develop your apps sum, you get that version localized, you make some tweaks for version two, and you don't lose anything when you export for another round of localization.

And this works for the non-string resources as well.

So this will have the French version of my image.

Great. So I can develop my app, keep localizing, keep working and it's all just as easy as the first time and it covers both my strings and my non-string resources and my intent definitions so that I can suggest additional trips to Mars.

Alright, so with that, I'm going to turn it back over to Chris for the last time to summarize.

[ Applause ]

Thank you again, Vivian.

Wow, that's really great.

I'm really looking forward to those trips now.

So as you've seen, Xcode So as you've seen, Xcode Localization Catalogs are our new standard in Xcode for localization.

And these support all of the localizable resources in your project, not just the strings based resources.

And they also provide flexibility to provide context to localizers, whether that's putting in screenshots from your tests or putting in readme files or movies of the use of your application, you can give your localizers the context that they need to ensure you get exactly the right translations the first time.

And you've also seen that Siri Shortcuts are easy to localize by localizing your intent definition files, that these use base localization with strings files and that you can use stringsdict files where appropriate to handle things like pluralization rules in a variety of languages, and that variety of languages, and that when you're creating an intent to donate in code, you can use deferred localized intent strings to ensure that a shortcut that's created from that donated intent is localized at the time that it's displayed to the user, rather than at the point where you donated it.

For more information, you can see our session page on the WWDC website.

Thank you again so much for coming and I hope you continue to have a great WWDC.

[ Applause ]

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