chore(lint): elargir les regles ruff et rendre le format bloquant en CI

QUA-002, seconde moitie. Le depot etant formate, l elargissement porte sur
des defauts et non sur du brassage.

Ajoute a la selection : B (bugbear), C4, RET, SIM, UP. Le lot entier n a
produit que 24 signalements sur 76 fichiers -- le code etait plus propre
que l audit ne le craignait. Neuf corriges automatiquement, quinze a la
main.

SIM108 est ignore : forcer un ternaire se lit moins bien que le if/else
qu il remplace, au seul endroit ou il se declenche.

isort (I) n est PAS active. Il reordonnerait les imports de 48 fichiers,
soit une seconde passe de pur brassage juste apres le commit de formatage.
A faire, mais seul.

Deux vrais defauts trouves par les nouvelles regles
  - team_matches.edit_match faisait `except ValueError: pass` sur l heure de
    debut et l heure de fin, trois lignes sous un champ date qui, lui,
    signale et redirige. Une heure mal saisie etait donc acceptee par le
    formulaire, jetee, l ancienne valeur conservee -- et la page annoncait
    la reussite. Meme traitement que la date desormais.
  - backup.py levait BackupError depuis deux blocs `except` sans `from`,
    ce qui perdait la cause d origine dans la trace.

Ainsi que : un `return` explicite dans force_https, `%`-formatage remplace
dans log_auth_event (operations de chaine avant journalisation, pas des
gabarits de logger -- la redaction n est pas affectee), une compréhension
inutile, un `set(...)` en compréhension d ensemble, `open(..., 'r')`, une
variable de boucle inutilisee, et `contextlib.suppress` dans conftest.

CI : `ruff format --check` remplace le commentaire qui expliquait pourquoi
il etait absent.

