cfsa-antigravity 2.15.0 → 2.18.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/package.json +1 -1
- package/template/.agent/kit-sync.md +3 -3
- package/template/.agent/rules/source-before-ask.md +93 -0
- package/template/.agent/rules/vertical-slices.md +46 -8
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +251 -73
- package/template/.agent/skill-library/surface/web/i18n-localization/references/icu-message-format.md +223 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/references/intl-api-patterns.md +326 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/references/rtl-support.md +298 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +1 -1
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +32 -17
- package/template/.agent/skills/prd-templates/references/gate-applicability.md +92 -0
- package/template/.agent/skills/prd-templates/references/map-guard-protocol.md +34 -13
- package/template/.agent/skills/prd-templates/references/shard-boundary-analysis.md +1 -1
- package/template/.agent/skills/prd-templates/references/shard-split-remediation.md +163 -0
- package/template/.agent/skills/prd-templates/references/workflow-checkpoint-protocol.md +112 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +235 -19
- package/template/.agent/workflows/bootstrap-agents-fill.md +4 -4
- package/template/.agent/workflows/bootstrap-agents.md +4 -0
- package/template/.agent/workflows/create-prd-architecture.md +8 -3
- package/template/.agent/workflows/create-prd-compile.md +6 -0
- package/template/.agent/workflows/create-prd-design-system.md +18 -4
- package/template/.agent/workflows/create-prd-security.md +8 -3
- package/template/.agent/workflows/create-prd-stack.md +47 -35
- package/template/.agent/workflows/create-prd.md +8 -3
- package/template/.agent/workflows/decompose-architecture-structure.md +5 -3
- package/template/.agent/workflows/decompose-architecture-validate.md +1 -1
- package/template/.agent/workflows/remediate-shard-split.md +201 -0
- package/template/.agent/workflows/validate-phase-readiness.md +42 -61
- package/template/.agent/workflows/write-architecture-spec-design.md +1 -1
- package/template/AGENTS.md +3 -1
- package/template/GEMINI.md +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Kit Sync State
|
|
2
2
|
|
|
3
3
|
upstream: https://github.com/RepairYourTech/cfsa-antigravity
|
|
4
|
-
last_synced_commit:
|
|
5
|
-
last_synced_at: 2026-03-
|
|
6
|
-
kit_version: 2.
|
|
4
|
+
last_synced_commit: a42ee2fd17830430d03da6a4a543039c37bb9213
|
|
5
|
+
last_synced_at: 2026-03-25T02:08:41Z
|
|
6
|
+
kit_version: 2.18.0
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Before any question or decision, reason about what source documents are relevant, read them, then speak — never ask from summaries alone
|
|
3
|
+
trigger: always_on
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Source Before Ask
|
|
7
|
+
|
|
8
|
+
> Never present a question, decision, or recommendation to the user without first reading the source documents that inform it. Feature names are not features. Summaries are not specs.
|
|
9
|
+
|
|
10
|
+
## The Rule
|
|
11
|
+
|
|
12
|
+
**Before presenting ANY question, decision, option table, or recommendation to the user:**
|
|
13
|
+
|
|
14
|
+
1. **Reason about relevance.** Ask yourself: "What domains, features, deep dives, CX files, or specs contain detail that affects THIS specific decision?" Think about second-order connections — a database decision doesn't just touch the "data" domain; it touches every domain that has complex query patterns, real-time sync, or graph relationships.
|
|
15
|
+
|
|
16
|
+
2. **Read those documents.** Not the summary. Not the index line. The actual source files that contain the architectural detail. If a domain has deep dives (`[DEEP]` or `[EXHAUSTED]` status), read the deep dive files — they contain the information that changes the answer.
|
|
17
|
+
|
|
18
|
+
3. **Cite what you found.** When presenting the question or decision, reference what you learned: "Based on the diagnostics deep dive, your multi-agent repair flow requires X, which means option A fits better than B because..."
|
|
19
|
+
|
|
20
|
+
4. **Only then ask.** Now you're asking an informed question that the user can answer without doing your research for you.
|
|
21
|
+
|
|
22
|
+
## The Per-Decision Research Loop
|
|
23
|
+
|
|
24
|
+
This loop fires for EVERY decision point, not once per workflow:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
For each question/decision/recommendation:
|
|
28
|
+
1. STOP — do not type anything to the user yet
|
|
29
|
+
2. THINK — what ideation/spec/CX content is relevant to THIS decision?
|
|
30
|
+
- Which domains does this decision affect?
|
|
31
|
+
- Which features have architectural constraints that change the answer?
|
|
32
|
+
- Which cross-cuts create dependencies?
|
|
33
|
+
- Which deep dives contain the detail I need?
|
|
34
|
+
3. READ — open and read those specific files now
|
|
35
|
+
4. SYNTHESIZE — what did I learn that affects this decision?
|
|
36
|
+
5. PRESENT — now ask the question, citing what you found
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Common Relevance Patterns
|
|
40
|
+
|
|
41
|
+
| Decision Type | What to Read Before Asking |
|
|
42
|
+
|--------------|---------------------------|
|
|
43
|
+
| Frontend framework | Every domain with UI complexity, responsive requirements, offline-first features, real-time updates |
|
|
44
|
+
| Database / persistence | Every domain with complex data relationships, sync requirements, search patterns, graph traversals |
|
|
45
|
+
| AI/ML framework | Every domain that mentions AI, ML, diagnostics, recommendations, automation, agents |
|
|
46
|
+
| Auth / security | Every domain's role matrix, CX files for cross-domain permission boundaries |
|
|
47
|
+
| API design | Every domain's CX files for cross-domain data flow, every deep dive with integration points |
|
|
48
|
+
| Deployment / hosting | Constraints file, every surface's performance requirements, offline capabilities |
|
|
49
|
+
| State management | Every domain with real-time features, collaborative editing, optimistic updates |
|
|
50
|
+
| Caching strategy | Every domain's query patterns, hot paths, data freshness requirements |
|
|
51
|
+
|
|
52
|
+
## Why
|
|
53
|
+
|
|
54
|
+
| Without this rule | With this rule |
|
|
55
|
+
|---|---|
|
|
56
|
+
| Agent asks "which database?" based on a MoSCoW bullet | Agent reads the graph traversal deep dive and knows you need a graph-capable store |
|
|
57
|
+
| User has to say "go read the docs" 15 times per session | Agent arrives at each question already informed |
|
|
58
|
+
| Decisions feel generic — could apply to any project | Decisions are grounded in YOUR project's specific architecture |
|
|
59
|
+
| Context evaporates after Step 0.5's bulk loading | Context is refreshed per-decision, exactly when it matters |
|
|
60
|
+
| Agent asks questions the ideation already answered | Agent knows what's been decided and asks only what's open |
|
|
61
|
+
|
|
62
|
+
## Applies To
|
|
63
|
+
|
|
64
|
+
**Every pipeline stage.** This is not limited to `/create-prd`:
|
|
65
|
+
|
|
66
|
+
| Stage | What This Means |
|
|
67
|
+
|-------|----------------|
|
|
68
|
+
| `/create-prd-stack` | Before each axis question, read the domains that axis touches |
|
|
69
|
+
| `/create-prd-architecture` | Before each component design, read the domains that component serves |
|
|
70
|
+
| `/create-prd-security` | Before each security item, read the role matrices and CX trust boundaries |
|
|
71
|
+
| `/write-architecture-spec` | Before each interaction design, read the relevant domain deep dives |
|
|
72
|
+
| `/write-be-spec` | Before each endpoint design, read the IA shard interactions that endpoint serves |
|
|
73
|
+
| `/write-fe-spec` | Before each component spec, read the BE endpoints and IA interactions it consumes |
|
|
74
|
+
| `/implement-slice` | Before each implementation decision, read the relevant specs |
|
|
75
|
+
|
|
76
|
+
## What Gets Flagged
|
|
77
|
+
|
|
78
|
+
| Pattern | Verdict |
|
|
79
|
+
|---------|---------|
|
|
80
|
+
| "Which database do you prefer?" without reading any domain files | ❌ Rejected. Read the domains first — the answer might be obvious. |
|
|
81
|
+
| Presenting 3 framework options with generic pros/cons | ❌ Rejected. Pros/cons must reference THIS project's specific needs. |
|
|
82
|
+
| Asking a question the ideation deep dives already answered | ❌ Rejected. Read before asking. |
|
|
83
|
+
| "Based on your diagnostics domain's multi-agent flow, you need X" | ✅ Correct. Informed by source material. |
|
|
84
|
+
| Citing specific CX dependencies when recommending architecture | ✅ Correct. Research before recommendation. |
|
|
85
|
+
| Re-reading a deep dive mid-workflow because THIS question needs it | ✅ Correct. Per-decision freshness. |
|
|
86
|
+
|
|
87
|
+
## The Litmus Test
|
|
88
|
+
|
|
89
|
+
Before sending any question to the user, ask yourself:
|
|
90
|
+
|
|
91
|
+
> **"Could a user reasonably respond: 'Did you even read my ideation docs?'"**
|
|
92
|
+
|
|
93
|
+
If the answer is yes — you didn't do this rule. Stop. Read. Then ask.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Features ship across all
|
|
2
|
+
description: Features ship across all declared surfaces or they don't ship — no half-built slices
|
|
3
3
|
trigger: always_on
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -9,6 +9,36 @@ trigger: always_on
|
|
|
9
9
|
|
|
10
10
|
**A feature is not "done" until it works across all required surfaces.** No "backend done, frontend pending." No "user-facing works, admin can't manage it."
|
|
11
11
|
|
|
12
|
+
## Surface Scope
|
|
13
|
+
|
|
14
|
+
Every slice **must declare its surface scope** during `/plan-phase`. The surface scope defines which project surfaces (web, mobile, desktop, CLI, etc.) the slice targets. The 4-layer checklist applies **within each declared surface**, not globally across all surfaces.
|
|
15
|
+
|
|
16
|
+
### Why Surface Scope Exists
|
|
17
|
+
|
|
18
|
+
Multi-surface projects have features that are inherently single-surface:
|
|
19
|
+
- A board-level component viewer is **desktop only** — forcing a web and mobile implementation violates the architecture
|
|
20
|
+
- Push notifications are **mobile only** — there's no web surface for this feature
|
|
21
|
+
- Some features launch **web-first** and port to desktop/mobile in later phases
|
|
22
|
+
|
|
23
|
+
Surface scope prevents both failure modes:
|
|
24
|
+
- ❌ **Under-scoping** — "backend done, frontend pending" within a declared surface
|
|
25
|
+
- ❌ **Over-scoping** — forcing all surfaces when the architecture says otherwise
|
|
26
|
+
|
|
27
|
+
### Surface Scope Rules
|
|
28
|
+
|
|
29
|
+
1. **Every slice must declare its surface scope** during `/plan-phase`. No implicit scope — undeclared scope is rejected.
|
|
30
|
+
2. **The 4-layer checklist applies within each declared surface.** A web-only slice must have all 4 layers complete for web. A desktop+mobile slice must have all 4 layers complete for both desktop and mobile.
|
|
31
|
+
3. **Surface scope comes from the architecture**, not from convenience. If the architecture says a feature spans web and mobile, the slice must cover both (or be split into "web" and "mobile" slices with an explicit dependency).
|
|
32
|
+
4. **Scope is locked at planning time.** Changing surface scope mid-implementation requires updating the phase plan — no silent scope reduction.
|
|
33
|
+
|
|
34
|
+
### Web-First (or Surface-First) Strategy
|
|
35
|
+
|
|
36
|
+
When a multi-surface feature launches on one surface first:
|
|
37
|
+
- The first-surface slice is "done" when its 4 layers are complete within its declared scope
|
|
38
|
+
- Ports to other surfaces are tracked as **separate dependent slices** in the phase plan
|
|
39
|
+
- Each port slice has its own 4-layer checklist and its own surface scope declaration
|
|
40
|
+
- Example: "User Profile — Web" (Phase 1) → "User Profile — Mobile" (Phase 2, depends on Web slice)
|
|
41
|
+
|
|
12
42
|
## The Four Implementation Layers
|
|
13
43
|
|
|
14
44
|
> **Note on terminology**: The layers below describe implementation completeness criteria — what every feature slice requires regardless of surface type. These are not the same as surface types (web/mobile/cli/etc.). For the mapping between surface types and how each implementation layer manifests on that surface, see `.agent/skills/prd-templates/references/surface-model.md`.
|
|
@@ -24,22 +54,30 @@ trigger: always_on
|
|
|
24
54
|
|
|
25
55
|
A feature slice is complete when:
|
|
26
56
|
|
|
27
|
-
- [ ]
|
|
28
|
-
- [ ]
|
|
29
|
-
- [ ]
|
|
30
|
-
- [ ]
|
|
57
|
+
- [ ] Surface scope declared in the phase plan (explicit list of target surfaces)
|
|
58
|
+
- [ ] **For each declared surface:**
|
|
59
|
+
- [ ] Data layer: schema defined, permissions set, seed data exists
|
|
60
|
+
- [ ] API layer: endpoints exist, validated with {{CONTRACT_LIBRARY}}, tested
|
|
61
|
+
- [ ] User-facing: component renders, handles loading/error/empty states
|
|
62
|
+
- [ ] Admin: can create/read/update/delete the resource (if the feature has admin management)
|
|
31
63
|
- [ ] Tests pass at all levels (contract, unit, integration, E2E)
|
|
32
64
|
- [ ] Navigation: every new route is reachable from at least one navigation element
|
|
33
65
|
- [ ] Auth gates: every route that requires auth has the auth gate implemented (not stubbed)
|
|
34
66
|
- [ ] The feature is reachable from the app's entry point via normal user navigation
|
|
67
|
+
- [ ] All declared surfaces complete — no partial surface delivery
|
|
35
68
|
|
|
36
69
|
## What Gets Flagged
|
|
37
70
|
|
|
38
71
|
| Pattern | Verdict |
|
|
39
72
|
|---------|---------|
|
|
40
|
-
|
|
|
41
|
-
| "
|
|
73
|
+
| Slice with no declared surface scope | ❌ Rejected. Every slice must declare its surfaces during `/plan-phase`. |
|
|
74
|
+
| "I'll add the admin panel later" | ❌ Rejected. Include admin CRUD in the slice (for features with admin management). |
|
|
75
|
+
| "The API works, frontend next sprint" (within same surface) | ❌ Rejected. Ship them together or not at all. |
|
|
42
76
|
| "Database is set up, just need endpoints" | ❌ Rejected. That's a layer, not a slice. |
|
|
43
77
|
| Route without navigation link from existing UI | ❌ Rejected. Must be reachable. |
|
|
44
78
|
| Auth-required route without auth gate | ❌ Rejected. Implement the gate. |
|
|
45
|
-
|
|
|
79
|
+
| Desktop-only feature forced to have a web implementation | ❌ Rejected. Surface scope should match the architecture. |
|
|
80
|
+
| Silently dropping a declared surface mid-implementation | ❌ Rejected. Update the phase plan or complete the surface. |
|
|
81
|
+
| Web-first slice with all 4 layers complete for web, mobile tracked as separate slice | ✅ Correct. Surface-first strategy. |
|
|
82
|
+
| Slice with declared scope and all layers complete within scope | ✅ Correct. |
|
|
83
|
+
| All declared surfaces + tests + navigation + auth gates | ✅ Correct. |
|
|
@@ -1,39 +1,148 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: i18n-localization
|
|
3
|
-
description: Internationalization and localization
|
|
4
|
-
|
|
3
|
+
description: "Internationalization and localization — structured workflow for extracting hardcoded strings, managing translations, ICU MessageFormat, Intl API, RTL support, and audit capabilities."
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
source: self
|
|
6
|
+
date_added: "2026-02-27"
|
|
7
|
+
date_rewritten: "2026-03-21"
|
|
5
8
|
---
|
|
6
9
|
|
|
7
10
|
# i18n & Localization
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
Production-grade internationalization skill. Covers string extraction, translation management, ICU MessageFormat, all Intl APIs, RTL support, and i18n codebase auditing.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- Extracting hardcoded strings from an existing codebase
|
|
17
|
+
- Setting up i18n infrastructure for a new project
|
|
18
|
+
- Auditing i18n coverage and completeness
|
|
19
|
+
- Adding RTL language support
|
|
20
|
+
- Formatting dates, numbers, currencies, or relative times for multiple locales
|
|
21
|
+
- Writing or reviewing translation strings with plural/gender/select patterns
|
|
22
|
+
|
|
23
|
+
## When NOT to Use
|
|
24
|
+
|
|
25
|
+
- Framework-specific i18n routing (e.g., Astro, Next.js locale routing — use the framework skill)
|
|
26
|
+
- Content management / CMS translation workflows — that's a product concern
|
|
27
|
+
- Machine translation quality review — out of scope
|
|
10
28
|
|
|
11
29
|
---
|
|
12
30
|
|
|
13
|
-
##
|
|
31
|
+
## Core Concepts
|
|
14
32
|
|
|
15
33
|
| Term | Meaning |
|
|
16
34
|
|------|---------|
|
|
17
|
-
| **i18n** | Internationalization
|
|
18
|
-
| **L10n** | Localization
|
|
19
|
-
| **Locale** | Language + Region (en-US, tr-TR) |
|
|
20
|
-
| **RTL** | Right-to-left
|
|
35
|
+
| **i18n** | Internationalization — making the app translatable |
|
|
36
|
+
| **L10n** | Localization — actual translations for a target locale |
|
|
37
|
+
| **Locale** | Language + Region code (en-US, tr-TR, ar-SA) |
|
|
38
|
+
| **RTL** | Right-to-left scripts (Arabic, Hebrew, Persian, Urdu) |
|
|
39
|
+
| **ICU** | International Components for Unicode — standard message format |
|
|
21
40
|
|
|
22
41
|
---
|
|
23
42
|
|
|
24
|
-
##
|
|
43
|
+
## Structured Workflow: SCAN → EXTRACT → VERIFY → PRESENT
|
|
44
|
+
|
|
45
|
+
### Phase 1: SCAN
|
|
46
|
+
|
|
47
|
+
Assess current state before touching any code.
|
|
48
|
+
|
|
49
|
+
1. **Detect i18n library in use** — search for `react-i18next`, `next-intl`, `vue-i18n`, `@angular/localize`, `gettext`, or native `Intl` usage
|
|
50
|
+
2. **Identify hardcoded user-facing strings** — grep for string literals in UI components and templates:
|
|
51
|
+
- JSX text content: `<h1>Welcome</h1>`, `<p>Loading...</p>`
|
|
52
|
+
- Attribute strings: `placeholder="Search"`, `aria-label="Close"`
|
|
53
|
+
- Alert/confirm/error messages: `alert('Error occurred')`
|
|
54
|
+
- Template literals with user-facing text in renderables
|
|
55
|
+
3. **Assess current coverage** — count: already-translated strings vs hardcoded strings, namespaces in use, supported locales
|
|
56
|
+
4. **Check for string concatenation** — find patterns like `"Hello, " + name` or `` `Order #${id}` `` in UI layer — these break translation
|
|
57
|
+
|
|
58
|
+
**Output**: Coverage report with string counts, namespaces, and problem patterns.
|
|
59
|
+
|
|
60
|
+
### Phase 2: EXTRACT
|
|
61
|
+
|
|
62
|
+
Wrap strings and generate translation files.
|
|
63
|
+
|
|
64
|
+
1. **Choose key convention** — use `feature.element.action` (see [ICU reference](references/icu-message-format.md) for full naming rules):
|
|
65
|
+
```
|
|
66
|
+
auth.login.title → "Sign In"
|
|
67
|
+
common.buttons.save → "Save"
|
|
68
|
+
dashboard.stats.revenue → "Total Revenue"
|
|
69
|
+
```
|
|
70
|
+
2. **Wrap strings** — replace hardcoded text with `t()` calls:
|
|
71
|
+
```tsx
|
|
72
|
+
// Before
|
|
73
|
+
<h1>Welcome back</h1>
|
|
74
|
+
|
|
75
|
+
// After
|
|
76
|
+
<h1>{t('dashboard.welcome.title')}</h1>
|
|
77
|
+
```
|
|
78
|
+
3. **Generate/update locale JSON** — create namespace files per feature:
|
|
79
|
+
```
|
|
80
|
+
locales/en/auth.json
|
|
81
|
+
locales/en/common.json
|
|
82
|
+
locales/en/dashboard.json
|
|
83
|
+
```
|
|
84
|
+
4. **Handle interpolation** — convert concatenation to ICU interpolation:
|
|
85
|
+
```json
|
|
86
|
+
{ "greeting": "Welcome back, {name}" }
|
|
87
|
+
```
|
|
88
|
+
5. **Handle plurals** — use ICU MessageFormat (see [ICU reference](references/icu-message-format.md)):
|
|
89
|
+
```json
|
|
90
|
+
{ "cart.count": "{count, plural, =0 {Cart empty} one {# item} other {# items}}" }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Phase 3: VERIFY
|
|
94
|
+
|
|
95
|
+
Validate correctness before presenting results.
|
|
96
|
+
|
|
97
|
+
1. **Intl API audit** — verify all locale-sensitive formatting uses `Intl` (see [Intl reference](references/intl-api-patterns.md)):
|
|
98
|
+
- Dates → `Intl.DateTimeFormat` (not `toLocaleDateString` without options)
|
|
99
|
+
- Numbers/currency → `Intl.NumberFormat`
|
|
100
|
+
- Relative time → `Intl.RelativeTimeFormat` (not manual "X days ago")
|
|
101
|
+
- Lists → `Intl.ListFormat` (not `.join(', ')`)
|
|
102
|
+
2. **String concatenation check** — confirm zero string concatenation for translated content
|
|
103
|
+
3. **RTL compatibility** — if RTL locales are in scope, run the [RTL checklist](references/rtl-support.md)
|
|
104
|
+
4. **Missing translations** — verify every key in the default locale exists in all target locales
|
|
105
|
+
5. **Unused keys** — check for translation keys that no longer appear in code
|
|
106
|
+
|
|
107
|
+
### Phase 4: PRESENT
|
|
108
|
+
|
|
109
|
+
Deliver structured output.
|
|
110
|
+
|
|
111
|
+
Every i18n task must produce these deliverables:
|
|
112
|
+
|
|
113
|
+
| Deliverable | Content |
|
|
114
|
+
|-------------|---------|
|
|
115
|
+
| **Extraction count** | Strings extracted or modified (e.g., "42 strings extracted") |
|
|
116
|
+
| **Namespace map** | Key structure and file organization |
|
|
117
|
+
| **Translation file changes** | JSON diffs or new files created |
|
|
118
|
+
| **Scope summary** | Component / feature / app-wide scope declaration |
|
|
119
|
+
| **Problem patterns** | Concatenation, missing Intl usage, RTL issues found |
|
|
120
|
+
| **Next steps** | Remaining work — new locales, RTL testing, translator handoff |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Scope Management
|
|
125
|
+
|
|
126
|
+
| Scope | String Count | Approach |
|
|
127
|
+
|-------|-------------|----------|
|
|
128
|
+
| **Component** | < 50 strings | Single PR, one namespace |
|
|
129
|
+
| **Feature** | < 200 strings | Plan first, single PR, 2-3 namespaces |
|
|
130
|
+
| **App-wide** | 200+ strings | Phased plan with progress tracking per namespace |
|
|
25
131
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
132
|
+
For app-wide extraction, create a tracking document:
|
|
133
|
+
|
|
134
|
+
```markdown
|
|
135
|
+
## i18n Extraction Progress
|
|
136
|
+
- [x] common (32/32 strings)
|
|
137
|
+
- [x] auth (18/18 strings)
|
|
138
|
+
- [/] dashboard (24/41 strings)
|
|
139
|
+
- [ ] settings (0/36 strings)
|
|
140
|
+
- [ ] billing (0/28 strings)
|
|
141
|
+
```
|
|
33
142
|
|
|
34
143
|
---
|
|
35
144
|
|
|
36
|
-
##
|
|
145
|
+
## Implementation Patterns
|
|
37
146
|
|
|
38
147
|
### React (react-i18next)
|
|
39
148
|
|
|
@@ -41,8 +150,14 @@ allowed-tools: Read, Glob, Grep
|
|
|
41
150
|
import { useTranslation } from 'react-i18next';
|
|
42
151
|
|
|
43
152
|
function Welcome() {
|
|
44
|
-
const { t } = useTranslation();
|
|
45
|
-
return
|
|
153
|
+
const { t } = useTranslation('dashboard');
|
|
154
|
+
return (
|
|
155
|
+
<div>
|
|
156
|
+
<h1>{t('welcome.title')}</h1>
|
|
157
|
+
<p>{t('welcome.subtitle', { name: user.name })}</p>
|
|
158
|
+
<p>{t('stats.itemCount', { count: items.length })}</p>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
46
161
|
}
|
|
47
162
|
```
|
|
48
163
|
|
|
@@ -53,7 +168,12 @@ import { useTranslations } from 'next-intl';
|
|
|
53
168
|
|
|
54
169
|
export default function Page() {
|
|
55
170
|
const t = useTranslations('Home');
|
|
56
|
-
return
|
|
171
|
+
return (
|
|
172
|
+
<div>
|
|
173
|
+
<h1>{t('title')}</h1>
|
|
174
|
+
<p>{t('description', { count: 5 })}</p>
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
57
177
|
}
|
|
58
178
|
```
|
|
59
179
|
|
|
@@ -61,94 +181,152 @@ export default function Page() {
|
|
|
61
181
|
|
|
62
182
|
```python
|
|
63
183
|
from gettext import gettext as _
|
|
184
|
+
from gettext import ngettext
|
|
64
185
|
|
|
65
186
|
print(_("Welcome to our app"))
|
|
187
|
+
print(ngettext("%(count)d item", "%(count)d items", count) % {"count": count})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Vue (vue-i18n)
|
|
191
|
+
|
|
192
|
+
```vue
|
|
193
|
+
<template>
|
|
194
|
+
<h1>{{ $t('dashboard.title') }}</h1>
|
|
195
|
+
<p>{{ $t('dashboard.greeting', { name: user.name }) }}</p>
|
|
196
|
+
</template>
|
|
66
197
|
```
|
|
67
198
|
|
|
68
199
|
---
|
|
69
200
|
|
|
70
|
-
##
|
|
201
|
+
## File Structure
|
|
71
202
|
|
|
72
203
|
```
|
|
73
204
|
locales/
|
|
74
|
-
├── en/
|
|
75
|
-
│ ├── common.json
|
|
76
|
-
│ ├── auth.json
|
|
77
|
-
│
|
|
78
|
-
├──
|
|
79
|
-
│
|
|
80
|
-
|
|
81
|
-
│ └──
|
|
82
|
-
|
|
205
|
+
├── en/ # Default / source locale
|
|
206
|
+
│ ├── common.json # Shared: buttons, labels, status
|
|
207
|
+
│ ├── auth.json # Auth feature strings
|
|
208
|
+
│ ├── dashboard.json # Dashboard feature strings
|
|
209
|
+
│ ├── errors.json # Error messages
|
|
210
|
+
│ └── validation.json # Form validation messages
|
|
211
|
+
├── de/ # German (30% longer text — test wrapping)
|
|
212
|
+
│ └── ...
|
|
213
|
+
├── ar/ # Arabic (RTL)
|
|
214
|
+
│ └── ...
|
|
215
|
+
└── ja/ # Japanese (CJK — test Segmenter)
|
|
83
216
|
└── ...
|
|
84
217
|
```
|
|
85
218
|
|
|
219
|
+
Namespace rules:
|
|
220
|
+
- One JSON file per feature domain
|
|
221
|
+
- `common.json` for cross-feature strings (buttons, labels, status words)
|
|
222
|
+
- Never exceed 200 keys per file — split by sub-feature if needed
|
|
223
|
+
|
|
86
224
|
---
|
|
87
225
|
|
|
88
|
-
##
|
|
226
|
+
## Translator Context
|
|
89
227
|
|
|
90
|
-
###
|
|
228
|
+
### When to Add Context Comments
|
|
91
229
|
|
|
92
|
-
|
|
93
|
-
- Namespace translations by feature
|
|
94
|
-
- Support pluralization
|
|
95
|
-
- Handle date/number formats per locale
|
|
96
|
-
- Plan for RTL from the start
|
|
97
|
-
- Use ICU message format for complex strings
|
|
230
|
+
Add context when a string is **ambiguous without seeing the UI**:
|
|
98
231
|
|
|
99
|
-
|
|
232
|
+
| Situation | Example |
|
|
233
|
+
|-----------|---------|
|
|
234
|
+
| **Homonyms** | "Save" — button label? saving to disk? sports save? |
|
|
235
|
+
| **Character limits** | Button has 15-char max width |
|
|
236
|
+
| **Placeholder context** | What `{name}` refers to (user name? product name?) |
|
|
237
|
+
| **Tone** | Formal vs casual for same meaning |
|
|
238
|
+
| **UI position** | Same word used as heading vs inline text |
|
|
100
239
|
|
|
101
|
-
|
|
102
|
-
- Concatenate translated strings
|
|
103
|
-
- Assume text length (German is 30% longer)
|
|
104
|
-
- Forget about RTL layout
|
|
105
|
-
- Mix languages in same file
|
|
240
|
+
### Context Format
|
|
106
241
|
|
|
107
|
-
|
|
242
|
+
In JSON locale files, use a parallel `_context` key:
|
|
108
243
|
|
|
109
|
-
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"common.save": "Save",
|
|
247
|
+
"common.save_context": "Button label for saving form data. Max 10 characters.",
|
|
110
248
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
| Missing translation | Fallback to default language |
|
|
114
|
-
| Hardcoded strings | Use linter/checker script |
|
|
115
|
-
| Date format | Use Intl.DateTimeFormat |
|
|
116
|
-
| Number format | Use Intl.NumberFormat |
|
|
117
|
-
| Pluralization | Use ICU message format |
|
|
249
|
+
"billing.charge": "Charge",
|
|
250
|
+
"billing.charge_context": "Verb — action button to charge customer's payment method.",
|
|
118
251
|
|
|
119
|
-
|
|
252
|
+
"dashboard.lead": "Lead",
|
|
253
|
+
"dashboard.lead_context": "Noun — a sales lead / prospective customer, not the verb."
|
|
254
|
+
}
|
|
255
|
+
```
|
|
120
256
|
|
|
121
|
-
|
|
257
|
+
Or in ARB format (Flutter/Dart convention, also used by some JS tools):
|
|
122
258
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"save": "Save",
|
|
262
|
+
"@save": {
|
|
263
|
+
"description": "Button label for saving form data",
|
|
264
|
+
"context": "Appears on all edit forms",
|
|
265
|
+
"maxLength": 10
|
|
266
|
+
}
|
|
128
267
|
}
|
|
268
|
+
```
|
|
129
269
|
|
|
130
|
-
|
|
131
|
-
|
|
270
|
+
### Glossary Management
|
|
271
|
+
|
|
272
|
+
For domain-specific terminology, maintain a glossary file:
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
locales/glossary.json
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"terms": {
|
|
281
|
+
"lead": "A prospective customer in the sales pipeline",
|
|
282
|
+
"sprint": "A 2-week development iteration",
|
|
283
|
+
"tenant": "An organization account in the multi-tenant system"
|
|
284
|
+
}
|
|
132
285
|
}
|
|
133
286
|
```
|
|
134
287
|
|
|
288
|
+
Share this glossary with translators to ensure consistent terminology across locales.
|
|
289
|
+
|
|
135
290
|
---
|
|
136
291
|
|
|
137
|
-
##
|
|
292
|
+
## Reference Material
|
|
138
293
|
|
|
139
|
-
|
|
294
|
+
Detailed reference docs are in the `references/` directory:
|
|
140
295
|
|
|
141
|
-
|
|
296
|
+
| Reference | Content |
|
|
297
|
+
|-----------|---------|
|
|
298
|
+
| [ICU MessageFormat](references/icu-message-format.md) | Plural, select, ordinal, nested patterns. Key naming conventions. Common mistakes. |
|
|
299
|
+
| [Intl API Patterns](references/intl-api-patterns.md) | All 7 `Intl` formatters with usage examples: DateTimeFormat, NumberFormat, RelativeTimeFormat, ListFormat, PluralRules, DisplayNames, Segmenter. |
|
|
300
|
+
| [RTL Support](references/rtl-support.md) | CSS logical properties table, component-level patterns, `dir` attribute usage, bidirectional text, testing checklist. |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Pre-Ship Checklist
|
|
305
|
+
|
|
306
|
+
- [ ] All user-facing strings use translation keys (`t()` / `$t()` / `_()`)
|
|
307
|
+
- [ ] Zero string concatenation for translated content
|
|
142
308
|
- [ ] Locale files exist for all supported languages
|
|
143
|
-
- [ ]
|
|
144
|
-
- [ ]
|
|
309
|
+
- [ ] All keys in default locale exist in every target locale
|
|
310
|
+
- [ ] ICU MessageFormat used for plurals, gender, select (no ternary hacks)
|
|
311
|
+
- [ ] Dates use `Intl.DateTimeFormat` — not `.toLocaleDateString()` without options
|
|
312
|
+
- [ ] Numbers/currency use `Intl.NumberFormat`
|
|
313
|
+
- [ ] Relative times use `Intl.RelativeTimeFormat`
|
|
314
|
+
- [ ] Lists use `Intl.ListFormat` — not `.join(', ')`
|
|
315
|
+
- [ ] RTL tested (if RTL locales in scope) — run [RTL checklist](references/rtl-support.md)
|
|
316
|
+
- [ ] Translator context provided for ambiguous strings
|
|
145
317
|
- [ ] Fallback language configured
|
|
146
|
-
- [ ]
|
|
318
|
+
- [ ] Text doesn't overflow containers (test with German — 30% expansion)
|
|
147
319
|
|
|
148
320
|
---
|
|
149
321
|
|
|
150
|
-
##
|
|
151
|
-
|
|
152
|
-
|
|
|
153
|
-
|
|
154
|
-
| `
|
|
322
|
+
## Anti-Patterns
|
|
323
|
+
|
|
324
|
+
| Pattern | Why It's Wrong | Fix |
|
|
325
|
+
|---------|---------------|-----|
|
|
326
|
+
| `"Hello, " + name` | Breaks translation word order | `t('greeting', { name })` |
|
|
327
|
+
| `count === 1 ? 'item' : 'items'` | Fails for Polish, Arabic, etc. | ICU `{count, plural, ...}` |
|
|
328
|
+
| `new Date().toLocaleDateString()` | Inconsistent without explicit options | `Intl.DateTimeFormat(locale, opts)` |
|
|
329
|
+
| `list.join(', ')` | Wrong separator for Japanese, Arabic | `Intl.ListFormat(locale)` |
|
|
330
|
+
| `margin-left: 1rem` in CSS | Breaks RTL layout | `margin-inline-start: 1rem` |
|
|
331
|
+
| `t('btn1')`, `t('btn2')` | Non-semantic keys are unmaintainable | `t('common.buttons.save')` |
|
|
332
|
+
| Splitting sentences across keys | Translators can't reorder words | One full sentence per key |
|