Streaming is available in most browsers,
and in the Developer app.
-
Meet the Translation API
Discover how you can translate text across different languages in your app using the new Translation framework. We'll show you how to quickly display translations in the system UI, and how to translate larger batches of text for your app's UI.
Chapters
- 0:00 - Introduction
- 2:10 - Simple overlay translation
- 4:01 - Flexible translation
- 11:34 - Language support
- 12:48 - Best practices
Resources
Related Videos
WWDC23
-
Download
Hi, I’m Louie, an engineer on the Machine Translation team, and welcome to “Meet the Translation API”! Often in my travels, I have to translate between many different languages. The beauty of the Translate app is that I don’t need to speak all these languages. At Apple, we try to remove language barriers, and let users benefit from the machine learning that powers translation features.
These features include the Translate app, where you can type-in any text to translate into various languages… System-wide translation, where you can get a translation sheet over any app on the system... Camera translation, where you can translate text found in images and the world around you, and more. And today we’re excited to introduce new APIs that harness the machine learning models behind these features and the Translate app, so you can unlock all this power in *your* apps. All the Translation APIs we’ll talk about today are supported on iOS, iPadOS and macOS. We’ll use an iPhone as an example, but all the code works on iPad and Mac as well. I love hiking, and I’m building an app to help users find great hikes across Europe. My app has descriptions of hikes and allows users to review hikes that they take. These reviews can be written in any language, so I want to make sure other users can still understand everything, even reviews written in unfamiliar languages. Since this is user generated content, localization alone isn’t sufficient. I’m going to use this app to show you how easy it is to add translation features to make an app more useful for everybody. Here’s an overview of what we’ll talk about today: First we’ll go over the two options you have for offering translation within your app. The first is a super simple API to show a translation overlay, and the second is a text translation API that gives you more flexibility.
Then we’ll go over what languages are supported, and how to check this programmatically.
And finally we’ll go over some best practices when working with translation. So let’s get started! The easiest way to add translation to your app is with .translationPresentation() With just one line of SwiftUI, it shows users a translation of text into their own language. All you have to do is provide the text to translate, and then trigger the translation.
This API shipped recently, so you can already adopt this in production apps. Now, when a user comes across a review in another language… …it will be easy to get system UI that shows them a translation. Let me show you how easy it is to add this feature to my app. First, I’ll add storage to control whether the presentation is shown.
Next I’ll add a button to the context menu to trigger translation. When pressed, it sets showsTranslation to true And finally, I’ll add a .translationPresentation() telling it to present whenever showsTranslation is true... ...and passing in the review text to translate. And that’s it! Now, when I can’t understand a review, I can just press a button, and I see the translation.
I even have the option to change the target language if I want to.
What you get here is the same as the system-wide translation feature available elsewhere on iOS, but triggered by my app instead of through text selection. This was really easy to add and it's perfect for some apps. But there’s some scenarios where showing a single translation at a time isn’t the ideal experience. For instance, what if I wanted the user to be able to see multiple comments translated at the same time? What I would like is to display translations inline with each review. This kind of scenario is exactly why we built the flexible translation API! Let me tell you about it! The heart of the flexible translation API is the TranslationSession class. Using TranslationSession, you can translate one or more strings at a time and get results back using common Swift async syntax.
It’s up to you how you want to display those results in your UI.
You don’t make an instance of TranslationSession yourself. This is because it sometimes needs to show UI to the user. Instead, you attach a .translationTask to your view, which will call the closure to provide you a TranslationSession instance to use. In this example, the closure will run once when the view appears on screen.
But in many cases, you want more control over when translation occurs. This is where TranslationSession.Configuration comes in.
This closure will now run whenever configuration changes. To trigger translation initially, set the configuration to a non-nil value. If you need to trigger translation again, you’ll need to change the configuration so that SwiftUI knows to run the closure again. You can do so by changing the source or the target language, or you can call .invalidate() on the configuration if you want to translate new text. Let’s take a look at how this more flexible API is still really easy to adopt in my app. First, I’ll add storage for a TranslationSession.Configuration. This will start out nil so that translation waits until the user triggers it.
Next, I’ll add a .translationTask() that uses this configuration.
Anytime the configuration changes and isn’t nil, this will be called, providing me with a session to use for translation.
Then, I’ll perform the translation.
I ask the session to translate a batch of text.
I’m using a function I’ve already implemented down here to make translation requests out of all the filtered reviews. The results come back asynchronously one at a time.
When each result comes in, I call a function I’ve already implemented that takes the translation response, adds it to the model object, and updates the UI.
Now I need to trigger translation. I already added a filtering system to see reviews one language at a time. When I pick a language, there’s a button to translate the filtered reviews, but I haven’t finished implementing it yet, so let’s do so.
First, I check if the configuration already exists. If not, it means we haven’t translated yet, so I’ll create one.
I’m just using the default initializer here, which will pick languages automatically. I’ll talk more in a little bit about how to control which languages to use.
If the configuration already exists, it means we’ve already translated, but the user wants to translate again. SwiftUI can’t see that the source content changed, but calling .invalidate() will change the configuration, allowing the .translationTask closure to run again and translate new content. That’s all there is to it! I’ll show you how this works in my app.
Now, when filtering for Japanese reviews, with just one button press translations are added to reviews as they finish, letting users read them all at once without having to translate each one.
So it looks like people are saying that this is a great hike, but it’s pretty intense. I don’t think I’ll have time for a long hike on that day of my trip, so let’s try to find another hike.
Okay, this “Tulips and Windmill Walk” seems a bit more like what I’m looking for, but I wonder what people are saying about it.
Looks like most of the reviews are in Dutch, so let’s translate them.
But now when I translate content from Dutch, you’ll notice I see a prompt asking me to download that language. Let me explain what’s happening here. TranslationSession performs translation using on-device ML models. These models are shared with all apps on the system, including the Translate app. If the user has already downloaded languages, your app can use them too.
The API takes care of the details. When your app translates, the framework will only ask for download permission if the languages aren’t already installed. It also takes care of showing progress to the user during the download. And these downloads will continue in the background when the user dismisses this sheet, or even if they leave your app entirely. Next, let’s talk about how to pick these languages. You can specify the source and target language to use, or get automatic behavior like I did before. Specify the languages either directly in the .translationTask, or in the TranslationSession.Configuration.
Using nil for the source language will attempt to identify the content’s language automatically. If the framework can’t determine the language, it’ll ask the user to pick. Using nil for the target language will pick a good language to translate into. This is based on whatever is used for the source language, and the user’s preferred languages.
It’s worth noting that Locale and Locale.Language can take many forms and honestly it can get a little confusing since there are a lot of combinations and variants that you should be aware of. For example, depending on which API returns a language, it could be just a language, a language with a variant, a language with a region, or even a language with a seemingly unrelated region. For instance, a French speaking user living in Japan.
For the best results, you should use languages returned by the LanguageAvailability.supportedLanguages API.
You might be wondering how to know what language arbitrary content is in. Whenever possible, we recommend giving TranslationSession a nil source language to identify it for you. However if you do need to identify the language of text, you can use NLLanguageRecognizer. Call the processString function, get the dominantLanguage, and then convert to a Locale.Language that TranslationSession can use.
Many apps need the ability to translate multiple strings at a time. This was the case earlier when I translated different user reviews… ...or for example, your app might need to translate different strings found in a document or image. When translating multiple strings of the same language, it’s best and most efficient to use one of the batch translation functions, rather than the function that translates a single string.
You've two options: the former returns results all at once, after they’re all ready, and in the original order. This is more straightforward and easy to use since the ordering is always the same, and it’s simple to know what to do with each response. It’s also the best to use if you want to wait to show any translations until everything has finished translating. The latter function streams results as they become available, like an AsyncSequence. This is great because it can make your UI feel more responsive, since the first result will arrive sooner, and you can reflect that in your UI right away. When using this function that streams results, you’ll want to make sure that you set the clientIdentifier on each request. This way, you’ll know which is which when receiving each response. Refer to the documentation for more details here. Next, let’s talk about language support. The APIs we’ve discussed today support all these languages, which are the same as the languages supported in the Translate app.
And new this year, we’ve added support for Hindi. This will mean even more users can take advantage of translation, both in the Translate app, but now also your apps.
You can use the new LanguageAvailability class to check which languages are supported by translation. This list can be updated over time as we add support for more languages.
You can also check whether translation from one language to another is supported. The framework doesn’t support every combination of languages. For example, if you check the status of both US and UK variants of English to Hindi, it will tell you that the pairings are supported. Or it’ll report that they're installed if both languages are already downloaded.
On the other hand, if you check whether you can translate from one English variant to another, or from any language to itself, the framework will always report that this pairing is unsupported. While you could have created a TranslationSession with one of these unsupported pairings, every attempt to translate would give back an error. There’s even a function to check the status with a snippet of source text instead of a source language. Let’s go over a few best practices when working with translation. First, be sure to do development on an iPhone, iPad, or Mac. These translation APIs don’t function in the simulator.
Next, be sure to attach both .translationPresentation and .translationTask modifiers to the content itself. Since .translationPresentation() is a popover on iPad and Mac, you want to make sure it points to the right view. This code makes the popover point to the button itself, possibly blocking the original view.
Instead, attach the modifier to the content or its container. Now the popover nicely points to the content being translated, and won’t cover up the content.
You’ll need to take special precaution when translating content from multiple languages.
Any batch of requests should have all source text in the same language. Mixing different languages in the same batch will produce poor results. In this case, putting German and Spanish text in the same batch of requests is likely to output nonsense.
Instead, you should make separate calls to translate each language in a separate batch using the same session, as shown here.
In code, this means you shouldn’t make a single request with the contents of multiple languages, in this case German and Spanish text in the same request array.
Instead, you should make separate function calls for each language in a single session. Here, I translate the German text and then I translate the Spanish text. It’s important to note that the session’s source language must be nil when doing this, so that this session will first identify the language of each batch. You should also only specify languages that are supported. Otherwise all translations with this session will produce an error.
Whenever you’re unsure about what language the content is in or what language to translate into, use nil and let the framework pick for you. If you know what languages the user is likely to need ahead of time, you can ask the user for download approval without translating by using TranslationSession.prepareTranslation().
This is useful for situations where the user will be offline when they want to use translation, so they should start downloads ahead of time. And if your app needs to translate content that changes over time, you can use this API to get download approval beforehand so that it doesn’t block the screen. Be careful with how you store TranslationSession instances. TranslationSession is doing a lot of work for you under the hood, but this requires occasionally showing UI to the user. What powers this is by being anchored to a view in your app. Each instance of TranslationSession is tied to the view it was anchored to, so it won’t work if the underlying view disappears.
This also means you shouldn’t store an instance outside the lifetime of its view, for instance in a persistent model object, since the session may not be usable later on. And finally, there’s now a new SF Symbol available for translation. You can use this anywhere in your UI where you trigger translation APIs, or refer to the translation features that we’ve discussed today.
To wrap up, you should adopt `.translationPresentation()` as a way to display translations in system UI over your app. And there’s also a flexible translation API you can use if you want deeper integration within your app’s UI.
We always appreciate hearing your feedback using Feedback Assistant, so please, let us know if you encounter any issues, or if there's any enhancements you’d like to see. We’re excited for your apps to reach a wider audience using translation. Thank you so much!
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.