# PRP-008 — i18n & RTL (en/ar/fr)

- **Status:** Done
- **Plan:** Lite
- **Depends on:** — (do early so later screens add keys instead of hardcoded text)
- **Estimated effort:** ~1–1.5 days
- **Pro KB ref:** §7 (Localization & i18n)

> **Audience:** junior dev. This PRP adds English/Arabic/French translation and **RTL for Arabic** to
> the React client. Backend stays English for MVP. Set up the framework first, then convert screens.

---

## 1. Goal / Why
Shiprex sells into Arabic, English and French markets. The dashboard and public tracking must render in
the user's language, with correct **RTL** layout for Arabic. This widens the funnel.

## 2. Scope
**In:** i18n framework, 3 catalogs, language switcher, RTL toggle, localized dates/numbers, convert all
Lite screens + tracking.
**Out (Pro):** DB-backed admin-editable translations, Google auto-translate, per-tenant terminology.

## 3. Prerequisites
- Client builds (`npm run build:client`). Node/npm working.

## 4. Step-by-step implementation

### Step 1 — Install dependencies (client workspace)
```bash
npm --workspace client install i18next react-i18next i18next-browser-languagedetector
```

### Step 2 — Create catalogs
Create three files (start small; add keys as you convert screens):

**`client/src/i18n/en.json`**
```json
{
  "app": { "name": "Shiprex Lite" },
  "nav": { "dashboard": "Dashboard", "orders": "Orders", "zones": "Zones & Pricing", "settings": "Settings", "companies": "Companies", "logout": "Log out" },
  "auth": { "signin": "Sign in", "email": "Email", "password": "Password", "register": "Create your free account", "company_name": "Company name", "contact_name": "Contact name", "phone": "Phone", "country": "Country of operation" },
  "orders": { "title": "Orders", "new": "New order", "fee": "Delivery fee", "cod": "COD amount", "city": "City", "status": "Status", "fee_pro_note": "Automatic zone-based pricing is a Pro feature.", "cap_reached": "Daily limit reached" },
  "common": { "upgrade": "Upgrade to Pro", "pro": "PRO", "save": "Save", "cancel": "Cancel", "delete": "Delete", "today": "today" },
  "track": { "title": "Track your parcel", "reference": "Tracking reference", "track": "Track" }
}
```
**`client/src/i18n/ar.json`** (Arabic — RTL). Translate the same keys, e.g.:
```json
{
  "app": { "name": "شيبركس لايت" },
  "nav": { "dashboard": "لوحة التحكم", "orders": "الطلبات", "zones": "المناطق والأسعار", "settings": "الإعدادات", "companies": "الشركات", "logout": "تسجيل الخروج" },
  "auth": { "signin": "تسجيل الدخول", "email": "البريد الإلكتروني", "password": "كلمة المرور", "register": "أنشئ حسابك المجاني", "company_name": "اسم الشركة", "contact_name": "اسم المسؤول", "phone": "الهاتف", "country": "دولة التشغيل" },
  "orders": { "title": "الطلبات", "new": "طلب جديد", "fee": "رسوم التوصيل", "cod": "مبلغ الدفع عند الاستلام", "city": "المدينة", "status": "الحالة", "fee_pro_note": "التسعير التلقائي حسب المنطقة ميزة في النسخة الاحترافية.", "cap_reached": "تم بلوغ الحد اليومي" },
  "common": { "upgrade": "الترقية إلى Pro", "pro": "PRO", "save": "حفظ", "cancel": "إلغاء", "delete": "حذف", "today": "اليوم" },
  "track": { "title": "تتبع شحنتك", "reference": "رقم التتبع", "track": "تتبع" }
}
```
**`client/src/i18n/fr.json`** — French translations of the same keys.

> Keep the **key structure identical** across all three files. Missing keys fall back to English.

### Step 3 — Initialize i18n
Create **`client/src/i18n/index.ts`**:
```ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import en from './en.json';
import ar from './ar.json';
import fr from './fr.json';

export const LANGS = [
  { code: 'en', label: 'English', dir: 'ltr' },
  { code: 'ar', label: 'العربية', dir: 'rtl' },
  { code: 'fr', label: 'Français', dir: 'ltr' },
] as const;

i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: { en: { translation: en }, ar: { translation: ar }, fr: { translation: fr } },
    fallbackLng: 'en',
    interpolation: { escapeValue: false },
    detection: { order: ['localStorage', 'navigator'], caches: ['localStorage'] },
  });

// Keep <html dir/lang> in sync with the active language.
export function applyDir(lng: string) {
  const meta = LANGS.find((l) => l.code === lng) || LANGS[0];
  document.documentElement.setAttribute('dir', meta.dir);
  document.documentElement.setAttribute('lang', meta.code);
}
applyDir(i18n.language || 'en');
i18n.on('languageChanged', applyDir);

export default i18n;
```

