qe-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

类型US (en-US)UK (en-GB)Japan (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 - 跨平台i18n
  • 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能力: Agents可自动在所有支持的语言中验证翻译覆盖率、检测硬编码字符串、测试地区专属格式化、校验RTL布局。