qualia-framework 2.1.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 (261) hide show
  1. package/README.md +50 -0
  2. package/bin/cli.js +519 -0
  3. package/framework/agents/architecture-strategist.md +53 -0
  4. package/framework/agents/backend-agent.md +150 -0
  5. package/framework/agents/code-simplicity-reviewer.md +86 -0
  6. package/framework/agents/frontend-agent.md +111 -0
  7. package/framework/agents/kieran-typescript-reviewer.md +96 -0
  8. package/framework/agents/performance-oracle.md +111 -0
  9. package/framework/agents/qualia-codebase-mapper.md +760 -0
  10. package/framework/agents/qualia-debugger.md +1203 -0
  11. package/framework/agents/qualia-executor.md +881 -0
  12. package/framework/agents/qualia-integration-checker.md +423 -0
  13. package/framework/agents/qualia-phase-researcher.md +453 -0
  14. package/framework/agents/qualia-plan-checker.md +699 -0
  15. package/framework/agents/qualia-planner.md +1241 -0
  16. package/framework/agents/qualia-project-researcher.md +602 -0
  17. package/framework/agents/qualia-research-synthesizer.md +236 -0
  18. package/framework/agents/qualia-roadmapper.md +605 -0
  19. package/framework/agents/qualia-verifier.md +685 -0
  20. package/framework/agents/team-orchestrator.md +228 -0
  21. package/framework/agents/teams/full-stack-team.md +48 -0
  22. package/framework/agents/teams/optimize-team.md +53 -0
  23. package/framework/agents/teams/review-team.md +62 -0
  24. package/framework/agents/teams/ship-team.md +86 -0
  25. package/framework/agents/test-agent.md +182 -0
  26. package/framework/askpass.sh +2 -0
  27. package/framework/commands/design.md +53 -0
  28. package/framework/commands/quick-db.md +22 -0
  29. package/framework/config/retention.json +35 -0
  30. package/framework/core/PRINCIPLES.md +77 -0
  31. package/framework/hooks/auto-format.sh +45 -0
  32. package/framework/hooks/block-env-edit.sh +42 -0
  33. package/framework/hooks/branch-guard.sh +46 -0
  34. package/framework/hooks/confirm-delete.sh +56 -0
  35. package/framework/hooks/migration-validate.sh +68 -0
  36. package/framework/hooks/notification-speak.sh +15 -0
  37. package/framework/hooks/pre-commit.sh +80 -0
  38. package/framework/hooks/pre-compact.sh +55 -0
  39. package/framework/hooks/pre-deploy-gate.sh +151 -0
  40. package/framework/hooks/qualia-colors.sh +32 -0
  41. package/framework/hooks/retention-cleanup.sh +43 -0
  42. package/framework/hooks/save-session-state.sh +153 -0
  43. package/framework/hooks/session-context-loader.sh +28 -0
  44. package/framework/hooks/session-learn.sh +30 -0
  45. package/framework/knowledge/claudecode-bible.md +1384 -0
  46. package/framework/knowledge/client-prefs.md +22 -0
  47. package/framework/knowledge/common-fixes.md +25 -0
  48. package/framework/knowledge/deployment-map.md +35 -0
  49. package/framework/knowledge/email-signature.html +1 -0
  50. package/framework/knowledge/employees.md +8 -0
  51. package/framework/knowledge/learned-patterns.md +51 -0
  52. package/framework/knowledge/optimization-research-2026.md +137 -0
  53. package/framework/knowledge/qualia-context.md +67 -0
  54. package/framework/knowledge/supabase-patterns.md +50 -0
  55. package/framework/knowledge/voice-agent-patterns.md +46 -0
  56. package/framework/qualia-engine/VERSION +1 -0
  57. package/framework/qualia-engine/bin/qualia-tools.js +2160 -0
  58. package/framework/qualia-engine/bin/qualia-tools.test.js +1054 -0
  59. package/framework/qualia-engine/references/checkpoints.md +775 -0
  60. package/framework/qualia-engine/references/continuation-format.md +249 -0
  61. package/framework/qualia-engine/references/decimal-phase-calculation.md +65 -0
  62. package/framework/qualia-engine/references/design-quality.md +56 -0
  63. package/framework/qualia-engine/references/git-integration.md +254 -0
  64. package/framework/qualia-engine/references/git-planning-commit.md +50 -0
  65. package/framework/qualia-engine/references/model-profile-resolution.md +32 -0
  66. package/framework/qualia-engine/references/model-profiles.md +73 -0
  67. package/framework/qualia-engine/references/phase-argument-parsing.md +61 -0
  68. package/framework/qualia-engine/references/planning-config.md +195 -0
  69. package/framework/qualia-engine/references/questioning.md +141 -0
  70. package/framework/qualia-engine/references/tdd.md +263 -0
  71. package/framework/qualia-engine/references/ui-brand.md +160 -0
  72. package/framework/qualia-engine/references/verification-patterns.md +612 -0
  73. package/framework/qualia-engine/templates/DEBUG.md +159 -0
  74. package/framework/qualia-engine/templates/DESIGN.md +81 -0
  75. package/framework/qualia-engine/templates/UAT.md +247 -0
  76. package/framework/qualia-engine/templates/codebase/architecture.md +255 -0
  77. package/framework/qualia-engine/templates/codebase/concerns.md +310 -0
  78. package/framework/qualia-engine/templates/codebase/conventions.md +307 -0
  79. package/framework/qualia-engine/templates/codebase/integrations.md +280 -0
  80. package/framework/qualia-engine/templates/codebase/stack.md +186 -0
  81. package/framework/qualia-engine/templates/codebase/structure.md +285 -0
  82. package/framework/qualia-engine/templates/codebase/testing.md +480 -0
  83. package/framework/qualia-engine/templates/config.json +35 -0
  84. package/framework/qualia-engine/templates/context.md +283 -0
  85. package/framework/qualia-engine/templates/continue-here.md +78 -0
  86. package/framework/qualia-engine/templates/debug-subagent-prompt.md +91 -0
  87. package/framework/qualia-engine/templates/discovery.md +146 -0
  88. package/framework/qualia-engine/templates/milestone-archive.md +123 -0
  89. package/framework/qualia-engine/templates/milestone.md +115 -0
  90. package/framework/qualia-engine/templates/phase-prompt.md +567 -0
  91. package/framework/qualia-engine/templates/planner-subagent-prompt.md +117 -0
  92. package/framework/qualia-engine/templates/project.md +184 -0
  93. package/framework/qualia-engine/templates/projects/ai-agent.md +156 -0
  94. package/framework/qualia-engine/templates/projects/mobile-app.md +181 -0
  95. package/framework/qualia-engine/templates/projects/voice-agent.md +134 -0
  96. package/framework/qualia-engine/templates/projects/website.md +137 -0
  97. package/framework/qualia-engine/templates/requirements.md +231 -0
  98. package/framework/qualia-engine/templates/research-project/ARCHITECTURE.md +204 -0
  99. package/framework/qualia-engine/templates/research-project/FEATURES.md +147 -0
  100. package/framework/qualia-engine/templates/research-project/PITFALLS.md +200 -0
  101. package/framework/qualia-engine/templates/research-project/STACK.md +120 -0
  102. package/framework/qualia-engine/templates/research-project/SUMMARY.md +170 -0
  103. package/framework/qualia-engine/templates/research.md +552 -0
  104. package/framework/qualia-engine/templates/roadmap.md +202 -0
  105. package/framework/qualia-engine/templates/state.md +176 -0
  106. package/framework/qualia-engine/templates/summary-complex.md +59 -0
  107. package/framework/qualia-engine/templates/summary-minimal.md +41 -0
  108. package/framework/qualia-engine/templates/summary-standard.md +48 -0
  109. package/framework/qualia-engine/templates/summary.md +246 -0
  110. package/framework/qualia-engine/templates/user-setup.md +311 -0
  111. package/framework/qualia-engine/templates/verification-report.md +322 -0
  112. package/framework/qualia-engine/workflows/add-phase.md +179 -0
  113. package/framework/qualia-engine/workflows/add-todo.md +157 -0
  114. package/framework/qualia-engine/workflows/audit-milestone.md +241 -0
  115. package/framework/qualia-engine/workflows/check-todos.md +176 -0
  116. package/framework/qualia-engine/workflows/complete-milestone.md +858 -0
  117. package/framework/qualia-engine/workflows/diagnose-issues.md +219 -0
  118. package/framework/qualia-engine/workflows/discovery-phase.md +289 -0
  119. package/framework/qualia-engine/workflows/discuss-phase.md +534 -0
  120. package/framework/qualia-engine/workflows/execute-phase.md +559 -0
  121. package/framework/qualia-engine/workflows/execute-plan.md +438 -0
  122. package/framework/qualia-engine/workflows/help.md +470 -0
  123. package/framework/qualia-engine/workflows/insert-phase.md +220 -0
  124. package/framework/qualia-engine/workflows/list-phase-assumptions.md +178 -0
  125. package/framework/qualia-engine/workflows/map-codebase.md +327 -0
  126. package/framework/qualia-engine/workflows/new-milestone.md +363 -0
  127. package/framework/qualia-engine/workflows/new-project.md +1037 -0
  128. package/framework/qualia-engine/workflows/pause-work.md +122 -0
  129. package/framework/qualia-engine/workflows/plan-milestone-gaps.md +256 -0
  130. package/framework/qualia-engine/workflows/plan-phase.md +422 -0
  131. package/framework/qualia-engine/workflows/progress.md +354 -0
  132. package/framework/qualia-engine/workflows/quick.md +252 -0
  133. package/framework/qualia-engine/workflows/remove-phase.md +326 -0
  134. package/framework/qualia-engine/workflows/research-phase.md +74 -0
  135. package/framework/qualia-engine/workflows/resume-project.md +306 -0
  136. package/framework/qualia-engine/workflows/set-profile.md +80 -0
  137. package/framework/qualia-engine/workflows/settings.md +145 -0
  138. package/framework/qualia-engine/workflows/transition.md +556 -0
  139. package/framework/qualia-engine/workflows/update.md +197 -0
  140. package/framework/qualia-engine/workflows/verify-phase.md +195 -0
  141. package/framework/qualia-engine/workflows/verify-work.md +625 -0
  142. package/framework/rules/context7.md +11 -0
  143. package/framework/rules/deployment.md +29 -0
  144. package/framework/rules/frontend.md +33 -0
  145. package/framework/rules/security.md +12 -0
  146. package/framework/rules/speed.md +20 -0
  147. package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
  148. package/framework/scripts/apply-retention.sh +120 -0
  149. package/framework/scripts/bootstrap-pop-os.sh +354 -0
  150. package/framework/scripts/claude-voice +13 -0
  151. package/framework/scripts/cleanup.sh +131 -0
  152. package/framework/scripts/cowork-mode.sh +141 -0
  153. package/framework/scripts/generate-project-claude-md.sh +153 -0
  154. package/framework/scripts/load-test-webhook.js +172 -0
  155. package/framework/scripts/say.py +236 -0
  156. package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +167 -0
  157. package/framework/scripts/showcase-video-recorder/playwright-helpers.js +216 -0
  158. package/framework/scripts/speak.py +55 -0
  159. package/framework/scripts/speak.sh +18 -0
  160. package/framework/scripts/status.sh +138 -0
  161. package/framework/scripts/sync-to-framework.sh +65 -0
  162. package/framework/scripts/voice-hotkey.py +227 -0
  163. package/framework/scripts/voice-input.sh +51 -0
  164. package/framework/skills/animate/SKILL.md +202 -0
  165. package/framework/skills/bolder/SKILL.md +144 -0
  166. package/framework/skills/browser-qa/SKILL.md +536 -0
  167. package/framework/skills/clarify/SKILL.md +179 -0
  168. package/framework/skills/colorize/SKILL.md +170 -0
  169. package/framework/skills/critique/SKILL.md +126 -0
  170. package/framework/skills/deep-research/SKILL.md +271 -0
  171. package/framework/skills/delight/SKILL.md +329 -0
  172. package/framework/skills/deploy/SKILL.md +261 -0
  173. package/framework/skills/deploy-verify/SKILL.md +377 -0
  174. package/framework/skills/deploy-verify/scripts/canary-check.sh +206 -0
  175. package/framework/skills/deploy-verify/scripts/check-console-errors.js +147 -0
  176. package/framework/skills/deploy-verify/scripts/check-cwv.js +139 -0
  177. package/framework/skills/deploy-verify/scripts/project-detect.sh +84 -0
  178. package/framework/skills/deploy-verify/scripts/verify.sh +548 -0
  179. package/framework/skills/design-quieter/SKILL.md +130 -0
  180. package/framework/skills/distill/SKILL.md +149 -0
  181. package/framework/skills/docs-lookup/SKILL.md +78 -0
  182. package/framework/skills/fcm-notifications/SKILL.md +125 -0
  183. package/framework/skills/financial-ledger/SKILL.md +1039 -0
  184. package/framework/skills/frontend-master/NOTICE.md +4 -0
  185. package/framework/skills/frontend-master/SKILL.md +127 -0
  186. package/framework/skills/frontend-master/reference/color-and-contrast.md +132 -0
  187. package/framework/skills/frontend-master/reference/interaction-design.md +123 -0
  188. package/framework/skills/frontend-master/reference/motion-design.md +99 -0
  189. package/framework/skills/frontend-master/reference/responsive-design.md +114 -0
  190. package/framework/skills/frontend-master/reference/spatial-design.md +100 -0
  191. package/framework/skills/frontend-master/reference/typography.md +131 -0
  192. package/framework/skills/frontend-master/reference/ux-writing.md +107 -0
  193. package/framework/skills/harden/SKILL.md +357 -0
  194. package/framework/skills/i18n-rtl/SKILL.md +752 -0
  195. package/framework/skills/learn/SKILL.md +71 -0
  196. package/framework/skills/memory/SKILL.md +50 -0
  197. package/framework/skills/mobile-expo/SKILL.md +864 -0
  198. package/framework/skills/mobile-expo/references/store-checklist.md +550 -0
  199. package/framework/skills/nestjs-backend/README.md +73 -0
  200. package/framework/skills/nestjs-backend/SKILL.md +446 -0
  201. package/framework/skills/nestjs-backend/references/templates.md +1173 -0
  202. package/framework/skills/normalize/SKILL.md +79 -0
  203. package/framework/skills/onboard/SKILL.md +242 -0
  204. package/framework/skills/polish/SKILL.md +209 -0
  205. package/framework/skills/pr/SKILL.md +66 -0
  206. package/framework/skills/qualia/SKILL.md +153 -0
  207. package/framework/skills/qualia-add-todo/SKILL.md +68 -0
  208. package/framework/skills/qualia-audit-milestone/SKILL.md +92 -0
  209. package/framework/skills/qualia-check-todos/SKILL.md +55 -0
  210. package/framework/skills/qualia-complete-milestone/SKILL.md +108 -0
  211. package/framework/skills/qualia-debug/SKILL.md +149 -0
  212. package/framework/skills/qualia-design/SKILL.md +203 -0
  213. package/framework/skills/qualia-discuss-phase/SKILL.md +72 -0
  214. package/framework/skills/qualia-execute-phase/SKILL.md +86 -0
  215. package/framework/skills/qualia-help/SKILL.md +67 -0
  216. package/framework/skills/qualia-idk/SKILL.md +352 -0
  217. package/framework/skills/qualia-list-phase-assumptions/SKILL.md +67 -0
  218. package/framework/skills/qualia-new-milestone/SKILL.md +72 -0
  219. package/framework/skills/qualia-new-project/SKILL.md +92 -0
  220. package/framework/skills/qualia-optimize/SKILL.md +417 -0
  221. package/framework/skills/qualia-pause-work/SKILL.md +96 -0
  222. package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +57 -0
  223. package/framework/skills/qualia-plan-phase/SKILL.md +101 -0
  224. package/framework/skills/qualia-progress/SKILL.md +53 -0
  225. package/framework/skills/qualia-quick/SKILL.md +89 -0
  226. package/framework/skills/qualia-research-phase/SKILL.md +88 -0
  227. package/framework/skills/qualia-resume-work/SKILL.md +62 -0
  228. package/framework/skills/qualia-review/SKILL.md +263 -0
  229. package/framework/skills/qualia-start/SKILL.md +182 -0
  230. package/framework/skills/qualia-verify-work/SKILL.md +105 -0
  231. package/framework/skills/qualia-workflow/SKILL.md +130 -0
  232. package/framework/skills/rag/SKILL.md +750 -0
  233. package/framework/skills/responsive/SKILL.md +231 -0
  234. package/framework/skills/retro/SKILL.md +284 -0
  235. package/framework/skills/sakani-conventions/SKILL.md +136 -0
  236. package/framework/skills/sakani-conventions/evals/evals.json +23 -0
  237. package/framework/skills/sakani-conventions/references/entities.md +365 -0
  238. package/framework/skills/sakani-conventions/references/error-codes.md +95 -0
  239. package/framework/skills/seo-master/SKILL.md +490 -0
  240. package/framework/skills/seo-master/references/checklist.md +199 -0
  241. package/framework/skills/seo-master/references/structured-data.md +609 -0
  242. package/framework/skills/ship/SKILL.md +202 -0
  243. package/framework/skills/stack-researcher/SKILL.md +215 -0
  244. package/framework/skills/status/SKILL.md +154 -0
  245. package/framework/skills/status/scripts/health-check.sh +562 -0
  246. package/framework/skills/subscription-payments/SKILL.md +250 -0
  247. package/framework/skills/supabase/SKILL.md +973 -0
  248. package/framework/skills/supabase/references/templates.md +159 -0
  249. package/framework/skills/team/SKILL.md +67 -0
  250. package/framework/skills/test-runner/SKILL.md +202 -0
  251. package/framework/skills/voice-agent/SKILL.md +407 -0
  252. package/framework/skills/zoho-workflow/SKILL.md +51 -0
  253. package/framework/statusline-command.sh +117 -0
  254. package/package.json +24 -0
  255. package/profiles/fawzi.json +16 -0
  256. package/profiles/hasan.json +16 -0
  257. package/profiles/moayad.json +16 -0
  258. package/templates/CLAUDE-owner.md +52 -0
  259. package/templates/CLAUDE.md.hbs +58 -0
  260. package/templates/env.claude.template +12 -0
  261. package/templates/settings.json +141 -0
