# Persian (fa) copy style guide One page, binding for `messages/fa.json`. `scripts/check-copy.mjs` (`npm run lint:copy`, part of `npm run check`) enforces the banned-variant rules below so these decisions cannot silently regress. This file does not repeat `en.json` conventions beyond what's noted in §7 — the English catalog is hand-written and reviewed for idiom, not linted. ## 1. Brand name **«بالین‌یار» — ZWNJ (`‌`) between بالین and یار, always.** Never a plain space («بالین یار»). The brand name appears in money/trust copy (login, escrow, refunds) as often as anywhere else — an unstable brand mark there is the worst place to be inconsistent. ## 2. تأیید — hamza, always Write **تأیید** (with hamza) and its derived forms — **تأییدشده**, **تأییدیه**, **تأیید کردن** — every time, never تایید/تاییدشده/تاییدیه (hamza-less). This is the single most frequent word in a verification product; one spelling, no exceptions, in every namespace (booking, payment, auth, verification, admin, payouts, bnpl, refunds, legal — all of them). ## 3. جستجو — one form Standard form: **جستجو** (no ZWNJ, one word). Not «جست‌وجو» / «جست و جو». Applies to the noun and any compound (`در جستجو`, `نتایج جستجو`). ## 4. ZWNJ (نیم‌فاصله) rules Use ZWNJ (`‌`) — never a plain space or no separator — in: - **می‌ + verb stem**: می‌شود، می‌کند، می‌پردازید، می‌ماند (never میشود/می شود). - **Plural ها**: مراقب‌ها-style compounds keep the ZWNJ before ها when the base ends in a consonant that would otherwise misread (`شب‌ها` not `شبها`); a plain plural on a word already ending in a vowel/silent-h takes the ZWNJ too (`بچه‌ها`). - **Compound past-participle adjectives**: تأییدشده، لغوشده، ردشده، منتشرشده، پرداخت‌شده — the doer/state compound is one ZWNJ-joined word, not two spaced words («تایید شده») and not fused with no separator. - Brand name itself (§1) is the other load-bearing ZWNJ case. ## 5. Punctuation & quotes - Persian text uses «...» guillemets for quoted terms/labels in prose (as this document does), and Persian «،» / «؛» for commas/semicolons *inside translated sentences* where the surrounding punctuation is itself Persian prose (most UI strings use plain Latin `,`/`;` today for simplicity in short labels — don't retrofit existing short strings, but prefer «،»/«؛» in new multi-clause sentences). - English (`en.json`) uses **straight** apostrophes (`don't`, `couldn't`) throughout — never curly (`’`, `‘`). One admin-namespace holdout (curly `don't`/`couldn't`) is fixed by this phase; don't reintroduce curly quotes when editing English copy. ## 6. Domain glossary - **بیمار** — the care recipient, used consistently everywhere except one parenthetical. Do not adopt «مددجو» — it appeared exactly once (`booking.patient_label`) and has been dropped in favor of the 99%-majority «بیمار». - **پرستار** — the caregiver, always (never «مراقب» as a noun for the person — «مراقب» only survives as an adjective/role qualifier, e.g. `booking.gender_label` "جنسیت مراقب" meaning "the caregiver's gender"). - **رزرو** — a confirmed, paid booking. **درخواست رزرو** — a pre-payment request. Never conflate the two; a `booking_request` is never called «رزرو» before it converts. - **ویزیت** — one scheduled visit/session within a booking. - **شبا** — IBAN, always («شماره شبا» for the field label, «شبا» alone elsewhere). ## 7. Shell naming system One metaphor per audience class, not four: - **End-user shells** (family, nurse — the apps people book/work through day to day) → **«اپلیکیشن»**: «اپلیکیشن خانواده», «اپلیکیشن پرستار». - **Back-office shells** (staff consoles — admin, partner-center) → **«کنسول»**: «کنسول مدیریت», «کنسول همکار». - Never «نما» (view) or «پرتال» (portal) for a whole shell name — those read as one-off inconsistent metaphors. (`booking.evv_nurse_view` "نمای پرستار" is a different thing — a chip labeling *whose perspective* a shared booking-detail screen is rendered from, not a shell name; it correctly keeps «نما» in that narrower sense.) ## 8. Verification pipeline vs. the identity step **«تأیید صلاحیت»** names the whole 7-step nurse trust pipeline (nav entry, the verification hub's title, its start/progress/approved states, the admin queue). **«احراز هویت»** stays the name of the one KYC step inside it (national-ID + civil-registry + liveness selfie) — both on the nurse side (`verification.step_identity_kyc`) and the admin side (`admin.step_identity_kyc`). A nurse who passed the KYC step but still sees a pipeline titled «احراز هویت» incomplete in the nav used to read as a contradiction; they no longer share a name. ## 9. Status vocabulary — one nurse-facing form, one admin-facing form For "this step/item was rejected/failed" style states that appear on both a nurse-facing screen and an admin-facing screen for the *same underlying concept* (a verification step's outcome): - **Nurse-facing**: «رد شد» (`verification.status_failed`) — a short declarative sentence-style status, matching the register of its sibling `status_passed` ("تأییدشده")/`status_in_review` ("در حال بررسی"). - **Admin-facing**: «ردشده» (`admin.step_failed`, `admin.agg_rejected`, `admin.rstatus_rejected`, `admin.mstatus_rejected`) — the compound-adjective state form, matching the admin namespace's own `step_passed`/`agg_approved`/`center_state_verified` ("تأییدشده") pattern. This does **not** extend to unrelated money-failure vocabulary (`payouts.pstatus_failed`, `refunds.rstatus_failed`, `admin.batch_status_failed` all legitimately use «ناموفق» — a transfer/payment *failing* is a different concept from a document being *rejected*, and conflating them would blur a real distinction). ## 10. Digits policy Persian digits (۰۱۲۳۴۵۶۷۸۹) everywhere on `/fa` — both hard-coded literals (`"۲۴ ساعت"`) and interpolated numbers. For an interpolated `{count}`/`{hours}`/… inside an ICU message, use the ICU `number` sub-format (`{count, number}`) or a plain `#` inside a `plural` block — next-intl formats both through the active locale (`fa` → Persian digits) automatically. When a raw number is interpolated at a call site instead of through ICU (e.g. built into a larger string in code, not a message placeholder), route it through `formatNumber` (`@/utils`) — never template a raw JS number directly into Persian text. ## 11. Register Formal شما throughout, with polite imperatives (کنید) for actions and instructions. Already consistent across the whole catalog — this codifies it so a future addition can't drift into informal تو/imperative stems (نکن, برو). ## 12. Policy numbers Legally/financially sensitive numbers that the admin config panel can change (the dispute-window hours, cancellation lead-time hours, refund ETA days) are **never hard-coded into a message string**. The message key takes a parameter (`{hours}`, `{minDays}`/`{maxDays}`) and the call site interpolates from `client/src/constants/policy.ts` (single-sourced, REQ-065 tracks the eventual public config-read that replaces the constants file). A config edit must never again silently make the UI copy lie.