localization-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Localization & Internationalization Testing

本地化与国际化测试

<default_to_action> When testing multi-language/region support:
  1. VERIFY translation coverage (all strings translated)
  2. TEST locale-specific formats (date, time, currency, numbers)
  3. VALIDATE RTL layout (Arabic, Hebrew)
  4. CHECK character encoding (UTF-8, unicode)
  5. CONFIRM cultural appropriateness (icons, colors, content)
Quick i18n Checklist:
  • All user-facing strings externalized
  • No hardcoded text in code
  • Date/time/currency formatted per locale
  • RTL languages flip layout correctly
  • Unicode characters display properly
Critical Success Factors:
  • Don't hardcode strings - externalize everything
  • Test with real speakers, not just translation files
  • RTL requires mirrored UI layout </default_to_action>
<default_to_action> 测试多语言/区域支持时:
  1. 验证翻译覆盖范围(所有字符串均已翻译)
  2. 测试区域专属格式(日期、时间、货币、数字)
  3. 验证RTL布局(阿拉伯语、希伯来语)
  4. 检查字符编码(UTF-8、Unicode)
  5. 确认文化适宜性(图标、颜色、内容)
快速i18n检查清单:
  • 所有面向用户的字符串均已外部化
  • 代码中无硬编码文本
  • 日期/时间/货币按区域格式显示
  • RTL语言可正确翻转布局
  • Unicode字符可正常显示
关键成功因素:
  • 不要硬编码字符串——全部外部化
  • 与母语使用者协作测试,不要仅依赖翻译文件
  • RTL语言需要镜像化UI布局 </default_to_action>

Quick Reference Card

快速参考卡片

When to Use

适用场景

  • Launching in new markets
  • Adding language support
  • Before international releases
  • After UI changes
  • 新市场发布
  • 添加语言支持
  • 国际化版本发布前
  • UI变更后

i18n vs l10n

i18n vs l10n

TermFull NameFocus
i18nInternationalizationBuilding for localization
l10nLocalizationAdapting for specific locale
术语全称核心关注点
i18nInternationalization为本地化构建基础架构
l10nLocalization针对特定区域进行适配

Common Locale Formats

常见区域格式

TypeUS (en-US)UK (en-GB)Japan (ja-JP)
Date10/24/202524/10/20252025/10/24
Currency$1,234.56£1,234.56¥1,235
Number1,234.561,234.561,234.56

类型美国(en-US)英国(en-GB)日本(ja-JP)
日期10/24/202524/10/20252025/10/24
货币$1,234.56£1,234.56¥1,235
数字1,234.561,234.561,234.56

Translation Coverage Testing

翻译覆盖范围测试

javascript
test('all strings are translated', () => {
  const enKeys = Object.keys(translations.en);
  const frKeys = Object.keys(translations.fr);
  const esKeys = Object.keys(translations.es);

  // All locales have same keys
  expect(frKeys).toEqual(enKeys);
  expect(esKeys).toEqual(enKeys);
});

test('no missing translation placeholders', async ({ page }) => {
  await page.goto('/?lang=fr');
  const text = await page.textContent('body');

  // Should not see placeholder keys
  expect(text).not.toContain('translation.missing');
  expect(text).not.toMatch(/\{\{.*\}\}/); // {{key}} format
});

javascript
test('all strings are translated', () => {
  const enKeys = Object.keys(translations.en);
  const frKeys = Object.keys(translations.fr);
  const esKeys = Object.keys(translations.es);

  // All locales have same keys
  expect(frKeys).toEqual(enKeys);
  expect(esKeys).toEqual(enKeys);
});

test('no missing translation placeholders', async ({ page }) => {
  await page.goto('/?lang=fr');
  const text = await page.textContent('body');

  // Should not see placeholder keys
  expect(text).not.toContain('translation.missing');
  expect(text).not.toMatch(/\{\{.*\}\}/); // {{key}} format
});

Date/Time/Currency Formats

日期/时间/货币格式测试

javascript
test('date formats by locale', () => {
  const date = new Date('2025-10-24');

  expect(formatDate(date, 'en-US')).toBe('10/24/2025');
  expect(formatDate(date, 'en-GB')).toBe('24/10/2025');
  expect(formatDate(date, 'ja-JP')).toBe('2025/10/24');
});

test('currency formats by locale', () => {
  const amount = 1234.56;

  expect(formatCurrency(amount, 'en-US', 'USD')).toBe('$1,234.56');
  expect(formatCurrency(amount, 'de-DE', 'EUR')).toBe('1.234,56 €');
  expect(formatCurrency(amount, 'ja-JP', 'JPY')).toBe('¥1,235');
});

javascript
test('date formats by locale', () => {
  const date = new Date('2025-10-24');

  expect(formatDate(date, 'en-US')).toBe('10/24/2025');
  expect(formatDate(date, 'en-GB')).toBe('24/10/2025');
  expect(formatDate(date, 'ja-JP')).toBe('2025/10/24');
});

test('currency formats by locale', () => {
  const amount = 1234.56;

  expect(formatCurrency(amount, 'en-US', 'USD')).toBe('$1,234.56');
  expect(formatCurrency(amount, 'de-DE', 'EUR')).toBe('1.234,56 €');
  expect(formatCurrency(amount, 'ja-JP', 'JPY')).toBe('¥1,235');
});

RTL (Right-to-Left) Testing

RTL(从右到左)语言测试

