name: i18n-testing description: "Use this skill when writing, reviewing, or planning internationalization and localization tests. Covers string externalization, text expansion, RTL layout, date/time/number/currency formatting, pluralization, character encoding, pseudo-localization, and CJK/bidirectional text. Trigger when the user mentions i18n, l10n, localization, internationalization, translation testing, RTL, or locale-specific formatting."
Localization & i18n Testing
A reference for GitHub Copilot to generate internationalization and localization tests.
String Externalization
All user-visible strings must be externalized to resource files — never hardcoded in components or templates.
What to check:
- Hardcoded strings in JSX, templates, or UI code
- String concatenation to build sentences (breaks in languages with different word order)
- Template literals with embedded text that should be translated
- Alt text, ARIA labels, placeholder text, and error messages
- Strings in JavaScript/TypeScript that are displayed to users (alerts, confirmations, toasts)
Example test pattern:
test('no hardcoded user-facing strings in components', async () => {
// Scan component files for string literals that aren't i18n keys
// Flag any raw text inside JSX that should use t() or <Trans>
});
Text Expansion & Truncation
Translations are often 30–50% longer than English. UI must accommodate expansion without breaking layout.
What to check:
- Buttons, labels, and navigation items with fixed widths
- Table column headers with no wrapping or overflow handling
- Tooltips and badges that truncate at short character limits
- Responsive layouts that break when text is longer
- Text that overflows containers (check
overflow: hiddenandtext-overflow: ellipsis)
Test with pseudo-localization:
// Pseudo-locale adds ~35% length and special characters to expose layout issues
// Example: "Submit" → "[Ṡṵḅṁḭṫ ṡṵḅṁḭṫ]"
test('UI handles text expansion without overflow', async ({ page }) => {
// Set locale to pseudo-locale or a verbose language (German, Finnish)
// Check for horizontal scrollbars, truncated text, overlapping elements
});
RTL (Right-to-Left) Layout
Languages like Arabic and Hebrew flow right-to-left. The entire UI must mirror.
What to check:
dir="rtl"applied to the root element when locale is RTL- CSS logical properties used (
margin-inline-startinstead ofmargin-left) - Icons that imply direction (arrows, back buttons) are mirrored
- Text alignment shifts from left to right
- Bidirectional text (mixed LTR/RTL in the same string) renders correctly
- Navigation and reading order follows RTL flow
Example test:
test('layout mirrors correctly in RTL', async ({ page }) => {
await page.evaluate(() => document.documentElement.dir = 'rtl');
// Verify navigation is right-aligned
// Verify content flows right-to-left
// Verify no overlapping or misaligned elements
});
Date, Time, Number & Currency Formatting
Formatting varies significantly across locales.
What to check:
| Format | US English | German | Japanese |
|---|---|---|---|
| Date | 02/16/2026 | 16.02.2026 | 2026/02/16 |
| Number | 1,234.56 | 1.234,56 | 1,234.56 |
| Currency | $1,234.56 | 1.234,56 € | ¥1,234 |
| Time | 2:30 PM | 14:30 | 14:30 |
Best practices:
- Use
Intl.DateTimeFormat,Intl.NumberFormat, andIntl.RelativeTimeFormat - Never format dates with string concatenation or manual padding
- Test timezone-sensitive displays (event times, deadlines, "posted 2 hours ago")
- Check that date pickers and calendars respect locale (first day of week varies)
Pluralization & Gender
Many languages have complex plural rules beyond English's singular/plural.
What to check:
- Plural forms handled by i18n library (not
count === 1 ? 'item' : 'items') - Languages with multiple plural forms are supported (Arabic has 6, Polish has 4)
- Gender-specific translations where the language requires them
- Zero-count displays ("No items" vs "0 items")
Character Encoding & Input
What to check:
- UTF-8 encoding throughout the stack (database, API, files, HTTP headers)
- CJK characters (Chinese, Japanese, Korean) display and input correctly
- Diacritical marks (é, ñ, ü, ö) in names, search, and sorting
- Emoji in user-generated content
- Search and filtering works with accented characters (e.g., "café" matches "cafe")
- Database collation supports case-insensitive matching across scripts
Best Practices
- Test with real translations, not lorem ipsum — real text reveals length, layout, and encoding issues
- Test at minimum 3 locales — pick one LTR Latin (German/French), one CJK (Japanese/Chinese), and one RTL (Arabic)
- Automate string extraction checks — CI should fail if new user-facing strings aren't externalized
- Test locale switching at runtime — verify the app doesn't require a reload to change language
- Check SEO metadata —
<html lang="">,<meta>tags, andhreflangattributes update per locale