Group a language's variants in the picker, and pick one for a bare tag (#1053) #1064

Merged
tiagoagueda merged 1 commit from 1053-language-picker into main 2026-10-27 21:23:06 +00:00
Owner

Five languages are offered in more than one form, and the picker listed
each form as an entry of its own, grouped by how well it was translated:
português (Portugal) and português (Brasil) could sit under two headings.

Every language menu now shows a language's variants under its own name,
through one function, accounts.forms.grouped_by_language: the select on
Server settings -> Defaults, the document, record and CV language menus
(all LanguageSelect), and the rows of Settings -> Language and time.
The heading is CLDR's name for the language in itself, capitalised as
CLDR asks of a menu (Português, Español, Français, English, 中文), and
carries its lang; under it a variant is its country in its own language
(Brasil, México, United Kingdom; es reads as España), and Chinese is
named by script (简体中文, 繁體中文). A language offered in one form stays a
plain option. The closed control shows the whole name (data-chosen).
language_choices is flat now; the translation state stays on the rows.

Each option and row also carries the words it can be found by: its own
name, CLDR's English one and its name in the interface language, so the
box over a long select and the Settings search find Deutsch for
"German". Without scripts the plain select, with its groups, still works.

A browser asking for plain pt, es, fr, en or zh is given pt-BR, es-MX,
fr-FR, en-GB or zh-Hans (languages.DEFAULT_VARIANTS), in LocaleMiddleware;
a header that names a variant first still gets it. Where the instance
does not offer the form asked for, a visitor gets another offered form
of the same language before the instance default.

Closes #1053

Notes for review

  • The maintainer's decisions (2026-10-27):
    • Variants are grouped under their language.
    • A bare tag lands on the most-spoken variant: pt→pt-BR, es→es-MX, fr→fr-FR, en→en-GB, zh→zh-Hans.
    • Chinese is labelled by script.
    • A filter matches native and English names.
  • Decisions the issue left open:
    • language_choices() is flat now, because an <optgroup> cannot nest. So the Server defaults select loses its "Reviewed / Awaiting review / Partly translated" headings. Partial languages keep their percentage, and Settings still shows each language's state.
    • For a visitor, preferences.fallback tries another offered form of the same language before the instance default.
    • es-419 and es-AR still go to es (Spain). Only bare tags are remapped.
  • Sign-up has no language picker, so it is not changed.
  • Also updated: docs/TRANSLATING.md.

🤖 Generated with Claude Code

