BookTranslator
BookTranslator

Como traduzir um ficheiro HTML sem quebrar etiquetas, atributos ou ligações

O que traduzir num ficheiro HTML, o que deixar intacto e como verificá-lo. Com uma página de exemplo, um verificador gratuito e um teste de 9 execuções com um LLM local.

BookTranslator

BookTranslator Team

15 min de leitura

Para traduzir um ficheiro HTML, traduza o texto que as pessoas leem e os atributos que contêm palavras visíveis para o leitor, como alt, title, placeholder, aria-label e a meta descrição da página. Deixe a marcação intacta: nomes de etiquetas, href, src, id, class, scripts, estilos e tudo o que estiver marcado com translate="no". Depois, altere um valor que é fácil esquecer, o atributo lang no elemento <html>, para que os navegadores, os leitores de ecrã e os motores de busca saibam em que língua a página está agora.

Manter as etiquetas intactas revelou-se a parte fácil. Traduzimos uma página de ajuda HTML de 59 linhas para chinês simplificado nove vezes com um modelo local, usando três métodos, e verificámos cada resultado com um script. Todas as execuções mantiveram todas as etiquetas, ligações e IDs. O que correu mal foi mais silencioso: o modelo traduziu uma linha dentro de um bloco de código <pre> nas seis execuções que enviaram o ficheiro completo, deixou o aria-label da navegação em inglês nas seis, e o método que, por conceção, mantém a marcação mais segura, traduzindo os fragmentos de texto um a um, produziu uma frase que dizia ao leitor para fazer a coisa errada nas três execuções.

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

Parte do ficheiroExemplo da nossa amostraTraduzir?
Texto visívelcabeçalhos, parágrafos, células de tabela, texto de ligação, <label>Sim
<title> e meta descrição<title>Export Your Library | Shelfmark Help</title>Sim. Ambos aparecem nos resultados de pesquisa e nos separadores do navegador.
og:title e outras meta etiquetas 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-o para a língua de destino, por exemplo zh-Hans
Nomes de etiquetas 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 resultados de exemplo.
Texto definido por CSS.note::before { content: "Note: "; }Sim, mas está no stylesheet, por isso planeie com antecedência
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 como escapados. &lt; não deve tornar-se um < real.

Esta lista não é invenção nossa. A secção do HTML Standard sobre o atributo translate define "atributos traduzíveis": title em todos os elementos, alt em imagens, placeholder em inputs, content em elementos meta cujo nome se sabe ser traduzível, e lang, que diz dever ser alterado para corresponder ao novo idioma. Também nomeia o aria-label da ARIA como exemplo de um atributo que outras especificações podem acrescentar, e afirma que num elemento translate="no", o texto e os valores dos atributos "devem ser deixados como estão quando a página é localizada".

O que testámos

Escrevemos o sample-source.html, uma página de centro de ajuda para a mesma aplicação fictícia de leitura, Shelfmark, que usámos no nosso teste de tradução de Markdown. Tem um exemplo de cada linha da tabela acima, mais algumas armadilhas:

  • uma frase dividida por tags inline: "Antes de exportar, faça uma cópia de segurança das suas notas. Uma exportação copia os seus livros, mas não elimina nada do Shelfmark," com o nome do produto dentro de translate="no";
  • uma frase com dois elementos inline <code> cuja ordem importa: "Escreva 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;
  • uma ligação interna para #choose-format, uma ligação mailto:, um formulário de pesquisa e um bloco JSON-LD.

Depois pedimos a um modelo local para o traduzir para chinês simplificado de três formas:

  1. Ficheiro completo. Colar o ficheiro inteiro e pedir o ficheiro traduzido de volta.
  2. Com instruções. O mesmo, mais oito regras: manter todos os nomes de tags e atributos, não alterar href, src, id, class e valores semelhantes, traduzir os atributos de texto e meta tags listados, deixar <code>, <pre>, <script> e <style> em paz exceto o name e description do JSON-LD, respeitar translate="no", manter referências de caracteres e comentários, e definir lang para zh-Hans.
  3. Segmentos. A abordagem das ferramentas que extraem texto de HTML: um script divide o ficheiro em tags e texto, ignora elementos <code>, <pre>, <script>, <style> e translate="no", envia os restantes fragmentos de texto e atributos de texto ao modelo como uma lista JSON numerada, e escreve as traduções de volta na marcação intacta. Também define lang="zh-Hans" por si.

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

Este foi um teste pequeno de um modelo, um par de idiomas e uma página. Mostra que problemas acontecem e como os detetar. Não classifica modelos nem ferramentas.

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

