Translator.create() exige activación transitoria siempre que todavía haya que descargar el paquete de idioma, que es todo perfil nuevo. Llámalo desde un callback de voz y rechaza con NotAllowedError, justo en las máquinas donde más importa: las que no lo han ejecutado nunca. El precalentamiento tiene que ocurrir de forma síncrona dentro de un clic.
Por qué funciona en tu máquina
Una vez que el paquete está en disco, create resuelve sin activación y todo parece correcto. Así que el fallo es invisible para quien lo construyó, de la segunda ejecución en adelante, y solo aparece para quien abre la función por primera vez. Esa es la peor distribución posible: está roto justo para los usuarios nuevos y funciona para todos los que lo prueban.
Qué permite en realidad la activación transitoria
Es una ventana corta que abre un gesto real del usuario, y la consume el primer await. Esa es la parte que pilla a la gente. Un manejador de clic que hace await de getUserMedia y luego llama a create ya ha perdido la activación cuando llega ahí, aunque el código siga dentro del manejador y se lea como si no.
// 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();
}Así que la regla de orden es estrecha: arranca create antes del primer await y deja que se resuelva en segundo plano. Un callback de reconocimiento de voz llega tardísimo; para entonces el gesto quedó atrás hace minutos.
Diseña la función alrededor del gesto
Esto no es un apaño que se añade, condiciona la interfaz. Tiene que existir un momento en que la persona activa la traducción a propósito, y ese momento tiene que ser el que precalienta el paquete. Si la traducción debe arrancar en silencio al detectar voz, no hay gesto que gastar y la función no puede funcionar en una primera visita.
De todos modos prefiero esta vía cuando está disponible, porque no cuesta nada y nada sale de la máquina. Chrome en escritorio puede reconocer voz en local y traducir en local. Todo lo demás cae a un servicio alojado, que funciona y es el plan B en vez del predeterminado.
Cómo probarlo
- Prueba siempre con un perfil nuevo. Un perfil ya caliente no puede reproducir el fallo.
- Emula la regla en vez de fiarte de ella: un doble que rechaza con NotAllowedError salvo que haya habido un gesto en los últimos segundos pilla la regresión en CI sin descargar nada.
- Comprueba también la ruta de fallo. Si create rechaza, los subtítulos deben seguir apareciendo sin traducir en vez de desaparecer, porque un subtítulo que falta se lee como un micrófono roto.