BookTranslator
BookTranslator

Como traduzir um arquivo HTML sem quebrar tags, atributos ou links

O que traduzir em um arquivo HTML, o que deixar intacto e como verificar. Com uma página de exemplo, um verificador gratuito e um teste com LLM local em 9 execuções.

BookTranslator

BookTranslator Team

15 min de leitura

Para traduzir um arquivo HTML, traduza o texto que as pessoas leem e os atributos que carregam palavras voltadas ao leitor, como alt, title, placeholder, aria-label e a meta description da página. Deixe a marcação intacta: nomes de tags, href, src, id, class, scripts, estilos e qualquer coisa marcada com translate="no". Depois, altere um valor fácil de esquecer, o atributo lang no elemento <html>, para que navegadores, leitores de tela e mecanismos de busca saibam em qual idioma a página está agora.

Manter as tags intactas acabou sendo a parte fácil. Traduzimos uma página de ajuda em HTML de 59 linhas para chinês simplificado nove vezes com um modelo local, usando três métodos, e verificamos cada saída com um script. Todas as execuções mantiveram todas as tags, links e IDs. O que deu errado foi mais silencioso: o modelo traduziu uma linha dentro de um bloco de código <pre> em todas as seis execuções que enviaram o arquivo inteiro, deixou o aria-label da navegação em inglês em todas as seis, e o método que, por design, mantém a marcação mais segura, traduzindo trechos de texto um a um, produziu uma frase que dizia ao leitor para fazer a coisa errada em todas as suas três execuções.

Resposta rápida: o que traduzir e o que deixar intacto

Parte do arquivoExemplo da nossa amostraTraduzir?
Texto visíveltítulos, parágrafos, células de tabela, texto de link, <label>Sim
<title> e meta description<title>Export Your Library | Shelfmark Help</title>Sim. Ambos aparecem nos resultados de busca e nas abas do navegador.
og:title e outras meta tags sociais<meta property="og:title" content="Export Your Library">Sim, apenas o valor de content
alt, title, placeholder, aria-labelalt="The Export dialog with EPUB selected", aria-label="Breadcrumb"Sim
lang em <html><html lang="en">Altere para o idioma de destino, por exemplo zh-Hans
Nomes de tags e atributos<a>, <img>, width, o próprio aria-labelNão
href, src, id, class, for, name, type, data-*href="#choose-format", id="q"Não
<code>, <pre>, <script>, <style>shelfmark export --format epubNão. Decida separadamente sobre comentários de código e saída de exemplo.
Texto definido por CSS.note::before { content: "Note: "; }Sim, mas fica na folha de estilos, então planeje-se para isso
Dados estruturados JSON-LD"name": "Export your Shelfmark library"Traduza os valores de name e description; mantenha as chaves e o JSON válido
Elementos com translate="no"<span translate="no">Shelfmark</span>Não
Comentários HTML<!-- Generated by the help-center build... -->Opcional. Os leitores nunca os veem.
Referências de caracteres&lt;library&gt;, &nbsp;, &copy;Mantenha os escapados escapados. &lt; não deve se tornar um < real.

Esta lista não é invenção nossa. A seção do Padrão HTML sobre o atributo translate define "atributos traduzíveis": title em todo elemento, alt em imagens, placeholder em inputs, content em elementos meta cujo nome se sabe ser traduzível, e lang, que, segundo ela, deve ser alterado para corresponder ao novo idioma. Ela também cita o aria-label do ARIA como exemplo de atributo que outras especificações podem adicionar, e afirma que, em um elemento translate="no", o texto e os valores de atributo "devem ser deixados como estão quando a página é localizada".

O que testamos

Escrevemos o sample-source.html, uma página de central de ajuda para o mesmo aplicativo fictício de leitura, Shelfmark, que usamos no nosso teste de tradução de Markdown. Ela tem um exemplo de cada linha da tabela acima, além de algumas armadilhas:

  • uma frase dividida por tags inline: "Antes de exportar, faça backup das suas notas. Uma exportação copia seus livros, mas não exclui nada do Shelfmark", com o nome do produto dentro de translate="no";
  • uma frase com dois elementos inline <code> cuja ordem importa: "Digite o caminho para a pasta <library> depois de --out";
  • um bloco <pre><code> com um comando e uma linha de saída de exemplo, # Export finished: 128 books;
  • uma regra CSS que insere a palavra "Nota:" antes de um parágrafo;
  • um link na página para #choose-format, um link mailto:, um formulário de busca e um bloco JSON-LD.

