Docsbook
Visão geral

Traduções com IA

Uma etapa de tradução pega o Markdown já existente no seu repositório, renderiza-o exatamente como a página ativa o renderiza, divide-o, traduz as partes legíveis por humanos e armazena o resultado por página e por idioma. Não há arquivos de tradução, chaves de mensagem nem uma etapa de exportação. Esta página é o mecanismo, no nível do que o código realmente faz.

O que inicia uma execução#

Cinco coisas, e cada execução registra qual delas foi — para que o painel possa dizer Acionado pelo commit a1b2c3d em vez de atribuir um push a você.

Acionador O que o causa
language_enabled Você ativou um idioma.
commit O scanner do modo automático descobriu que o head do repositório mudou.
manual Você pressionou Traduzir agora, ou outra pessoa fez isso no painel.
agent Um agente chamado run_translation_pass. A chave e o ID da execução do agente são registrados na linha do trabalho.
O executor de retomada A cada 2 minutos, um ciclo do cron recolhe as execuções cujo heartbeat está silencioso há 15 minutos, libera seus bloqueios e conduz até três trabalhos ativos que estejam ociosos há 90 segundos.

O scanner só verifica um workspace que não tenha sido verificado há 15 minutos, e apenas quatro workspaces por ciclo, ordenados por quem está há mais tempo sem uma verificação. Ele é interrompido imediatamente quando o head do repositório não mudou — e o marcador com o qual ele compara só avança quando todos os idiomas ativados foram encontrados sincronizados naquele commit, para que uma execução interrompida por limite não possa congelar um workspace em uma tradução parcial e fazer com que ele nunca mais seja verificado.

Uma execução nunca inicia mais de três idiomas ao mesmo tempo, começando pelos mais importantes: cada execução representa minutos de trabalho de modelo cobrado, e uma etapa de agente que abrisse dez deles gastaria o orçamento de um mês em um único acionador. Os restantes são reportados como over_language_cap e processados na próxima vez, que é a versão honesta de "agora não".

Como uma página é dividida em blocos#

A unidade de tradução não é a página. É uma seção.

  1. Seu Markdown é pré-processado e renderizado pelo mesmo pipeline usado pela página em produção, incluindo sua lista de bloqueio de widgets. Portanto, a tradução vê a página que o leitor vê, e não uma segunda interpretação da fonte.
  2. O HTML renderizado é dividido nos limites <h2> e <h3>. O conteúdo anterior ao primeiro título se torna seu próprio bloco inicial.
  3. Um bloco com mais de 9.000 caracteres é dividido novamente — mas somente nos limites de blocos de nível superior (</p>, </li>, </table>, </pre>, </figure>, </h1></h6>), para que um fragmento nunca seja cortado no meio de uma tag.
  4. Cada bloco recebe um hash com base em seu próprio conteúdo. O hash junto com o idioma é a chave do cache.
  5. Os blocos são traduzidos no máximo 3 por vez, cada um com um tempo limite de 30 segundos para o upstream, e concatenados novamente na ordem.

Duas coisas resultam desse design, e elas são exatamente a razão pela qual ele foi construído dessa forma:

  • Editar um parágrafo traduz novamente uma seção. O hash de todos os outros blocos permanece inalterado, então eles são servidos do cache. Corrigir um erro de digitação custa uma seção, não uma página. A divisão — quantos blocos foram reutilizados em comparação com quantos foram enviados ao modelo — é registrada uma vez por página no registro de gastos, portanto a economia é um número medido, não uma alegação.
  • A terminologia não pode sofrer alterações no texto que você não modificou. Uma seção não editada é idêntica byte a byte à última vez em que foi traduzida, porque é literalmente a mesma string armazenada em cache.

As solicitações são enviadas com temperatura 0, e o orçamento de tokens de saída é calculado com base no comprimento da entrada, em vez de ser reservado de forma fixa — com um multiplicador de 2,6, escolhido porque o cirílico e os caracteres CJK custam muito mais tokens por caractere do que a fonte em inglês, e um orçamento de 1,5× retornava páginas truncadas.

O que é protegido do modelo#

Existem dois tipos diferentes de proteção aqui, e confundi-los é como a documentação acaba prometendo mais do que o código oferece.

Protegido estruturalmente — o modelo nunca o vê#

Elemento Mecanismo
Blocos de código delimitados Extraídos antes da solicitação e substituídos por __CODE_BLOCK_N__; restaurados byte a byte posteriormente.
Código inline (`like this`) Mesma extração, mesma restauração byte a byte.
Chaves e valores do frontmatter Nunca chegam ao modelo: a tradução é executada no HTML renderizado, e o frontmatter foi consumido no momento da renderização.
Marcadores de widgets (<!-- widget:name -->) Também nunca chegam ao modelo: os widgets são expandidos para HTML pelo pipeline de renderização antes da divisão em partes. Não resta nenhum marcador para ser corrompido. O texto visível dentro de um widget — o título de um cartão, por exemplo — é prosa e é traduzido.

