← Todos os Posts

O framework de tradução da Apple: gratuito, no dispositivo e mais afiado do que parece

O framework Translation da Apple traduz texto no próprio dispositivo, de graça, sem chave de API e sem nenhuma chamada de rede depois que o idioma é instalado1. Ele é construído sobre modelos Core ML, acompanha o sistema e oferece a um app o mesmo motor de tradução que o app Tradutor usa. Para recursos multilíngues que antes significavam uma conta de tradução na nuvem e uma dúvida de privacidade, o custo volta a arredondar para zero. E, assim como acontece com o framework Foundation Models, a parte interessante não é o caminho feliz; são as bordas que as demos pulam: o download do idioma que bloqueia sua primeira tradução, o simulador que silenciosamente se recusa a funcionar e a superfície exclusiva de SwiftUI que molda a forma como você o adota.

Resumo

  • Duas superfícies, duas versões do iOS. translationPresentation exibe o popover de tradução nativo da Apple (iOS 17.4+). TranslationSession, acessado pelo modificador translationTask, faz tradução programática dentro da sua própria interface (iOS 18+)2.
  • A tradução programática é async. Dentro da closure de translationTask você recebe um TranslationSession; chame-o para traduzir uma única string ou um lote3.
  • O lote é de primeira classe. Traduza uma lista em uma única requisição e mantenha cada resultado vinculado à sua entrada, em vez de iterar e aguardar um por vez3.
  • A interface de tradução é exclusiva de SwiftUI e não roda no Simulador do iOS. Os dois detalhes são fáceis de descobrir do jeito difícil; projete e teste levando isso em conta4.
  • Offline significa um download primeiro. A primeira tradução de um par de idiomas baixa pacotes, o que é um momento real de UX que você precisa tratar, não um detalhe5.
  • O casamento que vale conhecer: traduza a entrada do usuário com Translation, raciocine sobre ela com Foundation Models, e um recurso de agente monolíngue no dispositivo passa a funcionar em qualquer idioma que o aparelho consiga instalar.

Duas superfícies: o popover do sistema e a sua própria interface

O framework oferece duas formas distintas de traduzir, e escolher a certa já é a maior parte da decisão.

A opção leve é translationPresentation, disponível desde o iOS 17.4. Você a anexa a uma view, vincula um flag isPresented e passa o texto; quando o flag fica verdadeiro, o sistema desliza para cima o próprio popover de tradução sobre o seu conteúdo2:

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

Você não escreve nenhuma lógica de tradução e não enxerga o resultado; a Apple é dona da interface e da interação. Para “deixe o usuário traduzir esta passagem”, esse é o recurso inteiro, e partir para qualquer coisa mais pesada é trabalho desperdiçado.

A superfície programática é TranslationSession, disponível desde o iOS 18, e você a acessa pelo modificador translationTask. O modificador executa uma closure assíncrona e te entrega uma sessão que você mesmo chama, de modo que o texto traduzido volta para o seu código e você o renderiza do seu jeito2:

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

A divisão é limpa. translationPresentation serve para mostrar ao usuário uma tradução na interface da Apple. TranslationSession serve para trazer texto traduzido para os seus dados e suas views. A maioria dos apps que faz mais do que um “traduza isto” pontual recorre à sessão.

Tradução em lote: traduza a lista, não o loop

O detalhe que separa um recurso fluido de um truncado é o uso de lotes. Se você precisa traduzir uma lista (mensagens de chat, itens de catálogo, um conjunto de rótulos), não itere e use await em cada tradução por vez. O TranslationSession recebe um lote de requisições e devolve as respostas, cada uma vinculada à sua requisição, numa única passagem3:

.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
    }
}

O clientIdentifier é a parte que importa: ele retorna na resposta para que você consiga vincular cada tradução à linha à qual ela pertence sem depender da ordem. O lote também permite que o framework agende o trabalho de forma eficiente, em vez de pagar o custo por chamada ao longo de um loop. Para qualquer coisa além de uma única string, use lote.

A realidade offline que ninguém fotografa

Aqui está a borda que transforma uma demo limpa em um chamado de suporte. A tradução roda no dispositivo, mas o idioma precisa estar no dispositivo primeiro. Na primeira vez em que seu app traduz um determinado par de origem para destino, o sistema baixa os pacotes do idioma, e esse download leva tempo e exige conexão de rede5. Se você dispara uma tradução e renderiza o resultado sem nenhum tratamento para o download, seu recurso parece travar no primeiro uso para cada idioma novo.

