XLIFF 2.0 and 2.1 files

XLIFF 2.0 is a redesign, not a revision. It shares a name and an ancestry with 1.2 and almost nothing else: different namespace, different element names, different rules for inline codes. A tool that reads 1.2 does not read 2.0 unless someone wrote a second parser.

Unit, segment, ignorable

The namespace is urn:oasis:names:tc:xliff:document:2.0, and it is how you tell the two versions apart in one line. Inside, the structure is <file> → optional <group> → <unit>, and a unit holds an ordered list of <segment> and <ignorable> elements.

<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0"
       srcLang="en" trgLang="fr">
  <file id="f1" original="docs/deploy/checklist.html">
    <unit id="u1">
      <segment id="s1" state="translated">
        <source>Read the deployment checklist.</source>
        <target>Consultez la liste de contrôle de déploiement.</target>
      </segment>
      <ignorable>
        <source> </source>
      </ignorable>
      <segment id="s2" state="initial">
        <source>Promote the build.</source>
        <target></target>
      </segment>
    </unit>
  </file>
</xliff>

This is the fix for the biggest structural weakness of 1.2. A segment is a real element with its own source, its own target and its own state, instead of a marker pair smuggled into a paragraph. Concatenating a unit's segments and ignorables in document order reproduces the original paragraph exactly, which is what makes re-segmentation safe.

<ignorable> is the other half of that deal: the whitespace and punctuation the segmenter had to remove to split a paragraph into sentences. It is not translatable content, it never appears as a row in xliff.ai, and it is never edited or spliced. Tools that show ignorables as empty segments are misreading the format.

Language codes moved too: where 1.2 had source-language on the file element, 2.0 puts srcLang and trgLang on the root. Attribute names are camelCase throughout, which is a quick way to spot a hand-written file that is really 1.2 wearing a 2.0 namespace.

2.0 against 2.1

2.1 keeps the same core namespace and the same version attribute slot — a 2.1 file says version="2.1" and otherwise parses under 2.0 rules. What it adds sits in modules, each in its own namespace: metadata (mda), translation candidates (mtc), glossary (gls), change tracking, size and length restriction, validation, resource data. 2.1 also adds a mapping to ITS 2.0 for localization metadata such as terminology and locale filters.

Modules matter to a parser for one reason: they contain their own <source> and <target> elements. A translation candidate inside mtc:matches looks exactly like a segment to a naive walker. xliff.ai skips every foreign-namespace subtree wholesale, so module payloads never leak into the grid, and they come back out of the export untouched.

Inline codes

2.0 replaced the ten inline elements of 1.2 with a smaller, stricter set. Every code carries an id that is unique within its unit, and codes must nest properly or use the split forms below.

  • <pc> — A paired code with content, the direct replacement for the 1.2 g and bpt/ept pairs. Its two halves reference originalData through dataRefStart and dataRefEnd.

    Read the <pc id="3" dataRefStart="d1" dataRefEnd="d2">complete checklist</pc>.
  • <ph/> — A standalone placeholder: an image, a line break, a runtime variable. dataRef points at its native code.

    The queue holds <ph id="p1" dataRef="d2" equiv="{{count}}" disp="{{count}}"/> jobs.
  • <sc/> and <ec/> — The start and end of a spanning code written as two standalone elements, joined by startRef. This is how a code legally crosses a segment boundary; isolated="yes" marks a half whose partner is in another unit.

    <sc id="sc1" dataRef="d1"/>error budget burn rate … <ec startRef="sc1" dataRef="d2"/>
  • <mrk> — An annotation with content: a comment, a term, a do-not-translate span. type says which, and value carries the payload.

    Your plan includes <mrk id="mrk1" type="comment" value="seat = postazione">10 seats</mrk>.
  • <sm/> and <em/> — The same annotation split into two standalone markers, joined by startRef, for when the annotation crosses a segment or overlaps another span.

    <sm id="mrk2" type="comment" value="Do not reword."/>unused seats are not refunded<em startRef="mrk2"/>
  • <cp/> — A single character that cannot legally appear in XML, carried as a hex code point.

    Ends with a form feed<cp hex="000C"/>

