feat(i18n): traduire les messages flash et de validation

198 appels flash dans les sept modules de routes, plus les 23 messages de
validation de app/validators.py. Le catalogue compte desormais 631 chaines,
aucune non traduite.

validators.py utilise lazy_gettext : les champs de schema sont construits a
l'import, donc avant qu'une requete existe. Un gettext ordinaire s'y
resoudrait une seule fois, dans la langue active au demarrage.

Un bug introduit par la conversion, puis corrige
  Le convertisseur automatique ne voyait que le premier litteral d'un appel
  flash, ce qui a casse deux chaines concatenees sur plusieurs lignes dans
  users.py -- le resultat n'etait meme pas du Python valide. Ma premiere
  verification ne l'a pas vu : elle enchainait py_compile sur head, or head
  reussit toujours, donc le "OK" s'affichait quoi qu'il arrive. Les deux
  appels sont reecrits et la verification refaite correctement.

Un bug plus interessant, revele par le test de fumee
  La langue choisie ne survivait pas a la connexion. login() et logout()
  appellent tous deux session.clear() -- l'un contre la fixation de session,
  l'autre pour terminer la session -- et le choix de langue partait avec le
  reste. Concretement : quelqu'un qui lisait la page de connexion en anglais
  se retrouvait en francais des qu'il se connectait.

  La langue est une preference d'affichage, pas un etat appartenant au
  compte. Les deux endroits la reportent maintenant explicitement, a cote du
  jeton CSRF. Quatre tests couvrent le cas, dont un qui verifie que corriger
  une cle preservee n'a pas fait tomber l'autre.

Detail de nommage : le convertisseur avait genere %(value)s pour une
expression conditionnelle, ce qui n'aide pas un traducteur. Renomme en
%(player)s.

Les 14 traductions ecrites avec une apostrophe droite sont normalisees en
apostrophe typographique. Sans consequence en HTML, ou ' s'affiche
correctement -- mais les blocs <script> ne decodent pas les entites, et
autant que le catalogue soit homogene.