Em seguida, pedimos a um modelo local que o traduzisse para chinês simplificado de três maneiras:

  1. Arquivo inteiro. Cole o arquivo inteiro e peça o arquivo traduzido de volta.
  2. Instruído. O mesmo, mais oito regras: mantenha todos os nomes de tags e atributos, não altere href, src, id, class e valores semelhantes, traduza os atributos de texto e meta tags listados, deixe <code>, <pre>, <script> e <style> em paz, exceto o name e o description do JSON-LD, respeite translate="no", mantenha referências de caracteres e comentários, e defina lang como zh-Hans.
  3. Segmentos. A abordagem de ferramentas que extraem texto do HTML: um script divide o arquivo em tags e texto, ignora <code>, <pre>, <script>, <style> e elementos translate="no", envia os trechos de texto e atributos de texto restantes ao modelo como uma lista JSON numerada e grava as traduções de volta na marcação intocada. Ele também define lang="zh-Hans" por conta própria.

O modelo era o Qwen 3.6 27B (Q4_K_M) no LM Studio, com o modo de raciocínio desligado e temperatura 0,3, em um Apple M4 Max com 64 GB de memória. Executamos cada método três vezes, nove execuções no total, em 27 de outubro de 2026. O script é o run_llm_html_test.py, e todas as nove saídas são publicadas sem edição; o README lista todos os arquivos. Se você nunca configurou um modelo local, nosso guia de tradução com LLM local cobre as configurações.

Este foi um teste pequeno, com um modelo, um par de idiomas e uma página. Ele mostra quais problemas acontecem e como detectá-los. Não classifica modelos nem ferramentas.

Resultado: a marcação sobreviveu; três decisões, não

Verificamos cada saída com o check_html_translation.py, um verificador que usa apenas a biblioteca padrão do Python. A saída completa está em check-results.txt, e o results.csv tem uma linha por execução.

VerificaçãoArquivo inteiro (3 execuções)Com instruções (3 execuções)Segmentos (3 execuções)
As mesmas 58 tags em ordem; todos os href, src, id, class inalterados3 de 33 de 33 de 3
Texto com translate="no" mantido, link interno ainda funciona, &lt;library&gt; ainda escapado3 de 33 de 33 de 3
Linha de saída de exemplo dentro de <pre> traduzida3 de 33 de 30 de 3 (ignorado por design)
CSS content: "Note: " traduzido3 de 30 de 30 de 3 (ignorado por design)
JSON-LD name e description traduzidos3 de 33 de 30 de 3 (ignorado por design)
aria-label="Breadcrumb" traduzido0 de 30 de 33 de 3
Frase com dois elementos <code> inline diz a coisa certa3 de 33 de 30 de 3
Espaços entre texto chinês através de uma tag inlinenenhum0, 5 e 46 em cada execução
lang em <html>zh-CN (não solicitado)zh-Hanszh-Hans (definido pelo script)

Cada uma das nove execuções manteve as mesmas 58 tags na mesma ordem, cada href, src, id e class, o alvo do link na página, o comentário, o &lt;library&gt; escapado e o nome do produto dentro de translate="no". Se você estava preocupado que um modelo fosse deturpar a marcação de uma página simples, ele não fez isso. Os problemas estavam todos no que traduzir.

1. A saída de exemplo dentro de <pre> foi traduzida

O bloco de código do nosso exemplo termina com uma linha de saída do programa:

<pre><code>shelfmark export --format epub --covers --out ~/Books/export
# Export finished: 128 books</code></pre>

Em todas as seis execuções de arquivo inteiro e com instruções, o modelo retornou # 导出完成:128 本书 naquela linha, incluindo as três execuções em que o prompt dizia para não alterar nada dentro de <pre>. O comando em si nunca foi tocado. O modelo tratou a linha como um comentário, e traduzir comentários é uma escolha razoável em um tutorial. Mas essa linha é o que o programa imprime, e um leitor que a comparar com o seu terminal verá inglês. Decida antes de traduzir se a saída de exemplo e os comentários de código serão traduzidos, e avise a ferramenta, ou proteja completamente os blocos <pre>.