Verificámos cada resultado com check_html_translation.py, um verificador que utiliza apenas a biblioteca padrão do Python. O resultado completo está em check-results.txt, e results.csv tem uma linha por execução.

VerificaçãoFicheiro completo (3 execuções)Com instruções (3 execuções)Segmentos (3 execuções)
As mesmas 58 etiquetas pela mesma ordem; todos os href, src, id, class inalterados3 de 33 de 33 de 3
Texto com translate="no" mantido, link na página continua a funcionar, &lt;library&gt; continua escapado3 de 33 de 33 de 3
Linha de exemplo de saída dentro de <pre> traduzida3 de 33 de 30 de 3 (ignorado por predefinição)
CSS content: "Note: " traduzido3 de 30 de 30 de 3 (ignorado por predefinição)
name e description do JSON-LD traduzidos3 de 33 de 30 de 3 (ignorado por predefinição)
aria-label="Breadcrumb" traduzido0 de 30 de 33 de 3
Frase com dois elementos <code> em linha diz a coisa certa3 de 33 de 30 de 3
Espaços entre texto chinês através de uma etiqueta em linhanenhum0, 5 e 46 em cada execução
lang em <html>zh-CN (não pedido)zh-Hanszh-Hans (definido pelo script)

Cada uma das nove execuções manteve as mesmas 58 etiquetas na mesma ordem, todos os href, src, id e class, o destino da ligação na página, o comentário, o &lt;library&gt; escapado e o nome do produto dentro de translate="no". Se receava que um modelo estragasse a marcação de uma página simples, não estragou. Os problemas estavam todos no que traduzir.

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

O bloco de código no 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 ficheiro completo e com instruções, o modelo devolveu # 导出完成:128 本书 nessa 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 num tutorial. Mas esta linha é o que o programa imprime, e um leitor que a compare com o seu terminal verá inglês. Decida antes de traduzir se a saída de exemplo e os comentários de código são traduzidos, e diga-o à ferramenta, ou proteja completamente os blocos <pre>.

As execuções de ficheiro completo também traduziram o content: "Note: " do CSS no bloco <style>, enquanto as execuções com instruções, às quais foi dito para deixar <style> em paz, o mantiveram em inglês. Nenhuma está errada por si só. Traduzir a folha de estilos está correto para uma página em que o CSS é inline, e errado para um site em que uma folha de estilos partilhada serve todos os idiomas. De qualquer forma, é uma decisão que alguém tem de tomar, não um detalhe que um modelo deva adivinhar.

2. As etiquetas de acessibilidade foram ignoradas

A navegação de breadcrumb é <nav aria-label="Breadcrumb">. Um leitor de ecrã anuncia essa etiqueta; os leitores videntes nunca a veem. Em todas as seis execuções de ficheiro completo e com instruções, permaneceu em inglês, apesar de o prompt com instruções listar aria-label entre os atributos a traduzir. Numa execução com instruções, o aria-label="Search" do botão de pesquisa também permaneceu em inglês.

O método de segmentação traduziu-a sempre, porque o seu script recolheu todos os valores de aria-label, alt, title e placeholder e pediu cada um explicitamente. Esse é o argumento mais forte para extrair atributos de texto de propósito, em vez de esperar que o modelo repare neles.

3. Traduzir por segmentos preservou as etiquetas e quebrou a frase

O método de segmentação é seguro para a marcação por construção: o modelo nunca vê uma etiqueta, por isso não a pode danificar. Passou todas as verificações estruturais nas três execuções. Também produziu a única tradução no 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 divide-a em três partes: "Type the path to the", "folder after" e um ponto final. O chinês coloca estas palavras por uma ordem diferente, por isso um tradutor precisa de mover os dois elementos de código. O método de segmentação não os consegue mover. 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>文件夹的路径。

Isto lê-se "depois de <library>, escreva o caminho da pasta --out", o inverso da instrução. As seis execuções de ficheiro completo 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 indesejados onde uma etiqueta encontra texto chinês, como 前往 <b>设置</b> e <b>书库</b> ,, nas três execuções por segmentos, seis locais por execução. Um navegador mostra-os como lacunas visíveis, incluindo antes de pontuação chinesa. As execuções de ficheiro completo não tiveram nenhum; duas das três execuções com instruções tiveram quatro ou cinco.

Um verificador estrutural não consegue detetar a frase invertida, porque cada etiqueta está exatamente onde estava. O nosso verificador reporta quando o código inline muda de ordem, o que é normal em muitas línguas, mas esse aviso não distingue o certo do errado. Neste teste, disparou em todas as seis traduções corretas e ficou silencioso nas três erradas, porque as erradas mantiveram a ordem inglesa. Só uma pessoa a ler a frase o consegue dizer. A solução é enviar frases completas, com as suas etiquetas inline, para o tradutor, que é o que as execuções de ficheiro completo fizeram, e verificar a estrutura depois.

