← すべての記事

AppleのTranslationフレームワーク:無料、オンデバイス、そして見た目以上に切れ味鋭い

AppleのTranslationフレームワークは、テキストをオンデバイスで、無料で翻訳します。言語さえインストールされていれば、APIキーもネットワーク通信も不要です1。Core MLモデルの上に構築され、システムに同梱されており、Translateアプリが使っているのと同じ翻訳エンジンをアプリに与えてくれます。多言語対応の機能といえば、かつてはクラウド翻訳の請求書とプライバシーの懸念がつきものでしたが、そのコストはまたしても実質ゼロに収束します。そしてFoundation Modelsフレームワークと同じく、面白いのは順調に進む経路ではありません。デモが省略する縁の部分——最初の翻訳を止めてしまう言語ダウンロード、何も言わずに動作を拒むシミュレーター、そして導入の仕方を左右するSwiftUI専用の表面——こそが見どころなのです。

TL;DR

  • 2つの表面、2つのiOSバージョン。 translationPresentationはAppleの組み込み翻訳ポップオーバーを表示します(iOS 17.4以降)。translationTaskモディファイア経由で使うTranslationSessionは、自前のUIの中でプログラム的な翻訳を行います(iOS 18以降)2
  • プログラム的翻訳はasyncです。 translationTaskクロージャの中でTranslationSessionを受け取り、それを呼び出して1つの文字列、あるいはバッチを翻訳します3
  • バッチは一級市民です。 リストを1リクエストで翻訳し、各結果を入力に対応づけたまま受け取れます。1件ずつループしてawaitする必要はありません3
  • 翻訳UIはSwiftUI専用で、iOSシミュレーターでは動きません。 どちらも痛い目を見て初めて気づきやすい仕様です。それを踏まえて設計・テストしましょう4
  • オフラインとは、まずダウンロードがあるということ。 ある言語ペアの初回翻訳ではバンドルがダウンロードされます。これは見過ごせるディテールではなく、あなたが捌くべき本物のUXの瞬間です5
  • 押さえておく価値のある組み合わせ——ユーザーの入力をTranslationで翻訳し、それをFoundation Modelsで推論する。こうすれば、単一言語で書いたオンデバイスのエージェント機能が、デバイスにインストールできるあらゆる言語で動作します。

2つの表面:システムのポップオーバーと自前のUI

このフレームワークは翻訳の手段を2つ与えてくれます。そして正しい方を選ぶことが、判断のほとんどを占めます。

軽いほうの選択肢はtranslationPresentationで、iOS 17.4から使えます。ビューにアタッチしてisPresentedフラグをバインドし、テキストを渡すだけ。フラグがtrueになると、システムが自前の翻訳ポップオーバーをコンテンツの上にせり上げて表示します2

.translationPresentation(isPresented: $showTranslation, text: selectedText)

翻訳ロジックは一切書きませんし、結果を目にすることもありません。UIもインタラクションもAppleが受け持ちます。「ユーザーにこの一節を翻訳させたい」という用途なら、これだけで機能の全体が完成します。これより重いものに手を伸ばすのは無駄な労力です。

プログラム的な表面はTranslationSessionで、iOS 18から使えます。これにはtranslationTaskモディファイア経由でアクセスします。このモディファイアはasyncクロージャを実行し、あなた自身が呼び出すセッションを手渡します。だから翻訳されたテキストはあなたのコードに返ってきて、思いどおりに描画できます2

.translationTask(configuration) { session in
    let response = try await session.translate("Good morning")
    await MainActor.run { translated = response.targetText }
}

棲み分けは明快です。translationPresentationはAppleのUIでユーザーに翻訳を見せるためのもの。TranslationSessionは翻訳済みテキストを自分のデータとビューに取り込むためのもの。一度きりの「これを翻訳」を超えることをするアプリのほとんどは、セッションのほうを選ぶことになります。

バッチ翻訳:ループではなく、リストを翻訳する

