Skip to main content

Text Expansion in i18n: Prevent Layout Breakage from Translation Length

Your English UI fits perfectly. Then German translations arrive — 30% longer. Finnish is 40% longer. Your buttons overflow, your tables break, and your carefully designed layout falls apart. Text expansion testing prevents this.

1

Why Text Expansion Breaks Layouts

Developers design UIs with English text, which is one of the most compact languages. When translations arrive, longer languages overflow containers, break grid layouts, truncate button labels, and push content off-screen. These bugs only appear in specific locales, making them invisible during English-only development and testing.

The expansion problem
// English is one of the most compact languages.
// Translations are almost always LONGER.

// English (source):
"Save"           // 4 chars

// Translations:
"Speichern"      // German: 10 chars (+150%)
"Enregistrer"    // French: 12 chars (+200%)
"Guardar"        // Spanish: 7 chars (+75%)
"Сохранить"      // Russian: 9 chars (+125%)
"Tallenna"       // Finnish: 8 chars (+100%)

// Buttons, labels, and table headers designed for
// English text WILL break in other languages.
Text expansion is not an edge case. Every UI that supports multiple languages will encounter it. German is 30% longer than English, Finnish is 40% longer, and some languages can be 100%+ longer for short strings. Testing for expansion before translations arrive prevents expensive redesigns.
2

Text Expansion Ratios by Language

Average expansion ratios relative to English source text. Short strings (under 20 characters) expand more than long strings because individual word choices have a bigger impact on total length.

Expansion ratios by language
// Average text expansion relative to English:

// European languages:
// German:     +30-35%  (compound words)
// Finnish:    +30-40%  (agglutinative)
// French:     +15-25%  (articles, prepositions)
// Spanish:    +15-25%
// Italian:    +15-25%
// Portuguese: +15-25%
// Russian:    +20-30%  (case endings)
// Polish:     +20-30%
// Greek:      +20-30%

// Asian languages (CJK):
// Chinese:    -30-50%  (shorter in characters, but wider per char)
// Japanese:   -20-40%  (kanji compress meaning)
// Korean:     -10-20%

// Right-to-left:
// Arabic:     +20-30%
// Hebrew:     +10-20%

// Rule of thumb by source string length:
// 1-10 chars:   expect +200% expansion
// 11-20 chars:  expect +80% expansion
// 21-70 chars:  expect +40% expansion
// 71+ chars:    expect +30% expansion
These are averages. Individual strings can expand significantly more — a 2-word English button label might become 4 words in German. Test with higher ratios (50%+) for critical UI elements like buttons, navigation, and table headers.
3

Testing with i18n-pseudo

i18n-pseudo's expansion strategy adds padding to your source strings to simulate translation length. Set the expansion ratio to match your target languages and test your layouts before real translations arrive.

Terminal
# Method 1: Pseudo-localization with expansion
npx i18n-pseudo generate \
  --source locales/en.json \
  --output locales/pseudo-expanded.json \
  --expansion 1.4 \
  --preset expanded

# Method 2: Longest-translation analysis
npx i18n-validate expansion \
  --source locales/en.json \
  --targets 'locales/*.json' \
  --report expansion-report.json

# Output:
# Key                  | EN  | Longest | Lang | Ratio
# ---------------------|-----|---------|------|-------
# nav.settings         | 8   | 14      | de   | 175%
# buttons.save         | 4   | 12      | fr   | 300%
# errors.networkFailed | 14  | 28      | fi   | 200%

# Method 3: Visual regression with expanded text
npx playwright test \
  --project=expansion-test \
  --update-snapshots
Visual regression tests
// playwright.config.ts
export default defineConfig({
  projects: [
    {
      name: 'expansion-test',
      use: {
        locale: 'pseudo-expanded',
      },
    },
  ],
});

// tests/expansion.spec.ts
test('buttons do not overflow with expanded text', async ({ page }) => {
  await page.goto('/');

  // Check no horizontal overflow
  const buttons = await page.locator('button').all();
  for (const button of buttons) {
    const box = await button.boundingBox();
    const parent = await button.locator('..').boundingBox();
    expect(box!.x + box!.width).toBeLessThanOrEqual(
      parent!.x + parent!.width
    );
  }

  // Visual snapshot comparison
  await expect(page).toHaveScreenshot('homepage-expanded.png', {
    maxDiffPixels: 100,
  });
});
Test with 40% expansion for European languages and 50% for worst-case scenarios. If your layout survives 50% expansion, it will handle virtually any language.
4

Design Best Practices for i18n

Building layouts that handle text expansion requires design decisions made before any translation work begins. These practices prevent the most common expansion-related bugs.

CSS best practices
/* 1. Use flexible containers, not fixed widths */
/* WRONG */
.button { width: 120px; }

/* RIGHT */
.button { min-width: 80px; padding: 8px 16px; }

/* 2. Allow text wrapping in labels */
/* WRONG */
.label { white-space: nowrap; overflow: hidden; }

/* RIGHT */
.label { overflow-wrap: break-word; }

/* 3. Use CSS Grid/Flexbox for adaptive layouts */
.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* 4. Reserve space for the longest expected translation */
/* Use min-width based on ~1.4x English length */
.table-header {
  min-width: max-content;
  padding-right: 16px;
}

/* 5. Test with the longest language first */
/* German and Finnish are good stress-test languages */

/* 6. For CJK: account for wider characters */
/* CJK characters are typically 2x the width of Latin chars */
/* Even though text is shorter, it may be wider visually */

Try i18n Agent Now

Drop your translation file here

JSON, YAML, PO, XML, CSV, Markdown, Properties

or click to browse

Target languages

No signup requiredInstant estimate

Text Expansion FAQ