Estas são garantias. Um modelo não pode alterar, reorganizar ou "traduzir" um exemplo de código que nunca recebeu.

Protegidos por instrução — verifique estes, não os presuma#

O prompt informa ao modelo, como regras absolutas, para não traduzir nem modificar tags HTML, atributos, nomes de classes, IDs, valores href ou atributos de dados, para não alterar a estrutura HTML, para não traduzir identificadores de código e nomes de variáveis, para não adicionar comentários e para reproduzir exatamente os placeholders __CODE_BLOCK_N__. Essa é uma instrução forte para um modelo executado com temperatura 0, e ela funciona na prática — mas é uma instrução, não um mecanismo, e a palavra honesta para isso é geralmente.

Três consequências que vale a pena conhecer:

  • Os links mantêm seus destinos. href é um atributo, e os atributos estão na lista de itens que não devem ser tocados. O texto do link é prosa e é traduzido.
  • As âncoras dos títulos permanecem no idioma de origem. Os atributos id do título são definidos antes da tradução e devem ser deixados inalterados, portanto um link profundo para uma âncora de título em inglês continua funcionando na página traduzida.
  • O texto alt das imagens não é traduzido. Ele é um atributo HTML, e a regra que protege href também protege alt. Se o texto alternativo acessível no idioma do leitor for importante para você, isso é uma lacuna, não um recurso.

Traduzidos como conjuntos, não um de cada vez#

Os rótulos de navegação são traduzidos como um único grupo em uma única solicitação, que deve retornar o mesmo número de rótulos e na mesma ordem; uma resposta malformada ou incompatível mantém os originais em vez de tentar adivinhar. Se todos os rótulos retornados forem idênticos aos originais — a assinatura de uma tradução que não ocorreu — o resultado será descartado em vez de ser armazenado em cache, para que a próxima tentativa possa ocorrer novamente, em vez de fixar os rótulos em inglês para sempre. O título e a descrição de uma página são traduzidos juntos como um par, para que nunca fiquem dessincronizados.

Como uma tradução desatualizada é detectada#

Por comparação com o git, não por um indicador de status.

Cada linha de tradução armazenada mantém source_hash — o SHA do blob git do arquivo de origem no momento em que foi traduzido. A cobertura é calculada lendo a árvore do repositório em HEAD e comparando, por caminho:

Estado Significado
current Existe uma tradução automática e o SHA armazenado é igual ao SHA do arquivo em HEAD.
behind Existe uma tradução automática, mas de uma versão mais antiga dessa página.
missing A página existe no repositório e nunca foi traduzida para este idioma.
manual Escrita manualmente ou enviada por upload. A atualização fica a critério do autor, portanto nunca é contabilizada como atrasada.
orphaned Uma tradução cujo arquivo de origem não existe mais em HEAD.

A cobertura é (current + manual) / total, e um idioma está sincronizado quando behind e missing são ambos zero. Quando não é possível ler o repositório, a cobertura é null — nunca um zero confiável, e cada superfície informa "desconhecido" em vez de marcar um idioma saudável em vermelho.

A coluna status = 'outdated' no banco de dados deliberadamente não é usada para isso. Nada no produto a preenche automaticamente, então ela permanece zero em todos os workspaces; uma verificação de atualização baseada nela relataria saúde perfeita para sempre.

Uma execução ordenada por essa comparação traduz os itens atrasados antes dos ausentes. Uma tradução desatualizada está dizendo ativamente ao leitor algo que sua documentação não diz mais; uma tradução ausente recorre ao original e simplesmente deixa de ajudar.

O fluxo de revisão e aprovação#

Há três origens possíveis para uma tradução armazenada, e elas são tratadas de forma diferente de propósito.

Origem Escrito por Disponibilizado aos leitores Sobrescrito por uma passagem posterior
docsbook_ai Uma passagem de tradução Sim Sim
manual_upload Você, por meio do editor do painel ou de upload_translation Leia isto primeiro Não — uma passagem automática não o substituirá
external_api Seu próprio pipeline no modo external Leia isto primeiro Não

Os uploads chegam como rascunho por padrão. list_pending_translations retorna os rascunhos, approve_translation move um deles para publicado, e editar o conteúdo de uma tradução marca a linha como um upload manual, para que uma passagem posterior a deixe intacta. No modo external, o ciclo é: o Docsbook emite translation.needed quando uma página está prestes a ser traduzida, seu pipeline realiza o trabalho e upload_translation publica o resultado de volta.

