iKit
Guide · 10 min read ·

Lorem Ipsum for i18n Testing: Catch Text Overflow (2026)

Lorem Ipsum passes every layout test, then German breaks it. Here is why Latin filler hides i18n bugs and what to paste instead before you localise.

Lorem Ipsum for i18n Testing: Catch Text Overflow (2026)

Lorem Ipsum for i18n Testing: Catch Text Overflow Early

Your mockup looked fine. Then the German build shipped, "Save" became "Speichern", the tab strip wrapped onto two lines, and a settings label ran underneath its toggle. Lorem Ipsum for i18n testing is part of the reason: Latin filler has roughly English word lengths, so it flatters every layout it touches. Real translations do not. Here is how to generate filler that breaks your UI on purpose, before a translator does it for you.

TL;DR

  • Lorem Ipsum word lengths track English, so it never stresses a layout.
  • Short strings expand most: under 10 characters means 200-300% growth.
  • Pseudolocales beat filler — they expand your real strings in place.
  • Android ships en-XA and ar-XB; Xcode ships Double Length and RTL.
  • Fix with flexible containers, overflow-wrap, and no fixed-width buttons.

Why Lorem Ipsum passes a layout that German will break

Filler text is a distribution, not a language. A generator draws from a fixed bank of roughly 180 deduplicated Latin words and assembles them into sentences with no grammar. What survives that process is the shape of the words — and Latin's shape is uncomfortably close to English's.

Latin word lengths look like English word lengths

The standard word bank averages around eight characters per token, with a long tail that rarely exceeds fourteen. English UI copy sits in the same band. So when you drop filler into a card, a tab, or a form label, the container is being tested against a string it was already designed to hold. You learn nothing.

You can check this in about ten seconds: generate a paragraph in the Lorem Ipsum generator, paste it into the word and character counter, and divide characters by words. Then do the same with a paragraph of German product copy. The gap is the bug you have not found yet.

How much does text expand when translated?

This is the number most designers never internalise, and it is counter-intuitive: the shorter the string, the worse the expansion. IBM's globalization guidance, republished in the W3C's article on text size in translation, breaks it down by source length.

English source length Budget for Real-world example
Under 10 chars 200-300% viewsvisualizzazioni
11-30 chars 160-200% Input processing → German compound
31-70 chars 140-170% Form hints, tooltips, empty states
Over 70 chars ~130% Paragraphs, legal copy, descriptions

Look at what lives in the top row: button labels, tab titles, table headers, menu items, badge text. Those are exactly the elements you squeezed into the tightest boxes. The W3C's own example is Flickr's "views", which comes back from Italian as visualizzazioni — three times the width, in a spot the designer budgeted five characters for.

Why filler never produces a compound noun

German, Finnish and Dutch glue word sequences into a single orthographic word. The W3C's worked example is English "Input processing features" arriving as German Eingabeverarbeitungsfunktionen — one 30-character token with no space in it.

That is a different failure mode from "the text is longer". Longer text wraps. A 30-character token cannot wrap by default, so it either overflows its container, forces the container wider, or gets clipped. Lorem Ipsum will never generate one, because its word bank tops out around fourteen characters. If your only test data is Latin filler, compound-noun overflow is invisible to you until a support ticket arrives.

How to test text expansion without waiting for translations

You do not need a single translated string to find 80% of these bugs. You need a pseudolocale.

What pseudolocalization actually does

A pseudolocale is a fake locale that transforms your existing English strings at runtime rather than replacing them. Android's documentation on testing with pseudolocales describes English (XA) as doing three things at once: it adds Latin accents to the base text, pads the string with extra non-accented characters, and wraps each message unit in brackets.

Each of those three transforms catches a different class of bug:

  • Accents — any string still rendering as plain ASCII is hardcoded and will never be sent for translation.
  • Padding — anything that overflows, clips, or wraps badly is a layout bug you now own.
  • Brackets — a sentence that appears as two bracketed fragments is concatenated string-building, which translators cannot reorder. Japanese, Korean and Tamil put the verb last; a concatenated sentence makes correct translation structurally impossible.

The second pseudolocale, AR (XB), flips the writing direction of your left-to-right messages so you can find unmirrored icons and stuck-left padding without reading a word of Arabic.

How to enable pseudolocales on Android

Two steps: turn it on in the build, then select it on the device. In your module's build file:

android {
  buildTypes.getByName("debug") {
    isPseudoLocalesEnabled = true
  }
}

Then, on a device with developer options enabled and running Android 4.3 (API 18) or later, open Settings → Languages and input → Language preferences and drag English (XA) or AR (XB) to the top of the list. Every app that supports pseudolocales — including the system Settings app — switches with you.

How to test localization in Xcode with a pseudolanguage

Apple's guide to testing your internationalized app puts the switch in the scheme editor: choose Edit Scheme → Options → Application Language, then pick a pseudolanguage. Double Length Pseudolanguage duplicates every localized string, which is the fastest Auto Layout stress test available. Right to Left Pseudolanguage mirrors the interface.

If you would rather not edit the scheme, the same behaviour is available as launch arguments:

NSDoubleLocalizedStrings YES
NSShowNonLocalizedStrings YES
-AppleTextDirection YES
-AppleLanguages "(de)"

NSShowNonLocalizedStrings renders untranslated strings in uppercase — the iOS equivalent of Android's unaccented-text tell.

Which pseudolocale to reach for

