Files
Salon/docs/execplans/arabic-localization.md
T
2026-02-28 11:38:39 +03:00

8.5 KiB
Raw Blame History

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.

The requirements for ExecPlans live in PLANS.md at the repository root. This document must be maintained in accordance with that file.

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.

Progress

  • (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.

Surprises & Discoveries

  • Observation: None yet. Evidence: No implementation work has started.

Decision Log

  • 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: 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
  • Decision: Localize both backend API messages and frontend UI strings. Rationale: A partial localization would create mismatched language experiences and confuse users. Date/Author: 2026-02-27, Codex
  • Decision: Use i18next + react-i18next with a small custom locale selection helper rather than a detection plugin. Rationale: The project is small and can avoid extra dependencies while still meeting locale selection requirements. Date/Author: 2026-02-27, Codex

Outcomes & Retrospective

Not started yet.

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.

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.

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.

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.

Concrete Steps

Run these commands from the repository root (/home/kopernikus/kshkool/Salon).

  1. Add backend locale middleware, settings, and preferred_language field, then create a migration.

    • Update backend/salon_api/settings.py, backend/apps/accounts/models.py, and add backend/apps/accounts/middleware.py.
    • Run: python3 backend/manage.py makemigrations accounts
  2. Generate and compile Arabic translations.

    • Run: python3 backend/manage.py makemessages -l ar --ignore frontend --ignore node_modules python3 backend/manage.py compilemessages
    • Edit backend/locale/ar/LC_MESSAGES/django.po to translate the newly wrapped strings.
  3. Add frontend i18n resources and wire them into the app.

    • Update frontend/package.json, frontend/src/main.jsx, frontend/src/api/client.js, frontend/src/App.jsx, and create frontend/src/i18n/index.js plus translation JSON files.
  4. Run tests and verify behavior.

    • Backend: python3 -m pytest
    • Frontend: cd frontend npm run test

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:

$ 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":["رقم الهاتف مطلوب أو غير صالح."]}

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

The locale settings and middleware changes are safe to apply multiple times. Translation commands can be rerun; makemessages updates catalogs and compilemessages rebuilds .mo files. If a translation file is corrupted, re-run makemessages and re-apply translations. The migration adding preferred_language is additive and reversible via standard Django migration rollback.

Artifacts and Notes

Expected header behavior after implementing locale selection:

Content-Language: ar-sa

Example local storage entry for the frontend:

localStorage["locale"] = "ar-SA"

Interfaces and Dependencies

Add backend localization dependencies by using Djangos built-in translation system and middleware (django.middleware.locale.LocaleMiddleware) and a new apps.accounts.middleware.UserLocaleMiddleware to enforce user preference. The User model gains a language preference field:

preferred_language = models.CharField(max_length=10, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE)

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.