As execuções de arquivo inteiro também traduziram o content: "Note: " do CSS no bloco <style>, enquanto as execuções com instruções, que diziam para deixar <style> em paz, o mantiveram em inglês. Nenhuma das duas está errada por si só. Traduzir a folha de estilos é correto para uma página em que o CSS é inline, e errado para um site em que uma folha de estilos compartilhada atende todos os idiomas. De qualquer forma, é uma decisão que alguém precisa tomar, não um detalhe que um modelo deve adivinhar.

2. Os rótulos de acessibilidade foram ignorados

A navegação de breadcrumb é <nav aria-label="Breadcrumb">. Um leitor de tela anuncia esse rótulo; leitores visuais nunca o veem. Em todas as seis execuções de arquivo inteiro e com instruções, ele permaneceu em inglês, embora o prompt com instruções listasse aria-label entre os atributos a traduzir. Em uma execução com instruções, o aria-label="Search" do botão de busca também permaneceu em inglês.

O método de segmentos o traduziu todas as vezes, porque seu script coletava cada valor de aria-label, alt, title e placeholder e pedia cada um explicitamente. Esse é o argumento mais forte para extrair atributos de texto de propósito, em vez de esperar que o modelo os note.

3. Traduzir em pedaços preservou as tags e quebrou a frase

O método de segmentação é seguro para a marcação por construção: o modelo nunca vê uma tag, então não pode danificar nenhuma. Ele passou em todas as verificações estruturais nas três execuções. Também produziu a única tradução do teste que deu instruções erradas ao leitor.

A frase em inglês é "Type the path to the <library> folder after --out." O <code> inline a divide em três pedaços: "Type the path to the", "folder after" e um ponto final. O chinês coloca essas palavras em uma ordem diferente, então um tradutor precisa mover os dois elementos de código. O método de segmentação não consegue movê-los. As três execuções inverteram a instrução. A execução 2 produziu isto (as execuções 1 e 3 dizem 后 em vez de 之后, com o mesmo significado):

在 <code>&lt;library&gt;</code> 之后输入 <code>--out</code>文件夹的路径。

Isso lê-se "depois de <library>, digite o caminho da pasta --out", o inverso da instrução. Todas as seis execuções de arquivo inteiro e com instruções moveram os elementos de código e acertaram:

在 <code>--out</code> 后面输入 <code>&lt;library&gt;</code> 文件夹的路径。

A mesma divisão deixou espaços estranhos onde uma tag encontra texto chinês, como 前往 <b>设置</b> e <b>书库</b> ,, em todas as três execuções de segmentação, seis lugares por execução. Um navegador os mostra como lacunas visíveis, inclusive antes de pontuação chinesa. As execuções de arquivo inteiro não tiveram nenhum; duas das três execuções com instruções tiveram quatro ou cinco.

Um verificador estrutural não consegue detectar a frase invertida, porque cada tag está exatamente onde estava. Nosso verificador relata quando o código inline muda de ordem, o que é normal para muitos idiomas, mas esse aviso não consegue distinguir certo de errado. Neste teste, ele disparou em todas as seis traduções corretas e ficou silencioso nas três erradas, porque as erradas mantiveram a ordem do inglês. Só uma pessoa lendo a frase consegue perceber. A correção é enviar frases inteiras, com suas tags inline, ao tradutor, que é o que as execuções de arquivo inteiro fizeram, e verificar a estrutura depois.

Diferenças menores

  • lang: as execuções de arquivo inteiro o alteraram para zh-CN por conta própria. As execuções com instruções usaram zh-Hans, conforme solicitado. Ambos são tags de idioma válidas; zh-Hans nomeia o sistema de escrita (chinês simplificado), zh-CN nomeia uma região. A orientação sobre declarações de idioma do W3C recomenda declarar o idioma no elemento <html> e não com uma meta tag Content-Language.
  • JSON-LD: as execuções de arquivo inteiro e com instruções traduziram os valores de name e description e mantiveram o JSON válido. Nosso script de segmentação ignorou o conteúdo de <script>, então seus dados estruturados permaneceram em inglês, que é como uma ferramenta que ignora scripts também se comportará.
  • Referências de caracteres: as execuções de arquivo inteiro e com instruções mantiveram &rsaquo;, &nbsp;, &copy; e a referência de emoji como escritas. Cinco dessas seis execuções reescreveram o intervalo 2&ndash;5 em palavras chinesas (2 到 5 ou 2 至 5); uma execução com instruções escreveu um travessão simples em vez da referência, embora seu prompt dissesse para manter as referências. Nosso script de segmentação decodificou todas e escreveu os caracteres de volta, o que exibe o mesmo. A que importa, &lt;library&gt; dentro de <code>, permaneceu escapada em todas as nove execuções.