@@ -0,0 +1,752 @@
1
+ ---
2
+ name: i18n-rtl
3
+ description: "Internationalization and RTL (Right-to-Left) layout patterns — Arabic/English bilingual apps, RTL CSS/Tailwind, message key systems, locale switching, numeral handling, date/time formatting, and bidirectional text. Use whenever implementing multi-language support, Arabic UI, RTL layouts, translation systems, or locale-aware formatting in web or mobile apps. Triggers on: i18n, internationalization, RTL, right-to-left, Arabic, translation, locale, language switching, bilingual, message keys, متعدد اللغات."
4
+ tags: [i18n, rtl, arabic, localization]
5
+ ---
6
+
7
+ # Internationalization & RTL (Right-to-Left) Layout Patterns
8
+
9
+ This skill covers Arabic/English bilingual application design—message key architectures, RTL layout strategies, locale detection, numeral display, date/time formatting, and bidirectional text handling.
10
+
11
+ ## Core Architecture
12
+
13
+ ### Message Key System
14
+
15
+ All user-facing strings must use message keys. No hardcoded text anywhere—this enables translation, consistency, and independent text updates without code changes.
16
+
17
+ **Backend Contract:**
18
+ - Backend returns only message keys and structured data
19
+ - Never return display text from the server
20
+ - Include all context needed for plural/conditional rendering
21
+
22
+ **Frontend Resolution:**
23
+ - React context or hooks resolve keys → localized strings
24
+ - Fallback chain: user locale → default locale (ar) → key itself
25
+
26
+ **Key Naming Convention:**
27
+
28
+ ```typescript
29
+ // In @sakani/shared or dedicated i18n package
30
+ // Dot-notation, grouped by domain and entity
31
+ const translations = {
32
+ ar: {
33
+ // Building domain
34
+ 'building.name': 'اسم المبنى',
35
+ 'building.type.residential': 'سكني',
36
+ 'building.type.commercial': 'تجاري',
37
+ 'building.label.floorNumber': 'رقم الطابق',
38
+
39
+ // Error domain (all error codes → message keys)
40
+ 'error.auth.unauthenticated': 'يرجى تسجيل الدخول',
41
+ 'error.auth.forbidden': 'ليس لديك صلاحيات كافية',
42
+ 'error.validation.required': 'هذا الحقل مطلوب',
43
+ 'error.validation.emailInvalid': 'البريد الإلكتروني غير صحيح',
44
+
45
+ // Dues domain (reason codes → message keys)
46
+ 'dues.status.paid': 'مدفوع',
47
+ 'dues.status.unpaid': 'غير مدفوع',
48
+ 'dues.status.late': 'متأخر',
49
+ 'dues.reason.regularExpense': 'مصروف منتظم',
50
+ 'dues.reason.specialAssessment': 'تقييم خاص',
51
+
52
+ // Action domain
53
+ 'action.create': 'إنشاء',
54
+ 'action.update': 'تحديث',
55
+ 'action.delete': 'حذف',
56
+ 'action.save': 'حفظ',
57
+ 'action.cancel': 'إلغاء',
58
+ },
59
+ en: {
60
+ 'building.name': 'Building Name',
61
+ 'building.type.residential': 'Residential',
62
+ 'building.type.commercial': 'Commercial',
63
+ 'building.label.floorNumber': 'Floor Number',
64
+
65
+ 'error.auth.unauthenticated': 'Please sign in',
66
+ 'error.auth.forbidden': 'You do not have permission',
67
+ 'error.validation.required': 'This field is required',
68
+ 'error.validation.emailInvalid': 'Email address is invalid',
69
+
70
+ 'dues.status.paid': 'Paid',
71
+ 'dues.status.unpaid': 'Unpaid',
72
+ 'dues.status.late': 'Late',
73
+ 'dues.reason.regularExpense': 'Regular Expense',
74
+ 'dues.reason.specialAssessment': 'Special Assessment',
75
+
76
+ 'action.create': 'Create',
77
+ 'action.update': 'Update',
78
+ 'action.delete': 'Delete',
79
+ 'action.save': 'Save',
80
+ 'action.cancel': 'Cancel',
81
+ }
82
+ };
83
+ ```
84
+
85
+ **Naming Pattern:**
86
+ - `{domain}.{entity}.{property}` — for attributes/labels
87
+ - `{domain}.{action}.{context}` — for operations/statuses
88
+ - All error codes map 1:1 to a message key
89
+ - All reason/status codes are message keys, not magic strings
90
+
91
+ ### Locale Detection & Persistence
92
+
93
+ **Priority Order:**
94
+ 1. User preference (profile setting, synced across devices)
95
+ 2. Device locale (from OS settings)
96
+ 3. Default: `ar` (Arabic)
97
+
98
+ **Persistence:**
99
+ - Web: localStorage + server user profile
100
+ - Mobile: AsyncStorage + server user profile
101
+ - On app load: fetch user preference from profile (source of truth)
102
+ - On logout: fall back to device locale
103
+ - Offline: use last known preference from device storage
104
+
105
+ ## RTL Layout — Web (Tailwind CSS)
106
+
107
+ ### Setup
108
+
109
+ Install and configure `tailwindcss-rtl` plugin:
110
+
111
+ ```bash
112
+ npm install tailwindcss-rtl
113
+ ```
114
+
115
+ ```javascript
116
+ // tailwind.config.js
117
+ module.exports = {
118
+ plugins: [require('tailwindcss-rtl')],
119
+ };
120
+ ```
121
+
122
+ ### Logical Properties (Not Physical)
123
+
124
+ Use Tailwind's logical property system—`start`/`end` instead of `left`/`right`, which automatically flip based on text direction.
125
+
126
+ **Examples:**
127
+
128
+ | Use | Don't Use | When RTL |
129
+ |-----|-----------|---------|
130
+ | `ms-4` | `ml-4` | becomes `margin-right` |
131
+ | `ps-8` | `pl-8` | becomes `padding-right` |
132
+ | `text-start` | `text-left` | becomes `text-right` |
133
+ | `float-start` | `float-left` | becomes `float-right` |
134
+ | `rounded-s-lg` | `rounded-l-lg` | becomes `rounded-r-lg` |
135
+ | `border-s-2` | `border-l-2` | becomes `border-r-2` |
136
+ | `inset-s-0` | `inset-l-0` | becomes `inset-r-0` |
137
+
138
+ **Complete Example:**
139
+
140
+ ```jsx
141
+ // Header with logo (start) and menu button (end)
142
+ <header className="flex items-center justify-between p-4">
143
+ <div className="w-10 h-10">Logo</div>
144
+ <button>Menu</button>
145
+ </header>
146
+
147
+ // Sidebar layout — flex-col on mobile, row on desktop
148
+ // RTL: flex-row-reverse flips the sidebar to the right
149
+ <div className="flex flex-col md:flex-row md:rtl:flex-row-reverse gap-4">
150
+ <aside className="w-full md:w-64">Sidebar</aside>
151
+ <main className="flex-1">Content</main>
152
+ </div>
153
+
154
+ // List with icon (left in LTR, right in RTL)
155
+ <li className="flex items-center gap-3">
156
+ <span className="text-xl">✓</span>
157
+ <span>Item text</span>
158
+ </li>
159
+
160
+ // Input with icon inside
161
+ <div className="relative">
162
+ <input className="ps-10 pe-4" type="text" />
163
+ <span className="absolute inset-s-0 flex items-center ps-3">🔍</span>
164
+ </div>
165
+ ```
166
+
167
+ ### Root Element & Direction
168
+
169
+ Set `dir` attribute on the root element:
170
+
171
+ ```jsx
172
+ // In your layout wrapper or _app.tsx
173
+ import { useLocale } from '@/hooks/useLocale';
174
+
175
+ export default function App({ Component, pageProps }) {
176
+ const { locale } = useLocale();
177
+
178
+ return (
179
+ <html dir={locale === 'ar' ? 'rtl' : 'ltr'}>
180
+ <head>
181
+ <meta charSet="utf-8" />
182
+ </head>
183
+ <body>
184
+ <Component {...pageProps} />
185
+ </body>
186
+ </html>
187
+ );
188
+ }
189
+ ```
190
+
191
+ Or with Next.js `next-intl`:
192
+
193
+ ```jsx
194
+ import { useLocale } from 'next-intl';
195
+
196
+ export default function RootLayout({ children }) {
197
+ const locale = useLocale();
198
+
199
+ return (
200
+ <html dir={locale === 'ar' ? 'rtl' : 'ltr'} lang={locale}>
201
+ {children}
202
+ </html>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ### RTL-Specific Overrides
208
+
209
+ Use the `rtl:` variant for RTL-only styles:
210
+
211
+ ```jsx
212
+ // Icon that should point right in LTR, left in RTL
213
+ <svg className="w-4 h-4 rtl:rotate-180">
214
+ <use href="#arrow-right" />
215
+ </svg>
216
+
217
+ // Navigation arrow that reverses in RTL
218
+ <button className="flex items-center gap-2 rtl:flex-row-reverse">
219
+ <span>Next</span>
220
+ <ChevronRight className="w-4 h-4" />
221
+ </button>
222
+
223
+ // Grid that becomes single column in RTL (depends on layout)
224
+ <div className="grid grid-cols-3 gap-4 rtl:grid-cols-1">
225
+ ...
226
+ </div>
227
+ ```
228
+
229
+ ### Icons & Graphics
230
+
231
+ Icons need manual flipping in RTL. Common ones to flip:
232
+
233
+ - Chevrons / arrows (right, left)
234
+ - Play buttons (play, pause, skip)
235
+ - Notifications (bell, envelope)
236
+ - Checkmarks / close icons (usually symmetric, no flip)
237
+
238
+ **Implementation:**
239
+
240
+ ```jsx
241
+ import { useLocale } from '@/hooks/useLocale';
242
+
243
+ function ChevronRight() {
244
+ const { locale } = useLocale();
245
+ const isRTL = locale === 'ar';
246
+
247
+ return (
248
+ <svg className={isRTL ? 'rotate-180' : ''}>
249
+ <path d="M9 5l5 7-5 7" />
250
+ </svg>
251
+ );
252
+ }
253
+
254
+ // Or use a utility:
255
+ function DirectionalIcon({ children, icon }) {
256
+ const { locale } = useLocale();
257
+ return locale === 'ar' && icon.flipsInRTL ? (
258
+ <span className="inline-block rotate-180">{children}</span>
259
+ ) : (
260
+ children
261
+ );
262
+ }
263
+ ```
264
+
265
+ ## RTL Layout — React Native
266
+
267
+ ### Forced RTL Mode
268
+
269
+ ```typescript
270
+ import { I18nManager } from 'react-native';
271
+ import { useLocale } from '@/hooks/useLocale';
272
+
273
+ // In app initialization / locale context
274
+ export function useRTL() {
275
+ const { locale } = useLocale();
276
+ const isRTL = locale === 'ar';
277
+
278
+ useEffect(() => {
279
+ I18nManager.forceRTL(isRTL);
280
+ // Note: May require app reload on some platforms
281
+ }, [isRTL]);
282
+
283
+ return isRTL;
284
+ }
285
+
286
+ // Check current RTL state
287
+ const isCurrentlyRTL = I18nManager.isRTL;
288
+ ```
289
+
290
+ ### Layout Patterns
291
+
292
+ ```typescript
293
+ import { StyleSheet, View, Text, I18nManager } from 'react-native';
294
+
295
+ const styles = StyleSheet.create({
296
+ // Use logical properties where possible
297
+ container: {
298
+ paddingStart: 16,
299
+ paddingEnd: 16,
300
+ },
301
+
302
+ // Flip flex direction for RTL
303
+ row: {
304
+ flexDirection: 'row',
305
+ },
306
+ rowReverse: {
307
+ flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
308
+ },
309
+
310
+ // Text alignment
311
+ textStart: {
312
+ textAlign: I18nManager.isRTL ? 'right' : 'left',
313
+ },
314
+ textEnd: {
315
+ textAlign: I18nManager.isRTL ? 'left' : 'right',
316
+ },
317
+ });
318
+
319
+ // Component with RTL awareness
320
+ function Header() {
321
+ const isRTL = I18nManager.isRTL;
322
+
323
+ return (
324
+ <View style={[styles.row, { justifyContent: 'space-between' }]}>
325
+ <Text>Title</Text>
326
+ <Icon
327
+ name={isRTL ? 'chevron-left' : 'chevron-right'}
328
+ size={24}
329
+ />
330
+ </View>
331
+ );
332
+ }
333
+ ```
334
+
335
+ ### TextInput & Text Direction
336
+
337
+ ```typescript
338
+ <TextInput
339
+ style={{ textAlign: I18nManager.isRTL ? 'right' : 'left' }}
340
+ writingDirection={I18nManager.isRTL ? 'rtl' : 'ltr'}
341
+ placeholder="Type here..."
342
+ />
343
+ ```
344
+
345
+ ## Numeral Display
346
+
347
+ **Rule: Always display Western Arabic numerals (0–9), never Eastern Arabic (٠–٩).**
348
+
349
+ Even in Arabic locale, use `0-9`. This applies to:
350
+ - Prices: `1,234.56`
351
+ - Quantities: `12`
352
+ - Dates: `2025-03-06`
353
+ - Phone numbers: `+962 6 123 4567`
354
+
355
+ **Implementation:**
356
+
357
+ ```typescript
358
+ // Correct: Western numerals in Arabic
359
+ const formatter = new Intl.NumberFormat('ar-JO');
360
+ formatter.format(1234); // → "1,234"
361
+
362
+ // Correct: Using date-fns (automatically handles numerals)
363
+ import { format } from 'date-fns';
364
+ import { ar } from 'date-fns/locale';
365
+ format(new Date(), 'd/M/yyyy', { locale: ar }); // → "06/03/2025"
366
+
367
+ // Avoid: Eastern Arabic numerals
368
+ // ❌ "١٢٣٤" — don't display this in UI
369
+ ```
370
+
371
+ ## Date & Time Formatting
372
+
373
+ ### Storage & Timezone
374
+
375
+ - **Store:** Always UTC in the database
376
+ - **Display:** Asia/Amman timezone (Jordan local time)
377
+ - **Format:** Use `Intl.DateTimeFormat` or `date-fns` with locale
378
+
379
+ ### Implementation
380
+
381
+ ```typescript
382
+ import { format } from 'date-fns';
383
+ import { ar, en } from 'date-fns/locale';
384
+
385
+ function formatDate(isoDate: string, locale: 'ar' | 'en') {
386
+ const date = new Date(isoDate);
387
+
388
+ if (locale === 'ar') {
389
+ return format(date, 'd MMMM yyyy', { locale: ar });
390
+ // → "06 مارس 2025"
391
+ }
392
+
393
+ return format(date, 'd MMMM yyyy', { locale: en });
394
+ // → "6 March 2025"
395
+ }
396
+
397
+ // Or with Intl.DateTimeFormat
398
+ function formatDateIntl(isoDate: string, locale: 'ar' | 'en') {
399
+ const date = new Date(isoDate);
400
+ return new Intl.DateTimeFormat(locale === 'ar' ? 'ar-JO' : 'en-GB', {
401
+ year: 'numeric',
402
+ month: 'long',
403
+ day: 'numeric',
404
+ timeZone: 'Asia/Amman',
405
+ }).format(date);
406
+ }
407
+
408
+ // Time with timezone awareness
409
+ function formatTime(isoDate: string, locale: 'ar' | 'en') {
410
+ const date = new Date(isoDate);
411
+ return new Intl.DateTimeFormat(locale === 'ar' ? 'ar-JO' : 'en-GB', {
412
+ hour: '2-digit',
413
+ minute: '2-digit',
414
+ second: '2-digit',
415
+ timeZone: 'Asia/Amman',
416
+ }).format(date);
417
+ }
418
+ ```
419
+
420
+ ### Date Formats by Locale
421
+
422
+ - **Arabic:** `DD/MM/YYYY` — `06/03/2025`
423
+ - **English:** `DD/MM/YYYY` or `MM/DD/YYYY` depending on region
424
+ - Always use locale-aware formatters, don't hardcode
425
+
426
+ ## Currency Formatting
427
+
428
+ ### Jordan Dinar (JOD)
429
+
430
+ - **Currency Code:** JOD
431
+ - **Decimal Places:** 3
432
+ - **Decimal Separator:** `.` (universal) or `٫` (Arabic specific)
433
+ - **Symbol Position:** After amount in Arabic, before in English
434
+
435
+ ### Implementation
436
+
437
+ ```typescript
438
+ function formatCurrency(amount: number, locale: 'ar' | 'en') {
439
+ const formatter = new Intl.NumberFormat(locale === 'ar' ? 'ar-JO' : 'en-GB', {
440
+ style: 'currency',
441
+ currency: 'JOD',
442
+ minimumFractionDigits: 3,
443
+ maximumFractionDigits: 3,
444
+ });
445
+
446
+ return formatter.format(amount);
447
+ // ar: "12٫000 د.أ"
448
+ // en: "JOD 12.000"
449
+ }
450
+
451
+ // Manual formatting with custom formatting
452
+ function formatCurrencyCustom(amount: number, locale: 'ar' | 'en') {
453
+ const numStr = amount.toFixed(3);
454
+ const symbol = 'د.أ'; // JOD symbol
455
+
456
+ if (locale === 'ar') {
457
+ return `${numStr} ${symbol}`;
458
+ }
459
+
460
+ return `JOD ${numStr}`;
461
+ }
462
+ ```
463
+
464
+ ## Locale Switching
465
+
466
+ ### User Preference Flow
467
+
468
+ 1. **On App Load:**
469
+ - Fetch user profile (includes locale preference)
470
+ - If missing, use device locale
471
+ - If not ar/en, default to ar
472
+
473
+ 2. **User Changes Language:**
474
+ - Update user profile (API call)
475
+ - Update local context/state
476
+ - Update UI direction (`dir` attribute or `I18nManager.forceRTL`)
477
+ - Reload component tree or update i18n library
478
+
479
+ 3. **Persistence:**
480
+ - Web: localStorage + server (server is source of truth)
481
+ - Mobile: AsyncStorage + server (server is source of truth)
482
+
483
+ ### Implementation
484
+
485
+ ```typescript
486
+ // useLocale hook
487
+ import { createContext, useContext, useState, useEffect } from 'react';
488
+
489
+ const LocaleContext = createContext<{
490
+ locale: 'ar' | 'en';
491
+ setLocale: (locale: 'ar' | 'en') => Promise<void>;
492
+ }>(null);
493
+
494
+ export function LocaleProvider({ children }) {
495
+ const [locale, setLocaleState] = useState<'ar' | 'en'>('ar');
496
+ const [loading, setLoading] = useState(true);
497
+
498
+ useEffect(() => {
499
+ // Fetch user profile on mount
500
+ async function initLocale() {
501
+ try {
502
+ const profile = await fetchUserProfile();
503
+ const userLocale = profile.locale || 'ar';
504
+ setLocaleState(userLocale);
505
+
506
+ // Apply to DOM/RN
507
+ if (typeof document !== 'undefined') {
508
+ document.documentElement.dir = userLocale === 'ar' ? 'rtl' : 'ltr';
509
+ document.documentElement.lang = userLocale;
510
+ }
511
+ } catch (err) {
512
+ // Fallback to device locale
513
+ setLocaleState('ar');
514
+ } finally {
515
+ setLoading(false);
516
+ }
517
+ }
518
+
519
+ initLocale();
520
+ }, []);
521
+
522
+ const setLocale = async (newLocale: 'ar' | 'en') => {
523
+ try {
524
+ // Update server
525
+ await updateUserProfile({ locale: newLocale });
526
+
527
+ // Update local state
528
+ setLocaleState(newLocale);
529
+
530
+ // Update DOM
531
+ if (typeof document !== 'undefined') {
532
+ document.documentElement.dir = newLocale === 'ar' ? 'rtl' : 'ltr';
533
+ document.documentElement.lang = newLocale;
534
+ }
535
+
536
+ // Persist to device storage
537
+ if (typeof localStorage !== 'undefined') {
538
+ localStorage.setItem('locale', newLocale);
539
+ }
540
+ } catch (err) {
541
+ console.error('Failed to change locale:', err);
542
+ }
543
+ };
544
+
545
+ return (
546
+ <LocaleContext.Provider value={{ locale, setLocale }}>
547
+ {!loading && children}
548
+ </LocaleContext.Provider>
549
+ );
550
+ }
551
+
552
+ export function useLocale() {
553
+ const context = useContext(LocaleContext);
554
+ if (!context) throw new Error('useLocale must be used within LocaleProvider');
555
+ return context;
556
+ }
557
+ ```
558
+
559
+ ## Bidirectional Text
560
+
561
+ ### Mixed-Direction Content
562
+
563
+ When Arabic and English text mix (e.g., product names, brand names), use Unicode bidirectional formatting to prevent visual corruption.
564
+
565
+ **Example Problem:**
566
+ ```
567
+ Arabic: "اسم المنتج Product Name"
568
+ (text-align changes based on first character)
569
+ ```
570
+
571
+ **Solution: Use `<bdi>` tag or Unicode Isolates**
572
+
573
+ ```jsx
574
+ // Automatically isolate direction
575
+ <p>الشركة: <bdi>Apple Inc.</bdi></p>
576
+ // → "الشركة: Apple Inc." (email correct)
577
+
578
+ // Or with span and dir attribute
579
+ <span dir="auto">مرحبا Hello</span>
580
+ // → Direction auto-detected from content
581
+
582
+ // Unicode isolates (lowest-level)
583
+ <p>{'الشركة: \u2066' + 'Apple Inc.' + '\u2069'}</p>
584
+ // \u2066 = LRI (Left-to-Right Isolate)
585
+ // \u2069 = PDI (Pop Directional Isolate)
586
+ ```
587
+
588
+ ### Phone Numbers, Emails, URLs (Always LTR)
589
+
590
+ ```jsx
591
+ // Phone number in RTL context — always LTR
592
+ <p>
593
+ الهاتف: <span dir="ltr">+962 6 123 4567</span>
594
+ </p>
595
+
596
+ // Email address
597
+ <a href="mailto:user@example.com" dir="ltr">
598
+ user@example.com
599
+ </a>
600
+
601
+ // URL in Arabic text
602
+ <p>
603
+ زيارة الموقع: <span dir="ltr">https://example.com</span>
604
+ </p>
605
+ ```
606
+
607
+ ### User-Generated Content
608
+
609
+ For text from users (comments, descriptions), use `<bdi>` to auto-detect direction:
610
+
611
+ ```jsx
612
+ function UserComment({ text, locale }) {
613
+ return (
614
+ <div className={locale === 'ar' ? 'text-right' : 'text-left'}>
615
+ <bdi>{text}</bdi>
616
+ {/* Auto-detects whether text is RTL or LTR */}
617
+ </div>
618
+ );
619
+ }
620
+ ```
621
+
622
+ ## Common Mistakes & How to Avoid
623
+
624
+ ### 1. Using Physical Properties Instead of Logical
625
+
626
+ ```jsx
627
+ // ❌ Wrong: Text will be on the wrong side in RTL
628
+ <div className="ml-4 float-left">Content</div>
629
+
630
+ // ✓ Correct: Automatically flips in RTL
631
+ <div className="ms-4 float-start">Content</div>
632
+ ```
633
+
634
+ ### 2. Forgetting to Flip Icons
635
+
636
+ ```jsx
637
+ // ❌ Wrong: Arrow always points right
638
+ <button>
639
+ Next <ChevronRight />
640
+ </button>
641
+
642
+ // ✓ Correct: Icon flips based on locale
643
+ function NextButton() {
644
+ const { locale } = useLocale();
645
+ return (
646
+ <button className={locale === 'ar' ? 'flex-row-reverse' : ''}>
647
+ Next
648
+ <ChevronRight className={locale === 'ar' ? 'rotate-180' : ''} />
649
+ </button>
650
+ );
651
+ }
652
+ ```
653
+
654
+ ### 3. Testing with Latin Placeholders Hides RTL Bugs
655
+
656
+ ```
657
+ ❌ "Lorem ipsum" in RTL container looks correct
658
+ ✓ "مرحبا بك" (Arabic) immediately reveals direction issues
659
+ ```
660
+
661
+ **Always test with actual Arabic text**, not Lorem Ipsum.
662
+
663
+ ### 4. Hardcoding Text Alignment
664
+
665
+ ```jsx
666
+ // ❌ Wrong: Alignment is fixed regardless of direction
667
+ <h1 style={{ textAlign: 'left' }}>Title</h1>
668
+
669
+ // ✓ Correct: Flips based on locale
670
+ <h1 className="text-start">Title</h1>
671
+ // or
672
+ <h1 style={{ textAlign: locale === 'ar' ? 'right' : 'left' }}>Title</h1>
673
+ ```
674
+
675
+ ### 5. Not Isolating Mixed-Direction Content
676
+
677
+ ```jsx
678
+ // ❌ Wrong: "Product Name" gets pulled to the wrong side
679
+ <p>المنتج: Product Name</p>
680
+
681
+ // ✓ Correct: Uses bidirectional isolation
682
+ <p>المنتج: <bdi>Product Name</bdi></p>
683
+ ```
684
+
685
+ ### 6. Using Eastern Arabic Numerals (٠–٩)
686
+
687
+ ```
688
+ ❌ "السعر: ١٢٣٤"
689
+ ✓ "السعر: 1234"
690
+ ```
691
+
692
+ Always use Western numerals (0–9), even in Arabic UI.
693
+
694
+ ## Recommended Libraries
695
+
696
+ ### Web (Next.js or React)
697
+
698
+ - **`next-intl`** — Built for Next.js, excellent RTL support, type-safe message keys
699
+ ```bash
700
+ npm install next-intl
701
+ ```
702
+ Configuration in `next.config.js`, message files in `messages/` directory.
703
+
704
+ - **`react-i18next`** — Popular, flexible, works with any React setup
705
+ ```bash
706
+ npm install i18next react-i18next
707
+ ```
708
+ Share translation files with backend/mobile via `@sakani/shared`.
709
+
710
+ ### Mobile (React Native/Expo)
711
+
712
+ - **`react-i18next`** — Same library as web, share translation files
713
+ - **`expo-localization`** — Get device locale
714
+ ```bash
715
+ npx expo install expo-localization
716
+ ```
717
+
718
+ ### Shared (Backend & Frontend)
719
+
720
+ - **`i18next`** — Core i18n engine, language-agnostic
721
+ - Message files in JSON or TypeScript in shared package (`@sakani/shared/i18n/`)
722
+ - Both frontend and backend import from shared package
723
+
724
+ ### Date & Time
725
+
726
+ - **`date-fns`** — Lightweight, tree-shakeable, excellent locale support
727
+ ```bash
728
+ npm install date-fns
729
+ ```
730
+ Import locales: `import { ar } from 'date-fns/locale'`
731
+
732
+ - **Native `Intl` API** — Built-in, no dependencies, sufficient for most use cases
733
+ ```typescript
734
+ new Intl.DateTimeFormat('ar-JO', { ... }).format(date)
735
+ ```
736
+
737
+ ## Summary Checklist
738
+
739
+ - [ ] All UI strings use message keys (`key.domain.entity`)
740
+ - [ ] Backend returns message keys, never display text
741
+ - [ ] Frontend resolves keys via i18n library (next-intl, react-i18next, etc.)
742
+ - [ ] Web: `tailwindcss-rtl` installed, using logical properties (`ms-`, `ps-`, `text-start`)
743
+ - [ ] Web: Root `dir="rtl"` set when locale is Arabic
744
+ - [ ] Mobile: `I18nManager.forceRTL(isArabic)` on app init
745
+ - [ ] Icons tested and flipped for RTL (chevrons, arrows)
746
+ - [ ] Date formatting uses `Intl.DateTimeFormat` or `date-fns` with locale
747
+ - [ ] All numerals are Western (0–9), never Eastern (٠–٩)
748
+ - [ ] Mixed-direction content (Arabic + English) uses `<bdi>` or `dir="auto"`
749
+ - [ ] Phone numbers, emails, URLs wrapped in `dir="ltr"`
750
+ - [ ] Locale preference stored in user profile (synced) + device storage (offline)
751
+ - [ ] Locale switcher tested: changes are persisted and UI updates immediately
752
+ - [ ] RTL testing done with **actual Arabic text**, not placeholders