AI for Translation & Localization
Capable · M19 · lesson 19 of 21 · queued
Preview — browse every lesson free. Enroll to mark lessons complete, open partner links and save your progress. Login & enroll →
Structured Output for CAT and TMS
📖
now learning

Structured Output for CAT and TMS

15 min

The file came back from the linguist at 4:40 on a Friday, and the project manager did what she always did: she dragged it into the translation-management system and clicked import. She expected the same green progress bar she had seen ten thousand times. Instead she got a red wall of errors. "Segment count mismatch: source 412, target 397." "Tag validation failed on 38 segments." "Unrecognized record at line 1,204." The translations themselves were excellent. The linguist had used an LLM to draft, post-edited every segment against the source, caught two flipped numbers, fixed a dropped negation, and the prose was clean. None of that mattered, because the thing she handed over was not a file the system could read. It was a beautiful wall of text the engine had emitted as a chat reply: numbered segments, helpful headers, a friendly "Here are your translations!" at the top, three segments accidentally merged into one because the model thought they read better joined, and inline tags rewritten into pretty Unicode arrows that no longer matched anything. The meaning was right. The structure was unusable. And the PM now had ninety minutes of manual cleanup ahead of her, on a Friday, to turn an excellent translation into something the TMS would actually accept. This lesson is about that exact gap: the difference between an AI output that is correct and an AI output that imports, and the discipline that closes it.

The File the Machine Actually Has to Read

To understand why free-form AI output breaks, you first have to understand what the receiving system is and what it expects. A CAT tool (computer-assisted translation tool, the software a linguist actually works in, where source and target sit side by side segment by segment) and a TMS (translation-management system, the platform that routes files, assigns linguists, tracks status, and stores the translation memory and termbase across a whole organization) are not reading your translation the way a human reader does. They are not reading for meaning at all. They are parsing a data structure, and they will accept exactly the structure they were built to accept and reject everything else, no matter how good the words inside it are.

The unit that matters here is the segment. A segment is the atomic chunk a CAT tool splits text into for translation, usually a sentence, sometimes a heading, a list item, or a cell, defined by the tool's segmentation rules. Every segment carries a segment id, a stable identifier (a number, a code, a string like tu-0412) that ties one specific source unit to its one specific translation. The segment id is the spine of the entire system. It is how the TMS knows that your target for segment 412 belongs to source 412 and not to 411 or 413. It is how the translation memory stores the pair so it can be leveraged later. It is how a reviewer's comment lands on the right line, how a status flag marks one unit done, how a build pulls the right string into the right slot. Lose the segment id, or break the one-to-one alignment between source segments and target segments, and you have not produced a slightly messy file. You have produced a file the system literally cannot reassemble.

This is the conceptual leap a linguist coming from a chat interface has to make. When you ask a chatbot to translate a paragraph and it hands you back fluent target text, you read it and you are satisfied, because you are the consumer and your eye does the reassembly. But the TMS is the consumer here, and it does not have an eye. It has a parser. It expects records, each one keyed to a segment id, each one carrying a target that aligns exactly to its source, each one preserving every structural element the source segment held. It is closer to a database import than a piece of writing, and a database import that is "mostly right" is not partially accepted. It is rejected.

The TMS does not read your translation for meaning. It parses your file for structure. A perfect translation in the wrong structure is, to the system, a broken file.

Why Chat-Shaped Output Is the Wrong Shape

An LLM (large language model, a general-purpose text predictor that produces translation as a side effect of predicting plausible next words) is trained, by default, to be a helpful conversational partner. Left to its instincts it produces chat-shaped output, and chat-shaped output is structurally hostile to a TMS in a dozen small ways at once. It adds a preamble: "Sure! Here are the translations for your segments:" which is not a segment and breaks the parse at line one. It adds commentary: "Note: I translated segment 7 more freely because the literal version sounded awkward," which the parser does not know how to file. It renumbers: it drops segments it thought were redundant, or splits one long source segment into two target sentences because two sentences read better, silently destroying the one-to-one alignment. It reformats: it turns a plain segment into a Markdown bullet, wraps things in code fences, helpfully bolds what it considers the key term. Every one of these is the model being a good conversationalist, and every one of them is a structural defect from the TMS's point of view. The model is optimizing to please a reader. The TMS is not a reader. It is a machine that needs a contract honored exactly.

