이글을 작성하는 이유는 Translation 관련 앱을 만들어 보려는중, 애플에서 Translation 관련 API가 있다는 것을 알게되어 WWDC에서 소개한 Translation API 영상에 대해서 정리한번 하고자 작성했습니다. (WWDC 영상 해석본이라고 생각하시면 됩니다.)
Apple은 언어 장벽을 없애려고 노력하며, 사용자가 번역 기능을 지원하는 머신 러닝의 혜택을 누릴 수 있도록 합니다.
1. 앱에 텍스트를 입력하면 다양한 언어로 번역할 수 있습니다.
2. 시스템 차원 번역에서는 시스템의 어느 앱에서든 번역 시트가 나타납니다.
3. 카메라 번역을 사용하면 이미지나 주변 세계에 있는 텍스트를 번역할 수 있습니다.
이러한 기능과 번역 앱 뒤에서 머신 러닝 모델을 활용하는 새로운 API를 소개하고, 이제 여러분의 앱에서도 이 강력한 기능을 사용할 수 있습니다.
오늘 다룰 모든 번역 API는 iOS, iPadOS, macOS에서 지원됩니다.
오늘 다룰 내용의 개요는 다음과 같습니다.
먼저, 앱 내에서 번역을 제공하기 위해 사용하는 두 가지 옵션을 살펴보겠습니다.
첫 번째는 번역 오버레이를 보여주는 아주 간단한 API이고, 두 번째는 유연성이 더 큰 텍스트 번역 API입니다.
다음으로 어떤 언어가 지원되는지와 프로그래밍 방식으로 이를 확인하는 방법을 살펴보겠습니다.
끝으로 번역 기능 작업 시 모범 사례를 살펴보겠습니다.
앱에 번역 기능을 쉽게 추가하려면 translationPresentation()을 사용할 수 있습니다.
SwiftUI 한 줄만 사용하면 사용자의 언어로 번역된 텍스트를 표시할 수 있습니다.
번역할 텍스트를 제공한 다음 번역 기능을 트리거하면 됩니다.

이 API는 최근 제공되어, 아래와 같이 앱에 적용할 수 있습니다.


이 기능을 앱에 추가하는 방법을 살펴보겠습니다.
이 기능을 앱에 추가하는 방법은 다음과 같습니다.
1. 번역문 표시 여부를 제어하는 저장 공간 추가
2. 번역 기능을 트리거하는 버튼을 메뉴에 추가
3. 버튼을 누르면 showsTranslation이 true로 설정됨
4. translationPresentation()을 추가해 showsTranslation이 true일 때 표시하도록 설정하고, 번역할 텍스트 제출
이제 사용자는 버튼 하나만 누르면 번역문을 볼 수 있습니다. 또한, 필요한 도착어를 변경하는 옵션도 제공합니다.
하지만 한 번에 번역문 하나만 표시하는 방식이 모든 경우에 적합하지 않을 수 있습니다.
예를 들어, 사용자가 번역된 댓글을 여러 개 동시에 보고 싶다면 어떻게 해야 할까요?

이럴때 Flexible translation API를 사용하면 됩니다.

여러 문자열을 동시에 번역하기 위해서는 Flexible translation API를 사용해야 합니다.
이 API의 핵심에는 TranslationSession 클래스가 있습니다. TranslationSession을 사용하면 여러 문자열을 동시에 번역하고, Swift의 비동기 구문을 통해 결과를 반환받을 수 있습니다.
UI에 결과를 어떻게 표시할지는 개발자가 직접 제어할 수 있습니다.
가끔 이 클래스로 사용자에게 UI를 표시해야 하기 때문에, 직접 TranslationSession 인스턴스를 만들지 않습니다.
그 대신에 .translationTask를 뷰에 첨부하면 클로저를 호출해 사용할 TranslationSession을 제공합니다.
이 예시에서는 뷰가 나타날 때 클로저가 한 번 실행됩니다
하지만 번역이 실행될 때 대부분 더 많은 제어권을 원합니다. TranslationSession.Configuration이 이때 필요합니다.
이제 이 클로저는 구성이 변경될 때마다 실행됩니다. 초기에 번역을 트리거하려면 nil이 아닌 값으로 구성해야 합니다. 번역을 다시 트리거해야 하면, 클로저를 다시 실행한다는 걸 SwiftUI가 알 수 있도록 구성을 변경해야 합니다.
출발어나 도착어를 변경해서 그렇게 할 수 있습니다. 또는 새 텍스트를 번역하고 싶다면, 구성에서 .invalidate()를 호출할 수 있습니다.
이 API를 활용하는 방법은 다음과 같습니다.

