Guides / 9 of 14

Machine-translating an XLIFF file without breaking its tags

Why machine translation damages inline tags and placeholders, three ways to protect them, and how xliff.ai's bring-your-own-key AI translation keeps tags, writes Draft and refuses any result that loses one.

Getting a machine to translate the words in an XLIFF file is the easy part. Getting the file back in a state the source system will accept is where it goes wrong, and almost always for the same reason: something happened to the inline tags.

Why tags are the problem

A segment is rarely plain text. Formatting and placeholders inside it are stored as inline elements such as <g>, <x/>, <bpt>, <ept> and <ph>, and the target has to carry the same inline codes as the source. Lose one, invent one, or break a pair, and the file either fails to import or imports into a document where a link has vanished or bold never ends. The inline tags guide explains what each element stands for.

A translation engine was trained on sentences, not on XML. Hand it Click <g id="1">Save</g> to keep <x id="2"/> changes and it may translate the attribute values, drop the self-closing tag because it carries no words, or move the closing tag to where a natural sentence in the target language would put it, which may not be where the formatting belongs. Placeholders such as {0} or %s suffer the same way; the placeholder guide lists the syntaxes and how each gets corrupted.

Three ways to protect them

  1. Strip the tags and translate plain text. Safe for the engine, bad for the file: someone then has to put every tag back by hand, which on a heavily formatted document costs more than the machine saved.
  2. Send the raw markup and hope. Fast, and right most of the time. The cases where it is wrong are invisible until import fails.
  3. Replace each tag with a short numbered token, translate, then check every token came back exactly once and restore the original markup. This is the approach that scales, because the check is mechanical: either the tokens match or the result is rejected.

How xliff.ai does it

The editor’s AI panel can review a translation or write one, using your own key with Anthropic, OpenAI, Google Gemini, OpenRouter, DeepSeek, Azure OpenAI or an endpoint you name, such as a local model. It uses the third approach:

  • Tags travel as tokens. Each segment’s tags are numbered, <t1>…</t1> for a pair and <t2/> for a standalone tag, and every request tells the model to keep them.
  • The check is strict. When a translation comes back, a token the source does not have, a duplicate, a closing token before its opening one, half of a pair, or any source tag left out makes the result invalid.
  • An invalid result is not written. The segment stays empty and the run’s report lists it as having lost or broken an inline tag, so you know exactly which ones to translate yourself.
  • The original markup is restored. Valid tokens are swapped back for the exact tags the file arrived with, so nothing the engine saw can leak into the file.

Two gaps to know about. Distinct tags that come back in a different order are not rejected by the check; that is sometimes correct for the target language and sometimes not, so look at reordered formatting when you review. And plain-text placeholders such as {0} or %s are protected by the instruction to the model, not by tokens, unless the format already stores them as tags. The placeholder check catches any that went missing, which is why QA belongs straight after an AI run.

What it writes, and what it never does

  • Only empty segments. A run fills the empty targets in your current view. Locked segments and segments with an empty source are skipped, and a target that someone filled in the meantime is left alone.
  • Draft, never confirmed. Every AI result is written as Draft. Nothing becomes Translated until you confirm it with Ctrl+Enter, so an export never presents machine output as finished work by accident.
  • One undo for the whole run. Ctrl+Z puts every segment of the run back as it was.
  • One segment on request. “Translate this segment” retranslates the selected row, replacing what is there, again as Draft and again undoable.

What leaves your computer

Everything else in xliff.ai runs locally; the AI feature is the exception, and it is worth being precise about it. When you press the button, the editor sends, straight from your browser to the provider you chose:

  • the source text of the segments in your current view, with tags as tokens;
  • two neighbouring segments on each side of each one, for context;
  • any matching entries from your glossary, and the two language codes.

It does not send the file itself, its name, or your translation memories. Your key is stored in this browser, or only in memory if you choose “This session only”, and is sent to no one but that provider. See the privacy page for the full wording.

Cost and speed

Requests go in batches of 5 to 50 segments (25 by default), four at a time, and a temporary rate limit or server error is retried with backoff. Before a run starts you see an estimate of the segments, requests, tokens and price at the provider’s list rates, labelled as an estimate, because providers bill you directly and xliff.ai never sees the bill. Azure OpenAI endpoints usually block requests from a browser, and the panel says so before you try.

A workflow that holds up

  1. Load your glossary first, so its terms travel with each segment.
  2. Filter to the segments you want translated, and check the estimate.
  3. Run the translation; read the report for segments that came back without their tags.
  4. Run QA, and fix missing placeholders and numbers before anything else.
  5. Review the Drafts, paying attention to moved formatting, and confirm what you accept.

The machine does the first draft. The tags, the confirmation and the delivery stay yours.