Skip to content

Bridge bug: TTXFilter does not recognize <Seg> wrappers and merges all <Tu> into a single TextUnit #21

Description

@asgeirf

Surfaced by the spec contract audit (PR spec/ttx).

Symptom

The Okapi TTXFilter parses Trados TTX content but diverges from the Trados Studio output shape in two ways:

  1. <Seg> wrappers inside <Tuv> are treated as opaque inline placeholders rather than the canonical content container. Real-world TTX files produced by SDL/Trados Studio wrap segment text in <Tuv><Seg>...</Seg></Tuv>. The Okapi filter does not recognise <Seg> as a segment-content marker; it walks the XML expecting text directly inside <Tuv>. As a result, every <Tuv><Seg>text</Seg></Tuv> produces an empty TextUnit (no extractable text) and the file appears to have no translatable content.

  2. All <Tu> elements within a single <Raw> collapse into one TextUnit with multiple Segments rather than one TextUnit per <Tu>. When <Seg> is omitted (text directly inside <Tuv>), the filter does extract content but emits a single multi-segment TextUnit. Downstream consumers that expect one Block per TU (which is the convention of every other TM-like filter — TMX, XLIFF) see joined text instead.

Tracked in neokapi/neokapi#453 as the documented native-vs-bridge divergence (`Native TTX needs different sample shape`); this issue captures the underlying root cause for the Okapi side.

Reproduction

`core/formats/ttx/spec.yaml` features `trans_unit_extraction`, `match_percent`, `inline_tags`, `xml_entities`, `segment_mode_*`, `document_structure` — every example uses the ``-wrapped Trados Studio shape. The bridge produces 0 translatable Blocks for every one of them.

```
input: <Tu MatchPercent="0">
<Tuv Lang="EN-US">Hello world
<Tuv Lang="FR-FR">Bonjour le monde

expected: 1 Block, source = "Hello world", target FR-FR = "Bonjour le monde" (native, matches Trados Studio output)
bridge: 0 Blocks (TTXFilter treats as opaque placeholder, no text extracted)
```

Stripping the `` wrappers (text directly inside ``) lets the bridge extract — but it then merges all `` in the same `` into one multi-segment TextUnit:

```
input:
<Tuv Lang="EN-US">Hello world<Tuv Lang="FR-FR">Bonjour le monde
<Tuv Lang="EN-US">Goodbye<Tuv Lang="FR-FR">Au revoir

expected: 2 Blocks
bridge: 1 Block, source = "Hello worldGoodbye" (segments concatenated)
```

Spec tags

Every example in `core/formats/ttx/spec.yaml` is tagged `expected_fail:` so the parity gate downgrades the bridge mismatches to warnings until the filter is fixed. Once the bridge fix lands (or the upstream Okapi behavior is documented as intentional and the spec adapts), drop the `expected_fail:` blocks.

Repro test

```
KAPI_PARITY_SANDBOX=$PWD/.parity \
go test -tags parity -run TestParityTtxSpec -count=1 -v ./parity/...
```

(from `cli/`, on branch `spec/ttx`)

Affected upstream code

`okf_ttx` Java filter — `net.sf.okapi.filters.ttx.TTXFilter` (all pinned Okapi versions). Specifically:

  • `TTXFilter#getEventInTU` start-element switch only branches on `ut`, `Tu`, `Tuv`, `df`; everything else falls through to `appendCode` as a placeholder, including `Seg`.
  • `TTXFilter#processTU` only flushes a TextUnit when `` or `` is reached, treating intervening `` boundaries as segment splits inside one TextUnit.

This is consistent with the upstream `TTXFilterTest` corpus — none of the 55 `@Test` methods use `` wrappers. Trados Studio output, however, does. If the upstream behavior is intentional and it's the Trados Studio shape that should adapt, then the resolution is to update the native reader to ALSO accept the no-`` shape and to mirror the multi-segment TextUnit shape — at which point the spec examples can flip to that shape too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions