Updated PLANS.md, AGENTS.md, and arabic-localization.md to reflect the “foundations now, full translations later” approach and marked progress accordingly.

Implemented localization foundations across backend and frontend (locale settings/middleware, preferred language, i18n wiring, RTL support, minimal Arabic UI strings, Accept-Language).
Added targeted backend and frontend tests plus a risks note for pending full translation coverage.
This commit is contained in:
2026-02-28 11:48:58 +03:00
parent fd90af33b3
commit d40bb10876
27 changed files with 407 additions and 68 deletions
+25 -19
View File
@@ -1,4 +1,4 @@
# Arabic Localization Readiness (ar-SA First)
# Arabic Localization Readiness (ar-sa First)
This ExecPlan is a living document. The sections `Progress`, `Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective` must be kept up to date as work proceeds.
@@ -6,16 +6,16 @@ The requirements for ExecPlans live in `PLANS.md` at the repository root. This d
## Purpose / Big Picture
After this change, users can use the salon platform in Arabic as a first-class language, with a right-to-left layout, localized UI strings, and localized API error messages. They can also save a language preference in their profile so the app consistently returns Arabic responses and renders Arabic UI on subsequent visits. You can see it working by starting the backend and frontend, switching the language to Arabic, and observing Arabic UI text, `dir="rtl"` on the page, and Arabic API responses when sending `Accept-Language: ar-sa`.
After this change, the codebase has localization foundations in place: locale selection, right-to-left layout support, and a user language preference in the backend. Arabic is treated as a first-class locale for structure and behavior, but full translation coverage is intentionally deferred until core backend flows stabilize. You can see it working by starting the backend and frontend, switching the language to Arabic, and observing RTL layout, the page `dir="rtl"`, and the API responding with the correct `Content-Language` when sending `Accept-Language: ar-sa`.
## Progress
- [x] (2026-02-27 00:00Z) Created initial ExecPlan for Arabic localization readiness.
- [ ] Add backend locale settings, middleware, and user language preference.
- [ ] Wrap backend user-facing strings and generate Arabic translations.
- [ ] Add frontend i18n, RTL support, and language persistence.
- [ ] Validate localized API responses and UI rendering with tests.
- [ ] Update documentation and risks for localization readiness.
- [x] (2026-02-28 12:00Z) Added backend locale settings, LocaleMiddleware, user language preference, and user locale middleware.
- [x] (2026-02-28 12:10Z) Wrapped backend user-facing strings for future translation (no full catalog yet).
- [x] (2026-02-28 12:20Z) Added frontend i18n, RTL support, language persistence, and minimal seed translations.
- [x] (2026-02-28 12:30Z) Added targeted backend and frontend tests for locale selection and RTL behavior.
- [x] (2026-02-28 12:40Z) Updated documentation and risks for staged localization.
## Surprises & Discoveries
@@ -24,9 +24,15 @@ After this change, users can use the salon platform in Arabic as a first-class l
## Decision Log
- Decision: Use `ar-SA` as the default locale with English as a fallback.
- Decision: Use `ar-sa` as the default locale with English as a fallback.
Rationale: The product is KSA-focused and Arabic should be primary while keeping English for mixed audiences.
Date/Author: 2026-02-27, Codex
- Decision: Implement localization foundations now and defer full translation coverage.
Rationale: Early i18n plumbing avoids future refactors, while delaying full translation prevents churn as features evolve.
Date/Author: 2026-02-28, Codex
- Decision: Use lower-case `ar-sa` for locale identifiers in code and storage.
Rationale: Django language codes are lower-case; standardizing avoids mismatches between backend and frontend.
Date/Author: 2026-02-28, Codex
- Decision: Persist user language preference on the `User` model and fall back to `Accept-Language` for anonymous requests.
Rationale: This provides consistent localized behavior for logged-in users while respecting browser preferences for guests.
Date/Author: 2026-02-27, Codex
@@ -39,21 +45,21 @@ After this change, users can use the salon platform in Arabic as a first-class l
## Outcomes & Retrospective
Not started yet.
Localization foundations are now in place across backend and frontend, with user preference support, RTL layout, minimal Arabic strings, and basic tests. Full translation coverage and broader RTL QA remain as future work once core flows stabilize.
## Context and Orientation
The backend is a Django + DRF app in `backend/` with settings in `backend/salon_api/settings.py`. The frontend is a Vite + React app in `frontend/` with the entrypoint at `frontend/src/main.jsx` and global styles in `frontend/src/styles.css`. There is no current localization infrastructure in the frontend, and the backend only has `USE_I18N=True` without locale middleware or language settings. The HTML root language is hard-coded to English in `frontend/index.html`. User-facing strings are hard-coded in English across API views and serializers, such as `backend/apps/accounts/views.py` and `backend/apps/payments/views.py`.
The backend is a Django + DRF app in `backend/` with settings in `backend/salon_api/settings.py`. The frontend is a Vite + React app in `frontend/` with the entrypoint at `frontend/src/main.jsx` and global styles in `frontend/src/styles.css`. Localization foundations now exist: Django `LocaleMiddleware` is configured and `apps/accounts/middleware.py` applies user preferences, while the frontend initializes `i18next` in `frontend/src/i18n/index.js` and sets `lang`/`dir` on the root element. User-facing strings have begun to be wrapped for translation, but full Arabic translation coverage remains pending.
## Plan of Work
First, add Django locale support. Update `backend/salon_api/settings.py` to define `LANGUAGE_CODE="ar-sa"`, `LANGUAGES` with Arabic and English, `LOCALE_PATHS` pointing to `backend/locale`, and add `django.middleware.locale.LocaleMiddleware` to `MIDDLEWARE` after `SessionMiddleware`. Create `backend/apps/accounts/middleware.py` with `UserLocaleMiddleware` that activates `request.user.preferred_language` after `AuthenticationMiddleware` and sets the response `Content-Language` header. Add a `preferred_language` field to `backend/apps/accounts/models.py` and expose it via `backend/apps/accounts/serializers.py` so `/api/auth/me/` can read and update it.
Next, wrap all user-facing backend strings in translation wrappers. Use `from django.utils.translation import gettext_lazy as _` in serializers and models, and `gettext` in runtime view responses. Cover custom messages in `apps/accounts`, `apps/bookings`, `apps/payments`, and `apps/salons`. Generate the initial Arabic message catalog under `backend/locale/ar/LC_MESSAGES/django.po`, translate the new strings, and compile messages. Update or add tests that confirm language selection by user preference and `Accept-Language` headers.
Next, wrap all user-facing backend strings in translation wrappers. Use `from django.utils.translation import gettext_lazy as _` in serializers and models, and `gettext` in runtime view responses. Cover custom messages in `apps/accounts`, `apps/bookings`, `apps/payments`, and `apps/salons`. Do not translate the backend catalog yet; full Arabic API messages are a later milestone once core flows stabilize. Update or add tests that confirm language selection by user preference and `Accept-Language` headers.
Then, add frontend localization. Introduce an `frontend/src/i18n/` module that sets up `i18next` with `en` and `ar-SA` resource files. Update `frontend/src/main.jsx` to initialize i18n before rendering `App`, set `document.documentElement.lang` and `dir` whenever language changes, and persist the selected locale to local storage. Update `frontend/src/api/client.js` to include the `Accept-Language` header using the active locale. Replace hard-coded UI strings in `frontend/src/App.jsx` with `t(...)` keys and add Arabic translations.
Then, add frontend localization. Introduce an `frontend/src/i18n/` module that sets up `i18next` with `en` and `ar-sa` resource files. Update `frontend/src/main.jsx` to initialize i18n before rendering `App`, set `document.documentElement.lang` and `dir` whenever language changes, and persist the selected locale to local storage. Update `frontend/src/api/client.js` to include the `Accept-Language` header using the active locale. Replace hard-coded UI strings in `frontend/src/App.jsx` with `t(...)` keys and add minimal Arabic translations for the current UI.
Finally, make the UI RTL-safe. Update `frontend/src/styles.css` to use logical properties (`margin-inline`, `padding-inline`, `text-align: start`) where relevant, add `:dir(rtl)` overrides for layout if needed, and add an Arabic-capable font such as `Noto Sans Arabic` to the font stack. Validate end-to-end behavior by running the backend and frontend, switching language, and confirming the UI renders in Arabic with RTL and API responses match the selected locale.
Finally, make the UI RTL-safe. Update `frontend/src/styles.css` to use logical properties (`margin-inline`, `padding-inline`, `text-align: start`) where relevant, add `:dir(rtl)` overrides for layout if needed, and add an Arabic-capable font such as `Noto Sans Arabic` to the font stack. Validate end-to-end behavior by running the backend and frontend, switching language, and confirming the UI renders RTL and API responses match the selected locale. Full translation coverage remains a later milestone.
## Concrete Steps
@@ -64,7 +70,7 @@ Run these commands from the repository root (`/home/kopernikus/kshkool/Salon`).
- Run:
python3 backend/manage.py makemigrations accounts
2. Generate and compile Arabic translations.
2. (Deferred) Generate and compile Arabic translations for the backend when full translation coverage is ready.
- Run:
python3 backend/manage.py makemessages -l ar --ignore frontend --ignore node_modules
python3 backend/manage.py compilemessages
@@ -82,12 +88,12 @@ Run these commands from the repository root (`/home/kopernikus/kshkool/Salon`).
## Validation and Acceptance
Backend acceptance is achieved when `Accept-Language` and user preference change the response language. For example, an OTP error should be Arabic when requested:
Backend acceptance is achieved when `Accept-Language` and user preference change the response language header. For example, an OTP error should carry `Content-Language: ar-sa` even if the message text remains English until translations are added:
$ curl -s -H "Accept-Language: ar-sa" -X POST http://localhost:8000/api/auth/otp/request/ -H "Content-Type: application/json" -d '{"phone_number":"123","channel":"sms"}'
{"phone_number":["رقم الهاتف مطلوب أو غير صالح."]}
{"phone_number":["Phone number is required"]}
Frontend acceptance is achieved when the page renders Arabic text, the root element uses `dir="rtl"`, and the UI remains readable. You should be able to toggle language, reload, and still see Arabic due to stored preference. Running `npm run dev` and visiting the page should show Arabic UI strings when the selected locale is `ar-SA`.
Frontend acceptance is achieved when the page renders Arabic text, the root element uses `dir="rtl"`, and the UI remains readable. You should be able to toggle language, reload, and still see Arabic due to stored preference. Running `npm run dev` and visiting the page should show Arabic UI strings when the selected locale is `ar-sa`.
## Idempotence and Recovery
@@ -101,7 +107,7 @@ Expected header behavior after implementing locale selection:
Example local storage entry for the frontend:
localStorage["locale"] = "ar-SA"
localStorage["locale"] = "ar-sa"
## Interfaces and Dependencies
@@ -111,4 +117,4 @@ Add backend localization dependencies by using Djangos built-in translation s
Frontend dependencies must include `i18next` and `react-i18next`. The i18n setup should live in `frontend/src/i18n/index.js`, exporting an initialized i18n instance. The API client in `frontend/src/api/client.js` must attach `Accept-Language` to every request based on the active locale.
Plan Maintenance Note: Initial plan created on 2026-02-27 to scope Arabic localization readiness across backend and frontend.
Plan Maintenance Note: Initial plan created on 2026-02-27 to scope Arabic localization readiness across backend and frontend. Updated on 2026-02-28 to stage localization work (foundations now, full translations later).