The Three Things the Output Must Carry

If chat-shaped output is the wrong shape, what is the right one? Structured output for a CAT tool or TMS has to carry three things faithfully, and a failure in any one of them is enough to break the import. Name them, because the rest of this lesson is about protecting each one in turn.

First, segment alignment. Every source segment must produce exactly one target segment, keyed to the same segment id, in a record the parser can match back to the source. Not more, not fewer, not merged, not split, not reordered. If the source file has 412 segments, the structured output has 412 target records, each one stamped with the source's segment id. This is the non-negotiable backbone. The other two failures cost you cleanup time; this one costs you the whole file, because once alignment is gone the system cannot even tell which translation belongs to which source, and there is no automated way to put them back.

Second, tag preservation. Many segments are not plain text. They carry inline tags and placeholders embedded in the words. An inline tag is a piece of markup inside a segment that controls formatting or holds structure, for example a bold span, a link, or a styled run, and a placeholder is a token the running program replaces with a real value at runtime, like {count} or %s or a user's name. In CAT tools and the interchange formats they use, these inline elements are represented as tags inside the segment, often as numbered tag pairs the tool tracks. The structured output must preserve every one of these tags, in the right place, paired correctly, spelled exactly, because the TMS validates them. If the source segment had three tags and your target has two, or has them in an order the tool considers invalid, the segment fails tag validation and, depending on the setup, the file is rejected or the segment is locked for manual repair.

Third, the record contract. The output has to be in a shape the receiving system can parse without guessing: a known format, with known fields, with nothing extra. Whether that is a clean JSON array, a CSV with fixed columns, or content destined to be wrapped back into an interchange format like XLIFF, the structure has to be strict and predictable. JSON (JavaScript Object Notation, a simple, strict text format of keyed records and lists that machines parse reliably) is the workhorse intermediate format for LLM output precisely because it is strict: a missing comma or an unescaped quote fails the parse loudly and immediately, which is far better than failing silently downstream. XLIFF (XML Localization Interchange File Format, the industry-standard XML file that carries source segments, target segments, segment ids, and inline tags between tools) is frequently the actual file the TMS ingests, and a malformed XLIFF is rejected on import just as a broken JSON is. The point is the same: the container has to be valid and minimal, carrying the segments and nothing the parser did not ask for.

Segment alignment, tag preservation, and a strict record contract. Free-form output breaks all three at once, and each one alone is enough to fail the import.

Getting Segment-Id-Aligned Output

The first and most important discipline is forcing the model to honor segment alignment, and the core technique is simple to state and easy to get wrong: give the model segment ids on the way in and require them on the way out. Do not hand the model a paragraph and ask it to translate. Hand it a structured list of records, each one already carrying its segment id and its source text, and instruct it to return the same structure with a target added to each record, the ids unchanged. You are not asking the model to invent structure. You are asking it to fill in a structure you supplied. That distinction is the whole game.

Concretely, the input you give the model looks like a list of records, for example a JSON array where each element has a segment_id and a source. The instruction tells the model to return a JSON array of the same length, each element carrying the same segment_id and an added target field, in the same order, with no segments added, dropped, merged, or split, and with nothing outside the array, no preamble, no commentary, no code fence. When the output comes back, the segment ids are the verification handle: you can check, mechanically, that the set of ids in equals the set of ids out, that the count matches, that no id is missing and none is invented. The id turns "did the model keep the segments aligned?" from a judgment call into a check a script runs in a millisecond.

Why the Id Must Come From You, Not the Model

A tempting shortcut is to let the model number the segments itself: "translate these and number each one." Do not. A model that generates its own numbering will renumber when it merges or splits, and the numbers will look perfectly sequential and orderly while no longer corresponding to the source's actual segments. The id has to be data you own, supplied by you, echoed back by the model, never minted by the model, because the entire value of the id is that it is a fixed reference to a source segment that exists in your system. An id the model invented references nothing. When the model echoes an id you supplied, a mismatch is detectable. When the model invents an id, a mismatch is invisible, because there is no source of truth to compare against. This is the same principle that runs through the whole program: you do not trust the fluent surface, you verify it against a source you control.