As traduções automáticas não entram nesta fila. Uma passagem grava linhas com o status auto, não draft, portanto list_pending_translations nunca as lista. O fluxo de aprovação é um portão para traduções que chegam de fora, não uma etapa de revisão humana antes da saída da IA. Se você quiser que a saída da IA seja revisada antes que os leitores a vejam, o modo external é o formato que faz isso; o modo auto padrão publica à medida que avança.

O que acontece quando uma execução falha#

Cada modo de falha abaixo é uma decisão deliberada para exibir o original em vez de armazenar algo quebrado.

Falha O que acontece
O modelo atinge seu limite de tokens de saída (finish_reason: length) Tratado como uma falha grave e recusado, sem ser armazenado. Um trecho truncado certa vez fez com que metade de uma página ficasse armazenada em cache como tradução para sempre.
O modelo retorna conteúdo vazio Também é uma falha grave. Uma string vazia propagada como sucesso foi o motivo pelo qual 808 linhas de tradução em branco se acumularam certa vez em um projeto.
Um trecho falha A página é montada com o texto original desse trecho e exibida somente para essa solicitação. Ela não é gravada no Redis, não é gravada no Postgres e não é indexada.
A página montada está em branco enquanto a fonte não está Não é armazenada; a fonte é exibida.
Um trecho falhou recentemente Um cache negativo de 10 minutos impede uma avalanche de novas tentativas. A próxima visita após a expiração traduz novamente apenas os trechos ausentes.
O provedor retorna 402/403 na chave compartilhada do Docsbook Uma interrupção global é definida por 4 horas e todas as execuções pendentes são interrompidas imediatamente, em vez de sobrecarregar uma conta esgotada. Os espaços de trabalho com sua própria chave não são afetados.
A cota da sua própria chave se esgota Apenas a execução do seu projeto falha. A cota esgotada de outra pessoa nunca interrompe você, e a sua nunca interrompe a outra pessoa.
O orçamento de gastos do projeto se esgota A execução é interrompida com esse motivo descrito em palavras, e as páginas restantes são traduzidas em uma execução posterior, assim que o saldo permitir. Nada do que já foi pago é perdido.
A invocação é encerrada no meio da execução O trabalho mantém um cursor e um heartbeat. O executor de 2 minutos remove um trabalho silencioso por 15 minutos, libera seu bloqueio e o reinicia a partir da próxima página não traduzida.

Uma execução parcialmente concluída é normal, não um estado de erro: um site grande requer mais de uma invocação, cada invocação avança tanto quanto seu tempo de execução permite, e o próximo ciclo continua. O que você nunca deve ver é uma página metade em inglês e metade em outro idioma, porque essa montagem é exatamente o que o código se recusa a persistir.

Enquanto uma página ainda não tem tradução, o leitor recebe o original — sem indicador de carregamento, sem erro e sem um banner prometendo uma tradução que esta solicitação não está produzindo. Quando existe apenas uma tradução mais antiga, o leitor recebe essa tradução mais antiga imediatamente, em vez de voltar ao original: conteúdo legível no idioma correto é melhor do que esperar.

Limites#

  • A consistência da terminologia não conta com um glossário. Não há uma base terminológica, nenhuma lista de termos que você possa fornecer para não traduzir e nenhuma verificação de consistência entre páginas. A consistência existente vem da temperatura 0, das seções não editadas que são fornecidas literalmente do cache e dos rótulos e do título/descrição traduzidos como conjuntos. Duas páginas diferentes que usam o mesmo termo foram traduzidas de forma independente e podem não estar de acordo.
  • “Não traduza identificadores” é uma instrução, não uma garantia. O código dentro de blocos delimitados e de crases é protegido mecanicamente. Um identificador isolado escrito como prosa comum — um nome de parâmetro em uma frase, sem crases — fica protegido apenas pelo prompt. Escrever identificadores entre crases é a medida de maior impacto que você pode tomar para suas próprias traduções.
  • O texto alt da imagem permanece no idioma de origem. Consulte acima; isso é consequência da proteção integral dos atributos HTML.
  • Uma tradução armazenada em cache foi renderizada sob a lista de bloqueio de widgets vigente quando foi criada. Desativar um widget não reescreve as páginas já traduzidas; elas o utilizam na próxima passagem. Recriar a chave do cache com base na lista de bloqueio faria com que todas as páginas de todos os idiomas fossem traduzidas novamente por causa de uma alternância de apresentação.
  • O modo automático reage a uma consulta, não ao seu push. Consulte Configurações de tradução.

Updated

Esta página foi útil?