TranslationSession.Configuration 저장 공간을 추가합니다. 사용자가 트리거할 때까지 번역 기능이 기다리도록 nil로 시작합니다.
다음, 이 구성을 사용하는 .translationTask()를 추가합니다.
구성이 변경되고 nil이 아닐 때마다 호출되어 번역에 사용할 세션을 제공합니다.

지금은 번역 기능을 수행하기위해, 이 세션에 한 묶음의 텍스트 번역을 요청합니다.
여기 아래에서 이미 구현한 함수(translationBatch)를 사용하고 있는데, 필터링된 모든 리뷰를 번역하라고 요청하는 것 입니다.
결과는 한 번에 하나씩 비동기식으로 반환됩니다.
각 결과가 반환 될 때마다 이미 구현한 함수(addTranslation)를 호출해 번역 응답을 받고 응답을 모델 객체에 추가하고 UI를 업데이트합니다.

이제 번역 기능을 트리거해야 합니다.
먼저, 구성이 이미 있는지 확인합니다. 없으면 아직 번역하지 않았으니 구성을 생성하겠습니다.
여기서 기본 이니셜라이저를 사용하고 있는데 자동으로 언어를 선택할 겁니다.
구성이 이미 있으면 벌써 번역했다는 뜻이지만 사용자가 다시 번역을 원합니다.
SwiftUI는 소스 콘텐츠 변경을 알 수 없지만, invalidate()를 호출하면 구성이 변경되고, translationTask 클로저 실행으로 새 콘텐츠를 번역할 수 있습니다.
이제 필터링된 리뷰를 선택한 후, 버튼 하나만 누르면 아래 사진 처럼 여러 개의 리뷰를 한꺼번에 번역할 수 있습니다.
번역 API는 온디바이스 머신 러닝(ML) 모델을 사용해 번역을 수행합니다.
이 모델은 번역 앱뿐만 아니라 시스템의 모든 앱에서 공유됩니다.
만약 번역하려는 언어가 이미 다운로드되었다면 앱에서 즉시 번역할 수 있습니다.
하지만 언어가 아직 설치되지 않았다면, API가 다운로드를 자동으로 요청합니다.
사용자는 다운로드 진행 상황을 확인할 수 있으며, 다운로드는 백그라운드에서 지속됩니다.
출발어와 도착어를 직접 지정할 수도 있고, 자동으로 선택하도록 설정할 수도 있습니다.

translationTask()에 직접 언어를 지정TranslationSession.Configuration에서 지정nil로 지정하면 콘텐츠 언어를 자동으로 식별nil로 지정하면 사용자의 기본 언어에 맞춰 자동 선택콘텐츠가 어떤 언어인지 아는 방법이 궁금할 겁니다.
가능하면 TranslationSession에 출발어를 nil로 지정해 언어를 자동으로 식별하는 것이 좋습니다.
하지만 여러분이 텍스트 언어를 식별해야 하는 경우 NLLanguageRecognizer를 사용할 수 있습니다.

processString 함수를 호출하고 dominantLanguage를 가져온 다음 TranslationSession에서 사용하는 Locale.Language로 변환합니다.
아래 사진들 처럼, 한 번에 여러 문자열을 번역하는 기능이 필요한 앱이 많습니다.