javascript
test('layout flips for RTL languages', async ({ page }) => {
  await page.goto('/?lang=ar'); // Arabic

  const dir = await page.locator('html').getAttribute('dir');
  expect(dir).toBe('rtl');

  // Navigation should be on right
  const nav = await page.locator('nav');
  const styles = await nav.evaluate(el =>
    window.getComputedStyle(el)
  );
  expect(styles.direction).toBe('rtl');
});

test('icons/images appropriate for RTL', async ({ page }) => {
  await page.goto('/?lang=he'); // Hebrew

  // Back arrow should point right in RTL
  const backIcon = await page.locator('.back-icon');
  expect(await backIcon.getAttribute('class')).toContain('rtl-flipped');
});

javascript
test('layout flips for RTL languages', async ({ page }) => {
  await page.goto('/?lang=ar'); // Arabic

  const dir = await page.locator('html').getAttribute('dir');
  expect(dir).toBe('rtl');

  // Navigation should be on right
  const nav = await page.locator('nav');
  const styles = await nav.evaluate(el =>
    window.getComputedStyle(el)
  );
  expect(styles.direction).toBe('rtl');
});

test('icons/images appropriate for RTL', async ({ page }) => {
  await page.goto('/?lang=he'); // Hebrew

  // Back arrow should point right in RTL
  const backIcon = await page.locator('.back-icon');
  expect(await backIcon.getAttribute('class')).toContain('rtl-flipped');
});

Unicode Character Support

Unicode字符支持测试

javascript
test('supports unicode characters', async ({ page }) => {
  // Japanese
  await page.fill('#name', '山田太郎');
  await page.click('#submit');

  const saved = await db.users.findOne({ /* ... */ });
  expect(saved.name).toBe('山田太郎');

  // Arabic
  await page.fill('#name', 'محمد');
  // Emoji
  await page.fill('#bio', '👋🌍');

  expect(saved.bio).toBe('👋🌍');
});

javascript
test('supports unicode characters', async ({ page }) => {
  // Japanese
  await page.fill('#name', '山田太郎');
  await page.click('#submit');

  const saved = await db.users.findOne({ /* ... */ });
  expect(saved.name).toBe('山田太郎');

  // Arabic
  await page.fill('#name', 'محمد');
  // Emoji
  await page.fill('#bio', '👋🌍');

  expect(saved.bio).toBe('👋🌍');
});

Agent-Driven Localization Testing

Agent驱动的本地化测试

typescript
// Comprehensive localization validation
await Task("Localization Testing", {
  url: 'https://example.com',
  locales: ['en-US', 'fr-FR', 'de-DE', 'ja-JP', 'ar-SA'],
  checks: ['translations', 'formats', 'rtl', 'unicode'],
  detectHardcodedStrings: true
}, "qe-test-generator");

// Returns:
// {
//   locales: 5,
//   missingTranslations: 3,
//   formatIssues: 1,
//   rtlIssues: 0,
//   hardcodedStrings: ['button.submit', 'header.title']
// }

typescript
// Comprehensive localization validation
await Task("Localization Testing", {
  url: 'https://example.com',
  locales: ['en-US', 'fr-FR', 'de-DE', 'ja-JP', 'ar-SA'],
  checks: ['translations', 'formats', 'rtl', 'unicode'],
  detectHardcodedStrings: true
}, "qe-test-generator");

// Returns:
// {
//   locales: 5,
//   missingTranslations: 3,
//   formatIssues: 1,
//   rtlIssues: 0,
//   hardcodedStrings: ['button.submit', 'header.title']
// }

Agent Coordination Hints

Agent协作提示

Memory Namespace

内存命名空间

aqe/localization-testing/
├── translations/*       - Translation coverage
├── formats/*            - Locale-specific formats
├── rtl-validation/*     - RTL layout checks
└── unicode/*            - Character encoding tests
aqe/localization-testing/
├── translations/*       - Translation coverage
├── formats/*            - Locale-specific formats
├── rtl-validation/*     - RTL layout checks
└── unicode/*            - Character encoding tests

Fleet Coordination

集群协作

typescript
const l10nFleet = await FleetManager.coordinate({
  strategy: 'localization-testing',
  agents: [
    'qe-test-generator',   // Generate l10n tests
    'qe-test-executor',    // Execute across locales
    'qe-visual-tester'     // RTL visual validation
  ],
  topology: 'parallel'
});

typescript
const l10nFleet = await FleetManager.coordinate({
  strategy: 'localization-testing',
  agents: [
    'qe-test-generator',   // Generate l10n tests
    'qe-test-executor',    // Execute across locales
    'qe-visual-tester'     // RTL visual validation
  ],
  topology: 'parallel'
});

Related Skills

相关技能

  • accessibility-testing - Language accessibility
  • compatibility-testing - Cross-platform i18n
  • visual-testing-advanced - RTL visual regression

  • accessibility-testing - 语言可访问性
  • compatibility-testing - 跨平台国际化
  • visual-testing-advanced - RTL视觉回归测试

Remember

注意事项

Don't hardcode. Externalize all user-facing strings. Every string visible to users must come from translation files, not code.
Test with native speakers, not just translation files. Machine translations and translation files can have context issues that only native speakers catch.
With Agents: Agents validate translation coverage, detect hardcoded strings, test locale-specific formatting, and verify RTL layouts automatically across all supported languages.
不要硬编码。将所有面向用户的字符串外部化。 所有用户可见的字符串必须来自翻译文件,而非代码。
与母语使用者协作测试,不要仅依赖翻译文件。 机器翻译和翻译文件可能存在语境问题,只有母语使用者才能发现。
借助Agent: Agent可自动在所有支持的语言中验证翻译覆盖范围、检测硬编码字符串、测试区域专属格式,并验证RTL布局。