ENESFRPT

Profundidade em tudo. Superficialidade em nada.

Translator.create precisa de um clique real

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.

Tens uma coisa em mãos que tem de aguentar?

Se estás algures entre uma demo e um sistema de que depende gente a sério, essa é precisamente a parte que eu faço.