BookTranslator
BookTranslator

Een HTML-bestand vertalen zonder tags, attributen of links te breken

Wat je in een HTML-bestand vertaalt, wat je met rust laat en hoe je het controleert. Met een voorbeeldpagina, een gratis checker en een lokale LLM-test met 9 runs.

BookTranslator

BookTranslator Team

14 min lezen

Om een HTML-bestand te vertalen, vertaal je de tekst die mensen lezen en de attributen die lezersgerichte woorden bevatten, zoals alt, title, placeholder, aria-label en de metabeschrijving van de pagina. Laat de opmaak met rust: tagnamen, href, src, id, class, scripts, stijlen en alles wat gemarkeerd is met translate="no". Wijzig daarna één waarde die makkelijk vergeten wordt, het lang-attribuut op het <html>-element, zodat browsers, schermlezers en zoekmachines weten in welke taal de pagina nu is.

De tags intact houden bleek het makkelijke deel. We hebben een HTML-hulppagina van 59 regels negen keer naar Vereenvoudigd Chinees vertaald met een lokaal model, met drie methoden, en elke uitvoer met een script gecontroleerd. Elke run behield elke tag, link en ID. Wat misging was subtieler: het model vertaalde een regel binnen een <pre>-codeblok in alle zes runs die het hele bestand verstuurden, het liet de aria-label van de navigatie in alle zes in het Engels staan, en de methode die de opmaak door zijn ontwerp het veiligst houdt, het stukje voor stukje vertalen van tekst, produceerde in alle drie de runs een zin die de lezer het verkeerde liet doen.

Snel antwoord: wat je vertaalt en wat je met rust laat

Deel van het bestandVoorbeeld uit onze steekproefVertalen?
Zichtbare tekstkoppen, alinea's, tabelcellen, linktekst, <label>Ja
<title> en metabeschrijving<title>Export Your Library | Shelfmark Help</title>Ja. Beide verschijnen in zoekresultaten en browsertabs.
og:title en andere social-meta-tags<meta property="og:title" content="Export Your Library">Ja, alleen de content-waarde
alt, title, placeholder, aria-labelalt="The Export dialog with EPUB selected", aria-label="Breadcrumb"Ja
lang op <html><html lang="en">Wijzig het naar de doeltaal, bijvoorbeeld zh-Hans
Tag- en attribuutnamen<a>, <img>, width, aria-label zelfNee
href, src, id, class, for, name, type, data-*href="#choose-format", id="q"Nee
<code>, <pre>, <script>, <style>shelfmark export --format epubNee. Beslis apart over codecommentaar en voorbeelduitvoer.
Tekst ingesteld door CSS.note::before { content: "Note: "; }Ja, maar het staat in de stylesheet, dus houd er rekening mee
JSON-LD-gestructureerde gegevens"name": "Export your Shelfmark library"Vertaal de waarden van name en description; houd de sleutels en de JSON geldig
Elementen met translate="no"<span translate="no">Shelfmark</span>Nee
HTML-opmerkingen<!-- Generated by the help-center build... -->Optioneel. Lezers zien ze nooit.
Tekenverwijzingen&lt;library&gt;, &nbsp;, &copy;Houd de geëscaleerde geëscaleerd. &lt; mag geen echte < worden.

Deze lijst is niet onze uitvinding. De sectie over het translate-attribuut in de HTML-standaard definieert "vertaalbare attributen": title op elk element, alt op afbeeldingen, placeholder op invoervelden, content op meta-elementen waarvan de naam bekend staat als vertaalbaar, en lang, dat volgens de standaard moet worden aangepast aan de nieuwe taal. Ook noemt het ARIA's aria-label als voorbeeld van een attribuut dat andere specificaties kunnen toevoegen, en het stelt dat in een element met translate="no" tekst en attribuutwaarden "ongewijzigd moeten blijven wanneer de pagina wordt gelokaliseerd."

Wat we hebben getest

We schreven sample-source.html, een helpcenter-pagina voor dezelfde fictieve leesapp, Shelfmark, die we gebruikten in onze Markdown-vertaaltest. Het bevat één voorbeeld van elke rij in de bovenstaande tabel, plus een paar valkuilen:

  • een zin opgesplitst door inline-tags: "Voordat je exporteert, maak een back-up van je notities. Een export kopieert je boeken, maar verwijdert niets uit Shelfmark," met de productnaam binnen translate="no";
  • een zin met twee inline <code>-elementen waarvan de volgorde belangrijk is: "Typ het pad naar de map <library> na --out";
  • een <pre><code>-blok met een commando en één regel voorbeelduitvoer, # Export finished: 128 books;
  • een CSS-regel die het woord "Let op:" vóór een alinea invoegt;
  • een link binnen de pagina naar #choose-format, een mailto:-link, een zoekformulier en een JSON-LD-blok.

