Documents and notifications speak the language of the request, not of the document or the person receiving them #223

Closed
opened 2026-09-15 21:23:24 +00:00 by tiagoagueda · 0 comments
Owner

Nothing in src/ ever switches translation to anything but the request's language: translation.override appears nowhere. As a result, the language a document declares, and the language a person chose, are ignored exactly where they matter most. Found in the 2026-09-15 code audit.

1. CVs and letters print their fixed words in the interface language

  • documents/rendering.py:23-31,131: section headings come from SECTION_LABELS via str() in the active language.
  • themes/base_cv.html:55,95-98 and base_portfolio.html:63-66: "present", month names (date:"M Y") and get_proficiency_display all follow the interface.
  • base_letter.html:27: the letter date is {% now "j F Y" %}.
  • rendering.py:215: the {{ date }} placeholder uses strftime("%B") in the C locale, so it is always English.
  • A French CV exported by somebody reading Postulo in English says "Experience … Mar 2021 – present", and a letter can carry two dates in two languages. #131 translated the entries but not the page around them.

2. Store copies are labelled with the owner's language

documents/stores.py:88 sends language from the profile, not from the document, so a French CV reaches Paperless labelled with the owner's interface language.

3. The PDF title and file name carry the private variant name

  • base_cv.html:10, base_portfolio.html:19 and base_letter.html:10 set <title>{{ cv.name }}</title>, which WeasyPrint writes into the PDF /Title that viewers and screen readers announce.
  • rendering.py:287-290 names the download "Backend, English — CV.pdf", and that name is what gets attached to portals and emails.
  • The model's own help text says the name is "For you, not for the employer" (documents/models.py:110).

4. Scheduled and API notifications ignore the recipient's language

  • send_due_reminders.py:44 and applications/quiet.py:104-121 call gettext in a management command where no language is active, so the text is always LANGUAGE_CODE (en-gb).
  • core/middleware.py:41-46 applies profile.language only to a signed-in session. API token requests are not one, so "Captured: …" (api/api.py:291-311) follows whatever Accept-Language the extension sends.

Proposal

  • Render CVs and letters inside translation.override(document_language(...)), falling back when no catalogue exists. Build {{ date }} with formats.date_format inside it.
  • stores.metadata_for: use the document's language for renders.
  • PDF title and download name from the contact name and the kind ("Alex Morgan — CV"); the variant name stays inside Postulo.
  • notify() renders inside translation.override(owner.profile.language or site default). Build Notification from lazy strings, or have the service call a builder under the override.
  • Tests: an fr CV rendered while the interface is en, and a reminder for a person whose language is not English.
Nothing in `src/` ever switches translation to anything but the request's language: `translation.override` appears nowhere. As a result, the language a document declares, and the language a person chose, are ignored exactly where they matter most. Found in the 2026-09-15 code audit. ## 1. CVs and letters print their fixed words in the interface language - `documents/rendering.py:23-31,131`: section headings come from `SECTION_LABELS` via `str()` in the active language. - `themes/base_cv.html:55,95-98` and `base_portfolio.html:63-66`: "present", month names (`date:"M Y"`) and `get_proficiency_display` all follow the interface. - `base_letter.html:27`: the letter date is `{% now "j F Y" %}`. - `rendering.py:215`: the `{{ date }}` placeholder uses `strftime("%B")` in the C locale, so it is always English. - A French CV exported by somebody reading Postulo in English says "Experience … Mar 2021 – present", and a letter can carry two dates in two languages. #131 translated the entries but not the page around them. ## 2. Store copies are labelled with the owner's language `documents/stores.py:88` sends `language` from the profile, not from the document, so a French CV reaches Paperless labelled with the owner's interface language. ## 3. The PDF title and file name carry the private variant name - `base_cv.html:10`, `base_portfolio.html:19` and `base_letter.html:10` set `<title>{{ cv.name }}</title>`, which WeasyPrint writes into the PDF `/Title` that viewers and screen readers announce. - `rendering.py:287-290` names the download "Backend, English — CV.pdf", and that name is what gets attached to portals and emails. - The model's own help text says the name is "For you, not for the employer" (`documents/models.py:110`). ## 4. Scheduled and API notifications ignore the recipient's language - `send_due_reminders.py:44` and `applications/quiet.py:104-121` call `gettext` in a management command where no language is active, so the text is always `LANGUAGE_CODE` (en-gb). - `core/middleware.py:41-46` applies `profile.language` only to a signed-in session. API token requests are not one, so "Captured: …" (`api/api.py:291-311`) follows whatever `Accept-Language` the extension sends. ## Proposal - Render CVs and letters inside `translation.override(document_language(...))`, falling back when no catalogue exists. Build `{{ date }}` with `formats.date_format` inside it. - `stores.metadata_for`: use the document's language for renders. - PDF title and download name from the contact name and the kind ("Alex Morgan — CV"); the variant name stays inside Postulo. - `notify()` renders inside `translation.override(owner.profile.language or site default)`. Build `Notification` from lazy strings, or have the service call a builder under the override. - Tests: an `fr` CV rendered while the interface is `en`, and a reminder for a person whose language is not English.
tiagoagueda added this to the 0.4.0 milestone 2026-09-15 21:33:23 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo#223
No description provided.