Engineeringこの記事を日本語で読む

Why translated text overflows your UI, and what to actually measure

A button that fits its English label perfectly is a bet that every other language will be roughly the same length. That bet loses constantly. Some languages routinely need noticeably more characters to say the same thing than English does; others compress into fewer characters but render each one wider. Either direction breaks a layout that was only ever tested in one language.

Expansion and contraction are not symmetric

Text expansion varies by language pair and by string length — short strings tend to expand more, proportionally, than long ones, because fixed grammatical overhead (articles, particles, verb endings) matters more relative to a short label than a full sentence. Some languages are known for needing more horizontal space for the same meaning; German compound words and grammatical case markers are a commonly cited example.

CJK languages tend to run the other direction: a Japanese or Chinese translation is often shorter in character count than its English source, because a single kanji or hanzi can carry the meaning of a whole English word. But each of those characters is typically rendered at roughly double the width of a Latin character in the same font size — the fullwidth forms used for CJK text occupy a wider advance width by design. Fewer characters does not mean a narrower string.

'Length' is at least four different measurements

A length limit is only meaningful if everyone agrees what it counts, and in practice a string's 'length' can mean several different things that give different numbers for the same text:

  • Character count as a human would count it — what a reader perceives as one letter, kana, or symbol.
  • Grapheme clusters — the technical version of the above; a single perceived character can be made of multiple Unicode code points, for example a base letter plus a combining diacritical mark, or an emoji plus a modifier joined with zero-width joiners.
  • Code points — the raw count of Unicode scalar values in the string; this already diverges from grapheme clusters whenever combining characters are used.
  • Code units — how many strings are actually measured in code, and often the least intuitive: in UTF-16 (JavaScript's native string representation, for example), any code point above U+FFFF is stored as a surrogate pair of two 16-bit units, so `string.length` counts those units, not characters — a single emoji can report as length 2.
  • Rendered width — the only measurement a UI actually cares about, and the one none of the above reliably predicts, because it depends on the font, the script's typical glyph width, and kerning.

A concrete failure mode

Code that enforces a limit on `string.length` is enforcing a limit on UTF-16 code units, not on what a translator or a player would call characters. That is usually close enough for plain CJK or Latin text, but it silently overcounts as soon as combining marks or supplementary-plane characters appear:

const label = "café"; // could be "cafe\u0301" — e with a combining acute accent
label.length; // 5, even though a reader sees 4 characters

const emoji = "🎮";
emoji.length; // 2 — a surrogate pair, not 1

Set a length budget per field, and check it mechanically

The fix is not a smarter counting function — it is deciding, per UI field, what actually constrains it, and testing against that instead of a single universal character limit.

  • For fixed-width elements (buttons, tab labels, name plates), the real constraint is rendered width in the target font, not character count. Measure it — either at build time against the shipped font, or at runtime by checking the rendered box against its container.
  • Where a hard limit is unavoidable (a database column, a fixed-size buffer), document whether it counts bytes, code points, or code units, and pick the measurement that matches how the string is actually stored and compared.
  • Give translators a budget as guidance up front (for example, 'up to roughly 1.3x the English length') rather than discovering the overflow after the fact — it is cheaper to ask for a shorter phrase during translation than to redesign a layout afterward.
  • Treat CJK expansion in the other direction, too: a button sized to fit a short Japanese label can look cramped or unbalanced once the same button carries a longer English or German string.

Related articles