Framework Translation da Apple: gratuito, on-device 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 está instalado1. Ele é construído sobre modelos Core ML, vem junto com o sistema e dá ao seu 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 pergunta sobre privacidade, o custo volta a arredondar para zero. E, assim como no framework Foundation Models6, a parte interessante não é o caminho feliz; são as arestas que as demos ignoram: o download do idioma que trava sua primeira tradução, o simulador que silenciosamente se recusa a funcionar e a superfície exclusiva do SwiftUI que molda como você adota tudo isso.
Resumo
- Duas superfícies, duas versões do iOS.
translationPresentationexibe o popover de tradução nativo da Apple (iOS 17.4+).TranslationSession, acessado pelo modificadortranslationTask, faz tradução programática dentro da sua própria interface (iOS 18+)2. - Tradução programática é
async. Dentro do closure detranslationTaskvocê recebe umaTranslationSession; chame-a para traduzir uma string ou um lote inteiro3. - Lote é cidadão de primeira classe. Traduza uma lista em uma única requisição e mantenha cada resultado casado com sua entrada, em vez de percorrer item a item esperando um de cada vez3.
- A interface de tradução é exclusiva do SwiftUI e não roda no simulador do iOS. Ambas as coisas são fáceis de descobrir do jeito difícil; projete e teste levando isso em conta4.
- Offline significa um download antes. A primeira tradução de um par de idiomas baixa os pacotes, e isso é um momento real de UX que você precisa tratar, não um detalhe5.
- A combinação que vale conhecer: traduza a entrada do usuário com Translation, depois raciocine sobre ela com Foundation Models — e um recurso de agente on-device monolíngue passa a funcionar em qualquer idioma que o dispositivo 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.
O toque leve é translationPresentation, disponível desde o iOS 17.4. Você o anexa a uma view, vincula uma flag isPresented e passa o texto; quando a flag vira true, o sistema desliza o próprio popover de tradução por cima do seu conteúdo2:
.translationPresentation(isPresented: $showTranslation, text: selectedText)
Você não escreve nenhuma lógica de tradução e não vê o resultado; a Apple é dona da interface e da interação. Para o caso “deixe o usuário traduzir este trecho”, isso é o recurso inteiro, e partir para qualquer coisa mais pesada é trabalho jogado fora.
A superfície programática é TranslationSession, disponível desde o iOS 18, e você chega até ela pelo modificador translationTask. O modificador executa um closure assíncrono e te entrega uma sessão que você mesmo chama, então 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 dentro da interface da Apple. TranslationSession serve para trazer o texto traduzido para os seus dados e as suas views. A maioria dos apps que faz algo além de um “traduza isto” pontual recorre à sessão.
Tradução em lote: traduza a lista, não o laço
O detalhe que separa um recurso fluido de um recurso truncado é o processamento em lote. Se você precisa traduzir uma lista (mensagens de chat, itens de catálogo, um conjunto de rótulos), não percorra item a item dando await em cada tradução. TranslationSession recebe um lote de requisições e devolve as respostas, cada uma casada com sua requisição, em uma única passada3:
.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 peça que importa: ele volta na resposta, então você consegue casar cada tradução com a linha à qual ela pertence sem depender da ordem. O lote também permite que o framework organize o trabalho de forma eficiente, em vez de pagar o custo de cada chamada individual ao longo de um laço. Para qualquer coisa além de uma única string, use lote.
A realidade offline que ninguém coloca no screenshot
Aqui está a aresta que transforma uma demo limpa em um chamado de suporte. A tradução roda no dispositivo, mas o idioma precisa estar no dispositivo antes. Na primeira vez que seu app traduz um determinado par origem-destino, o sistema baixa os pacotes de idioma, e esse download consome 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 a cada novo idioma.
Trate isso de forma deliberada. O framework permite verificar a disponibilidade de idiomas e preparar (baixar) um par antes do momento em que você precisa dele, então você pode exibir um estado de “preparando tradução” ou fazer o download antecipado em um 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 um download de pacotes que acontece uma única vez, porque é exatamente isso que ele é. Planeje a UX contando com a existência do download, e o benefício de ser offline e gratuito aparece; ignore-o, e o benefício some atrás de um travamento.
Mais dois fatos que custam uma tarde inteira se você os descobrir tarde. As superfícies de interface de tradução são modificadores SwiftUI, então uma tela em UIKit hospeda uma view SwiftUI (via UIHostingController) para alcançá-las, embora uma TranslationSession também possa ser construída diretamente para trabalho sem interface4. E o framework não roda no simulador do iOS nem do iPadOS; tradução você testa em um dispositivo real4. Nenhum dos dois está documentado em alto e bom som, e é fácil bater de frente com ambos.
Combinando tradução com Foundation Models
A síntese que vale levar amarra este framework ao resto da pilha on-device. A maior parte do trabalho de linguagem no dispositivo pressupõe que a entrada está em um idioma que sua lógica e o modelo do sistema tratam bem. Usuários reais não colaboram. O framework Translation fecha essa lacuna: traduza a entrada do usuário para o idioma em que seu recurso raciocina, execute o trabalho de Foundation Models sobre o texto traduzido e depois traduza o resultado de volta.
O formato é um sanduíche: traduz para dentro, raciocina, traduz 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 dispositivo consiga instalar, bastando envolver a chamada de Foundation Models 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 (traduz para dentro, raciocina, traduz para fora) é o padrão que torna um pequeno recurso on-device genuinamente global, e ela só é possível porque as duas metades rodam localmente de graça.
Quando não usar
A tradução on-device é 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 on-device 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 dedicado de tradução na nuvem ainda ganha em qualidade e abrangência.
- Você não pode tolerar o download de primeiro uso. Para um recurso que precisa funcionar instantaneamente já na primeira execução e sem rede, a exigência de download pode, sozinha, desqualificar a tradução on-device — a não ser que você faça o download antecipado durante o onboarding.
- Seu app é UIKit sem espaço para hospedar SwiftUI, ou seu fluxo precisa rodar no simulador (um teste de UI automatizado, por exemplo). As restrições de ser exclusivo do SwiftUI e não rodar no simulador são rígidas, não recomendações.
O framework é uma das vitórias mais silenciosas do kit de ferramentas on-device: um motor de tradução genuinamente gratuito e privado que a maioria dos apps conseguiria adotar em uma tarde. A habilidade exigida é 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 lote 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 para virar uma capacidade local que você compõe com tudo o mais que o dispositivo 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 troca é que a qualidade da tradução e a cobertura de idiomas são boas, mas não as melhores do mercado, então trabalhos de alto risco ainda podem pedir um serviço na 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 antes. Na primeira vez que você traduz um determinado par origem-destino, o sistema baixa os pacotes de idioma, o que exige tempo e conexão de rede5. Verifique a disponibilidade e prepare (baixe antecipadamente) o par antes do momento em que vai precisar dele, assim você mostra 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, via um modificador de apresentação do SwiftUI, ou a sua própria interface movida por uma TranslationSession construída diretamente para trabalho sem interface4. Como as superfícies são modificadores SwiftUI, uma tela em UIKit chega até elas hospedando uma view SwiftUI através de UIHostingController.
O framework Translation da Apple funciona no simulador?
Não. O framework não roda no simulador do iOS nem do iPadOS, então tradução você testa em um dispositivo real4. Essa restrição é rígida, não uma recomendação, e também descarta tradução dentro de testes de UI automatizados no simulador.
Como faço um recurso de Foundation Models funcionar em qualquer idioma?
Envolva-o: traduza a entrada do usuário para o idioma em que sua lógica raciocina, execute o trabalho de 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 tradução on-device?
Quando você precisa da melhor qualidade possível ou da maior cobertura de idiomas (jurídico, médico, conteúdo publicado), quando um recurso precisa funcionar instantaneamente já na primeira execução, sem rede, e você não pode fazer o download antecipado, ou quando seu fluxo precisa rodar no simulador ou é UIKit sem espaço para hospedar SwiftUI. Essas últimas restrições são limites rígidos.
-
Apple Developer, framework “Translation”. Um framework nativo para tradução on-device fornecida pelo sistema, construído sobre modelos Core ML, que executa a tradução localmente sem chamada de rede depois que os pacotes de idioma estão instalados. ↩
-
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 um closure assíncrono que fornece uma
TranslationSessionpara tradução programática dentro da sua própria interface. ↩↩↩ -
Apple Developer,
TranslationSessioneTranslationSession.Request.translate(_:)lida com uma única string; a API de lote recebe um array de requisições, cada uma carregando umclientIdentifierque retorna na resposta correspondente, de modo que os resultados possam ser reassociados às suas entradas independentemente da ordem. ↩↩↩ -
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, viaUIHostingController) 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”. ↩↩↩↩↩ -
Apple Developer, “Translating text within your app” e
LanguageAvailability. A primeira tradução de um par de idiomas origem-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. ↩↩↩↩ -
Análise relacionada do autor sobre como compor capacidades on-device: Apple Foundation Models: o framework de LLM on-device, LLMs on-device com os Foundation Models da Apple e Adoção da API de Writing Tools. O padrão traduz-para-dentro, raciocina, traduz-para-fora envolve uma chamada monolíngue de Foundation Models com Translation para tornar um recurso on-device multilíngue sem que nada saia do dispositivo. ↩