@harness-engineering/cli 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/personas/documentation-maintainer.yaml +3 -1
- package/dist/agents/personas/performance-guardian.yaml +23 -0
- package/dist/agents/skills/claude-code/align-documentation/SKILL.md +13 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +25 -1
- package/dist/agents/skills/claude-code/cleanup-dead-code/skill.yaml +5 -2
- package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +12 -0
- package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +48 -1
- package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +5 -2
- package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +7 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +9 -1
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +76 -4
- package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +2 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +487 -234
- package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +15 -2
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +226 -0
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +64 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/skill.yaml +69 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +73 -8
- package/dist/agents/skills/claude-code/harness-execution/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +32 -6
- package/dist/agents/skills/claude-code/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/claude-code/harness-i18n/skill.yaml +54 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/skill.yaml +53 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +17 -1
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +46 -5
- package/dist/agents/skills/claude-code/harness-perf/SKILL.md +37 -8
- package/dist/agents/skills/claude-code/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +17 -4
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +57 -3
- package/dist/agents/skills/claude-code/harness-planning/skill.yaml +2 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +16 -0
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +562 -0
- package/dist/agents/skills/claude-code/harness-roadmap/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +36 -2
- package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +8 -6
- package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +48 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +66 -0
- package/dist/agents/skills/claude-code/harness-verification/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-verify/SKILL.md +11 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +15 -1
- package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +12 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +7 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +9 -1
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +226 -0
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +64 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +35 -6
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/skill.yaml +69 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +32 -6
- package/dist/agents/skills/gemini-cli/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/gemini-cli/harness-i18n/skill.yaml +54 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/skill.yaml +53 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +35 -6
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +46 -5
- package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +37 -8
- package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +17 -4
- package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +16 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +562 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +8 -6
- package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +48 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +35 -6
- package/dist/agents/skills/shared/i18n-knowledge/accessibility/intersection.yaml +142 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/encoding.yaml +67 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/formatting.yaml +106 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/layout.yaml +80 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/pluralization.yaml +80 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/string-handling.yaml +106 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/android-resources.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/apple-strings.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/backend-patterns.yaml +50 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/flutter-intl.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/i18next.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/react-intl.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/vue-i18n.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/ecommerce.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/fintech.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/gaming.yaml +69 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/healthcare.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/legal.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ar.yaml +41 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/de.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/en.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/es.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/fi.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/fr.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/he.yaml +41 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/hi.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/it.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ja.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ko.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/nl.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/pl.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/pt.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ru.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/sv.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/th.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/tr.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hans.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hant.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/i18next-mcp.yaml +56 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lingo-dev.yaml +56 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lokalise.yaml +60 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/tolgee.yaml +60 -0
- package/dist/agents/skills/shared/i18n-knowledge/testing/locale-testing.yaml +107 -0
- package/dist/agents/skills/shared/i18n-knowledge/testing/pseudo-localization.yaml +86 -0
- package/dist/bin/harness.js +64 -4
- package/dist/{chunk-4WUGOJQ7.js → chunk-3JWCBVUZ.js} +1 -1
- package/dist/{chunk-FFIX3QVG.js → chunk-LNI4T7R6.js} +131 -41
- package/dist/{chunk-GA6GN5J2.js → chunk-SJECMKSS.js} +2244 -34
- package/dist/{dist-N4D4QWFV.js → dist-BDO5GFEM.js} +1 -1
- package/dist/{dist-C4J67MPP.js → dist-NT3GXHQZ.js} +95 -1
- package/dist/index.d.ts +187 -7
- package/dist/index.js +7 -3
- package/dist/validate-cross-check-2OPGCGGU.js +7 -0
- package/package.json +7 -7
- package/dist/validate-cross-check-WGXQ7K62.js +0 -7
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
locale: "ru"
|
|
2
|
+
name: "Russian"
|
|
3
|
+
native_name: "Русский"
|
|
4
|
+
script: "Cyrillic"
|
|
5
|
+
direction: ltr
|
|
6
|
+
cldr_plural_categories: [one, few, many, other]
|
|
7
|
+
expansion_factor: 1.25
|
|
8
|
+
script_characteristics:
|
|
9
|
+
avg_char_width: "standard"
|
|
10
|
+
requires_complex_shaping: false
|
|
11
|
+
line_break_rules: "standard"
|
|
12
|
+
number_format:
|
|
13
|
+
decimal_separator: ","
|
|
14
|
+
grouping_separator: "\u00A0"
|
|
15
|
+
grouping_size: 3
|
|
16
|
+
date_format:
|
|
17
|
+
short: "DD.MM.YYYY"
|
|
18
|
+
long: "DD Month YYYY g."
|
|
19
|
+
first_day_of_week: "monday"
|
|
20
|
+
common_pitfalls:
|
|
21
|
+
- pitfall: "Four plural forms with complex rules"
|
|
22
|
+
example: "1 файл, 2 файла, 5 файлов, 21 файл — the rule depends on the last two digits"
|
|
23
|
+
fix: "Use CLDR plural rules: one (1,21,31...), few (2-4,22-24...), many (5-20,25-30...), other (fractional)"
|
|
24
|
+
- pitfall: "Six grammatical cases affecting dynamic content"
|
|
25
|
+
example: "'Москва' changes form by case: Москвы (genitive), Москве (dative), Москву (accusative)"
|
|
26
|
+
fix: "Include case-inflected forms in translation strings; never try to programmatically decline Russian nouns"
|
|
27
|
+
- pitfall: "Cyrillic characters that look identical to Latin"
|
|
28
|
+
example: "Cyrillic 'а' (U+0430) looks like Latin 'a' (U+0061) but they are different characters"
|
|
29
|
+
fix: "Use Unicode-aware text comparison; visually identical Cyrillic/Latin chars cause search and auth issues"
|
|
30
|
+
- pitfall: "Number grouping with non-breaking space"
|
|
31
|
+
example: "1 000 000 not 1,000,000 — Russian uses non-breaking space as grouping separator"
|
|
32
|
+
fix: "Use Intl.NumberFormat('ru') for correct space-based number grouping"
|
|
33
|
+
- pitfall: "Abbreviated month and day names"
|
|
34
|
+
example: "Russian abbreviations follow different patterns than English — 'янв.' not 'Янв'"
|
|
35
|
+
fix: "Use Intl.DateTimeFormat('ru') for abbreviated date components; do not manually truncate month names"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
locale: "sv"
|
|
2
|
+
name: "Swedish"
|
|
3
|
+
native_name: "Svenska"
|
|
4
|
+
script: "Latin"
|
|
5
|
+
direction: ltr
|
|
6
|
+
cldr_plural_categories: [one, other]
|
|
7
|
+
expansion_factor: 1.10
|
|
8
|
+
script_characteristics:
|
|
9
|
+
avg_char_width: "narrow"
|
|
10
|
+
requires_complex_shaping: false
|
|
11
|
+
line_break_rules: "standard"
|
|
12
|
+
number_format:
|
|
13
|
+
decimal_separator: ","
|
|
14
|
+
grouping_separator: "\u00A0"
|
|
15
|
+
grouping_size: 3
|
|
16
|
+
date_format:
|
|
17
|
+
short: "YYYY-MM-DD"
|
|
18
|
+
long: "DD Month YYYY"
|
|
19
|
+
first_day_of_week: "monday"
|
|
20
|
+
common_pitfalls:
|
|
21
|
+
- pitfall: "Definite article suffixes changing word length"
|
|
22
|
+
example: "'hus' (house) becomes 'huset' (the house) — suffix adds characters unpredictably"
|
|
23
|
+
fix: "Account for suffix-based articles when estimating text length; Swedish words grow with definiteness"
|
|
24
|
+
- pitfall: "Special characters in sorting"
|
|
25
|
+
example: "Swedish alphabet ends with A, A, O — these sort AFTER Z, not with A and O"
|
|
26
|
+
fix: "Use locale-aware string comparison (Intl.Collator('sv')) for sorting Swedish text"
|
|
27
|
+
- pitfall: "ISO 8601 date format as default"
|
|
28
|
+
example: "Swedish natively uses YYYY-MM-DD (ISO 8601) — displaying DD/MM/YYYY feels foreign"
|
|
29
|
+
fix: "Use Intl.DateTimeFormat('sv') which correctly produces the ISO-style date format"
|
|
30
|
+
- pitfall: "Number grouping with space separator"
|
|
31
|
+
example: "Displaying 1,000 instead of 1 000 — Swedish uses non-breaking space as grouping separator"
|
|
32
|
+
fix: "Use Intl.NumberFormat('sv') for correct space-based number grouping"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
locale: "th"
|
|
2
|
+
name: "Thai"
|
|
3
|
+
native_name: "ภาษาไทย"
|
|
4
|
+
script: "Thai"
|
|
5
|
+
direction: ltr
|
|
6
|
+
cldr_plural_categories: [other]
|
|
7
|
+
expansion_factor: 1.15
|
|
8
|
+
script_characteristics:
|
|
9
|
+
avg_char_width: "standard"
|
|
10
|
+
requires_complex_shaping: true
|
|
11
|
+
line_break_rules: "dictionary"
|
|
12
|
+
number_format:
|
|
13
|
+
decimal_separator: "."
|
|
14
|
+
grouping_separator: ","
|
|
15
|
+
grouping_size: 3
|
|
16
|
+
date_format:
|
|
17
|
+
short: "DD/MM/YYYY"
|
|
18
|
+
long: "DD Month YYYY"
|
|
19
|
+
first_day_of_week: "sunday"
|
|
20
|
+
common_pitfalls:
|
|
21
|
+
- pitfall: "No spaces between words — dictionary-based line breaking required"
|
|
22
|
+
example: "Thai text runs words together without spaces; standard word-wrap fails completely"
|
|
23
|
+
fix: "Use ICU or dictionary-based word segmentation (Intl.Segmenter with granularity: 'word') for line breaking"
|
|
24
|
+
- pitfall: "Stacking diacritics above and below characters"
|
|
25
|
+
example: "Thai uses above-character vowels, tone marks, and below-character vowels — vertical space needed"
|
|
26
|
+
fix: "Increase line-height to at least 1.8 for Thai text to accommodate stacking diacritics"
|
|
27
|
+
- pitfall: "Thai digits vs Western digits"
|
|
28
|
+
example: "Thai has its own digit set (๐๑๒๓๔๕๖๗๘๙) but Western digits are common in digital contexts"
|
|
29
|
+
fix: "Default to Western digits for apps; Thai digits are used mainly in formal/traditional documents"
|
|
30
|
+
- pitfall: "Buddhist Era calendar year"
|
|
31
|
+
example: "Thai calendar year = Gregorian + 543, so 2025 CE = 2568 BE — some users expect BE years"
|
|
32
|
+
fix: "Use Intl.DateTimeFormat('th', {calendar: 'buddhist'}) when Buddhist Era dates are appropriate"
|
|
33
|
+
- pitfall: "Complex character composition affecting string operations"
|
|
34
|
+
example: "A visual Thai 'character' may be composed of multiple Unicode code points (base + vowel + tone)"
|
|
35
|
+
fix: "Use grapheme cluster-aware string operations; never split Thai text by code point or char index"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
locale: "tr"
|
|
2
|
+
name: "Turkish"
|
|
3
|
+
native_name: "Türkçe"
|
|
4
|
+
script: "Latin"
|
|
5
|
+
direction: ltr
|
|
6
|
+
cldr_plural_categories: [one, other]
|
|
7
|
+
expansion_factor: 1.20
|
|
8
|
+
script_characteristics:
|
|
9
|
+
avg_char_width: "narrow"
|
|
10
|
+
requires_complex_shaping: false
|
|
11
|
+
line_break_rules: "standard"
|
|
12
|
+
number_format:
|
|
13
|
+
decimal_separator: ","
|
|
14
|
+
grouping_separator: "."
|
|
15
|
+
grouping_size: 3
|
|
16
|
+
date_format:
|
|
17
|
+
short: "DD.MM.YYYY"
|
|
18
|
+
long: "DD Month YYYY"
|
|
19
|
+
first_day_of_week: "monday"
|
|
20
|
+
common_pitfalls:
|
|
21
|
+
- pitfall: "Dotted vs dotless I — the most famous i18n bug"
|
|
22
|
+
example: "'istanbul'.toUpperCase() produces 'ISTANBUL' (ASCII I) instead of correct Turkish 'İSTANBUL' (İ, U+0130 Latin Capital Letter I With Dot Above)"
|
|
23
|
+
fix: "Always use locale-aware case conversion: toLocaleUpperCase('tr') and toLocaleLowerCase('tr')"
|
|
24
|
+
- pitfall: "Case-insensitive comparison breaking with Turkish locale"
|
|
25
|
+
example: "Comparing 'FILE' and 'file' with Turkish locale fails because I != i in Turkish"
|
|
26
|
+
fix: "Use locale-aware comparison (Intl.Collator) or normalize to a known locale for case-insensitive checks"
|
|
27
|
+
- pitfall: "Agglutinative grammar creating long words"
|
|
28
|
+
example: "'Avrupalilasamayanlardan' (from those who cannot be Europeanized) — suffixes stack"
|
|
29
|
+
fix: "Design for text expansion from suffix stacking; use CSS overflow-wrap: break-word for safety"
|
|
30
|
+
- pitfall: "Vowel harmony in suffixes"
|
|
31
|
+
example: "Suffixes change based on the last vowel: 'evde' (in the house) vs 'okulda' (in the school)"
|
|
32
|
+
fix: "Never programmatically append Turkish suffixes; always use translator-provided complete forms"
|
|
33
|
+
- pitfall: "Currency formatting for Turkish Lira"
|
|
34
|
+
example: "Turkish Lira symbol (₺) placement and number formatting must follow Turkish conventions"
|
|
35
|
+
fix: "Use Intl.NumberFormat('tr-TR', {style: 'currency', currency: 'TRY'}) for proper Lira formatting"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
locale: "zh-Hans"
|
|
2
|
+
name: "Chinese (Simplified)"
|
|
3
|
+
native_name: "简体中文"
|
|
4
|
+
script: "CJK"
|
|
5
|
+
direction: ltr
|
|
6
|
+
cldr_plural_categories: [other]
|
|
7
|
+
expansion_factor: 0.6
|
|
8
|
+
script_characteristics:
|
|
9
|
+
avg_char_width: "wide"
|
|
10
|
+
requires_complex_shaping: false
|
|
11
|
+
line_break_rules: "no-spaces"
|
|
12
|
+
cjk_width_handling: true
|
|
13
|
+
vertical_text_support: false
|
|
14
|
+
multiple_scripts: false
|
|
15
|
+
number_format:
|
|
16
|
+
decimal_separator: "."
|
|
17
|
+
grouping_separator: ","
|
|
18
|
+
grouping_size: 3
|
|
19
|
+
date_format:
|
|
20
|
+
short: "YYYY/MM/DD"
|
|
21
|
+
long: "YYYY年MM月DD日"
|
|
22
|
+
first_day_of_week: "sunday"
|
|
23
|
+
common_pitfalls:
|
|
24
|
+
- pitfall: "Text contraction causing UI elements to look empty"
|
|
25
|
+
example: "'Internationalization' (20 chars) becomes '国际化' (3 chars) — a 85% reduction"
|
|
26
|
+
fix: "Use min-width on buttons and containers to prevent them from collapsing with short CJK translations"
|
|
27
|
+
- pitfall: "No word spaces means no natural line breaks"
|
|
28
|
+
example: "A long Chinese sentence has no spaces — wrapping can break between any two characters"
|
|
29
|
+
fix: "Use CSS word-break: normal for CJK; browsers handle character-level breaking correctly by default"
|
|
30
|
+
- pitfall: "Confusing zh-Hans with zh-Hant"
|
|
31
|
+
example: "Showing traditional characters (繁體) to mainland China users who expect simplified (简体)"
|
|
32
|
+
fix: "Use explicit zh-Hans (simplified) vs zh-Hant (traditional) subtags; never use bare 'zh'"
|
|
33
|
+
- pitfall: "CJK punctuation width"
|
|
34
|
+
example: "Chinese uses full-width punctuation (。,!) not half-width (. , !) — affects text measurement"
|
|
35
|
+
fix: "Account for full-width punctuation in text width calculations and do not replace with ASCII equivalents"
|
|
36
|
+
- pitfall: "Font size minimum for CJK readability"
|
|
37
|
+
example: "Complex characters become illegible below 12px — strokes merge at small sizes"
|
|
38
|
+
fix: "Set minimum font size of 12px for CJK text; 14px is recommended for body text"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
locale: "zh-Hant"
|
|
2
|
+
name: "Chinese (Traditional)"
|
|
3
|
+
native_name: "繁體中文"
|
|
4
|
+
script: "CJK"
|
|
5
|
+
direction: ltr
|
|
6
|
+
cldr_plural_categories: [other]
|
|
7
|
+
expansion_factor: 0.6
|
|
8
|
+
script_characteristics:
|
|
9
|
+
avg_char_width: "wide"
|
|
10
|
+
requires_complex_shaping: false
|
|
11
|
+
line_break_rules: "no-spaces"
|
|
12
|
+
cjk_width_handling: true
|
|
13
|
+
vertical_text_support: true
|
|
14
|
+
multiple_scripts: false
|
|
15
|
+
number_format:
|
|
16
|
+
decimal_separator: "."
|
|
17
|
+
grouping_separator: ","
|
|
18
|
+
grouping_size: 3
|
|
19
|
+
date_format:
|
|
20
|
+
short: "YYYY/MM/DD"
|
|
21
|
+
long: "YYYY年MM月DD日"
|
|
22
|
+
first_day_of_week: "sunday"
|
|
23
|
+
common_pitfalls:
|
|
24
|
+
- pitfall: "Regional vocabulary differences (Taiwan vs Hong Kong vs Macau)"
|
|
25
|
+
example: "'Software' is '軟體' in Taiwan but '軟件' in Hong Kong — same script, different terms"
|
|
26
|
+
fix: "Support zh-Hant-TW and zh-Hant-HK as separate locales when targeting both markets"
|
|
27
|
+
- pitfall: "Automatic simplified-to-traditional conversion producing wrong characters"
|
|
28
|
+
example: "One simplified character may map to multiple traditional characters based on context"
|
|
29
|
+
fix: "Never use automated character conversion; commission proper traditional Chinese translations"
|
|
30
|
+
- pitfall: "More complex characters requiring larger minimum font size"
|
|
31
|
+
example: "Traditional characters have more strokes than simplified — 體 vs 体 — needing higher resolution"
|
|
32
|
+
fix: "Use minimum 13-14px for traditional Chinese body text to ensure stroke clarity"
|
|
33
|
+
- pitfall: "Mixed CJK and Latin text spacing"
|
|
34
|
+
example: "No space between Chinese and English words looks cramped: '使用GitHub' vs '使用 GitHub'"
|
|
35
|
+
fix: "Apply CSS text-autospace or insert thin spaces between CJK and Latin text runs programmatically"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: "i18next MCP"
|
|
2
|
+
description: "i18next-specific MCP server for project analysis, translation coverage reporting, key usage analysis, and namespace management"
|
|
3
|
+
mcp_server_id: "i18next-mcp"
|
|
4
|
+
source: "https://github.com/anthropics/i18next-mcp"
|
|
5
|
+
|
|
6
|
+
capabilities:
|
|
7
|
+
- name: "Project Analysis"
|
|
8
|
+
description: "Analyze i18next project structure, configuration, and translation file organization"
|
|
9
|
+
tools: ["analyze_project", "get_config", "list_namespaces"]
|
|
10
|
+
- name: "Translation Coverage"
|
|
11
|
+
description: "Report translation coverage per locale and namespace, identifying missing translations"
|
|
12
|
+
tools: ["get_coverage_report", "find_missing_translations", "find_unused_keys"]
|
|
13
|
+
- name: "Key Usage Analysis"
|
|
14
|
+
description: "Trace translation key usage in source code to find unused or missing keys"
|
|
15
|
+
tools: ["find_key_usage", "find_hardcoded_strings", "extract_keys"]
|
|
16
|
+
- name: "Namespace Management"
|
|
17
|
+
description: "Create, merge, and split translation namespaces"
|
|
18
|
+
tools: ["create_namespace", "merge_namespaces", "move_keys"]
|
|
19
|
+
|
|
20
|
+
when_to_use:
|
|
21
|
+
- scenario: "Project already using i18next that wants deeper translation insights"
|
|
22
|
+
reason: "i18next MCP understands i18next conventions (namespaces, pluralization suffixes, interpolation) natively"
|
|
23
|
+
- scenario: "Auditing an existing codebase for i18n completeness"
|
|
24
|
+
reason: "Key usage analysis finds hardcoded strings and unused translation keys without manual code review"
|
|
25
|
+
- scenario: "Refactoring translation file organization"
|
|
26
|
+
reason: "Namespace management tools help split large translation files or merge fragmented namespaces"
|
|
27
|
+
|
|
28
|
+
when_not_to_use:
|
|
29
|
+
- scenario: "Project using react-intl, vue-i18n, or other non-i18next frameworks"
|
|
30
|
+
reason: "i18next MCP tools are specific to i18next conventions and file structures"
|
|
31
|
+
- scenario: "Team needing full TMS capabilities (translator collaboration, review workflows)"
|
|
32
|
+
reason: "i18next MCP is a developer tool, not a TMS; use Tolgee or Lokalise for translator workflows"
|
|
33
|
+
|
|
34
|
+
integration_patterns:
|
|
35
|
+
- pattern: "Harness workflow with i18next MCP for translation audit"
|
|
36
|
+
description: "Use i18next MCP tools during the i18n assessment phase to analyze coverage and identify gaps"
|
|
37
|
+
config_example: |
|
|
38
|
+
// harness.config.json
|
|
39
|
+
{
|
|
40
|
+
"mcp": {
|
|
41
|
+
"servers": {
|
|
42
|
+
"i18next": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "@anthropic/i18next-mcp"],
|
|
45
|
+
"env": {
|
|
46
|
+
"I18NEXT_PROJECT_PATH": "."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
limitations:
|
|
54
|
+
- "Only supports i18next ecosystem; not compatible with other i18n frameworks"
|
|
55
|
+
- "Key extraction may miss dynamically constructed translation keys (t(`error.${code}`))"
|
|
56
|
+
- "Coverage reporting depends on consistent file structure matching the configured pattern"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: "Lingo.dev"
|
|
2
|
+
description: "AI-powered translation platform with brand voice consistency, multi-engine machine translation, and glossary management"
|
|
3
|
+
mcp_server_id: "lingo-dev-mcp"
|
|
4
|
+
source: "https://github.com/anthropics/lingo-dev-mcp"
|
|
5
|
+
|
|
6
|
+
capabilities:
|
|
7
|
+
- name: "Multi-Engine Machine Translation"
|
|
8
|
+
description: "Translate content using multiple AI/MT engines with quality comparison"
|
|
9
|
+
tools: ["translate_text", "translate_file", "batch_translate"]
|
|
10
|
+
- name: "Glossary Management"
|
|
11
|
+
description: "Manage terminology glossaries to ensure translation consistency"
|
|
12
|
+
tools: ["create_glossary_term", "list_glossary", "update_glossary_term"]
|
|
13
|
+
- name: "Brand Voice Consistency"
|
|
14
|
+
description: "Configure and enforce brand voice profiles for translations"
|
|
15
|
+
tools: ["set_brand_voice", "check_brand_consistency"]
|
|
16
|
+
- name: "Translation Memory"
|
|
17
|
+
description: "Leverage previously approved translations for consistency and cost savings"
|
|
18
|
+
tools: ["search_translation_memory", "add_to_translation_memory"]
|
|
19
|
+
|
|
20
|
+
when_to_use:
|
|
21
|
+
- scenario: "Team needs high-quality machine translation with terminology consistency"
|
|
22
|
+
reason: "Lingo.dev specializes in AI translation quality with glossary enforcement and brand voice"
|
|
23
|
+
- scenario: "Project has established brand terminology that must be preserved across languages"
|
|
24
|
+
reason: "Glossary management ensures product names, features, and key terms are translated consistently"
|
|
25
|
+
- scenario: "Rapid iteration with frequent string changes"
|
|
26
|
+
reason: "AI translation with translation memory enables fast turnaround without waiting for human translators"
|
|
27
|
+
|
|
28
|
+
when_not_to_use:
|
|
29
|
+
- scenario: "Content requiring certified or sworn translations (legal, medical)"
|
|
30
|
+
reason: "AI translation, even high quality, does not meet certification requirements for regulated content"
|
|
31
|
+
- scenario: "Team prefers full human translation workflow"
|
|
32
|
+
reason: "Lingo.dev's value proposition centers on AI translation; pure human workflows are better served by a traditional TMS"
|
|
33
|
+
|
|
34
|
+
integration_patterns:
|
|
35
|
+
- pattern: "Harness workflow with Lingo.dev for rapid translation"
|
|
36
|
+
description: "Use Lingo.dev MCP tools to translate new strings immediately, then queue for human review"
|
|
37
|
+
config_example: |
|
|
38
|
+
// harness.config.json
|
|
39
|
+
{
|
|
40
|
+
"mcp": {
|
|
41
|
+
"servers": {
|
|
42
|
+
"lingo-dev": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "@anthropic/lingo-dev-mcp"],
|
|
45
|
+
"env": {
|
|
46
|
+
"LINGO_API_KEY": "<your-api-key>"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
limitations:
|
|
54
|
+
- "AI translation quality varies by language pair; low-resource languages may have lower quality"
|
|
55
|
+
- "Brand voice enforcement requires initial setup and training on existing approved translations"
|
|
56
|
+
- "Translation memory benefits increase over time; initial runs have no prior context"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: "Lokalise"
|
|
2
|
+
description: "Enterprise translation management system with team collaboration, branching, QA checks, and extensive integration ecosystem"
|
|
3
|
+
mcp_server_id: "lokalise-mcp"
|
|
4
|
+
source: "https://github.com/anthropics/lokalise-mcp"
|
|
5
|
+
|
|
6
|
+
capabilities:
|
|
7
|
+
- name: "Key Management"
|
|
8
|
+
description: "Create, update, delete, and filter translation keys with tags and platform labels"
|
|
9
|
+
tools: ["create_key", "update_key", "delete_key", "list_keys", "bulk_update_keys"]
|
|
10
|
+
- name: "File Operations"
|
|
11
|
+
description: "Upload source files and download translated files in any format"
|
|
12
|
+
tools: ["upload_file", "download_files", "list_files"]
|
|
13
|
+
- name: "Task Management"
|
|
14
|
+
description: "Create and manage translation tasks for team members and external translators"
|
|
15
|
+
tools: ["create_task", "list_tasks", "complete_task"]
|
|
16
|
+
- name: "Branching"
|
|
17
|
+
description: "Create and merge translation branches aligned with code branches"
|
|
18
|
+
tools: ["create_branch", "merge_branch", "list_branches"]
|
|
19
|
+
- name: "QA Checks"
|
|
20
|
+
description: "Run automated quality assurance checks on translations (placeholders, length, glossary)"
|
|
21
|
+
tools: ["run_qa_checks", "get_qa_results"]
|
|
22
|
+
|
|
23
|
+
when_to_use:
|
|
24
|
+
- scenario: "Larger team with multiple translators and complex review workflows"
|
|
25
|
+
reason: "Lokalise excels at team collaboration with task assignment, review stages, and comments"
|
|
26
|
+
- scenario: "Project with release branching that needs translation branching to match"
|
|
27
|
+
reason: "Lokalise's branching model maps to git branches, keeping translations in sync with code releases"
|
|
28
|
+
- scenario: "Enterprise requiring SOC 2 compliance and uptime SLA"
|
|
29
|
+
reason: "Lokalise offers enterprise security certifications and guaranteed uptime SLAs"
|
|
30
|
+
|
|
31
|
+
when_not_to_use:
|
|
32
|
+
- scenario: "Small team or solo developer with simple translation needs"
|
|
33
|
+
reason: "Lokalise's enterprise features add complexity; simpler tools like Tolgee may be more appropriate"
|
|
34
|
+
- scenario: "Team wanting self-hosted translation infrastructure"
|
|
35
|
+
reason: "Lokalise is cloud-only; use Tolgee or Weblate for self-hosted requirements"
|
|
36
|
+
|
|
37
|
+
integration_patterns:
|
|
38
|
+
- pattern: "Harness workflow with Lokalise for enterprise translation management"
|
|
39
|
+
description: "Use Lokalise MCP tools to sync translation keys with code changes, create tasks for translators, and download completed translations"
|
|
40
|
+
config_example: |
|
|
41
|
+
// harness.config.json
|
|
42
|
+
{
|
|
43
|
+
"mcp": {
|
|
44
|
+
"servers": {
|
|
45
|
+
"lokalise": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["-y", "@anthropic/lokalise-mcp"],
|
|
48
|
+
"env": {
|
|
49
|
+
"LOKALISE_API_TOKEN": "<your-api-token>",
|
|
50
|
+
"LOKALISE_PROJECT_ID": "<your-project-id>"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
limitations:
|
|
58
|
+
- "Per-seat pricing can be expensive for large teams"
|
|
59
|
+
- "API rate limits may affect large batch operations via MCP"
|
|
60
|
+
- "Branch merging requires manual conflict resolution for overlapping translations"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: "Tolgee"
|
|
2
|
+
description: "Open-source translation management system with in-context editing, AI translation, and comprehensive MCP server exposing 59 tools"
|
|
3
|
+
mcp_server_id: "tolgee-mcp"
|
|
4
|
+
source: "https://github.com/tolgee/tolgee-mcp"
|
|
5
|
+
|
|
6
|
+
capabilities:
|
|
7
|
+
- name: "Project Management"
|
|
8
|
+
description: "Create, list, and manage translation projects"
|
|
9
|
+
tools: ["create_project", "list_projects", "get_project"]
|
|
10
|
+
- name: "Key Management"
|
|
11
|
+
description: "Create, update, delete, and search translation keys with namespace support"
|
|
12
|
+
tools: ["create_key", "update_key", "delete_key", "search_keys", "import_keys"]
|
|
13
|
+
- name: "Translation Operations"
|
|
14
|
+
description: "Get, set, and batch-update translations per locale"
|
|
15
|
+
tools: ["get_translations", "set_translation", "batch_set_translations"]
|
|
16
|
+
- name: "Screenshot Management"
|
|
17
|
+
description: "Upload and manage screenshots linked to translation keys for translator context"
|
|
18
|
+
tools: ["upload_screenshot", "get_screenshots", "delete_screenshot"]
|
|
19
|
+
- name: "Import/Export"
|
|
20
|
+
description: "Import and export translation files in various formats (JSON, XLIFF, PO, etc.)"
|
|
21
|
+
tools: ["import_file", "export_translations"]
|
|
22
|
+
|
|
23
|
+
when_to_use:
|
|
24
|
+
- scenario: "Team wants a self-hosted TMS with developer-friendly workflow"
|
|
25
|
+
reason: "Tolgee can be self-hosted (Docker) and provides in-context editing for developers to see translations in the actual UI"
|
|
26
|
+
- scenario: "Project needs AI-assisted translation with human review"
|
|
27
|
+
reason: "Tolgee integrates AI translation providers while maintaining a human review workflow"
|
|
28
|
+
- scenario: "Small to medium team without budget for enterprise TMS"
|
|
29
|
+
reason: "Open-source core with generous free tier; self-hosting eliminates per-seat costs"
|
|
30
|
+
|
|
31
|
+
when_not_to_use:
|
|
32
|
+
- scenario: "Enterprise requiring SOC 2 compliance and SLA guarantees"
|
|
33
|
+
reason: "Self-hosted requires managing your own infrastructure and compliance; Tolgee Cloud has fewer enterprise certifications than Lokalise"
|
|
34
|
+
- scenario: "Project with complex branching/versioning workflows"
|
|
35
|
+
reason: "Tolgee's branching support is less mature than Lokalise or Crowdin for complex release management"
|
|
36
|
+
|
|
37
|
+
integration_patterns:
|
|
38
|
+
- pattern: "Harness workflow with Tolgee MCP for key management"
|
|
39
|
+
description: "Use Tolgee MCP tools during the i18n audit phase to check translation coverage and create missing keys"
|
|
40
|
+
config_example: |
|
|
41
|
+
// harness.config.json
|
|
42
|
+
{
|
|
43
|
+
"mcp": {
|
|
44
|
+
"servers": {
|
|
45
|
+
"tolgee": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["-y", "@anthropic/tolgee-mcp"],
|
|
48
|
+
"env": {
|
|
49
|
+
"TOLGEE_API_URL": "https://app.tolgee.io",
|
|
50
|
+
"TOLGEE_API_KEY": "<your-api-key>"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
limitations:
|
|
58
|
+
- "59 MCP tools may cause token overhead in LLM context; consider filtering to used capabilities"
|
|
59
|
+
- "Self-hosted instance requires Docker and PostgreSQL infrastructure"
|
|
60
|
+
- "In-context editing SDK adds bundle size to the frontend application"
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
description: "Locale testing techniques — systematic approaches to verify i18n correctness across real locales"
|
|
2
|
+
|
|
3
|
+
techniques:
|
|
4
|
+
- name: "Functional testing per locale"
|
|
5
|
+
description: "Run functional test suites with different locale configurations to verify locale-dependent behavior"
|
|
6
|
+
catches:
|
|
7
|
+
- "Form submission failures with locale-formatted input (commas vs periods in numbers)"
|
|
8
|
+
- "Date picker displaying wrong format or first day of week"
|
|
9
|
+
- "Number input rejecting valid locale-formatted values"
|
|
10
|
+
- "Sort order bugs with locale-specific collation"
|
|
11
|
+
implementation:
|
|
12
|
+
approach: "Parameterize functional tests with locale fixtures; run core user flows per locale"
|
|
13
|
+
tools: ["Playwright with locale option", "Cypress with cy.clock locale", "Jest with Intl mocks"]
|
|
14
|
+
example: |
|
|
15
|
+
// Playwright locale-parameterized test
|
|
16
|
+
for (const locale of ['en-US', 'de-DE', 'ja-JP', 'ar-SA']) {
|
|
17
|
+
test(`checkout flow works in ${locale}`, async ({ browser }) => {
|
|
18
|
+
const context = await browser.newContext({ locale });
|
|
19
|
+
const page = await context.newPage();
|
|
20
|
+
// ... test checkout flow
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
when_to_use: "In CI pipeline for every PR that touches i18n-sensitive code"
|
|
24
|
+
automation: "Run locale matrix in CI: en-US (baseline), de-DE (expansion), ja-JP (CJK), ar-SA (RTL)"
|
|
25
|
+
|
|
26
|
+
- name: "Visual regression testing across locales"
|
|
27
|
+
description: "Capture screenshots per locale and compare against baselines to detect text overflow and layout shifts"
|
|
28
|
+
catches:
|
|
29
|
+
- "Text overflow from translation expansion"
|
|
30
|
+
- "RTL layout mirroring regressions"
|
|
31
|
+
- "Font rendering differences across locales"
|
|
32
|
+
- "Container height changes from multi-line wrapping"
|
|
33
|
+
implementation:
|
|
34
|
+
approach: "Run visual regression tool with locale-specific baselines; flag visual differences above threshold"
|
|
35
|
+
tools: ["Playwright screenshot comparison", "Percy", "Chromatic", "BackstopJS"]
|
|
36
|
+
example: |
|
|
37
|
+
// Capture screenshots for visual comparison
|
|
38
|
+
for (const locale of ['en', 'de', 'ar', 'ja']) {
|
|
39
|
+
await page.goto(`/?locale=${locale}`);
|
|
40
|
+
await expect(page).toHaveScreenshot(`homepage-${locale}.png`);
|
|
41
|
+
}
|
|
42
|
+
when_to_use: "In CI for PRs that touch layout, typography, or translation files"
|
|
43
|
+
automation: "Maintain per-locale visual baselines; auto-update baselines when translations change"
|
|
44
|
+
|
|
45
|
+
- name: "Boundary locale testing"
|
|
46
|
+
description: "Test with the most extreme locales to find edge cases: longest translations, most plural forms, RTL"
|
|
47
|
+
catches:
|
|
48
|
+
- "Worst-case text expansion overflow (German/Finnish)"
|
|
49
|
+
- "Complex pluralization bugs (Arabic with 6 forms)"
|
|
50
|
+
- "Bidi rendering issues (Arabic RTL)"
|
|
51
|
+
- "CJK-specific line breaking and width issues (Japanese)"
|
|
52
|
+
implementation:
|
|
53
|
+
approach: "Select boundary locales that represent extremes: de (long), fi (longest), ar (RTL + 6 plurals), ja (CJK)"
|
|
54
|
+
tools: ["Any test framework with locale configuration"]
|
|
55
|
+
example: |
|
|
56
|
+
// Boundary locale set for maximum coverage
|
|
57
|
+
const BOUNDARY_LOCALES = {
|
|
58
|
+
'de': 'Longest Western European text expansion',
|
|
59
|
+
'fi': 'Extreme expansion with agglutinative grammar',
|
|
60
|
+
'ar': 'RTL + 6 plural forms + letter reshaping',
|
|
61
|
+
'ja': 'CJK no-space + multiple scripts + contraction',
|
|
62
|
+
'th': 'Dictionary-based line breaking + stacking diacritics',
|
|
63
|
+
};
|
|
64
|
+
when_to_use: "For every release; as smoke test in CI for i18n-related changes"
|
|
65
|
+
automation: "Run boundary locale tests as a required CI check; block release if any boundary locale fails"
|
|
66
|
+
|
|
67
|
+
- name: "Input method testing"
|
|
68
|
+
description: "Test text input with locale-specific input methods (CJK IME, Arabic keyboard, Devanagari input)"
|
|
69
|
+
catches:
|
|
70
|
+
- "IME composition events not handled (text appears garbled during CJK input)"
|
|
71
|
+
- "Keyboard layout assumptions (QWERTY vs AZERTY vs others)"
|
|
72
|
+
- "Input field not accepting non-Latin characters"
|
|
73
|
+
- "Search and filter not working with IME-composed text"
|
|
74
|
+
implementation:
|
|
75
|
+
approach: "Use Playwright's keyboard IME simulation or manual testing with actual input methods"
|
|
76
|
+
tools: ["Playwright keyboard API", "BrowserStack with device keyboards", "manual testing with OS IME"]
|
|
77
|
+
example: |
|
|
78
|
+
// Test CJK IME input in Playwright
|
|
79
|
+
await page.locator('input[name="search"]').click();
|
|
80
|
+
await page.keyboard.imeSetComposition('にほん', 3, 3);
|
|
81
|
+
await page.keyboard.imeCommit();
|
|
82
|
+
// Verify search results include Japanese text
|
|
83
|
+
when_to_use: "Before releasing to CJK, Arabic, or Devanagari markets; for search and text input features"
|
|
84
|
+
automation: "Include IME input tests in smoke test suite for markets with non-Latin input methods"
|
|
85
|
+
|
|
86
|
+
- name: "Locale switching testing"
|
|
87
|
+
description: "Test runtime locale change without page reload to verify all components update correctly"
|
|
88
|
+
catches:
|
|
89
|
+
- "Components that cache translated text and do not re-render on locale change"
|
|
90
|
+
- "Date/number formatters that initialize once and do not update"
|
|
91
|
+
- "Stale translations in error messages or toast notifications"
|
|
92
|
+
- "Layout direction not updating when switching between LTR and RTL locales"
|
|
93
|
+
implementation:
|
|
94
|
+
approach: "Switch locale at runtime and verify all visible text, formatting, and layout update"
|
|
95
|
+
tools: ["Framework-specific locale switching API", "Playwright for E2E verification"]
|
|
96
|
+
example: |
|
|
97
|
+
// Test locale switching
|
|
98
|
+
await page.click('[data-testid="language-selector"]');
|
|
99
|
+
await page.click('[data-value="ar"]');
|
|
100
|
+
// Verify RTL layout applied
|
|
101
|
+
const dir = await page.getAttribute('html', 'dir');
|
|
102
|
+
expect(dir).toBe('rtl');
|
|
103
|
+
// Verify translated content
|
|
104
|
+
const heading = await page.textContent('h1');
|
|
105
|
+
expect(heading).toMatch(/[\u0600-\u06FF]/); // Arabic characters
|
|
106
|
+
when_to_use: "When the app supports runtime locale switching; after changes to locale provider or context"
|
|
107
|
+
automation: "Include locale switching in E2E test suite; test switching from LTR to RTL and back"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
description: "Pseudo-localization testing techniques — automated methods to detect i18n issues without real translations"
|
|
2
|
+
|
|
3
|
+
techniques:
|
|
4
|
+
- name: "Accent character replacement"
|
|
5
|
+
description: "Replace ASCII characters with accented Unicode equivalents (a to a, e to e, etc.) to simulate translated text"
|
|
6
|
+
catches:
|
|
7
|
+
- "Hardcoded strings missed by extraction tools (they remain in plain ASCII)"
|
|
8
|
+
- "Character encoding issues (accented characters display as mojibake)"
|
|
9
|
+
- "Font coverage gaps (missing glyphs for accented characters)"
|
|
10
|
+
- "String comparison bugs (accented versions fail equality checks)"
|
|
11
|
+
implementation:
|
|
12
|
+
approach: "Transform each ASCII letter to its accented equivalent using a lookup table"
|
|
13
|
+
tools: ["pseudo-localization (npm)", "@formatjs/cli --pseudo-locale xx-AC"]
|
|
14
|
+
example: |
|
|
15
|
+
// Input: "Hello, World!"
|
|
16
|
+
// Output: "[Ĥéĺĺö, Ŵöŕĺð!]"
|
|
17
|
+
import { pseudoLocalize } from 'pseudo-localization';
|
|
18
|
+
const pseudo = pseudoLocalize('Hello, World!');
|
|
19
|
+
when_to_use: "During development, before real translations are available"
|
|
20
|
+
automation: "Generate pseudo-locale as part of the build pipeline; run visual regression tests against it"
|
|
21
|
+
|
|
22
|
+
- name: "Text expansion padding"
|
|
23
|
+
description: "Add extra characters to simulate the text expansion that occurs in verbose languages (German, Finnish)"
|
|
24
|
+
catches:
|
|
25
|
+
- "Fixed-width layout overflow"
|
|
26
|
+
- "Text truncation in buttons, labels, and navigation"
|
|
27
|
+
- "Container height overflow from multi-line wrapping"
|
|
28
|
+
- "Tooltip and popup sizing issues"
|
|
29
|
+
implementation:
|
|
30
|
+
approach: "Pad translated strings with repeated characters to simulate 35-40% expansion"
|
|
31
|
+
tools: ["pseudo-localization (npm)", "custom expansion generator"]
|
|
32
|
+
example: |
|
|
33
|
+
// Input: "Settings" (8 chars)
|
|
34
|
+
// Output with 35% expansion: "Settingsxxx" (11 chars)
|
|
35
|
+
// Realistic: "[Séţţîñĝšxxxxx]" (accent + expansion)
|
|
36
|
+
when_to_use: "Before UI review; especially before locking down layout dimensions"
|
|
37
|
+
automation: "Include expansion pseudo-locale in visual regression test suite"
|
|
38
|
+
|
|
39
|
+
- name: "Bracket wrapping"
|
|
40
|
+
description: "Wrap each translated string with brackets [like this] to reveal concatenation boundaries"
|
|
41
|
+
catches:
|
|
42
|
+
- "String concatenation (brackets break across concatenation: '[Hello, ][World!]' instead of '[Hello, World!]')"
|
|
43
|
+
- "Strings assembled from multiple translation calls"
|
|
44
|
+
- "Missing translations (bracketed strings are visually distinct)"
|
|
45
|
+
implementation:
|
|
46
|
+
approach: "Prepend '[' and append ']' to every translated string"
|
|
47
|
+
tools: ["pseudo-localization (npm)", "custom i18next post-processor"]
|
|
48
|
+
example: |
|
|
49
|
+
// Correct: "[Hello, World!]"
|
|
50
|
+
// Concatenation bug: "[Hello, ]" + "[World!]"
|
|
51
|
+
// The broken brackets reveal the concatenation point
|
|
52
|
+
when_to_use: "During string extraction audit; verifying all strings go through translation pipeline"
|
|
53
|
+
automation: "Enable bracket wrapping in development/staging environments as a QA overlay"
|
|
54
|
+
|
|
55
|
+
- name: "Mirror/bidi simulation"
|
|
56
|
+
description: "Reverse text direction to simulate RTL layout without needing a real RTL locale"
|
|
57
|
+
catches:
|
|
58
|
+
- "Layout mirroring issues (margins, padding, flex direction)"
|
|
59
|
+
- "Icon placement that should or should not mirror"
|
|
60
|
+
- "CSS left/right vs logical properties usage"
|
|
61
|
+
- "Mixed-direction text rendering problems"
|
|
62
|
+
implementation:
|
|
63
|
+
approach: "Apply dir='rtl' to the document and reverse string characters for visual simulation"
|
|
64
|
+
tools: ["@formatjs/cli --pseudo-locale xx-HA", "Android ar-XB pseudolocale"]
|
|
65
|
+
example: |
|
|
66
|
+
// Input: "Hello, World!"
|
|
67
|
+
// Output: "!dlroW ,olleH" (reversed for visual RTL simulation)
|
|
68
|
+
// Combined with accent: "[!ðĺŕöŴ ,öĺĺéĤ]"
|
|
69
|
+
when_to_use: "Before adding RTL locale support; during RTL layout review"
|
|
70
|
+
automation: "Include bidi pseudo-locale in visual regression tests alongside standard pseudo-locale"
|
|
71
|
+
|
|
72
|
+
- name: "Placeholder preservation verification"
|
|
73
|
+
description: "Verify that interpolation placeholders ({variable}, {{variable}}, %s) survive pseudo-localization intact"
|
|
74
|
+
catches:
|
|
75
|
+
- "Broken interpolation from accent-replacing characters inside placeholders"
|
|
76
|
+
- "Format string corruption from text transformation"
|
|
77
|
+
- "Missing placeholder values at runtime"
|
|
78
|
+
implementation:
|
|
79
|
+
approach: "Pseudo-localize text while preserving content inside interpolation markers"
|
|
80
|
+
tools: ["pseudo-localization (npm) with placeholder regex", "custom preserving transformer"]
|
|
81
|
+
example: |
|
|
82
|
+
// Input: "Hello, {name}! You have {count} items."
|
|
83
|
+
// Correct: "[Ĥéĺĺö, {name}! Ýöû ĥàvé {count} îţéḿš.]"
|
|
84
|
+
// Wrong: "[Ĥéĺĺö, {ñàḿé}! Ýöû ĥàvé {çöûñţ} îţéḿš.]"
|
|
85
|
+
when_to_use: "When configuring pseudo-localization pipeline; validating custom pseudo generators"
|
|
86
|
+
automation: "Add unit test that pseudo-localizes all messages and verifies placeholders are preserved"
|