200 tests.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
GGThed
2026-08-07 22:12:27 -04:00
co-authored by Claude Opus 5
parent 80bc1413f1
commit 37f70c89e3
15 changed files with 1639 additions and 249 deletions
+636 -3
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: team-tryouts VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-08-07 21:41-0400\n"
"POT-Creation-Date: 2026-08-07 22:03-0400\n"
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
@@ -19,6 +19,88 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.18.0\n"
#: app/validators.py:43
msgid "Password must be at least 8 characters with uppercase, lowercase, and a number."
msgstr "Password must be at least 8 characters with uppercase, lowercase, and a number."
#: app/validators.py:62
msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)."
msgstr "Username must be 3-30 characters (letters, numbers, underscore, hyphen)."
#: app/validators.py:81
msgid "Invalid Discord username format."
msgstr "Invalid Discord username format."
#: app/validators.py:98
msgid "Discord User ID must be a 17-20 digit number."
msgstr "Discord User ID must be a 17-20 digit number."
#: app/validators.py:116
msgid "Invalid phone number format."
msgstr "Invalid phone number format."
#: app/validators.py:155
msgid "Username is required."
msgstr "Username is required."
#: app/validators.py:159
msgid "Password is required."
msgstr "Password is required."
#: app/validators.py:180 app/validators.py:251
msgid "Username must be 3-80 characters."
msgstr "Username must be 3-80 characters."
#: app/validators.py:186
msgid "Email must be 120 characters or less."
msgstr "Email must be 120 characters or less."
#: app/validators.py:199 app/validators.py:266 app/validators.py:299 app/validators.py:365
msgid "Full name is required."
msgstr "Full name is required."
#: app/validators.py:234
msgid "Passwords do not match."
msgstr "Passwords do not match."
#: app/validators.py:272 app/validators.py:309
msgid "Invalid role selected."
msgstr "Invalid role selected."
#: app/validators.py:409
msgid "Player must be selected."
msgstr "Player must be selected."
#: app/validators.py:412
msgid "Notes must be 2000 characters or less."
msgstr "Notes must be 2000 characters or less."
#: app/validators.py:431
msgid "Date must be in YYYY-MM-DD format."
msgstr "Date must be in YYYY-MM-DD format."
#: app/validators.py:438 app/validators.py:473
msgid "Start time must be in HH:MM format."
msgstr "Start time must be in HH:MM format."
#: app/validators.py:445
msgid "End time must be in HH:MM format."
msgstr "End time must be in HH:MM format."
#: app/validators.py:449
msgid "Points must be 2000 characters or less."
msgstr "Points must be 2000 characters or less."
#: app/validators.py:466
msgid "Day must be 0 (Monday) to 6 (Sunday)."
msgstr "Day must be 0 (Monday) to 6 (Sunday)."
#: app/routes/auth.py:129 app/routes/auth.py:258 app/routes/users.py:46
#: app/routes/users.py:649
#, python-format
msgid "%(field)s: %(msg)s"
msgstr "%(field)s: %(msg)s"
#: app/routes/auth.py:141
#, python-format
msgid ""
@@ -59,11 +141,11 @@ msgstr "Login unsuccessful. Please check username and password."
msgid "Incorrect CAPTCHA answer. Please try again."
msgstr "Incorrect CAPTCHA answer. Please try again."
#: app/routes/auth.py:281
#: app/routes/auth.py:281 app/routes/users.py:317
msgid "Username already exists."
msgstr "Username already exists."
#: app/routes/auth.py:293
#: app/routes/auth.py:293 app/routes/users.py:321
msgid "Email already registered."
msgstr "Email already registered."
@@ -107,6 +189,554 @@ msgstr "Discord account connected! Your profile has been pre-filled."
msgid "You have been logged out."
msgstr "You have been logged out."
#: app/routes/evaluations.py:41
msgid "You do not have permission to view evaluations."
msgstr "You do not have permission to view evaluations."
#: app/routes/evaluations.py:122
msgid "You do not have permission to evaluate players."
msgstr "You do not have permission to evaluate players."
#: app/routes/evaluations.py:127 app/routes/evaluations.py:220
msgid "You do not have permission to evaluate players in this tryout."
msgstr "You do not have permission to evaluate players in this tryout."
#: app/routes/evaluations.py:134
msgid "Player is not registered for this tryout."
msgstr "Player is not registered for this tryout."
#: app/routes/evaluations.py:139
msgid "Can only evaluate players."
msgstr "Can only evaluate players."
#: app/routes/evaluations.py:177
msgid "Evaluation updated!"
msgstr "Evaluation updated!"
#: app/routes/evaluations.py:190
msgid "Evaluation submitted successfully!"
msgstr "Evaluation submitted successfully!"
#: app/routes/evaluations.py:215 app/routes/teams.py:249 app/routes/teams.py:280
#: app/routes/teams.py:311 app/routes/teams.py:336 app/routes/teams.py:361
#: app/routes/teams.py:393 app/routes/tryouts.py:341 app/routes/tryouts.py:357
#: app/routes/tryouts.py:376 app/routes/tryouts.py:413 app/routes/tryouts.py:448
#: app/routes/tryouts.py:467
msgid "Permission denied."
msgstr "Permission denied."
#: app/routes/main.py:43
msgid "That language is not available."
msgstr "That language is not available."
#: app/routes/matches.py:201
msgid "You do not have permission to schedule matches for this tryout."
msgstr "You do not have permission to schedule matches for this tryout."
#: app/routes/matches.py:205 app/routes/matches.py:336
msgid "This tryout has ended. Matches can no longer be created or modified."
msgstr "This tryout has ended. Matches can no longer be created or modified."
#: app/routes/matches.py:224
msgid "Start time is required. Please select a time slot."
msgstr "Start time is required. Please select a time slot."
#: app/routes/matches.py:231 app/routes/matches.py:359 app/routes/team_matches.py:139
#: app/routes/team_matches.py:222
msgid "Invalid date format."
msgstr "Invalid date format."
#: app/routes/matches.py:246 app/routes/team_matches.py:156
msgid "Invalid time format."
msgstr "Invalid time format."
#: app/routes/matches.py:317
msgid "Match scheduled successfully!"
msgstr "Match scheduled successfully!"
#: app/routes/matches.py:332 app/routes/team_matches.py:209
msgid "You do not have permission to edit this match."
msgstr "You do not have permission to edit this match."
#: app/routes/matches.py:365
msgid "Start time is required."
msgstr "Start time is required."
#: app/routes/matches.py:461 app/routes/team_matches.py:245
msgid "Match updated successfully!"
msgstr "Match updated successfully!"
#: app/routes/matches.py:506 app/routes/team_matches.py:259
msgid "You do not have permission to delete this match."
msgstr "You do not have permission to delete this match."
#: app/routes/matches.py:509
msgid "This tryout has ended. Matches can no longer be deleted."
msgstr "This tryout has ended. Matches can no longer be deleted."
#: app/routes/matches.py:521 app/routes/team_matches.py:263
msgid "Match deleted successfully."
msgstr "Match deleted successfully."
#: app/routes/team_matches.py:97
msgid "You do not have permission to schedule matches for this team."
msgstr "You do not have permission to schedule matches for this team."
#: app/routes/team_matches.py:132
msgid "Date is required."
msgstr "Date is required."
#: app/routes/team_matches.py:195
#, python-format
msgid "Team match \"%(title)s\" scheduled successfully!"
msgstr "Team match \"%(title)s\" scheduled successfully!"
#: app/routes/teams.py:43
msgid "Use My Team(s) to view your teams."
msgstr "Use My Team(s) to view your teams."
#: app/routes/teams.py:46
msgid "You do not have permission to view teams."
msgstr "You do not have permission to view teams."
#: app/routes/teams.py:61
msgid "This page is for players."
msgstr "This page is for players."
#: app/routes/teams.py:103
msgid "You do not have permission to create teams."
msgstr "You do not have permission to create teams."
#: app/routes/teams.py:111 app/routes/teams.py:156
msgid "Team name is required."
msgstr "Team name is required."
#: app/routes/teams.py:116 app/routes/teams.py:161
#, python-format
msgid "Team \"%(name)s\" already exists."
msgstr "Team \"%(name)s\" already exists."
#: app/routes/teams.py:138
#, python-format
msgid "Team \"%(name)s\" created successfully!"
msgstr "Team \"%(name)s\" created successfully!"
#: app/routes/teams.py:148
msgid "You do not have permission to edit this team."
msgstr "You do not have permission to edit this team."
#: app/routes/teams.py:199
#, python-format
msgid "Team \"%(name)s\" updated successfully!"
msgstr "Team \"%(name)s\" updated successfully!"
#: app/routes/teams.py:208
msgid "You do not have permission to delete teams."
msgstr "You do not have permission to delete teams."
#: app/routes/teams.py:239
#, python-format
msgid "Team \"%(name)s\" deleted successfully."
msgstr "Team \"%(name)s\" deleted successfully."
#: app/routes/teams.py:254
msgid "Please select a coach."
msgstr "Please select a coach."
#: app/routes/teams.py:259
msgid "Only coaches can be assigned as coach."
msgstr "Only coaches can be assigned as coach."
#: app/routes/teams.py:263
#, python-format
msgid "%(username)s is already a coach of %(name)s."
msgstr "%(username)s is already a coach of %(name)s."
#: app/routes/teams.py:270
#, python-format
msgid "%(username)s added as coach of %(name)s."
msgstr "%(username)s added as coach of %(name)s."
#: app/routes/teams.py:285
msgid "Please select a manager."
msgstr "Please select a manager."
#: app/routes/teams.py:290
msgid "Only managers can be assigned as manager."
msgstr "Only managers can be assigned as manager."
#: app/routes/teams.py:294
#, python-format
msgid "%(username)s is already a manager of %(name)s."
msgstr "%(username)s is already a manager of %(name)s."
#: app/routes/teams.py:301
#, python-format
msgid "%(username)s added as manager of %(name)s."
msgstr "%(username)s added as manager of %(name)s."
#: app/routes/teams.py:326
#, python-format
msgid "Coach removed from %(name)s."
msgstr "Coach removed from %(name)s."
#: app/routes/teams.py:351
#, python-format
msgid "Manager removed from %(name)s."
msgstr "Manager removed from %(name)s."
#: app/routes/teams.py:367 app/routes/tryouts.py:380 app/routes/tryouts.py:478
msgid "Please select a player."
msgstr "Please select a player."
#: app/routes/teams.py:372
msgid "Can only assign players to teams."
msgstr "Can only assign players to teams."
#: app/routes/teams.py:377
#, python-format
msgid "%(username)s is already on %(name)s."
msgstr "%(username)s is already on %(name)s."
#: app/routes/teams.py:383
#, python-format
msgid "%(username)s added to %(name)s!"
msgstr "%(username)s added to %(name)s!"
#: app/routes/teams.py:399 app/routes/teams.py:462
#, python-format
msgid "%(username)s is not on %(name)s."
msgstr "%(username)s is not on %(name)s."
#: app/routes/teams.py:404
#, python-format
msgid "%(username)s removed from %(name)s."
msgstr "%(username)s removed from %(name)s."
#: app/routes/teams.py:434 app/routes/teams.py:452
msgid "You do not have permission to add notes to this team."
msgstr "You do not have permission to add notes to this team."
#: app/routes/teams.py:442
msgid "Team notes added successfully!"
msgstr "Team notes added successfully!"
#: app/routes/teams.py:457 app/routes/users.py:1227 app/routes/users.py:1269
msgid "Can only add notes for players."
msgstr "Can only add notes for players."
#: app/routes/teams.py:470
#, python-format
msgid "Note added for %(username)s!"
msgstr "Note added for %(username)s!"
#: app/routes/tryouts.py:43
msgid "You do not have permission to create tryouts."
msgstr "You do not have permission to create tryouts."
#: app/routes/tryouts.py:65 app/routes/tryouts.py:140
msgid "Invalid start date format."
msgstr "Invalid start date format."
#: app/routes/tryouts.py:74 app/routes/tryouts.py:149
msgid "End date cannot be before start date."
msgstr "End date cannot be before start date."
#: app/routes/tryouts.py:78 app/routes/tryouts.py:153
msgid "Invalid end date format."
msgstr "Invalid end date format."
#: app/routes/tryouts.py:100
msgid "Tryout created successfully!"
msgstr "Tryout created successfully!"
#: app/routes/tryouts.py:114
msgid "You do not have permission to edit this tryout."
msgstr "You do not have permission to edit this tryout."
#: app/routes/tryouts.py:118
msgid "This tryout has ended and can no longer be modified."
msgstr "This tryout has ended and can no longer be modified."
#: app/routes/tryouts.py:175
msgid "Tryout updated successfully!"
msgstr "Tryout updated successfully!"
#: app/routes/tryouts.py:207
msgid "You do not have permission to view this tryout."
msgstr "You do not have permission to view this tryout."
#: app/routes/tryouts.py:309
msgid "Only players can register for tryouts."
msgstr "Only players can register for tryouts."
#: app/routes/tryouts.py:313
msgid "This tryout is not accepting registrations."
msgstr "This tryout is not accepting registrations."
#: app/routes/tryouts.py:319
msgid "You are already registered for this tryout."
msgstr "You are already registered for this tryout."
#: app/routes/tryouts.py:325 app/routes/tryouts.py:397
msgid "This tryout is full."
msgstr "This tryout is full."
#: app/routes/tryouts.py:331
msgid "Successfully registered for tryout!"
msgstr "Successfully registered for tryout!"
#: app/routes/tryouts.py:347
#, python-format
msgid "Tryout status updated to %(new_status)s."
msgstr "Tryout status updated to %(new_status)s."
#: app/routes/tryouts.py:366
msgid "Registration status updated."
msgstr "Registration status updated."
#: app/routes/tryouts.py:385
msgid "Can only register players."
msgstr "Can only register players."
#: app/routes/tryouts.py:391
#, python-format
msgid "%(username)s is already registered for this tryout."
msgstr "%(username)s is already registered for this tryout."
#: app/routes/tryouts.py:403
#, python-format
msgid "%(username)s registered for tryout!"
msgstr "%(username)s registered for tryout!"
#: app/routes/tryouts.py:438
#, python-format
msgid "%(username)s removed from tryout."
msgstr "%(username)s removed from tryout."
#: app/routes/tryouts.py:456
#, python-format
msgid "Team \"%(team_name)s\" created!"
msgstr "Team \"%(team_name)s\" created!"
#: app/routes/tryouts.py:485
msgid "That player is not registered for this tryout."
msgstr "That player is not registered for this tryout."
#: app/routes/tryouts.py:491
msgid "Player is already on this team."
msgstr "Player is already on this team."
#: app/routes/tryouts.py:496
msgid "Player added to team!"
msgstr "Player added to team!"
#: app/routes/tryouts.py:506
msgid "You do not have permission to delete this tryout."
msgstr "You do not have permission to delete this tryout."
#: app/routes/tryouts.py:541
msgid "Tryout deleted successfully."
msgstr "Tryout deleted successfully."
#: app/routes/users.py:116
msgid "Only the president can manage users."
msgstr "Only the president can manage users."
#: app/routes/users.py:128
msgid "Only the president can edit users."
msgstr "Only the president can edit users."
#: app/routes/users.py:168
msgid "Email already in use by another account."
msgstr "Email already in use by another account."
#: app/routes/users.py:175
msgid "You cannot change your own role. Ask another president to do it."
msgstr "You cannot change your own role. Ask another president to do it."
#: app/routes/users.py:186
msgid "This is the last active president. Promote another account before changing this one."
msgstr "This is the last active president. Promote another account before changing this one."
#: app/routes/users.py:232
#, python-format
msgid "User %(username)s updated successfully!"
msgstr "User %(username)s updated successfully!"
#: app/routes/users.py:247
msgid "Only the president can delete users."
msgstr "Only the president can delete users."
#: app/routes/users.py:251
msgid "You cannot delete your own account."
msgstr "You cannot delete your own account."
#: app/routes/users.py:288
#, python-format
msgid "User %(deleted_username)s has been removed."
msgstr "User %(deleted_username)s has been removed."
#: app/routes/users.py:297
msgid "Only the president can create users."
msgstr "Only the president can create users."
#: app/routes/users.py:336
#, python-format
msgid "User %(full_name)s created as %(role)s!"
msgstr "User %(full_name)s created as %(role)s!"
#: app/routes/users.py:393
msgid "Username already taken."
msgstr "Username already taken."
#: app/routes/users.py:399
msgid "Email already in use."
msgstr "Email already in use."
#: app/routes/users.py:424
msgid "Profile updated successfully!"
msgstr "Profile updated successfully!"
#: app/routes/users.py:629
msgid "Only presidents, managers, and coaches can upload contracts."
msgstr "Only presidents, managers, and coaches can upload contracts."
#: app/routes/users.py:656
msgid "You do not have permission to upload a contract for this player."
msgstr "You do not have permission to upload a contract for this player."
#: app/routes/users.py:660 app/routes/users.py:665 app/routes/users.py:717
#: app/routes/users.py:722
msgid "No file selected."
msgstr "No file selected."
#: app/routes/users.py:668
msgid "Only PDF files are allowed for contracts."
msgstr "Only PDF files are allowed for contracts."
#: app/routes/users.py:701
#, python-format
msgid "Contract uploaded successfully for %(username)s!"
msgstr "Contract uploaded successfully for %(username)s!"
#: app/routes/users.py:713
msgid "Only the player can upload their signed contract."
msgstr "Only the player can upload their signed contract."
#: app/routes/users.py:733
msgid "Signed contract uploaded successfully!"
msgstr "Signed contract uploaded successfully!"
#: app/routes/users.py:743 app/routes/users.py:754
msgid "You do not have permission to download this contract."
msgstr "You do not have permission to download this contract."
#: app/routes/users.py:757
msgid "No signed contract available."
msgstr "No signed contract available."
#: app/routes/users.py:824
msgid "Only players can request One on One sessions."
msgstr "Only players can request One on One sessions."
#: app/routes/users.py:832
msgid "You do not have a coach assigned to your team."
msgstr "You do not have a coach assigned to your team."
#: app/routes/users.py:859
msgid "Cannot request One on One - no coach assigned."
msgstr "Cannot request One on One - no coach assigned."
#: app/routes/users.py:867
msgid "Invalid date or time format."
msgstr "Invalid date or time format."
#: app/routes/users.py:881
msgid "The requested time is not within the coach's availability."
msgstr "The requested time is not within the coach's availability."
#: app/routes/users.py:904
msgid "Your One on One request has been submitted!"
msgstr "Your One on One request has been submitted!"
#: app/routes/users.py:939
msgid "Only coaches can accept One on One requests."
msgstr "Only coaches can accept One on One requests."
#: app/routes/users.py:945 app/routes/users.py:986
msgid "This request is not for you."
msgstr "This request is not for you."
#: app/routes/users.py:949 app/routes/users.py:990
msgid "This request has already been processed."
msgstr "This request has already been processed."
#: app/routes/users.py:971
#, python-format
msgid "One on One request from %(player)s has been approved!"
msgstr "One on One request from %(player)s has been approved!"
#: app/routes/users.py:980
msgid "Only coaches can reject One on One requests."
msgstr "Only coaches can reject One on One requests."
#: app/routes/users.py:1017
#, python-format
msgid "One on One request from %(player)s has been rejected."
msgstr "One on One request from %(player)s has been rejected."
#: app/routes/users.py:1030
msgid "This page is for players only."
msgstr "This page is for players only."
#: app/routes/users.py:1061
msgid "Only coaches can manage availability."
msgstr "Only coaches can manage availability."
#: app/routes/users.py:1123
msgid "Only coaches can access the notes dashboard."
msgstr "Only coaches can access the notes dashboard."
#: app/routes/users.py:1184
msgid "Only coaches can manage team notes."
msgstr "Only coaches can manage team notes."
#: app/routes/users.py:1189
msgid "You are not assigned to a team."
msgstr "You are not assigned to a team."
#: app/routes/users.py:1201
msgid "Team notes saved successfully!"
msgstr "Team notes saved successfully!"
#: app/routes/users.py:1215
msgid "Only coaches can manage personal notes."
msgstr "Only coaches can manage personal notes."
#: app/routes/users.py:1222 app/routes/users.py:1264 app/routes/users.py:1314
#: app/routes/users.py:1365
msgid "Player and content are required."
msgstr "Player and content are required."
#: app/routes/users.py:1231 app/routes/users.py:1273 app/routes/users.py:1318
#: app/routes/users.py:1369
msgid "You can only write notes about players you work with."
msgstr "You can only write notes about players you work with."
#: app/routes/users.py:1241 app/routes/users.py:1286
#, python-format
msgid "Note added for %(username)s."
msgstr "Note added for %(username)s."
#: app/routes/users.py:1254 app/routes/users.py:1299 app/routes/users.py:1349
msgid "Only coaches can add personal notes."
msgstr "Only coaches can add personal notes."
#: app/routes/users.py:1329 app/routes/users.py:1380
msgid "Note added successfully."
msgstr "Note added successfully."
#: app/templates/errors/400.html:2
msgid "400 Bad Request"
msgstr "400 Bad Request"
@@ -2086,3 +2716,6 @@ msgstr "View Profile"
#~ msgid "&times;"
#~ msgstr "&times;"
#~ msgid "One on One request from %(value)s has been approved!"
#~ msgstr ""