같은 언어로 된 여러 문자열을 번역할 때는 단일 문자열 번역 함수보다는 묶음 번역 함수 중 하나를 사용하는 것이 가장 좋고 효율적입니다.
두 가지 옵션이 있습니다.
public func translations(from batch: [Request]) async throws -> [Response]
public func translate(batch: [Request]) -> BatchResponse
clientIdentifier를 설정하고자 합니다.
오늘 설명한 API는 여기 있는 모든 언어를 지원합니다.
번역 앱에서 지원하는 언어와 동일합니다.
올해 새로 힌디어 지원이 추가되었습니다.
따라서 훨씬 더 많은 사용자가 번역 기능을 활용할 수 있습니다.
새로운 LanguageAvailability 클래스를 사용하면 지원되는 언어를 확인할 수 있습니다.
출발어와 도착어 쌍도 확인 가능하며, 지원되지 않는 언어 쌍으로 번역을 시도하면 오류가 발생합니다.
지원되지 않는 언어 쌍으로 TranslationSession을 만들 수는 있겠지만 번역을 시도할 때마다 오류가 반환될 것입니다
번역 기능 작업 시 모범 사례 몇 가지를 살펴보겠습니다.
먼저 iPhone, iPad 또는 Mac에서 개발해야 합니다.
이런 번역 API들은 시뮬레이터에서 작동하지 않습니다. translationPresentation과 .translationTask 한정자를 모두 콘텐츠 자체에 첨부해야 합니다.
translationPresentation()은 iPad와 Mac에서 팝오버라 올바른 보기를 가리키도록 해야 합니다.
이 코드는 팝오버가 버튼 자체를 가리키도록 해서 원래 뷰를 가립니다

모디파이어를 콘텐츠나 해당 컨테이너에 첨부합니다. 이제 팝오버가 번역될 콘텐츠를 정확히 가리키고 콘텐츠를 가리지 않습니다
여러 언어로 된 콘텐츠를 번역할 때는 각별한 주의를 기울여야 합니다.
요청 묶음의 소스 텍스트가 모두 같은 언어여야 합니다.
같은 묶음에 다른 언어를 섞으면 조악한 결과를 얻게 됩니다.
독일어와 스페인어 텍스트를 같은 요청 묶음에 포함하면 터무니없는 결과를 얻을 겁니다.
그 대신에 각 언어를 번역하는 호출을 별도로 작성해야 합니다.
여기처럼 같은 세션에 별도의 묶음으로 말입니다.
코드 작성 시 단일 요청에 여러 언어의 콘텐츠를 포함하면 안 된다는 뜻입니다.
여기 독일어와 스페인어 텍스트가 같은 요청 어레이에 있습니다.
대신에 단일 세션에서 각 언어에 대해 함수 호출을 별도로 해야 합니다.
독일어 텍스트를 번역한 후 스페인어 텍스트를 번역합니다.
이렇게 할 때 중요한 점은 세션의 출발어가 nil이어야 합니다.
이 세션에서 먼저 각 묶음의 언어를 식별하기 위해서죠.

또한 지원되는 언어만 지정해야 합니다. 그렇지 않으면 이 세션의 모든 번역에서 오류가 발생합니다.
콘텐츠가 어떤 언어인지 또는 어떤 언어로 번역할 것인지 확실하지 않으면 nil을 사용해 프레임워크에서 언어를 선택하도록 합니다.
사용자에게 어떤 언어가 필요한지 미리 안다면 번역하기 전에 TranslationSession. prepareTranslation()으로 다운로드 승인을 요청할 수 있습니다.
이는 사용자가 오프라인 상태에서 번역 기능을 사용하려는 경우 미리 다운로드를 시작하도록 할 때 유용합니다.
앱에서 시간이 흐르면서 변경되는 콘텐츠를 번역해야 하는 경우 이 API를 사용해 미리 다운로드 승인을 받으면 화면을 가리지 않습니다.
TranslationSession 인스턴스를 저장하는 방법에 주의하세요.

TranslationSession은 뷰에 연결된 상태에서만 정상적으로 작동합니다.
수명이 끝난 인스턴스를 모델 객체에 영구 저장하면 나중에 사용할 수 없을 수 있습니다.
마지막으로, 이제 번역에 새로운 SF Symbol를 사용할 수 있습니다.
번역 API를 트리거하거나 오늘 설명한 번역 기능을 참조하는 UI의 어느 곳에서든 이것을 사용할 수 있습니다.

translationPresentation()을 사용하면 앱의 시스템 UI에 번역문을 쉽게 표시할 수 있습니다.