Skip to content

Internationalization Overview

Multi-layer i18n strategy spanning backend, admin dashboard, and borrower portal. Currently supports English and Spanish.

Architecture

i18n flows through four layers:

Tenant Config (locale, timezone, currency)
TenantLocaleMiddleware (activates per-request)
Backend (gettext, Babel formatters, Jinja2 filters)
Frontend (react-admin Polyglot / browser Intl APIs)

Supported Languages

Code Language Status
en English Default, complete
es Spanish Supported, complete

Configured in backend/config/settings/base.py:

LANGUAGES = [
    ("en", "English"),
    ("es", "Spanish"),
]

Per-Tenant Configuration

Each tenant has locale, timezone, and currency settings:

Field Default Purpose
locale en Default language for tenant users
timezone UTC IANA timezone for date/time display
default_currency USD ISO 4217 currency for monetary values

These are stored on the Tenant model and activated per-request by TenantLocaleMiddleware.

Locale Flow

Request Processing

  1. TenantLocaleMiddleware resolves the language:
    • Accept-Language header (if language is in LANGUAGES)
    • Tenant's locale field (for dynamic tenants)
    • LANGUAGE_CODE fallback (en-us)
  2. Activates Django's translation.activate() and timezone.activate()
  3. Sets request.locale, request.tenant_timezone, request.tenant_currency
  4. Sets Content-Language response header

API Responses

API responses return raw values (Decimal, ISO dates). The frontend formats them using browser Intl APIs. Server-side formatting is reserved for PDFs, emails, and compliance documents.

Communication Templates

When sending communications:

  1. borrower.language_preference determines the template language
  2. resolve_template_for_language() finds a matching template, falling back to English
  3. Jinja2 filters format currency/dates using the borrower's locale

PDF Generation

When generating PDFs:

  1. borrower.language_preference selects the template variant
  2. render_pdf() tries {stem}_{lang}{suffix} first (e.g., monthly_statement_es.html)
  3. Falls back to the English template if no variant exists

Layer Summary

Layer Technology Scope
Backend translation Django gettext / gettext_lazy Model labels, error messages, choices
Backend formatting Babel (common/formatting.py) PDFs, emails, compliance docs
Template formatting Jinja2 filters (currency, date, etc.) Communication and PDF templates
Admin frontend react-admin Polyglot i18n provider UI labels, menu items
Borrower portal Browser Intl APIs Currency, date formatting
Per-borrower preference borrower.language_preference field Template language selection

See Also