Trate isso de forma deliberada. O framework permite verificar a disponibilidade do idioma e preparar (baixar) um par com antecedência, antes do momento em que você precisa dele, para que você possa exibir um estado de “preparando a tradução” ou pré-baixar num momento mais tranquilo, em vez de travar no meio da interação5. O modelo mental: trate a primeira tradução de um par de idiomas como o download único de um recurso, porque é exatamente isso que ela é. Planeje a UX contando com a existência do download, e o benefício de ser offline e gratuito se concretiza; ignore-a, e o benefício fica escondido atrás de um travamento.

Mais dois fatos que custam uma tarde se você os descobre tarde demais. As superfícies de interface de tradução são modificadores de SwiftUI, então uma tela em UIKit precisa hospedar uma view SwiftUI (por meio do UIHostingController) para acessá-las, embora um TranslationSession também possa ser construído diretamente para trabalho sem interface4. E o framework não roda no Simulador do iOS ou do iPadOS; você testa a tradução em um dispositivo físico4. Nenhum dos dois está documentado em alto e bom som, e os dois são fáceis de bater de frente.

Combinando tradução com Foundation Models

A síntese que vale levar conecta este framework ao resto da pilha que roda no dispositivo. A maior parte do trabalho de linguagem no dispositivo pressupõe que a entrada esteja num idioma que a sua lógica e o modelo do sistema tratam bem. Os usuários reais não colaboram. O framework Translation fecha essa lacuna: traduza a entrada do usuário para o idioma em que o seu recurso raciocina, execute o trabalho com Foundation Models sobre o texto traduzido e depois traduza o resultado de volta.

O formato é um colchete: traduza para dentro, raciocine, traduza para fora.

// 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

Um recurso de triagem de suporte, um resumidor de notas, um extrator de intenção: cada um pode ser escrito uma vez, de forma monolíngue, e passar a funcionar em qualquer idioma que o aparelho consiga instalar, colocando a chamada de Foundation Models entre colchetes com Translation. As duas direções usam duas configurações de sessão (o idioma do usuário para o inglês e, depois, o inglês de volta), já que uma sessão é configurada para um único par de idiomas. As duas camadas rodam no dispositivo, as duas são gratuitas e nada sai do telefone, então a versão multilíngue não custa nenhuma privacidade nem nenhuma conta de nuvem que a versão monolíngue já não custasse. Essa composição (traduza para dentro, raciocine, traduza para fora) é o padrão que torna um pequeno recurso no dispositivo genuinamente global, e ele só é possível porque as duas metades rodam localmente de graça.

Quando não usar

A tradução no dispositivo é gratuita e privada, o que a torna o padrão certo para tradução dentro do app. Ela é a ferramenta errada em alguns casos honestos.

  • Você precisa da melhor qualidade de tradução possível ou da maior cobertura de idiomas. Os modelos no dispositivo são bons, não os melhores disponíveis, e o conjunto de idiomas instaláveis é finito. Para tradução de alto risco (jurídica, médica, conteúdo publicado), um serviço de tradução em nuvem dedicado ainda vence em qualidade e abrangência.
  • Você não pode tolerar o download de primeiro uso. Para um recurso que precisa funcionar instantaneamente no primeiro lançamento sem rede, o requisito de download pode, por si só, desqualificar a tradução no dispositivo, a menos que você faça o pré-download durante o onboarding.
  • Seu app é em UIKit sem espaço para um host de SwiftUI, ou o seu fluxo precisa rodar no Simulador (um teste automatizado de interface, por exemplo). As restrições de ser exclusivo de SwiftUI e de não rodar no Simulador são rígidas, não meras recomendações.

O framework é uma das vitórias mais discretas do kit de ferramentas no dispositivo: um motor de tradução genuinamente gratuito e privado que a maioria dos apps poderia adotar numa tarde. A habilidade é a mesma que o resto dessa pilha recompensa. Saiba qual superfície se encaixa (o popover do sistema ou a sua própria sessão), use lotes quando tiver uma lista e projete contando com o download em vez de fingir que ele não existe. Faça isso, e a tradução deixa de ser uma dependência de nuvem e passa a ser uma capacidade local que você compõe com tudo o mais que o aparelho faz de graça.

Perguntas frequentes

O framework Translation da Apple é gratuito e roda no dispositivo?

Sim. A tradução roda no dispositivo e é gratuita, sem nada saindo do telefone, o que a torna o padrão certo para tradução dentro do app. A contrapartida é que a qualidade da tradução e a cobertura de idiomas são boas, não as melhores da categoria, então trabalhos de alto risco ainda podem preferir um serviço de nuvem.

Por que a primeira tradução trava ou pede um download?

