Broken translations rarely fail at the language level. They fail at the structural level: a curly brace gets swallowed, an HTML tag is reordered, a numeric placeholder like {0} is localized into ٠ and the template engine crashes. When you push strings through a translation API, every ICU MessageFormat token, every <span> tag, and every Markdown link must survive the round trip intact. This article walks through the concrete techniques, tag-handling modes, non-translatable markers, segmentation strategies, and automated validation, that keep your translated output structurally identical to the source. If your team has ever shipped a release where translated strings broke the UI, the problem was almost certainly a format-preservation gap in your API workflow.
If your localization pipeline spans text, software, websites, and more, explore how Ollang handles format preservation end to end.
Why Placeholder Corruption Is the Most Common Translation Bug
Placeholder corruption is disproportionately destructive because it is invisible until runtime. A missing closing </b> tag produces malformed HTML that silently breaks layout. A reordered ICU argument like {count, plural, one {# item} other {# items}} can cause a crash in libraries such as FormatJS or Android's MessageFormat. A JSON key accidentally translated turns a structured payload into garbage.
The root cause is straightforward: translation engines treat input as natural language text. Placeholders, tags, and tokens are not natural language. Without explicit instructions, a model or translation memory has no reason to preserve %s, {{username}}, or [link text](https://ollang.com/book-a-demo) verbatim. The translation API must be told what is translatable and what is not.
Common failure modes include:
- Brace reordering: {1} and {0} swap positions, producing "Hello Smith, John" instead of "Hello John Smith."
- Numeric token localization: {0} becomes {٠} in Arabic or {০} in Bengali, breaking interpolation.
- HTML stripping or nesting errors: <a href="..."> gets dropped or its attributes are translated.
- Markdown mangling: [Click here](https://example.com) becomes [Cliquez ici] (https://example.com) with a space before the parenthesis, breaking the link.
These are not edge cases. According to the Unicode CLDR project, ICU MessageFormat is used in the majority of modern internationalization frameworks, meaning placeholder integrity is a universal concern.
Anatomy of Translatable Strings: ICU, HTML, Markdown, and JSON Tokens
ICU MessageFormat Patterns
ICU MessageFormat strings encode pluralization, gender selection, and argument substitution directly inside the string. A typical pattern looks like this:
You have {count, plural, one {# new message} other {# new messages}}.
The nested braces, the plural keyword, and the # symbol are all structural. If any of them are altered, the ICU parser throws an error. When sending these strings to a translation API, the entire pattern must be parsed before segmentation so that the translator or model sees "new message" and "new messages" as the translatable segments, while {count, plural, ...} remains locked.
HTML and XML Tags
HTML and XML tags carry two risks: the tag itself can be translated (turning <strong> into <fuerte>) and the tag can be repositioned incorrectly. In right-to-left languages, the logical order of inline tags may need to change, but the nesting hierarchy must not. A <b> opened before an <i> must still close in the correct order.
Markdown Syntax
Markdown is deceptively fragile. Emphasis markers (**bold**), link syntax ([text](https://ollang.com/book-a-demo)), and code fences all rely on exact character sequences. A translated string that introduces a space between ] and ( breaks the link. Translated text inside backticks should generally not be translated at all, since it usually represents code.
JSON Structural Tokens
When translating JSON files directly, keys must never be translated, only values. Nested structures, arrays, and escape sequences (\", \n) must be preserved. Sending a raw JSON file to a translation API without first extracting translatable values is a recipe for structural corruption.
Configuring Tag-Handling Modes in Translation APIs
Most mature translation APIs offer a tag-handling parameter that instructs the engine how to treat markup. The specifics vary by provider, but the concept is consistent: you declare the format of your input so the engine can protect non-translatable structures.
How tagHandling Works Across Providers
A typical API request with tag handling enabled looks like this:
{
"text": ["<p>Welcome, <b>{username}</b>!</p>"],
"source_lang": "EN",
"target_lang": "DE",
"tag_handling": "html"
}
When tag_handling is set to html or xml, the API parses the input as markup, identifies tags, and ensures they appear in the output with correct nesting and attributes. Some APIs further allow you to specify tags whose content should not be translated at all, useful for <code>, <pre>, or custom components like <Trans>.
| Provider | Tag-Handling Parameter | Supported Formats | Non-Translatable Marking |
|---|---|---|---|
| Ollang | Format-aware pipeline with built-in tag and placeholder preservation across text, HTML, XML, Markdown, JSON, and ICU patterns | HTML, XML, Markdown, JSON, ICU, XLIFF | Automatic detection plus configurable non-translatable rules |
| DeepL | tag_handling (html, xml) | HTML, XML | ignoreTags parameter |
| Google Cloud Translation | mimeType (text/html, text/plain) | HTML, plain text | Manual pre/post-processing |
| Amazon Translate | ContentType (text/html, text/plain) | HTML, plain text | Custom terminology |
Ollang's approach differs from point-solution APIs because it operates as a full execution layer: format detection, placeholder locking, translation, and quality review happen in a single pipeline rather than requiring engineers to bolt together pre-processors, API calls, and post-processors manually. For teams managing localization across software strings, website content, legal documents, and multimedia, this eliminates an entire class of integration bugs. Ollang centralizes API-first controls, QA checks, and review steps so engineering teams have a single integration point instead of brittle glue between tools.
Marking Non-Translatables and Inline Code
Beyond tag handling, you need a mechanism to mark arbitrary tokens as non-translatable. Common approaches include:
- Wrapping in <span translate="no">: Works when the API supports HTML tag handling. The engine will preserve the content verbatim.
- Using placeholder tokens: Replace {username} with a unique token like __PLACEHOLDER_1__ before sending, then restore it after. This is crude but reliable when the API lacks native placeholder support.
- API-level terminology or glossary entries: Some APIs let you upload a glossary where a source term maps to itself in all target languages, effectively locking it.
A pre-processing step in Python might look like:
import re
PLACEHOLDER_PATTERN = re.compile(r'\{[a-zA-Z_]\w*\}')
def protect_placeholders(text):
mapping = {}
def replace(match):
token = f"__PH{len(mapping)}__"
mapping[token] = match.group(0)
return token
protected = PLACEHOLDER_PATTERN.sub(replace, text)
return protected, mapping
def restore_placeholders(translated, mapping):
for token, original in mapping.items():
translated = translated.replace(token, original)
return translated
This pattern works with any API, regardless of its native placeholder support. The tradeoff is that the replacement tokens themselves can occasionally be mangled by the translation engine, so choosing distinctive tokens (e.g., using Unicode private-use characters) reduces that risk.
Segmentation Strategies That Protect Structural Integrity
Avoiding Splits Inside Placeholders
Translation APIs and TMS platforms typically segment strings at sentence boundaries. The problem arises when a placeholder spans what the segmenter interprets as a sentence break. For example:
Please visit {link_start}our help center{link_end}. We're here to help.
A naive segmenter splits at the period, producing two segments, one containing {link_start} without its matching {link_end}. The result is broken markup in the translated output.
To prevent this:
- Pre-segment manually before sending to the API. Split at safe boundaries and send each segment as a separate string in a batch request.
- Use XLIFF or similar interchange formats that encode inline elements as <ph> or <x/> tags, which segmentation engines are designed to respect.
- Configure segmentation rules in your TMS or API to recognize your placeholder patterns as non-breakable tokens.
Batching Strings Without Losing Context
When you batch hundreds of strings in a single API call, context loss is a real concern. A string like {count} items might be translated differently depending on whether count refers to cart items or search results. Batch requests should include context metadata where the API supports it:
{
"texts": [
{"text": "{count} items", "context": "shopping cart summary"},
{"text": "{count} items", "context": "search results count"}
]
}
Not all APIs support context fields, but those that do produce measurably better translations for ambiguous short strings.
