Skip to content

XLIFF

phil/translation-memory

Segments leave for a translation tool as an XLIFF file and come back from one.

Export: XLIFF 2.1

$file = XliffFile::fromSegments('page:42', LanguageTag::of('en'), LanguageTag::of('fr'), $segments);
$xml = new XliffWriter()->write($file);
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.1" srcLang="en" trgLang="fr">
  <file id="f1" original="page:42">
    <unit id="u1" name="b1/text">
      <originalData><data id="d1">&lt;b&gt;</data><data id="d2">&lt;/b&gt;</data></originalData>
      <segment state="translated">
        <source>A <ph id="1" dataRef="d1"/>bold<ph id="2" dataRef="d2"/> word</source>
        <target>Un mot <ph id="1" dataRef="d1"/>gras<ph id="2" dataRef="d2"/></target>
      </segment>
    </unit>
  </file>
</xliff>

(The writer puts no white space between elements; it is added here to read.)

  • One unit per segment, identified u1, u2… — XLIFF identifiers are tokens, keys are not — and named after the key.
  • Tags become <ph> codes whose HTML is in the unit's <originalData>: a translation tool shows them as codes to place. A tag of the target that the source holds takes the same code.
  • Text is written as text: &amp; in the source is & in the file, escaped by XML.
SegmentstatesubState
untranslatedinitial—
suggestedinitialphil:suggested
translatedtranslated—
reviewedreviewed—
staleinitialphil:stale, and the earlier source in <note category="phil:previous-source">

Import: XLIFF 2.x and 1.2

$file = new XliffReader()->read($xml);
$result = XliffMerge::merge($segments, $file, LanguageTag::of('en'), LanguageTag::of('fr'));

XliffReader reads XLIFF 2.0, 2.1 and 2.2 — namespace urn:oasis:names:tc:xliff:document:2.0 — and XLIFF 1.2 — namespace urn:oasis:names:tc:xliff:document:1.2. A file that declares a document type is refused before it is parsed; nothing is fetched from the network.

XLIFF 2.xXLIFF 1.2
Keyname, else id of the unitresname, else id of the trans-unit
LanguagessrcLang, trgLang of the rootsource-language, target-language of the first <file>
Codes turned back into HTML<ph>, <sc>, <ec> by dataRef; <pc> by dataRefStart and dataRefEnd; <cp> as its characterThe native code inside <ph>, <bpt>, <ept>, <it>
Codes kept as their words only<mrk>, <pc> without data<g>, <mrk>
Several segmentsJoined, with the <ignorable> between them; the least advanced state—
State in the fileSegment
no target, or a target without wordsuntranslated
2.x initial; 1.2 new, needs-* or a custom statesuggested
2.x translated; 1.2 translated or no statetranslated
2.x reviewed or final; 1.2 final, signed-off or approved="yes"reviewed

Merging

XliffMerge::merge() checks the languages given against the file's, then applies each unit to the segment of its key:

Skipped asWhen
unknown-keyNo segment has the key
source-changedThe segment's source no longer has the words the file was made from
no-targetThe unit has no target with words
unchangedThe target and state are those of the segment, or the same target only proposed

Other units are applied as suggested, translated or reviewed, as the file says. Tags the source does not hold are left out of the target, their words kept: a file cannot bring markup the document never had. The MergeResult holds every segment in its order, the keys applied and the units skipped.