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"><strong></data>
<data id="d2"></strong></data>
<data id="d9"><br/></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="<br/>"/></source>
<target>Consultez la liste <pc id="3" dataRefStart="d1" dataRefEnd="d2">complète</pc>.<ph id="5" dataRef="d9" equiv=" " disp="<br/>"/></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.