263 tests passent. Les deux nouveaux messages sont traduits ; attention,
pybabel les avait apparies en `fuzzy` avec des entrees « date » existantes,
et une entree fuzzy est ignoree a l execution.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
GGThed
2026-08-08 15:59:40 -04:00
co-authored by Claude Opus 5
parent 7cec18c139
commit 8e3865f557
17 changed files with 475 additions and 439 deletions
+5 -4
View File
@@ -61,10 +61,11 @@ jobs:
- name: Run ruff linter - name: Run ruff linter
run: ruff check . --output-format=github run: ruff check . --output-format=github
# `ruff format --check` is deliberately absent for now: the codebase has # Enabled now that the repository has been formatted once, in its own
# never been formatted, so it would fail on 62 of 64 files for reasons # commit (QUA-002). Reaching this step before that would have failed on
# unrelated to correctness. Reformatting in one isolated commit and then # 72 of 76 files for reasons unrelated to correctness.
# enforcing it here is tracked as QUA-002. - name: Check formatting
run: ruff format --check .
security-scan: security-scan:
name: Security Scan name: Security Scan
+8 -1
View File
@@ -333,10 +333,17 @@ def create_app(config=None):
Respects the X-Forwarded-Proto header from reverse proxies. Respects the X-Forwarded-Proto header from reverse proxies.
Can be disabled via FORCE_HTTPS environment variable. Can be disabled via FORCE_HTTPS environment variable.
Returns:
Response | None: A redirect, or None to let the request through.
""" """
if not app.debug and app.config['FORCE_HTTPS']: if not app.debug and app.config['FORCE_HTTPS']:
if not request.is_secure and request.headers.get('X-Forwarded-Proto') != 'https': already_secure = (
request.is_secure or request.headers.get('X-Forwarded-Proto') == 'https'
)
if not already_secure:
return redirect(request.url.replace('http://', 'https://'), code=301) return redirect(request.url.replace('http://', 'https://'), code=301)
return None
# ========================================================================= # =========================================================================
# Health Check Endpoint # Health Check Endpoint
+1 -1
View File
@@ -69,7 +69,7 @@ class TeamTryoutsBot(commands.Bot):
"""Load pending requests from the JSON file.""" """Load pending requests from the JSON file."""
try: try:
if os.path.exists(PENDING_FILE): if os.path.exists(PENDING_FILE):
with open(PENDING_FILE, 'r') as f: with open(PENDING_FILE) as f:
data = json.load(f) data = json.load(f)
# Convert string keys back to int # Convert string keys back to int
self.pending_requests = {int(k): v for k, v in data.items()} self.pending_requests = {int(k): v for k, v in data.items()}
+4 -4
View File
@@ -211,10 +211,10 @@ def log_auth_event(event, **fields):
""" """
from flask import has_request_context, request from flask import has_request_context, request
parts = ['event=%s' % event] parts = [f'event={event}']
if has_request_context(): if has_request_context():
parts.append('ip=%s' % request.remote_addr) parts.append(f'ip={request.remote_addr}')
parts.append('path=%s' % request.path) parts.append(f'path={request.path}')
parts.extend('%s=%s' % (key, value) for key, value in fields.items()) parts.extend(f'{key}={value}' for key, value in fields.items())
get_auth_logger().info(' '.join(parts)) get_auth_logger().info(' '.join(parts))
+2 -2
View File
@@ -34,11 +34,11 @@ class UserGamertag(db.Model):
platform.lower().replace(' ', '-') if platform else '', platform.lower().replace(' ', '-') if platform else '',
) )
return url.format(platform_code=platform_code, username=encoded_gamertag) return url.format(platform_code=platform_code, username=encoded_gamertag)
elif '{platform}' in url and '{username}' in url: if '{platform}' in url and '{username}' in url:
return url.format( return url.format(
platform=platform.lower().replace(' ', '-') if platform else '', platform=platform.lower().replace(' ', '-') if platform else '',
username=encoded_gamertag, username=encoded_gamertag,
) )
elif '{username}' in url: if '{username}' in url:
return url.format(username=encoded_gamertag) return url.format(username=encoded_gamertag)
return url return url
+1 -1
View File
@@ -29,7 +29,7 @@ class Player(User):
) )
.all() .all()
) )
extra_ids = set(m.tryout_id for m in player_matches) extra_ids = {m.tryout_id for m in player_matches}
extra = ( extra = (
Tryout.query.filter( Tryout.query.filter(
Tryout.id.in_(extra_ids), Tryout.id.in_(extra_ids),
+27 -28
View File
@@ -237,40 +237,39 @@ def login():
next_page = None next_page = None
flash(_('Welcome back, %(username)s!', username=user.username), 'success') flash(_('Welcome back, %(username)s!', username=user.username), 'success')
return redirect(next_page) if next_page else redirect(url_for('main.dashboard')) return redirect(next_page) if next_page else redirect(url_for('main.dashboard'))
else: # One message for every failure. The old code said "N attempts
# One message for every failure. The old code said "N attempts # remaining" to a real account and "check username and password"
# remaining" to a real account and "check username and password" # to an unknown one, which listed the club's accounts to anyone
# to an unknown one, which listed the club's accounts to anyone # who asked (SEC-017).
# who asked (SEC-017). if user:
if user: user.failed_login_attempts += 1
user.failed_login_attempts += 1 log_auth_event(
'login.failure',
username=username,
user_id=user.id,
attempts=user.failed_login_attempts,
)
if user.failed_login_attempts >= MAX_LOGIN_ATTEMPTS:
minutes = cooloff_minutes(user.failed_login_attempts)
user.locked_until = datetime.utcnow() + timedelta(minutes=minutes)
log_auth_event( log_auth_event(
'login.failure', 'account.throttled',
username=username, username=username,
user_id=user.id, user_id=user.id,
minutes=minutes,
attempts=user.failed_login_attempts, attempts=user.failed_login_attempts,
) )
if user.failed_login_attempts >= MAX_LOGIN_ATTEMPTS: db.session.commit()
minutes = cooloff_minutes(user.failed_login_attempts) else:
user.locked_until = datetime.utcnow() + timedelta(minutes=minutes) log_auth_event('login.failure.unknown_user', username=username)
log_auth_event(
'account.throttled',
username=username,
user_id=user.id,
minutes=minutes,
attempts=user.failed_login_attempts,
)
db.session.commit()
else:
log_auth_event('login.failure.unknown_user', username=username)
flash( flash(
_( _(
'Login unsuccessful. Please check your username and ' 'Login unsuccessful. Please check your username and '
'password, or ask a president for help.' 'password, or ask a president for help.'
), ),
'danger', 'danger',
) )
return render_template('pages/login.html') return render_template('pages/login.html')
+11 -5
View File
@@ -98,7 +98,7 @@ def create_match(team_id):
flash(_('You do not have permission to schedule matches for this team.'), 'danger') flash(_('You do not have permission to schedule matches for this team.'), 'danger')
return redirect(url_for('team_matches.list_matches')) return redirect(url_for('team_matches.list_matches'))
team_players = [tp for tp in TeamPlayer.query.filter_by(org_team_id=team_id).all()] team_players = TeamPlayer.query.filter_by(org_team_id=team_id).all()
prefill_date = request.args.get('date', '') prefill_date = request.args.get('date', '')
is_practice = request.args.get('type') == 'practice' is_practice = request.args.get('type') == 'practice'
default_title = 'Practice' if is_practice else f'Team Match — {team.name}' default_title = 'Practice' if is_practice else f'Team Match — {team.name}'
@@ -255,19 +255,25 @@ def edit_match(match_id):
flash(_('Invalid date format.'), 'danger') flash(_('Invalid date format.'), 'danger')
return redirect(url_for('team_matches.edit_match', match_id=match_id)) return redirect(url_for('team_matches.edit_match', match_id=match_id))
# Both used to `except ValueError: pass`, three lines below a date
# field that flashes and redirects. A mistyped time was therefore
# accepted by the form, discarded, and the old value kept — with the
# page reporting success. Same treatment as the date now.
start_time_str = request.form.get('start_time') start_time_str = request.form.get('start_time')
if start_time_str: if start_time_str:
try: try:
team_match.start_time = datetime.strptime(start_time_str, '%H:%M').time() team_match.start_time = datetime.strptime(start_time_str, '%H:%M').time()
except ValueError: except (ValueError, TypeError):
pass flash(_('Invalid start time format.'), 'danger')
return redirect(url_for('team_matches.edit_match', match_id=match_id))
end_time_str = request.form.get('end_time') end_time_str = request.form.get('end_time')
if end_time_str: if end_time_str:
try: try:
team_match.end_time = datetime.strptime(end_time_str, '%H:%M').time() team_match.end_time = datetime.strptime(end_time_str, '%H:%M').time()
except ValueError: except (ValueError, TypeError):
pass flash(_('Invalid end time format.'), 'danger')
return redirect(url_for('team_matches.edit_match', match_id=match_id))
team_match.location = request.form.get('location', '') or None team_match.location = request.form.get('location', '') or None
status = request.form.get('status') status = request.form.get('status')
+4 -4
View File
@@ -167,13 +167,13 @@ def backup_database(conn):
text=True, text=True,
timeout=900, timeout=900,
) )
except FileNotFoundError: except FileNotFoundError as err:
raise BackupError( raise BackupError(
f'{PG_DUMP} not found. Install the PostgreSQL client tools, or set ' f'{PG_DUMP} not found. Install the PostgreSQL client tools, or set '
'PG_DUMP to its full path.' 'PG_DUMP to its full path.'
) ) from err
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired as err:
raise BackupError('pg_dump timed out after 15 minutes.') raise BackupError('pg_dump timed out after 15 minutes.') from err
if result.returncode != 0: if result.returncode != 0:
raise BackupError(f'pg_dump failed: {result.stderr.strip()}') raise BackupError(f'pg_dump failed: {result.stderr.strip()}')
+25 -28
View File
@@ -176,29 +176,27 @@ def check_dependencies():
if result.returncode == 0: if result.returncode == 0:
print('[OK] No known vulnerabilities found') print('[OK] No known vulnerabilities found')
return True return True
else: try:
try: data = json.loads(result.stdout)
data = json.loads(result.stdout) # pip-audit's "dependencies" array lists EVERY dependency, each
# pip-audit's "dependencies" array lists EVERY dependency, each # carrying a "vulns" list that is empty when the package is
# carrying a "vulns" list that is empty when the package is # clean. Treating the array itself as the vulnerability list
# clean. Treating the array itself as the vulnerability list # reported all ~45 installed packages as vulnerable on every
# reported all ~45 installed packages as vulnerable on every # run, which is why this check was pure noise.
# run, which is why this check was pure noise. affected = [dep for dep in data.get('dependencies', []) if dep.get('vulns')]
affected = [dep for dep in data.get('dependencies', []) if dep.get('vulns')] if affected:
if affected: for dep in affected:
for dep in affected: ids = ', '.join(v.get('id', '?') for v in dep.get('vulns', []))
ids = ', '.join(v.get('id', '?') for v in dep.get('vulns', [])) print(f'[FAIL] {dep["name"]}=={dep["version"]}: {ids}')
print(f'[FAIL] {dep["name"]}=={dep["version"]}: {ids}') return False
return False print('[OK] No vulnerabilities found')
else: return True
print('[OK] No vulnerabilities found') except json.JSONDecodeError:
return True if result.stdout:
except json.JSONDecodeError: print(f'[INFO] {result.stdout.strip()}')
if result.stdout: if result.stderr:
print(f'[INFO] {result.stdout.strip()}') print(f'[WARN] {result.stderr.strip()}')
if result.stderr: return True
print(f'[WARN] {result.stderr.strip()}')
return True
except FileNotFoundError: except FileNotFoundError:
print('[SKIP] pip-audit not installed. Run: pip install pip-audit') print('[SKIP] pip-audit not installed. Run: pip install pip-audit')
return True return True
@@ -223,7 +221,7 @@ def check_file_permissions():
gitignore_path = os.path.join(os.getcwd(), '.gitignore') gitignore_path = os.path.join(os.getcwd(), '.gitignore')
if os.path.exists(gitignore_path): if os.path.exists(gitignore_path):
required_patterns = ['.env', 'instance/', '*.db', '*.log'] required_patterns = ['.env', 'instance/', '*.db', '*.log']
with open(gitignore_path, 'r') as f: with open(gitignore_path) as f:
content = f.read() content = f.read()
for pattern in required_patterns: for pattern in required_patterns:
@@ -245,7 +243,7 @@ def check_file_permissions():
# Check for leftover .pyc or __pycache__ # Check for leftover .pyc or __pycache__
pycache_count = 0 pycache_count = 0
for root, dirs, files in os.walk(os.getcwd()): for _root, dirs, files in os.walk(os.getcwd()):
if '__pycache__' in dirs: if '__pycache__' in dirs:
pycache_count += 1 pycache_count += 1
for f in files: for f in files:
@@ -402,9 +400,8 @@ def main():
if failed == 0: if failed == 0:
print('\n[OK] All security checks passed!') print('\n[OK] All security checks passed!')
return 0 return 0
else: print(f'\n[WARN] {failed} check(s) failed. Review the output above.')
print(f'\n[WARN] {failed} check(s) failed. Review the output above.') return 1
return 1
if __name__ == '__main__': if __name__ == '__main__':
Binary file not shown.
+182 -174
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: team-tryouts VERSION\n" "Project-Id-Version: team-tryouts VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-08-08 15:07-0400\n" "POT-Creation-Date: 2026-08-08 15:57-0400\n"
"PO-Revision-Date: 2026-08-07 20:22-0400\n" "PO-Revision-Date: 2026-08-07 20:22-0400\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n" "Language: en\n"
@@ -19,7 +19,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.18.0\n" "Generated-By: Babel 2.18.0\n"
#: app/validators.py:43 #: app/validators.py:49
msgid "" msgid ""
"Password must be at least 8 characters with uppercase, lowercase, and a " "Password must be at least 8 characters with uppercase, lowercase, and a "
"number." "number."
@@ -27,72 +27,72 @@ msgstr ""
"Password must be at least 8 characters with uppercase, lowercase, and a " "Password must be at least 8 characters with uppercase, lowercase, and a "
"number." "number."
#: app/validators.py:62 #: app/validators.py:67
msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)." msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)."
msgstr "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 #: app/validators.py:86
msgid "Invalid Discord username format." msgid "Invalid Discord username format."
msgstr "Invalid Discord username format." msgstr "Invalid Discord username format."
#: app/validators.py:98 #: app/validators.py:103
msgid "Discord User ID must be a 17-20 digit number." msgid "Discord User ID must be a 17-20 digit number."
msgstr "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 #: app/validators.py:121
msgid "Invalid phone number format." msgid "Invalid phone number format."
msgstr "Invalid phone number format." msgstr "Invalid phone number format."
#: app/validators.py:155 #: app/validators.py:163
msgid "Username is required." msgid "Username is required."
msgstr "Username is required." msgstr "Username is required."
#: app/validators.py:159 #: app/validators.py:167
msgid "Password is required." msgid "Password is required."
msgstr "Password is required." msgstr "Password is required."
#: app/validators.py:180 app/validators.py:251 #: app/validators.py:189 app/validators.py:261
msgid "Username must be 3-80 characters." msgid "Username must be 3-80 characters."
msgstr "Username must be 3-80 characters." msgstr "Username must be 3-80 characters."
#: app/validators.py:186 #: app/validators.py:195
msgid "Email must be 120 characters or less." msgid "Email must be 120 characters or less."
msgstr "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:208 app/validators.py:276 app/validators.py:307
#: app/validators.py:365 #: app/validators.py:371
msgid "Full name is required." msgid "Full name is required."
msgstr "Full name is required." msgstr "Full name is required."
#: app/validators.py:234 #: app/validators.py:243
msgid "Passwords do not match." msgid "Passwords do not match."
msgstr "Passwords do not match." msgstr "Passwords do not match."
#: app/validators.py:272 app/validators.py:309 #: app/validators.py:280 app/validators.py:315
msgid "Invalid role selected." msgid "Invalid role selected."
msgstr "Invalid role selected." msgstr "Invalid role selected."
#: app/validators.py:409 #: app/validators.py:416
msgid "Player must be selected." msgid "Player must be selected."
msgstr "Player must be selected." msgstr "Player must be selected."
#: app/validators.py:412 #: app/validators.py:419
msgid "Notes must be 2000 characters or less." msgid "Notes must be 2000 characters or less."
msgstr "Notes must be 2000 characters or less." msgstr "Notes must be 2000 characters or less."
#: app/validators.py:431 #: app/validators.py:438
msgid "Date must be in YYYY-MM-DD format." msgid "Date must be in YYYY-MM-DD format."
msgstr "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 #: app/validators.py:443 app/validators.py:470
msgid "Start time must be in HH:MM format." msgid "Start time must be in HH:MM format."
msgstr "Start time must be in HH:MM format." msgstr "Start time must be in HH:MM format."
#: app/validators.py:445 #: app/validators.py:447
msgid "End time must be in HH:MM format." msgid "End time must be in HH:MM format."
msgstr "End time must be in HH:MM format." msgstr "End time must be in HH:MM format."
#: app/validators.py:449 #: app/validators.py:450
msgid "Points must be 2000 characters or less." msgid "Points must be 2000 characters or less."
msgstr "Points must be 2000 characters or less." msgstr "Points must be 2000 characters or less."
@@ -100,22 +100,22 @@ msgstr "Points must be 2000 characters or less."
msgid "Day must be 0 (Monday) to 6 (Sunday)." msgid "Day must be 0 (Monday) to 6 (Sunday)."
msgstr "Day must be 0 (Monday) to 6 (Sunday)." msgstr "Day must be 0 (Monday) to 6 (Sunday)."
#: app/routes/auth.py:186 app/routes/auth.py:314 app/routes/users.py:83 #: app/routes/auth.py:186 app/routes/auth.py:322 app/routes/users.py:106
#: app/routes/users.py:687 #: app/routes/users.py:821
#, python-format #, python-format
msgid "%(field)s: %(msg)s" msgid "%(field)s: %(msg)s"
msgstr "%(field)s: %(msg)s" msgstr "%(field)s: %(msg)s"
#: app/routes/auth.py:204 #: app/routes/auth.py:203
msgid "This account has been deactivated." msgid "This account has been deactivated."
msgstr "This account has been deactivated." msgstr "This account has been deactivated."
#: app/routes/auth.py:242 #: app/routes/auth.py:238
#, python-format #, python-format
msgid "Welcome back, %(username)s!" msgid "Welcome back, %(username)s!"
msgstr "Welcome back, %(username)s!" msgstr "Welcome back, %(username)s!"
#: app/routes/auth.py:263 #: app/routes/auth.py:268
msgid "" msgid ""
"Login unsuccessful. Please check your username and password, or ask a " "Login unsuccessful. Please check your username and password, or ask a "
"president for help." "president for help."
@@ -123,27 +123,27 @@ msgstr ""
"Login unsuccessful. Please check your username and password, or ask a " "Login unsuccessful. Please check your username and password, or ask a "
"president for help." "president for help."
#: app/routes/auth.py:295 #: app/routes/auth.py:303
msgid "Incorrect CAPTCHA answer. Please try again." msgid "Incorrect CAPTCHA answer. Please try again."
msgstr "Incorrect CAPTCHA answer. Please try again." msgstr "Incorrect CAPTCHA answer. Please try again."
#: app/routes/auth.py:337 app/routes/users.py:370 #: app/routes/auth.py:345 app/routes/users.py:436
msgid "Username already exists." msgid "Username already exists."
msgstr "Username already exists." msgstr "Username already exists."
#: app/routes/auth.py:349 app/routes/users.py:374 #: app/routes/auth.py:357 app/routes/users.py:440
msgid "Email already registered." msgid "Email already registered."
msgstr "Email already registered." msgstr "Email already registered."
#: app/routes/auth.py:395 #: app/routes/auth.py:404
msgid "Your account has been created! You can now log in." msgid "Your account has been created! You can now log in."
msgstr "Your account has been created! You can now log in." msgstr "Your account has been created! You can now log in."
#: app/routes/auth.py:421 #: app/routes/auth.py:430
msgid "Discord OAuth2 is not configured." msgid "Discord OAuth2 is not configured."
msgstr "Discord OAuth2 is not configured." msgstr "Discord OAuth2 is not configured."
#: app/routes/auth.py:461 #: app/routes/auth.py:471
msgid "" msgid ""
"Discord authorization could not be verified. Please start the connection " "Discord authorization could not be verified. Please start the connection "
"again from this page." "again from this page."
@@ -151,410 +151,418 @@ msgstr ""
"Discord authorization could not be verified. Please start the connection " "Discord authorization could not be verified. Please start the connection "
"again from this page." "again from this page."
#: app/routes/auth.py:469 #: app/routes/auth.py:480
msgid "Discord authorization failed. No code received." msgid "Discord authorization failed. No code received."
msgstr "Discord authorization failed. No code received." msgstr "Discord authorization failed. No code received."
#: app/routes/auth.py:493 #: app/routes/auth.py:504
msgid "Failed to connect to Discord. Please try again." msgid "Failed to connect to Discord. Please try again."
msgstr "Failed to connect to Discord. Please try again." msgstr "Failed to connect to Discord. Please try again."
#: app/routes/auth.py:497 #: app/routes/auth.py:508
msgid "Failed to obtain Discord access token." msgid "Failed to obtain Discord access token."
msgstr "Failed to obtain Discord access token." msgstr "Failed to obtain Discord access token."
#: app/routes/auth.py:512 #: app/routes/auth.py:523
msgid "Failed to fetch Discord user profile." msgid "Failed to fetch Discord user profile."
msgstr "Failed to fetch Discord user profile." msgstr "Failed to fetch Discord user profile."
#: app/routes/auth.py:559 #: app/routes/auth.py:570
msgid "Discord account connected! Your profile has been pre-filled." msgid "Discord account connected! Your profile has been pre-filled."
msgstr "Discord account connected! Your profile has been pre-filled." msgstr "Discord account connected! Your profile has been pre-filled."
#: app/routes/auth.py:587 #: app/routes/auth.py:598
msgid "You have been logged out." msgid "You have been logged out."
msgstr "You have been logged out." msgstr "You have been logged out."
#: app/routes/evaluations.py:41 #: app/routes/evaluations.py:45
msgid "You do not have permission to view evaluations." msgid "You do not have permission to view evaluations."
msgstr "You do not have permission to view evaluations." msgstr "You do not have permission to view evaluations."
#: app/routes/evaluations.py:122 #: app/routes/evaluations.py:135
msgid "You do not have permission to evaluate players." msgid "You do not have permission to evaluate players."
msgstr "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 #: app/routes/evaluations.py:140 app/routes/evaluations.py:263
msgid "You do not have permission to evaluate players in this tryout." msgid "You do not have permission to evaluate players in this tryout."
msgstr "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 #: app/routes/evaluations.py:151
msgid "Player is not registered for this tryout." msgid "Player is not registered for this tryout."
msgstr "Player is not registered for this tryout." msgstr "Player is not registered for this tryout."
#: app/routes/evaluations.py:139 #: app/routes/evaluations.py:156
msgid "Can only evaluate players." msgid "Can only evaluate players."
msgstr "Can only evaluate players." msgstr "Can only evaluate players."
#: app/routes/evaluations.py:177 #: app/routes/evaluations.py:208
msgid "Evaluation updated!" msgid "Evaluation updated!"
msgstr "Evaluation updated!" msgstr "Evaluation updated!"
#: app/routes/evaluations.py:190 #: app/routes/evaluations.py:228
msgid "Evaluation submitted successfully!" msgid "Evaluation submitted successfully!"
msgstr "Evaluation submitted successfully!" msgstr "Evaluation submitted successfully!"
#: app/routes/evaluations.py:215 app/routes/teams.py:236 #: app/routes/evaluations.py:258 app/routes/teams.py:268
#: app/routes/teams.py:267 app/routes/teams.py:298 app/routes/teams.py:323 #: app/routes/teams.py:309 app/routes/teams.py:350 app/routes/teams.py:375
#: app/routes/teams.py:348 app/routes/teams.py:380 app/routes/tryouts.py:341 #: app/routes/teams.py:400 app/routes/teams.py:435 app/routes/tryouts.py:472
#: app/routes/tryouts.py:357 app/routes/tryouts.py:376 #: app/routes/tryouts.py:488 app/routes/tryouts.py:508
#: app/routes/tryouts.py:413 app/routes/tryouts.py:448 #: app/routes/tryouts.py:547 app/routes/tryouts.py:583
#: app/routes/tryouts.py:467 #: app/routes/tryouts.py:602
msgid "Permission denied." msgid "Permission denied."
msgstr "Permission denied." msgstr "Permission denied."
#: app/routes/main.py:44 #: app/routes/main.py:53
msgid "That language is not available." msgid "That language is not available."
msgstr "That language is not available." msgstr "That language is not available."
#: app/routes/matches.py:201 #: app/routes/matches.py:245
msgid "You do not have permission to schedule matches for this tryout." msgid "You do not have permission to schedule matches for this tryout."
msgstr "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 #: app/routes/matches.py:249 app/routes/matches.py:422
msgid "This tryout has ended. Matches can no longer be created or modified." 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." msgstr "This tryout has ended. Matches can no longer be created or modified."
#: app/routes/matches.py:224 #: app/routes/matches.py:270
msgid "Start time is required. Please select a time slot." msgid "Start time is required. Please select a time slot."
msgstr "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/matches.py:282 app/routes/matches.py:445
#: app/routes/team_matches.py:123 app/routes/team_matches.py:206 #: app/routes/team_matches.py:151 app/routes/team_matches.py:255
msgid "Invalid date format." msgid "Invalid date format."
msgstr "Invalid date format." msgstr "Invalid date format."
#: app/routes/matches.py:246 app/routes/team_matches.py:140 #: app/routes/matches.py:302 app/routes/team_matches.py:172
msgid "Invalid time format." msgid "Invalid time format."
msgstr "Invalid time format." msgstr "Invalid time format."
#: app/routes/matches.py:317 #: app/routes/matches.py:398
msgid "Match scheduled successfully!" msgid "Match scheduled successfully!"
msgstr "Match scheduled successfully!" msgstr "Match scheduled successfully!"
#: app/routes/matches.py:332 app/routes/team_matches.py:193 #: app/routes/matches.py:418 app/routes/team_matches.py:242
msgid "You do not have permission to edit this match." msgid "You do not have permission to edit this match."
msgstr "You do not have permission to edit this match." msgstr "You do not have permission to edit this match."
#: app/routes/matches.py:365 #: app/routes/matches.py:456
msgid "Start time is required." msgid "Start time is required."
msgstr "Start time is required." msgstr "Start time is required."
#: app/routes/matches.py:461 app/routes/team_matches.py:229 #: app/routes/matches.py:578 app/routes/team_matches.py:284
msgid "Match updated successfully!" msgid "Match updated successfully!"
msgstr "Match updated successfully!" msgstr "Match updated successfully!"
#: app/routes/matches.py:506 app/routes/team_matches.py:243 #: app/routes/matches.py:631 app/routes/team_matches.py:299
msgid "You do not have permission to delete this match." msgid "You do not have permission to delete this match."
msgstr "You do not have permission to delete this match." msgstr "You do not have permission to delete this match."
#: app/routes/matches.py:509 #: app/routes/matches.py:634
msgid "This tryout has ended. Matches can no longer be deleted." msgid "This tryout has ended. Matches can no longer be deleted."
msgstr "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:247 #: app/routes/matches.py:647 app/routes/team_matches.py:303
msgid "Match deleted successfully." msgid "Match deleted successfully."
msgstr "Match deleted successfully." msgstr "Match deleted successfully."
#: app/routes/team_matches.py:81 #: app/routes/team_matches.py:98
msgid "You do not have permission to schedule matches for this team." msgid "You do not have permission to schedule matches for this team."
msgstr "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:116 #: app/routes/team_matches.py:140
msgid "Date is required." msgid "Date is required."
msgstr "Date is required." msgstr "Date is required."
#: app/routes/team_matches.py:179 #: app/routes/team_matches.py:228
#, python-format #, python-format
msgid "Team match \"%(title)s\" scheduled successfully!" msgid "Team match \"%(title)s\" scheduled successfully!"
msgstr "Team match \"%(title)s\" scheduled successfully!" msgstr "Team match \"%(title)s\" scheduled successfully!"
#: app/routes/teams.py:28 #: app/routes/team_matches.py:267
msgid "Invalid start time format."
msgstr "Invalid start time format."
#: app/routes/team_matches.py:275
msgid "Invalid end time format."
msgstr "Invalid end time format."
#: app/routes/teams.py:38
msgid "Use My Team(s) to view your teams." msgid "Use My Team(s) to view your teams."
msgstr "Use My Team(s) to view your teams." msgstr "Use My Team(s) to view your teams."
#: app/routes/teams.py:31 #: app/routes/teams.py:41
msgid "You do not have permission to view teams." msgid "You do not have permission to view teams."
msgstr "You do not have permission to view teams." msgstr "You do not have permission to view teams."
#: app/routes/teams.py:48 #: app/routes/teams.py:68
msgid "This page is for players." msgid "This page is for players."
msgstr "This page is for players." msgstr "This page is for players."
#: app/routes/teams.py:90 #: app/routes/teams.py:121
msgid "You do not have permission to create teams." msgid "You do not have permission to create teams."
msgstr "You do not have permission to create teams." msgstr "You do not have permission to create teams."
#: app/routes/teams.py:98 app/routes/teams.py:143 #: app/routes/teams.py:129 app/routes/teams.py:174
msgid "Team name is required." msgid "Team name is required."
msgstr "Team name is required." msgstr "Team name is required."
#: app/routes/teams.py:103 app/routes/teams.py:148 #: app/routes/teams.py:134 app/routes/teams.py:179
#, python-format #, python-format
msgid "Team \"%(name)s\" already exists." msgid "Team \"%(name)s\" already exists."
msgstr "Team \"%(name)s\" already exists." msgstr "Team \"%(name)s\" already exists."
#: app/routes/teams.py:125 #: app/routes/teams.py:156
#, python-format #, python-format
msgid "Team \"%(name)s\" created successfully!" msgid "Team \"%(name)s\" created successfully!"
msgstr "Team \"%(name)s\" created successfully!" msgstr "Team \"%(name)s\" created successfully!"
#: app/routes/teams.py:135 #: app/routes/teams.py:166
msgid "You do not have permission to edit this team." msgid "You do not have permission to edit this team."
msgstr "You do not have permission to edit this team." msgstr "You do not have permission to edit this team."
#: app/routes/teams.py:186 #: app/routes/teams.py:217
#, python-format #, python-format
msgid "Team \"%(name)s\" updated successfully!" msgid "Team \"%(name)s\" updated successfully!"
msgstr "Team \"%(name)s\" updated successfully!" msgstr "Team \"%(name)s\" updated successfully!"
#: app/routes/teams.py:195 #: app/routes/teams.py:226
msgid "You do not have permission to delete teams." msgid "You do not have permission to delete teams."
msgstr "You do not have permission to delete teams." msgstr "You do not have permission to delete teams."
#: app/routes/teams.py:226 #: app/routes/teams.py:258
#, python-format #, python-format
msgid "Team \"%(name)s\" deleted successfully." msgid "Team \"%(name)s\" deleted successfully."
msgstr "Team \"%(name)s\" deleted successfully." msgstr "Team \"%(name)s\" deleted successfully."
#: app/routes/teams.py:241 #: app/routes/teams.py:273
msgid "Please select a coach." msgid "Please select a coach."
msgstr "Please select a coach." msgstr "Please select a coach."
#: app/routes/teams.py:246 #: app/routes/teams.py:278
msgid "Only coaches can be assigned as coach." msgid "Only coaches can be assigned as coach."
msgstr "Only coaches can be assigned as coach." msgstr "Only coaches can be assigned as coach."
#: app/routes/teams.py:250 #: app/routes/teams.py:284
#, python-format #, python-format
msgid "%(username)s is already a coach of %(name)s." msgid "%(username)s is already a coach of %(name)s."
msgstr "%(username)s is already a coach of %(name)s." msgstr "%(username)s is already a coach of %(name)s."
#: app/routes/teams.py:257 #: app/routes/teams.py:297
#, python-format #, python-format
msgid "%(username)s added as coach of %(name)s." msgid "%(username)s added as coach of %(name)s."
msgstr "%(username)s added as coach of %(name)s." msgstr "%(username)s added as coach of %(name)s."
#: app/routes/teams.py:272 #: app/routes/teams.py:314
msgid "Please select a manager." msgid "Please select a manager."
msgstr "Please select a manager." msgstr "Please select a manager."
#: app/routes/teams.py:277 #: app/routes/teams.py:319
msgid "Only managers can be assigned as manager." msgid "Only managers can be assigned as manager."
msgstr "Only managers can be assigned as manager." msgstr "Only managers can be assigned as manager."
#: app/routes/teams.py:281 #: app/routes/teams.py:325
#, python-format #, python-format
msgid "%(username)s is already a manager of %(name)s." msgid "%(username)s is already a manager of %(name)s."
msgstr "%(username)s is already a manager of %(name)s." msgstr "%(username)s is already a manager of %(name)s."
#: app/routes/teams.py:288 #: app/routes/teams.py:338
#, python-format #, python-format
msgid "%(username)s added as manager of %(name)s." msgid "%(username)s added as manager of %(name)s."
msgstr "%(username)s added as manager of %(name)s." msgstr "%(username)s added as manager of %(name)s."
#: app/routes/teams.py:313 #: app/routes/teams.py:365
#, python-format #, python-format
msgid "Coach removed from %(name)s." msgid "Coach removed from %(name)s."
msgstr "Coach removed from %(name)s." msgstr "Coach removed from %(name)s."
#: app/routes/teams.py:338 #: app/routes/teams.py:390
#, python-format #, python-format
msgid "Manager removed from %(name)s." msgid "Manager removed from %(name)s."
msgstr "Manager removed from %(name)s." msgstr "Manager removed from %(name)s."
#: app/routes/teams.py:354 app/routes/tryouts.py:380 app/routes/tryouts.py:478 #: app/routes/teams.py:406 app/routes/tryouts.py:512 app/routes/tryouts.py:613
msgid "Please select a player." msgid "Please select a player."
msgstr "Please select a player." msgstr "Please select a player."
#: app/routes/teams.py:359 #: app/routes/teams.py:411
msgid "Can only assign players to teams." msgid "Can only assign players to teams."
msgstr "Can only assign players to teams." msgstr "Can only assign players to teams."
#: app/routes/teams.py:364 #: app/routes/teams.py:417
#, python-format #, python-format
msgid "%(username)s is already on %(name)s." msgid "%(username)s is already on %(name)s."
msgstr "%(username)s is already on %(name)s." msgstr "%(username)s is already on %(name)s."
#: app/routes/teams.py:370 #: app/routes/teams.py:425
#, python-format #, python-format
msgid "%(username)s added to %(name)s!" msgid "%(username)s added to %(name)s!"
msgstr "%(username)s added to %(name)s!" msgstr "%(username)s added to %(name)s!"
#: app/routes/teams.py:386 app/routes/teams.py:449 #: app/routes/teams.py:442 app/routes/teams.py:515
#, python-format #, python-format
msgid "%(username)s is not on %(name)s." msgid "%(username)s is not on %(name)s."
msgstr "%(username)s is not on %(name)s." msgstr "%(username)s is not on %(name)s."
#: app/routes/teams.py:391 #: app/routes/teams.py:450
#, python-format #, python-format
msgid "%(username)s removed from %(name)s." msgid "%(username)s removed from %(name)s."
msgstr "%(username)s removed from %(name)s." msgstr "%(username)s removed from %(name)s."
#: app/routes/teams.py:421 app/routes/teams.py:439 #: app/routes/teams.py:486 app/routes/teams.py:504
msgid "You do not have permission to add notes to this team." msgid "You do not have permission to add notes to this team."
msgstr "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:429 #: app/routes/teams.py:494
msgid "Team notes added successfully!" msgid "Team notes added successfully!"
msgstr "Team notes added successfully!" msgstr "Team notes added successfully!"
#: app/routes/teams.py:444 app/routes/users.py:1266 app/routes/users.py:1308 #: app/routes/teams.py:509 app/routes/users.py:1530 app/routes/users.py:1573
msgid "Can only add notes for players." msgid "Can only add notes for players."
msgstr "Can only add notes for players." msgstr "Can only add notes for players."
#: app/routes/teams.py:457 #: app/routes/teams.py:525
#, python-format #, python-format
msgid "Note added for %(username)s!" msgid "Note added for %(username)s!"
msgstr "Note added for %(username)s!" msgstr "Note added for %(username)s!"
#: app/routes/tryouts.py:43 #: app/routes/tryouts.py:56
msgid "You do not have permission to create tryouts." msgid "You do not have permission to create tryouts."
msgstr "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 #: app/routes/tryouts.py:82 app/routes/tryouts.py:189
msgid "Invalid start date format." msgid "Invalid start date format."
msgstr "Invalid start date format." msgstr "Invalid start date format."
#: app/routes/tryouts.py:74 app/routes/tryouts.py:149 #: app/routes/tryouts.py:97 app/routes/tryouts.py:204
msgid "End date cannot be before start date." msgid "End date cannot be before start date."
msgstr "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 #: app/routes/tryouts.py:107 app/routes/tryouts.py:214
msgid "Invalid end date format." msgid "Invalid end date format."
msgstr "Invalid end date format." msgstr "Invalid end date format."
#: app/routes/tryouts.py:100 #: app/routes/tryouts.py:139
msgid "Tryout created successfully!" msgid "Tryout created successfully!"
msgstr "Tryout created successfully!" msgstr "Tryout created successfully!"
#: app/routes/tryouts.py:114 #: app/routes/tryouts.py:159
msgid "You do not have permission to edit this tryout." msgid "You do not have permission to edit this tryout."
msgstr "You do not have permission to edit this tryout." msgstr "You do not have permission to edit this tryout."
#: app/routes/tryouts.py:118 #: app/routes/tryouts.py:163
msgid "This tryout has ended and can no longer be modified." msgid "This tryout has ended and can no longer be modified."
msgstr "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 #: app/routes/tryouts.py:242
msgid "Tryout updated successfully!" msgid "Tryout updated successfully!"
msgstr "Tryout updated successfully!" msgstr "Tryout updated successfully!"
#: app/routes/tryouts.py:207 #: app/routes/tryouts.py:289
msgid "You do not have permission to view this tryout." msgid "You do not have permission to view this tryout."
msgstr "You do not have permission to view this tryout." msgstr "You do not have permission to view this tryout."
#: app/routes/tryouts.py:309 #: app/routes/tryouts.py:439
msgid "Only players can register for tryouts." msgid "Only players can register for tryouts."
msgstr "Only players can register for tryouts." msgstr "Only players can register for tryouts."
#: app/routes/tryouts.py:313 #: app/routes/tryouts.py:443
msgid "This tryout is not accepting registrations." msgid "This tryout is not accepting registrations."
msgstr "This tryout is not accepting registrations." msgstr "This tryout is not accepting registrations."
#: app/routes/tryouts.py:319 #: app/routes/tryouts.py:450
msgid "You are already registered for this tryout." msgid "You are already registered for this tryout."
msgstr "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 #: app/routes/tryouts.py:456 app/routes/tryouts.py:531
msgid "This tryout is full." msgid "This tryout is full."
msgstr "This tryout is full." msgstr "This tryout is full."
#: app/routes/tryouts.py:331 #: app/routes/tryouts.py:462
msgid "Successfully registered for tryout!" msgid "Successfully registered for tryout!"
msgstr "Successfully registered for tryout!" msgstr "Successfully registered for tryout!"
#: app/routes/tryouts.py:347 #: app/routes/tryouts.py:478
#, python-format #, python-format
msgid "Tryout status updated to %(new_status)s." msgid "Tryout status updated to %(new_status)s."
msgstr "Tryout status updated to %(new_status)s." msgstr "Tryout status updated to %(new_status)s."
#: app/routes/tryouts.py:366 #: app/routes/tryouts.py:498
msgid "Registration status updated." msgid "Registration status updated."
msgstr "Registration status updated." msgstr "Registration status updated."
#: app/routes/tryouts.py:385 #: app/routes/tryouts.py:517
msgid "Can only register players." msgid "Can only register players."
msgstr "Can only register players." msgstr "Can only register players."
#: app/routes/tryouts.py:391 #: app/routes/tryouts.py:523
#, python-format #, python-format
msgid "%(username)s is already registered for this tryout." msgid "%(username)s is already registered for this tryout."
msgstr "%(username)s is already registered for this tryout." msgstr "%(username)s is already registered for this tryout."
#: app/routes/tryouts.py:403 #: app/routes/tryouts.py:537
#, python-format #, python-format
msgid "%(username)s registered for tryout!" msgid "%(username)s registered for tryout!"
msgstr "%(username)s registered for tryout!" msgstr "%(username)s registered for tryout!"
#: app/routes/tryouts.py:438 #: app/routes/tryouts.py:573
#, python-format #, python-format
msgid "%(username)s removed from tryout." msgid "%(username)s removed from tryout."
msgstr "%(username)s removed from tryout." msgstr "%(username)s removed from tryout."
#: app/routes/tryouts.py:456 #: app/routes/tryouts.py:591
#, python-format #, python-format
msgid "Team \"%(team_name)s\" created!" msgid "Team \"%(team_name)s\" created!"
msgstr "Team \"%(team_name)s\" created!" msgstr "Team \"%(team_name)s\" created!"
#: app/routes/tryouts.py:485 #: app/routes/tryouts.py:622
msgid "That player is not registered for this tryout." msgid "That player is not registered for this tryout."
msgstr "That player is not registered for this tryout." msgstr "That player is not registered for this tryout."
#: app/routes/tryouts.py:491 #: app/routes/tryouts.py:628
msgid "Player is already on this team." msgid "Player is already on this team."
msgstr "Player is already on this team." msgstr "Player is already on this team."
#: app/routes/tryouts.py:496 #: app/routes/tryouts.py:633
msgid "Player added to team!" msgid "Player added to team!"
msgstr "Player added to team!" msgstr "Player added to team!"
#: app/routes/tryouts.py:506 #: app/routes/tryouts.py:643
msgid "You do not have permission to delete this tryout." msgid "You do not have permission to delete this tryout."
msgstr "You do not have permission to delete this tryout." msgstr "You do not have permission to delete this tryout."
#: app/routes/tryouts.py:541 #: app/routes/tryouts.py:679
msgid "Tryout deleted successfully." msgid "Tryout deleted successfully."
msgstr "Tryout deleted successfully." msgstr "Tryout deleted successfully."
#: app/routes/users.py:61 #: app/routes/users.py:83
msgid "No file selected." msgid "No file selected."
msgstr "No file selected." msgstr "No file selected."
#: app/routes/users.py:65 #: app/routes/users.py:87
msgid "Only PDF files are allowed for contracts." msgid "Only PDF files are allowed for contracts."
msgstr "Only PDF files are allowed for contracts." msgstr "Only PDF files are allowed for contracts."
#: app/routes/users.py:70 #: app/routes/users.py:92
msgid "That file is not a PDF, whatever its name says." msgid "That file is not a PDF, whatever its name says."
msgstr "That file is not a PDF, whatever its name says." msgstr "That file is not a PDF, whatever its name says."
#: app/routes/users.py:153 #: app/routes/users.py:181
msgid "Only the president can manage users." msgid "Only the president can manage users."
msgstr "Only the president can manage users." msgstr "Only the president can manage users."
#: app/routes/users.py:165 #: app/routes/users.py:193
msgid "Only the president can edit users." msgid "Only the president can edit users."
msgstr "Only the president can edit users." msgstr "Only the president can edit users."
#: app/routes/users.py:202 #: app/routes/users.py:234
msgid "Email already in use by another account." msgid "Email already in use by another account."
msgstr "Email already in use by another account." msgstr "Email already in use by another account."
#: app/routes/users.py:212 #: app/routes/users.py:245
msgid "You cannot change your own role. Ask another president to do it." 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." msgstr "You cannot change your own role. Ask another president to do it."
#: app/routes/users.py:223 #: app/routes/users.py:258
msgid "" msgid ""
"This is the last active president. Promote another account before " "This is the last active president. Promote another account before "
"changing this one." "changing this one."
@@ -562,172 +570,172 @@ msgstr ""
"This is the last active president. Promote another account before " "This is the last active president. Promote another account before "
"changing this one." "changing this one."
#: app/routes/users.py:285 #: app/routes/users.py:337
#, python-format #, python-format
msgid "User %(username)s updated successfully!" msgid "User %(username)s updated successfully!"
msgstr "User %(username)s updated successfully!" msgstr "User %(username)s updated successfully!"
#: app/routes/users.py:300 #: app/routes/users.py:358
msgid "Only the president can delete users." msgid "Only the president can delete users."
msgstr "Only the president can delete users." msgstr "Only the president can delete users."
#: app/routes/users.py:304 #: app/routes/users.py:362
msgid "You cannot delete your own account." msgid "You cannot delete your own account."
msgstr "You cannot delete your own account." msgstr "You cannot delete your own account."
#: app/routes/users.py:341 #: app/routes/users.py:405
#, python-format #, python-format
msgid "User %(deleted_username)s has been removed." msgid "User %(deleted_username)s has been removed."
msgstr "User %(deleted_username)s has been removed." msgstr "User %(deleted_username)s has been removed."
#: app/routes/users.py:350 #: app/routes/users.py:416
msgid "Only the president can create users." msgid "Only the president can create users."
msgstr "Only the president can create users." msgstr "Only the president can create users."
#: app/routes/users.py:389 #: app/routes/users.py:464
#, python-format #, python-format
msgid "User %(full_name)s created as %(role)s!" msgid "User %(full_name)s created as %(role)s!"
msgstr "User %(full_name)s created as %(role)s!" msgstr "User %(full_name)s created as %(role)s!"
#: app/routes/users.py:446 #: app/routes/users.py:534
msgid "Username already taken." msgid "Username already taken."
msgstr "Username already taken." msgstr "Username already taken."
#: app/routes/users.py:452 #: app/routes/users.py:544
msgid "Email already in use." msgid "Email already in use."
msgstr "Email already in use." msgstr "Email already in use."
#: app/routes/users.py:477 #: app/routes/users.py:574
msgid "Profile updated successfully!" msgid "Profile updated successfully!"
msgstr "Profile updated successfully!" msgstr "Profile updated successfully!"
#: app/routes/users.py:675 #: app/routes/users.py:809
msgid "Only presidents, managers, and coaches can upload contracts." msgid "Only presidents, managers, and coaches can upload contracts."
msgstr "Only presidents, managers, and coaches can upload contracts." msgstr "Only presidents, managers, and coaches can upload contracts."
#: app/routes/users.py:694 #: app/routes/users.py:828
msgid "You do not have permission to upload a contract for this player." 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." msgstr "You do not have permission to upload a contract for this player."
#: app/routes/users.py:733 #: app/routes/users.py:869
#, python-format #, python-format
msgid "Contract uploaded successfully for %(username)s!" msgid "Contract uploaded successfully for %(username)s!"
msgstr "Contract uploaded successfully for %(username)s!" msgstr "Contract uploaded successfully for %(username)s!"
#: app/routes/users.py:745 #: app/routes/users.py:883
msgid "Only the player can upload their signed contract." msgid "Only the player can upload their signed contract."
msgstr "Only the player can upload their signed contract." msgstr "Only the player can upload their signed contract."
#: app/routes/users.py:762 #: app/routes/users.py:902
msgid "Signed contract uploaded successfully!" msgid "Signed contract uploaded successfully!"
msgstr "Signed contract uploaded successfully!" msgstr "Signed contract uploaded successfully!"
#: app/routes/users.py:772 app/routes/users.py:783 #: app/routes/users.py:912 app/routes/users.py:925
msgid "You do not have permission to download this contract." msgid "You do not have permission to download this contract."
msgstr "You do not have permission to download this contract." msgstr "You do not have permission to download this contract."
#: app/routes/users.py:786 #: app/routes/users.py:928
msgid "No signed contract available." msgid "No signed contract available."
msgstr "No signed contract available." msgstr "No signed contract available."
#: app/routes/users.py:853 #: app/routes/users.py:1034
msgid "Only players can request One on One sessions." msgid "Only players can request One on One sessions."
msgstr "Only players can request One on One sessions." msgstr "Only players can request One on One sessions."
#: app/routes/users.py:866 #: app/routes/users.py:1047
msgid "You do not have a coach assigned to your team." msgid "You do not have a coach assigned to your team."
msgstr "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:893 #: app/routes/users.py:1082
msgid "Cannot request One on One - no coach assigned." msgid "Cannot request One on One - no coach assigned."
msgstr "Cannot request One on One - no coach assigned." msgstr "Cannot request One on One - no coach assigned."
#: app/routes/users.py:901 #: app/routes/users.py:1090
msgid "Invalid date or time format." msgid "Invalid date or time format."
msgstr "Invalid date or time format." msgstr "Invalid date or time format."
#: app/routes/users.py:915 #: app/routes/users.py:1104
msgid "The requested time is not within the coach's availability." msgid "The requested time is not within the coach's availability."
msgstr "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:938 #: app/routes/users.py:1132
msgid "Your One on One request has been submitted!" msgid "Your One on One request has been submitted!"
msgstr "Your One on One request has been submitted!" msgstr "Your One on One request has been submitted!"
#: app/routes/users.py:973 #: app/routes/users.py:1176
msgid "Only coaches can accept One on One requests." msgid "Only coaches can accept One on One requests."
msgstr "Only coaches can accept One on One requests." msgstr "Only coaches can accept One on One requests."
#: app/routes/users.py:979 app/routes/users.py:1020 #: app/routes/users.py:1182 app/routes/users.py:1232
msgid "This request is not for you." msgid "This request is not for you."
msgstr "This request is not for you." msgstr "This request is not for you."
#: app/routes/users.py:983 app/routes/users.py:1024 #: app/routes/users.py:1186 app/routes/users.py:1236
msgid "This request has already been processed." msgid "This request has already been processed."
msgstr "This request has already been processed." msgstr "This request has already been processed."
#: app/routes/users.py:1005 #: app/routes/users.py:1213
#, python-format #, python-format
msgid "One on One request from %(player)s has been approved!" msgid "One on One request from %(player)s has been approved!"
msgstr "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:1014 #: app/routes/users.py:1226
msgid "Only coaches can reject One on One requests." msgid "Only coaches can reject One on One requests."
msgstr "Only coaches can reject One on One requests." msgstr "Only coaches can reject One on One requests."
#: app/routes/users.py:1051 #: app/routes/users.py:1268
#, python-format #, python-format
msgid "One on One request from %(player)s has been rejected." msgid "One on One request from %(player)s has been rejected."
msgstr "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:1064 #: app/routes/users.py:1286
msgid "This page is for players only." msgid "This page is for players only."
msgstr "This page is for players only." msgstr "This page is for players only."
#: app/routes/users.py:1095 #: app/routes/users.py:1328
msgid "Only coaches can manage availability." msgid "Only coaches can manage availability."
msgstr "Only coaches can manage availability." msgstr "Only coaches can manage availability."
#: app/routes/users.py:1157 #: app/routes/users.py:1394
msgid "Only coaches can access the notes dashboard." msgid "Only coaches can access the notes dashboard."
msgstr "Only coaches can access the notes dashboard." msgstr "Only coaches can access the notes dashboard."
#: app/routes/users.py:1221 #: app/routes/users.py:1484
msgid "Only coaches can manage team notes." msgid "Only coaches can manage team notes."
msgstr "Only coaches can manage team notes." msgstr "Only coaches can manage team notes."
#: app/routes/users.py:1227 #: app/routes/users.py:1490
msgid "You are not assigned to a team." msgid "You are not assigned to a team."
msgstr "You are not assigned to a team." msgstr "You are not assigned to a team."
#: app/routes/users.py:1240 #: app/routes/users.py:1503
msgid "Team notes saved successfully!" msgid "Team notes saved successfully!"
msgstr "Team notes saved successfully!" msgstr "Team notes saved successfully!"
#: app/routes/users.py:1254 #: app/routes/users.py:1518
msgid "Only coaches can manage personal notes." msgid "Only coaches can manage personal notes."
msgstr "Only coaches can manage personal notes." msgstr "Only coaches can manage personal notes."
#: app/routes/users.py:1261 app/routes/users.py:1303 app/routes/users.py:1353 #: app/routes/users.py:1525 app/routes/users.py:1568 app/routes/users.py:1619
#: app/routes/users.py:1404 #: app/routes/users.py:1673
msgid "Player and content are required." msgid "Player and content are required."
msgstr "Player and content are required." msgstr "Player and content are required."
#: app/routes/users.py:1270 app/routes/users.py:1312 app/routes/users.py:1357 #: app/routes/users.py:1534 app/routes/users.py:1577 app/routes/users.py:1623
#: app/routes/users.py:1408 #: app/routes/users.py:1677
msgid "You can only write notes about players you work with." msgid "You can only write notes about players you work with."
msgstr "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:1280 app/routes/users.py:1325 #: app/routes/users.py:1544 app/routes/users.py:1590
#, python-format #, python-format
msgid "Note added for %(username)s." msgid "Note added for %(username)s."
msgstr "Note added for %(username)s." msgstr "Note added for %(username)s."
#: app/routes/users.py:1293 app/routes/users.py:1338 app/routes/users.py:1388 #: app/routes/users.py:1558 app/routes/users.py:1604 app/routes/users.py:1657
msgid "Only coaches can add personal notes." msgid "Only coaches can add personal notes."
msgstr "Only coaches can add personal notes." msgstr "Only coaches can add personal notes."
#: app/routes/users.py:1368 app/routes/users.py:1419 #: app/routes/users.py:1634 app/routes/users.py:1688
msgid "Note added successfully." msgid "Note added successfully."
msgstr "Note added successfully." msgstr "Note added successfully."
Binary file not shown.
+182 -174
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: team-tryouts VERSION\n" "Project-Id-Version: team-tryouts VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-08-08 15:07-0400\n" "POT-Creation-Date: 2026-08-08 15:57-0400\n"
"PO-Revision-Date: 2026-08-07 20:22-0400\n" "PO-Revision-Date: 2026-08-07 20:22-0400\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: fr\n" "Language: fr\n"
@@ -19,7 +19,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.18.0\n" "Generated-By: Babel 2.18.0\n"
#: app/validators.py:43 #: app/validators.py:49
msgid "" msgid ""
"Password must be at least 8 characters with uppercase, lowercase, and a " "Password must be at least 8 characters with uppercase, lowercase, and a "
"number." "number."
@@ -27,74 +27,74 @@ msgstr ""
"Le mot de passe doit compter au moins 8 caractères, dont une majuscule, " "Le mot de passe doit compter au moins 8 caractères, dont une majuscule, "
"une minuscule et un chiffre." "une minuscule et un chiffre."
#: app/validators.py:62 #: app/validators.py:67
msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)." msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)."
msgstr "" msgstr ""
"Le nom dutilisateur doit compter de 3 à 30 caractères (lettres, " "Le nom dutilisateur doit compter de 3 à 30 caractères (lettres, "
"chiffres, tiret bas, trait dunion)." "chiffres, tiret bas, trait dunion)."
#: app/validators.py:81 #: app/validators.py:86
msgid "Invalid Discord username format." msgid "Invalid Discord username format."
msgstr "Format de nom dutilisateur Discord invalide." msgstr "Format de nom dutilisateur Discord invalide."
#: app/validators.py:98 #: app/validators.py:103
msgid "Discord User ID must be a 17-20 digit number." msgid "Discord User ID must be a 17-20 digit number."
msgstr "Lidentifiant Discord doit être un nombre de 17 à 20 chiffres." msgstr "Lidentifiant Discord doit être un nombre de 17 à 20 chiffres."
#: app/validators.py:116 #: app/validators.py:121
msgid "Invalid phone number format." msgid "Invalid phone number format."
msgstr "Format de numéro de téléphone invalide." msgstr "Format de numéro de téléphone invalide."
#: app/validators.py:155 #: app/validators.py:163
msgid "Username is required." msgid "Username is required."
msgstr "Le nom dutilisateur est obligatoire." msgstr "Le nom dutilisateur est obligatoire."
#: app/validators.py:159 #: app/validators.py:167
msgid "Password is required." msgid "Password is required."
msgstr "Le mot de passe est obligatoire." msgstr "Le mot de passe est obligatoire."
#: app/validators.py:180 app/validators.py:251 #: app/validators.py:189 app/validators.py:261
msgid "Username must be 3-80 characters." msgid "Username must be 3-80 characters."
msgstr "Le nom dutilisateur doit compter de 3 à 80 caractères." msgstr "Le nom dutilisateur doit compter de 3 à 80 caractères."
#: app/validators.py:186 #: app/validators.py:195
msgid "Email must be 120 characters or less." msgid "Email must be 120 characters or less."
msgstr "Ladresse courriel ne doit pas dépasser 120 caractères." msgstr "Ladresse courriel ne doit pas dépasser 120 caractères."
#: app/validators.py:199 app/validators.py:266 app/validators.py:299 #: app/validators.py:208 app/validators.py:276 app/validators.py:307
#: app/validators.py:365 #: app/validators.py:371
msgid "Full name is required." msgid "Full name is required."
msgstr "Le nom complet est obligatoire." msgstr "Le nom complet est obligatoire."
#: app/validators.py:234 #: app/validators.py:243
msgid "Passwords do not match." msgid "Passwords do not match."
msgstr "Les mots de passe ne concordent pas." msgstr "Les mots de passe ne concordent pas."
#: app/validators.py:272 app/validators.py:309 #: app/validators.py:280 app/validators.py:315
msgid "Invalid role selected." msgid "Invalid role selected."
msgstr "Rôle sélectionné invalide." msgstr "Rôle sélectionné invalide."
#: app/validators.py:409 #: app/validators.py:416
msgid "Player must be selected." msgid "Player must be selected."
msgstr "Vous devez choisir un joueur." msgstr "Vous devez choisir un joueur."
#: app/validators.py:412 #: app/validators.py:419
msgid "Notes must be 2000 characters or less." msgid "Notes must be 2000 characters or less."
msgstr "Les notes ne doivent pas dépasser 2000 caractères." msgstr "Les notes ne doivent pas dépasser 2000 caractères."
#: app/validators.py:431 #: app/validators.py:438
msgid "Date must be in YYYY-MM-DD format." msgid "Date must be in YYYY-MM-DD format."
msgstr "La date doit être au format AAAA-MM-JJ." msgstr "La date doit être au format AAAA-MM-JJ."
#: app/validators.py:438 app/validators.py:473 #: app/validators.py:443 app/validators.py:470
msgid "Start time must be in HH:MM format." msgid "Start time must be in HH:MM format."
msgstr "Lheure de début doit être au format HH:MM." msgstr "Lheure de début doit être au format HH:MM."
#: app/validators.py:445 #: app/validators.py:447
msgid "End time must be in HH:MM format." msgid "End time must be in HH:MM format."
msgstr "Lheure de fin doit être au format HH:MM." msgstr "Lheure de fin doit être au format HH:MM."
#: app/validators.py:449 #: app/validators.py:450
msgid "Points must be 2000 characters or less." msgid "Points must be 2000 characters or less."
msgstr "Les points ne doivent pas dépasser 2000 caractères." msgstr "Les points ne doivent pas dépasser 2000 caractères."
@@ -102,22 +102,22 @@ msgstr "Les points ne doivent pas dépasser 2000 caractères."
msgid "Day must be 0 (Monday) to 6 (Sunday)." msgid "Day must be 0 (Monday) to 6 (Sunday)."
msgstr "Le jour doit aller de 0 (lundi) à 6 (dimanche)." msgstr "Le jour doit aller de 0 (lundi) à 6 (dimanche)."
#: app/routes/auth.py:186 app/routes/auth.py:314 app/routes/users.py:83 #: app/routes/auth.py:186 app/routes/auth.py:322 app/routes/users.py:106
#: app/routes/users.py:687 #: app/routes/users.py:821
#, python-format #, python-format
msgid "%(field)s: %(msg)s" msgid "%(field)s: %(msg)s"
msgstr "%(field)s : %(msg)s" msgstr "%(field)s : %(msg)s"
#: app/routes/auth.py:204 #: app/routes/auth.py:203
msgid "This account has been deactivated." msgid "This account has been deactivated."
msgstr "Ce compte a été désactivé." msgstr "Ce compte a été désactivé."
#: app/routes/auth.py:242 #: app/routes/auth.py:238
#, python-format #, python-format
msgid "Welcome back, %(username)s!" msgid "Welcome back, %(username)s!"
msgstr "Bon retour, %(username)s !" msgstr "Bon retour, %(username)s !"
#: app/routes/auth.py:263 #: app/routes/auth.py:268
msgid "" msgid ""
"Login unsuccessful. Please check your username and password, or ask a " "Login unsuccessful. Please check your username and password, or ask a "
"president for help." "president for help."
@@ -125,27 +125,27 @@ msgstr ""
"Échec de la connexion. Vérifiez le nom dutilisateur et le mot de passe, " "Échec de la connexion. Vérifiez le nom dutilisateur et le mot de passe, "
"ou demandez de laide à un président." "ou demandez de laide à un président."
#: app/routes/auth.py:295 #: app/routes/auth.py:303
msgid "Incorrect CAPTCHA answer. Please try again." msgid "Incorrect CAPTCHA answer. Please try again."
msgstr "Réponse au CAPTCHA incorrecte. Veuillez réessayer." msgstr "Réponse au CAPTCHA incorrecte. Veuillez réessayer."
#: app/routes/auth.py:337 app/routes/users.py:370 #: app/routes/auth.py:345 app/routes/users.py:436
msgid "Username already exists." msgid "Username already exists."
msgstr "Ce nom dutilisateur est déjà pris." msgstr "Ce nom dutilisateur est déjà pris."
#: app/routes/auth.py:349 app/routes/users.py:374 #: app/routes/auth.py:357 app/routes/users.py:440
msgid "Email already registered." msgid "Email already registered."
msgstr "Cette adresse courriel est déjà enregistrée." msgstr "Cette adresse courriel est déjà enregistrée."
#: app/routes/auth.py:395 #: app/routes/auth.py:404
msgid "Your account has been created! You can now log in." msgid "Your account has been created! You can now log in."
msgstr "Votre compte a été créé. Vous pouvez maintenant vous connecter." msgstr "Votre compte a été créé. Vous pouvez maintenant vous connecter."
#: app/routes/auth.py:421 #: app/routes/auth.py:430
msgid "Discord OAuth2 is not configured." msgid "Discord OAuth2 is not configured."
msgstr "La connexion Discord nest pas configurée." msgstr "La connexion Discord nest pas configurée."
#: app/routes/auth.py:461 #: app/routes/auth.py:471
msgid "" msgid ""
"Discord authorization could not be verified. Please start the connection " "Discord authorization could not be verified. Please start the connection "
"again from this page." "again from this page."
@@ -153,414 +153,422 @@ msgstr ""
"Lautorisation Discord na pas pu être vérifiée. Relancez la connexion " "Lautorisation Discord na pas pu être vérifiée. Relancez la connexion "
"depuis cette page." "depuis cette page."
#: app/routes/auth.py:469 #: app/routes/auth.py:480
msgid "Discord authorization failed. No code received." msgid "Discord authorization failed. No code received."
msgstr "Lautorisation Discord a échoué : aucun code reçu." msgstr "Lautorisation Discord a échoué : aucun code reçu."
#: app/routes/auth.py:493 #: app/routes/auth.py:504
msgid "Failed to connect to Discord. Please try again." msgid "Failed to connect to Discord. Please try again."
msgstr "Impossible de joindre Discord. Veuillez réessayer." msgstr "Impossible de joindre Discord. Veuillez réessayer."
#: app/routes/auth.py:497 #: app/routes/auth.py:508
msgid "Failed to obtain Discord access token." msgid "Failed to obtain Discord access token."
msgstr "Impossible dobtenir le jeton daccès Discord." msgstr "Impossible dobtenir le jeton daccès Discord."
#: app/routes/auth.py:512 #: app/routes/auth.py:523
msgid "Failed to fetch Discord user profile." msgid "Failed to fetch Discord user profile."
msgstr "Impossible de récupérer le profil Discord." msgstr "Impossible de récupérer le profil Discord."
#: app/routes/auth.py:559 #: app/routes/auth.py:570
msgid "Discord account connected! Your profile has been pre-filled." msgid "Discord account connected! Your profile has been pre-filled."
msgstr "Compte Discord connecté. Votre profil a été pré-rempli." msgstr "Compte Discord connecté. Votre profil a été pré-rempli."
#: app/routes/auth.py:587 #: app/routes/auth.py:598
msgid "You have been logged out." msgid "You have been logged out."
msgstr "Vous avez été déconnecté." msgstr "Vous avez été déconnecté."
#: app/routes/evaluations.py:41 #: app/routes/evaluations.py:45
msgid "You do not have permission to view evaluations." msgid "You do not have permission to view evaluations."
msgstr "Vous navez pas les droits pour consulter les évaluations." msgstr "Vous navez pas les droits pour consulter les évaluations."
#: app/routes/evaluations.py:122 #: app/routes/evaluations.py:135
msgid "You do not have permission to evaluate players." msgid "You do not have permission to evaluate players."
msgstr "Vous navez pas les droits pour évaluer des joueurs." msgstr "Vous navez pas les droits pour évaluer des joueurs."
#: app/routes/evaluations.py:127 app/routes/evaluations.py:220 #: app/routes/evaluations.py:140 app/routes/evaluations.py:263
msgid "You do not have permission to evaluate players in this tryout." msgid "You do not have permission to evaluate players in this tryout."
msgstr "Vous navez pas les droits pour évaluer des joueurs dans cette sélection." msgstr "Vous navez pas les droits pour évaluer des joueurs dans cette sélection."
#: app/routes/evaluations.py:134 #: app/routes/evaluations.py:151
msgid "Player is not registered for this tryout." msgid "Player is not registered for this tryout."
msgstr "Ce joueur nest pas inscrit à cette sélection." msgstr "Ce joueur nest pas inscrit à cette sélection."
#: app/routes/evaluations.py:139 #: app/routes/evaluations.py:156
msgid "Can only evaluate players." msgid "Can only evaluate players."
msgstr "Seuls des joueurs peuvent être évalués." msgstr "Seuls des joueurs peuvent être évalués."
#: app/routes/evaluations.py:177 #: app/routes/evaluations.py:208
msgid "Evaluation updated!" msgid "Evaluation updated!"
msgstr "Évaluation mise à jour." msgstr "Évaluation mise à jour."
#: app/routes/evaluations.py:190 #: app/routes/evaluations.py:228
msgid "Evaluation submitted successfully!" msgid "Evaluation submitted successfully!"
msgstr "Évaluation enregistrée." msgstr "Évaluation enregistrée."
#: app/routes/evaluations.py:215 app/routes/teams.py:236 #: app/routes/evaluations.py:258 app/routes/teams.py:268
#: app/routes/teams.py:267 app/routes/teams.py:298 app/routes/teams.py:323 #: app/routes/teams.py:309 app/routes/teams.py:350 app/routes/teams.py:375
#: app/routes/teams.py:348 app/routes/teams.py:380 app/routes/tryouts.py:341 #: app/routes/teams.py:400 app/routes/teams.py:435 app/routes/tryouts.py:472
#: app/routes/tryouts.py:357 app/routes/tryouts.py:376 #: app/routes/tryouts.py:488 app/routes/tryouts.py:508
#: app/routes/tryouts.py:413 app/routes/tryouts.py:448 #: app/routes/tryouts.py:547 app/routes/tryouts.py:583
#: app/routes/tryouts.py:467 #: app/routes/tryouts.py:602
msgid "Permission denied." msgid "Permission denied."
msgstr "Accès refusé." msgstr "Accès refusé."
#: app/routes/main.py:44 #: app/routes/main.py:53
msgid "That language is not available." msgid "That language is not available."
msgstr "Cette langue nest pas disponible." msgstr "Cette langue nest pas disponible."
#: app/routes/matches.py:201 #: app/routes/matches.py:245
msgid "You do not have permission to schedule matches for this tryout." msgid "You do not have permission to schedule matches for this tryout."
msgstr "Vous navez pas les droits pour planifier des matchs pour cette sélection." msgstr "Vous navez pas les droits pour planifier des matchs pour cette sélection."
#: app/routes/matches.py:205 app/routes/matches.py:336 #: app/routes/matches.py:249 app/routes/matches.py:422
msgid "This tryout has ended. Matches can no longer be created or modified." msgid "This tryout has ended. Matches can no longer be created or modified."
msgstr "" msgstr ""
"Cette sélection est terminée. Les matchs ne peuvent plus être créés ni " "Cette sélection est terminée. Les matchs ne peuvent plus être créés ni "
"modifiés." "modifiés."
#: app/routes/matches.py:224 #: app/routes/matches.py:270
msgid "Start time is required. Please select a time slot." msgid "Start time is required. Please select a time slot."
msgstr "Lheure de début est obligatoire. Choisissez une plage horaire." msgstr "Lheure de début est obligatoire. Choisissez une plage horaire."
#: app/routes/matches.py:231 app/routes/matches.py:359 #: app/routes/matches.py:282 app/routes/matches.py:445
#: app/routes/team_matches.py:123 app/routes/team_matches.py:206 #: app/routes/team_matches.py:151 app/routes/team_matches.py:255
msgid "Invalid date format." msgid "Invalid date format."
msgstr "Format de date invalide." msgstr "Format de date invalide."
#: app/routes/matches.py:246 app/routes/team_matches.py:140 #: app/routes/matches.py:302 app/routes/team_matches.py:172
msgid "Invalid time format." msgid "Invalid time format."
msgstr "Format dheure invalide." msgstr "Format dheure invalide."
#: app/routes/matches.py:317 #: app/routes/matches.py:398
msgid "Match scheduled successfully!" msgid "Match scheduled successfully!"
msgstr "Match planifié." msgstr "Match planifié."
#: app/routes/matches.py:332 app/routes/team_matches.py:193 #: app/routes/matches.py:418 app/routes/team_matches.py:242
msgid "You do not have permission to edit this match." msgid "You do not have permission to edit this match."
msgstr "Vous navez pas les droits pour modifier ce match." msgstr "Vous navez pas les droits pour modifier ce match."
#: app/routes/matches.py:365 #: app/routes/matches.py:456
msgid "Start time is required." msgid "Start time is required."
msgstr "Lheure de début est obligatoire." msgstr "Lheure de début est obligatoire."
#: app/routes/matches.py:461 app/routes/team_matches.py:229 #: app/routes/matches.py:578 app/routes/team_matches.py:284
msgid "Match updated successfully!" msgid "Match updated successfully!"
msgstr "Match mis à jour." msgstr "Match mis à jour."
#: app/routes/matches.py:506 app/routes/team_matches.py:243 #: app/routes/matches.py:631 app/routes/team_matches.py:299
msgid "You do not have permission to delete this match." msgid "You do not have permission to delete this match."
msgstr "Vous navez pas les droits pour supprimer ce match." msgstr "Vous navez pas les droits pour supprimer ce match."
#: app/routes/matches.py:509 #: app/routes/matches.py:634
msgid "This tryout has ended. Matches can no longer be deleted." msgid "This tryout has ended. Matches can no longer be deleted."
msgstr "Cette sélection est terminée. Les matchs ne peuvent plus être supprimés." msgstr "Cette sélection est terminée. Les matchs ne peuvent plus être supprimés."
#: app/routes/matches.py:521 app/routes/team_matches.py:247 #: app/routes/matches.py:647 app/routes/team_matches.py:303
msgid "Match deleted successfully." msgid "Match deleted successfully."
msgstr "Match supprimé." msgstr "Match supprimé."
#: app/routes/team_matches.py:81 #: app/routes/team_matches.py:98
msgid "You do not have permission to schedule matches for this team." msgid "You do not have permission to schedule matches for this team."
msgstr "Vous navez pas les droits pour planifier des matchs pour cette équipe." msgstr "Vous navez pas les droits pour planifier des matchs pour cette équipe."
#: app/routes/team_matches.py:116 #: app/routes/team_matches.py:140
msgid "Date is required." msgid "Date is required."
msgstr "La date est obligatoire." msgstr "La date est obligatoire."
#: app/routes/team_matches.py:179 #: app/routes/team_matches.py:228
#, python-format #, python-format
msgid "Team match \"%(title)s\" scheduled successfully!" msgid "Team match \"%(title)s\" scheduled successfully!"
msgstr "Match d’équipe « %(title)s » planifié." msgstr "Match d’équipe « %(title)s » planifié."
#: app/routes/teams.py:28 #: app/routes/team_matches.py:267
msgid "Invalid start time format."
msgstr "Format dheure de début invalide."
#: app/routes/team_matches.py:275
msgid "Invalid end time format."
msgstr "Format dheure de fin invalide."
#: app/routes/teams.py:38
msgid "Use My Team(s) to view your teams." msgid "Use My Team(s) to view your teams."
msgstr "Utilisez « Mon ou mes équipes » pour consulter vos équipes." msgstr "Utilisez « Mon ou mes équipes » pour consulter vos équipes."
#: app/routes/teams.py:31 #: app/routes/teams.py:41
msgid "You do not have permission to view teams." msgid "You do not have permission to view teams."
msgstr "Vous navez pas les droits pour consulter les équipes." msgstr "Vous navez pas les droits pour consulter les équipes."
#: app/routes/teams.py:48 #: app/routes/teams.py:68
msgid "This page is for players." msgid "This page is for players."
msgstr "Cette page est réservée aux joueurs." msgstr "Cette page est réservée aux joueurs."
#: app/routes/teams.py:90 #: app/routes/teams.py:121
msgid "You do not have permission to create teams." msgid "You do not have permission to create teams."
msgstr "Vous navez pas les droits pour créer une équipe." msgstr "Vous navez pas les droits pour créer une équipe."
#: app/routes/teams.py:98 app/routes/teams.py:143 #: app/routes/teams.py:129 app/routes/teams.py:174
msgid "Team name is required." msgid "Team name is required."
msgstr "Le nom de l’équipe est obligatoire." msgstr "Le nom de l’équipe est obligatoire."
#: app/routes/teams.py:103 app/routes/teams.py:148 #: app/routes/teams.py:134 app/routes/teams.py:179
#, python-format #, python-format
msgid "Team \"%(name)s\" already exists." msgid "Team \"%(name)s\" already exists."
msgstr "L’équipe « %(name)s » existe déjà." msgstr "L’équipe « %(name)s » existe déjà."
#: app/routes/teams.py:125 #: app/routes/teams.py:156
#, python-format #, python-format
msgid "Team \"%(name)s\" created successfully!" msgid "Team \"%(name)s\" created successfully!"
msgstr "Équipe « %(name)s » créée." msgstr "Équipe « %(name)s » créée."
#: app/routes/teams.py:135 #: app/routes/teams.py:166
msgid "You do not have permission to edit this team." msgid "You do not have permission to edit this team."
msgstr "Vous navez pas les droits pour modifier cette équipe." msgstr "Vous navez pas les droits pour modifier cette équipe."
#: app/routes/teams.py:186 #: app/routes/teams.py:217
#, python-format #, python-format
msgid "Team \"%(name)s\" updated successfully!" msgid "Team \"%(name)s\" updated successfully!"
msgstr "Équipe « %(name)s » mise à jour." msgstr "Équipe « %(name)s » mise à jour."
#: app/routes/teams.py:195 #: app/routes/teams.py:226
msgid "You do not have permission to delete teams." msgid "You do not have permission to delete teams."
msgstr "Vous navez pas les droits pour supprimer une équipe." msgstr "Vous navez pas les droits pour supprimer une équipe."
#: app/routes/teams.py:226 #: app/routes/teams.py:258
#, python-format #, python-format
msgid "Team \"%(name)s\" deleted successfully." msgid "Team \"%(name)s\" deleted successfully."
msgstr "Équipe « %(name)s » supprimée." msgstr "Équipe « %(name)s » supprimée."
#: app/routes/teams.py:241 #: app/routes/teams.py:273
msgid "Please select a coach." msgid "Please select a coach."
msgstr "Veuillez choisir un coach." msgstr "Veuillez choisir un coach."
#: app/routes/teams.py:246 #: app/routes/teams.py:278
msgid "Only coaches can be assigned as coach." msgid "Only coaches can be assigned as coach."
msgstr "Seuls les coachs peuvent être assignés comme coach." msgstr "Seuls les coachs peuvent être assignés comme coach."
#: app/routes/teams.py:250 #: app/routes/teams.py:284
#, python-format #, python-format
msgid "%(username)s is already a coach of %(name)s." msgid "%(username)s is already a coach of %(name)s."
msgstr "%(username)s est déjà coach de %(name)s." msgstr "%(username)s est déjà coach de %(name)s."
#: app/routes/teams.py:257 #: app/routes/teams.py:297
#, python-format #, python-format
msgid "%(username)s added as coach of %(name)s." msgid "%(username)s added as coach of %(name)s."
msgstr "%(username)s a été ajouté comme coach de %(name)s." msgstr "%(username)s a été ajouté comme coach de %(name)s."
#: app/routes/teams.py:272 #: app/routes/teams.py:314
msgid "Please select a manager." msgid "Please select a manager."
msgstr "Veuillez choisir un gérant." msgstr "Veuillez choisir un gérant."
#: app/routes/teams.py:277 #: app/routes/teams.py:319
msgid "Only managers can be assigned as manager." msgid "Only managers can be assigned as manager."
msgstr "Seuls les gérants peuvent être assignés comme gérant." msgstr "Seuls les gérants peuvent être assignés comme gérant."
#: app/routes/teams.py:281 #: app/routes/teams.py:325
#, python-format #, python-format
msgid "%(username)s is already a manager of %(name)s." msgid "%(username)s is already a manager of %(name)s."
msgstr "%(username)s est déjà gérant de %(name)s." msgstr "%(username)s est déjà gérant de %(name)s."
#: app/routes/teams.py:288 #: app/routes/teams.py:338
#, python-format #, python-format
msgid "%(username)s added as manager of %(name)s." msgid "%(username)s added as manager of %(name)s."
msgstr "%(username)s a été ajouté comme gérant de %(name)s." msgstr "%(username)s a été ajouté comme gérant de %(name)s."
#: app/routes/teams.py:313 #: app/routes/teams.py:365
#, python-format #, python-format
msgid "Coach removed from %(name)s." msgid "Coach removed from %(name)s."
msgstr "Coach retiré de %(name)s." msgstr "Coach retiré de %(name)s."
#: app/routes/teams.py:338 #: app/routes/teams.py:390
#, python-format #, python-format
msgid "Manager removed from %(name)s." msgid "Manager removed from %(name)s."
msgstr "Gérant retiré de %(name)s." msgstr "Gérant retiré de %(name)s."
#: app/routes/teams.py:354 app/routes/tryouts.py:380 app/routes/tryouts.py:478 #: app/routes/teams.py:406 app/routes/tryouts.py:512 app/routes/tryouts.py:613
msgid "Please select a player." msgid "Please select a player."
msgstr "Veuillez choisir un joueur." msgstr "Veuillez choisir un joueur."
#: app/routes/teams.py:359 #: app/routes/teams.py:411
msgid "Can only assign players to teams." msgid "Can only assign players to teams."
msgstr "Seuls des joueurs peuvent être assignés à une équipe." msgstr "Seuls des joueurs peuvent être assignés à une équipe."
#: app/routes/teams.py:364 #: app/routes/teams.py:417
#, python-format #, python-format
msgid "%(username)s is already on %(name)s." msgid "%(username)s is already on %(name)s."
msgstr "%(username)s fait déjà partie de %(name)s." msgstr "%(username)s fait déjà partie de %(name)s."
#: app/routes/teams.py:370 #: app/routes/teams.py:425
#, python-format #, python-format
msgid "%(username)s added to %(name)s!" msgid "%(username)s added to %(name)s!"
msgstr "%(username)s a été ajouté à %(name)s." msgstr "%(username)s a été ajouté à %(name)s."
#: app/routes/teams.py:386 app/routes/teams.py:449 #: app/routes/teams.py:442 app/routes/teams.py:515
#, python-format #, python-format
msgid "%(username)s is not on %(name)s." msgid "%(username)s is not on %(name)s."
msgstr "%(username)s ne fait pas partie de %(name)s." msgstr "%(username)s ne fait pas partie de %(name)s."
#: app/routes/teams.py:391 #: app/routes/teams.py:450
#, python-format #, python-format
msgid "%(username)s removed from %(name)s." msgid "%(username)s removed from %(name)s."
msgstr "%(username)s a été retiré de %(name)s." msgstr "%(username)s a été retiré de %(name)s."
#: app/routes/teams.py:421 app/routes/teams.py:439 #: app/routes/teams.py:486 app/routes/teams.py:504
msgid "You do not have permission to add notes to this team." msgid "You do not have permission to add notes to this team."
msgstr "Vous navez pas les droits pour ajouter des notes à cette équipe." msgstr "Vous navez pas les droits pour ajouter des notes à cette équipe."
#: app/routes/teams.py:429 #: app/routes/teams.py:494
msgid "Team notes added successfully!" msgid "Team notes added successfully!"
msgstr "Notes d’équipe ajoutées." msgstr "Notes d’équipe ajoutées."
#: app/routes/teams.py:444 app/routes/users.py:1266 app/routes/users.py:1308 #: app/routes/teams.py:509 app/routes/users.py:1530 app/routes/users.py:1573
msgid "Can only add notes for players." msgid "Can only add notes for players."
msgstr "Il nest possible dajouter des notes que pour des joueurs." msgstr "Il nest possible dajouter des notes que pour des joueurs."
#: app/routes/teams.py:457 #: app/routes/teams.py:525
#, python-format #, python-format
msgid "Note added for %(username)s!" msgid "Note added for %(username)s!"
msgstr "Note ajoutée pour %(username)s." msgstr "Note ajoutée pour %(username)s."
#: app/routes/tryouts.py:43 #: app/routes/tryouts.py:56
msgid "You do not have permission to create tryouts." msgid "You do not have permission to create tryouts."
msgstr "Vous navez pas les droits pour créer une sélection." msgstr "Vous navez pas les droits pour créer une sélection."
#: app/routes/tryouts.py:65 app/routes/tryouts.py:140 #: app/routes/tryouts.py:82 app/routes/tryouts.py:189
msgid "Invalid start date format." msgid "Invalid start date format."
msgstr "Format de date de début invalide." msgstr "Format de date de début invalide."
#: app/routes/tryouts.py:74 app/routes/tryouts.py:149 #: app/routes/tryouts.py:97 app/routes/tryouts.py:204
msgid "End date cannot be before start date." msgid "End date cannot be before start date."
msgstr "La date de fin ne peut pas précéder la date de début." msgstr "La date de fin ne peut pas précéder la date de début."
#: app/routes/tryouts.py:78 app/routes/tryouts.py:153 #: app/routes/tryouts.py:107 app/routes/tryouts.py:214
msgid "Invalid end date format." msgid "Invalid end date format."
msgstr "Format de date de fin invalide." msgstr "Format de date de fin invalide."
#: app/routes/tryouts.py:100 #: app/routes/tryouts.py:139
msgid "Tryout created successfully!" msgid "Tryout created successfully!"
msgstr "Sélection créée." msgstr "Sélection créée."
#: app/routes/tryouts.py:114 #: app/routes/tryouts.py:159
msgid "You do not have permission to edit this tryout." msgid "You do not have permission to edit this tryout."
msgstr "Vous navez pas les droits pour modifier cette sélection." msgstr "Vous navez pas les droits pour modifier cette sélection."
#: app/routes/tryouts.py:118 #: app/routes/tryouts.py:163
msgid "This tryout has ended and can no longer be modified." msgid "This tryout has ended and can no longer be modified."
msgstr "Cette sélection est terminée et ne peut plus être modifiée." msgstr "Cette sélection est terminée et ne peut plus être modifiée."
#: app/routes/tryouts.py:175 #: app/routes/tryouts.py:242
msgid "Tryout updated successfully!" msgid "Tryout updated successfully!"
msgstr "Sélection mise à jour." msgstr "Sélection mise à jour."
#: app/routes/tryouts.py:207 #: app/routes/tryouts.py:289
msgid "You do not have permission to view this tryout." msgid "You do not have permission to view this tryout."
msgstr "Vous navez pas les droits pour consulter cette sélection." msgstr "Vous navez pas les droits pour consulter cette sélection."
#: app/routes/tryouts.py:309 #: app/routes/tryouts.py:439
msgid "Only players can register for tryouts." msgid "Only players can register for tryouts."
msgstr "Seuls les joueurs peuvent sinscrire à une sélection." msgstr "Seuls les joueurs peuvent sinscrire à une sélection."
#: app/routes/tryouts.py:313 #: app/routes/tryouts.py:443
msgid "This tryout is not accepting registrations." msgid "This tryout is not accepting registrations."
msgstr "Cette sélection naccepte pas dinscriptions." msgstr "Cette sélection naccepte pas dinscriptions."
#: app/routes/tryouts.py:319 #: app/routes/tryouts.py:450
msgid "You are already registered for this tryout." msgid "You are already registered for this tryout."
msgstr "Vous êtes déjà inscrit à cette sélection." msgstr "Vous êtes déjà inscrit à cette sélection."
#: app/routes/tryouts.py:325 app/routes/tryouts.py:397 #: app/routes/tryouts.py:456 app/routes/tryouts.py:531
msgid "This tryout is full." msgid "This tryout is full."
msgstr "Cette sélection est complète." msgstr "Cette sélection est complète."
#: app/routes/tryouts.py:331 #: app/routes/tryouts.py:462
msgid "Successfully registered for tryout!" msgid "Successfully registered for tryout!"
msgstr "Inscription à la sélection réussie." msgstr "Inscription à la sélection réussie."
#: app/routes/tryouts.py:347 #: app/routes/tryouts.py:478
#, python-format #, python-format
msgid "Tryout status updated to %(new_status)s." msgid "Tryout status updated to %(new_status)s."
msgstr "Statut de la sélection mis à jour : %(new_status)s." msgstr "Statut de la sélection mis à jour : %(new_status)s."
#: app/routes/tryouts.py:366 #: app/routes/tryouts.py:498
msgid "Registration status updated." msgid "Registration status updated."
msgstr "Statut dinscription mis à jour." msgstr "Statut dinscription mis à jour."
#: app/routes/tryouts.py:385 #: app/routes/tryouts.py:517
msgid "Can only register players." msgid "Can only register players."
msgstr "Seuls des joueurs peuvent être inscrits." msgstr "Seuls des joueurs peuvent être inscrits."
#: app/routes/tryouts.py:391 #: app/routes/tryouts.py:523
#, python-format #, python-format
msgid "%(username)s is already registered for this tryout." msgid "%(username)s is already registered for this tryout."
msgstr "%(username)s est déjà inscrit à cette sélection." msgstr "%(username)s est déjà inscrit à cette sélection."
#: app/routes/tryouts.py:403 #: app/routes/tryouts.py:537
#, python-format #, python-format
msgid "%(username)s registered for tryout!" msgid "%(username)s registered for tryout!"
msgstr "%(username)s est inscrit à la sélection." msgstr "%(username)s est inscrit à la sélection."
#: app/routes/tryouts.py:438 #: app/routes/tryouts.py:573
#, python-format #, python-format
msgid "%(username)s removed from tryout." msgid "%(username)s removed from tryout."
msgstr "%(username)s a été retiré de la sélection." msgstr "%(username)s a été retiré de la sélection."
#: app/routes/tryouts.py:456 #: app/routes/tryouts.py:591
#, python-format #, python-format
msgid "Team \"%(team_name)s\" created!" msgid "Team \"%(team_name)s\" created!"
msgstr "Équipe « %(team_name)s » créée." msgstr "Équipe « %(team_name)s » créée."
#: app/routes/tryouts.py:485 #: app/routes/tryouts.py:622
msgid "That player is not registered for this tryout." msgid "That player is not registered for this tryout."
msgstr "Ce joueur nest pas inscrit à cette sélection." msgstr "Ce joueur nest pas inscrit à cette sélection."
#: app/routes/tryouts.py:491 #: app/routes/tryouts.py:628
msgid "Player is already on this team." msgid "Player is already on this team."
msgstr "Ce joueur est déjà dans cette équipe." msgstr "Ce joueur est déjà dans cette équipe."
#: app/routes/tryouts.py:496 #: app/routes/tryouts.py:633
msgid "Player added to team!" msgid "Player added to team!"
msgstr "Joueur ajouté à l’équipe." msgstr "Joueur ajouté à l’équipe."
#: app/routes/tryouts.py:506 #: app/routes/tryouts.py:643
msgid "You do not have permission to delete this tryout." msgid "You do not have permission to delete this tryout."
msgstr "Vous navez pas les droits pour supprimer cette sélection." msgstr "Vous navez pas les droits pour supprimer cette sélection."
#: app/routes/tryouts.py:541 #: app/routes/tryouts.py:679
msgid "Tryout deleted successfully." msgid "Tryout deleted successfully."
msgstr "Sélection supprimée." msgstr "Sélection supprimée."
#: app/routes/users.py:61 #: app/routes/users.py:83
msgid "No file selected." msgid "No file selected."
msgstr "Aucun fichier sélectionné." msgstr "Aucun fichier sélectionné."
#: app/routes/users.py:65 #: app/routes/users.py:87
msgid "Only PDF files are allowed for contracts." msgid "Only PDF files are allowed for contracts."
msgstr "Seuls les fichiers PDF sont acceptés pour les contrats." msgstr "Seuls les fichiers PDF sont acceptés pour les contrats."
#: app/routes/users.py:70 #: app/routes/users.py:92
msgid "That file is not a PDF, whatever its name says." msgid "That file is not a PDF, whatever its name says."
msgstr "Ce fichier nest pas un PDF, quel que soit son nom." msgstr "Ce fichier nest pas un PDF, quel que soit son nom."
#: app/routes/users.py:153 #: app/routes/users.py:181
msgid "Only the president can manage users." msgid "Only the president can manage users."
msgstr "Seul le président peut gérer les utilisateurs." msgstr "Seul le président peut gérer les utilisateurs."
#: app/routes/users.py:165 #: app/routes/users.py:193
msgid "Only the president can edit users." msgid "Only the president can edit users."
msgstr "Seul le président peut modifier des utilisateurs." msgstr "Seul le président peut modifier des utilisateurs."
#: app/routes/users.py:202 #: app/routes/users.py:234
msgid "Email already in use by another account." msgid "Email already in use by another account."
msgstr "Cette adresse courriel est déjà utilisée par un autre compte." msgstr "Cette adresse courriel est déjà utilisée par un autre compte."
#: app/routes/users.py:212 #: app/routes/users.py:245
msgid "You cannot change your own role. Ask another president to do it." msgid "You cannot change your own role. Ask another president to do it."
msgstr "" msgstr ""
"Vous ne pouvez pas modifier votre propre rôle. Demandez à un autre " "Vous ne pouvez pas modifier votre propre rôle. Demandez à un autre "
"président de le faire." "président de le faire."
#: app/routes/users.py:223 #: app/routes/users.py:258
msgid "" msgid ""
"This is the last active president. Promote another account before " "This is the last active president. Promote another account before "
"changing this one." "changing this one."
@@ -568,174 +576,174 @@ msgstr ""
"Cest le dernier président actif. Promouvez un autre compte avant de " "Cest le dernier président actif. Promouvez un autre compte avant de "
"modifier celui-ci." "modifier celui-ci."
#: app/routes/users.py:285 #: app/routes/users.py:337
#, python-format #, python-format
msgid "User %(username)s updated successfully!" msgid "User %(username)s updated successfully!"
msgstr "Utilisateur %(username)s mis à jour." msgstr "Utilisateur %(username)s mis à jour."
#: app/routes/users.py:300 #: app/routes/users.py:358
msgid "Only the president can delete users." msgid "Only the president can delete users."
msgstr "Seul le président peut supprimer des utilisateurs." msgstr "Seul le président peut supprimer des utilisateurs."
#: app/routes/users.py:304 #: app/routes/users.py:362
msgid "You cannot delete your own account." msgid "You cannot delete your own account."
msgstr "Vous ne pouvez pas supprimer votre propre compte." msgstr "Vous ne pouvez pas supprimer votre propre compte."
#: app/routes/users.py:341 #: app/routes/users.py:405
#, python-format #, python-format
msgid "User %(deleted_username)s has been removed." msgid "User %(deleted_username)s has been removed."
msgstr "Lutilisateur %(deleted_username)s a été supprimé." msgstr "Lutilisateur %(deleted_username)s a été supprimé."
#: app/routes/users.py:350 #: app/routes/users.py:416
msgid "Only the president can create users." msgid "Only the president can create users."
msgstr "Seul le président peut créer des utilisateurs." msgstr "Seul le président peut créer des utilisateurs."
#: app/routes/users.py:389 #: app/routes/users.py:464
#, python-format #, python-format
msgid "User %(full_name)s created as %(role)s!" msgid "User %(full_name)s created as %(role)s!"
msgstr "Utilisateur %(full_name)s créé avec le rôle %(role)s." msgstr "Utilisateur %(full_name)s créé avec le rôle %(role)s."
#: app/routes/users.py:446 #: app/routes/users.py:534
msgid "Username already taken." msgid "Username already taken."
msgstr "Ce nom dutilisateur est déjà pris." msgstr "Ce nom dutilisateur est déjà pris."
#: app/routes/users.py:452 #: app/routes/users.py:544
msgid "Email already in use." msgid "Email already in use."
msgstr "Cette adresse courriel est déjà utilisée." msgstr "Cette adresse courriel est déjà utilisée."
#: app/routes/users.py:477 #: app/routes/users.py:574
msgid "Profile updated successfully!" msgid "Profile updated successfully!"
msgstr "Profil mis à jour." msgstr "Profil mis à jour."
#: app/routes/users.py:675 #: app/routes/users.py:809
msgid "Only presidents, managers, and coaches can upload contracts." msgid "Only presidents, managers, and coaches can upload contracts."
msgstr "Seuls les présidents, gérants et coachs peuvent téléverser un contrat." msgstr "Seuls les présidents, gérants et coachs peuvent téléverser un contrat."
#: app/routes/users.py:694 #: app/routes/users.py:828
msgid "You do not have permission to upload a contract for this player." msgid "You do not have permission to upload a contract for this player."
msgstr "Vous navez pas les droits pour téléverser un contrat pour ce joueur." msgstr "Vous navez pas les droits pour téléverser un contrat pour ce joueur."
#: app/routes/users.py:733 #: app/routes/users.py:869
#, python-format #, python-format
msgid "Contract uploaded successfully for %(username)s!" msgid "Contract uploaded successfully for %(username)s!"
msgstr "Contrat téléversé pour %(username)s." msgstr "Contrat téléversé pour %(username)s."
#: app/routes/users.py:745 #: app/routes/users.py:883
msgid "Only the player can upload their signed contract." msgid "Only the player can upload their signed contract."
msgstr "Seul le joueur peut téléverser son contrat signé." msgstr "Seul le joueur peut téléverser son contrat signé."
#: app/routes/users.py:762 #: app/routes/users.py:902
msgid "Signed contract uploaded successfully!" msgid "Signed contract uploaded successfully!"
msgstr "Contrat signé téléversé." msgstr "Contrat signé téléversé."
#: app/routes/users.py:772 app/routes/users.py:783 #: app/routes/users.py:912 app/routes/users.py:925
msgid "You do not have permission to download this contract." msgid "You do not have permission to download this contract."
msgstr "Vous navez pas les droits pour télécharger ce contrat." msgstr "Vous navez pas les droits pour télécharger ce contrat."
#: app/routes/users.py:786 #: app/routes/users.py:928
msgid "No signed contract available." msgid "No signed contract available."
msgstr "Aucun contrat signé disponible." msgstr "Aucun contrat signé disponible."
#: app/routes/users.py:853 #: app/routes/users.py:1034
msgid "Only players can request One on One sessions." msgid "Only players can request One on One sessions."
msgstr "Seuls les joueurs peuvent demander une rencontre individuelle." msgstr "Seuls les joueurs peuvent demander une rencontre individuelle."
#: app/routes/users.py:866 #: app/routes/users.py:1047
msgid "You do not have a coach assigned to your team." msgid "You do not have a coach assigned to your team."
msgstr "Aucun coach nest assigné à votre équipe." msgstr "Aucun coach nest assigné à votre équipe."
#: app/routes/users.py:893 #: app/routes/users.py:1082
msgid "Cannot request One on One - no coach assigned." msgid "Cannot request One on One - no coach assigned."
msgstr "Impossible de demander une rencontre : aucun coach assigné." msgstr "Impossible de demander une rencontre : aucun coach assigné."
#: app/routes/users.py:901 #: app/routes/users.py:1090
msgid "Invalid date or time format." msgid "Invalid date or time format."
msgstr "Format de date ou dheure invalide." msgstr "Format de date ou dheure invalide."
#: app/routes/users.py:915 #: app/routes/users.py:1104
msgid "The requested time is not within the coach's availability." msgid "The requested time is not within the coach's availability."
msgstr "Lhoraire demandé ne correspond à aucune disponibilité du coach." msgstr "Lhoraire demandé ne correspond à aucune disponibilité du coach."
#: app/routes/users.py:938 #: app/routes/users.py:1132
msgid "Your One on One request has been submitted!" msgid "Your One on One request has been submitted!"
msgstr "Votre demande de rencontre a été envoyée." msgstr "Votre demande de rencontre a été envoyée."
#: app/routes/users.py:973 #: app/routes/users.py:1176
msgid "Only coaches can accept One on One requests." msgid "Only coaches can accept One on One requests."
msgstr "Seuls les coachs peuvent accepter une demande de rencontre." msgstr "Seuls les coachs peuvent accepter une demande de rencontre."
#: app/routes/users.py:979 app/routes/users.py:1020 #: app/routes/users.py:1182 app/routes/users.py:1232
msgid "This request is not for you." msgid "This request is not for you."
msgstr "Cette demande ne vous est pas destinée." msgstr "Cette demande ne vous est pas destinée."
#: app/routes/users.py:983 app/routes/users.py:1024 #: app/routes/users.py:1186 app/routes/users.py:1236
msgid "This request has already been processed." msgid "This request has already been processed."
msgstr "Cette demande a déjà été traitée." msgstr "Cette demande a déjà été traitée."
#: app/routes/users.py:1005 #: app/routes/users.py:1213
#, python-format #, python-format
msgid "One on One request from %(player)s has been approved!" msgid "One on One request from %(player)s has been approved!"
msgstr "La demande de rencontre de %(player)s a été approuvée." msgstr "La demande de rencontre de %(player)s a été approuvée."
#: app/routes/users.py:1014 #: app/routes/users.py:1226
msgid "Only coaches can reject One on One requests." msgid "Only coaches can reject One on One requests."
msgstr "Seuls les coachs peuvent refuser une demande de rencontre." msgstr "Seuls les coachs peuvent refuser une demande de rencontre."
#: app/routes/users.py:1051 #: app/routes/users.py:1268
#, python-format #, python-format
msgid "One on One request from %(player)s has been rejected." msgid "One on One request from %(player)s has been rejected."
msgstr "La demande de rencontre de %(player)s a été refusée." msgstr "La demande de rencontre de %(player)s a été refusée."
#: app/routes/users.py:1064 #: app/routes/users.py:1286
msgid "This page is for players only." msgid "This page is for players only."
msgstr "Cette page est réservée aux joueurs." msgstr "Cette page est réservée aux joueurs."
#: app/routes/users.py:1095 #: app/routes/users.py:1328
msgid "Only coaches can manage availability." msgid "Only coaches can manage availability."
msgstr "Seuls les coachs peuvent gérer leurs disponibilités." msgstr "Seuls les coachs peuvent gérer leurs disponibilités."
#: app/routes/users.py:1157 #: app/routes/users.py:1394
msgid "Only coaches can access the notes dashboard." msgid "Only coaches can access the notes dashboard."
msgstr "Seuls les coachs ont accès au tableau des notes." msgstr "Seuls les coachs ont accès au tableau des notes."
#: app/routes/users.py:1221 #: app/routes/users.py:1484
msgid "Only coaches can manage team notes." msgid "Only coaches can manage team notes."
msgstr "Seuls les coachs peuvent gérer les notes d’équipe." msgstr "Seuls les coachs peuvent gérer les notes d’équipe."
#: app/routes/users.py:1227 #: app/routes/users.py:1490
msgid "You are not assigned to a team." msgid "You are not assigned to a team."
msgstr "Vous n’êtes assigné à aucune équipe." msgstr "Vous n’êtes assigné à aucune équipe."
#: app/routes/users.py:1240 #: app/routes/users.py:1503
msgid "Team notes saved successfully!" msgid "Team notes saved successfully!"
msgstr "Notes d’équipe enregistrées." msgstr "Notes d’équipe enregistrées."
#: app/routes/users.py:1254 #: app/routes/users.py:1518
msgid "Only coaches can manage personal notes." msgid "Only coaches can manage personal notes."
msgstr "Seuls les coachs peuvent gérer les notes personnelles." msgstr "Seuls les coachs peuvent gérer les notes personnelles."
#: app/routes/users.py:1261 app/routes/users.py:1303 app/routes/users.py:1353 #: app/routes/users.py:1525 app/routes/users.py:1568 app/routes/users.py:1619
#: app/routes/users.py:1404 #: app/routes/users.py:1673
msgid "Player and content are required." msgid "Player and content are required."
msgstr "Le joueur et le contenu sont obligatoires." msgstr "Le joueur et le contenu sont obligatoires."
#: app/routes/users.py:1270 app/routes/users.py:1312 app/routes/users.py:1357 #: app/routes/users.py:1534 app/routes/users.py:1577 app/routes/users.py:1623
#: app/routes/users.py:1408 #: app/routes/users.py:1677
msgid "You can only write notes about players you work with." msgid "You can only write notes about players you work with."
msgstr "" msgstr ""
"Vous ne pouvez écrire des notes que sur les joueurs avec qui vous " "Vous ne pouvez écrire des notes que sur les joueurs avec qui vous "
"travaillez." "travaillez."
#: app/routes/users.py:1280 app/routes/users.py:1325 #: app/routes/users.py:1544 app/routes/users.py:1590
#, python-format #, python-format
msgid "Note added for %(username)s." msgid "Note added for %(username)s."
msgstr "Note ajoutée pour %(username)s." msgstr "Note ajoutée pour %(username)s."
#: app/routes/users.py:1293 app/routes/users.py:1338 app/routes/users.py:1388 #: app/routes/users.py:1558 app/routes/users.py:1604 app/routes/users.py:1657
msgid "Only coaches can add personal notes." msgid "Only coaches can add personal notes."
msgstr "Seuls les coachs peuvent ajouter des notes personnelles." msgstr "Seuls les coachs peuvent ajouter des notes personnelles."
#: app/routes/users.py:1368 app/routes/users.py:1419 #: app/routes/users.py:1634 app/routes/users.py:1688
msgid "Note added successfully." msgid "Note added successfully."
msgstr "Note ajoutée." msgstr "Note ajoutée."
+19 -5
View File
@@ -32,11 +32,25 @@ target-version = "py312"
exclude = [".venv", "venv", "migrations", "docs"] exclude = [".venv", "venv", "migrations", "docs"]
[tool.ruff.lint] [tool.ruff.lint]
# Starting from ruff's default rule set (pyflakes + a slice of pycodestyle). # Widened once the repository had been formatted, so that this enforcement
# Widening it — bugbear, isort, pyupgrade — is deliberately deferred until # is about defects rather than churn (QUA-002). The whole set produced 24
# the codebase has been formatted once, so that the first enforcement is # findings across 76 files — the code was cleaner than the audit feared.
# about real defects rather than churn. Tracked as QUA-002. #
select = ["E4", "E7", "E9", "F"] # E4/E7/E9, F pyflakes and the pycodestyle subset ruff enables by default
# B bugbear; B904 alone is worth it (lost exception causes)
# C4 comprehension shortcuts
# RET return-flow tidiness
# SIM obvious simplifications
# UP syntax available on the 3.12 this targets
#
# isort (I) is not enabled yet: it would reorder imports in 48 files, i.e. a
# second sweep of pure churn right after the formatting commit. Worth doing,
# worth doing on its own.
select = ["E4", "E7", "E9", "F", "B", "C4", "RET", "SIM", "UP"]
# Forcing a ternary reads worse than the if/else it replaces in the one place
# it fires (evaluations.py, choosing a sort direction).
ignore = ["SIM108"]
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
# Intentional re-export facade: `from app.models import User, Tryout, ...` # Intentional re-export facade: `from app.models import User, Tryout, ...`
+3 -6
View File
@@ -5,6 +5,7 @@ here: no environment variable is required to run the suite, no database
server is needed, and the Discord bot never starts. server is needed, and the Discord bot never starts.
""" """
import contextlib
import os import os
import sys import sys
import tempfile import tempfile
@@ -87,10 +88,8 @@ def app():
with application.app_context(): with application.app_context():
_db.session.remove() _db.session.remove()
_db.engine.dispose() _db.engine.dispose()
try: with contextlib.suppress(OSError):
os.unlink(db_path) os.unlink(db_path)
except OSError:
pass
@pytest.fixture @pytest.fixture
@@ -106,10 +105,8 @@ def app_with_csrf():
with application.app_context(): with application.app_context():
_db.session.remove() _db.session.remove()
_db.engine.dispose() _db.engine.dispose()
try: with contextlib.suppress(OSError):
os.unlink(db_path) os.unlink(db_path)
except OSError:
pass
@pytest.fixture @pytest.fixture
+1 -2
View File
@@ -182,7 +182,6 @@ class TestCatalogueIntegrity:
@pytest.mark.parametrize('locale', SUPPORTED_LOCALES) @pytest.mark.parametrize('locale', SUPPORTED_LOCALES)
def test_every_message_is_translated(self, locale): def test_every_message_is_translated(self, locale):
import io
import os import os
from babel.messages.pofile import read_po from babel.messages.pofile import read_po
@@ -195,7 +194,7 @@ class TestCatalogueIntegrity:
'LC_MESSAGES', 'LC_MESSAGES',
'messages.po', 'messages.po',
) )
with io.open(path, encoding='utf-8') as handle: with open(path, encoding='utf-8') as handle:
catalog = read_po(handle, locale=locale) catalog = read_po(handle, locale=locale)
untranslated = [m.id for m in catalog if m.id and not m.string] untranslated = [m.id for m in catalog if m.id and not m.string]