localization-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLocalization & Internationalization Testing
本地化与国际化测试
<default_to_action>
When testing multi-language/region support:
- VERIFY translation coverage (all strings translated)
- TEST locale-specific formats (date, time, currency, numbers)
- VALIDATE RTL layout (Arabic, Hebrew)
- CHECK character encoding (UTF-8, unicode)
- 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>
测试多语言/区域支持时:
- 验证翻译覆盖范围(所有字符串均已翻译)
- 测试区域专属格式(日期、时间、货币、数字)
- 验证RTL布局(阿拉伯语、希伯来语)
- 检查字符编码(UTF-8、Unicode)
- 确认文化适宜性(图标、颜色、内容)
快速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
| Term | Full Name | Focus |
|---|---|---|
| i18n | Internationalization | Building for localization |
| l10n | Localization | Adapting for specific locale |
| 术语 | 全称 | 核心关注点 |
|---|---|---|
| i18n | Internationalization | 为本地化构建基础架构 |
| l10n | Localization | 针对特定区域进行适配 |
Common Locale Formats
常见区域格式
| Type | US (en-US) | UK (en-GB) | Japan (ja-JP) |
|---|---|---|---|
| Date | 10/24/2025 | 24/10/2025 | 2025/10/24 |
| Currency | $1,234.56 | £1,234.56 | ¥1,235 |
| Number | 1,234.56 | 1,234.56 | 1,234.56 |
| 类型 | 美国(en-US) | 英国(en-GB) | 日本(ja-JP) |
|---|---|---|---|
| 日期 | 10/24/2025 | 24/10/2025 | 2025/10/24 |
| 货币 | $1,234.56 | £1,234.56 | ¥1,235 |
| 数字 | 1,234.56 | 1,234.56 | 1,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 testsaqe/localization-testing/
├── translations/* - Translation coverage
├── formats/* - Locale-specific formats
├── rtl-validation/* - RTL layout checks
└── unicode/* - Character encoding testsFleet 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布局。