Antes de traduzir: prepare o arquivo

  1. Marque o que não deve mudar. Coloque translate="no" em nomes de produtos, números de modelo, strings parecidas com código em prosa e qualquer outra coisa que deva permanecer como está. Faz parte do HTML, não custa nada, e o modelo respeitou isso em todas as seis execuções que enviaram o arquivo inteiro. Ferramentas de segmentação que leem isso, como nosso script, pulam esses elementos inteiramente. Nosso guia do que não traduzir cobre como decidir o que entra nessa lista.
  2. Decida a política de código. Comentários de código são traduzidos? A saída de exemplo é? A folha de estilo é compartilhada entre idiomas? Anote a resposta, junto com os nomes que não devem mudar, em um glossário de tradução, e entregue a quem ou ao que traduz.
  3. Mantenha os IDs no idioma de origem. Links na página apontam para valores de id. Se alguém traduzir um id, todos os links para ele quebram. Nenhuma das nossas execuções fez isso, mas um tradutor que "ajuda" localizando âncoras fará.
  4. Colete o texto oculto. Liste os atributos que contêm palavras, alt, title, placeholder, aria-label, value em botões, meta tags e JSON-LD, para que sejam verificados e não esquecidos.
  5. Não traduza strings JavaScript no lugar. Mensagens definidas por um script, como um alerta ou um rótulo de botão criado no código, precisam de uma etapa de localização separada no código. Nenhuma das seis execuções de arquivo inteiro ou com instruções alterou nosso bloco de script, o que está correto, mas isso significa que essas strings permanecem em inglês.

Depois de traduzir: verifique

  1. Execute a verificação estrutural.

    python3 check_html_translation.py source.html translated.html --lang zh-Hans --keep Shelfmark
    

    Ela compara tags e sua ordem, todo atributo que não é texto voltado ao leitor, o conteúdo de <pre>, <script> e <style>, código inline, chaves JSON-LD, texto com translate="no", comentários e links na página. Ela avisa sobre atributos de texto ainda em inglês, um valor de lang diferente do esperado, texto visível que parece não traduzido, código inline que mudou de ordem e espaços entre texto chinês, japonês ou coreano através de uma tag inline. Ela não julga a qualidade da tradução.

  2. Leia cada frase que contém uma tag inline. É aqui que o significado se quebrou no nosso teste. Não confie no aviso de "código inline reordenado" do verificador para encontrar essas frases: no nosso teste, as traduções erradas eram as que mantinham a ordem original.

  3. Abra a página em um navegador. Clique nos links da página, navegue pelo formulário com um leitor de tela se puder, e procure lacunas ao redor de texto em negrito e com links.

  4. Para idiomas da direita para a esquerda, também defina dir="rtl" no elemento <html>. Nosso guia de tradução de livros RTL cobre o que mais muda.

  5. Para XHTML, como os arquivos de capítulo dentro de um EPUB, também confirme que o arquivo ainda é XML bem formado, por exemplo com xmllint --noout chapter.xhtml. Um navegador perdoa uma tag não fechada; um leitor de e-books pode não perdoar. Nossa lista de verificação de QA de tradução de EPUB cobre o restante de um ebook.

Onde o BookTranslator se encaixa

A página de upload do BookTranslator aceita arquivos .html, .htm e .xhtml junto com livros e documentos, então você pode enviar uma página salva ou um artigo de ajuda estático como um arquivo inteiro. Não passamos esta amostra pelo BookTranslator para este artigo, e não testamos como ele lida com a ordem do código inline, conteúdo CSS ou JSON-LD, então verifique a saída da mesma forma que verificaria a de qualquer outra ferramenta. Você vê o preço antes de pagar.

Independentemente do que usar, faça as etapas de preparação antes de traduzir e as verificações depois. Uma página com todas as tags intactas ainda pode instruir o leitor a digitar algo errado. Se seu HTML for, na verdade, documentação escrita em Markdown, nosso guia de tradução de Markdown aborda o formato de origem.

Obtenha os arquivos de teste

Tudo deste teste é livre para reutilização:

Posts Relacionados