AI in Localization Engineering and Media
At 11:58 on a release night, a build went red over a single line of Turkish. The string in the source file read Welcome back, {firstName}! You have {count} new messages. A localization engineer, the person who handles the technical plumbing of internationalization (i18n, the practice of building software so it can be translated at all) and localization (l10n, the act of adapting it to a specific market), watched the continuous-integration log throw a runtime error in the Turkish app. The engine that had drafted the translation had done something fluent and reasonable and completely fatal: it had translated the variable. Where the source had a placeholder, a slot the running program fills in at runtime with a real value, the machine had rendered {firstName} as {ilkAd} because "first name" in Turkish is "ilk ad," and the translation read beautifully. But the program does not speak Turkish. It looks up a token spelled exactly firstName, finds nothing called ilkAd, and crashes. A linguist proofreading the French version would never have caught it, because the French was perfect prose. The thing that was broken was not the meaning. It was the structure. And that is the entire subject of this lesson: in localization engineering and media, the engine that protects the meaning and the engineer who protects the structure are two different jobs, and a confident machine breaks the second one in ways the first one cannot see.
The String Is Not a Sentence
A working translator thinks in sentences. A localization engineer thinks in strings. A string is a single unit of text as the software stores it: a label on a button, a line of a dialog box, a sentence in a user manual, an error message, a single subtitle. To a linguist it looks like language. To the program it is a value pulled from a resource file by a key, dropped into a slot in the running interface, and displayed inside a box that has a fixed number of pixels. The text is only one of its properties. The string also has a length budget, a position in a layout, an encoding, and very often pieces of machinery embedded inside it that are not words at all and must survive translation untouched.
This is the conceptual leap that separates localization engineering from translation, and it is the leap an MT or LLM engine cannot make on its own. A machine-translation (MT) engine, any system that converts source text to target text without a human writing the words, and a large language model (LLM), a general-purpose text predictor that translates as a side effect of predicting plausible next words, are both built to do one thing supremely well: produce fluent target-language prose. They treat their input as language to be re-expressed. But a software string is not pure language. It is language with structural cargo riding inside it, and the engine, optimizing for natural prose, will cheerfully rewrite, reorder, or destroy that cargo because the cargo is invisible to a process that only knows how to make sentences sound good.
Think of it as the difference between a poem and a circuit board with a poem silk-screened onto it. The translator's job is the poem. The engineer's job is everything else on the board: the traces, the connectors, the solder points that have to line up exactly or nothing powers on. When you hand the whole board to a machine that only understands poetry, it will produce a gorgeous new poem and quietly melt three traces doing it. The output reads perfectly. The board is dead.
The linguist protects the meaning. The engineer protects the structure. A confident engine produces beautiful meaning while silently breaking structure the linguist's eye is not trained to see.
Why This Is the Expensive Failure Mode
Format failures are uniquely expensive for a reason that has nothing to do with how hard they are to fix and everything to do with when they are caught. A meaning error, a mistranslation, is caught by a reviewer reading the target language, or worst case by an end user who is confused. A format error is often invisible to every human in the linguistic chain, the translator, the reviewer, the project manager, because they are all reading for meaning, and the meaning is fine. It surfaces at build time as a broken compile, or at runtime as a crash, or in production as a button with no label, a date in the wrong format, a sentence chopped off mid-word by a box that ran out of room. By then the file has shipped through translation, review, and integration, and the cost of the fix has multiplied at every stage it passed through undetected. The cheapest place to catch a broken placeholder is before the engine ever touches the string. The most expensive place is in the app store, in front of users, in a language nobody on the emergency call can read.
Placeholders: The Variable the Engine Must Leave Alone
The pacemaker of localization engineering, the one structural element whose corruption is most common and most catastrophic, is the placeholder. A placeholder is a token inside a string that the program replaces at runtime with a real value: a user's name, a number, a date, a currency amount, a count of items. The string You have {count} unread emails ships to the user as "You have 3 unread emails" because the running program substitutes the live value of count into the slot. The placeholder is not language. It is an instruction to the program, and it must arrive in the translated string spelled exactly as it was in the source, or the substitution fails.
Placeholders come in many notations, and an engine that has seen all of them in training has also seen them translated, which is the root of the danger. Some common forms a localization engineer meets daily:
- Curly-brace named placeholders:
{username},{count},{orderTotal}. Common in modern frameworks and in the ICU message format. The name inside the braces is a token the code looks up, not a word to be translated. - printf-style format specifiers:
%sfor a string,%dfor an integer,%1$sfor a positionally numbered argument. Decades old, still everywhere in C, Java, and older systems. A translated%sis a guaranteed crash or a garbled output. - Positional braces:
{0},{1}, used by Java's MessageFormat and many .NET resources. The number is the argument index, and the order of words around it may legitimately change in translation while the indices must stay correct. - Double-brace and template syntaxes:
{{name}}in templating systems,$variableor${variable}in others. Each framework has its own dialect, and each is a live wire.
Now watch how a fluent engine breaks each one. The simplest failure is the one from the opening: the engine translates the token inside the placeholder, turning {firstName} into {ilkAd} or {prenom}, because to a prose machine "firstName" looks like words and words get translated. The program crashes. A subtler failure is when the engine changes the surrounding syntax: it sees %s, decides the percent sign needs a space, and emits % s, or it helpfully "corrects" {0} to (0) because the braces looked like a typo. A third failure, specific to languages whose word order differs from the source, is dropping or reordering positional placeholders incorrectly: a string with {0} and {1} gets reordered for target-language grammar, which is often legitimate, but the engine swaps which value goes where, so "transfer {0} to {1}" becomes the target equivalent of "transfer the recipient to the amount." The sentence is grammatical. The transfer is backwards.
Why the Linguist Cannot Catch It
Here is the cruelty of the placeholder failure: it is engineered to be invisible to the person most likely to see the file. A reviewer reading the translated Turkish sees {ilkAd} and, if they think about it at all, thinks the translator localized a variable name, which sounds almost responsible. They are reading for meaning and tone, and the meaning and tone are fine. The placeholder corruption lives in a layer below language, in the contract between the string and the program, and that contract is the engineer's domain, not the linguist's. This is why placeholder protection cannot be left to proofreading. It has to be enforced by tooling: by locking the placeholders so the engine and the post-editor physically cannot alter them, and by an automated check that compares the set of placeholders in the source string against the set in the target string and fails the file if they do not match exactly. The discipline is the same one that runs through this whole program: you do not trust the fluent surface, you verify the structure against the source.
A placeholder is an instruction to the program wearing the costume of a word. The engine translates the costume and breaks the instruction, and the meaning-reader never sees the wound.
ICU Plurals: Where Grammar and Code Collide
If the bare placeholder is the common injury, the broken plural is the one that humbles engineers who thought they understood the problem. English has a tidy, lazy notion of plurals: one thing or many things, two forms, "1 message" and "2 messages." Most of the world is not so simple. Russian has different forms for one, for two through four, and for five and up, plus more rules for fractions. Arabic has six plural categories. Polish, Welsh, Irish, and Lithuanian each carve the number line differently. A string that says "You have {count} new messages" cannot be translated as a single sentence into these languages, because the correct word changes depending on the actual value of count, and that value is unknown until runtime.
The industry's answer is the ICU message format. ICU stands for International Components for Unicode, and its message format is a small, structured syntax embedded inside a string that lets one string express all the plural forms a language needs and select the right one at runtime based on the number. A plural message looks like this:
{count, plural, one {You have # new message} other {You have # new messages}}
That is not prose. It is a tiny program. The {count, plural, ...} wrapper tells the system to choose a branch based on the value of count. The keywords one and other are plural categories, not the literal numbers one and other, and which categories a language uses is fixed by the Unicode plural rules: English uses one and other; Russian uses one, few, many, and other; Japanese uses only other because it does not inflect for number. The # is a special placeholder for the number itself. The whole structure is machinery, and only the prose inside each branch is language to be translated.
Now imagine handing that string to an engine that wants to produce fluent sentences. The failure modes are spectacular and varied. The engine may translate the keyword one into the target word for the number one, destroying the category selector so the system cannot match the branch. It may collapse the structure into a single sentence, because to a prose machine the repeated content looks like clumsy redundancy worth smoothing away, deleting the branching the language requires. It may add or remove categories without regard to the Unicode rules, producing a Russian plural with only one and other when Russian needs four, so most numbers display the wrong grammatical form. It may mangle the # or the braces, breaking the parser entirely. And in every case the output, if you read only one branch of it, can look like perfectly good target-language text. The translator who post-edits it sees a fluent sentence and approves it. The string fails to compile, or compiles and then displays "5 сообщение" where Russian grammar demands "5 сообщений," a small, glaring error that tells every native speaker the product was localized by something that does not speak their language.
The Engineer's Defense for ICU
The defense is structural, not vigilant. The string is parsed before translation so the tooling knows exactly which spans are machinery, the {count, plural, wrapper, the category keywords, the #, the braces, and which spans are translatable prose, the text inside each branch. The machinery is locked; only the prose is exposed to the engine and the post-editor. The right number of plural categories for the target language is supplied automatically from the Unicode plural rules, so the target structure is correct by construction and the linguist only fills in the words for each branch. This is the recurring shape of localization engineering: the engine and the human handle the language, and the tooling guarantees the structure, because structure is too easy to break and too invisible to verify by reading.
Tags and Encoding: The Other Cargo
Placeholders and plurals are the headline injuries, but two more kinds of structural cargo ride inside strings and meet the engine daily: tags and encoding.
Tags: Inline Formatting That Must Survive
A tag is a piece of inline markup inside a string that controls formatting or links, most familiarly the HTML tags that make text bold, italic, or clickable. The string Click <a href="/help">here</a> to continue contains a translatable part, "Click here to continue," and a tag pair, the <a> opening tag with its href attribute and the </a> closing tag, that must wrap the correct words in the target. In many languages the word that should be the link is not in the same position as in English; "here" might move to the front or the middle of the target sentence, and the tags must move with it, still correctly paired and still wrapping the right span. This is legitimate, necessary reordering, and it is exactly the kind of thing a good translator does and a careless engine does wrong.
The engine's tag failures echo the placeholder failures. It may translate the attribute or the tag name, turning href into a target word or <a> into something that is no longer valid markup. It may break the pairing, emitting an opening tag with no close or two opens and one close, so the markup is malformed and the rendering collapses, dragging the rest of the page's formatting into the link. It may strip the tags entirely because they looked like noise interrupting the prose, leaving the words but losing the link and the formatting. It may nest them wrongly, crossing a bold span and a link span so neither closes cleanly. As with placeholders, the defense is to protect the tags as locked, non-editable inline elements that the engine must carry through intact and the tooling verifies are balanced and complete in the target, never as free text the engine may reshape.
Encoding: The Bytes Under the Letters
Encoding is the system that maps the characters you see to the bytes a computer stores, and it is the silent foundation under every string. The modern standard, UTF-8, can represent every character in every living script, which is why a correctly engineered pipeline can carry Japanese, Arabic, Cyrillic, emoji, and accented Latin in the same file without trouble. Encoding failures appear when a file is read or written assuming the wrong encoding: the accented or non-Latin characters turn into mojibake, the garbled sequences of question marks, boxes, or nonsense symbols that appear when bytes meant for one encoding are interpreted as another. A French "é" becomes "é," a curly quote becomes a three-character smear, an entire Japanese subtitle file becomes a wall of boxes.
An engine does not usually cause an encoding error on its own; the engine works in characters, not bytes. But the pipeline around it does, at every point a file is imported, exported, or passed between tools, and the localization engineer owns those boundaries. An engine can introduce a subtler relative of the encoding bug: it can swap characters that look right but are technically different, a straight quote for a curly quote, a hyphen for a non-breaking hyphen, a regular space for a non-breaking space, an invisible zero-width character that breaks a search or a hash. These do not crash, but they corrupt downstream matching, search, and string comparison in ways that are maddening to debug because the text looks identical. The discipline is to fix the encoding to UTF-8 end to end and to normalize the characters the engine might silently substitute, so that what the byte sees and what the eye sees are the same thing.
Text Expansion: The Pixel Budget the Engine Blows
Even when every placeholder, plural, tag, and byte is correct, a string can still break the interface for a reason that has nothing to do with code and everything to do with language: it is too long. This is text expansion, and it is the format failure most directly downstream of translation quality, because the engine controls the length of the words it produces.
The rule of thumb every localization engineer carries is that text expands when it leaves English. A short English source string can grow substantially in translation, and the worst offenders are predictable. German is notorious for compound nouns that stack several English words into one very long word; a "settings synchronization status" can become a single forty-character German noun. Finnish, with its agglutinative grammar and long case endings, expands dramatically. Russian and the Romance languages run reliably longer than English. As a planning figure, engineers budget for English strings to grow by anywhere from 30% on long passages to well over 100% or even 200% on the short strings that matter most, the buttons, the labels, the menu items, where a single English word becomes three target words and there is no room for them.
The pixel budget is the trap. A button is sized for "Save." The German is "Speichern," which fits. The Finnish or a longer compound does not, and the interface has no instruction for what to do when the text is too long for the box. Depending on how the UI was built, the overflow does one of several ugly things: the text is truncated, chopped off so "Synchronize settings now" becomes "Synchronize sett...," sometimes hiding the verb that told the user what the button does; or it wraps onto a second line that the layout did not expect, pushing other elements down and breaking the visual design; or it overflows the box and overlaps neighboring elements into an unreadable smear; or, in a fixed-width layout, it forces a horizontal scrollbar onto a screen that should never have one.
Why This Is an AI Problem Now
Text expansion has always existed, but an MT or LLM engine makes it both worse and more tractable. Worse, because an engine optimizing for fluent, natural prose is not optimizing for brevity; it will happily produce the most natural rendering, which is often the longest, with no awareness that the string lives in a 120-pixel button. The engine does not know there is a budget. More tractable, because the same engines can be instructed to honor a length constraint when the tooling tells them one exists. The string can carry a maximum-length attribute, a character or pixel budget the engineer attaches from the UI specification, and the engine or the post-editor is told to produce a rendering that fits, choosing a shorter synonym, an accepted abbreviation, or a restructured phrase. The judgment about whether a shortened rendering is still faithful and still natural is the linguist's; the budget itself is the engineer's. Neither can do it without the other, and the engine can only respect a constraint it is told about. A pipeline that never communicates the pixel budget to the translation step is a pipeline that discovers expansion failures in screenshots after the build, which is the expensive place to discover them.
The engine produces the most fluent rendering, not the shortest. If nobody tells it the button is 120 pixels wide, it will write a sentence that does not fit and call it a job well done.
Subtitling: Translation on a Clock
Media localization adds a dimension that text on a page never has: time. A subtitle is a line of translated text displayed on screen for a measured interval, timed to the speech it represents, and constrained by how fast a human being can actually read. Roughly 70% of language-service providers now offer subtitling, much of it machine-first, which means the engine that mistranslates a placeholder is now also being asked to produce subtitles, and subtitling has its own structural laws the engine knows nothing about. A subtitle is not just a translation. It is a translation that must fit in a box, appear and disappear at the right instant, and be readable in the seconds it is on screen. Get the words right and the timing wrong, and the subtitle is useless or worse, unwatchable.
Reading Rate: The Law of the Subtitle
The governing constraint is the reading rate, the speed at which a viewer can comfortably read subtitle text, measured in characters per second (CPS). The widely used professional norm sits around 15 to 17 characters per second for adult content, lower for children's programming, and a subtitle that exceeds it forces the viewer to either stop watching the picture to finish reading or miss the end of the line. Reading rate, not translation accuracy, is the first law of subtitling, and it has hard consequences for the translated text. If a character speaks quickly, there is simply not enough on-screen time to display a full, faithful translation of everything said at a readable speed. The subtitler must condense: convey the meaning in fewer characters, cutting filler, compressing phrasing, sometimes dropping a redundant aside, so the line fits the available time at a readable rate without losing what matters.
Condensation is a craft skill that sits at the exact collision of the linguist's job and the engineer's. It is a linguistic decision, what to keep and what to cut so the meaning survives, and it is bounded by a hard numeric constraint, the characters that fit in the seconds available. An MT or LLM engine left to itself does the opposite of condensation: it produces a complete, fluent translation of every word, because completeness and fluency are what it optimizes for, and that complete translation routinely overruns the reading rate. The result is a subtitle that is a perfect translation and an unwatchable one, racing past faster than any human can read it, or one that has to be cut off, losing the end. The engine can be told the character budget per line and the duration of the cue and asked to produce a rendering that fits, which is genuinely useful, but the judgment about which words to sacrifice in the cut belongs to a human who understands what the scene needs.
Line Length and Segmentation
Subtitles also obey rules about shape that have nothing to do with the words' meaning. Convention limits a subtitle to a maximum number of characters per line, commonly around 42 for Latin scripts, and to no more than two lines on screen at once. Where a subtitle breaks across its two lines is itself a linguistic decision: a good break falls at a natural grammatical boundary, after a complete phrase, so the eye can parse each line as a unit, and a bad break splits an article from its noun or a preposition from its object and forces the reader to hold an incomplete fragment until the next line resolves it. An engine producing a subtitle as a single run of fluent prose has no concept of the two-line box or the grammatical break point; it will overrun the character limit and break in whatever spot the text happens to wrap, which is frequently the wrong one. The segmentation, splitting the dialogue into cues and breaking each cue into well-formed lines, is structural work the engine does not do and the engineer and subtitler must own.
Sync: The Other Clock
Finally, there is sync, the alignment of each subtitle's appearance and disappearance with the speech and the cut of the picture. A subtitle that appears a beat before the line is spoken spoils the joke or the reveal; one that lingers after the speaker has stopped, or bleeds across a hard cut to a new scene, jars the viewer and signals amateur work. Professional norms govern the minimum time a subtitle must stay on screen to be readable, the small gaps between consecutive subtitles, and the rule that subtitles should respect shot changes rather than straddle them. These timings are encoded in the subtitle file itself, in formats like SRT and WebVTT, as in-and-out timecodes attached to each cue. When an engine translates a subtitle file, it must touch only the text inside each cue and leave the timecodes and cue structure exactly as they are, the same locked-structure discipline as a placeholder. A pipeline that lets the engine reflow the file can shift or corrupt the timecodes, and a subtitle with perfect words and broken timing is, to the viewer, simply broken. The words protect the meaning. The timecodes protect the sync. Both have to survive, and only one of them is something a prose engine understands.
The Division of Labor That Actually Works
Step back from the individual failures and a single principle organizes all of them. In localization engineering and media, there are two jobs riding inside every string and every subtitle, and they belong to two different owners. The meaning belongs to the linguist: is the translation faithful to the source, natural in the target, correct in terminology, appropriate in register? The structure belongs to the engineer: do the placeholders match, do the plural categories obey the Unicode rules, are the tags balanced, is the encoding UTF-8, does the text fit the pixel budget, does the subtitle obey the reading rate and keep its timecodes? A confident MT or LLM engine is competent at the first job and oblivious to the second, and its obliviousness is invisible because it is wrapped in the fluency that makes the first job look done.
The expensive mistake, made constantly, is to assume that because the prose is good the string is good. The prose being good tells you nothing about whether the placeholder survived, the plural compiled, the tag balanced, the text fit, or the subtitle is readable in the time it is on screen. Those are separate properties, verified separately, by tooling and by an engineer, against the source structure, not by reading the target for meaning. This is the same discipline that runs through the rest of this program, applied to a new layer: you do not trust the fluent surface, you verify the thing underneath it against the source. For meaning, the thing underneath is the source's intent. For engineering, the thing underneath is the source's structure. The engine guarantees neither and reads as if it guaranteed both.
What This Makes the Engineer Worth
This is why localization engineering, far from being automated away by better engines, becomes more valuable as MT-first pipelines spread. The faster and more fluently the engine drafts, the more strings flow through the system, and the more places a fluent draft can silently break structure. The engineer who builds the placeholder lock, the plural-rule supplier, the tag validator, the length-budget check, the encoding normalizer, and the subtitle-timing guard is building the safety rail that lets the organization use the engine's speed without shipping its structural failures to users. The engine drafts the meaning; the engineer guarantees that the draft is a thing the program can actually run, the layout can actually hold, and the viewer can actually read. That guarantee does not come from the engine, and it does not come from reading the prose. It comes from protecting the structure on purpose, which is a marvel of unglamorous, load-bearing work, and a job the machine makes more necessary every time it gets more fluent.
Key Takeaways
- A software string is not a sentence. It is language carrying structural cargo, placeholders, plural machinery, tags, encoding, length budgets, and an MT or LLM engine optimizing for fluent prose will rewrite or destroy that cargo because the cargo is invisible to a process that only knows how to make sentences sound good. The linguist protects the meaning; the engineer protects the structure.
- A placeholder is a token like {firstName} or %s or {0} that the program replaces with a real value at runtime, and it must reach the target string spelled exactly as in the source. Engines break it by translating the token, altering its syntax, or swapping positional indices, and the failure is invisible to a reviewer reading for meaning because the meaning is fine.
- The ICU message format embeds a tiny program inside a string to select the correct plural form at runtime using Unicode plural categories like one, few, many, and other. Engines break it by translating the category keywords, collapsing the branches into one sentence, or supplying the wrong number of categories for the target language, producing grammatically wrong plurals every native speaker notices.
- Tags are inline markup like the HTML anchor pair that must move with the words they wrap and stay balanced. Encoding maps characters to bytes; UTF-8 carries every script, and mojibake appears when bytes are read in the wrong encoding. Both are locked structure the engine must carry through intact, not free text it may reshape.
- Text expands out of English, by 30% on long passages and well over 100% on short strings, with German compounds and Finnish agglutination as worst cases. An engine produces the most fluent rendering, not the shortest, so without a communicated pixel or character budget it writes strings that truncate, wrap, or overflow the UI.
- A subtitle is timed, budgeted text bounded by reading rate, around 15 to 17 characters per second, so a fast speaker forces condensation: cutting and compressing so the meaning fits the seconds available at a readable speed. An engine produces complete fluent translations that overrun the reading rate, making a perfect translation an unwatchable subtitle.
- Subtitles also obey line-length limits near 42 characters, a two-line maximum, grammatical line breaks, and sync rules with in-and-out timecodes in formats like SRT and WebVTT. The engine must touch only the cue text and leave the timecodes locked, the same discipline as a placeholder, because perfect words with broken timing is simply broken.
- The organizing principle is one division of labor: meaning belongs to the linguist and is verified against the source's intent; structure belongs to the engineer and is verified against the source's structure by tooling, never by reading the prose. Good prose tells you nothing about whether the placeholder survived, the plural compiled, or the subtitle is readable, which is exactly why localization engineering grows more valuable as fluent MT-first pipelines spread.
Skill.re