Visual overview

Use the workflow to follow the task, and the architecture map to separate responsibilities. These are conceptual maps; the guide below defines implementation details and verification limits.

01 / WorkflowFrom intent to a checked result
  1. Select source and target languages
  2. Check translation readiness
  3. Translate scoped text
  4. Handle unavailable language support
02 / ArchitectureResponsibility boundaries
  1. Boundary 1Source text
  2. Boundary 2Translation session
  3. Boundary 3Translated presentation

Connected responsibilities, not a required class hierarchy or an execution trace.

Context

Load this when an app needs in-app text translation, system translation UI, custom translation flows, language-pair availability checks, model download handling, or multilingual user-generated content workflows.

Use the Translation framework for text translation. Use Natural Language for text analysis, Speech for speech-to-text, and Foundation Models only when translation is part of a broader generative workflow that still needs review.

Choosing the API

Need Use
Simple user-facing translation popover translationPresentation(...)
Replace selected text with a translation translationPresentation(..., replacementAction:)
Custom UI with one or more translated strings translationTask(...) and TranslationSession
Batch translation TranslationSession batch APIs
Check if languages are supported/installed LanguageAvailability

System translation UI

Use the system presentation when the product needs a familiar, lightweight translation affordance and does not need custom layout.

import SwiftUI
import Translation

struct MessageRow: View {
    let text: String
    @State private var showingTranslation = false

    var body: some View {
        Text(text)
            .textSelection(.enabled)
            .contextMenu {
                Button("Translate") {
                    showingTranslation = true
                }
            }
            .translationPresentation(
                isPresented: $showingTranslation,
                text: text
            )
    }
}

Rules:

  • Attach the presentation to the view that owns the source text.
  • Do not present translation for empty or already-redacted private text.
  • Keep the original text available so users can compare.

Custom translation flow

Use a custom session when the app owns the layout, wants batch translation, or needs to store a translated draft.

import SwiftUI
import Translation

struct TranslationDraftView: View {
    let sourceText: String
    let source: Locale.Language?
    let target: Locale.Language?

    @State private var translatedText = ""
    @State private var errorMessage: String?

    var body: some View {
        VStack(alignment: .leading) {
            Text(sourceText)
            Divider()
            Text(translatedText.isEmpty ? "Translation unavailable" : translatedText)
        }
        .translationTask(source: source, target: target) { session in
            do {
                let response = try await session.translate(sourceText)
                translatedText = response.targetText
            } catch is CancellationError {
                return
            } catch {
                errorMessage = error.localizedDescription
            }
        }
    }
}

Rules:

  • Keep translation work tied to view/task lifetime.
  • Cancel or let SwiftUI cancel translation when inputs change.
  • Show source and target language when user trust matters.
  • Do not silently replace legal, medical, financial, or safety-critical text.

Language availability

Check availability before offering a custom translation control.

import Translation

func translationIsSupported(
    from source: Locale.Language,
    to target: Locale.Language
) async -> Bool {
    let availability = LanguageAvailability()
    let status = await availability.status(from: source, to: target)

    switch status {
    case .installed, .supported:
        return true
    case .unsupported:
        return false
    @unknown default:
        return false
    }
}

Rules:

  • supported may still require a model download before use.
  • Treat unsupported language pairs as a normal UI state.
  • Test source-language auto-detection separately from explicit source language.

Product and privacy rules

  • Explain when translated text is generated by the system.
  • Let users inspect the original text.
  • Do not use translation as a hidden moderation, compliance, or policy decision.
  • Avoid storing translations unless the product needs persistence.
  • If stored, mark the translated language and source text version.
  • Handle mixed-language text, names, code snippets, and domain terms carefully.

Verification checklist

  • [ ] Source and target languages are explicit or intentionally auto-detected.
  • [ ] LanguageAvailability is checked for custom flows.
  • [ ] Unsupported language pairs have a clear fallback.
  • [ ] Model download or permission prompts are not surprising.
  • [ ] Cancellation is tested when text/language changes.
  • [ ] Original text remains reachable.
  • [ ] Localized UI labels fit at accessibility text sizes.
  • [ ] Privacy copy matches the actual data path.

Source anchor

Use only to verify API signatures and availability: https://developer.apple.com/documentation/translation