Vervolgens vroegen we een lokaal model om het op drie manieren naar Vereenvoudigd Chinees te vertalen:

  1. Heel bestand. Plak het hele bestand en vraag om het vertaalde bestand terug.
  2. Met instructies. Hetzelfde, plus acht regels: behoud elke tag- en attribuutnaam, wijzig href, src, id, class en vergelijkbare waarden niet, vertaal de genoemde tekstattributen en meta-tags, laat <code>, <pre>, <script> en <style> met rust behalve de JSON-LD name en description, respecteer translate="no", behoud tekenverwijzingen en opmerkingen, en stel lang in op zh-Hans.
  3. Segmenten. De aanpak van tools die tekst uit HTML halen: een script splitst het bestand in tags en tekst, slaat <code>, <pre>, <script>, <style> en elementen met translate="no" over, stuurt de overgebleven tekstfragmenten en tekstattributen als een genummerde JSON-lijst naar het model, en schrijft de vertalingen terug in de onaangetaste markup. Het stelt ook zelf lang="zh-Hans" in.

Het model was Qwen 3.6 27B (Q4_K_M) in LM Studio, met thinking uitgeschakeld en temperatuur 0,3, op een Apple M4 Max met 64 GB geheugen. We voerden elke methode drie keer uit, negen runs in totaal, op 27 oktober 2026. Het script is run_llm_html_test.py, en alle negen uitvoer is ongewijzigd gepubliceerd; de README vermeldt elk bestand. Als je nog nooit een lokaal model hebt opgezet, behandelt onze handleiding voor lokaal LLM-vertalen de instellingen.

Dit was een kleine test van één model, één talenpaar en één pagina. Het laat zien welke problemen optreden en hoe je ze kunt opsporen. Het rangschikt geen modellen of tools.

Resultaat: De markup overleefde; drie beslissingen niet

We hebben elke uitvoer gecontroleerd met check_html_translation.py, een checker die alleen de standaardbibliotheek van Python gebruikt. De volledige uitvoer staat in check-results.txt, en results.csv bevat één rij per run.

ControleHeel bestand (3 runs)Geïnstrueerd (3 runs)Segmenten (3 runs)
Dezelfde 58 tags in volgorde; elke href, src, id, class ongewijzigd3 van 33 van 33 van 3
translate="no"-tekst behouden, link op de pagina werkt nog, &lt;library&gt; nog steeds geëscaped3 van 33 van 33 van 3
Voorbeelduitvoerregel binnen <pre> vertaald3 van 33 van 30 van 3 (overgeslagen by design)
CSS content: "Note: " vertaald3 van 30 van 30 van 3 (overgeslagen by design)
JSON-LD name en description vertaald3 van 33 van 30 van 3 (bewust overgeslagen)
aria-label="Breadcrumb" vertaald0 van 30 van 33 van 3
Zin met twee inline <code>-elementen zegt het juiste3 van 33 van 30 van 3
Spaties tussen Chinese tekst over een inline tag heengeen0, 5 en 46 in elke run
lang op <html>zh-CN (niet gevraagd)zh-Hanszh-Hans (ingesteld door het script)

Elk van de negen runs behield dezelfde 58 tags in dezelfde volgorde, elke href, src, id en class, het doel van de link binnen de pagina, de opmerking, de geëscaleerde &lt;library&gt; en de productnaam binnen translate="no". Als je je zorgen maakte dat een model de opmaak van een eenvoudige pagina zou verminken: dat deed het niet. De problemen zaten allemaal in wat er vertaald moest worden.

1. Voorbeelduitvoer binnen <pre> werd vertaald

Het codeblok in ons voorbeeld eindigt met een regel programma-uitvoer:

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

In alle zes runs op het hele bestand en met instructies gaf het model op die regel # 导出完成:128 本书 terug, inclusief de drie runs waarin de prompt zei niets binnen <pre> te wijzigen. Het commando zelf werd nooit aangeraakt. Het model behandelde de regel als een opmerking, en opmerkingen vertalen is een redelijke keuze in een tutorial. Maar deze regel is wat het programma afdrukt, en een lezer die hem met zijn terminal vergelijkt, ziet Engels. Beslis vóór het vertalen of voorbeelduitvoer en codeopmerkingen worden vertaald, en vertel het de tool, of bescherm <pre>-blokken volledig.

