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.

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 bestand | Voorbeeld uit onze steekproef | Vertalen? |
|---|---|---|
| Zichtbare tekst | koppen, 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-label | alt="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 zelf | Nee |
href, src, id, class, for, name, type, data-* | href="#choose-format", id="q" | Nee |
<code>, <pre>, <script>, <style> | shelfmark export --format epub | Nee. 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 | <library>, , © | Houd de geëscaleerde geëscaleerd. < 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, eenmailto:-link, een zoekformulier en een JSON-LD-blok.
Vervolgens vroegen we een lokaal model om het op drie manieren naar Vereenvoudigd Chinees te vertalen:
- Heel bestand. Plak het hele bestand en vraag om het vertaalde bestand terug.
- Met instructies. Hetzelfde, plus acht regels: behoud elke tag- en attribuutnaam, wijzig
href,src,id,classen vergelijkbare waarden niet, vertaal de genoemde tekstattributen en meta-tags, laat<code>,<pre>,<script>en<style>met rust behalve de JSON-LDnameendescription, respecteertranslate="no", behoud tekenverwijzingen en opmerkingen, en stellangin opzh-Hans. - 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 mettranslate="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 zelflang="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.
| Controle | Heel bestand (3 runs) | Geïnstrueerd (3 runs) | Segmenten (3 runs) |
|---|---|---|---|
Dezelfde 58 tags in volgorde; elke href, src, id, class ongewijzigd | 3 van 3 | 3 van 3 | 3 van 3 |
translate="no"-tekst behouden, link op de pagina werkt nog, <library> nog steeds geëscaped | 3 van 3 | 3 van 3 | 3 van 3 |
Voorbeelduitvoerregel binnen <pre> vertaald | 3 van 3 | 3 van 3 | 0 van 3 (overgeslagen by design) |
CSS content: "Note: " vertaald | 3 van 3 | 0 van 3 | 0 van 3 (overgeslagen by design) |
JSON-LD name en description vertaald | 3 van 3 | 3 van 3 | 0 van 3 (bewust overgeslagen) |
aria-label="Breadcrumb" vertaald | 0 van 3 | 0 van 3 | 3 van 3 |
Zin met twee inline <code>-elementen zegt het juiste | 3 van 3 | 3 van 3 | 0 van 3 |
| Spaties tussen Chinese tekst over een inline tag heen | geen | 0, 5 en 4 | 6 in elke run |
lang op <html> | zh-CN (niet gevraagd) | zh-Hans | zh-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 <library> 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><library></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><library></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 inzh-CN. De geïnstrueerde runs gebruiktenzh-Hans, zoals gevraagd. Beide zijn geldige taaltags;zh-Hansbenoemt het schrift (Vereenvoudigd Chinees),zh-CNbenoemt een regio. De richtlijnen van het W3C over taaldeclaraties raden aan de taal op het<html>-element te declareren en niet met eenContent-Language-metatag.- JSON-LD: de whole-file- en geïnstrueerde runs vertaalden de waarden van
nameendescriptionen 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
›, ,©en de emoji-verwijzing zoals geschreven. Vijf van die zes runs herschreven het bereik2–5in 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,<library>binnen<code>, bleef in alle negen runs geëscaped.
Voordat je vertaalt: bereid het bestand voor
- 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. - 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.
- Houd ID's in de brontaal. Links binnen de pagina verwijzen naar
id-waarden. Als iemand eenidvertaalt, breekt elke link ernaar. Geen van onze runs deed dat, maar een vertaler die "behulpzaam" ankers lokaliseert, zal dat wel doen. - Verzamel de verborgen tekst. Maak een lijst van de attributen die woorden bevatten,
alt,title,placeholder,aria-label,valueop knoppen, metatags en JSON-LD, zodat ze worden gecontroleerd en niet vergeten. - 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
-
Voer de structurele controle uit.
python3 check_html_translation.py source.html translated.html --lang zh-Hans --keep ShelfmarkHet 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 mettranslate="no", commentaren en links binnen de pagina. Het waarschuwt voor tekstattributen die nog in het Engels zijn, eenlang-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. -
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.
-
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.
-
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. -
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:
- sample-source.html: het Engelse voorbeeld van 59 regels;
- check_html_translation.py: de structuurcontrole (alleen de Python-standaardbibliotheek);
- run_llm_html_test.py: de drie methoden, voor elke OpenAI-compatibele lokale server;
- de negen uitvoerbestanden in de map outputs, met check-results.txt en results.csv.
Gerelateerde berichten