なめらかな機能とぎこちない機能を分けるディテールが、バッチ処理です。リスト(チャットのメッセージ、カタログの項目、ラベルの集合)を翻訳する必要があるなら、ループして1件ずつawaitしてはいけません。TranslationSessionはリクエストのバッチを受け取り、それぞれをリクエストに対応づけたレスポンスを、1回のパスで返します3

.translationTask(configuration) { session in
    let requests = items.map { TranslationSession.Request(sourceText: $0.text, clientIdentifier: $0.id) }
    for try await response in session.translate(batch: requests) {
        store[response.clientIdentifier] = response.targetText
    }
}

肝心なのはclientIdentifierです。これはレスポンスに付いて返ってくるので、順序に頼らずに各翻訳を所属する行に対応づけられます。さらにバッチ処理なら、フレームワークはループで呼び出しごとのオーバーヘッドを払う代わりに、作業を効率よくスケジューリングできます。文字列1つを超えるなら、バッチで。

誰もスクリーンショットに撮らないオフラインの現実

ここが、きれいなデモをサポートチケットに変える縁です。翻訳はオンデバイスで動きますが、その言語がまずデバイス上に存在していなければなりません。アプリがある元言語→目的言語のペアを初めて翻訳するとき、システムは言語バンドルをダウンロードします。そのダウンロードには時間とネットワーク接続が要ります5。ダウンロードへの手当てをせずに翻訳を実行して結果を描画すると、新しい言語ごとに初回利用で機能がフリーズしたように見えてしまいます。

ここは意図的に捌きましょう。フレームワークは、必要になる瞬間より前に言語の利用可否を確認し、ペアを準備(ダウンロード)する手段を用意しています。だから「翻訳を準備中」という状態を見せたり、落ち着いた頃合いに先読みダウンロードしたりでき、操作の途中で止まらずに済みます5。心構えとしては、言語ペアの初回翻訳を一度きりのアセットダウンロードと同じように扱うこと。実際それがその正体だからです。ダウンロードが存在する前提でUXを設計すれば、オフラインかつ無料という利点がきちんと届きます。無視すれば、その利点はフリーズの裏に隠れてしまいます。

学ぶのが遅れると半日を失う事実が、あと2つあります。翻訳UIの表面はSwiftUIモディファイアなので、UIKitの画面はそれらに到達するために(UIHostingController経由で)SwiftUIビューをホストします。とはいえ、UIを伴わない作業のためならTranslationSessionを直接構築することもできます4。そしてこのフレームワークはiOSやiPadOSのシミュレーターでは動作しません。翻訳のテストは実機で行います4。どちらも声高には文書化されておらず、どちらも真正面からぶつかりやすい落とし穴です。

翻訳とFoundation Modelsを組み合わせる

持ち帰る価値のある統合は、このフレームワークをオンデバイススタックの残りの部分と結びつけます。オンデバイスの言語処理のほとんどは、入力があなたのロジックとシステムモデルがうまく扱える言語であることを前提にしています。しかし現実のユーザーは協力してくれません。Translationフレームワークはその溝を埋めます——ユーザーの入力を、機能が推論する言語へ翻訳し、その翻訳済みテキストに対してFoundation Modelsの処理を走らせ、結果をまた元の言語へ翻訳して戻すのです。

形は括弧(ブラケット)です——翻訳して入れ、推論し、翻訳して出す。

// 1. translate the user's text into English (session configured for their language -> en)
let english = try await inboundSession.translate(userText).targetText
// 2. reason on-device, monolingually, in English
let summary = try await LanguageModelSession()
    .respond(to: "Summarize in one line: \(english)").content
// 3. translate the result back (a session configured for en -> their language)
let localized = try await outboundSession.translate(summary).targetText

