Adding a Language¶
Step-by-step guide for adding a new language to the system. This example adds French (fr).
Step 1: Add to Django Settings¶
In backend/config/settings/base.py, add the language to LANGUAGES:
Step 2: Add SupportedLocale Choice¶
In backend/apps/tenants/choices.py, add the locale choice:
class SupportedLocale(models.TextChoices):
EN = "en", _("English")
ES = "es", _("Spanish")
FR = "fr", _("French") # New choice
This allows tenants to select the new language as their default locale.
Step 3: Create PDF Template Variants¶
Create language-specific PDF templates in backend/apps/documents/templates/:
monthly_statement_fr.htmltila_disclosure_fr.htmladverse_action_notice_fr.html
Copy the English templates as a starting point and translate the static text. Dynamic values use Jinja2 filters that handle locale automatically:
Step 4: Create Communication Template Records¶
Insert database rows for each template type/channel combination with language="fr":
INSERT INTO communications_communicationtemplate
(template_type, channel, program_id, language, subject, body, is_active)
VALUES
('payment_reminder', 'email', NULL, 'fr', 'Rappel de paiement', '...', true),
('payment_reminder', 'sms', NULL, 'fr', NULL, '...', true),
-- ... for each template type and channel
;
Or create via the admin dashboard's Communication Template management screens.
Step 5: Extract and Compile Messages¶
cd backend
# Extract translatable strings (adds new .po file for French)
uv run python manage.py makemessages -l en -l es -l fr --no-wrap
# Translate the new strings in backend/locale/fr/LC_MESSAGES/django.po
# Compile all message catalogs
uv run python manage.py compilemessages
The makemessages command creates backend/locale/fr/LC_MESSAGES/django.po with all translatable strings. Translate the msgstr entries, then compile.
Step 6: Update Frontend Admin i18n Provider¶
In frontend/admin/src/providers/i18nProvider.ts:
import frenchMessages from "ra-language-french";
const messages: Record<string, TranslationMessages> = {
en: englishMessages,
es: spanishMessages,
fr: frenchMessages,
};
const i18nProvider = polyglotI18nProvider(
(locale: string) => messages[locale] ?? messages.en,
"en",
[
{ locale: "en", name: "English" },
{ locale: "es", name: "Español" },
{ locale: "fr", name: "Français" },
],
);
Install the language package first:
Step 7: Verify¶
- Backend messages: Check that
django.poanddjango.moexist inbackend/locale/fr/LC_MESSAGES/ - Tenant config: Set a test tenant's locale to
frand verify middleware activates French - PDF generation: Generate a statement for a borrower with
language_preference="fr"and confirm the French template is used - Communication templates: Send a test communication and verify the French template resolves
- Admin dashboard: Switch language in the AppBar and confirm UI labels update
- Fallback: Test with missing French templates to confirm English fallback works
Checklist¶
- [ ]
LANGUAGESupdated in settings - [ ]
SupportedLocalechoice added - [ ] PDF template variants created (
_fr.html) - [ ] Communication template DB rows created
- [ ] Message catalog extracted, translated, and compiled
- [ ] Frontend i18n provider updated
- [ ] Both
.poand.mofiles committed
See Also¶
- Backend i18n --- Translation markers and message catalogs
- Frontend i18n --- react-admin i18n provider
- Localization --- Template resolution logic