feat(i18n): traduire l'ensemble des gabarits
Le site s'affiche desormais integralement en francais. 483 chaines, aucune non traduite, dans les deux catalogues. Couvert : navigation et mise en page partagee, connexion, les cinq pages d'erreur, et les 29 gabarits de pages. Methode Marquage semi-automatique, conservateur par construction : seuls des motifs sans ambiguite sont balises -- contenu de balises de texte, attributs placeholder/title/aria-label, texte suivant une icone, blocs title et page_title -- et tout contenu comportant du Jinja ou du balisage imbrique est laisse de cote. Deux passes, la seconde pour td, li, h6, strong, em et caption. 97 entrees etaient marquees fuzzy par pybabel update, c'est-a-dire devinees par similarite. Une entree fuzzy est **ignoree a l'execution** : elles ont donc ete traitees comme non traduites, et le drapeau retire une fois la traduction ecrite. Deux pieges rencontres, tous deux documentes dans docs/translations.md Une entite HTML n'est pas du texte. ×, utilise comme libelle de bouton de fermeture, a ete balise par la passe automatique. Jinja l'echappait alors en &times; et le bouton aurait affiche le texte litteral × au lieu de la croix. Corrige dans cinq gabarits. Huit chaines subsistent dans des blocs <script>. Elles fonctionnent mais restent fragiles : Jinja echappe & < > " ' dans un bloc script, et ces entites n'y sont pas decodees -- une traduction contenant une apostrophe droite arriverait dans la chaine JavaScript sous la forme '. Le francais retenu utilise des apostrophes typographiques, non echappees, donc l'existant est sur. Toute nouvelle chaine a cet endroit devra passer par un attribut data- ou un bloc <script type="application/json">. Vocabulaire retenu -- a valider avec le club tryout -> selection · manager -> gerant · coach -> coach (conserve, terme d'usage en e-sport) · scout -> recruteur · email -> courriel · scrim -> scrim. Les noms de jeux et les postes (Support, Duelist, AWPer) restent en anglais : ce sont les termes employes par les joueurs. Ces choix vivent dans un seul catalogue, donc chacun se change en un endroit. Reste a faire : les messages flash hors routes/auth.py, et les messages de validation de app/validators.py, qui necessitent lazy_gettext puisque les champs de schema sont construits a l'import. Verifie : 13 pages parcourues dans les deux langues, aucune ne laisse de marqueur Jinja non evalue ni d'entite doublement echappee. 193 tests. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+30
-24
@@ -146,32 +146,38 @@ That second check is what keeps the migration honest: adding
|
||||
|
||||
## 5. State of the migration
|
||||
|
||||
Done: navigation, login page, the five error pages, and every flash message
|
||||
in `app/routes/auth.py`.
|
||||
**Templates are done.** 483 strings, all translated, in both catalogues.
|
||||
The suite fails if that stops being true.
|
||||
|
||||
Remaining, roughly in order of how often a member sees them:
|
||||
Covered: navigation and shared layout, login, the five error pages, and
|
||||
every page template.
|
||||
|
||||
| Area | Files |
|
||||
|---|---|
|
||||
| Dashboard | `pages/dashboard.html` |
|
||||
| Tryouts | `pages/tryouts.html`, `view_tryout.html`, `tryout_form.html` |
|
||||
| Registration | `pages/register.html` |
|
||||
| Profile | `pages/profile.html`, `edit_profile.html` |
|
||||
| Teams | `pages/teams.html`, `my_teams.html` |
|
||||
| Calendar and matches | `pages/calendar.html`, `match_form.html`, `team_matches.html` |
|
||||
| Notes and One on One | `pages/notes.html`, `one_on_one.html`, `add_note.html`, … |
|
||||
| Contracts | `pages/contracts.html`, `upload_contract.html` |
|
||||
| Remaining flash messages | `routes/users.py`, `tryouts.py`, `teams.py`, `matches.py`, … |
|
||||
### What is not covered yet
|
||||
|
||||
Two things to keep in mind while continuing.
|
||||
**Flash messages outside `routes/auth.py`.** `users.py`, `tryouts.py`,
|
||||
`teams.py`, `matches.py`, `team_matches.py` and `evaluations.py` still
|
||||
build them in English. They are the largest remaining block.
|
||||
|
||||
**Strings inside `<script>` blocks** cannot be marked with `{{ _() }}` and
|
||||
left at that — see `SEC-XSS-001`. Pass translated text through a `data-`
|
||||
attribute, or a `<script type="application/json">` block read by an
|
||||
external file. This lines up with the work needed to drop `unsafe-inline`
|
||||
from the CSP (`OPS-010`), so the two are best done together, template by
|
||||
template.
|
||||
**Validation messages in `app/validators.py`.** Shown to users, not marked.
|
||||
They need `lazy_gettext`, since schema fields are built at import time.
|
||||
|
||||
**Validation messages in `app/validators.py`** are shown to users and are
|
||||
not yet marked. They need `lazy_gettext`, since schema fields are built at
|
||||
import time.
|
||||
**Model constants** — `ESPORT_GAMES`, `GAME_POSITIONS` — are data, not
|
||||
interface. Game names stay as they are; positions such as "Support" or
|
||||
"Duelist" are the terms players use in English and are deliberately left
|
||||
alone.
|
||||
|
||||
### Two traps met during this migration
|
||||
|
||||
**HTML entities are not text.** `×`, used as a close-button label,
|
||||
was marked by the automated pass. Jinja escaped it to `&times;`, so
|
||||
the button would have shown the literal text `×` instead of ×.
|
||||
Anything that is markup rather than prose must stay out of `_()`.
|
||||
|
||||
**Strings inside `<script>` blocks.** Eight remain, in `match_form.html`,
|
||||
`one_on_one.html` and `coach_availability.html`. They work, but they are
|
||||
fragile: Jinja escapes `& < > " '` inside a script block, and those
|
||||
entities are *not* decoded there — a translation containing an apostrophe
|
||||
would land in the JavaScript string as `'`. The French wording uses
|
||||
typographic apostrophes (’), which are untouched, so the current strings
|
||||
are safe. Anything added there should be passed through a `data-`
|
||||
attribute or a `<script type="application/json">` block instead.
|
||||
|
||||
Reference in New Issue
Block a user