Solución de problemas
Cada entrada aquí es un modo de falla que alguien realmente encontró. Cada una indica el síntoma, por qué ocurre y la solución; la mayoría se reduce a una de tres cosas: la frase no está en el proyecto, el SDK nunca se inicializó o un marcador de posición se escribió para el contexto equivocado.
Nada se traduce: todas las frases permanecen en el idioma de origen
Cuando todo muestra el texto de origen, lo más probable es que el SDK no se haya inicializado. Está diseñado para fallar de forma silenciosa (tu interfaz nunca debe romperse), así que la única señal clara es la consola del navegador: revísala primero. Las causas habituales, por orden de probabilidad:
- CORS. La primera solicitud del SDK es
authorize-project; si tu API no incluye el origen de la app en su lista de permitidos, el navegador la bloquea y la inicialización falla ahí mismo. Recuerda que un origen es exactamente esquema + host + puerto:localhost:5173ylocalhost:5174son orígenes distintos, y los servidores de desarrollo cambian de puerto cuando el habitual está ocupado. Agrega a la lista de permitidos todos los puertos que uses realmente para desarrollar. - Credenciales incorrectas. Un ID de proyecto o una clave de API faltante o con errores de escritura hace fallar la misma llamada de autorización. La consola muestra la solicitud fallida y la URL.
- Estás viendo la configuración regional base. En la configuración regional base, la "traducción" es el texto original, por lo que no hay cambios visibles. Cambia a una configuración regional de destino para probar.
# The SDK's first call is an authorize-project request.
# If the browser blocks it, NOTHING translates. Check the console for:
Access to fetch at 'https://your-api/api/authorize-project/...'
from origin 'http://localhost:5173' has been blocked by CORS policy
# Fix: allowlist the app's EXACT origin (scheme + host + port) on the API.
CORS_ALLOWED_ORIGINS=http://localhost:5173,https://app.example.com Una frase no se traduce (pero otras sí)
La frase en tu código es la clave de búsqueda: la frase es la clave. Si una sola frase se muestra como texto fuente mientras las demás se traducen, esa clave no está en el catálogo del proyecto:
- Nunca se registró. El registro se realiza mediante el descubrimiento de tokens, y solo una clave de escritura puede hacerlo. Si la frase se creó mientras la app se ejecutaba con una clave de solo lectura, nunca se envió a ningún lado: ejecuta la pantalla una vez en desarrollo con una clave de escritura o agrega la frase en el panel.
- El texto cambió. Cualquier edición —una palabra, un signo de puntuación o incluso un espacio en blanco— la convierte en una frase nueva sin traducciones todavía. Las traducciones anteriores siguen existiendo bajo la clave anterior. Esto afecta especialmente a los bloques de contenido: un bloque
<Translate>se tokeniza a partir de su marcado, así que editar el texto o la estructura del bloque cambia lo que se busca, y el bloque recurre silenciosamente al texto de origen hasta que la nueva versión se registre y se traduzca. - La traducción automática aún no se ha puesto al día. Una frase recién registrada puede tardar un momento en recibir sus traducciones, y una configuración regional que no esté en la lista de destinos del proyecto nunca recibe ninguna. Revisa la frase en el panel: ¿está registrada? ¿está traducida a esta configuración regional?
¿Por qué las frases faltantes no generan un error?
Es intencional. En producción, un sistema de traducción debe degradarse a texto fuente legible, nunca a una página rota; por eso una frase no registrada muestra su texto original y el SDK no emite avisos. La contrapartida: con una clave de solo lectura, una frase faltante es silenciosa. No se registra nada, no se guarda nada, y lo primero que te enteras es cuando un usuario ve inglés. La disciplina que lo evita es la separación de claves: desarrolla con una clave de escritura para que se descubra cada frase que renderiza tu interfaz, y luego publica con una clave de solo lectura.
# Development — write key: new phrases are discovered,
# registered, and machine-translated as you build.
VITE_LANGSYS_API_KEY=write-key
# Production — read-only key: fetches the finished catalog only.
# Unregistered phrases silently render their source text.
VITE_LANGSYS_API_KEY=read-only-key Mi marcador de posición se muestra literalmente: "Hi %name%" o "Hi {name}"
- En las llamadas a
t(), los marcadores de posición usan una sola llave{name}, y la interpolación solo se ejecuta cuando pasas los parámetros:t('Hello, {name}!', 'Greetings', { name }). - En el marcado
<Translate>/<Phrase>bajo React, Vue o Svelte, escribe los marcadores de posición como%name%. El compilador del framework interpreta un{name}sin formato como una expresión antes de que el SDK llegue a verlo;%name%sobrevive a la compilación y el SDK lo normaliza de nuevo a{name}al momento de la captura. El formato simple{name}funciona bien en HTML puro, donde no hay sintaxis de plantillas con la que pueda chocar. - ¿Faltan parámetros? Si no se proporcionan
params, la plantilla se renderiza tal cual: ese es el%name%literal que estás viendo.
Funciona, pero se rompe después de cambiar de idioma varias veces
Actualiza el SDK. Errores reales ya corregidos en esta área: volver a la configuración regional inicial o de SSR dejaba activo el catálogo anterior (corregido en langsys-js-typescript 0.2.2), y los consumidores de Translate/Phrase de bloques de contenido podían quedarse colgados para siempre con un catálogo precargado por el servidor (corregido en 0.2.3). Si ves cadenas de una configuración regional anterior o bloques que nunca se resuelven, compara tu versión instalada con el registro de cambios del SDK base antes de depurar tu propio código.
Del lado del servidor: la página devuelve un error 500 en lugar de degradarse con elegancia
El cliente del SDK de PHP lanza una excepción si se construye sin credenciales, así que una aplicación Laravel (o PHP simple) con LANGSYS_API_KEY vacía falla al resolver el contenedor, antes de que se ejecute cualquier traducción. Configura las credenciales (o, si la aplicación debe iniciar sin ellas, vincula un cliente sustituto como lo hacen las aplicaciones de demostración). Una vez que existen las credenciales, las fallas de la API en tiempo de ejecución sí se manejan sin romper nada: si la API no está disponible o rechaza la solicitud, se muestra el texto original y se reporta la excepción; nunca se cae la página.
En el servidor: la primera solicitud se queda colgada, luego todo es rápido
El tiempo de espera HTTP del SDK de PHP es de 30 segundos, y una instancia de la API que se reactiva tras estar inactiva puede acercarse a ese límite en la primera llamada. Esa solicitud o bien se completa con lentitud (y calienta la caché del catálogo: todo lo que sigue se sirve desde la caché) o bien agota el tiempo de espera y muestra el texto original. Si la primera carga de página después de un periodo de inactividad es lenta, esta es la razón: es la API que se está calentando, no tu integración.
Del lado del servidor: rendericé con una clave de escritura, pero la frase no aparece en el panel
Las frases descubiertas se ponen en cola durante la solicitud y se envían después de que se envía la respuesta, como el middleware terminable de Laravel. Actualiza el panel un momento después de que cargue la página, no durante la carga. En entornos de ejecución de workers de larga duración (Octane, FrankenPHP, RoadRunner), asegúrate de usar la integración que proporciona el SDK: el hook de cierre de PHP estándar nunca se activa entre las solicitudes de un worker.
Renderizado en el servidor: las traducciones de una solicitud se filtran a otra
El SDK base de JS mantiene el catálogo de una sola configuración regional a la vez: es un singleton a nivel de módulo. Un servidor Node que renderiza distintas configuraciones regionales para solicitudes concurrentes tendrá condiciones de carrera. Obtén el catálogo en cada solicitud e inicializa el cliente con él, el patrón de las guías de Next.js, Nuxt y SvelteKit, o ejecuta una configuración regional por proceso.
¿Sigues atascado? Abre un issue en el repositorio del SDK (typescript, react, vue, svelte, php o laravel) con la salida de la consola (o el registro del servidor) de la solicitud que falla. O escribe a [email protected].