Instruction 2

TranslationSession is a powerful API you can use to initiate a translation process, check translation eligibility from a source language to a target language, batch-translate multiple chunks of text at once and handle any errors that occur during the process.

An important task is to check the language availability. There is a class specifically for this task.

let availability = LanguageAvailability()
let status = await availability.status(from: translateFrom,
  to: translateTo)

The LanguageAvailability class checks whether the framework supports the language pairing to initiate a TranslationSession and returns with a status, such as supported or unsupported.

switch status {
case .installed, .supported:
  isTranslationSupported = true
case .unsupported:
  isTranslationSupported = false
@unknown default:
  print("Translation support status for the selected
    language pair is unknown")
}

Note that the Translation API doesn’t let you execute a translation session between the same language although you can translate between dialects such as English (en-US) and English (en-GB).

Listening to Configuration Changes

A TranslationSession.Configuration is a type used to pass information to perform the current translation. It keeps track of the source language and the target language that is used in the current translation.

You can create a translationTask to listen on configuration changes, such as when a user selects the source and target language. To do so, declare a @State variable as follows:

@State private var configuration: TranslationSession.Configuration?

You’ll need to update the configuration every time you call the translateAll() method. You can do that like this:

private func translateAll() {
  if configuration == nil {
    // Set the language pairing.
    configuration = .init(source: viewModel.translateFrom,
      target: viewModel.translateTo)
  } else {
    // Invalidate the previous configuration.
    configuration?.invalidate()
  }
}

This method will help initialize a configuration for your selected language pair kept in the ViewModel. If there’s already a configuration, it’ll just invalidate the old one to use the latest language pair available in the ViewModel.

Thus, you need to listen to the configuration changes to trigger a translationTask:

.translationTask(configuration) { session in
}

Whenever you select a language pair for translation, it’ll observe the configuration changes and create a new TranslationSession to execute a translationTask.

Performing Batch Translations

A TranslationSession helps you translate a bunch of text at once. You use the TranslationSession to perform a batch job of translating multiple strings at the same time. You get a combined result using the session created from the translationTask callback.

Take a closer look at the DetailView screen:

Review to translate
Review to translate

As you can see from the screenshot, the review Description and Highlights sections for Humble Bakery are both in Italian, so you need to translate both of them.

Here’s an used to perform a batch translation. First you need

extension ViewModel {
  func translateAllAtOnce(review: Review,
    using session: TranslationSession) async -> Review {

      let requests: [TranslationSession.Request] = [
        TranslationSession.Request(sourceText: review.description),
        TranslationSession.Request(sourceText: review.highlights)
      ]

This function takes the review object to apply translation and the TranslationSession reference to perform the job. It creates two translation requests, one for the review description and another for highlights, and then queues them in the requests array. The rest is easy—it executes translations() with the requests and waits for a result.

  do {
    let responses = try await session.translations(from: requests)
    let translatedReview = Review(
      id: review.id,
      name: review.name,
      address: review.address,
      description: responses.first?.targetText ?? review.description,
      highlights: responses.last?.targetText ?? review.highlights,
      price_range: review.price_range,
      rating: review.rating
    )
    return translatedReview
  } catch {
    print("Error executing translateAllAtOnce: \(error)")
    return review
  }
}

The translations() is an asynchronous call that returns an array of responses containing the text translations matching the order they were sent. In this case, you sent only two translation requests for description and highlights. You can access them from the responses array using their index, such as responses.first?.targetText for description and responses.last?.targetText for highlights.

The translatedReview object here is basically a mutated review that contains the translated version of description and highlights to be displayed in the UI.

To display them in the UI, update .translationTask(configuration) in the DetailView as follows:

translationTask(configuration) { session in
  guard let translatableReview = review else {
    return
  }
  Task {
    review = await viewModel.translateAllAtOnce(
      review: translatableReview, using: session)
  }
}

That code checks if you have a review to translate and then calls viewModel.translateAllAtOnce() with that review providing the translationTask session. Once you have a result, it updates the review state with the translated review to display the translated texts.

You can see examples of all this code in the starter project in the downloadable materials.

See forum comments
Download course materials from Github
Previous: Instruction 1 Next: Demo