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.

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 ficheiro | Exemplo da nossa amostra | Traduzir? |
|---|---|---|
| Texto visível | cabeç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-label | alt="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-label | Não |
href, src, id, class, for, name, type, data-* | href="#choose-format", id="q" | Não |
<code>, <pre>, <script>, <style> | shelfmark export --format epub | Nã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 | <library>, , © | Mantenha os escapados como escapados. < 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çãomailto:, 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:
- Ficheiro completo. Colar o ficheiro inteiro e pedir o ficheiro traduzido de volta.
- Com instruções. O mesmo, mais oito regras: manter todos os nomes de tags e atributos, não alterar
href,src,id,classe valores semelhantes, traduzir os atributos de texto e meta tags listados, deixar<code>,<pre>,<script>e<style>em paz exceto onameedescriptiondo JSON-LD, respeitartranslate="no", manter referências de caracteres e comentários, e definirlangparazh-Hans. - 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>etranslate="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 definelang="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ção | Ficheiro 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 inalterados | 3 de 3 | 3 de 3 | 3 de 3 |
Texto com translate="no" mantido, link na página continua a funcionar, <library> continua escapado | 3 de 3 | 3 de 3 | 3 de 3 |
Linha de exemplo de saída dentro de <pre> traduzida | 3 de 3 | 3 de 3 | 0 de 3 (ignorado por predefinição) |
CSS content: "Note: " traduzido | 3 de 3 | 0 de 3 | 0 de 3 (ignorado por predefinição) |
name e description do JSON-LD traduzidos | 3 de 3 | 3 de 3 | 0 de 3 (ignorado por predefinição) |
aria-label="Breadcrumb" traduzido | 0 de 3 | 0 de 3 | 3 de 3 |
Frase com dois elementos <code> em linha diz a coisa certa | 3 de 3 | 3 de 3 | 0 de 3 |
| Espaços entre texto chinês através de uma etiqueta em linha | nenhum | 0, 5 e 4 | 6 em cada execução |
lang em <html> | zh-CN (não pedido) | zh-Hans | zh-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 <library> 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><library></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><library></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 parazh-CNpor iniciativa própria. As execuções com instruções usaramzh-Hans, como pedido. Ambos são etiquetas de língua válidas;zh-Hansnomeia o sistema de escrita (chinês simplificado),zh-CNnomeia 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 etiquetaContent-Language.- JSON-LD: as execuções de ficheiro completo e com instruções traduziram os valores
nameedescriptione 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
›, ,©e a referência de emoji como escritas. Cinco dessas seis execuções reescreveram o intervalo2–5em 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,<library>dentro de<code>, permaneceu escapada nas nove execuções.
Antes de Traduzir: Preparar o Ficheiro
- 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. - 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.
- Mantenha os IDs na língua de origem. As ligações dentro da página apontam para valores
id. Se alguém traduzir umid, todas as ligações para ele quebram. Nenhuma das nossas execuções o fez, mas um tradutor que "ajude" a localizar âncoras fá-lo-á. - Recolha o texto oculto. Liste os atributos que contêm palavras,
alt,title,placeholder,aria-label,valueem botões, meta etiquetas e JSON-LD, para que sejam verificados e não esquecidos. - 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
-
Execute a verificação estrutural.
python3 check_html_translation.py source.html translated.html --lang zh-Hans --keep ShelfmarkCompara 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 comtranslate="no", os comentários e as ligações dentro da página. Avisa sobre atributos de texto ainda em inglês, um valorlangdiferente 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. -
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.
-
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.
-
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. -
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:
- sample-source.html: a amostra em inglês de 59 linhas;
- check_html_translation.py: o verificador estrutural (apenas biblioteca padrão do Python);
- run_llm_html_test.py: os três métodos, para qualquer servidor local compatível com OpenAI;
- os nove resultados na pasta de resultados, com check-results.txt e results.csv.
Publicações relacionadas





