Server settings → Defaults: show each language's flag, as the language picker does #208

Closed
opened 2026-09-15 18:39:32 +00:00 by tiagoagueda · 0 comments
Owner

Server settings → Defaults names languages in two places and shows no flag in either, while Settings → Language and time shows a flag beside every language (#52, #88, #119). The same list should look the same on both pages.

Where the languages appear without flags

src/postulo/templates/server/defaults.html

  1. Languages this instance offers (#120): a grid of checkboxes. Each row is {{ option.tag }} plus <span lang="…">{{ option.choice_label }}</span>. The rows come from OfferedLanguagesForm (core/server_forms.py), whose choices are only (code, name) pairs from languages.NATIVE_NAMES, so no country reaches the template.
  2. Language for new accounts (DefaultsForm.default_language): a plain <select> drawn by partials/field.html, with choices from accounts.forms.language_choices.
  3. The "In force now: {{ language }}, {{ zone }}." line is text only. It probably stays that way, but it is worth deciding.

What already exists to reuse

  • {% flag country %} in core/templatetags/postulo.py draws an SVG out of static/flags/. It is decorative by default (alt="" aria-hidden="true"), 20×15, and draws nothing for an unknown or empty country.
  • languages.flag_country(code) in core/languages.py gives the country (or ISO 3166-2 subdivision, e.g. ES-CT) for a language. It returns "" on purpose for languages with no single home, e.g. ar, sw, ha. The row has to close up cleanly when that happens.
  • LocaleForm.language_groups() / _language_option() in accounts/forms.py already build rows with code, name, country, state and percent. settings/locale.html renders them as {% flag option.country %} between the input and the lang span.

Points to settle

  • Checkbox grid: the simple part. Either give each choice its country (e.g. a small helper on OfferedLanguagesForm that returns rows with country), or call languages.flag_country(option.data.value) through a template filter/tag. Put the flag outside the lang span, as on the locale page.
  • Default language <select>: an <option> cannot hold an image. #119 turned the account picker into a <details> with radio rows for this reason, because a flag in the option text gets read aloud with the name. Options:
    • (a) reuse the locale page's disclosure-of-radios pattern here (probably as a shared partial rather than a copy);
    • (b) show only the chosen language's flag beside the closed <select>, which needs app.js to update it on change (the CSP forbids inline script, and without scripts it would show the saved value);
    • (c) flags on the checkbox grid only, and leave the select as it is.
  • Whether the translation-state marks (partials/translation_state.html) should come along too, or only the flag.

Checks when this is picked up

  • Tests: tests/test_offered_languages.py, tests/test_server_settings.py, and tests/test_flags.py, which covers the tag and the locale picker. Add: every offered-language row whose language has a country draws data-flag, a language without one draws no <img>, and the flag is aria-hidden.
  • The e2e/axe run over Server settings → Defaults in both themes.
  • npm run build:css if new classes appear (the flag's white-edge rule is already in the stylesheet, see test_the_stylesheet_keeps_a_white_edged_flag_from_disappearing).
  • The wiki page for server settings, if it has a screenshot of this page.
*Server settings → Defaults* names languages in two places and shows no flag in either, while *Settings → Language and time* shows a flag beside every language (#52, #88, #119). The same list should look the same on both pages. ## Where the languages appear without flags `src/postulo/templates/server/defaults.html` 1. **Languages this instance offers** (#120): a grid of checkboxes. Each row is `{{ option.tag }}` plus `<span lang="…">{{ option.choice_label }}</span>`. The rows come from `OfferedLanguagesForm` (`core/server_forms.py`), whose choices are only `(code, name)` pairs from `languages.NATIVE_NAMES`, so no country reaches the template. 2. **Language for new accounts** (`DefaultsForm.default_language`): a plain `<select>` drawn by `partials/field.html`, with choices from `accounts.forms.language_choices`. 3. The *"In force now: {{ language }}, {{ zone }}."* line is text only. It probably stays that way, but it is worth deciding. ## What already exists to reuse - `{% flag country %}` in `core/templatetags/postulo.py` draws an SVG out of `static/flags/`. It is decorative by default (`alt="" aria-hidden="true"`), 20×15, and draws nothing for an unknown or empty country. - `languages.flag_country(code)` in `core/languages.py` gives the country (or ISO 3166-2 subdivision, e.g. `ES-CT`) for a language. It returns `""` on purpose for languages with no single home, e.g. `ar`, `sw`, `ha`. The row has to close up cleanly when that happens. - `LocaleForm.language_groups()` / `_language_option()` in `accounts/forms.py` already build rows with `code`, `name`, `country`, `state` and `percent`. `settings/locale.html` renders them as `{% flag option.country %}` between the input and the `lang` span. ## Points to settle - **Checkbox grid:** the simple part. Either give each choice its country (e.g. a small helper on `OfferedLanguagesForm` that returns rows with `country`), or call `languages.flag_country(option.data.value)` through a template filter/tag. Put the flag outside the `lang` span, as on the locale page. - **Default language `<select>`:** an `<option>` cannot hold an image. #119 turned the account picker into a `<details>` with radio rows for this reason, because a flag in the option text gets read aloud with the name. Options: - (a) reuse the locale page's disclosure-of-radios pattern here (probably as a shared partial rather than a copy); - (b) show only the chosen language's flag beside the closed `<select>`, which needs `app.js` to update it on change (the CSP forbids inline script, and without scripts it would show the saved value); - (c) flags on the checkbox grid only, and leave the select as it is. - Whether the translation-state marks (`partials/translation_state.html`) should come along too, or only the flag. ## Checks when this is picked up - Tests: `tests/test_offered_languages.py`, `tests/test_server_settings.py`, and `tests/test_flags.py`, which covers the tag and the locale picker. Add: every offered-language row whose language has a country draws `data-flag`, a language without one draws no `<img>`, and the flag is `aria-hidden`. - The e2e/axe run over *Server settings → Defaults* in both themes. - `npm run build:css` if new classes appear (the flag's white-edge rule is already in the stylesheet, see `test_the_stylesheet_keeps_a_white_edged_flag_from_disappearing`). - The wiki page for server settings, if it has a screenshot of this page.
tiagoagueda added this to the 0.4.0 milestone 2026-09-15 21:33:20 +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#208
No description provided.