Guides

Inline tags explained

Inline tags are the markup that survives extraction. When a filter pulls a sentence out of a DOCX, an HTML page or a resource file, the formatting and the placeholders inside that sentence have to travel with it, and they cannot travel as literal markup — a raw < in the text would break the XLIFF itself. So every XLIFF version defines a set of elements that stand in for native code inside source and target.

Getting them wrong is the most common way to produce a bilingual file that opens fine and fails on import.

The XLIFF 1.2 taxonomy

1.2 grew two competing inline models and kept both. That is the single biggest source of confusion in the format.

ElementRepresentsNotes
gA paired native code wrapping translatable textWell-formed container; the text inside stays translatable
xA standalone native code with no contentLine break, image, field
bx / exBegin and end of a pair, as two empty elementsJoined by rid; used when the pair cannot nest cleanly
bpt / eptBegin and end of a pair, carrying the native code insideJoined by rid; the markup itself is escaped in the element content
phA standalone code, carrying the native code insideThe x equivalent for the “native code” model
itAn isolated half of a pair whose partner is in another unitpos="open" or pos="close"
subTranslatable text embedded inside a native codeAn alt or title attribute value; nests inside ph, bpt, ept, it
mrkAn annotation over a spanmtype="seg", term, protected, or a vendor x-* value

The difference between the two models is where the native markup lives. The abstract model hides it:

<source>Press <g id="1">Save</g> or <x id="2"/> to continue.</source>

The native-code model carries it:

<source>Press <bpt id="1">&lt;b&gt;</bpt>Save<ept id="1">&lt;/b&gt;</ept> or
<ph id="2">&lt;br/&gt;</ph> to continue.</source>

Both are valid. Which one you get depends entirely on the filter that produced the file, which is why a generic 1.2 reader has to implement all of it.

sub deserves a mention because it is routinely mishandled. It marks translatable text inside a code — the alt text of an image, the title of a link — so a segment can contain a tag which itself contains a second piece of text that needs translating. Tools that treat every code as opaque simply lose that text.

The XLIFF 2.0 taxonomy

2.0 replaced all of the above with one model, and moved the native markup out of the text stream entirely.

ElementRepresentsNotes
pcA paired code wrapping translatable textMust be well-formed; dataRefStart / dataRefEnd point at originalData
phA standalone codedataRef points at originalData
sc / ecStart code and end code, as two empty elementsFor overlapping or isolated codes; ec carries startRef
mrkAn annotation over a well-formed spantype="term", translate, comment, generic, or a prefixed custom value
sm / emAn annotation span that is not well-formedem carries startRef; use when the annotation crosses code boundaries
cpA character that XML cannot represent literallycp hex="0003" — control characters from the original resource

The originalData store is the structural improvement:

<unit id="u1">
  <originalData>
    <data id="d1">&lt;a href="/help"&gt;</data>
    <data id="d2">&lt;/a&gt;</data>
  </originalData>
  <segment>
    <source>See the <pc id="1" dataRefStart="d1" dataRefEnd="d2">help page</pc>.</source>
  </segment>
</unit>

The markup appears once, at unit level. The content stream carries a reference. A translator moving pc id="1" around the sentence cannot corrupt the href, because the href is not in the sentence.

2.0 also attaches editing constraints to each code, and a conforming editor must honour them:

  • canDelete="no" — the tag may not be removed from the target.
  • canReorder="no" — the tag may not move relative to its siblings.
  • canCopy="no" — the tag may not be duplicated.
  • canOverlap — whether this code may overlap another.

This editor reads canDelete and makes the chip undeletable in the grid when it is no. A 1.2 file has no equivalent; every code there is nominally editable, which is part of why 1.2 files break more often.

Pairing rules

The rules are simple and unforgiving.

In 1.2, bx/ex and bpt/ept are joined by rid. When rid is absent the id serves as the link, which is why you see files where both halves of a pair carry id="1". g needs no join because it is a container — the nesting is the pairing. Overlap is legal in the flat models and impossible in g, which is exactly why filters emit bpt/ept for HTML: overlapping spans are normal there.

In 2.0, pc must nest well-formed and may not overlap unless canOverlap="yes". Anything that cannot be expressed that way becomes sc/ec, with ec/@startRef naming the id of its sc. When the partner is genuinely in a different unit — a bold run that opens in one sentence and closes in the next — the survivor is marked isolated="yes", the 2.0 equivalent of 1.2’s it.

The practical consequence for a translator: an unpaired end tag in the target is not a cosmetic problem. It is a file that will fail validation on import, or worse, produce output where the formatting runs to the end of the document.

Why an editor must treat tags as atomic

A tag chip is not text with a border around it. In this editor a tag’s identity is the exact original byte range it came from, kept verbatim, and export splices those same bytes back into the original file. The chip is selectable only as a whole; there is no caret position inside it.

That is a deliberate constraint, not a limitation:

  • The markup inside a code is not translatable. An href, a rsid attribute, a field code — none of it should ever be typed by a translator, and any interface that allows a caret inside it invites exactly that.
  • Ids and refs are a contract with the converter. The CAT tool that produced the file maps id="1" back to a specific run in the source document. Renumber it and the map breaks silently.
  • Partial edits produce valid XML with wrong meaning. Deleting one character from an escaped &lt;/b&gt; yields a file that parses, passes a schema check, and renders a document where bold never ends.

The QA layer follows the same principle. The tag-mismatch check compares source and target tag multisets by their exact original markup, not by the chip label, because two chips can both display g and be different tags. It reports missing, extra and reordered as three separate findings, since a translator fixes each one with a different action, and it only evaluates order once the multisets already agree — order is meaningless while tags are missing.

What tag soup does to leverage

Tag soup is what you get when the source document was formatted by hand instead of by styles. The usual producers:

  • DOCX with revision-tracking residue, where rsid attributes split one sentence into a dozen runs.
  • PDF-to-Word conversions, which set font and size on nearly every word.
  • HTML from a WYSIWYG editor, with a span carrying inline CSS per phrase.
  • DTP files with character-level kerning or language overrides.

The result is a segment with fifteen tags around eight words. The cost is not mainly annoyance; it is leverage.

Translation memories store the tag structure alongside the text. Two segments with identical words but different tag counts or positions are not a 100% match — they return as 99% or fuzzy, which means a human has to open, check and confirm each one. On a repeat-heavy manual, that is the difference between a quote built on 70% leverage and one built on 40%, and the words themselves never changed. Tag soup also degrades concordance results, breaks alignment when you build a TM from legacy files, and forces MT engines to work around placeholders they cannot interpret.

The fix is upstream. Clean formatting in the source document — real paragraph and character styles, no direct formatting, no leftover tracked changes — before extraction. Most CAT tools also have filter settings that merge or ignore formatting-only codes; turning those on for a soupy project is usually the fastest available win.

What an editor must not do is clean tags on save. Normalizing a file’s inline markup to make it prettier destroys the vendor round trip, and the translator who did nothing wrong gets the rejection notice. This one leaves them alone.