サポートのトリアージ機能、ノートの要約、意図の抽出——いずれも一度だけ、単一言語で書いて、Foundation Modelsの呼び出しをTranslationで挟むことで、デバイスにインストールできるあらゆる言語で動かせます。2つの方向には2つのセッション構成を使います(ユーザーの言語から英語へ、それから英語を元へ)。セッションは1つの言語ペアに対して構成されるからです。どちらの層もオンデバイスで、どちらも無料、そして何もスマートフォンの外へ出ません。だから多言語版は、単一言語版が払っていなかったプライバシーのコストもクラウドの請求書も払わずに済みます。その合成(翻訳して入れ、推論し、翻訳して出す)こそ、小さなオンデバイス機能を本当の意味でグローバルにするパターンであり、それが可能なのは両方の半分がローカルで無料で動くからにほかなりません。

使うべきでないとき

オンデバイス翻訳は無料でプライベートです。だからアプリ内翻訳の既定の選択肢として正しい。とはいえ、いくつかの正直な場面では誤った道具です。

  • 可能なかぎり最高の翻訳品質、あるいは最も広い言語カバレッジが必要なとき。 オンデバイスモデルは良質ですが、最良ではありません。インストールできる言語のセットも有限です。重大な翻訳(法務、医療、公開コンテンツ)では、品質と網羅性で専用のクラウド翻訳サービスがなお勝ります。
  • 初回利用のダウンロードを許容できないとき。 ネットワークなしで初回起動から即座に動かねばならない機能では、オンボーディング中に先読みダウンロードしておかないかぎり、このダウンロード要件だけでオンデバイス翻訳が失格になることもあります。
  • アプリがUIKitでSwiftUIホストを置く余地がない、あるいはフローがシミュレーターで動く必要がある場合(たとえば自動UIテスト)。SwiftUI専用とシミュレーター不可という制約は、助言ではなく硬い制約です。

このフレームワークは、オンデバイスのツールキットの中でも控えめな勝利のひとつです——本当に無料でプライベートな翻訳エンジンで、たいていのアプリが半日で導入できます。求められる技量は、このスタックの他の部分が報いるのと同じものです。どの表面が合うか(システムのポップオーバーか、自分のセッションか)を見極め、リストがあるならバッチで処理し、ダウンロードを存在しないふりをするのではなく、それを前提に設計する。そうすれば翻訳はクラウドへの依存ではなくなり、デバイスが無料でこなす他のすべてと組み合わせられるローカルの能力になります。

FAQ

AppleのTranslationフレームワークは無料でオンデバイスですか?

はい。翻訳はオンデバイスで動き、無料で、何もスマートフォンの外へ出ません。だからアプリ内翻訳の既定の選択肢として正しいのです。トレードオフは、翻訳品質と言語カバレッジが最高クラスというより良質という水準にあること。なので重大な作業では、なおクラウドサービスを使いたい場合があります。

なぜ最初の翻訳が止まったり、ダウンロードが必要になったりするのですか?

翻訳はオンデバイスで動きますが、その言語ペアがまずデバイス上に存在していなければなりません。ある元言語→目的言語のペアを初めて翻訳するとき、システムは言語バンドルをダウンロードします。これには時間とネットワーク接続が要ります5。必要になる瞬間より前に利用可否を確認してペアを準備(先読みダウンロード)しておけば、操作の途中で止まる代わりに「準備中」の状態を見せられます。

アプリに翻訳を追加する2つの方法とは?

SwiftUIのプレゼンテーションモディファイアによるシステムのポップオーバーか、UIを伴わない作業のために直接構築したTranslationSessionで駆動する自前のUIです4。これらの表面はSwiftUIモディファイアなので、UIKitの画面はUIHostingControllerを通じてSwiftUIビューをホストすることでそれらに到達します。

AppleのTranslationフレームワークはシミュレーターで動きますか?

いいえ。このフレームワークはiOSやiPadOSのシミュレーターでは動作しないため、翻訳のテストは実機で行います4。この制約は助言ではなく硬い制約で、自動化されたシミュレーターUIテストの中での翻訳も同様に除外されます。

Foundation Modelsの機能をあらゆる言語で動かすには?

