Guidance for AI tools and developers working in this repository (Flask, Flask-Babel, Jinja2).
- Python: use
python3. - Tests:
python3 -m pytest(from repo root; target files or-kas needed). - Translations: see
scripts/compile_translations.shfor the full extract → update → compile workflow.
- One logical
msgidin templates: keep strings likeDiscussions & Programmeswith a literal&in the source. Do not duplicate msgids with&in the Python/Jinja string just to please HTML; that desynchronizesmessages.potand all.pofiles. - Text nodes / attributes in HTML where gettext may return Markup and the string can contain
&or<: use the Jinja filter|escape_i18nso output is always entity-safe. Implementation:app/lib/jinja_i18n.py(Markup(escape(str(value)))unwraps Markup before escaping; the default|edoes not in that situation). - Do not apply
|escape_i18nto copy that is intentionally HTML (|safe, rich entity markup from translators, etc.). - Email templates that pass HTML fragments into
gettext: useemail_anchor_htmlfromapp/email_utils.py(registered as Jinja global) sohref/ attributes are escaped and link bodies areMarkupwhere needed. See existing email templates for patterns. - babel:
babel.cfgdocuments where to look forescape_i18nwhen editing templates.
- Published vs audit: Participant-facing counts and aligned aggregates exclude votes on deleted or negatively moderated statements (
visible_statement_vote_filtersinapp/lib/participation_metrics.py). Rawstatement_voterows may still exist for audit; do not mix definitions without labelling the export or UI. Full rationale: adr/0001-published-vs-audit-vote-semantics.md. - Anonymous voters: Use
anonymous_fingerprint_aliases_for_daily_lookup()fromapp/lib/vote_identity.pyfor “this visitor’s votes” lookups (legacy cookies + embed fingerprint). Avoidsession_fingerprint == single_fpfor UX summaries unless you document why.
Project overview, setup, and feature list live in README.md. Keep this file limited to conventions that are easy to miss in code review.