Both standards write files called .xlf. Both call themselves XLIFF. A tool that
reads one may reject the other outright, and the only reliable way to tell them
apart before parsing is the root namespace:
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0">
Trust the namespace, not the version attribute. Files exist in the wild where
someone bumped the version string on a 1.2 document and shipped it.
XLIFF 1.2 became an OASIS Standard in February 2008. XLIFF 2.0 followed in August 2014, and it is a redesign rather than a revision — nothing in 2.0 is backward compatible with 1.2. Well over a decade later, 1.2 is still the format that CAT tools actually exchange.
What changed structurally
A 1.2 document nests file → body → optional group → trans-unit, and the
trans-unit is the unit of work:
<trans-unit id="7">
<source>Open the file and press <g id="1">Save</g>.</source>
<target state="translated">Öffnen Sie die Datei und drücken Sie <g id="1">Speichern</g>.</target>
</trans-unit>
Segmentation was retrofitted. A segmented 1.2 file keeps the whole paragraph in
source, adds a parallel seg-source in which each sentence is wrapped in
mrk mtype="seg" with a mid, and expects target to carry matching markers
with the same mid values:
<trans-unit id="7">
<source>First sentence. Second sentence.</source>
<seg-source>
<mrk mtype="seg" mid="1">First sentence.</mrk> <mrk mtype="seg" mid="2">Second sentence.</mrk>
</seg-source>
<target>
<mrk mtype="seg" mid="1">Erster Satz.</mrk> <mrk mtype="seg" mid="2">Zweiter Satz.</mrk>
</target>
</trans-unit>
That is two parallel representations of the same text which have to be kept
consistent by hand. Miss one mid and you get a file that opens cleanly and
silently drops part of the translation on import.
XLIFF 2.0 makes the segment a first-class container and drops group from the
core:
<unit id="7">
<originalData>
<data id="d1"><b></data>
<data id="d2"></b></data>
</originalData>
<segment id="s1" state="translated">
<source>Open the file.</source>
<target>Öffnen Sie die Datei.</target>
</segment>
<ignorable>
<source> </source>
</ignorable>
<segment id="s2" state="initial">
<source>Press <pc id="1" dataRefStart="d1" dataRefEnd="d2">Save</pc>.</source>
</segment>
</unit>
Three things in that fragment matter. state moved from target to segment,
which is the correct home for it. ignorable holds the material between
segments — the space after a full stop, a bullet character — so nothing lives
outside a container and resegmentation stops being guesswork. And the native
markup moved out of the text stream into originalData, referenced by id.
Beyond structure, three changes shape day-to-day behaviour:
- Modules. The 2.0 core is small and mandatory; optional functionality lives in separately namespaced modules — Translation Candidates, Glossary, Metadata, Format Style, Resource Data, Change Tracking, Size and Length Restriction. A conforming tool declares which it supports and may legally drop the rest. In 1.2 everything shared one namespace and “conformance” meant whatever the vendor implemented.
- One inline model instead of three. 1.2 offers
g/x,bx/ex, andbpt/ept/phfor the same job, and tools implement different subsets. 2.0 has exactly one model. See the inline tag guide. - Constrained extensibility. 1.2 let a vendor hang foreign-namespace elements and attributes almost anywhere. 2.0 limits the extension points and points vendors at the Metadata module instead.
Why 1.2 still dominates interchange
The blunt reason is that the two bilingual formats translators exchange most are
both 1.2 underneath. SDLXLIFF, the working format inside Trados Studio projects,
is XLIFF 1.2 plus an sdl namespace. MQXLIFF, memoQ’s bilingual export, is
XLIFF 1.2 plus an mq namespace. Phrase and Crowdin both emit 1.2 by default.
Once the largest tools settled on a lowest common denominator, every filter,
script and QA tool in the chain was written against it.
The extensibility 2.0 tightened is precisely what those vendors depend on. A
confirmation level in sdl:seg conf="...", a match rate in mq:percent, a
comment id, a lock flag — under 2.0’s rules that data belongs in the Metadata
module, which means rewriting the filter layer on both sides for no benefit any
customer can see. A working interchange path is worth more than a clean one.
Where 2.0 did land is upstream of the CAT tools: newer software-localization platforms, ICU and Java toolchains, the Okapi framework (which reads and writes both), and procurement that specifies the current standard. If a 2.0 file reaches you today, it most likely came out of a developer’s build pipeline rather than another translator’s project.
Migration realities
Conversion between the two is lossy in both directions, and the losses are not evenly distributed.
State. 1.2 has ten state values plus a separate approved flag; 2.0 has
four. Going up, the needs-review-* family collapses. Coming down, you are
inventing detail the file never carried.
Identity. 1.2 addresses a segment as trans-unit/@id plus mrk/@mid; 2.0
as unit/@id plus segment/@id. The mapping is not one-to-one for unsegmented
1.2 files, and it is not stable at all if a tool resegmented on import.
Inline codes. Properly nested bpt/ept pairs convert to pc cleanly.
Overlapping pairs — legal in 1.2 and routine out of HTML filters, where a bold
span opens inside an italic span and closes outside it — cannot. They have to
become sc/ec with a correct startRef, or isolated="yes" when the partner
lives in another unit. This is the case behind most “the converted file opens
but the tags are wrong” reports.
Vendor data. Nothing in the sdl or mq namespaces has a 2.0 equivalent.
Convert a Trados Studio bilingual file to 2.0 and the match rates, comments and
lock flags do not survive.
The practical rules follow from that: convert at a project boundary, never mid-project; keep the original file, always; and if a client sends 2.0 and your tool wants 1.2, ask for a 1.2 export from the same source rather than converting the bilingual file yourself. If you are the one generating XLIFF from an application, emit 2.x — you own both ends of that pipe.
What 2.1 changed
XLIFF 2.1 reached OASIS Standard status in February 2018 and is purely additive.
The core namespace did not change: a 2.1 document is still
urn:oasis:names:tc:xliff:document:2.0 with version="2.1", which is why a
reader written for 2.0 normally handles 2.1 without a second code path. This
editor treats them as one format for exactly that reason.
Two things arrived. First, native support for W3C ITS 2.0 metadata — terminology, localization notes, domain, provenance, MT confidence, text analysis — instead of the vendor extensions everyone had been using. Second, the Validation module, which lets constraint rules travel with the file: this target must contain that string, must not exceed that length. Any conforming tool can check them, so the rules stop living in a separate spreadsheet.
Neither is breaking and neither moved the market much. If you are choosing a version to emit today, emit 2.1. If you are writing a reader for files other people send you, write 1.2 first.
How this editor handles both
The parsers are separate — formats/xliff12 and formats/xliff20 in the
open-source engine — but they produce the same segment model, so the
grid, the QA checks and the exports do not care which standard you opened.
Nothing is re-serialized: the original bytes are kept and only the ranges you
actually changed are spliced back, so attribute order, entity style, namespace
prefixes and every vendor extension survive a round trip untouched. Native state
strings the mapping table does not recognise are preserved verbatim and written
back unchanged unless you edit that segment’s state yourself.