AI for Translation & Localization
Capable · M9 · lesson 9 of 21 · queued
Preview — browse every lesson free. Enroll to mark lessons complete, open partner links and save your progress. Login & enroll →
Handling Placeholders, Tags, and Length
📖
now learning

Handling Placeholders, Tags, and Length

15 min

The ticket came in at 4:40 on a Friday, flagged red, with a screenshot attached and a subject line in all capitals: CHECKOUT BUTTON BROKEN IN GERMAN, BLOCKING RELEASE. Beatriz, a post-editor on a retail account who had spent the week clearing an MT-first batch of UI strings, opened it expecting a mistranslation. Instead she found something stranger. The German build would not compile at all, and the error pointed at one string she had post-edited two hours earlier: the order-confirmation line that, in English, read You will be charged {amount} on {date}. She pulled up her delivered target and read it. The German was excellent. It was natural, it was correctly cased, a native speaker would not blink. And it said Ihnen werden {Betrag} am {Datum} berechnet. She had translated the words inside the curly braces. The engine had drafted it that way, fluent and confident, she had read it for meaning, the meaning was perfect, and she had confirmed it. The build looked for a value called amount, found a slot named Betrag instead, found nothing to fill it, and died. Two hours of clean German, and the one thing she got wrong was the one thing that was never language at all. This lesson is about that wound: how an engine breaks the code, the markup, and the size limits hiding inside a string, why your eye cannot catch it, and the concrete checks and prompts that stop it before a build goes red on a Friday night.

The String Has a Skeleton You Cannot Translate

A translator is trained to look at a unit of text and ask: what does this mean, and how do I say it naturally in the target? That instinct is correct for prose and dangerous for software. The thing on your screen in the CAT tool (computer-assisted translation tool, the editor where you post-edit segment by segment) is not always a sentence. Often it is a string: a single unit of text the software stores under a key and drops into the running interface. And a string can carry, riding inside it, three kinds of cargo that are not language and must never be treated as language.

The first is the placeholder: a token the program replaces at runtime with a real value. {amount}, %s, {0}, {name} are placeholders. The running program looks for that exact token, swaps in a live value (a price, a username, a count), and shows the result. The placeholder is an instruction to the code, spelled in a way the code recognizes, and the code recognizes it by exact characters, not by meaning. The second is the tag: a piece of inline markup, most often HTML or XML, that formats or links part of the text. <b>...</b> makes text bold, <a href="...">...</a> makes it a link. The tag is structure, and it must stay balanced and wrap the right words. The third is the length budget: the maximum number of characters, or the pixel width, the string is allowed to occupy in the interface, because it lives in a box of a fixed size and the box does not grow to fit your translation.

Here is the conceptual leap that decides whether you ship clean files or ship build breaks. The meaning of a string is your domain. The skeleton of a string, the placeholders, the tags, the size limit, is not a translation problem at all. It is a structural contract between the string and the program, and that contract is satisfied by exact characters and exact counts, not by good language. You can produce the most faithful, natural, beautifully cased German on earth, and if you changed one character inside a placeholder, the contract is broken and the program crashes. The two properties are independent. Good prose tells you nothing about whether the skeleton survived.

A string is a sentence wearing a skeleton. Translate the sentence; never touch the skeleton. The engine cannot tell them apart, and your eye, trained on meaning, slides right past the broken bone.

Why the Engine Breaks It, and Why You Confirm It

To understand the fix you have to understand the failure, and the failure starts with what a machine-translation (MT) engine, any system that turns source text into target text without a human writing the words, and a large language model (LLM), a general text predictor that translates as a byproduct of guessing plausible next words, are actually built to do. They are built to produce fluent target-language prose. They treat their entire input as language to be re-expressed. A placeholder like {firstName} does not arrive at the engine wearing a label that says "I am code, leave me alone." It arrives as a run of characters that, to a prose machine, looks exactly like a slightly unusual English word. And the engine has seen, somewhere in its training, text where someone translated something that looked like that. So it does the thing it always does: it renders the input in the target language. {firstName} becomes {Vorname} in German, {prenom} in French, {ad} in Turkish, fluently, confidently, and fatally.