The Instructions That Actually Hold

Forcing alignment in practice comes down to a handful of explicit instructions in the prompt or system prompt, each one closing a specific failure mode you have now seen:

  • Return only the structure, nothing else. No greeting, no "here are your translations," no trailing notes, no Markdown, no code fence. The first character of the output is the opening bracket of the array and the last is its close. This kills the preamble-and-commentary failure that breaks the parse at line one.
  • One target per source, same id, same order, same count. State that the output array must have exactly as many elements as the input, that each element keeps its supplied id, and that the model must never merge two source segments into one target or split one into two. This kills the alignment-destroying merge and split.
  • If a segment cannot be translated, return it with a flag, never drop it. Give the model a way to say "I am unsure" or "this is empty" inside the structure (a field, a marker) so that its uncertainty becomes a record you can route, not a missing segment that silently shrinks the count. A dropped segment is the worst outcome because it is the hardest to notice.
  • Echo the source back alongside the target. Having the model return the source it translated, unchanged, next to its target gives you a second alignment check: you can confirm the source field still matches the source you sent for that id, catching the case where the model quietly shifted content between records.

None of these instructions improve the translation. Every one of them protects the structure, and that is the point. The quality of the words is a separate problem, solved by source-fidelity prompting and post-editing, covered elsewhere in this program. Structured output is the discipline that ensures the good words arrive in a container the system can open.

Preserving Inline Tags and Placeholders in Structured Form

Segment alignment gets the right translation onto the right line. Tag preservation keeps that line from failing validation once it is there. This is the second discipline, and it is where structured output and the format-failure problem meet, because the structure now has to carry not just text but the machinery embedded in the text.

Start with what the tags are in interchange terms. When a CAT tool exports a segment that contained, say, a bold word and a link, it does not export the raw HTML. It represents the formatting as inline tags inside the segment, frequently as numbered placeholder tags so the tool can track each one and validate that the target has the same set. A source segment might arrive as something like Click <g id="1">here</g> to confirm your <g id="2">{count}</g> items, where <g id="1"> and <g id="2"> are inline tags the tool will check for, and {count} is a placeholder the program fills at runtime. The translated target must contain the same two tags, correctly paired, wrapping the right words in the target's word order, and the same {count} placeholder spelled exactly. If the target moves the link to a different position because the target language puts it there naturally, that is fine and often necessary, as long as the tags move with it intact.

Now the danger. A model producing fluent prose treats tags and placeholders as either words to translate or noise to clean up, and both instincts corrupt the structure. It may translate the placeholder token, turning {count} into {cuenta}, which reads sensibly and crashes the program. It may strip a tag it considered clutter, leaving the words but losing the bold or the link and unbalancing the markup. It may rewrite the tag into something prettier, turning <g id="1"> into a Unicode styling it inferred, which no longer matches anything the tool tracks. It may duplicate a tag, or close one it never opened, or nest two so they cross. Every one of these passes a meaning read, because the words are fine, and fails tag validation, because the structure is not.

The Locked-Placeholder Technique

The defense, as everywhere in this layer, is structural rather than vigilant. You do not ask the model nicely to preserve the tags and then hope. You make preserving them the path of least resistance and verify the result mechanically. Three moves do most of the work:

  • Present tags as opaque, non-translatable tokens and say so. Tell the model explicitly that anything matching the tag pattern (the <g id="..."> form, the curly-brace placeholders, the percent specifiers) is a protected token that must appear in the target unchanged, in spelling and in count, and is never to be translated, altered, or removed. Naming the patterns and the rule turns "please be careful" into a concrete constraint the model can follow.
  • Require the same tag set in, tag set out. Instruct the model that the multiset of tags and placeholders in each target segment must be identical to the multiset in the corresponding source segment, only their position within the target may change. This frames the constraint the way the tool's validator frames it, which is exactly the check the segment has to survive.
  • Keep the tags inside the structured record, not floating in prose. Because each segment is its own record keyed to its id, the tags travel inside that record's source and target fields, scoped to one segment, never bleeding across segment boundaries. A tag that escapes its record is a tag that fails validation, and the per-segment structure is what keeps each tag where it belongs.