Diferenças menores

  • lang: as execuções de ficheiro completo alteraram-no para zh-CN por iniciativa própria. As execuções com instruções usaram zh-Hans, como pedido. Ambos são etiquetas de língua válidas; zh-Hans nomeia o sistema de escrita (chinês simplificado), zh-CN nomeia uma região. A orientação do W3C sobre declarações de língua recomenda declarar a língua no elemento <html> e não com uma meta etiqueta Content-Language.
  • JSON-LD: as execuções de ficheiro completo e com instruções traduziram os valores name e description e mantiveram o JSON válido. O nosso script de segmentação ignorou o conteúdo <script>, por isso os seus dados estruturados ficaram em inglês, que é como uma ferramenta que ignora scripts também se comportará.
  • Referências de caracteres: as execuções de ficheiro completo 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 o seu prompt dissesse para manter as referências. O nosso script de segmentação descodificou-as todas e escreveu os caracteres de volta, o que exibe o mesmo. A que importa, &lt;library&gt; dentro de <code>, permaneceu escapada nas nove execuções.

Antes de Traduzir: Preparar o Ficheiro

  1. Marque o que não deve mudar. Coloque translate="no" em nomes de produtos, números de modelo, cadeias semelhantes a código em prosa e qualquer outra coisa que deva ficar como está. Faz parte do HTML, não custa nada e o modelo respeitou-o nas seis execuções que lhe enviaram o ficheiro completo. Ferramentas de segmentação que o leem, como o nosso script, ignoram esses elementos por completo. O nosso guia do que não traduzir explica como decidir o que entra nessa lista.
  2. Decida a política de código. Os comentários de código são traduzidos? E a saída de exemplo? A folha de estilos é partilhada entre línguas? Escreva a resposta, juntamente com os nomes que não devem mudar, num glossário de tradução e entregue-o a quem ou ao que traduz.
  3. Mantenha os IDs na língua de origem. As ligações dentro da página apontam para valores id. Se alguém traduzir um id, todas as ligações para ele quebram. Nenhuma das nossas execuções o fez, mas um tradutor que "ajude" a localizar âncoras fá-lo-á.
  4. Recolha o texto oculto. Liste os atributos que contêm palavras, alt, title, placeholder, aria-label, value em botões, meta etiquetas e JSON-LD, para que sejam verificados e não esquecidos.
  5. Não traduza cadeias JavaScript no local. As mensagens definidas por um script, como um alerta ou a etiqueta de um botão criada em código, precisam de um passo de localização separado no código. Nenhuma das seis execuções de ficheiro completo ou com instruções alterou o nosso bloco de script, o que está correto, mas significa que essas cadeias ficam em inglês.

Depois de Traduzir: Verificar

  1. Execute a verificação estrutural.

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

    Compara as etiquetas e a sua ordem, todos os atributos que não são texto destinado ao leitor, o conteúdo de <pre>, <script> e <style>, o código inline, as chaves JSON-LD, o texto com translate="no", os comentários e as ligações dentro da página. Avisa sobre atributos de texto ainda em inglês, um valor 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 etiqueta inline. Não avalia a qualidade da tradução.

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

  3. Abra a página num navegador. Clique nas ligações dentro da página, percorra o formulário com um leitor de ecrã, se puder, e procure lacunas à volta de texto a negrito e com ligações.

  4. Para línguas da direita para a esquerda, defina também dir="rtl" no elemento <html>. O nosso guia de tradução de livros RTL explica o que mais muda.

  5. Para XHTML, como os ficheiros de capítulo dentro de um EPUB, confirme também que o ficheiro continua a ser XML bem formado, por exemplo com xmllint --noout chapter.xhtml. Um navegador perdoa uma etiqueta não fechada; um leitor de ebooks pode não perdoar. A nossa lista de verificação de QA de tradução de EPUB cobre o resto de um ebook.

Onde o BookTranslator se Encaixa

A página de carregamento do BookTranslator aceita ficheiros .html, .htm e .xhtml, juntamente com livros e documentos, pelo que pode carregar uma página guardada ou um artigo de ajuda estático como um ficheiro completo. Não passámos esta amostra pelo BookTranslator para este artigo e não testámos como este lida com a ordem do código inline, conteúdo CSS ou JSON-LD, por isso verifique o resultado da mesma forma que verificaria o de qualquer outra ferramenta. Vê o preço antes de pagar.

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

Obtenha os ficheiros de teste

Tudo deste teste é gratuito para reutilizar:

Publicações relacionadas