Then the second half of the failure happens, and it is the half this lesson is really about, because it is the half you control. The post-editor reads the segment. They are reading for meaning and tone, because that is what post-editing is, and the meaning and tone are flawless. The placeholder corruption sits in a layer below meaning, in the contract with the program, a layer the meaning-reader is not scanning. So they confirm it. Beatriz is not careless. She is doing exactly the job post-editing asks of her, reading the target as language, and the trap is that the wound is not in the language. This is why placeholder, tag, and length protection can never be left to "read it carefully." Careful reading is a meaning check. The skeleton needs a structure check, a different act, performed against the source structure, often by a machine, because a machine is better than your eye at comparing two sets of tokens for an exact match.

Placeholders: The Token That Must Arrive Untouched

Placeholders are the most common and most catastrophic of the three, so we dig in here first and hardest. The rule is brutally simple and worth memorizing in exactly these words: every placeholder in the source must appear in the target, spelled identically, with nothing added and nothing removed. Same tokens, same count, same characters inside. The order in which they appear in the sentence may change, and often must change, because target grammar reorders the words around them. But the tokens themselves are frozen.

The trouble is that placeholders come in a zoo of notations, and you will meet several in a single project. Knowing the family on sight is half the defense, because you cannot protect a token you do not recognize as a token:

  • Named curly-brace placeholders: {name}, {amount}, {orderTotal}. Standard in modern frameworks and in the ICU message format. The text inside the braces is a key the code looks up. It is never translated, never re-cased, never re-spaced.
  • printf-style format specifiers: %s for a string value, %d for an integer, %f for a float, and positional forms like %1$s and %2$d. Decades old, still everywhere in C, Java, Python, PHP, and iOS/Android resources. A space inserted into %s or a translated letter is a crash or garbage output.
  • Positional index placeholders: {0}, {1}, {2}, used by Java's MessageFormat, .NET, and many resource systems. The number is the argument index. The words around it may reorder freely; the index must point at the same value it pointed at in the source.
  • Template and double-brace syntaxes: {{name}} in templating engines like Handlebars or Mustache, $variable and ${variable} in shell and many config formats, %(name)s in older Python. Each ecosystem has its own dialect, and each one is a live wire that translates into a crash.

Now the catalogue of how an engine breaks them, because naming the failure mode is what lets a QA check exist for it.

The Four Placeholder Failures

Failure one: translating the token. The engine renders the contents of the placeholder in the target language. {firstName} to {Vorname}, {count} to {compte}. This is Beatriz's failure. The placeholder no longer matches the key the code expects, the lookup fails, and depending on the framework the program either crashes or silently shows an empty slot where a value should be. It is the most common single defect in MT-first UI work, and it is the most invisible, because the translated token reads as a responsible, even thoughtful, localization of a variable name.

Failure two: mangling the syntax. The engine leaves the meaning of the token alone but alters the punctuation that makes it valid. %s becomes % s because the engine "tidied" the spacing. {0} becomes ( 0 ) or {0} with full-width braces from a CJK keyboard model. ${name} loses its dollar sign. The token is recognizable to a human but not to the parser, which needs the exact bytes. This failure loves languages whose typography differs from the source, because the engine helpfully applies target-typographic conventions to characters that are not typography at all.

Failure three: dropping or duplicating. The engine, smoothing the sentence, decides a placeholder is redundant and omits it, or repeats it. A source string with {startDate} and {endDate} comes back with {startDate} twice and {endDate} gone. The sentence is fluent. At runtime one date is missing and the other is duplicated, and a user sees "valid from March 3 to March 3."

Failure four: swapping positional indices. This is the quiet, expensive one. A string with {0} and {1} is legitimately reordered for target grammar, which is correct, but the engine puts the wrong index in the wrong slot. "Transfer {0} to {1}" (transfer the amount to the recipient) becomes the grammatically perfect target equivalent of "transfer {1} to {0}", which now reads "transfer the recipient to the amount." Every placeholder is present. The count matches. A naive check passes it. And the money goes the wrong way. This is the failure that proves a present-and-counted check is not enough; the indices have to be reasoned about against the source meaning, which is where the human comes back in.

A placeholder check that only confirms the same tokens are present will pass a string where the engine swapped which value goes in which slot. Presence is necessary and not sufficient. For positional indices, you still have to read.

The Defense: Lock, Then Verify