括弧で挟みます——ユーザーの入力を、ロジックが推論する言語へ翻訳し、その翻訳済みテキストにFoundation Modelsの処理を走らせ、結果をまた元へ翻訳して戻すのです。2つの方向には2つのTranslationSession構成を使います(ユーザーの言語から英語へ、それから英語を元へ)。セッションは1つの言語ペアに対して構成されるからです。どちらの層もオンデバイスで無料なので、多言語版にプライバシーのコストもクラウドの請求書もかかりません。

オンデバイス翻訳を使うべきでないのはどんなときですか?

可能なかぎり最高の品質や最も広い言語カバレッジが必要なとき(法務、医療、公開コンテンツ)、機能がネットワークなしで初回起動から即座に動かねばならず先読みダウンロードできないとき、あるいはフローがシミュレーターで動く必要がある、もしくはUIKitでSwiftUIホストを置く余地がないとき。これら最後の制約は硬い限界です。



  1. Apple Developer, “Translation” framework. Core MLモデルの上に構築された、オンデバイスでシステム提供の翻訳のためのファーストパーティフレームワーク。言語アセットがインストールされていれば、ネットワーク通信なしでローカルに翻訳を実行する。 

  2. Apple Developer, “translationPresentation(isPresented:text:attachmentAnchor:arrowEdge:replacementAction:)”(iOS 17.4以降)はビューの上にシステム組み込みの翻訳UIを提示する。“translationTask(_:action:)”(iOS 18以降)はasyncクロージャを実行し、自前のインターフェースでプログラム的な翻訳を行うTranslationSessionを提供する。 

  3. Apple Developer, TranslationSessionおよびTranslationSession.Request. translate(_:)は単一の文字列を扱う。バッチAPIはリクエストの配列を受け取り、各リクエストはclientIdentifierを携える。これが対応するレスポンスに付いて返るため、結果を順序とは独立に入力へ再対応づけできる。 

  4. Translationフレームワークの翻訳APIはSwiftUIビューモディファイア(translationTasktranslationPresentation)を通じて表面化され、UIKitのエントリーポイントを持たない。UIKitの画面は(たとえばUIHostingController経由で)SwiftUIビューをホストしてそれらを使う。フレームワークはまた物理デバイスを要求し、iOSシミュレーターでは機能しない。Translationフレームワークのドキュメントおよび“Translating text within your app”を参照。 

  5. Apple Developer, “Translating text within your app”およびLanguageAvailability. 元言語→目的言語のペアの初回翻訳では、必要な言語アセットがダウンロードされる。フレームワークは言語の利用可否チェックと、ペアを事前に準備(ダウンロード)する手段を公開しており、アプリは初回利用で止まる代わりにダウンロードの瞬間を管理できる。 

  6. オンデバイス能力の合成に関する筆者の関連分析:Apple Foundation Models:オンデバイスLLMフレームワークAppleのFoundation ModelsによるオンデバイスLLMWriting Tools APIの導入. 翻訳して入れ、推論し、翻訳して出すというパターンは、単一言語のFoundation Models呼び出しをTranslationで挟むことで、デバイスの外へ出ることなくオンデバイス機能を多言語化する。 

関連記事

Image Playground API:SwiftUIシート、プログラムによるImage Creator、そしてスタイル制御

Image Playgroundはアプリに2つの経路を提供します。SwiftUIのimagePlaygroundSheetモディファイアと、コンセプトから画像を生成するプログラム的なImageCreator APIです。

2 分で読める

GenmojiとNSAdaptiveImageGlyph:iOS 18+でのインライン絵文字

Genmojiは属性付きテキスト内でNSAdaptiveImageGlyphとして提供されます。TextKit 2を使用するUITextViewのアプリでは、supportsAdaptiveImageGlyphを有効にし、シリアライズに対応…

1 分で読める

The Robots Are Taking Exams in My Search Console

First-party GSC data: 91% of 3.8M impressions fail a human-query filter. Exam questions, pasted errors, and agent sweeps…

10 分で読める