After generation, you verify. For each segment id, extract the set of tags and placeholders from the source and from the target, and compare. Equal sets, the segment passes. Unequal, the segment is flagged for repair before it ever reaches the TMS, where it would have failed validation anyway, except now you catch it cheaply at your own desk instead of expensively at import. The check is mechanical and fast, and it is the difference between finding the broken placeholder before you ship and finding it in the PM's red wall of errors.

A placeholder is an instruction to the program wearing the costume of a word, and an inline tag is structure the validator counts. The model translates the costume and drops the count; the per-segment record and the tag-set check are how you stop it.

Validating the Structure Before Import

Here is the habit that separates a linguist who ships clean files from one who generates the PM's Friday afternoon: you validate the structure yourself, before you hand it over, with a check you run every time. The TMS is going to validate it on import regardless. The only question is whether the validation fails at your desk, where a failure costs you five minutes and a regeneration, or at the PM's desk, where it costs ninety minutes of manual cleanup, a missed deadline, and your reputation as the linguist whose files always need rework. Validation before import is not optional polish. It is the entire reason structured output is a discipline and not just a prompt.

A pre-import structural check does not look at the translation quality at all, deliberately. It looks only at the contract, and it asks a fixed series of questions in order. Run them as a checklist, ideally as a script, on every structured output before it leaves your hands:

  • Does it parse at all? Feed the output to a strict parser for its format, a JSON parser, an XML/XLIFF validator. If it does not parse, nothing else matters; the container is broken and the model probably leaked a preamble, a code fence, or an unescaped character. This is the cheapest, first check and it catches the most common failure.
  • Does the segment count match? Count the target records and compare to the source segment count. They must be equal. A mismatch means a segment was dropped, merged, or split, and the alignment is gone.
  • Do the ids match, exactly and completely? Compare the set of segment ids in the output to the set you supplied. Every supplied id present once, no id missing, no id invented. This is the alignment check that the count alone cannot catch, because a model can drop one segment and split another and still land on the right total.
  • Is every target non-empty (or explicitly flagged)? A segment with an empty target that was not deliberately flagged is a silent omission. Catch it here.
  • Do the tags and placeholders balance per segment? For each id, compare the tag-and-placeholder set in source and target. Equal sets pass; unequal sets flag. This is the validation the TMS will run, run first by you.

Only after all five pass is the structure sound enough to import. Notice what this checklist is and is not. It is not a quality check; a file can pass every one of these and still contain a flipped dosage or a dropped negation, which is why source-fidelity post-editing and severity scoring are separate, essential disciplines this program teaches in their own right. The structural check guarantees the file imports cleanly; the linguistic checks guarantee the translation is correct. You need both, in that order, because a correct translation in a broken structure never reaches anyone, and a clean structure full of mistranslations ships a liability smoothly. Structured-output validation is the gate that gets the words to the system; it is not the gate that decides the words are right.

Why the Machine Check Beats the Eyeball

You might think you can eyeball a structured file and see the problems. You cannot, reliably, and the reason is the same reason the silent critical error is dangerous in the prose: the structural defects are invisible to a meaning-reader. A merged pair of segments reads as a perfectly good translation; you have to count to know two became one. A renumbered id looks orderly; you have to compare sets to know it drifted. A translated placeholder reads sensibly; you have to match patterns to know it will crash. A missing segment leaves no gap on the page; the surrounding text flows fine. These are exactly the failures the eye glides over and a parser catches instantly, which is why the validation has to be mechanical. A human reading for sense is the wrong instrument for finding a structural break, just as a human reading for fluency is the wrong instrument for finding a flipped number. In both cases the fix is the same: verify against the source structure with a tool, do not trust the surface.

A Worked Example: TMS-Ready Output, End to End

Bring it together with the file the PM should have received on Friday. A small UI batch, six segments, two of them carrying inline tags and placeholders, going from English into Spanish. Watch the whole arc: the wrong way the model wants to answer, the structured input that constrains it, the structured output that imports, and the validation that proves it.

