[WWDC24] Translation API 소개

2026. 3. 25. 19:12·iOS & Swift

애플이 WWDC에서 번역 기능을 제공하는 API를 소개했습니다!

 

바로 Translation 프레임워크인데요,

이 프레임워크를 사용하면 앱 내에 번역 기능을 손쉽게 추가할 수 있습니다.
시스템에서 제공하는 팝업 UI를 활용해 번역을 제공할 수도 있고, 필요에 따라 커스텀 UI로 구성할 수도 있습니다.

 

Simple overlay: 번역 오버레이를 보여주는 아주 간단한 API

 

번역 기능을 추가하기 위해서는 다음과 같은 함수를 사용합니다.

func translationPresentation(
    isPresented: Binding<Bool>,	// 팝오버를 표시할지 여부를 결정하는 Bool type 바인딩
    text: String,		// 번역할 텍스트
    attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds),	// 팝오버의 Anchor의 위치 지정, 기본값은 bounds
    arrowEdge: Edge = .top,	// macOS에서 팝오버 화살표의 위치를 정의, 기본값은 top.
    				// 이 값은 macOS에서만 적용되며, iOS에서는 무시됨.
    replacementAction: ((String) -> Void)? = nil // 번역된 텍스트로 기존 텍스트를 교체할 때 사용할 수 있는 콜백
) -> some View

 

예제 코드로 살펴보기

struct ContentView: View {
    @State private var translationVisible = false
    private var originalText = "Hallo, Welt!"


    var body: some View {
        VStack {
            Text(verbatim: originalText)
                .translationPresentation(isPresented: $translationVisible, text: originalText)
            Button("Translate") {
                translationVisible.toggle()
            }
        }
    }
}

 

Translation 문서에 있는 예제 코드를 기반으로 동작을 살펴보겠습니다.

 

이 코드를 실행하면 번역 팝오버 UI를 확인할 수 있습니다.

 

 

앱의 동작 흐름은 다음과 같습니다!

  1. Translate 버튼을 클릭한다.
  2. 시스템 번역 팝오버 UI를 통해 번역 결과가 표시된다.

 

1. Translate 버튼 클릭

@State private var translationVisible = false

...

Button("Translate") {
	translationVisible.toggle()
}

 

Translate 버튼을 클릭할 시 실행되는 액션은 translationVisible.toggle()입니다.

 

translationVisible은 Bool 타입의 상태 변수이기 때문에,
버튼을 통해 번역 팝오버의 표시 여부를 제어할 수 있습니다.

 

2. 번역 팝오버 표시

@State private var translationVisible = false
private var originalText = "Hallo, Welt!"

var body: some View {
    VStack {
    	Text(verbatim: originalText)
        	.translationPresentation(isPresented: $translationVisible, text: originalText)
        Button("Translate") {
        	translationVisible.toggle()
		}
	}
}

 

translationPresentation에는 isPresented라는 바인딩 값이 전달됩니다.

 

버튼 클릭으로 translationVisible이 true가 되면,
modifier가 해당 상태 변화를 감지하여 번역 팝오버를 표시합니다.

 

이때 시스템이 번역 가능 여부를 판단하며,
지원되는 경우에만 번역 결과가 사용자에게 표시됩니다.

 

텍스트 필드 입력을 통한 번역기 앱

이전까지는 변수에 저장된 고정된 문자열을 기준으로,
Translate 버튼을 눌러 translationPresentation을 호출하는 방식이었습니다.

 

그렇다면 사용자가 직접 텍스트를 입력하고, 해당 내용을 번역하려면 어떻게 구현할 수 있을까요?

 

import SwiftUI
import Translation

struct ContentView: View {
    @State private var translationVisible = false
    @State private var originalText = "Hallo, Welt!"


    var body: some View {
        VStack(spacing: 20) {
            TextField("Text to translate", text: $originalText, axis: .vertical)
                .textFieldStyle(.roundedBorder)
                .translationPresentation(isPresented: $translationVisible, text: originalText) { translatedString in
                    // 번역된 텍스트로 기존 값을 업데이트
                    originalText = translatedString
                }
            Button("Translate") {
                translationVisible.toggle()
            }
        }
        .padding()
    }
}

 

이 코드의 핵심은 TextField와 상태 변수인 @State의 연결입니다.

 

TextField는 $originalText와 바인딩되어 있기 때문에,
사용자가 입력한 값이 실시간으로 originalText에 반영됩니다.

 

따라서 Translate 버튼을 누르면,
현재 TextField에 입력된 최신 텍스트를 기준으로 번역이 수행됩니다.

 

또한 translationPresentation의 replacementAction을 활용하면,
번역 결과를 다시 TextField에 반영할 수 있습니다.

originalText = translatedString

 

이렇게 하면 번역 결과가 입력 필드에 바로 적용되어,
간단한 번역기 앱 형태로 확장할 수 있습니다.

 

Flexible translation: 유연성이 더 큰 텍스트 번역 API

Flexible Translation API는 단일 문자열뿐만 아니라,
여러 문자열을 한 번에 번역할 수 있는 보다 유연한 방식의 API입니다.

 

let session: TranslationSession
let inputStrings: [String] = ...

let requests: [TranslationSession.Request] = inputStrings.map { .init(sourceText: $0) }
for response in try? await session.translations(from: requests) {
	handle(response: response)
}

 

TranslationSession을 사용하면 여러 문자열을 일괄적으로 번역할 수 있으며,
Swift의 비동기 구문(async/await)을 통해 결과를 순차적으로 받아올 수 있습니다.

 

