Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.
I18nMedium

Design UI components to accommodate text expansion from translation

Ensure that layouts use flexible sizing so that translated text — which can be 30–50% longer than English — does not overflow, clip, or break the UI.

Utilities
Quick take
Typical fix time 30 min
  • German translations are typically 30% longer than English; Finnish 50% longer
  • Avoid fixed-width containers for text-bearing elements like buttons and labels
  • Use min-inline-size instead of inline-size to allow natural growth
  • Test with a pseudo-locale that inflates strings before committing translations
  • Include pseudolocalization in CI or preview testing, not just manual QA
Why it matters: Layouts designed only with English copy routinely break when translated: buttons overflow their containers, labels truncate, and navigation items wrap unexpectedly. Catching these issues early with pseudo-locale testing is far cheaper than fixing them after translations are delivered.

Rule Details

Text expansion is the increase in string length that occurs during translation. English is typically the shortest form of most content; other languages require more characters to express the same idea. The W3C provides approximate expansion factors:

String length (English)Expected expansion
Up to 10 characters100–200% longer
11–20 characters80–100% longer
21–30 characters60–80% longer
Over 70 characters30% longer

German and Dutch routinely exceed English by 30%; Finnish and Hungarian by 50%. Plan for at least 30% expansion in every text-bearing component.

Code Example

The most common cause of text-expansion breakage is setting an explicit width or inline-size on a button or label:

