O Translator.create() exige ativação transitória sempre que o pacote de idioma ainda tem de ser descarregado, ou seja, em todo o perfil novo. Chama-o a partir de um callback de voz e rejeita com NotAllowedError, precisamente nas máquinas onde mais interessa: as que nunca o correram. O aquecimento tem de acontecer de forma síncrona dentro de um clique.
Porque funciona na tua máquina
Assim que o pacote está em disco, o create resolve sem ativação e parece tudo bem. Por isso o erro é invisível para quem o construiu, da segunda execução em diante, e só aparece para quem abre a funcionalidade pela primeira vez. É a pior distribuição possível: está partido exatamente para os utilizadores novos e funciona para todos os que o testam.
O que a ativação transitória permite mesmo
É uma janela curta aberta por um gesto real do utilizador, e é gasta pelo primeiro await. É essa a parte que apanha as pessoas. Um handler de clique que faz await do getUserMedia e depois chama o create já perdeu a ativação quando lá chega, mesmo que o código continue dentro do handler e se leia como se não estivesse.
// Inside the click handler. No await before Translator.create, because the
// first await spends the activation and the call then rejects.
function onStart() {
// Wrong: await getUserMedia() here and the activation is gone.
const warm = Translator.create({ sourceLanguage: 'es', targetLanguage: 'en' });
warm.then((t) => (translator = t)).catch(() => (translator = null));
// Everything that can wait, waits after the create call is already in flight.
void startCaptureAndJoin();
}Por isso a regra de ordem é estreita: arranca o create antes do primeiro await e deixa-o resolver em segundo plano. Um callback de reconhecimento de voz chega tardíssimo; a essa altura o gesto ficou para trás há minutos.
Desenha a funcionalidade à volta do gesto
Isto não é um remendo que se acrescenta, condiciona a interface. Tem de existir um momento em que a pessoa liga a tradução de propósito, e esse momento tem de ser o que aquece o pacote. Se a tradução tem de arrancar em silêncio quando deteta voz, não há gesto para gastar e a funcionalidade não pode funcionar numa primeira visita.
De qualquer forma prefiro esta via quando está disponível, porque não custa nada e nada sai da máquina. O Chrome em computador consegue reconhecer voz localmente e traduzir localmente. Todo o resto cai para um serviço alojado, que funciona e que é o plano B em vez do padrão.
Como testar
- Testa sempre com um perfil novo. Um perfil já quente não consegue reproduzir a falha.
- Emula a regra em vez de confiar nela: um duplo que rejeita com NotAllowedError a não ser que tenha havido um gesto nos últimos segundos apanha a regressão em CI, sem descarregar nada.
- Verifica também o caminho de falha. Se o create rejeitar, as legendas têm de continuar a aparecer por traduzir em vez de desaparecerem, porque uma legenda em falta lê-se como um microfone avariado.