번역 결과를 어떤 방식으로 UI에 표시할지는 개발자의 선택에 달려 있습니다.

 

TranslationSession의 핵심 개념

유연한 번역 API의 중심에는 TranslationSession 클래스가 있습니다.

이 클래스는 번역 요청을 관리하고, 결과를 비동기적으로 반환하는 역할을 합니다.

import SwiftUI
import Translation

struct MyView: View {
    var sourceText: Stirng
    @State private var targetText: String?
    
    var body: some View {
    	Text(targetText ?? sourceText)
        	.translationTask { session in
            	do {
                	let response = try await session.translate(sourcetext)
                    targetText = response.targetText
                } catch { /* Handle error */ }
            }
    }
}

.translationTask를 활용하여 번역을 할 때에는 TranslationSession 인스턴스를 직접 생성하지 않고,
.translationTask modifier를 통해 시스템이 제공하는 세션을 전달받아 사용합니다.

 

이 modifier는 뷰가 나타날 때 클로저를 실행하며,
해당 시점에 번역 작업을 수행할 수 있습니다.

 

import SwiftUI
import Translation

struct MyView: View {
    var sourceTest: String
    @State private var targetText: String?
    @Stage private var configuration: TranslationSession.Configuration?
    
    var body: some View {
    	Text(targetText ?? sourceText)
        	.translationTask(configuration) { session in
            	do {
                	let response = try await session.translate(sourceText)
                    targetText = response.targetText
                } catch { /* Handle error */ }
            }
    }
}

 

하지만 실제 앱에서는 번역 실행 시점을 더 세밀하게 제어해야 하는 경우가 많은데요,
이때 TranslationSession.Configuration을 사용할 수 있습니다.

 

configuration 값이 변경되면 .translationTask의 클로저가 다시 실행되며,
이를 통해 번역 작업을 재트리거할 수 있습니다.

 

번역 재실행 방법

번역을 다시 수행하려면 다음과 같은 방법을 사용할 수 있습니다.

  • configuration에 새로운 값을 할당
  • 출발어(source) 또는 도착어(target) 변경
  • configuration.invalidate() 호출

이러한 방식으로 SwiftUI에 상태 변화가 발생했음을 알리고,
번역 작업을 다시 실행할 수 있습니다.

 

Flexible translation API는 단순한 UI 기반 번역을 넘어,
비동기 처리와 상태 관리를 통해 보다 유연한 번역 흐름을 구성할 수 있도록 도와줍니다.

 

특히 TranslationSession과 translationTask를 활용하면
앱의 요구사항에 맞는 다양한 번역 시나리오를 구현할 수 있습니다.

 

여담

과거 저는 이 API를 학습한 이후, macOS용 번역 애플리케이션을 개발해보려고 했습니다.

 

공식 문서가 대부분 영어로 작성되어 있다 보니,
이를 모두 한국어로 번역하면 오히려 어색한 문체 때문에 가독성이 떨어진다고 느꼈습니다.

 

그래서 이 API를 활용하여
사용자가 커서로 텍스트를 드래그한 뒤 특정 키보드를 누르면 번역 팝오버가 나타나도록 구현해보고자 했습니다.

 

하지만 이 API는 웹 환경에서는 동작하지 않는다는 사실을 알게 되었습니다...!!

오직 macOS, iPadOS, iOS와 같은 네이티브 환경에서만 사용할 수 있는 API였습니다.

 

결국 시도는 실패로 끝났지만, 그 과정에서 많은 것을 배울 수 있었습니다! ^_^

 

 

https://www.youtube.com/watch?v=MuIFhbHNmqA
https://developer.apple.com/documentation/Translation

 

'iOS & Swift' 카테고리의 다른 글

[iOS] 서버 없는 근거리 P2P 통신, Multipeer Connectivity (1) 개념편  (4) 2026.05.17
[SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 4장. 상태관리  (3) 2026.04.26
[SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 3장. SwiftUI 구성 요소  (0) 2026.03.22
[SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 2장. SwiftUI 시작  (3) 2026.03.16
[SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 1장. SwiftUI: 새로운 시작  (1) 2026.03.14
'iOS & Swift' 카테고리의 다른 글
  • [iOS] 서버 없는 근거리 P2P 통신, Multipeer Connectivity (1) 개념편
  • [SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 4장. 상태관리
  • [SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 3장. SwiftUI 구성 요소
  • [SwiftUI와 컴바인을 활용한 비동기 프로그래밍] 2장. SwiftUI 시작
Rossi(은지)
Rossi(은지)
iOS Developer | 취준생
  • Rossi(은지)
    개발적 사고
    Rossi(은지)
  • 블로그 메뉴

    • 홈
    • GitHub
    • LinkedIn
  • 전체
    오늘
    어제
    • 분류 전체보기 (15)
      • iOS & Swift (10)
      • Apple Developer Academy @POSTECH (4)
      • Retrospective (1)
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Challenge 1
    애플
    UML Diagram
    SWIFT
    Apple Developer Academy
    Swift Student Challenge
    ios
    Peer to Peer
    Apple Developer Academy @POSTECH
    SwiftUI와 컴바인을 활용한 비동기 프로그래밍
    Multipeer Connectivity
    swiftUI
    WWDC26
    P2P
    Apple
    wwdc
    애플 디벨로퍼 아카데미
    UIKit
    swiftpm
    Challenge 2
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Rossi(은지)
[WWDC24] Translation API 소개

티스토리툴바