Two display attributes travel with most codes. equiv is the plain-text equivalent used for length counting; disp is what a tool should show the translator. xliff.ai labels a chip from disp, then equiv, then the id, in that order.

originalData

In 1.2 the native markup lives inside the inline tag. In 2.0 it is hoisted out into a <originalData> block at the top of the unit, and the codes point at it by id. That is why 2.0 inline markup looks empty at first glance — the actual HTML or XML is a few lines above.

<unit id="u1">
  <originalData>
    <data id="d1">&lt;strong&gt;</data>
    <data id="d2">&lt;/strong&gt;</data>
    <data id="d9">&lt;br/&gt;</data>
  </originalData>
  <segment id="s1" state="translated">
    <source>Read the <pc id="3" dataRefStart="d1" dataRefEnd="d2">complete</pc> checklist.<ph id="5" dataRef="d9" equiv=" " disp="&lt;br/&gt;"/></source>
    <target>Consultez la liste <pc id="3" dataRefStart="d1" dataRefEnd="d2">complète</pc>.<ph id="5" dataRef="d9" equiv=" " disp="&lt;br/&gt;"/></target>
  </segment>
</unit>

dataRef on a standalone code and dataRefStart / dataRefEnd on a paired code are the links. The practical consequence: a code with no data reference is not broken, it is a code whose original form the extractor chose not to record. The upside is that identical markup is stored once per unit instead of once per occurrence, which makes 2.0 files noticeably smaller on tag-heavy content.

canDelete, canCopy, canReorder

These three attributes are the reason 2.0 can express constraints that 1.2 could only document in a mail. All three default to yes.

  • canDelete="no" — the translator must not remove this code. In xliff.ai the chip refuses to delete: backspace over it and nothing happens, so a placeholder the developer depends on cannot quietly disappear.
  • canCopy="no" — the code must appear at most once. Duplicating it would create two elements with the same id in the target.
  • canReorder="no" — this code must stay in the same order relative to its neighbours. canReorder="firstNo" marks the first code of a sequence that has to move as a block: the group can move, but not the members within it.

A file that sets none of them is not saying the codes are free to move; it is saying the extractor had no opinion. Treat placeholders with the same care either way.

state and subState

2.0 cut the ten states of 1.2 down to four, and moved the attribute onto <segment> where it belongs.

Value What it means
initial The default when the attribute is absent. No translation work has been recorded, whether or not the target holds text.
translated Translated, not yet reviewed.
reviewed Reviewed, not yet signed off as final.
final Finished. No further work expected.

subState carries the vendor detail the four values cannot express. It is free-form but must be prefixed with a registered authority — subState="acme:reviewLevel2" — and it only has meaning alongside a state. xliff.ai reads it, shows it, and never rewrites it: an export touches the state attribute of segments whose status you actually changed, and nothing else on the segment tag.

Because 2.0 has no separate "empty" state, xliff.ai tells an untouched segment from a started one by whether the target holds content, and writes initial for both when you clear a status.

What an export changes

The same rule as every XML format here: the original bytes are kept and only replacement ranges are spliced in. Open a 2.0 file, change nothing, export it, and the result is byte-identical to the input. Edit four segments and exactly four target ranges differ, plus the state attribute on those four segment tags. Module payloads, <originalData>, notes, comments, processing instructions, indentation and entity style all come back untouched, because nothing outside the edited ranges is ever written.

Related formats

XLIFF 1.2 covers the older structure, its ten inline tags and its ten states. SDLXLIFF and MQXLIFF are both 1.2 dialects, so a project that mixes them is mixing versions as well as vendors.

Checking how much room the codes leave you: pseudo-translate the file first.