The defense against placeholder corruption has two layers, and a mature pipeline runs both. The first is to prevent the engine from touching the placeholder at all. Good CAT tools and TMS (translation-management system, the platform that moves files through the localization process) parse the string before translation, recognize the placeholders, and convert them into locked, non-editable inline elements, often shown as little numbered chips you can move but cannot edit or delete. When the placeholder is a locked chip, the engine and the post-editor physically cannot retype its contents; they can only place it. This kills failures one, two, and most of three by construction. It is the single highest-leverage setting in the whole subject, and the first thing to confirm is on before a batch starts: are placeholders protected as locked tags, or are they raw editable text the engine can rewrite?

The second layer is verification, because locking is not always available, not always correct, and never covers index swaps. The verification is a placeholder QA check, an automated rule that extracts the set of placeholders from the source segment and the set from the target segment and flags any segment where the two sets do not match exactly. It is mechanical, it does not get tired at 4:40 on a Friday, and it catches what your meaning-reading eye cannot. Every serious CAT tool ships one (Trados, memoQ, Xbench, and the open checks in many TMS platforms all have a tag/placeholder verification). Turning it on, and not delivering a file with unresolved placeholder warnings, is non-negotiable. The one thing it does not catch is failure four, the index swap, because both indices are present and the set matches. For that, the human reads the positional string against the source meaning, deliberately, as a named step. Lock what you can, verify the rest by machine, and reason about indices by hand.

ICU Plurals: A Tiny Program Inside the String

If the bare placeholder is the common fracture, the ICU plural is the one that humbles people who thought they had the problem solved. English is lazy about number: one thing or many, two forms, "1 file" and "2 files." Most languages are not. Russian inflects differently for one, for two-to-four, and for five-and-up. Arabic has six number categories. Polish, Welsh, Lithuanian, and Irish each cut the number line their own way. So a string like "You have {count} new messages" cannot be one fixed sentence in those languages, because the correct word depends on the runtime value of count, which nobody knows until the program runs.