De runs op het hele bestand vertaalden ook de CSS content: "Note: " in het <style>-blok, terwijl de runs met instructies, met de opdracht <style> met rust te laten, die in het Engels hielden. Geen van beide is op zichzelf fout. De stylesheet vertalen is correct voor een pagina waar de CSS inline staat, en fout voor een site waar één gedeelde stylesheet elke taal bedient. Hoe dan ook, het is een beslissing die iemand moet nemen, geen detail dat een model zou moeten raden.

2. Toegankelijkheidslabels werden overgeslagen

De breadcrumb-navigatie is <nav aria-label="Breadcrumb">. Een schermlezer kondigt dat label aan; ziende lezers zien het nooit. In alle zes runs op het hele bestand en met instructies bleef het in het Engels, ook al noemde de prompt met instructies aria-label bij de te vertalen attributen. In één run met instructies bleef ook de aria-label="Search" van de zoekknop in het Engels.

De segmentmethode vertaalde het elke keer, omdat het script elke waarde van aria-label, alt, title en placeholder verzamelde en er elk afzonderlijk om vroeg. Dat is het sterkste argument om tekstattributen doelbewust te extraheren in plaats van te hopen dat het model ze opmerkt.

3. Het vertalen van stukjes behield de tags en verbrak de zin

De segmentmethode is per constructie veilig voor de opmaak: het model ziet nooit een tag, dus het kan er geen beschadigen. Het doorstond elke structurele controle in alle drie de runs. Het leverde ook de enige vertaling in de test op die de lezer verkeerde instructies gaf.

De Engelse zin is "Type the path to the <library> folder after --out." Inline <code> splitst hem in drie stukken: "Type the path to the", "folder after" en een punt. Het Chinees zet deze woorden in een andere volgorde, dus een vertaler moet de twee code-elementen verplaatsen. De segmentmethode kan ze niet verplaatsen. Alle drie de runs keerden de instructie om. Run 2 produceerde dit (runs 1 en 3 zeggen 后 in plaats van 之后, met dezelfde betekenis):

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

Dat leest als "na <library>, typ het pad van de --out-map," het omgekeerde van de instructie. Alle zes whole-file- en geïnstrueerde runs verplaatsten de code-elementen en deden het goed:

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

Dezelfde splitsing liet losse spaties achter waar een tag aan Chinese tekst grenst, zoals 前往 <b>设置</b> en <b>书库</b> ,, in alle drie de segmentruns, zes plaatsen per run. Een browser toont ze als zichtbare gaten, ook vóór Chinese leestekens. De whole-file-runs hadden er geen; twee van de drie geïnstrueerde runs hadden er vier of vijf.

Een structurele checker kan de omgekeerde zin niet vangen, omdat elke tag precies staat waar hij stond. Onze checker meldt wanneer inline code van volgorde verandert, wat normaal is voor veel talen, maar die waarschuwing kan goed en fout niet onderscheiden. In deze test sloeg hij aan bij alle zes correcte vertalingen en bleef hij stil bij de drie foute, omdat de foute de Engelse volgorde aanhielden. Alleen een persoon die de zin leest, kan het verschil zien. De oplossing is om hele zinnen, met hun inline tags, naar de vertaler te sturen, wat de whole-file-runs deden, en daarna de structuur te controleren.

Kleinere verschillen

  • lang: de whole-file-runs veranderden het uit zichzelf in zh-CN. De geïnstrueerde runs gebruikten zh-Hans, zoals gevraagd. Beide zijn geldige taaltags; zh-Hans benoemt het schrift (Vereenvoudigd Chinees), zh-CN benoemt een regio. De richtlijnen van het W3C over taaldeclaraties raden aan de taal op het <html>-element te declareren en niet met een Content-Language-metatag.
  • JSON-LD: de whole-file- en geïnstrueerde runs vertaalden de waarden van name en description en hielden de JSON geldig. Ons segment-script sloeg de inhoud van <script> over, dus de gestructureerde data bleef in het Engels, wat een tool die scripts negeert ook zal doen.
  • Tekelverwijzingen: de whole-file- en geïnstrueerde runs hielden &rsaquo;, &nbsp;, &copy; en de emoji-verwijzing zoals geschreven. Vijf van die zes runs herschreven het bereik 2&ndash;5 in Chinese woorden (2 到 5 of 2 至 5); één geïnstrueerde run schreef een gewoon streepje in plaats van de verwijzing, hoewel de prompt zei verwijzingen te behouden. Ons segment-script decodeerde ze allemaal en schreef de tekens terug, wat hetzelfde weergeeft. De belangrijkste, &lt;library&gt; binnen <code>, bleef in alle negen runs geëscaped.

