Risoluzione dei problemi
Ogni voce qui riportata è un errore in cui qualcuno si è imbattuto davvero. Per ciascuna sono indicati il sintomo, la causa e la soluzione: nella maggior parte dei casi il problema si riconduce a una di tre cause: la frase non è presente nel progetto, l'SDK non è mai stato inizializzato oppure un segnaposto è stato scritto per il contesto sbagliato.
Nulla viene tradotto: ogni frase resta nella lingua di partenza
Quando tutto mostra il testo di partenza, quasi certamente l'SDK non è riuscito a inizializzarsi. È progettato per fallire in modo silenzioso (la tua UI non deve mai rompersi), quindi l'unico segnale evidente è la console del browser: controllala per prima. Le cause più comuni, in ordine di probabilità:
- CORS. La prima richiesta dell'SDK è
authorize-project; se la tua API non include l'origine dell'app nella allowlist, il browser la blocca e l'inizializzazione si interrompe proprio lì. Ricorda che un'origine è esattamente schema + host + porta:localhost:5173elocalhost:5174sono origini diverse, e i server di sviluppo cambiano porta quando quella abituale è occupata. Inserisci nella allowlist ogni porta su cui sviluppi davvero. - Credenziali errate. Un ID progetto o una chiave API mancanti o digitati in modo errato fanno fallire la stessa chiamata di autorizzazione. La console mostra la richiesta non riuscita e l'URL.
- Stai visualizzando la lingua di base. Nella lingua di base la "traduzione" è il testo di partenza: non cambia nulla di visibile. Passa a una lingua di destinazione per fare una prova.
# 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 non viene tradotta (ma le altre sì)
La frase nel tuo codice è la chiave di ricerca: la frase è la chiave. Se una singola frase viene mostrata come testo sorgente mentre quelle vicine sono tradotte, quella chiave non è nel catalogo del progetto:
- Non è mai stata registrata. La registrazione avviene tramite token discovery e solo una chiave di scrittura può eseguirla. Se la frase è nata mentre l'app girava con una chiave di sola lettura, non è mai stata inviata da nessuna parte: esegui la schermata una volta in sviluppo con una chiave di scrittura, oppure aggiungi la frase nella dashboard.
- Il testo è cambiato. Qualsiasi modifica — una parola, la punteggiatura, persino uno spazio — lo trasforma in una frase nuova senza ancora traduzioni. Le vecchie traduzioni esistono ancora sotto la vecchia chiave. Questo vale soprattutto per i blocchi di contenuto: un blocco
<Translate>viene scomposto in token a partire dal suo markup, quindi modificare il testo o la struttura del blocco cambia ciò che viene cercato, e il blocco ripiega silenziosamente sul testo di origine finché la nuova forma non viene registrata e tradotta. - La traduzione automatica non è ancora arrivata. Una frase appena registrata può avere le sue traduzioni con un po' di ritardo, e un locale che non rientra tra quelli di destinazione del progetto non ne riceve mai alcuna. Controlla la frase nella dashboard: è registrata? è tradotta in questo locale?
Perché le frasi mancanti non generano un errore?
È voluto. In produzione un sistema di traduzione deve ripiegare su un testo sorgente leggibile, mai su una pagina rotta: perciò una frase non registrata mostra il testo sorgente e l'SDK non segnala nulla. Il rovescio della medaglia: con una chiave di sola lettura una frase mancante passa in silenzio. Non viene registrato nulla, non viene censito nulla, e la prima a notarlo è un utente che vede l'inglese. La pratica che lo previene è la separazione delle chiavi: sviluppa con una chiave di scrittura in modo che ogni frase visualizzata dalla tua UI venga individuata, poi rilascia in sola lettura.
# 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 Il mio segnaposto viene visualizzato letteralmente — "Hi %name%" o "Hi {name}"
- Nelle chiamate a
t(), i segnaposto usano singole parentesi graffe{name}e l'interpolazione viene eseguita solo se passi i parametri:t('Hello, {name}!', 'Greetings', { name }). - Nel markup
<Translate>/<Phrase>con React, Vue o Svelte, scrivi i segnaposto come%name%. Il compilatore del framework interpreta un semplice{name}come un'espressione prima ancora che l'SDK lo veda;%name%supera la compilazione e l'SDK lo normalizza di nuovo in{name}durante l'acquisizione. Il semplice{name}va bene in HTML puro, dove non c'è alcuna sintassi di template con cui andare in conflitto. - Parametri mancanti? Se non vengono forniti
params, il template viene renderizzato così com'è: è proprio il%name%letterale che stai vedendo.
Funziona, poi smette di funzionare dopo che cambio lingua avanti e indietro
Aggiorna l'SDK. Bug reali già risolti in quest'area: tornando alla lingua iniziale/SSR restava attivo il catalogo precedente (risolto in langsys-js-typescript 0.2.2) e i consumer di Translate/Phrase dei blocchi di contenuto potevano bloccarsi all'infinito con un catalogo precaricato dal server (risolto nella 0.2.3). Se vedi stringhe in una lingua obsoleta o blocchi che non si risolvono mai, confronta la versione installata con il changelog dell'SDK di base prima di fare il debug del tuo codice.
Lato server: la pagina restituisce un errore 500 invece di degradare in modo controllato
Il client dell'SDK PHP genera un'eccezione se viene costruito senza credenziali: quindi un'app Laravel (o PHP puro) con LANGSYS_API_KEY vuota va in errore durante la risoluzione del container, prima che venga eseguita qualsiasi traduzione. Imposta le credenziali (oppure, per un'app che deve avviarsi anche senza, associa un client sostitutivo come fanno le app demo). Una volta presenti le credenziali, gli errori dell'API a runtime degradano in modo controllato: se l'API non è raggiungibile o rifiuta la richiesta, viene mostrato il testo di origine e l'eccezione viene segnalata, senza mai mandare in errore la pagina.
Lato server: la prima richiesta si blocca, poi tutto è veloce
Il timeout HTTP dell'SDK PHP è di 30 secondi, e un'istanza dell'API che si riattiva dopo un periodo di inattività può avvicinarsi a questo limite già alla primissima chiamata. Quella richiesta o si completa lentamente (e riscalda la cache del catalogo: tutto ciò che segue viene servito dalla cache) oppure va in timeout e mostra il testo di origine. Se il primo caricamento di pagina dopo un periodo di inattività è lento, il motivo è questo: è l'API che si sta riscaldando, non la tua integrazione.
Lato server: ho eseguito il rendering con una chiave di scrittura, ma la frase non compare nella dashboard
Le frasi individuate vengono messe in coda durante la richiesta e inviate dopo l'invio della risposta, come nel middleware terminabile di Laravel. Aggiorna la dashboard poco dopo il caricamento della pagina, non durante. Nei runtime con worker persistenti (Octane, FrankenPHP, RoadRunner) assicurati di usare l'integrazione fornita dall'SDK: il normale hook di shutdown di PHP non viene mai eseguito tra una richiesta e l'altra del worker.
Rendering lato server: le traduzioni di una richiesta finiscono in un'altra
L'SDK JS di base contiene il catalogo di una sola lingua alla volta: è un singleton a livello di modulo. Un server Node che renderizza lingue diverse per richieste concorrenti va in race condition. Recupera il catalogo a ogni richiesta e usalo per inizializzare il client, come nel pattern delle guide Next.js, Nuxt e SvelteKit, oppure usa una lingua per processo.
Ancora bloccato? Apri una issue nel repository dell'SDK — typescript, react, vue, svelte, php o laravel — allegando l'output della console (o il log del server) della richiesta non riuscita. Oppure scrivi a [email protected].