The industry's answer is the ICU message format. ICU stands for International Components for Unicode; its message format is a small structured syntax embedded inside a string that holds every plural form a language needs and selects the right one at runtime from the number. It looks like this:

  • {count, plural, one {You have # new message} other {You have # new messages}}

Read that carefully, because almost none of it is translatable prose. The {count, plural, ...} wrapper is machinery: it tells the system to branch on the value of count. The words one and other are plural categories, fixed keywords from the Unicode plural rules, not the English words "one" and "other." English uses two categories, one and other. Russian uses four: one, few, many, other. Japanese uses one, just other, because it does not inflect for number. The # is a special placeholder that prints the number itself. The only language in that whole string is the text inside each pair of inner braces: "You have # new message" and "You have # new messages." Everything else is code.

Hand that to an engine optimizing for fluent sentences and the failures are spectacular. It may translate the keyword one into the target word for the numeral one, destroying the category selector so the system can no longer match a branch. It may collapse the branches into a single smooth sentence, because the repetition looks like clumsy redundancy to a prose machine, deleting the very branching the language requires. It may supply the wrong number of categories, producing a Russian plural with only one and other when Russian needs four, so most numbers render in the wrong grammatical form. It may break the # or the braces and take down the parser entirely. And in every case, if you read just one branch, the prose looks fine. The post-editor approves a fluent fragment and ships a string that compiles into "5 сообщение" where Russian grammar demands "5 сообщений," a glaring error to every native speaker and an invisible one to a reviewer reading a single branch in isolation.

The ICU Defense Is Structural

You do not defend ICU by being vigilant. You defend it by structure. The right tool parses the message before translation and knows exactly which spans are machinery (the {count, plural, wrapper, the category keywords, the #, the braces) and which spans are the translatable text inside each branch. It locks the machinery and exposes only the prose. It supplies the correct set of categories for the target language from the Unicode plural rules, so a Russian project automatically gets four branches to fill and a Japanese project gets one. The post-editor never edits the structure; they fill in the words for each branch that the structure hands them. When you must work an ICU string by hand, the discipline is the same: identify the machinery, treat it as frozen, translate only the prose inside each branch, and confirm the category set matches what the target language actually requires. If your tool is handing you a raw ICU string as editable text, that is a warning, not a convenience.

Tags: The Markup That Must Stay Balanced

The third kind of cargo is the tag, inline markup inside a string that controls formatting or links. The most familiar are HTML and XML tags. Consider Read our <a href="/terms">terms of service</a> before continuing. This string has a translatable part, "Read our terms of service before continuing," and a tag pair: the opening <a> with its href attribute and the closing </a>. The tags must wrap the correct words in the target, and here is the subtlety that makes this a translation problem and not just a copy-paste problem: in many target languages, "terms of service" will not sit in the same position it occupies in English. It might move to the front of the sentence or the middle. The tags have to move with it, still correctly paired, still wrapping exactly the right span. That movement is legitimate, necessary work, and it is precisely the kind of thing a careful human does right and a careless engine does wrong.

The tag failures rhyme with the placeholder failures. The engine may translate the tag name or attribute, turning href into a target word or <b> into something that is no longer valid markup. It may break the pairing: an opening tag with no closing tag, or two opens and one close, so the markup is malformed and the page's rendering collapses, often dragging the formatting of everything after it into the broken link. It may strip the tags entirely because they looked like noise interrupting the prose, leaving the words but losing the link and the bold. It may cross the nesting, opening a bold span inside a link and closing the link before the bold, so neither closes cleanly and the browser guesses. As with placeholders, you do not fix this by reading for meaning. You fix it by treating tags as locked, paired inline elements the engine must carry through intact, and by a tag QA check that verifies the target has the same tags as the source, correctly paired and balanced. The check counts opens and closes, matches tag types, and flags any imbalance. It is the same mechanical discipline as the placeholder check, applied to a different kind of token, and it belongs in the same non-negotiable QA pass before delivery.

Placeholders and tags are both instructions wearing the costume of words. Lock them so the engine cannot edit them, verify them by machine so a tired eye cannot miss them, and never confuse "the prose is good" with "the structure survived."

Length: The Pixel Budget the Engine Cannot See

Now the third cargo, and the one that breaks the interface even when every placeholder and tag is perfect: length. A string lives in a box. A button, a menu item, a label, a notification, a column header all have a fixed amount of room, measured in characters or in pixels, and that room is the character budget: the maximum length the string is allowed to occupy before it overflows, truncates, or wraps in a way the layout never planned for. The box does not stretch to fit your translation. Your translation has to fit the box.

The governing fact is that text expands when it leaves English, and it expands most exactly where there is least room. German stacks several English words into one long compound noun; a "settings synchronization status" can become a single forty-character German word. Finnish, agglutinative with long case endings, expands dramatically. Russian and the Romance languages run reliably longer. The planning figures localization engineers carry: long passages grow by around 30%, but short strings, the buttons and labels that matter most, can grow by well over 100%, sometimes 200%, because a one-word English button becomes a three-word target phrase and there is no room for three words on a button sized for one.

The engine makes this both worse and more fixable. Worse, because an engine optimizing for natural, fluent prose is not optimizing for brevity; it produces the most natural rendering, which is frequently the longest, with zero awareness that the string lives in a 96-pixel button. The engine does not know the budget exists. More fixable, because the same engine, and the same post-editor, can be told the budget and asked to honor it, choosing a shorter synonym, an accepted abbreviation, or a restructured phrase that conveys the meaning in fewer characters. The judgment about whether the shortened rendering is still faithful and still natural is yours; the budget is the engineer's, attached to the string from the UI specification. Neither of you can do it without the other, and the engine can only respect a constraint it has been told about. When the budget is overrun, the interface does one of several ugly things: it truncates, chopping "Synchronize now" into "Synchronize..." and hiding the verb; it wraps onto a second line the layout never expected, shoving everything below it down; it overflows and overlaps the neighboring element into an unreadable smear; or in a fixed-width layout it spawns a horizontal scrollbar on a screen that should never have one. A pipeline that never tells the translation step the pixel budget is a pipeline that discovers expansion failures in screenshots after the build, which is the most expensive place to find them.

Working a Length Constraint by Hand

When a string carries a maximum-length attribute, you treat it as a hard wall, not a suggestion. The faithful translation that runs three characters over the budget is not acceptable; it will truncate or overflow, and a truncated word that hides the meaning is a worse failure than a slightly less elegant phrasing that fits. The craft is to compress without lying: drop a redundant word, use the standard abbreviation the target market actually recognizes (not one you invented), restructure so a long compound becomes a shorter construction, choose the shorter of two true synonyms. What you may not do is cut meaning that matters or invent an abbreviation the user will not parse. The length check is mechanical, a count against the budget, and your tool should flag every segment over its limit. The repair is human judgment inside that mechanical wall.

A Worked Example: From Red Build to Clean Delivery

Return to Beatriz on Friday night, because the fix is as instructive as the failure, and walking it slowly is the point of the whole lesson. The build is red. The compiler error names the German order-confirmation string. She opens it side by side with the source.

Source: You will be charged {amount} on {date}.
Her delivered target: Ihnen werden {Betrag} am {Datum} berechnet.

The diagnosis takes ten seconds once she looks at the skeleton instead of the meaning. The source has two placeholders, {amount} and {date}. Her target has two placeholders too, so a naive count matches, which is exactly why nothing screamed. But the tokens are wrong: she has {Betrag} and {Datum}, the German words for amount and date, where the code expects the literal keys amount and date. This is failure one, translating the token, and she committed it because the engine drafted it that way and she read the segment for meaning, where it was flawless. The fix is to restore the exact source tokens while keeping the German word order she correctly chose:

Corrected target: Ihnen werden {amount} am {date} berechnet.

The German is still natural, the placeholders now match the keys the code looks for, the build goes green. But Beatriz does not stop there, because one corrupted string in a delivered batch means the batch was never verified for skeleton integrity at all, and a single Friday is not how she wants to find the rest. She runs the placeholder QA check across the entire batch and finds two more: a notification string where the engine dropped a %s entirely (failure three), and a settings line where {0} and {1} had been reordered for German grammar but the indices swapped, so the string would have shown the new value where the old one belonged (failure four, the one the count-based check would have passed if she had not also read the positional strings against the source). She fixes all three. Then she does the thing that prevents the next Friday: she confirms placeholder locking was off for this project, which is why the engine could rewrite the tokens at all, and she files to have it turned on, converting every placeholder to a locked chip the engine cannot edit. The corrective action is not "be more careful." It is "make the failure structurally impossible, and verify the rest by machine."

The Prompt That Would Have Prevented It

Beatriz post-edits MT output, but a growing share of this work is done by prompting an LLM directly, and the prompt is where you install the defense before the draft exists. A generic "translate this to German" invites every failure in this lesson. A disciplined prompt names the skeleton explicitly and forbids touching it. The levers that matter:

  • Identify and freeze placeholders: "The text contains placeholders in curly braces and printf format. Reproduce every placeholder exactly as written, character for character. Do not translate, re-case, re-space, add, remove, or reorder the contents of any placeholder." Naming the notations and the exact prohibition closes failures one through three.
  • Preserve tags and pairing: "Inline HTML tags must appear in the target with the same tag names and attributes, correctly paired and balanced, wrapping the corresponding translated words. Never translate a tag name or attribute." This closes the tag failures.
  • State the length budget: "This string must not exceed 18 characters. If a faithful translation does not fit, use a recognized abbreviation or a shorter synonym, and tell me what you cut." Giving the engine the budget is the only way it can respect it, and asking it to report the cut keeps your judgment in the loop.
  • Demand a flag, not a guess: "If you cannot satisfy any of these constraints, do not produce a translation that violates them. Flag the segment and explain the conflict." This converts a silent break into a visible question, which is the entire game.

The prompt does not replace the QA check; it reduces how often the check has to catch something. The order is always the same: constrain the engine before the draft, verify the structure by machine after the draft, and reason by hand about the two things machines miss, positional index swaps and whether a shortened string still says what the source meant. Belt, suspenders, and a human who reads the source.

The QA Stack That Catches Skeleton Errors

Pull the individual defenses into the order you actually run them, because the value is in the sequence, not any single check. A skeleton-safe delivery is the product of a small stack of controls whose gaps do not overlap, run every time, on every file, by design rather than by vigilance.

  • Before the draft: lock the structure. Confirm placeholders, ICU machinery, and tags are parsed and protected as locked inline elements, not editable text. If you are prompting an LLM instead, install the constraints in the prompt. This is prevention, and it is worth more than every downstream check combined because it removes the failure rather than catching it.
  • After the draft, by machine: the placeholder and tag check. An automated rule that compares the set of placeholders and the set of tags in source and target and flags every mismatch in count, spelling, or pairing. Mechanical, tireless, and exactly suited to the comparison your meaning-reading eye is worst at. Do not deliver a file with open placeholder or tag warnings.
  • After the draft, by machine: the length check. A count of each string against its character or pixel budget, flagging every overrun. Cheap to run, and it moves expansion failures from post-build screenshots to pre-delivery flags.
  • After the draft, by machine: ICU and encoding validation. A parse of every ICU message to confirm it still compiles and has the right category set for the target language, plus an encoding check that the file is valid UTF-8 with no mojibake (the garbled characters that appear when bytes are read in the wrong encoding) and no silently substituted look-alike characters.
  • By hand, deliberately: the two checks machines miss. Read every positional-index string against the source meaning to catch a swap that the count passed. Read every length-shortened string to confirm the compression did not cut meaning that matters. These are the named human steps, small in number and high in consequence, that a present-and-counted check cannot perform.

Notice the shape, because it is the shape of this entire program applied to a new layer. You do not trust the fluent surface. You verify the structure against the source, mostly by machine because a machine compares tokens better than a tired human, and you reserve human judgment for the two things that require understanding the meaning, not just matching the characters. The engine guarantees neither meaning nor structure and reads as if it guaranteed both. The stack is how you make the guarantee yourself.

Why This Skill Pays

It is tempting to file placeholder and length discipline under "tedious housekeeping," and that is exactly the framing that gets a build broken on a Friday. Reframe it. As MT-first pipelines push more strings through the system faster, the number of places a fluent draft can silently snap a placeholder, unbalance a tag, or blow a budget goes up, not down. The post-editor who knows the four placeholder failures on sight, runs the QA stack as reflex, writes the constraining prompt, and reads the positional strings by hand is the one whose files compile, whose UI fits, and whose name on a delivery means the skeleton survived. That is not housekeeping. It is the difference between a linguist who hands the client a clean build and one who hands them a 4:40-on-Friday emergency, and in an MT-first shop it is one of the most concrete, demonstrable forms of "I own the quality the engine cannot." The engine drafts the meaning. You guarantee the program can run it, the layout can hold it, and the key the code looks for is still spelled exactly the way the code expects.

Key Takeaways

  • A string is a sentence wearing a skeleton: placeholders, tags, and a length budget that are not language and must never be translated. Good prose tells you nothing about whether the skeleton survived, because meaning and structure are independent properties verified by different acts. An MT or LLM engine optimizes for fluent prose and rewrites the skeleton, and a post-editor reading for meaning confirms the break without seeing it.
  • A placeholder is a token like {amount}, %s, or {0} that the program swaps for a real value at runtime, recognized by exact characters, not meaning. The rule: every source placeholder must appear in the target spelled identically, same count, nothing added or removed. Recognize the families (named braces, printf, positional, template) on sight, because you cannot protect a token you do not recognize.
  • The four placeholder failures are translating the token ({firstName} to {Vorname}), mangling the syntax (%s to % s), dropping or duplicating, and swapping positional indices so the right values land in the wrong slots. A count-based check catches the first three; it passes the index swap, which is why positional strings must still be read by hand against the source meaning.
  • ICU message format embeds a tiny program in the string to pick the right plural form at runtime using Unicode categories (one, few, many, other), and only the prose inside each branch is translatable. Engines break it by translating the category keyword, collapsing the branches, supplying the wrong category count for the target language, or mangling the # and braces. Defend it structurally: lock the machinery, expose only the branch prose, supply the correct categories from the Unicode rules.
  • Tags are inline markup like the HTML anchor pair that must move with the words they wrap, stay paired, and stay balanced. Engines translate tag names, break pairing, strip tags, or cross the nesting. Lock tags as non-editable inline elements and run a tag QA check that matches and balances source and target tags by machine, the same discipline as placeholders applied to a different token.
  • Text expands out of English, around 30% on long passages and well over 100% on short buttons and labels, with German compounds and Finnish agglutination as worst cases. The engine produces the most fluent rendering, not the shortest, and cannot honor a character budget it was never told about. State the budget, treat it as a hard wall, and compress without cutting meaning or inventing abbreviations the user cannot parse.
  • The prompt is where you install the defense before the draft: name and freeze the placeholders character for character, preserve tag names and pairing, state the length budget and ask the engine to report any cut, and demand a flag instead of a constraint-violating guess. The prompt reduces how often the QA check has to catch something; it does not replace it.
  • Run the stack in order, every file, by design: lock the structure before the draft, then by machine run the placeholder and tag check, the length check, and ICU/encoding validation, then by hand read positional-index strings and length-shortened strings, the two things a count-based check cannot judge. As MT-first pipelines push more strings faster, the linguist who runs this stack as reflex is the one whose builds compile and whose deliveries mean the skeleton survived.