Guides

Segment states across CAT tools

“Confirmed” is not a portable concept. Every CAT tool has a status model, every model encodes a slightly different workflow, and the bilingual file is where those models have to meet. A file that leaves one tool showing 800 confirmed segments can arrive in another showing 800 drafts — nothing was corrupted, the two tools simply disagree about what a state is and where it lives.

Here is what each format actually stores.

The XLIFF 1.2 model

1.2 puts a state attribute on target, with ten defined values:

<target state="needs-review-translation">Öffnen Sie die Datei.</target>

new, needs-translation, needs-adaptation, needs-l10n, needs-review-translation, needs-review-adaptation, needs-review-l10n, translated, signed-off, final.

The list mixes two axes. needs-translation and needs-review-translation describe what has to happen next; translated and signed-off describe what already happened. The -adaptation and -l10n variants exist for workflows that distinguish linguistic adaptation from full localization, and in practice almost nobody writes them.

Two more attributes complicate things. state-qualifier on target records where the translation came from — exact-match, fuzzy-match, mt-suggestion, leveraged-tm and friends — and it is not a state, so tools reading only state lose it. And approved="yes" on trans-unit is a separate boolean that several tools use as their real “confirmed” flag, orthogonally to state. This editor reads it: a segment marked translated that also carries approved="yes" is promoted to reviewed, because that combination is what a reviewer’s sign-off looks like in most 1.2 producers.

The XLIFF 2.0 model

2.0 cut the list to four values and moved the attribute where it belongs, onto segment:

<segment id="s1" state="reviewed" subState="acme:proofread">

initial, translated, reviewed, final. That is the whole vocabulary. The committee deliberately removed the “needs” family: a state should say what is true, not what someone intends to do next.

Everything finer-grained goes into subState, which is free-form but must carry a prefix identifying who defined it. That makes subState honest — it is explicitly vendor-private data, and a receiving tool is not expected to understand it. It also makes it useless for interchange, which is the trade the committee accepted.

One thing 2.0 cannot express: the difference between a segment nobody has touched and a segment someone started and left unfinished. Both are initial. You tell them apart by whether target has content, which is exactly what this editor does on read.

The SDLXLIFF model

An SDLXLIFF is XLIFF 1.2 plus an sdl namespace, and this is the trap: the confirmation level is not in the state attribute. It lives in sdl:seg-defs, on a sdl:seg element matched to the segment by id:

<sdl:seg-defs>
  <sdl:seg id="1" conf="ApprovedTranslation" origin="tm" percent="98" locked="false"/>
</sdl:seg-defs>

Values: Draft, Translated, RejectedTranslation, ApprovedTranslation, RejectedSignOff, ApprovedSignOff. A lock is locked="true" on the same element.

A file exported from Trados Studio very often has no state attribute on target at all. Feed it to a naive 1.2 reader and every segment looks untranslated — a support ticket that gets filed against roughly every web XLIFF tool eventually. This editor ignores the 1.2 state attribute entirely on SDLXLIFF and treats conf as the authority.

The neighbouring attributes matter too. percent is the match rate, origin says whether the content came from TM, MT, interactive typing or auto-propagation, and struct-match / text-match record context-match quality. None of that is state, none of it has an equivalent anywhere else, and all of it has to survive a round trip untouched or the project manager’s analysis stops matching the file.

The MQXLIFF model

An MQXLIFF is XLIFF 1.2 plus an mq namespace, and it moves status somewhere else again — onto trans-unit rather than target:

<trans-unit id="42" mq:status="Proofread" mq:percent="101" mq:locked="false">

Values: NotStarted, PartiallyEdited, ManuallyTranslated, Edited, Proofread, Reviewer1, Reviewer2. Edited means content that arrived from a machine or fragment source and was then touched by a human — a confirmed translation, despite the name. Reviewer1 and Reviewer2 come from memoQ’s two-stage review workflow, which no other tool models.

One practical detail worth knowing if you write your own parser: memoQ declares the namespace as the bare string MQXliff, not a URI. It is legal enough for XML but strict validators complain, and code that matches on a URI pattern will miss it.

The mapping this editor uses

One internal state model, mapped both ways at the file boundary:

InternalXLIFF 1.2 stateXLIFF 2.0 stateSDLXLIFF confMQXLIFF mq:status
emptynewinitialDraftNotStarted
draftneeds-translationinitialDraftPartiallyEdited
translatedtranslatedtranslatedTranslatedManuallyTranslated
reviewedneeds-review-translation → translated on confirmreviewedApprovedTranslationProofread
finalsigned-offfinalApprovedSignOffReviewer2

Locked is orthogonal in every model and is tracked separately, not as a state — though memoQ does also expose a Locked status string, which this editor reads as a lock and preserves literally.

The rule that keeps files safe is the one about unmapped values: when a file arrives with a native state the table does not cover, the original string is kept and written back unchanged unless you explicitly change that segment’s state. State derivation runs through identical code on read and on write, so a document you opened and did not edit produces zero byte changes on export. That symmetry is the whole reason a vendor file survives the trip.

What gets lost crossing tools

Some information has nowhere to go, and it is worth knowing which before you promise a client a round trip.

Rejections. RejectedTranslation and RejectedSignOff say a reviewer sent work back. Nothing in XLIFF 1.2, XLIFF 2.0 or memoQ’s model expresses that. The closest honest mapping degrades a rejection to “needs work”, which is why this editor treats those as draft or reviewed by content and keeps the literal string for the return trip.

Multi-stage review. Reviewer1 and Reviewer2 compress into one “reviewed” notion elsewhere. Round-trip through a tool that does not model two reviewers and the distinction is gone.

Provenance and match rates. state-qualifier, sdl:percent, mq:percent, origin — all of it is invisible to a tool that reads only state, and all of it is what pricing arguments are made of.

Vendor sub-states. 2.0’s subState is private by construction. Anything you put there is a note to yourself.

Empty versus started. Lossy in 2.0 in both directions, as above.

The operational advice that follows: agree the state contract in writing before the first handoff, send a five-segment probe file through the full round trip before the real one, and never assume that “translated” means the same thing on both ends of the chain. When a status disagreement does appear, check where the status lives in the format before assuming a file is corrupt — nine times out of ten the data is still there, in an attribute the reading tool never looked at.