Voordat je vertaalt: bereid het bestand voor

  1. Markeer wat niet mag veranderen. Zet translate="no" op productnamen, modelnummers, code-achtige strings in proza en al het andere dat zo moet blijven. Het is onderdeel van HTML, het kost niets, en het model respecteerde het in alle zes runs die het hele bestand ontvingen. Segmenttools die het lezen, zoals ons script, slaan die elementen volledig over. Onze gids voor niet-vertalen behandelt hoe je bepaalt wat op die lijst komt.
  2. Bepaal het codebeleid. Worden codecommentaren vertaald? Voorbeelduitvoer? Wordt de stylesheet gedeeld tussen talen? Schrijf het antwoord op, samen met de namen die niet mogen veranderen, in een vertaalwoordenlijst, en geef die aan wie of wat er ook vertaalt.
  3. Houd ID's in de brontaal. Links binnen de pagina verwijzen naar id-waarden. Als iemand een id vertaalt, breekt elke link ernaar. Geen van onze runs deed dat, maar een vertaler die "behulpzaam" ankers lokaliseert, zal dat wel doen.
  4. Verzamel de verborgen tekst. Maak een lijst van de attributen die woorden bevatten, alt, title, placeholder, aria-label, value op knoppen, metatags en JSON-LD, zodat ze worden gecontroleerd en niet vergeten.
  5. Vertaal JavaScript-strings niet ter plaatse. Berichten die door een script worden ingesteld, zoals een alert of een knoplabel dat in code wordt gemaakt, vereisen een aparte lokalisatiestap in de code. Geen van de zes whole-file- of geïnstrueerde runs veranderde ons scriptblok, wat correct is, maar het betekent dat die strings in het Engels blijven.

Nadat je hebt vertaald: controleer het

  1. Voer de structurele controle uit.

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

    Het vergelijkt tags en hun volgorde, elk attribuut dat geen lezersgerichte tekst is, de inhoud van <pre>, <script> en <style>, inline code, JSON-LD-sleutels, tekst met translate="no", commentaren en links binnen de pagina. Het waarschuwt voor tekstattributen die nog in het Engels zijn, een lang-waarde die afwijkt van wat je verwacht, zichtbare tekst die onvertaald lijkt, inline code die van volgorde is veranderd, en spaties tussen Chinese, Japanse of Koreaanse tekst over een inline tag heen. Het beoordeelt de vertaalkwaliteit niet.

  2. Lees elke zin die een inline tag bevat. Hier brak de betekenis in onze test. Vertrouw niet op de waarschuwing "inline code herschikt" van de checker om deze zinnen te vinden: in onze test waren de foute vertalingen juist degenen die de oorspronkelijke volgorde aanhielden.

  3. Open de pagina in een browser. Klik op de links binnen de pagina, tab door het formulier met een schermlezer als je kunt, en let op gaten rond vetgedrukte en gelinkte tekst.

  4. Voor rechts-naar-links talen, stel ook dir="rtl" in op het <html>-element. Onze gids voor RTL-boekvertaling behandelt wat er nog meer verandert.

  5. Voor XHTML, zoals de hoofdstukbestanden in een EPUB, bevestig ook dat het bestand nog steeds goed gevormde XML is, bijvoorbeeld met xmllint --noout chapter.xhtml. Een browser vergeeft een niet-gesloten tag; een e-reader misschien niet. Onze QA-checklist voor EPUB-vertalingen behandelt de rest van een e-book.

Waar BookTranslator past

De uploadpagina van BookTranslator accepteert .html-, .htm- en .xhtml-bestanden naast boeken en documenten, zodat je een opgeslagen pagina of een statisch helpartikel als heel bestand kunt uploaden. We hebben dit voorbeeld voor dit artikel niet door BookTranslator gehaald, en we hebben niet getest hoe het omgaat met de volgorde van inline code, CSS-inhoud of JSON-LD, dus controleer de uitvoer op dezelfde manier als je bij elke andere tool zou doen. Je ziet de prijs voordat je betaalt.

Wat je ook gebruikt, doe de voorbereidende stappen vóór het vertalen en de controles erna. Een pagina met alle tags intact kan een lezer nog steeds het verkeerde laten typen. Als je HTML eigenlijk documentatie is die in Markdown is geschreven, behandelt onze Markdown-vertaalgids het bronformaat.

Download de testbestanden

Alles uit deze test mag vrij worden hergebruikt:

Gerelateerde berichten