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.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/template/.agent/kit-sync.md +3 -3
  3. package/template/.agent/rules/source-before-ask.md +93 -0
  4. package/template/.agent/rules/vertical-slices.md +46 -8
  5. package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +251 -73
  6. package/template/.agent/skill-library/surface/web/i18n-localization/references/icu-message-format.md +223 -0
  7. package/template/.agent/skill-library/surface/web/i18n-localization/references/intl-api-patterns.md +326 -0
  8. package/template/.agent/skill-library/surface/web/i18n-localization/references/rtl-support.md +298 -0
  9. package/template/.agent/skills/architecture-mapping/SKILL.md +1 -1
  10. package/template/.agent/skills/prd-templates/references/decomposition-templates.md +32 -17
  11. package/template/.agent/skills/prd-templates/references/gate-applicability.md +92 -0
  12. package/template/.agent/skills/prd-templates/references/map-guard-protocol.md +34 -13
  13. package/template/.agent/skills/prd-templates/references/shard-boundary-analysis.md +1 -1
  14. package/template/.agent/skills/prd-templates/references/shard-split-remediation.md +163 -0
  15. package/template/.agent/skills/prd-templates/references/workflow-checkpoint-protocol.md +112 -0
  16. package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +235 -19
  17. package/template/.agent/workflows/bootstrap-agents-fill.md +4 -4
  18. package/template/.agent/workflows/bootstrap-agents.md +4 -0
  19. package/template/.agent/workflows/create-prd-architecture.md +8 -3
  20. package/template/.agent/workflows/create-prd-compile.md +6 -0
  21. package/template/.agent/workflows/create-prd-design-system.md +18 -4
  22. package/template/.agent/workflows/create-prd-security.md +8 -3
  23. package/template/.agent/workflows/create-prd-stack.md +47 -35
  24. package/template/.agent/workflows/create-prd.md +8 -3
  25. package/template/.agent/workflows/decompose-architecture-structure.md +5 -3
  26. package/template/.agent/workflows/decompose-architecture-validate.md +1 -1
  27. package/template/.agent/workflows/remediate-shard-split.md +201 -0
  28. package/template/.agent/workflows/validate-phase-readiness.md +42 -61
  29. package/template/.agent/workflows/write-architecture-spec-design.md +1 -1
  30. package/template/AGENTS.md +3 -1
  31. package/template/GEMINI.md +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cfsa-antigravity",
3
- "version": "2.15.0",
3
+ "version": "2.18.0",
4
4
  "description": "CFSA Pipeline — Constraint-First Specification Architecture for AI agents. Production-grade from line one.",
5
5
  "scripts": {
6
6
  "changeset": "changeset",
@@ -1,6 +1,6 @@
1
1
  # Kit Sync State
2
2
 
3
3
  upstream: https://github.com/RepairYourTech/cfsa-antigravity
4
- last_synced_commit: 7c5b0504d422958d0c36cf83768a7b12d3a6ab2a
5
- last_synced_at: 2026-03-20T18:30:16Z
6
- kit_version: 2.15.0
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 four surfaces or they don't ship — no half-built slices
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
- - [ ] Data layer: schema defined, permissions set, seed data exists
28
- - [ ] API layer: endpoints exist, validated with {{CONTRACT_LIBRARY}}, tested
29
- - [ ] User-facing: component renders, handles loading/error/empty states
30
- - [ ] Admin: can create/read/update/delete the resource
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
- | "I'll add the admin panel later" | ❌ Rejected. Include admin CRUD in the slice. |
41
- | "The API works, frontend next sprint" | ❌ Rejected. Ship them together or not at all. |
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
- | All 4 layers + tests + navigation + auth gates | Correct. |
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 patterns. Detecting hardcoded strings, managing translations, locale files, RTL support.
4
- allowed-tools: Read, Glob, Grep
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
- > Internationalization (i18n) and Localization (L10n) best practices.
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
- ## 1. Core Concepts
31
+ ## Core Concepts
14
32
 
15
33
  | Term | Meaning |
16
34
  |------|---------|
17
- | **i18n** | Internationalization - making app translatable |
18
- | **L10n** | Localization - actual translations |
19
- | **Locale** | Language + Region (en-US, tr-TR) |
20
- | **RTL** | Right-to-left languages (Arabic, Hebrew) |
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
- ## 2. When to Use i18n
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
- | Project Type | i18n Needed? |
27
- |--------------|--------------|
28
- | Public web app | ✅ Yes |
29
- | SaaS product | ✅ Yes |
30
- | Internal tool | ⚠️ Maybe |
31
- | Single-region app | ⚠️ Consider future |
32
- | Personal project | ❌ Optional |
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
- ## 3. Implementation Patterns
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 <h1>{t('welcome.title')}</h1>;
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 <h1>{t('title')}</h1>;
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
- ## 4. File Structure
201
+ ## File Structure
71
202
 
72
203
  ```
73
204
  locales/
74
- ├── en/
75
- │ ├── common.json
76
- │ ├── auth.json
77
- └── errors.json
78
- ├── tr/
79
- ├── common.json
80
- ├── auth.json
81
- │ └── errors.json
82
- └── ar/ # RTL
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
- ## 5. Best Practices
226
+ ## Translator Context
89
227
 
90
- ### DO
228
+ ### When to Add Context Comments
91
229
 
92
- - Use translation keys, not raw text
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
- ### DON'T
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
- - Hardcode strings in components
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
- ## 6. Common Issues
244
+ ```json
245
+ {
246
+ "common.save": "Save",
247
+ "common.save_context": "Button label for saving form data. Max 10 characters.",
110
248
 
111
- | Issue | Solution |
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
- ## 7. RTL Support
257
+ Or in ARB format (Flutter/Dart convention, also used by some JS tools):
122
258
 
123
- ```css
124
- /* CSS Logical Properties */
125
- .container {
126
- margin-inline-start: 1rem; /* Not margin-left */
127
- padding-inline-end: 1rem; /* Not padding-right */
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
- [dir="rtl"] .icon {
131
- transform: scaleX(-1);
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
- ## 8. Checklist
292
+ ## Reference Material
138
293
 
139
- Before shipping:
294
+ Detailed reference docs are in the `references/` directory:
140
295
 
141
- - [ ] All user-facing strings use translation keys
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
- - [ ] Date/number formatting uses Intl API
144
- - [ ] RTL layout tested (if applicable)
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
- - [ ] No hardcoded strings in components
318
+ - [ ] Text doesn't overflow containers (test with German — 30% expansion)
147
319
 
148
320
  ---
149
321
 
150
- ## Script
151
-
152
- | Script | Purpose | Command |
153
- |--------|---------|---------|
154
- | `scripts/i18n_checker.py` | Detect hardcoded strings & missing translations | `python scripts/i18n_checker.py <project_path>` |
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 |