/* ❌ Breaks when "Submit" becomes "Abschicken" in German */
.button {
  width: 120px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

Truncating a button label with an ellipsis is almost always wrong — the user cannot know what action they are triggering.

Why It Matters

Layouts designed only with English copy routinely break when translated: buttons overflow their containers, labels truncate, and navigation items wrap unexpectedly. Catching these issues early with pseudo-locale testing is far cheaper than fixing them after translations are delivered.

Use min-inline-size for Flexible Growth

Logical properties (inline-size, min-inline-size, block-size) are preferred over physical properties (width, height) because they adapt automatically to writing direction (LTR/RTL):

/* ✅ Button grows to accommodate longer translations */
.button {
  min-inline-size: 7.5rem; /* sets a sensible minimum, but allows growth */
  padding-inline: 1rem;
  padding-block: 0.5rem;
  white-space: normal; /* allow wrapping only if the design permits it */
}
 
/* ✅ Navigation item */
.nav-item {
  min-inline-size: max-content; /* never narrower than the content */
  padding-inline: 0.75rem;
}

Flexible Container Patterns

/* ✅ Card with flexible content area */
.card {
  display: grid;
  grid-template-rows: auto 1fr auto; /* header / body / footer */
  /* No fixed height — body expands with content */
}
 
/* ✅ Form label + input row */
.form-row {
  display: flex;
  flex-wrap: wrap; /* wraps label above input when label is very long */
  gap: 0.5rem;
  align-items: baseline;
}
 
.form-row label {
  flex: 0 1 auto; /* shrink allowed, grow allowed up to content width */
  min-inline-size: 6rem;
}
 
/* ✅ Badge / chip */
.badge {
  display: inline-flex;
  align-items: center;
  padding-inline: 0.5rem;
  /* No width — grows with text */
  border-radius: 9999px;
}

CSS Logical Properties Reference

Using logical properties ensures your flexible layout also works correctly in RTL locales:

Physical propertyLogical equivalent
widthinline-size
min-widthmin-inline-size
max-widthmax-inline-size
heightblock-size
padding-left / padding-rightpadding-inline-start / padding-inline-end
margin-leftmargin-inline-start
text-align: lefttext-align: start

Pseudo-Locale Testing

A pseudo-locale inflates and decorates every source string to simulate translation expansion before real translations exist. This lets you catch layout breaks in CI or Storybook:

// lib/pseudo-locale.ts
 
/**
 * Wraps each character in an accented equivalent and pads the string
 * to simulate ~40% expansion. Output is readable but visually distinct.
 */
export function pseudoLocalize(input: string): string {
  const charMap: Record<string, string> = {
    a: 'à', b: 'ƀ', c: 'ç', d: 'ď', e: 'è',
    f: 'ƒ', g: 'ĝ', h: 'ĥ', i: 'ì', j: 'ĵ',
    k: 'ķ', l: 'ĺ', m: 'ɱ', n: 'ñ', o: 'ò',
    p: 'þ', q: 'q', r: 'ŗ', s: 'š', t: 'ţ',
    u: 'ù', v: 'v', w: 'ŵ', x: 'x', y: 'ý', z: 'ž',
    A: 'À', B: 'Ɓ', C: 'Ç', D: 'Ď', E: 'È',
  };
 
  // Replace characters and pad with brackets to show boundaries
  const mapped = input
    .split('')
    .map((c) => charMap[c] ?? c)
    .join('');
 
  // Add ~40% padding with repeated characters
  const padding = '~'.repeat(Math.ceil(input.length * 0.4));
  return `[${mapped}${padding}]`;
}
 
// Usage in i18n provider during development
import i18n from 'i18next';
 
if (process.env.NEXT_PUBLIC_PSEUDO_LOCALE === 'true') {
  i18n.use({
    type: 'postProcessor',
    name: 'pseudoLocalize',
    process: (value: string) => pseudoLocalize(value),
  });
}

To enable during a test run:

NEXT_PUBLIC_PSEUDO_LOCALE=true pnpm dev
Don't rely on English-only visual QA

Running visual regression tests only with English strings gives a false sense of confidence. Add a pseudo-locale story or Playwright snapshot to your CI pipeline to catch expansion breakages automatically.

Overflow as a Last Resort

If a design genuinely cannot accommodate expansion (e.g. a column in a data table), apply truncation with a tooltip so the full text remains accessible:

// TruncatedCell.tsx
function TruncatedCell({ text }: { text: string }) {
  return (
    <td
      style={{
        maxInlineSize: '12rem',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
      }}
      title={text} // full text accessible on hover / focus
      aria-label={text}
    >
      {text}
    </td>
  );
}

Support Notes

  • Internationalization behavior depends on browser locale APIs, layout engines, and text rendering, so verify the output in the supported browser matrix.
  • Document any fallback when locale-sensitive formatting or layout behavior differs by browser or platform.

Verification

Automated Checks

  • Run visual regression snapshots with the pseudo-locale enabled in CI.
  • Manually test the longest-known translation (commonly German or Finnish) for critical UI strings like the primary CTA, navigation items, and form labels.
  • Keep a pseudolocalized preview route or build flag available so expansion testing does not depend on translators delivering real strings first.

Manual Checks

  • Enable the pseudo-locale and review every page at 1280px — no button label, form label, or navigation item should overflow or clip.
  • Search CSS for width: and inline-size: values on elements that render t() or translated strings — replace with min-inline-size:.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Identify CSS rules and component styles that use fixed widths or hard truncation on elements containing translatable text, which would break when content expands in other languages. Check that the team can test a pseudolocalized build or preview.

Fix

Auto-fix issues

Replace fixed inline-size with min-inline-size on text containers, remove overflow: hidden from interactive elements, and add a pseudo-locale build step for visual testing in local development and CI.

Explain

Learn more

Explain how text expansion during translation breaks fixed layouts and what CSS patterns prevent overflow and clipping across locales.

Review

Code review

Review CSS files and component styles for fixed widths, overflow: hidden, white-space: nowrap, and text-overflow: ellipsis on buttons, labels, navigation items, and headings that contain translatable text.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Rules that often go hand-in-hand with this one.

Use Intl APIs for currency, number, and date formatting

Format monetary values, numbers, and dates using the browser's built-in Intl.NumberFormat and Intl.DateTimeFormat APIs instead of manual string manipulation.

I18n
Set text direction for RTL languages

The dir attribute is used for languages that read right-to-left (RTL) or mixed content.

HTML
Use locale-neutral images and provide cultural overrides when needed

Default to abstract, culture-neutral icons and illustrations, and supply locale-specific image variants only when visual content carries meaning that differs across regions.

I18n
Prevent horizontal scrolling

Web pages must not require horizontal scrolling at standard viewport widths. Horizontal overflow breaks responsive layouts and makes content inaccessible to low-vision users who zoom in.

CSS

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385