Five languages are offered in more than one form, and the picker listed each form as an entry of its own, grouped by how well it was translated: português (Portugal) and português (Brasil) could sit under two headings. Every language menu now shows a language's variants under its own name, through one function, accounts.forms.grouped_by_language: the select on Server settings -> Defaults, the document, record and CV language menus (all LanguageSelect), and the rows of Settings -> Language and time. The heading is CLDR's name for the language in itself, capitalised as CLDR asks of a menu (Português, Español, Français, English, 中文), and carries its lang; under it a variant is its country in its own language (Brasil, México, United Kingdom; es reads as España), and Chinese is named by script (简体中文, 繁體中文). A language offered in one form stays a plain option. The closed control shows the whole name (data-chosen). language_choices is flat now; the translation state stays on the rows. Each option and row also carries the words it can be found by: its own name, CLDR's English one and its name in the interface language, so the box over a long select and the Settings search find Deutsch for "German". Without scripts the plain select, with its groups, still works. A browser asking for plain pt, es, fr, en or zh is given pt-BR, es-MX, fr-FR, en-GB or zh-Hans (languages.DEFAULT_VARIANTS), in LocaleMiddleware; a header that names a variant first still gets it. Where the instance does not offer the form asked for, a visitor gets another offered form of the same language before the instance default. Closes #1053 ## Notes for review - **The maintainer's decisions (2026-10-27):** - Variants are grouped under their language. - A bare tag lands on the most-spoken variant: `pt`→`pt-BR`, `es`→`es-MX`, `fr`→`fr-FR`, `en`→`en-GB`, `zh`→`zh-Hans`. - Chinese is labelled by script. - A filter matches native and English names. - **Decisions the issue left open:** - `language_choices()` is flat now, because an `<optgroup>` cannot nest. So the Server defaults select loses its "Reviewed / Awaiting review / Partly translated" headings. Partial languages keep their percentage, and Settings still shows each language's state. - For a visitor, `preferences.fallback` tries another offered form of the same language before the instance default. - `es-419` and `es-AR` still go to `es` (Spain). Only bare tags are remapped. - **Sign-up** has no language picker, so it is not changed. - **Also updated:** `docs/TRANSLATING.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Group a language's variants in the picker, and pick one for a bare tag (#1053)
Some checks failed
CI / Security audit (push) Successful in 43s
Every Python / Unit tests (Python 3.13) (push) Has been cancelled
CI / Browser tests (Chromium) (pull_request) Has been cancelled
CI / Browser tests (Chromium) (push) Successful in 30m59s
Every Python / Unit tests (Python 3.12) (push) Successful in 12m29s
CI / Unit tests and coverage (Python 3.14) (pull_request) Has been cancelled
CI / Checks: lint, migrations, catalogues, settings, built files (pull_request) Has been cancelled
CI / Database tests on PostgreSQL (pull_request) Has been cancelled
CI / Security audit (pull_request) Has been cancelled
CI / Unit tests and coverage (Python 3.14) (push) Successful in 12m35s
CI / Checks: lint, migrations, catalogues, settings, built files (push) Successful in 2m39s
CI / Database tests on PostgreSQL (push) Successful in 3m41s
96b24936aa
Five languages are offered in more than one form, and the picker listed
each form as an entry of its own, grouped by how well it was translated:
português (Portugal) and português (Brasil) could sit under two headings.

Every language menu now shows a language's variants under its own name,
through one function, accounts.forms.grouped_by_language: the select on
Server settings -> Defaults, the document, record and CV language menus
(all LanguageSelect), and the rows of Settings -> Language and time.
The heading is CLDR's name for the language in itself, capitalised as
CLDR asks of a menu (Português, Español, Français, English, 中文), and
carries its lang; under it a variant is its country in its own language
(Brasil, México, United Kingdom; es reads as España), and Chinese is
named by script (简体中文, 繁體中文). A language offered in one form stays a
plain option. The closed control shows the whole name (data-chosen).
language_choices is flat now; the translation state stays on the rows.

Each option and row also carries the words it can be found by: its own
name, CLDR's English one and its name in the interface language, so the
box over a long select and the Settings search find Deutsch for
"German". Without scripts the plain select, with its groups, still works.

A browser asking for plain pt, es, fr, en or zh is given pt-BR, es-MX,
fr-FR, en-GB or zh-Hans (languages.DEFAULT_VARIANTS), in LocaleMiddleware;
a header that names a variant first still gets it. Where the instance
does not offer the form asked for, a visitor gets another offered form
of the same language before the instance default.

Closes #1053

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tiagoagueda force-pushed 1053-language-picker from 96b24936aa
Some checks failed
CI / Security audit (push) Successful in 43s
Every Python / Unit tests (Python 3.13) (push) Has been cancelled
CI / Browser tests (Chromium) (pull_request) Has been cancelled
CI / Browser tests (Chromium) (push) Successful in 30m59s
Every Python / Unit tests (Python 3.12) (push) Successful in 12m29s
CI / Unit tests and coverage (Python 3.14) (pull_request) Has been cancelled
CI / Checks: lint, migrations, catalogues, settings, built files (pull_request) Has been cancelled
CI / Database tests on PostgreSQL (pull_request) Has been cancelled
CI / Security audit (pull_request) Has been cancelled
CI / Unit tests and coverage (Python 3.14) (push) Successful in 12m35s
CI / Checks: lint, migrations, catalogues, settings, built files (push) Successful in 2m39s
CI / Database tests on PostgreSQL (push) Successful in 3m41s
to 4eab1bdb39
All checks were successful
CI / Checks: lint, migrations, catalogues, settings, built files (push) Successful in 3m5s
CI / Unit tests and coverage (Python 3.14) (push) Successful in 15m40s
CI / Database tests on PostgreSQL (push) Successful in 5m14s
Every Python / Unit tests (Python 3.13) (push) Successful in 13m18s
CI / Security audit (push) Successful in 1m52s
CI / Browser tests (Chromium) (push) Successful in 35m13s
Every Python / Unit tests (Python 3.12) (push) Successful in 14m45s
CI / Checks: lint, migrations, catalogues, settings, built files (pull_request) Successful in 2m59s
CI / Database tests on PostgreSQL (pull_request) Successful in 4m8s
CI / Unit tests and coverage (Python 3.14) (pull_request) Successful in 12m41s
CI / Security audit (pull_request) Successful in 59s
CI / Browser tests (Chromium) (pull_request) Successful in 31m17s
2026-10-27 21:22:56 +00:00
Compare
tiagoagueda deleted branch 1053-language-picker 2026-10-27 21:23:09 +00:00
Sign in to join this conversation.
No reviewers
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!1064
No description provided.