qe-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 |
| 类型 | US (en-US) | UK (en-GB) | Japan (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 - 跨平台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布局。