The Source, and the Free-Form Trap

The source segments, as the CAT tool exported them, with their ids and their inline elements:

  • ui-001: Save changes
  • ui-002: You have <g id="1">{count}</g> unread messages
  • ui-003: Settings
  • ui-004: Click <g id="1">here</g> to learn more
  • ui-005: Your session will expire in %d minutes
  • ui-006: Cancel

Ask a chatbot, in plain conversation, to "translate these UI strings into Spanish," and the helpful free-form reply comes back looking something like: a cheerful intro line, then a numbered list, "1. Guardar cambios, 2. Tienes {cuenta} mensajes no leídos, 3. Ajustes..." with the placeholder translated to {cuenta}, the inline <g> tags silently dropped from segments 2 and 4 because they looked like clutter, segment 5's %d rendered as the word "varios" because the model decided a literal specifier was awkward, and a closing note: "Let me know if you'd like a more formal register!" Every translation is defensible as Spanish. The file is unusable: the ids are gone, the tags are gone, two placeholders are corrupted, and the parser will choke on the intro line before it reaches a single segment.

The Structured Input That Constrains the Model

Now do it the disciplined way. The input handed to the model is itself structured, a JSON array, each record carrying the id and the source exactly as exported, tags and placeholders intact:

  • [{"segment_id":"ui-001","source":"Save changes"},
  • {"segment_id":"ui-002","source":"You have <g id=\"1\">{count}</g> unread messages"},
  • {"segment_id":"ui-003","source":"Settings"},
  • {"segment_id":"ui-004","source":"Click <g id=\"1\">here</g> to learn more"},
  • {"segment_id":"ui-005","source":"Your session will expire in %d minutes"},
  • {"segment_id":"ui-006","source":"Cancel"}]

The instruction is explicit and structural: "Return a JSON array of the same length and the same order. For each element, keep segment_id and source exactly as given and add a target with the Spanish translation. Treat anything matching <g id=\"...\">...</g>, {...}, and %d or %s as a protected token: it must appear in the target unchanged in spelling and count, never translated or removed, and may only change position. Do not merge, split, drop, or add segments. Return only the array, no other text." You have supplied the structure; the model's only job is to fill the target field while honoring the constraints.

The TMS-Ready Output

The structured output that comes back, when the constraints hold, is a file the TMS accepts on the first try:

  • [{"segment_id":"ui-001","source":"Save changes","target":"Guardar cambios"},
  • {"segment_id":"ui-002","source":"You have <g id=\"1\">{count}</g> unread messages","target":"Tienes <g id=\"1\">{count}</g> mensajes sin leer"},
  • {"segment_id":"ui-003","source":"Settings","target":"Ajustes"},
  • {"segment_id":"ui-004","source":"Click <g id=\"1\">here</g> to learn more","target":"Haz clic <g id=\"1\">aquí</g> para obtener más información"},
  • {"segment_id":"ui-005","source":"Your session will expire in %d minutes","target":"Tu sesión expirará en %d minutos"},
  • {"segment_id":"ui-006","source":"Cancel","target":"Cancelar"}]

Read what the structure preserved. Six records in, six records out, same ids, same order: alignment intact. Segment ui-002 keeps its <g id="1"> pair wrapping the unchanged {count} placeholder, now around the Spanish word order. Segment ui-004 moved the link tag to wrap aquí, the natural Spanish position, with the pair intact and balanced, exactly the legitimate reordering tags are supposed to allow. Segment ui-005 carries the %d specifier through untouched. The translations are good Spanish and, just as importantly, they are good Spanish in a structure the parser reads without a single manual fix.

The Validation That Proves It

Before this goes anywhere near the TMS, the five-question structural check runs against it, and watch each one pass. Does it parse? Yes, it is a valid JSON array, no preamble, no code fence, no trailing note. Does the count match? Six source records, six target records, equal. Do the ids match? The set {ui-001 ... ui-006} in equals the set out, each present once, none missing, none invented. Is every target non-empty? Yes, all six carry a target. Do the tags and placeholders balance per segment? Segment ui-002 source has one <g> pair and one {count}; target has the same. Segment ui-004 source has one <g> pair; target has the same. Segment ui-005 source has one %d; target has the same. The other three are plain text with empty tag sets on both sides. Every check passes, so the file is structurally sound and clears for import. The linguist hands the PM a file that imports green on the first click, and the ninety minutes of Friday cleanup never happen.