A tradução roda no dispositivo, mas o par de idiomas precisa estar no dispositivo primeiro. Na primeira vez em que você traduz um determinado par de origem para destino, o sistema baixa os pacotes do idioma, o que exige tempo e conexão de rede5. Verifique a disponibilidade e prepare (faça o pré-download) o par antes do momento em que você precisa dele, para poder exibir um estado de “preparando” em vez de travar no meio da interação.

Quais são as duas formas de adicionar tradução a um app?

O popover do sistema, por meio de um modificador de apresentação do SwiftUI, ou a sua própria interface, conduzida por um TranslationSession construído diretamente para trabalho sem interface4. Como as superfícies são modificadores de SwiftUI, uma tela em UIKit chega até elas hospedando uma view SwiftUI por meio do UIHostingController.

O framework Translation da Apple funciona no Simulador?

Não. O framework não roda no Simulador do iOS ou do iPadOS, então você testa a tradução em um dispositivo físico4. Essa restrição é rígida, não uma recomendação, e também descarta a tradução dentro de testes automatizados de interface no Simulador.

Como faço um recurso de Foundation Models funcionar em qualquer idioma?

Coloque-o entre colchetes: traduza a entrada do usuário para o idioma em que a sua lógica raciocina, execute o trabalho com Foundation Models sobre o texto traduzido e depois traduza o resultado de volta. As duas direções usam duas configurações de TranslationSession (o idioma do usuário para o inglês e, depois, o inglês de volta), já que uma sessão é configurada para um único par de idiomas. As duas camadas rodam no dispositivo e são gratuitas, então a versão multilíngue não custa nenhuma privacidade nem nenhuma conta de nuvem.

Quando eu não deveria usar a tradução no dispositivo?

Quando você precisa da melhor qualidade possível ou da maior cobertura de idiomas (conteúdo jurídico, médico, publicado), quando um recurso precisa funcionar instantaneamente no primeiro lançamento sem rede e você não pode fazer o pré-download, ou quando o seu fluxo precisa rodar no Simulador ou é em UIKit sem espaço para um host de SwiftUI. Essas últimas restrições são limites rígidos.



  1. Apple Developer, framework “Translation”. Um framework de primeira parte para tradução no dispositivo, fornecida pelo sistema e construída sobre modelos Core ML, que realiza a tradução localmente sem nenhuma chamada de rede depois que os pacotes do idioma estão instalados. 

  2. Apple Developer, “translationPresentation(isPresented:text:attachmentAnchor:arrowEdge:replacementAction:)” (iOS 17.4+) apresenta a interface de tradução nativa do sistema sobre uma view; “translationTask(_:action:)” (iOS 18+) executa uma closure assíncrona que fornece um TranslationSession para tradução programática na sua própria interface. 

  3. Apple Developer, TranslationSession e TranslationSession.Request. translate(_:) trata uma única string; a API de lote recebe um array de requisições, cada uma carregando um clientIdentifier que retorna na resposta correspondente, de modo que os resultados podem ser reassociados às suas entradas independentemente da ordem. 

  4. As APIs de tradução do framework Translation são expostas por meio de modificadores de view do SwiftUI (translationTask, translationPresentation) e não têm ponto de entrada em UIKit; uma tela em UIKit hospeda uma view SwiftUI (por exemplo, via UIHostingController) para usá-las. O framework também exige um dispositivo físico e não funciona no Simulador do iOS. Veja a documentação do framework Translation e “Translating text within your app”

  5. Apple Developer, “Translating text within your app” e LanguageAvailability. A primeira tradução de um par de idiomas de origem para destino baixa os pacotes de idioma necessários; o framework expõe verificações de disponibilidade de idioma e uma forma de preparar (baixar) um par com antecedência, para que os apps possam gerenciar o momento do download em vez de travar no primeiro uso. 

  6. Análise relacionada do autor sobre como compor capacidades no dispositivo: Apple Foundation Models: o framework de LLM no dispositivo, LLMs no dispositivo com o Foundation Models da Apple e Adoção da API Writing Tools. O padrão de traduzir para dentro, raciocinar e traduzir para fora coloca uma chamada monolíngue de Foundation Models entre colchetes com Translation para tornar um recurso no dispositivo multilíngue sem que nada saia do aparelho. 

Artigos relacionados

Image Playground API: sheet no SwiftUI, criação programática de imagens e controle de estilo

O Image Playground dá aos apps dois caminhos: o modifier imagePlaygroundSheet do SwiftUI e a API programática ImageCreat…

11 min de leitura

Genmoji e NSAdaptiveImageGlyph: emoji inline no iOS 18+

Genmoji é entregue como NSAdaptiveImageGlyph em texto atribuído. Aplicativos que usam UITextView com TextKit 2 ativam su…

9 min de leitura

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 min de leitura