Platform Expansion test RTL test
Android English (XA) AR (XB)
iOS / macOS Double Length Right to Left
Web custom transform dir="rtl" on <html>

How to fake text expansion in a web app

The web has no built-in pseudolocale, which is why front-end teams reach for Lorem Ipsum and stop there. Writing the transform yourself takes about fifteen lines.

A minimal pseudolocalizer in JavaScript

const MAP = { a:'á', e:'é', i:'í', o:'ó',
              u:'ú', c:'ç', n:'ñ', s:'š' };

function pseudo(str, pad = 0.4) {
  const body = [...str]
    .map(ch => MAP[ch.toLowerCase()] ?? ch)
    .join('');
  const extra = '·'.repeat(
    Math.ceil(body.length * pad)
  );
  return `[${body} ${extra}]`;
}

pseudo('Save');     // [Šávé ··]
pseudo('Settings'); // [Šéttíngš ····]

Run every string in your message catalogue through it behind a ?pseudo=1 query flag. A 40% pad is a gentle default; set it to 2.0 to simulate the worst row of the expansion table above. Because the brackets mark message boundaries, a label that renders as [Deleted ] [3 items] tells you immediately that somebody concatenated a sentence.

Generating worst-case filler when you need a body of text

Pseudolocalization handles UI strings. For prose regions — article bodies, descriptions, rich-text blocks — you still want filler, and this is where a generator earns its place. Three rules make the output useful rather than flattering:

  • Generate at the top of your real content budget, not a round number. If a card description is 15-25 words in production, generate 25.
  • Paste one long unbreakable token into every text container at least once. Eingabeverarbeitungsfunktionen works; so does a 40-character email address or a URL with no hyphens.
  • Mark the filler lang="la" so screen readers and hyphenation engines do not treat it as English. This also stops a Latin block from skewing any language-detection you run in CI.

For the prose blocks themselves, the Lorem Ipsum generator gives you exact word counts, which is what you want when you are matching a content budget rather than filling space.

Testing CJK line height, not just width

Width is only half the problem. The W3C notes that non-Latin scripts frequently need more vertical space: Thai text can occupy around 150% of the line height of the equivalent Latin text, and Devanagari, Arabic in Nastaliq, Chinese, Japanese, Korean and Tibetan all run taller than Latin.

There is also a width trap that character counts hide. English "desktop" becomes デスクトップ in Japanese — one character shorter, but visibly wider, because each CJK glyph occupies roughly two Latin character widths. Any layout logic keyed to str.length will get this wrong; if you count CJK content for a living, our guide to counting Chinese, Japanese and Korean words covers where the character-count assumptions break.

So: paste a paragraph of Japanese and a paragraph of Thai into your longest text container before you ship. Two minutes, and it catches every height: 40px you left on a list row.

The CSS that survives a 300% expansion

Most i18n overflow bugs come down to four habits. Fixing them costs almost nothing and removes an entire bug category.

overflow-wrap, hyphens, and the compound-noun problem

By default a long unbreakable token will overflow rather than break. MDN's reference on overflow-wrap covers the property that changes that; pairing it with language-aware hyphenation gives German and Finnish somewhere to break:

.label {
  overflow-wrap: break-word;
  hyphens: auto;
}

hyphens: auto needs a lang attribute on the element or an ancestor to pick the right dictionary, which is another reason to set lang properly rather than leaving everything as en.

Stop putting fixed widths on buttons and tabs

A button sized width: 120px is a promise that no translation exceeds 120 pixels. You cannot keep that promise. Use padding and let the content size the box:

.btn {
  padding: 0.5rem 1rem;
  min-width: 6rem;   /* floor, not ceiling */
  white-space: normal;
}

Set a min-width if short labels look mean, but never a max-width or a fixed width. The same applies to tab strips, table headers, and anything inside a graphic — the W3C's guidance is blunt on this point: be especially careful fitting text snugly into graphic designs, because the background cannot grow with the text.

Think twice before abbreviating to make something fit

Abbreviation is the most common fix for a too-long label, and it is a trap. Many languages abbreviate rarely or not at all, and Arabic in particular builds words from compact pattern-based roots that lose meaning when clipped. An abbreviation that saves you four characters in English can force the translator into a longer string than the one you started with. If the label does not fit, fix the container.

An i18n text-overflow checklist

Run this before the first string leaves for translation, not after the first bug report.

Before you write a single layout

  • Budget every short string for 200-300% growth, not 20%.
  • Never concatenate a sentence from fragments; use a single parameterised message.
  • Keep presentation out of content so font size and line height can be adapted per locale.
  • Size database and API fields in characters with the expanded length in mind.

Before you ship

Build once with pseudolocales enabled and walk every screen. Then walk them again in RTL. Pay attention to three places specifically: tab strips and segmented controls, anything rendered inside a fixed-size graphic, and table headers, which combine the shortest strings with the tightest columns.

After the translations come back

A pseudolocale approximates expansion; it does not predict it. Re-walk the same screens in the two languages that expand hardest for you — usually German and one Romance language — before you call the release done. If you keep your message catalogue in version control, a quick pass through a diff checker between the English file and the returned translation file will surface missing keys and stray placeholders before they reach a build, which is the kind of drift that otherwise shows up as a blank label two releases later.

The goal is not to make your UI look good in a pseudolocale. It is to make every string in your app fail loudly, on your machine, while it is still cheap to fix.

References

Related on iKit

Related posts