### Step 4 — Load i18n at app startup
In **`client/src/main.tsx`**, import the config **before** `<App/>` renders:
```ts
import './i18n';
```
(add the line near the top with the other imports).

### Step 5 — Add a language switcher
Create **`client/src/components/LanguageSwitcher.tsx`**:
```tsx
import { useTranslation } from 'react-i18next';
import { LANGS } from '../i18n';

export default function LanguageSwitcher() {
  const { i18n } = useTranslation();
  return (
    <select value={i18n.language} onChange={(e) => i18n.changeLanguage(e.target.value)} style={{ width: 'auto' }}>
      {LANGS.map((l) => <option key={l.code} value={l.code}>{l.label}</option>)}
    </select>
  );
}
```
Place it in the sidebar (`App.tsx` Shell) and on the `Login`, `Register`, and `Track` pages.

### Step 6 — RTL styling
In **`client/src/styles.css`** add RTL-aware rules so the sidebar/layout mirror under Arabic:
```css
html[dir="rtl"] body { direction: rtl; }
html[dir="rtl"] .sidebar { border-right: none; border-left: 1px solid var(--border); }
html[dir="rtl"] th, html[dir="rtl"] td { text-align: right; }
html[dir="rtl"] .main { text-align: right; }
```
Prefer logical CSS properties where you can (e.g. `margin-inline-start`) to reduce special cases.

### Step 7 — Convert screens to `t()`
Replace hardcoded strings with `const { t } = useTranslation();` and `t('nav.orders')` etc., across:
`App.tsx` (sidebar), `Login`, `Register`, `Dashboard`, `Orders`, `OrderDetail`, `Zones`, `Admin`,
`Settings`, `Track`. Add any new keys to all three catalogs.

### Step 8 — Localized dates/numbers
Use `new Intl.DateTimeFormat(i18n.language).format(date)` and `new Intl.NumberFormat(i18n.language)`
for display. Create a small `client/src/lib/format.ts` with `formatDate(d)` / `formatNumber(n)` reading
`i18n.language`.

### Step 9 — Build & verify
```bash
npm run build:client
```
Toggle each language on every page; check Arabic flips to RTL with no broken alignment; reload to
confirm the choice persists (localStorage).

---

## 5. API endpoints & Postman documentation
**None.** This PRP is frontend-only; server messages remain English for MVP. No Postman changes.

> Future (optional): persist locale on the user via a small `PATCH /api/auth/me` — out of scope here.

---

## 6. Manual test / acceptance verification
- Switch to Arabic → entire dashboard mirrors RTL; reload → still Arabic.
- Switch to French → all visible copy in French, no `nav.orders`-style raw keys showing.
- Public `/track` respects the switcher.

**Acceptance criteria**
- [ ] en/ar/fr render with no missing-key fallbacks on core screens.
- [ ] Arabic flips layout to RTL correctly.
- [ ] Language choice persists across reload.

---

## 7. Git commits (follow in order)
**Commit 1 — i18n framework + catalogs**
```bash
git add client/package.json client/src/i18n client/src/main.tsx
git commit -m "feat(web): PRP-008 add i18n (en/ar/fr) framework + catalogs

Adds i18next/react-i18next with language detection, three catalogs, and
<html dir/lang> sync (RTL for Arabic). Loaded at startup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"
```

**Commit 2 — switcher + RTL styles**
```bash
git add client/src/components/LanguageSwitcher.tsx client/src/styles.css client/src/App.tsx
git commit -m "feat(web): PRP-008 language switcher + RTL styles"
```

**Commit 3 — convert screens to translation keys**
```bash
git add client/src
git commit -m "feat(web): PRP-008 translate all Lite screens + localized dates/numbers"
```

**Commit 4 — PRP status**
```bash
git add PRPs/PRP-008-i18n-rtl.md PRPs/README.md
git commit -m "docs(prp): mark PRP-008 done"
```

---

## 8. Done checklist
- [x] Deps installed; i18n initialized at startup.
- [x] 3 catalogs with identical key trees; switcher works; RTL verified.
- [x] All screens use `t()`; dates/numbers localized.
- [x] Build passes; persistence verified.
- [ ] Commits made; PRP marked Done.
