qualia-framework 2.5.1 → 3.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 (327) hide show
  1. package/CLAUDE.md +63 -0
  2. package/README.md +108 -30
  3. package/agents/builder.md +110 -0
  4. package/agents/planner.md +186 -0
  5. package/agents/qa-browser.md +186 -0
  6. package/agents/verifier.md +369 -0
  7. package/bin/cli.js +706 -417
  8. package/bin/install.js +622 -0
  9. package/bin/qualia-ui.js +284 -0
  10. package/bin/state.js +824 -0
  11. package/bin/statusline.js +252 -0
  12. package/docs/erp-contract.md +161 -0
  13. package/guide.md +63 -0
  14. package/hooks/auto-update.js +117 -0
  15. package/hooks/block-env-edit.js +52 -0
  16. package/hooks/branch-guard.js +68 -0
  17. package/hooks/migration-guard.js +83 -0
  18. package/hooks/pre-compact.js +52 -0
  19. package/hooks/pre-deploy-gate.js +149 -0
  20. package/hooks/pre-push.js +53 -0
  21. package/hooks/session-start.js +126 -0
  22. package/package.json +31 -17
  23. package/rules/design-reference.md +179 -0
  24. package/rules/frontend.md +126 -0
  25. package/rules/infrastructure.md +87 -0
  26. package/skills/qualia/SKILL.md +88 -0
  27. package/skills/qualia-build/SKILL.md +115 -0
  28. package/skills/qualia-debug/SKILL.md +87 -0
  29. package/skills/qualia-design/SKILL.md +99 -0
  30. package/skills/qualia-handoff/SKILL.md +66 -0
  31. package/skills/qualia-help/SKILL.md +60 -0
  32. package/skills/qualia-idk/SKILL.md +8 -0
  33. package/skills/qualia-learn/SKILL.md +111 -0
  34. package/skills/qualia-new/SKILL.md +323 -0
  35. package/skills/qualia-pause/SKILL.md +63 -0
  36. package/skills/qualia-plan/SKILL.md +101 -0
  37. package/skills/qualia-polish/SKILL.md +207 -0
  38. package/skills/qualia-quick/SKILL.md +37 -0
  39. package/skills/qualia-report/SKILL.md +114 -0
  40. package/skills/qualia-resume/SKILL.md +49 -0
  41. package/skills/qualia-review/SKILL.md +161 -0
  42. package/skills/qualia-ship/SKILL.md +90 -0
  43. package/skills/qualia-skill-new/SKILL.md +167 -0
  44. package/skills/qualia-task/SKILL.md +91 -0
  45. package/skills/qualia-test/SKILL.md +134 -0
  46. package/skills/qualia-verify/SKILL.md +113 -0
  47. package/templates/DESIGN.md +475 -0
  48. package/templates/help.html +476 -0
  49. package/templates/plan.md +42 -0
  50. package/templates/project.md +22 -0
  51. package/templates/state.md +27 -0
  52. package/templates/tracking.json +20 -0
  53. package/tests/bin.test.sh +687 -0
  54. package/tests/hooks.test.sh +384 -0
  55. package/tests/runner.js +1956 -0
  56. package/tests/state.test.sh +713 -0
  57. package/tests/statusline.test.sh +243 -0
  58. package/bin/collect-metrics.sh +0 -62
  59. package/framework/.claudeignore +0 -51
  60. package/framework/CLAUDE.md +0 -51
  61. package/framework/MCP_SETUP.md +0 -229
  62. package/framework/agents/architecture-strategist.md +0 -53
  63. package/framework/agents/backend-agent.md +0 -150
  64. package/framework/agents/code-simplicity-reviewer.md +0 -86
  65. package/framework/agents/frontend-agent.md +0 -111
  66. package/framework/agents/kieran-typescript-reviewer.md +0 -96
  67. package/framework/agents/performance-oracle.md +0 -111
  68. package/framework/agents/qualia-codebase-mapper.md +0 -761
  69. package/framework/agents/qualia-debugger.md +0 -1204
  70. package/framework/agents/qualia-executor.md +0 -882
  71. package/framework/agents/qualia-integration-checker.md +0 -424
  72. package/framework/agents/qualia-phase-researcher.md +0 -457
  73. package/framework/agents/qualia-plan-checker.md +0 -700
  74. package/framework/agents/qualia-planner.md +0 -1245
  75. package/framework/agents/qualia-project-researcher.md +0 -603
  76. package/framework/agents/qualia-research-synthesizer.md +0 -200
  77. package/framework/agents/qualia-roadmapper.md +0 -606
  78. package/framework/agents/qualia-verifier.md +0 -686
  79. package/framework/agents/red-team-qa.md +0 -130
  80. package/framework/agents/security-auditor.md +0 -72
  81. package/framework/agents/team-orchestrator.md +0 -229
  82. package/framework/agents/teams/framework-audit-team.md +0 -66
  83. package/framework/agents/teams/full-stack-team.md +0 -48
  84. package/framework/agents/teams/optimize-team.md +0 -53
  85. package/framework/agents/teams/review-team.md +0 -70
  86. package/framework/agents/teams/ship-team.md +0 -86
  87. package/framework/agents/test-agent.md +0 -182
  88. package/framework/hooks/auto-format.sh +0 -54
  89. package/framework/hooks/block-env-edit.sh +0 -42
  90. package/framework/hooks/branch-guard.sh +0 -43
  91. package/framework/hooks/confirm-delete.sh +0 -59
  92. package/framework/hooks/migration-validate.sh +0 -77
  93. package/framework/hooks/notification-speak.sh +0 -16
  94. package/framework/hooks/pre-commit.sh +0 -100
  95. package/framework/hooks/pre-compact.sh +0 -56
  96. package/framework/hooks/pre-deploy-gate.sh +0 -160
  97. package/framework/hooks/qualia-colors.sh +0 -32
  98. package/framework/hooks/retention-cleanup.sh +0 -62
  99. package/framework/hooks/save-session-state.sh +0 -185
  100. package/framework/hooks/session-context-loader.sh +0 -96
  101. package/framework/hooks/session-learn.sh +0 -32
  102. package/framework/hooks/skill-announce.sh +0 -123
  103. package/framework/hooks/tool-error-announce.sh +0 -27
  104. package/framework/install.ps1 +0 -323
  105. package/framework/install.sh +0 -313
  106. package/framework/qualia-framework/VERSION +0 -1
  107. package/framework/qualia-framework/assets/qualia-logo.png +0 -0
  108. package/framework/qualia-framework/bin/collect-metrics.sh +0 -67
  109. package/framework/qualia-framework/bin/generate-report-docx.py +0 -429
  110. package/framework/qualia-framework/bin/qualia-tools.js +0 -2201
  111. package/framework/qualia-framework/bin/qualia-tools.test.js +0 -1054
  112. package/framework/qualia-framework/references/checkpoints.md +0 -775
  113. package/framework/qualia-framework/references/completion-checklists.md +0 -359
  114. package/framework/qualia-framework/references/continuation-format.md +0 -249
  115. package/framework/qualia-framework/references/continuation-prompt.md +0 -97
  116. package/framework/qualia-framework/references/decimal-phase-calculation.md +0 -65
  117. package/framework/qualia-framework/references/design-quality.md +0 -56
  118. package/framework/qualia-framework/references/employee-guide.md +0 -167
  119. package/framework/qualia-framework/references/git-integration.md +0 -254
  120. package/framework/qualia-framework/references/git-planning-commit.md +0 -50
  121. package/framework/qualia-framework/references/model-profile-resolution.md +0 -32
  122. package/framework/qualia-framework/references/model-profiles.md +0 -73
  123. package/framework/qualia-framework/references/phase-argument-parsing.md +0 -61
  124. package/framework/qualia-framework/references/planning-config.md +0 -195
  125. package/framework/qualia-framework/references/questioning.md +0 -141
  126. package/framework/qualia-framework/references/tdd.md +0 -263
  127. package/framework/qualia-framework/references/ui-brand.md +0 -160
  128. package/framework/qualia-framework/references/verification-patterns.md +0 -612
  129. package/framework/qualia-framework/templates/DEBUG.md +0 -159
  130. package/framework/qualia-framework/templates/DESIGN.md +0 -81
  131. package/framework/qualia-framework/templates/UAT.md +0 -247
  132. package/framework/qualia-framework/templates/codebase/architecture.md +0 -255
  133. package/framework/qualia-framework/templates/codebase/concerns.md +0 -310
  134. package/framework/qualia-framework/templates/codebase/conventions.md +0 -307
  135. package/framework/qualia-framework/templates/codebase/integrations.md +0 -280
  136. package/framework/qualia-framework/templates/codebase/stack.md +0 -186
  137. package/framework/qualia-framework/templates/codebase/structure.md +0 -285
  138. package/framework/qualia-framework/templates/codebase/testing.md +0 -480
  139. package/framework/qualia-framework/templates/config.json +0 -35
  140. package/framework/qualia-framework/templates/context.md +0 -283
  141. package/framework/qualia-framework/templates/continue-here.md +0 -78
  142. package/framework/qualia-framework/templates/debug-subagent-prompt.md +0 -91
  143. package/framework/qualia-framework/templates/discovery.md +0 -146
  144. package/framework/qualia-framework/templates/lab-notes.md +0 -16
  145. package/framework/qualia-framework/templates/milestone-archive.md +0 -123
  146. package/framework/qualia-framework/templates/milestone.md +0 -115
  147. package/framework/qualia-framework/templates/phase-prompt.md +0 -567
  148. package/framework/qualia-framework/templates/planner-subagent-prompt.md +0 -117
  149. package/framework/qualia-framework/templates/project.md +0 -184
  150. package/framework/qualia-framework/templates/projects/ai-agent.md +0 -156
  151. package/framework/qualia-framework/templates/projects/mobile-app.md +0 -181
  152. package/framework/qualia-framework/templates/projects/voice-agent.md +0 -134
  153. package/framework/qualia-framework/templates/projects/website.md +0 -137
  154. package/framework/qualia-framework/templates/requirements.md +0 -231
  155. package/framework/qualia-framework/templates/research-project/ARCHITECTURE.md +0 -204
  156. package/framework/qualia-framework/templates/research-project/FEATURES.md +0 -147
  157. package/framework/qualia-framework/templates/research-project/PITFALLS.md +0 -200
  158. package/framework/qualia-framework/templates/research-project/STACK.md +0 -120
  159. package/framework/qualia-framework/templates/research-project/SUMMARY.md +0 -170
  160. package/framework/qualia-framework/templates/research.md +0 -552
  161. package/framework/qualia-framework/templates/roadmap.md +0 -206
  162. package/framework/qualia-framework/templates/state.md +0 -179
  163. package/framework/qualia-framework/templates/summary-complex.md +0 -59
  164. package/framework/qualia-framework/templates/summary-minimal.md +0 -41
  165. package/framework/qualia-framework/templates/summary-standard.md +0 -48
  166. package/framework/qualia-framework/templates/summary.md +0 -246
  167. package/framework/qualia-framework/templates/user-setup.md +0 -311
  168. package/framework/qualia-framework/templates/verification-report.md +0 -322
  169. package/framework/qualia-framework/workflows/add-phase.md +0 -179
  170. package/framework/qualia-framework/workflows/add-todo.md +0 -157
  171. package/framework/qualia-framework/workflows/audit-milestone.md +0 -241
  172. package/framework/qualia-framework/workflows/check-todos.md +0 -176
  173. package/framework/qualia-framework/workflows/complete-milestone.md +0 -858
  174. package/framework/qualia-framework/workflows/diagnose-issues.md +0 -219
  175. package/framework/qualia-framework/workflows/discovery-phase.md +0 -289
  176. package/framework/qualia-framework/workflows/discuss-phase.md +0 -534
  177. package/framework/qualia-framework/workflows/execute-phase.md +0 -559
  178. package/framework/qualia-framework/workflows/execute-plan.md +0 -438
  179. package/framework/qualia-framework/workflows/help.md +0 -470
  180. package/framework/qualia-framework/workflows/insert-phase.md +0 -220
  181. package/framework/qualia-framework/workflows/list-phase-assumptions.md +0 -178
  182. package/framework/qualia-framework/workflows/map-codebase.md +0 -327
  183. package/framework/qualia-framework/workflows/new-milestone.md +0 -363
  184. package/framework/qualia-framework/workflows/new-project.md +0 -982
  185. package/framework/qualia-framework/workflows/pause-work.md +0 -122
  186. package/framework/qualia-framework/workflows/plan-milestone-gaps.md +0 -256
  187. package/framework/qualia-framework/workflows/plan-phase.md +0 -422
  188. package/framework/qualia-framework/workflows/progress.md +0 -389
  189. package/framework/qualia-framework/workflows/quick.md +0 -252
  190. package/framework/qualia-framework/workflows/remove-phase.md +0 -326
  191. package/framework/qualia-framework/workflows/research-phase.md +0 -74
  192. package/framework/qualia-framework/workflows/resume-project.md +0 -306
  193. package/framework/qualia-framework/workflows/set-profile.md +0 -80
  194. package/framework/qualia-framework/workflows/settings.md +0 -145
  195. package/framework/qualia-framework/workflows/transition.md +0 -556
  196. package/framework/qualia-framework/workflows/update.md +0 -197
  197. package/framework/qualia-framework/workflows/verify-phase.md +0 -195
  198. package/framework/qualia-framework/workflows/verify-work.md +0 -625
  199. package/framework/rules/context7.md +0 -14
  200. package/framework/rules/frontend.md +0 -33
  201. package/framework/rules/speed.md +0 -23
  202. package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
  203. package/framework/scripts/apply-retention.sh +0 -120
  204. package/framework/scripts/bootstrap-pop-os.sh +0 -354
  205. package/framework/scripts/claude-voice +0 -13
  206. package/framework/scripts/cleanup.sh +0 -131
  207. package/framework/scripts/cowork-mode.sh +0 -141
  208. package/framework/scripts/generate-project-claude-md.sh +0 -153
  209. package/framework/scripts/load-test-webhook.js +0 -172
  210. package/framework/scripts/say.py +0 -236
  211. package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +0 -167
  212. package/framework/scripts/showcase-video-recorder/playwright-helpers.js +0 -216
  213. package/framework/scripts/speak.py +0 -55
  214. package/framework/scripts/speak.sh +0 -18
  215. package/framework/scripts/status.sh +0 -138
  216. package/framework/scripts/sync-to-framework.sh +0 -65
  217. package/framework/scripts/voice-hotkey.py +0 -227
  218. package/framework/scripts/voice-input.sh +0 -51
  219. package/framework/skills/animate/SKILL.md +0 -202
  220. package/framework/skills/bolder/SKILL.md +0 -144
  221. package/framework/skills/browser-qa/SKILL.md +0 -536
  222. package/framework/skills/clarify/SKILL.md +0 -179
  223. package/framework/skills/client-handoff/SKILL.md +0 -135
  224. package/framework/skills/collab-onboard/SKILL.md +0 -111
  225. package/framework/skills/colorize/SKILL.md +0 -170
  226. package/framework/skills/critique/SKILL.md +0 -126
  227. package/framework/skills/deep-research/SKILL.md +0 -240
  228. package/framework/skills/delight/SKILL.md +0 -329
  229. package/framework/skills/deploy/SKILL.md +0 -261
  230. package/framework/skills/deploy-verify/SKILL.md +0 -377
  231. package/framework/skills/deploy-verify/scripts/canary-check.sh +0 -206
  232. package/framework/skills/deploy-verify/scripts/check-console-errors.js +0 -147
  233. package/framework/skills/deploy-verify/scripts/check-cwv.js +0 -139
  234. package/framework/skills/deploy-verify/scripts/project-detect.sh +0 -84
  235. package/framework/skills/deploy-verify/scripts/verify.sh +0 -548
  236. package/framework/skills/design-quieter/SKILL.md +0 -130
  237. package/framework/skills/distill/SKILL.md +0 -149
  238. package/framework/skills/docs-lookup/SKILL.md +0 -79
  239. package/framework/skills/fcm-notifications/SKILL.md +0 -125
  240. package/framework/skills/financial-ledger/SKILL.md +0 -1039
  241. package/framework/skills/frontend-master/NOTICE.md +0 -4
  242. package/framework/skills/frontend-master/SKILL.md +0 -127
  243. package/framework/skills/frontend-master/reference/color-and-contrast.md +0 -132
  244. package/framework/skills/frontend-master/reference/interaction-design.md +0 -123
  245. package/framework/skills/frontend-master/reference/motion-design.md +0 -99
  246. package/framework/skills/frontend-master/reference/responsive-design.md +0 -114
  247. package/framework/skills/frontend-master/reference/spatial-design.md +0 -100
  248. package/framework/skills/frontend-master/reference/typography.md +0 -131
  249. package/framework/skills/frontend-master/reference/ux-writing.md +0 -107
  250. package/framework/skills/harden/SKILL.md +0 -357
  251. package/framework/skills/i18n-rtl/SKILL.md +0 -752
  252. package/framework/skills/learn/SKILL.md +0 -95
  253. package/framework/skills/memory/SKILL.md +0 -50
  254. package/framework/skills/mobile-expo/SKILL.md +0 -977
  255. package/framework/skills/mobile-expo/references/store-checklist.md +0 -550
  256. package/framework/skills/nestjs-backend/README.md +0 -73
  257. package/framework/skills/nestjs-backend/SKILL.md +0 -446
  258. package/framework/skills/nestjs-backend/references/templates.md +0 -1173
  259. package/framework/skills/normalize/SKILL.md +0 -79
  260. package/framework/skills/onboard/SKILL.md +0 -242
  261. package/framework/skills/openrouter-agent/SKILL.md +0 -922
  262. package/framework/skills/polish/SKILL.md +0 -209
  263. package/framework/skills/pr/SKILL.md +0 -66
  264. package/framework/skills/qualia/SKILL.md +0 -199
  265. package/framework/skills/qualia-add-todo/SKILL.md +0 -68
  266. package/framework/skills/qualia-audit-milestone/SKILL.md +0 -95
  267. package/framework/skills/qualia-check-todos/SKILL.md +0 -55
  268. package/framework/skills/qualia-complete-milestone/SKILL.md +0 -134
  269. package/framework/skills/qualia-debug/SKILL.md +0 -149
  270. package/framework/skills/qualia-design/SKILL.md +0 -203
  271. package/framework/skills/qualia-discuss-phase/SKILL.md +0 -72
  272. package/framework/skills/qualia-evolve/SKILL.md +0 -200
  273. package/framework/skills/qualia-execute-phase/SKILL.md +0 -89
  274. package/framework/skills/qualia-framework-audit/SKILL.md +0 -604
  275. package/framework/skills/qualia-guide/SKILL.md +0 -32
  276. package/framework/skills/qualia-help/SKILL.md +0 -114
  277. package/framework/skills/qualia-idk/SKILL.md +0 -352
  278. package/framework/skills/qualia-list-phase-assumptions/SKILL.md +0 -67
  279. package/framework/skills/qualia-new-milestone/SKILL.md +0 -72
  280. package/framework/skills/qualia-new-project/SKILL.md +0 -232
  281. package/framework/skills/qualia-optimize/SKILL.md +0 -417
  282. package/framework/skills/qualia-pause-work/SKILL.md +0 -96
  283. package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +0 -57
  284. package/framework/skills/qualia-plan-phase/SKILL.md +0 -104
  285. package/framework/skills/qualia-production-check/SKILL.md +0 -0
  286. package/framework/skills/qualia-progress/SKILL.md +0 -53
  287. package/framework/skills/qualia-quick/SKILL.md +0 -89
  288. package/framework/skills/qualia-report/SKILL.md +0 -166
  289. package/framework/skills/qualia-research-phase/SKILL.md +0 -88
  290. package/framework/skills/qualia-resume-work/SKILL.md +0 -62
  291. package/framework/skills/qualia-review/SKILL.md +0 -263
  292. package/framework/skills/qualia-start/SKILL.md +0 -161
  293. package/framework/skills/qualia-verify-work/SKILL.md +0 -132
  294. package/framework/skills/rag/SKILL.md +0 -750
  295. package/framework/skills/responsive/SKILL.md +0 -231
  296. package/framework/skills/retro/SKILL.md +0 -284
  297. package/framework/skills/sakani-conventions/SKILL.md +0 -136
  298. package/framework/skills/sakani-conventions/evals/evals.json +0 -23
  299. package/framework/skills/sakani-conventions/references/entities.md +0 -365
  300. package/framework/skills/sakani-conventions/references/error-codes.md +0 -95
  301. package/framework/skills/seo-master/SKILL.md +0 -490
  302. package/framework/skills/seo-master/references/checklist.md +0 -199
  303. package/framework/skills/seo-master/references/structured-data.md +0 -609
  304. package/framework/skills/ship/SKILL.md +0 -239
  305. package/framework/skills/stack-researcher/SKILL.md +0 -215
  306. package/framework/skills/status/SKILL.md +0 -154
  307. package/framework/skills/status/scripts/health-check.sh +0 -562
  308. package/framework/skills/subscription-payments/SKILL.md +0 -250
  309. package/framework/skills/supabase/SKILL.md +0 -973
  310. package/framework/skills/supabase/references/templates.md +0 -159
  311. package/framework/skills/team/SKILL.md +0 -67
  312. package/framework/skills/test-runner/SKILL.md +0 -202
  313. package/framework/skills/voice-agent/SKILL.md +0 -1312
  314. package/framework/skills/zoho-workflow/SKILL.md +0 -51
  315. package/framework/statusline-command.sh +0 -117
  316. package/framework/teams/default/inboxes/plan-04.json +0 -9
  317. package/framework/teams/review-team.md +0 -75
  318. package/framework/teams/ship-team.md +0 -86
  319. package/profiles/fawzi.json +0 -16
  320. package/profiles/hasan.json +0 -16
  321. package/profiles/moayad.json +0 -16
  322. package/templates/CLAUDE-owner.md +0 -52
  323. package/templates/CLAUDE.md.hbs +0 -58
  324. package/templates/env.claude.template +0 -12
  325. package/templates/settings.json +0 -172
  326. /package/{framework/rules → rules}/deployment.md +0 -0
  327. /package/{framework/rules → rules}/security.md +0 -0
@@ -1,752 +0,0 @@
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