That is the entire discipline in one arc. The translation quality came from the source-fidelity and post-editing work this program teaches separately. The clean import came from structured output: ids supplied and echoed, tags protected and verified, the record contract held strict, and a mechanical validation run before handoff. Same words, two completely different outcomes, and the only difference is whether the linguist treated the output as a chat reply to a reader or as a data record for a parser.

Why This Discipline Pays

It is worth being honest about why a linguist should care about JSON arrays and tag sets when their craft is language. The answer is that in an MT-first, LLM-assisted shop, the linguist who can deliver structured, import-ready output is worth measurably more than the one who delivers excellent translations that need cleanup, and the gap is widening. Every file that imports green on the first try is a file the PM did not have to repair, a deadline that did not slip, a relationship that did not fray over rework. The throughput gains that make AI-assisted translation economical, the lift from roughly two thousand words a day to five thousand and beyond, evaporate the moment a human has to spend ninety minutes hand-cleaning each delivery to make it importable. Structured output is the discipline that lets the speed survive contact with the system.

There is also a quieter professional truth in it. The linguist who hands over a structured file with the ids aligned, the tags balanced, and a clean validation behind it is making a statement about who owns the quality of the deliverable, the whole deliverable, not just the words. It is the same move as attaching a severity score to a post-edited file or a verification log to a terminology batch: it turns "trust me, it's good" into "here is the proof it is sound." A file that imports cleanly the first time, every time, is a credential. It says the person who produced it understands that in this industry the translation and the structure that carries it are not separable, that a correct translation in a broken container is a failure, and that owning the quality means owning both. The machine drafts fast and breaks structure carelessly. The linguist who guarantees the structure is the one the machine cannot replace, and structured output is one of the most concrete, checkable ways to be that linguist.

Key Takeaways

  • A CAT tool and a TMS do not read your translation for meaning; they parse it for structure. A perfect translation in a chat-shaped reply is, to the system, a broken file, because the parser needs records keyed to segment ids, not prose a human eye reassembles.
  • Structured output must carry three things faithfully: segment alignment (one target per source, same id, same count, none merged or split), tag preservation (every inline tag and placeholder intact, paired, and spelled exactly), and a strict record contract (valid JSON, CSV, or XLIFF with nothing extra). A failure in any one is enough to fail the import.
  • The segment id is the spine. Supply ids on the way in and require them echoed unchanged on the way out; never let the model mint its own numbering, because an id the model invented references nothing and a mismatch becomes invisible. The id turns alignment from a judgment call into a millisecond check.
  • Force alignment with explicit instructions: return only the structure with no preamble or commentary, one target per source in the same order and count, flag untranslatable segments inside the structure instead of dropping them, and echo the source back for a second alignment check.
  • Preserve tags and placeholders by presenting them as opaque, non-translatable, protected tokens that must appear in the target unchanged in spelling and count, requiring the same tag set in and out with only position free to change, and keeping every tag scoped inside its own per-segment record so it cannot bleed across boundaries.
  • Validate the structure yourself before handoff with a fixed five-question check: does it parse, does the segment count match, do the ids match exactly and completely, is every target non-empty or explicitly flagged, and do the tags and placeholders balance per segment. Run it as a script, every time, because the structural defects are invisible to a meaning-reader and instant for a parser.
  • Structural validation is not quality validation. A file can pass every structural check and still hide a flipped dosage or a dropped negation, which is why source-fidelity post-editing and severity scoring remain separate, essential disciplines. The structural gate gets correct words into the system; the linguistic gate decides the words are correct, and you need both, in that order.
  • In an MT-first shop, the linguist who delivers import-ready structured output is worth more than the one who delivers excellent translations that need cleanup. A file that imports green on the first try preserves the throughput that makes AI-assisted translation economical and is a credential that says you own the whole deliverable, the words and the structure that carries them.