Translation APIs: Traducción y Detección en el Navegador

La web es global, pero el contenido a menudo no lo es. Las APIs de traducción tradicionales (Cloud Translation API, DeepL, etc.) son caras, lentas, y requieren enviar todo el contenido a servidores externos. Para aplicaciones en tiempo real como chats, comentarios en vivo, o soporte multilingüe, esto genera latencia perceptible y levanta preocupaciones de privacidad.
Chrome introduce dos APIs que resuelven esto: Translator API y Language Detector API. Ambas ejecutan modelos de traducción y detección de idioma completamente en el dispositivo del usuario, sin conexión a internet y sin enviar datos a servidores.
¿Por Qué Importa?
La diferencia fundamental es privacidad: puedes traducir documentos legales, historiales médicos, o conversaciones privadas sin que un solo byte salga del dispositivo.
Casos de uso que antes eran imposibles:
- Sectores regulados: Traducir historiales médicos sin violar HIPAA, documentos financieros sin incumplir compliance
- Aplicaciones offline-first: Traducciones en dispositivos sin conexión
- Chat en tiempo real: Traducción instantánea sin latencia de red
El trade-off: los modelos on-device son más pequeños que Google Translate o DeepL, por lo que la calidad puede ser inferior para textos complejos. Para la mayoría de casos (soporte, chat, contenido web), la calidad es suficiente.
Configuración del Entorno
Las Translation APIs comparten los mismos requisitos de hardware y configuración que las otras Built-in AI APIs. Si ya configuraste tu entorno, estás listo. Si no:
- Chrome Canary o Dev (versión 138+)
- Flags necesarios en
chrome://flags:Enables optimization guide on device: Enabled BypassPerfRequirementPrompt API for Gemini Nano: EnabledTranslation API: EnabledLanguage Detection API: Enabled
- Verificar componentes en
chrome://components: Actualizar "Optimization Guide On Device Model"
El Flujo de Trabajo Completo
Imagina un chat de soporte donde el agente habla español y el usuario inglés. Queremos traducción instantánea, privada, y sin depender de servicios externos.
Paso 1: Detectar el Idioma
Primero, necesitamos saber qué idioma habla el usuario. No asumas nada del navigator.language (el usuario puede tener el navegador en inglés pero escribir en español).
// 1. Verificar soporte del navegador
if (!('LanguageDetector' in self)) {
console.error('Language Detector API no soportada');
return;
}
// 2. Verificar disponibilidad del modelo
const availability = await LanguageDetector.availability();
if (availability === 'unavailable') {
// Hardware insuficiente, usar cloud API como fallback
return;
}
// 3. Crear el detector
const detector = await LanguageDetector.create();
// 4. Detectar idioma
const results = await detector.detect('Hello, how can I help you today?');
// results es un array ordenado por confianza descendente
const bestMatch = results[0];
console.log(bestMatch.detectedLanguage); // "en"
console.log(bestMatch.confidence); // 0.98
// El último elemento siempre es "und" (undetermined), representando
// la probabilidad de que el texto no sea reconocido
console.log(results[results.length - 1]);
// { detectedLanguage: "und", confidence: 0.02 }
La API retorna múltiples candidatos porque textos pueden ser multilingües ("I love sushi" puede detectar inglés y japonés).
Paso 2: Traducir el Texto
Una vez sabemos el idioma origen (en) y destino (es), creamos el traductor.
// 1. Verificar soporte
if (!('Translator' in self)) {
console.error('Translator API no soportada');
return;
}
// 2. Verificar disponibilidad para el par de idiomas
const availability = await Translator.availability({
sourceLanguage: 'en',
targetLanguage: 'es',
});
if (availability === 'unavailable') {
// Par de idiomas no soportado
console.error('Traducción en-es no disponible en este dispositivo');
return;
}
// 3. Crear traductor
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'es',
});
// 4. Traducir
const translated = await translator.translate(
'Hello, how can I help you today?'
);
console.log(translated);
// Output: "Hola, ¿cómo puedo ayudarte hoy?"
// 5. Limpiar recursos
translator.destroy();
Gestión de Paquetes de Idiomas
Los modelos de traducción son modulares: Chrome descarga pares de idiomas bajo demanda (en-es, ja-en, fr-de, etc.). Implicaciones:
- Primera vez es lenta:
create()puede tardar segundos/minutos descargando el paquete - Requiere user activation: La descarga necesita un click del usuario
- Almacenamiento: Cada paquete ocupa cientos de MB
Monitoreo de Descarga
Implementa una UX clara para mostrar el progreso de descarga:
const availability = await Translator.availability({
sourceLanguage: 'en',
targetLanguage: 'es',
});
if (availability === 'unavailable') {
showError('Este par de idiomas no está soportado en tu dispositivo');
return;
}
if (availability === 'downloadable') {
// Mostrar botón de descarga (requiere user activation)
showDownloadButton(
'Descargar modelo de traducción (una sola vez)',
async () => {
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'es',
monitor(m) {
m.addEventListener('downloadprogress', e => {
// e.loaded: 0 a 1 (progreso normalizado)
const percentage = Math.round(e.loaded * 100);
updateProgressBar(percentage);
console.log(`Descargando: ${percentage}%`);
});
},
});
hideDownloadButton();
showTranslationUI();
}
);
return;
}
if (availability === 'downloading') {
showMessage('Descarga en progreso... espera un momento');
return;
}
// availability === 'available'
// El modelo ya está descargado, crear directamente
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'es',
});
Nota: availability reporta "downloadable" para todos los pares de idiomas hasta que tu sitio descargue ese par (por privacidad).
Estados de Disponibilidad
| Estado | Significado | Acción Requerida |
|---|---|---|
unavailable | Hardware insuficiente o idioma no soportado | Usar cloud API como fallback |
downloadable | Modelo necesita descargarse | Mostrar botón de descarga (requiere user activation) |
downloading | Descarga en progreso | Mostrar UI de progreso |
available | Modelo listo para usar | Crear traductor directamente |
Limitaciones de Input y Quota
Al igual que las Task APIs, Translator tiene límites de tamaño de entrada:
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'es',
});
console.log(translator.inputQuota);
// Ej: 4096 (valor específico de implementación)
// Medir uso ANTES de traducir
const longText = '...texto muy largo...';
const usage = await translator.measureInputUsage(longText);
if (usage > translator.inputQuota) {
console.error(`Texto excede límite: ${usage} > ${translator.inputQuota}`);
// Dividir texto en chunks o usar cloud API
}
Advertencia: measureInputUsage() requiere un round-trip al modelo. No lo uses en el evento input (sería demasiado frecuente). Úsalo al hacer clic en "Traducir" o con debouncing (~500ms).
Traducción en Streaming
Para textos largos (varios párrafos), la traducción puede tardar segundos. El streaming mejora la percepción de velocidad mostrando resultados progresivamente:
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'es',
});
const outputElement = document.querySelector('#translation-output');
outputElement.textContent = ''; // Limpiar
try {
const stream = translator.translateStreaming(longText);
for await (const chunk of stream) {
// Cada chunk contiene el texto nuevo (delta), no acumulativo
outputElement.textContent += chunk;
}
} catch (error) {
if (error.name === 'QuotaExceededError') {
console.error(`Input demasiado largo: ${error.requested} > ${error.quota}`);
} else {
console.error('Error en traducción:', error);
}
}
translator.destroy();
UX recomendada: Muestra un skeleton loader durante el streaming y reemplázalo progresivamente con el texto traducido.
Language Detector: Consideraciones Importantes
Precisión vs Longitud de Input
La precisión depende dramáticamente de la longitud del texto. Textos muy cortos (<10 palabras) dan resultados no confiables.
// ❌ MAL: Muy corto
await detector.detect('Hi');
// ✅ BIEN: Suficiente contexto
await detector.detect(
'Hello! I would like to know more about your product. Can you help me?'
);
Para frases cortas, usa heurísticas simples o asume el idioma de navigator.language como fallback.
Idiomas Esperados
Si conocés los idiomas posibles de antemano, optimizá precisión y velocidad con expectedInputLanguages:
const detector = await LanguageDetector.create({
expectedInputLanguages: ['en', 'es', 'fr'],
});
Trade-off: Idiomas no esperados pueden no detectarse correctamente o lanzar NotSupportedError.
Monitoreo de descarga
Al igual que otras Built-in AI APIs, LanguageDetector.create() acepta un callback monitor(m) para rastrear progreso de descarga. Ver ejemplo de Translator.
Caso de Uso Real: Chat Multilingüe
Combinar ambas APIs permite crear un chat con traducción automática en tiempo real:
- Detección automática: Identifica el idioma cuando hay suficiente contexto (>10 palabras)
- Cache de traductores: Reutiliza instancias para cada par de idiomas
- Traducción bidireccional: Usuario ↔ Agente
- Fallback a cloud: Para pares no disponibles
La demo muestra un chat en tiempo real donde:
- El usuario puede escribir en inglés, español, francés, alemán o portugués
- El agente recibe los mensajes traducidos a su idioma configurado
- Las respuestas del agente se traducen de vuelta al idioma del usuario
- Ambos paneles muestran las traducciones con el texto original
Procesamiento Secuencial y UX
Advertencia: Las traducciones se procesan secuencialmente. Múltiples llamadas a translate() se bloquean hasta que las anteriores completen.
// ❌ Esto NO traduce en paralelo
const promises = messages.map(msg => translator.translate(msg));
const results = await Promise.all(promises);
Para múltiples mensajes, implementa indicadores de progreso acumulado.
Control de Acceso y Cancelación
Las Translation APIs siguen los mismos patrones de las otras Built-in AI APIs:
- Permissions Policy: Para habilitar en cross-origin iframes, usa
allow="translator; language-detector"en el elemento<iframe> - Cancelación con AbortController: Soporta
signalencreate()ytranslate()para cancelar descargas o traducciones en progreso - Web Workers: No soportado actualmente
Consulta la documentación de Prompt API para ejemplos detallados de estos patrones, que funcionan de manera idéntica en Translation APIs.
Manejo de Errores
Las Translation APIs lanzan errores estándar (QuotaExceededError, NotSupportedError, NetworkError, AbortError). El error más común es QuotaExceededError cuando el texto excede inputQuota:
try {
const result = await translator.translate(text);
} catch (error) {
if (error.name === 'QuotaExceededError') {
// Dividir en chunks o usar cloud API
const result = await cloudTranslate(text, from, to);
} else if (error.name === 'NotSupportedError') {
console.error('Par de idiomas no soportado, usar cloud API');
}
}
Comparativa: On-Device vs Cloud Translation
| Aspecto | Translation APIs (On-Device) | Cloud APIs (Google Translate, DeepL) |
|---|---|---|
| Privacidad | ✅ Total (sin salida de datos) | ❌ Contenido enviado a servidores |
| Latencia | ✅ <100ms (local) | ⚠️ 200-500ms (network round-trip) |
| Costo | ✅ Gratis (sin límites) | ❌ Pay-per-character |
| Offline | ✅ Funciona sin internet | ❌ Requiere conexión |
| Calidad | ⚠️ Buena (modelos pequeños) | ✅ Excelente (modelos grandes) |
| Pares de idiomas | ⚠️ Limitados por hardware | ✅ 100+ idiomas |
| Textos largos | ⚠️ Límite ~4K tokens | ✅ Sin límites prácticos |
| Soporte navegador | ⚠️ Solo Chrome 138+ | ✅ Universal (API REST) |
Estrategia: Translation APIs como default, fallback a cloud para textos largos, pares no soportados, o hardware insuficiente.
Conclusión
Las Translation APIs traen traducción y detección de idioma directamente al navegador, sin enviar datos a servidores. Esto abre casos de uso que antes eran imposibles: traducción de contenido sensible en sectores regulados, aplicaciones offline-first, y chat en tiempo real sin latencia de red.
El trade-off es claro: los modelos on-device son más pequeños, por lo que la calidad no alcanza a Google Translate o DeepL para textos complejos. Pero para la mayoría de casos (soporte, chat, contenido web), la calidad es suficiente y los beneficios superan las limitaciones.
Implementá estas APIs con progressive enhancement: detectá soporte, verificá disponibilidad, proporcioná fallbacks a cloud APIs, y diseñá UX claras para descargas de modelos. Con este enfoque, podés crear experiencias verdaderamente globales que respetan la privacidad del usuario y funcionan en cualquier condición de red.

