Solução de problemas
Cada item aqui é um modo de falha que alguém realmente enfrentou. Cada um lista o sintoma, o motivo pelo qual acontece e a solução — a maioria se resume a uma de três causas: a frase não está no projeto, o SDK nunca foi inicializado ou um placeholder foi escrito para o contexto errado.
Nada é traduzido — todas as frases permanecem no idioma de origem
Quando tudo aparece no texto de origem, quase certamente o SDK falhou ao inicializar. Ele falha de forma silenciosa por projeto (sua interface nunca deve quebrar), então o único sinal evidente é o console do navegador — verifique-o primeiro. As causas mais comuns, em ordem de probabilidade:
- CORS. A primeira requisição do SDK é
authorize-project; se a sua API não incluir a origem do app na lista de permissões, o navegador a bloqueia e a inicialização falha ali mesmo. Lembre-se de que uma origem é exatamente esquema + host + porta —localhost:5173elocalhost:5174são origens diferentes, e os servidores de desenvolvimento mudam de porta quando a habitual está ocupada. Inclua na lista de permissões todas as portas em que você realmente desenvolve. - Credenciais incorretas. Um ID de projeto ou chave de API ausente ou digitado errado faz a mesma chamada de autorização falhar. O console mostra a requisição com falha e a URL.
- Você está vendo o locale base. No locale base, a "tradução" é o texto de origem — nada muda visivelmente. Mude para um locale de destino para testar.
# 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 Uma frase não é traduzida (mas as outras são)
A frase no seu código é a chave de busca — a frase é a chave. Se uma única frase aparece como texto de origem enquanto as vizinhas são traduzidas, essa chave não está no catálogo do projeto:
- Ela nunca foi registrada. O registro acontece por meio da descoberta de tokens, e somente uma chave de escrita consegue fazer isso. Se a frase surgiu enquanto o app rodava com uma chave somente leitura, ela nunca foi enviada a lugar nenhum — execute a tela uma vez em desenvolvimento com uma chave de escrita ou adicione a frase no painel.
- O texto mudou. Qualquer edição — uma palavra, a pontuação, até um espaço em branco — o transforma em uma frase nova, ainda sem traduções. As traduções antigas continuam existindo sob a chave antiga. Isso pega especialmente os blocos de conteúdo: um bloco
<Translate>é convertido em tokens a partir da sua marcação, então editar o texto ou a estrutura do bloco muda o que é buscado, e o bloco volta silenciosamente ao texto de origem até que a nova forma seja registrada e traduzida. - A tradução automática ainda não chegou lá. Uma frase recém-registrada pode demorar um instante para ter suas traduções, e uma localidade fora da lista de destino do projeto nunca recebe nenhuma. Verifique a frase no painel: está registrada? Foi traduzida para esta localidade?
Por que frases ausentes não geram um erro?
Por design. Em produção, um sistema de tradução deve recorrer ao texto de origem legível, nunca a uma página quebrada — por isso, uma frase não registrada exibe o texto de origem e o SDK permanece em silêncio. O outro lado da moeda: com uma chave somente leitura, uma frase ausente fica em silêncio. Nada é registrado em log, nada é cadastrado, e você só fica sabendo quando um usuário vê o texto em inglês. A disciplina que evita isso é a divisão de chaves — desenvolva com uma chave de escrita para que toda frase renderizada pela sua interface seja descoberta e, depois, publique com chave somente leitura.
# 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 Meu placeholder aparece literalmente — "Hi %name%" ou "Hi {name}"
- Em chamadas de
t(), os placeholders usam chaves simples{name}, e a interpolação só é executada quando você passa os parâmetros:t('Hello, {name}!', 'Greetings', { name }). - Em markup
<Translate>/<Phrase>no React, Vue ou Svelte, escreva os placeholders como%name%. O compilador do framework consome um{name}simples como uma expressão antes mesmo de o SDK vê-lo; o%name%sobrevive à compilação e o SDK o normaliza de volta para{name}na captura. O{name}simples funciona bem em HTML puro, onde não há sintaxe de template para causar conflito. - Faltando parâmetros? Se nenhum
paramsfor informado, o template é renderizado como está — esse é o%name%literal que você está vendo.
Funciona, mas quebra depois que alterno entre locales várias vezes
Atualize o SDK. Bugs reais já corrigidos nesta área: voltar ao idioma inicial/SSR mantinha o catálogo anterior ativo (corrigido no langsys-js-typescript 0.2.2), e consumidores de Translate/Phrase de blocos de conteúdo podiam ficar travados para sempre em um catálogo carregado pelo servidor (corrigido na 0.2.3). Se você vir textos no idioma antigo ou blocos que nunca são resolvidos, compare a versão instalada com o changelog do SDK base antes de depurar seu próprio código.
No lado do servidor: a página retorna erro 500 em vez de se degradar graciosamente
O cliente do SDK para PHP lança uma exceção quando é construído sem credenciais — então um app Laravel (ou PHP puro) com LANGSYS_API_KEY vazia falha na resolução do contêiner, antes de qualquer tradução ser executada. Defina as credenciais (ou, se o app precisar inicializar sem elas, vincule um cliente substituto, como fazem os apps de demonstração). Depois que as credenciais existem, as falhas da API em tempo de execução degradam de forma suave: uma API inacessível ou que recusa a requisição exibe o texto de origem e registra a exceção — nunca derruba a página.
No servidor: a primeira requisição trava e depois tudo fica rápido
O timeout HTTP do SDK de PHP é de 30 segundos, e uma instância da API saindo da inatividade pode chegar perto desse limite já na primeira chamada. Essa requisição ou é concluída lentamente (e aquece o cache do catálogo — tudo o que vier depois é servido do cache) ou expira por timeout e exibe o texto de origem. Se o primeiro carregamento de página após um período de inatividade for lento, é por isso; é a API aquecendo, não a sua integração.
Lado do servidor: renderizei com uma chave de escrita, mas a frase não aparece no painel
As frases descobertas são colocadas na fila durante a requisição e enviadas depois que a resposta é entregue — o middleware terminável do Laravel. Atualize o painel um instante depois que a página carregar, não durante. Em runtimes de workers de longa duração (Octane, FrankenPHP, RoadRunner), certifique-se de usar a integração fornecida pelo SDK — o hook de shutdown padrão do PHP nunca é disparado entre as requisições de um worker.
Renderização no servidor: traduções de uma requisição vazam para outra
O SDK base de JS mantém o catálogo de um idioma por vez, pois é um singleton em nível de módulo. Um servidor Node que renderiza idiomas diferentes em requisições simultâneas vai gerar condições de corrida. Busque o catálogo a cada requisição e inicialize o cliente com ele, como no padrão dos guias de Next.js, Nuxt e SvelteKit, ou execute um idioma por processo.
Ainda com problemas? Abra uma issue no repositório do SDK — typescript, react, vue, svelte, php ou laravel — com a saída do console (ou o log do servidor) da requisição com falha. Ou escreva para [email protected].