diff --git a/app/routes/auth.py b/app/routes/auth.py
index 4c7f708..b9c972e 100644
--- a/app/routes/auth.py
+++ b/app/routes/auth.py
@@ -24,9 +24,17 @@ import requests
#: Session key holding the pending OAuth2 anti-forgery token.
DISCORD_STATE_KEY = 'discord_oauth_state'
-# Account lockout settings
+# Failed-attempt tracking. The tally is kept for the audit trail and for the
+# cool-off marker below; it no longer refuses a correct password (SEC-018).
MAX_LOGIN_ATTEMPTS = 5
LOCKOUT_DURATION_MINUTES = 15
+#: Ceiling on the doubling cool-off window.
+MAX_LOCKOUT_MINUTES = 240
+
+#: Hash of a value nobody can submit. Verifying against it when the username
+#: is unknown makes that path cost the same scrypt work as a real one, so the
+#: response time stops telling a caller which usernames exist (SEC-017).
+_ABSENT_USER_HASH = None
# Discord OAuth2 configuration
DISCORD_CLIENT_ID = os.getenv('DISCORD_CLIENT_ID')
@@ -47,17 +55,64 @@ DISCORD_PLATFORM_TO_GAMES = {
def is_safe_url(url):
"""Validate that a URL is safe for redirection (same origin).
+ Accepts an absolute URL on this host, or a path beginning with exactly
+ one slash. Everything else is refused, including the two forms that
+ read differently to urlparse and to a browser:
+
+ /\\evil.com several browsers normalise the backslash to a slash,
+ turning this into the protocol-relative //evil.com.
+ urlparse reports no netloc at all, so the old check
+ let it through and the redirect left the site.
+ /\\n//evil.com control characters are stripped before parsing.
+
Args:
url: The URL to validate.
Returns:
- bool: True if the URL is safe (relative or same origin).
+ bool: True if the URL is safe.
"""
if not url:
return False
+ if any(ord(char) < 0x20 or char in '\\\x7f' for char in url):
+ return False
+
parsed = urlparse(url)
- # Allow relative URLs (no netloc) or same-origin URLs
- return not parsed.netloc or parsed.netloc == request.host
+ if parsed.netloc:
+ return (parsed.netloc == request.host
+ and parsed.scheme in ('', 'http', 'https'))
+ # Relative targets must be rooted. 'dashboard' or 'javascript:...' are
+ # not paths on this site.
+ return url.startswith('/')
+
+
+def _absent_user_hash():
+ """A hash to verify against when the submitted username does not exist.
+
+ check_password() used to be reached only when a user row was found, so
+ an unknown username answered as fast as the database lookup, and a known
+ one as slowly as scrypt. The gap is measurable and enumerates accounts.
+ Computed once per process, from a random secret, so no submitted password
+ can ever match it.
+ """
+ global _ABSENT_USER_HASH
+ if _ABSENT_USER_HASH is None:
+ _ABSENT_USER_HASH = hash_password(secrets.token_urlsafe(32))
+ return _ABSENT_USER_HASH
+
+
+def cooloff_minutes(failed_attempts):
+ """Length of the cool-off window earned by this many failed attempts.
+
+ Doubles every MAX_LOGIN_ATTEMPTS further failures, up to a ceiling.
+
+ Args:
+ failed_attempts: Consecutive failures recorded on the account.
+
+ Returns:
+ int: Minutes.
+ """
+ steps = max(failed_attempts // MAX_LOGIN_ATTEMPTS - 1, 0)
+ return min(LOCKOUT_DURATION_MINUTES * (2 ** steps), MAX_LOCKOUT_MINUTES)
def generate_captcha():
@@ -102,16 +157,17 @@ auth_bp = Blueprint('auth', __name__, url_prefix='/auth')
@auth_bp.route('/login', methods=['GET', 'POST'])
@limiter.limit("10 per minute")
def login():
- """Handle user login authentication with account lockout protection.
+ """Handle user login authentication.
GET: Render the login form.
- POST: Authenticate user credentials with lockout check and audit logging.
+ POST: Authenticate user credentials, with audit logging.
- Account lockout: After 5 consecutive failed attempts, the account is
- locked for 15 minutes. Successful login resets the counter.
-
- Redirects authenticated users to dashboard. Validates credentials and checks
- account status before login.
+ Failed attempts are counted and open a cool-off window, recorded in
+ ``locked_until`` and in the authentication log. The window does not
+ refuse correct credentials: when it did, five wrong guesses against a
+ known username took that account out of service for fifteen minutes,
+ repeatably, and on a president's account that meant no administration
+ at all. Guess rate is bounded by the rate limit on this view.
Returns:
Response: Login form or redirect to dashboard/next page.
@@ -134,25 +190,23 @@ def login():
password = validated['password']
user = User.query.filter_by(username=username).first()
- # Check if account is locked
- if user and user.locked_until and user.locked_until > datetime.utcnow():
- log_auth_event('login.rejected.locked', username=username, user_id=user.id)
- remaining = (user.locked_until - datetime.utcnow()).seconds // 60
- flash(
- _('Account is locked due to too many failed attempts. '
- 'Please try again in %(remaining)s minute(s).', remaining=remaining),
- 'danger'
- )
- return render_template('pages/login.html')
+ # Verified before anything else is decided, and on both branches.
+ # Reaching this only when a row exists made the response time a
+ # reliable oracle for which usernames are registered (SEC-017).
+ credentials_ok = check_password(
+ user.password_hash if user else _absent_user_hash(), password
+ )
- if user and check_password(user.password_hash, password):
+ if user and credentials_ok:
if not user.is_active_account:
log_auth_event('login.rejected.deactivated',
username=username, user_id=user.id)
flash(_('This account has been deactivated.'), 'danger')
return render_template('pages/login.html')
- # Reset failed login attempts on successful login
+ # Correct credentials clear the tally, cool-off window included.
+ # The window used to refuse them too, which is what turned it
+ # into a way to lock a known account out at will (SEC-018).
user.failed_login_attempts = 0
user.locked_until = None
db.session.commit()
@@ -188,33 +242,26 @@ def login():
flash(_('Welcome back, %(username)s!', username=user.username), 'success')
return redirect(next_page) if next_page else redirect(url_for('main.dashboard'))
else:
- # Track failed login attempt
+ # One message for every failure. The old code said "N attempts
+ # remaining" to a real account and "check username and password"
+ # to an unknown one, which listed the club's accounts to anyone
+ # who asked (SEC-017).
if user:
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:
- user.locked_until = datetime.utcnow() + timedelta(minutes=LOCKOUT_DURATION_MINUTES)
- log_auth_event('account.locked', username=username, user_id=user.id,
- minutes=LOCKOUT_DURATION_MINUTES)
- flash(
- _('Account locked after %(attempts)s failed attempts. '
- 'Please try again in %(minutes)s minutes.',
- attempts=MAX_LOGIN_ATTEMPTS,
- minutes=LOCKOUT_DURATION_MINUTES),
- 'danger'
- )
- else:
- remaining = MAX_LOGIN_ATTEMPTS - user.failed_login_attempts
- flash(
- _('Login unsuccessful. %(remaining)s attempt(s) remaining '
- 'before lockout.', remaining=remaining),
- 'danger'
- )
+ minutes = cooloff_minutes(user.failed_login_attempts)
+ user.locked_until = datetime.utcnow() + timedelta(minutes=minutes)
+ 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(_('Login unsuccessful. Please check username and password.'), 'danger')
+
+ flash(_('Login unsuccessful. Please check your username and '
+ 'password, or ask a president for help.'), 'danger')
return render_template('pages/login.html')
@@ -513,11 +560,16 @@ def discord_callback():
return redirect(url_for('auth.register'))
-@auth_bp.route('/logout')
+@auth_bp.route('/logout', methods=['POST'])
@login_required
def logout():
"""Log out the current user and clear the session.
+ POST, not GET: a GET route is not covered by CSRF protection, so any
+ page on the internet could sign a user out with an
tag pointing
+ here. A nuisance rather than a compromise, but it costs one form to
+ close (SEC-019).
+
Clears the user session and regenerates session ID to prevent
session fixation/replay after logout.
diff --git a/app/static/css/style.css b/app/static/css/style.css
index 44fad61..48cff1e 100644
--- a/app/static/css/style.css
+++ b/app/static/css/style.css
@@ -138,7 +138,10 @@ a:hover { color: var(--primary-dark); }
padding: 10px 0;
}
-.nav-links li a {
+/* Logging out is a POST, so its nav entry is a button inside a form
+ rather than a link. It has to read as one of the entries above it. */
+.nav-links li a,
+.nav-links li .nav-form button {
display: flex;
align-items: center;
gap: 12px;
@@ -148,7 +151,17 @@ a:hover { color: var(--primary-dark); }
font-size: 0.9rem;
}
-.nav-links li a:hover, .nav-links li a.active {
+.nav-links li .nav-form button {
+ width: 100%;
+ background: none;
+ border: 0;
+ font-family: inherit;
+ text-align: left;
+ cursor: pointer;
+}
+
+.nav-links li a:hover, .nav-links li a.active,
+.nav-links li .nav-form button:hover {
background: rgba(255,255,255,0.08);
color: white;
}
@@ -158,7 +171,8 @@ a:hover { color: var(--primary-dark); }
padding-left: 17px;
}
-.nav-links li a i { width: 20px; text-align: center; font-size: 1.1rem; }
+.nav-links li a i,
+.nav-links li .nav-form button i { width: 20px; text-align: center; font-size: 1.1rem; }
.nav-divider {
height: 1px;
diff --git a/app/templates/layouts/base.html b/app/templates/layouts/base.html
index 9c0dd63..2d29dc3 100644
--- a/app/templates/layouts/base.html
+++ b/app/templates/layouts/base.html
@@ -112,10 +112,16 @@
-
-
- {{ _('Logout') }}
-
+ {# A form, not a link: logging out is a state change, and a
+ GET route carries no CSRF token — any site could sign the
+ user out with an
tag. Styled as a nav entry. #}
+
diff --git a/app/translations/en/LC_MESSAGES/messages.mo b/app/translations/en/LC_MESSAGES/messages.mo
index 2b21c93..4b02bbf 100644
Binary files a/app/translations/en/LC_MESSAGES/messages.mo and b/app/translations/en/LC_MESSAGES/messages.mo differ
diff --git a/app/translations/en/LC_MESSAGES/messages.po b/app/translations/en/LC_MESSAGES/messages.po
index 7703d5f..81612f3 100644
--- a/app/translations/en/LC_MESSAGES/messages.po
+++ b/app/translations/en/LC_MESSAGES/messages.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: team-tryouts VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2026-08-07 22:03-0400\n"
+"POT-Creation-Date: 2026-08-08 14:58-0400\n"
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
"Last-Translator: FULL NAME \n"
"Language: en\n"
@@ -20,8 +20,12 @@ msgstr ""
"Generated-By: Babel 2.18.0\n"
#: app/validators.py:43
-msgid "Password must be at least 8 characters with uppercase, lowercase, and a number."
-msgstr "Password must be at least 8 characters with uppercase, lowercase, and a number."
+msgid ""
+"Password must be at least 8 characters with uppercase, lowercase, and a "
+"number."
+msgstr ""
+"Password must be at least 8 characters with uppercase, lowercase, and a "
+"number."
#: app/validators.py:62
msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)."
@@ -55,7 +59,8 @@ msgstr "Username must be 3-80 characters."
msgid "Email must be 120 characters or less."
msgstr "Email must be 120 characters or less."
-#: app/validators.py:199 app/validators.py:266 app/validators.py:299 app/validators.py:365
+#: app/validators.py:199 app/validators.py:266 app/validators.py:299
+#: app/validators.py:365
msgid "Full name is required."
msgstr "Full name is required."
@@ -95,97 +100,78 @@ msgstr "Points must be 2000 characters or less."
msgid "Day must be 0 (Monday) to 6 (Sunday)."
msgstr "Day must be 0 (Monday) to 6 (Sunday)."
-#: app/routes/auth.py:129 app/routes/auth.py:258 app/routes/users.py:46
-#: app/routes/users.py:649
+#: app/routes/auth.py:169 app/routes/auth.py:297 app/routes/users.py:49
+#: app/routes/users.py:653
#, python-format
msgid "%(field)s: %(msg)s"
msgstr "%(field)s: %(msg)s"
-#: app/routes/auth.py:141
-#, python-format
-msgid ""
-"Account is locked due to too many failed attempts. Please try again in %(remaining)s "
-"minute(s)."
-msgstr ""
-"Account is locked due to too many failed attempts. Please try again in %(remaining)s "
-"minute(s)."
-
-#: app/routes/auth.py:151
+#: app/routes/auth.py:187
msgid "This account has been deactivated."
msgstr "This account has been deactivated."
-#: app/routes/auth.py:179
+#: app/routes/auth.py:225
#, python-format
msgid "Welcome back, %(username)s!"
msgstr "Welcome back, %(username)s!"
-#: app/routes/auth.py:192
-#, python-format
+#: app/routes/auth.py:246
msgid ""
-"Account locked after %(attempts)s failed attempts. Please try again in %(minutes)s "
-"minutes."
+"Login unsuccessful. Please check your username and password, or ask a "
+"president for help."
msgstr ""
-"Account locked after %(attempts)s failed attempts. Please try again in %(minutes)s "
-"minutes."
+"Login unsuccessful. Please check your username and password, or ask a "
+"president for help."
-#: app/routes/auth.py:201
-#, python-format
-msgid "Login unsuccessful. %(remaining)s attempt(s) remaining before lockout."
-msgstr "Login unsuccessful. %(remaining)s attempt(s) remaining before lockout."
-
-#: app/routes/auth.py:208
-msgid "Login unsuccessful. Please check username and password."
-msgstr "Login unsuccessful. Please check username and password."
-
-#: app/routes/auth.py:239
+#: app/routes/auth.py:278
msgid "Incorrect CAPTCHA answer. Please try again."
msgstr "Incorrect CAPTCHA answer. Please try again."
-#: app/routes/auth.py:281 app/routes/users.py:317
+#: app/routes/auth.py:320 app/routes/users.py:336
msgid "Username already exists."
msgstr "Username already exists."
-#: app/routes/auth.py:293 app/routes/users.py:321
+#: app/routes/auth.py:332 app/routes/users.py:340
msgid "Email already registered."
msgstr "Email already registered."
-#: app/routes/auth.py:339
+#: app/routes/auth.py:378
msgid "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:365
+#: app/routes/auth.py:404
msgid "Discord OAuth2 is not configured."
msgstr "Discord OAuth2 is not configured."
-#: app/routes/auth.py:405
+#: app/routes/auth.py:444
msgid ""
-"Discord authorization could not be verified. Please start the connection again from "
-"this page."
+"Discord authorization could not be verified. Please start the connection "
+"again from this page."
msgstr ""
-"Discord authorization could not be verified. Please start the connection again from "
-"this page."
+"Discord authorization could not be verified. Please start the connection "
+"again from this page."
-#: app/routes/auth.py:413
+#: app/routes/auth.py:452
msgid "Discord authorization failed. No code received."
msgstr "Discord authorization failed. No code received."
-#: app/routes/auth.py:437
+#: app/routes/auth.py:476
msgid "Failed to connect to Discord. Please try again."
msgstr "Failed to connect to Discord. Please try again."
-#: app/routes/auth.py:441
+#: app/routes/auth.py:480
msgid "Failed to obtain Discord access token."
msgstr "Failed to obtain Discord access token."
-#: app/routes/auth.py:456
+#: app/routes/auth.py:495
msgid "Failed to fetch Discord user profile."
msgstr "Failed to fetch Discord user profile."
-#: app/routes/auth.py:503
+#: app/routes/auth.py:542
msgid "Discord account connected! Your profile has been pre-filled."
msgstr "Discord account connected! Your profile has been pre-filled."
-#: app/routes/auth.py:521
+#: app/routes/auth.py:565
msgid "You have been logged out."
msgstr "You have been logged out."
@@ -217,15 +203,16 @@ msgstr "Evaluation updated!"
msgid "Evaluation submitted successfully!"
msgstr "Evaluation submitted successfully!"
-#: app/routes/evaluations.py:215 app/routes/teams.py:249 app/routes/teams.py:280
-#: app/routes/teams.py:311 app/routes/teams.py:336 app/routes/teams.py:361
-#: app/routes/teams.py:393 app/routes/tryouts.py:341 app/routes/tryouts.py:357
-#: app/routes/tryouts.py:376 app/routes/tryouts.py:413 app/routes/tryouts.py:448
+#: app/routes/evaluations.py:215 app/routes/teams.py:236
+#: app/routes/teams.py:267 app/routes/teams.py:298 app/routes/teams.py:323
+#: app/routes/teams.py:348 app/routes/teams.py:380 app/routes/tryouts.py:341
+#: app/routes/tryouts.py:357 app/routes/tryouts.py:376
+#: app/routes/tryouts.py:413 app/routes/tryouts.py:448
#: app/routes/tryouts.py:467
msgid "Permission denied."
msgstr "Permission denied."
-#: app/routes/main.py:43
+#: app/routes/main.py:44
msgid "That language is not available."
msgstr "That language is not available."
@@ -241,12 +228,12 @@ msgstr "This tryout has ended. Matches can no longer be created or modified."
msgid "Start time is required. Please select a time slot."
msgstr "Start time is required. Please select a time slot."
-#: app/routes/matches.py:231 app/routes/matches.py:359 app/routes/team_matches.py:139
-#: app/routes/team_matches.py:222
+#: app/routes/matches.py:231 app/routes/matches.py:359
+#: app/routes/team_matches.py:123 app/routes/team_matches.py:206
msgid "Invalid date format."
msgstr "Invalid date format."
-#: app/routes/matches.py:246 app/routes/team_matches.py:156
+#: app/routes/matches.py:246 app/routes/team_matches.py:140
msgid "Invalid time format."
msgstr "Invalid time format."
@@ -254,7 +241,7 @@ msgstr "Invalid time format."
msgid "Match scheduled successfully!"
msgstr "Match scheduled successfully!"
-#: app/routes/matches.py:332 app/routes/team_matches.py:209
+#: app/routes/matches.py:332 app/routes/team_matches.py:193
msgid "You do not have permission to edit this match."
msgstr "You do not have permission to edit this match."
@@ -262,11 +249,11 @@ msgstr "You do not have permission to edit this match."
msgid "Start time is required."
msgstr "Start time is required."
-#: app/routes/matches.py:461 app/routes/team_matches.py:245
+#: app/routes/matches.py:461 app/routes/team_matches.py:229
msgid "Match updated successfully!"
msgstr "Match updated successfully!"
-#: app/routes/matches.py:506 app/routes/team_matches.py:259
+#: app/routes/matches.py:506 app/routes/team_matches.py:243
msgid "You do not have permission to delete this match."
msgstr "You do not have permission to delete this match."
@@ -274,158 +261,158 @@ msgstr "You do not have permission to delete this match."
msgid "This tryout has ended. Matches can no longer be deleted."
msgstr "This tryout has ended. Matches can no longer be deleted."
-#: app/routes/matches.py:521 app/routes/team_matches.py:263
+#: app/routes/matches.py:521 app/routes/team_matches.py:247
msgid "Match deleted successfully."
msgstr "Match deleted successfully."
-#: app/routes/team_matches.py:97
+#: app/routes/team_matches.py:81
msgid "You do not have permission to schedule matches for this team."
msgstr "You do not have permission to schedule matches for this team."
-#: app/routes/team_matches.py:132
+#: app/routes/team_matches.py:116
msgid "Date is required."
msgstr "Date is required."
-#: app/routes/team_matches.py:195
+#: app/routes/team_matches.py:179
#, python-format
msgid "Team match \"%(title)s\" scheduled successfully!"
msgstr "Team match \"%(title)s\" scheduled successfully!"
-#: app/routes/teams.py:43
+#: app/routes/teams.py:28
msgid "Use My Team(s) to view your teams."
msgstr "Use My Team(s) to view your teams."
-#: app/routes/teams.py:46
+#: app/routes/teams.py:31
msgid "You do not have permission to view teams."
msgstr "You do not have permission to view teams."
-#: app/routes/teams.py:61
+#: app/routes/teams.py:48
msgid "This page is for players."
msgstr "This page is for players."
-#: app/routes/teams.py:103
+#: app/routes/teams.py:90
msgid "You do not have permission to create teams."
msgstr "You do not have permission to create teams."
-#: app/routes/teams.py:111 app/routes/teams.py:156
+#: app/routes/teams.py:98 app/routes/teams.py:143
msgid "Team name is required."
msgstr "Team name is required."
-#: app/routes/teams.py:116 app/routes/teams.py:161
+#: app/routes/teams.py:103 app/routes/teams.py:148
#, python-format
msgid "Team \"%(name)s\" already exists."
msgstr "Team \"%(name)s\" already exists."
-#: app/routes/teams.py:138
+#: app/routes/teams.py:125
#, python-format
msgid "Team \"%(name)s\" created successfully!"
msgstr "Team \"%(name)s\" created successfully!"
-#: app/routes/teams.py:148
+#: app/routes/teams.py:135
msgid "You do not have permission to edit this team."
msgstr "You do not have permission to edit this team."
-#: app/routes/teams.py:199
+#: app/routes/teams.py:186
#, python-format
msgid "Team \"%(name)s\" updated successfully!"
msgstr "Team \"%(name)s\" updated successfully!"
-#: app/routes/teams.py:208
+#: app/routes/teams.py:195
msgid "You do not have permission to delete teams."
msgstr "You do not have permission to delete teams."
-#: app/routes/teams.py:239
+#: app/routes/teams.py:226
#, python-format
msgid "Team \"%(name)s\" deleted successfully."
msgstr "Team \"%(name)s\" deleted successfully."
-#: app/routes/teams.py:254
+#: app/routes/teams.py:241
msgid "Please select a coach."
msgstr "Please select a coach."
-#: app/routes/teams.py:259
+#: app/routes/teams.py:246
msgid "Only coaches can be assigned as coach."
msgstr "Only coaches can be assigned as coach."
-#: app/routes/teams.py:263
+#: app/routes/teams.py:250
#, python-format
msgid "%(username)s is already a coach of %(name)s."
msgstr "%(username)s is already a coach of %(name)s."
-#: app/routes/teams.py:270
+#: app/routes/teams.py:257
#, python-format
msgid "%(username)s added as coach of %(name)s."
msgstr "%(username)s added as coach of %(name)s."
-#: app/routes/teams.py:285
+#: app/routes/teams.py:272
msgid "Please select a manager."
msgstr "Please select a manager."
-#: app/routes/teams.py:290
+#: app/routes/teams.py:277
msgid "Only managers can be assigned as manager."
msgstr "Only managers can be assigned as manager."
-#: app/routes/teams.py:294
+#: app/routes/teams.py:281
#, python-format
msgid "%(username)s is already a manager of %(name)s."
msgstr "%(username)s is already a manager of %(name)s."
-#: app/routes/teams.py:301
+#: app/routes/teams.py:288
#, python-format
msgid "%(username)s added as manager of %(name)s."
msgstr "%(username)s added as manager of %(name)s."
-#: app/routes/teams.py:326
+#: app/routes/teams.py:313
#, python-format
msgid "Coach removed from %(name)s."
msgstr "Coach removed from %(name)s."
-#: app/routes/teams.py:351
+#: app/routes/teams.py:338
#, python-format
msgid "Manager removed from %(name)s."
msgstr "Manager removed from %(name)s."
-#: app/routes/teams.py:367 app/routes/tryouts.py:380 app/routes/tryouts.py:478
+#: app/routes/teams.py:354 app/routes/tryouts.py:380 app/routes/tryouts.py:478
msgid "Please select a player."
msgstr "Please select a player."
-#: app/routes/teams.py:372
+#: app/routes/teams.py:359
msgid "Can only assign players to teams."
msgstr "Can only assign players to teams."
-#: app/routes/teams.py:377
+#: app/routes/teams.py:364
#, python-format
msgid "%(username)s is already on %(name)s."
msgstr "%(username)s is already on %(name)s."
-#: app/routes/teams.py:383
+#: app/routes/teams.py:370
#, python-format
msgid "%(username)s added to %(name)s!"
msgstr "%(username)s added to %(name)s!"
-#: app/routes/teams.py:399 app/routes/teams.py:462
+#: app/routes/teams.py:386 app/routes/teams.py:449
#, python-format
msgid "%(username)s is not on %(name)s."
msgstr "%(username)s is not on %(name)s."
-#: app/routes/teams.py:404
+#: app/routes/teams.py:391
#, python-format
msgid "%(username)s removed from %(name)s."
msgstr "%(username)s removed from %(name)s."
-#: app/routes/teams.py:434 app/routes/teams.py:452
+#: app/routes/teams.py:421 app/routes/teams.py:439
msgid "You do not have permission to add notes to this team."
msgstr "You do not have permission to add notes to this team."
-#: app/routes/teams.py:442
+#: app/routes/teams.py:429
msgid "Team notes added successfully!"
msgstr "Team notes added successfully!"
-#: app/routes/teams.py:457 app/routes/users.py:1227 app/routes/users.py:1269
+#: app/routes/teams.py:444 app/routes/users.py:1241 app/routes/users.py:1283
msgid "Can only add notes for players."
msgstr "Can only add notes for players."
-#: app/routes/teams.py:470
+#: app/routes/teams.py:457
#, python-format
msgid "Note added for %(username)s!"
msgstr "Note added for %(username)s!"
@@ -539,11 +526,11 @@ msgstr "You do not have permission to delete this tryout."
msgid "Tryout deleted successfully."
msgstr "Tryout deleted successfully."
-#: app/routes/users.py:116
+#: app/routes/users.py:119
msgid "Only the president can manage users."
msgstr "Only the president can manage users."
-#: app/routes/users.py:128
+#: app/routes/users.py:131
msgid "Only the president can edit users."
msgstr "Only the president can edit users."
@@ -551,189 +538,193 @@ msgstr "Only the president can edit users."
msgid "Email already in use by another account."
msgstr "Email already in use by another account."
-#: app/routes/users.py:175
+#: app/routes/users.py:178
msgid "You cannot change your own role. Ask another president to do it."
msgstr "You cannot change your own role. Ask another president to do it."
-#: app/routes/users.py:186
-msgid "This is the last active president. Promote another account before changing this one."
-msgstr "This is the last active president. Promote another account before changing this one."
+#: app/routes/users.py:189
+msgid ""
+"This is the last active president. Promote another account before "
+"changing this one."
+msgstr ""
+"This is the last active president. Promote another account before "
+"changing this one."
-#: app/routes/users.py:232
+#: app/routes/users.py:251
#, python-format
msgid "User %(username)s updated successfully!"
msgstr "User %(username)s updated successfully!"
-#: app/routes/users.py:247
+#: app/routes/users.py:266
msgid "Only the president can delete users."
msgstr "Only the president can delete users."
-#: app/routes/users.py:251
+#: app/routes/users.py:270
msgid "You cannot delete your own account."
msgstr "You cannot delete your own account."
-#: app/routes/users.py:288
+#: app/routes/users.py:307
#, python-format
msgid "User %(deleted_username)s has been removed."
msgstr "User %(deleted_username)s has been removed."
-#: app/routes/users.py:297
+#: app/routes/users.py:316
msgid "Only the president can create users."
msgstr "Only the president can create users."
-#: app/routes/users.py:336
+#: app/routes/users.py:355
#, python-format
msgid "User %(full_name)s created as %(role)s!"
msgstr "User %(full_name)s created as %(role)s!"
-#: app/routes/users.py:393
+#: app/routes/users.py:412
msgid "Username already taken."
msgstr "Username already taken."
-#: app/routes/users.py:399
+#: app/routes/users.py:418
msgid "Email already in use."
msgstr "Email already in use."
-#: app/routes/users.py:424
+#: app/routes/users.py:443
msgid "Profile updated successfully!"
msgstr "Profile updated successfully!"
-#: app/routes/users.py:629
+#: app/routes/users.py:641
msgid "Only presidents, managers, and coaches can upload contracts."
msgstr "Only presidents, managers, and coaches can upload contracts."
-#: app/routes/users.py:656
+#: app/routes/users.py:660
msgid "You do not have permission to upload a contract for this player."
msgstr "You do not have permission to upload a contract for this player."
-#: app/routes/users.py:660 app/routes/users.py:665 app/routes/users.py:717
-#: app/routes/users.py:722
+#: app/routes/users.py:664 app/routes/users.py:669 app/routes/users.py:721
+#: app/routes/users.py:726
msgid "No file selected."
msgstr "No file selected."
-#: app/routes/users.py:668
+#: app/routes/users.py:672
msgid "Only PDF files are allowed for contracts."
msgstr "Only PDF files are allowed for contracts."
-#: app/routes/users.py:701
+#: app/routes/users.py:705
#, python-format
msgid "Contract uploaded successfully for %(username)s!"
msgstr "Contract uploaded successfully for %(username)s!"
-#: app/routes/users.py:713
+#: app/routes/users.py:717
msgid "Only the player can upload their signed contract."
msgstr "Only the player can upload their signed contract."
-#: app/routes/users.py:733
+#: app/routes/users.py:737
msgid "Signed contract uploaded successfully!"
msgstr "Signed contract uploaded successfully!"
-#: app/routes/users.py:743 app/routes/users.py:754
+#: app/routes/users.py:747 app/routes/users.py:758
msgid "You do not have permission to download this contract."
msgstr "You do not have permission to download this contract."
-#: app/routes/users.py:757
+#: app/routes/users.py:761
msgid "No signed contract available."
msgstr "No signed contract available."
-#: app/routes/users.py:824
+#: app/routes/users.py:828
msgid "Only players can request One on One sessions."
msgstr "Only players can request One on One sessions."
-#: app/routes/users.py:832
+#: app/routes/users.py:841
msgid "You do not have a coach assigned to your team."
msgstr "You do not have a coach assigned to your team."
-#: app/routes/users.py:859
+#: app/routes/users.py:868
msgid "Cannot request One on One - no coach assigned."
msgstr "Cannot request One on One - no coach assigned."
-#: app/routes/users.py:867
+#: app/routes/users.py:876
msgid "Invalid date or time format."
msgstr "Invalid date or time format."
-#: app/routes/users.py:881
+#: app/routes/users.py:890
msgid "The requested time is not within the coach's availability."
msgstr "The requested time is not within the coach's availability."
-#: app/routes/users.py:904
+#: app/routes/users.py:913
msgid "Your One on One request has been submitted!"
msgstr "Your One on One request has been submitted!"
-#: app/routes/users.py:939
+#: app/routes/users.py:948
msgid "Only coaches can accept One on One requests."
msgstr "Only coaches can accept One on One requests."
-#: app/routes/users.py:945 app/routes/users.py:986
+#: app/routes/users.py:954 app/routes/users.py:995
msgid "This request is not for you."
msgstr "This request is not for you."
-#: app/routes/users.py:949 app/routes/users.py:990
+#: app/routes/users.py:958 app/routes/users.py:999
msgid "This request has already been processed."
msgstr "This request has already been processed."
-#: app/routes/users.py:971
+#: app/routes/users.py:980
#, python-format
msgid "One on One request from %(player)s has been approved!"
msgstr "One on One request from %(player)s has been approved!"
-#: app/routes/users.py:980
+#: app/routes/users.py:989
msgid "Only coaches can reject One on One requests."
msgstr "Only coaches can reject One on One requests."
-#: app/routes/users.py:1017
+#: app/routes/users.py:1026
#, python-format
msgid "One on One request from %(player)s has been rejected."
msgstr "One on One request from %(player)s has been rejected."
-#: app/routes/users.py:1030
+#: app/routes/users.py:1039
msgid "This page is for players only."
msgstr "This page is for players only."
-#: app/routes/users.py:1061
+#: app/routes/users.py:1070
msgid "Only coaches can manage availability."
msgstr "Only coaches can manage availability."
-#: app/routes/users.py:1123
+#: app/routes/users.py:1132
msgid "Only coaches can access the notes dashboard."
msgstr "Only coaches can access the notes dashboard."
-#: app/routes/users.py:1184
+#: app/routes/users.py:1196
msgid "Only coaches can manage team notes."
msgstr "Only coaches can manage team notes."
-#: app/routes/users.py:1189
+#: app/routes/users.py:1202
msgid "You are not assigned to a team."
msgstr "You are not assigned to a team."
-#: app/routes/users.py:1201
+#: app/routes/users.py:1215
msgid "Team notes saved successfully!"
msgstr "Team notes saved successfully!"
-#: app/routes/users.py:1215
+#: app/routes/users.py:1229
msgid "Only coaches can manage personal notes."
msgstr "Only coaches can manage personal notes."
-#: app/routes/users.py:1222 app/routes/users.py:1264 app/routes/users.py:1314
-#: app/routes/users.py:1365
+#: app/routes/users.py:1236 app/routes/users.py:1278 app/routes/users.py:1328
+#: app/routes/users.py:1379
msgid "Player and content are required."
msgstr "Player and content are required."
-#: app/routes/users.py:1231 app/routes/users.py:1273 app/routes/users.py:1318
-#: app/routes/users.py:1369
+#: app/routes/users.py:1245 app/routes/users.py:1287 app/routes/users.py:1332
+#: app/routes/users.py:1383
msgid "You can only write notes about players you work with."
msgstr "You can only write notes about players you work with."
-#: app/routes/users.py:1241 app/routes/users.py:1286
+#: app/routes/users.py:1255 app/routes/users.py:1300
#, python-format
msgid "Note added for %(username)s."
msgstr "Note added for %(username)s."
-#: app/routes/users.py:1254 app/routes/users.py:1299 app/routes/users.py:1349
+#: app/routes/users.py:1268 app/routes/users.py:1313 app/routes/users.py:1363
msgid "Only coaches can add personal notes."
msgstr "Only coaches can add personal notes."
-#: app/routes/users.py:1329 app/routes/users.py:1380
+#: app/routes/users.py:1343 app/routes/users.py:1394
msgid "Note added successfully."
msgstr "Note added successfully."
@@ -751,11 +742,11 @@ msgstr "400 — Bad Request"
#: app/templates/errors/400.html:10
msgid ""
-"The request could not be understood by the server. Please check your input and try "
-"again."
+"The request could not be understood by the server. Please check your "
+"input and try again."
msgstr ""
-"The request could not be understood by the server. Please check your input and try "
-"again."
+"The request could not be understood by the server. Please check your "
+"input and try again."
#: app/templates/errors/400.html:12 app/templates/errors/403.html:12
#: app/templates/errors/429.html:12
@@ -776,11 +767,11 @@ msgstr "403 — Forbidden"
#: app/templates/errors/403.html:10
msgid ""
-"You do not have permission to access this resource. If you believe this is an error, "
-"please contact an administrator."
+"You do not have permission to access this resource. If you believe this "
+"is an error, please contact an administrator."
msgstr ""
-"You do not have permission to access this resource. If you believe this is an error, "
-"please contact an administrator."
+"You do not have permission to access this resource. If you believe this "
+"is an error, please contact an administrator."
#: app/templates/errors/404.html:2
msgid "404 Not Found"
@@ -795,8 +786,12 @@ msgid "404 — Not Found"
msgstr "404 — Not Found"
#: app/templates/errors/404.html:10
-msgid "The page you are looking for does not exist. It may have been moved or deleted."
-msgstr "The page you are looking for does not exist. It may have been moved or deleted."
+msgid ""
+"The page you are looking for does not exist. It may have been moved or "
+"deleted."
+msgstr ""
+"The page you are looking for does not exist. It may have been moved or "
+"deleted."
#: app/templates/errors/404.html:12
msgid "Return Home"
@@ -815,8 +810,12 @@ msgid "429 — Too Many Requests"
msgstr "429 — Too Many Requests"
#: app/templates/errors/429.html:10
-msgid "You have sent too many requests in a short period. Please wait a moment and try again."
-msgstr "You have sent too many requests in a short period. Please wait a moment and try again."
+msgid ""
+"You have sent too many requests in a short period. Please wait a moment "
+"and try again."
+msgstr ""
+"You have sent too many requests in a short period. Please wait a moment "
+"and try again."
#: app/templates/errors/500.html:2
msgid "500 Server Error"
@@ -832,11 +831,11 @@ msgstr "500 — Internal Server Error"
#: app/templates/errors/500.html:10
msgid ""
-"Something went wrong on our end. The error has been logged and will be investigated. "
-"Please try again later."
+"Something went wrong on our end. The error has been logged and will be "
+"investigated. Please try again later."
msgstr ""
-"Something went wrong on our end. The error has been logged and will be investigated. "
-"Please try again later."
+"Something went wrong on our end. The error has been logged and will be "
+"investigated. Please try again later."
#: app/templates/errors/500.html:12
msgid "Try Again"
@@ -862,7 +861,8 @@ msgid "Calendar"
msgstr "Calendar"
#: app/templates/layouts/base.html:52 app/templates/pages/dashboard.html:43
-#: app/templates/pages/evaluations.html:2 app/templates/pages/evaluations.html:3
+#: app/templates/pages/evaluations.html:2
+#: app/templates/pages/evaluations.html:3
msgid "Evaluations"
msgstr "Evaluations"
@@ -880,7 +880,8 @@ msgstr "Manage Teams"
msgid "Manage Users"
msgstr "Manage Users"
-#: app/templates/layouts/base.html:83 app/templates/pages/player_personal_notes.html:2
+#: app/templates/layouts/base.html:83
+#: app/templates/pages/player_personal_notes.html:2
#: app/templates/pages/player_personal_notes.html:3
msgid "My Notes"
msgstr "My Notes"
@@ -930,16 +931,19 @@ msgid "Add Personal Note"
msgstr "Add Personal Note"
#: app/templates/pages/add_note.html:47 app/templates/pages/contracts.html:25
-#: app/templates/pages/dashboard.html:249 app/templates/pages/dashboard.html:363
-#: app/templates/pages/my_teams.html:52 app/templates/pages/notes.html:122
+#: app/templates/pages/dashboard.html:249
+#: app/templates/pages/dashboard.html:363 app/templates/pages/my_teams.html:52
+#: app/templates/pages/notes.html:122
#: app/templates/pages/players_to_evaluate.html:16
-#: app/templates/pages/team_match_form.html:114 app/templates/pages/teams.html:145
-#: app/templates/pages/view_tryout.html:148 app/templates/pages/view_tryout.html:492
+#: app/templates/pages/team_match_form.html:114
+#: app/templates/pages/teams.html:145 app/templates/pages/view_tryout.html:148
+#: app/templates/pages/view_tryout.html:492
msgid "Player"
msgstr "Player"
#: app/templates/pages/add_note.html:49 app/templates/pages/teams.html:216
-#: app/templates/pages/upload_contract.html:18 app/templates/pages/view_tryout.html:124
+#: app/templates/pages/upload_contract.html:18
+#: app/templates/pages/view_tryout.html:124
msgid "-- Select a player --"
msgstr "-- Select a player --"
@@ -980,8 +984,10 @@ msgstr "-- No team --"
msgid "Team Notes (Reference)"
msgstr "Team Notes (Reference)"
-#: app/templates/pages/add_note.html:120 app/templates/pages/evaluate_player.html:131
-#: app/templates/pages/notes.html:100 app/templates/pages/personal_notes.html:36
+#: app/templates/pages/add_note.html:120
+#: app/templates/pages/evaluate_player.html:131
+#: app/templates/pages/notes.html:100
+#: app/templates/pages/personal_notes.html:36
#: app/templates/pages/view_tryout.html:303
msgid "Add Note"
msgstr "Add Note"
@@ -1062,11 +1068,13 @@ msgstr "Event Details"
msgid "Confirm"
msgstr "Confirm"
-#: app/templates/pages/calendar.html:102 app/templates/pages/team_matches.html:102
+#: app/templates/pages/calendar.html:102
+#: app/templates/pages/team_matches.html:102
msgid "Delete Match"
msgstr "Delete Match"
-#: app/templates/pages/calendar.html:105 app/templates/pages/team_matches.html:97
+#: app/templates/pages/calendar.html:105
+#: app/templates/pages/team_matches.html:97
msgid "Edit Match"
msgstr "Edit Match"
@@ -1087,17 +1095,20 @@ msgstr "Set Your Weekly Availability"
msgid "Select time slots when you're available for One on One sessions"
msgstr "Select time slots when you're available for One on One sessions"
-#: app/templates/pages/coach_availability.html:14 app/templates/pages/profile.html:216
+#: app/templates/pages/coach_availability.html:14
+#: app/templates/pages/profile.html:216
msgid "Loading availability grid..."
msgstr "Loading availability grid..."
-#: app/templates/pages/coach_availability.html:19 app/templates/pages/profile.html:200
-#: app/templates/pages/profile.html:220
+#: app/templates/pages/coach_availability.html:19
+#: app/templates/pages/profile.html:200 app/templates/pages/profile.html:220
msgid "Clear All"
msgstr "Clear All"
-#: app/templates/pages/contracts.html:9 app/templates/pages/upload_contract.html:2
-#: app/templates/pages/upload_contract.html:3 app/templates/pages/upload_contract.html:39
+#: app/templates/pages/contracts.html:9
+#: app/templates/pages/upload_contract.html:2
+#: app/templates/pages/upload_contract.html:3
+#: app/templates/pages/upload_contract.html:39
msgid "Upload Contract"
msgstr "Upload Contract"
@@ -1115,14 +1126,17 @@ msgid "Contract"
msgstr "Contract"
#: app/templates/pages/contracts.html:28 app/templates/pages/dashboard.html:95
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:175
-#: app/templates/pages/dashboard.html:202 app/templates/pages/dashboard.html:321
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:175
+#: app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:321
#: app/templates/pages/match_form.html:60 app/templates/pages/my_teams.html:53
#: app/templates/pages/notes.html:126 app/templates/pages/one_on_one.html:73
#: app/templates/pages/players_to_evaluate.html:19
-#: app/templates/pages/team_match_form.html:61 app/templates/pages/team_matches.html:32
-#: app/templates/pages/teams.html:146 app/templates/pages/users.html:23
-#: app/templates/pages/view_tryout.html:149 app/templates/pages/view_tryout.html:321
+#: app/templates/pages/team_match_form.html:61
+#: app/templates/pages/team_matches.html:32 app/templates/pages/teams.html:146
+#: app/templates/pages/users.html:23 app/templates/pages/view_tryout.html:149
+#: app/templates/pages/view_tryout.html:321
msgid "Status"
msgstr "Status"
@@ -1131,7 +1145,8 @@ msgid "Uploaded"
msgstr "Uploaded"
#: app/templates/pages/contracts.html:30 app/templates/pages/dashboard.html:175
-#: app/templates/pages/notes.html:127 app/templates/pages/players_to_evaluate.html:20
+#: app/templates/pages/notes.html:127
+#: app/templates/pages/players_to_evaluate.html:20
#: app/templates/pages/team_matches.html:33 app/templates/pages/teams.html:151
#: app/templates/pages/users.html:25 app/templates/pages/view_tryout.html:154
#: app/templates/pages/view_tryout.html:323
@@ -1164,33 +1179,45 @@ msgid "No contracts found"
msgstr "No contracts found"
#: app/templates/pages/contracts.html:74
-msgid "No contracts have been uploaded for you yet. Contact your coach or manager."
-msgstr "No contracts have been uploaded for you yet. Contact your coach or manager."
+msgid ""
+"No contracts have been uploaded for you yet. Contact your coach or "
+"manager."
+msgstr ""
+"No contracts have been uploaded for you yet. Contact your coach or "
+"manager."
#: app/templates/pages/contracts.html:76
-msgid "No contracts have been uploaded yet. Upload a contract using the button above."
-msgstr "No contracts have been uploaded yet. Upload a contract using the button above."
+msgid ""
+"No contracts have been uploaded yet. Upload a contract using the button "
+"above."
+msgstr ""
+"No contracts have been uploaded yet. Upload a contract using the button "
+"above."
#: app/templates/pages/contracts.html:96
msgid "Select Signed Contract File"
msgstr "Select Signed Contract File"
-#: app/templates/pages/contracts.html:98 app/templates/pages/upload_contract.html:28
+#: app/templates/pages/contracts.html:98
+#: app/templates/pages/upload_contract.html:28
msgid "Accepted formats: PDF, DOC, DOCX, JPG, PNG"
msgstr "Accepted formats: PDF, DOC, DOCX, JPG, PNG"
-#: app/templates/pages/contracts.html:101 app/templates/pages/match_form.html:265
-#: app/templates/pages/notes.html:189 app/templates/pages/teams.html:48
-#: app/templates/pages/teams.html:295 app/templates/pages/view_tryout.html:239
+#: app/templates/pages/contracts.html:101
+#: app/templates/pages/match_form.html:265 app/templates/pages/notes.html:189
+#: app/templates/pages/teams.html:48 app/templates/pages/teams.html:295
+#: app/templates/pages/view_tryout.html:239
msgid "Cancel"
msgstr "Cancel"
-#: app/templates/pages/create_user.html:2 app/templates/pages/create_user.html:3
+#: app/templates/pages/create_user.html:2
+#: app/templates/pages/create_user.html:3
#: app/templates/pages/create_user.html:47
msgid "Create User"
msgstr "Create User"
-#: app/templates/pages/create_user.html:13 app/templates/pages/edit_profile.html:17
+#: app/templates/pages/create_user.html:13
+#: app/templates/pages/edit_profile.html:17
#: app/templates/pages/edit_user.html:13 app/templates/pages/register.html:10
msgid "Full Name"
msgstr "Full Name"
@@ -1199,9 +1226,9 @@ msgstr "Full Name"
msgid "Enter full name"
msgstr "Enter full name"
-#: app/templates/pages/create_user.html:17 app/templates/pages/edit_profile.html:13
-#: app/templates/pages/login.html:7 app/templates/pages/register.html:15
-#: app/templates/pages/users.html:20
+#: app/templates/pages/create_user.html:17
+#: app/templates/pages/edit_profile.html:13 app/templates/pages/login.html:7
+#: app/templates/pages/register.html:15 app/templates/pages/users.html:20
msgid "Username"
msgstr "Username"
@@ -1209,7 +1236,8 @@ msgstr "Username"
msgid "Choose username"
msgstr "Choose username"
-#: app/templates/pages/create_user.html:23 app/templates/pages/edit_profile.html:23
+#: app/templates/pages/create_user.html:23
+#: app/templates/pages/edit_profile.html:23
#: app/templates/pages/edit_user.html:17 app/templates/pages/register.html:20
#: app/templates/pages/teams.html:148 app/templates/pages/users.html:21
msgid "Email"
@@ -1219,7 +1247,8 @@ msgstr "Email"
msgid "Enter email"
msgstr "Enter email"
-#: app/templates/pages/create_user.html:27 app/templates/pages/edit_profile.html:27
+#: app/templates/pages/create_user.html:27
+#: app/templates/pages/edit_profile.html:27
#: app/templates/pages/edit_user.html:23 app/templates/pages/teams.html:149
msgid "Phone"
msgstr "Phone"
@@ -1228,8 +1257,9 @@ msgstr "Phone"
msgid "Phone number"
msgstr "Phone number"
-#: app/templates/pages/create_user.html:31 app/templates/pages/dashboard.html:74
-#: app/templates/pages/edit_user.html:27 app/templates/pages/users.html:22
+#: app/templates/pages/create_user.html:31
+#: app/templates/pages/dashboard.html:74 app/templates/pages/edit_user.html:27
+#: app/templates/pages/users.html:22
msgid "Role"
msgstr "Role"
@@ -1258,7 +1288,8 @@ msgstr "Total Tryouts"
msgid "Active Tryouts"
msgstr "Active Tryouts"
-#: app/templates/pages/dashboard.html:61 app/templates/pages/view_tryout.html:21
+#: app/templates/pages/dashboard.html:61
+#: app/templates/pages/view_tryout.html:21
msgid "Upcoming"
msgstr "Upcoming"
@@ -1283,38 +1314,45 @@ msgid "Title"
msgstr "Title"
#: app/templates/pages/dashboard.html:95 app/templates/pages/dashboard.html:175
-#: app/templates/pages/dashboard.html:249 app/templates/pages/dashboard.html:321
+#: app/templates/pages/dashboard.html:249
+#: app/templates/pages/dashboard.html:321
#: app/templates/pages/match_form.html:55 app/templates/pages/my_teams.html:92
#: app/templates/pages/notes.html:123 app/templates/pages/one_on_one.html:70
-#: app/templates/pages/team_match_form.html:34 app/templates/pages/team_matches.html:28
+#: app/templates/pages/team_match_form.html:34
+#: app/templates/pages/team_matches.html:28
#: app/templates/pages/view_tryout.html:317
msgid "Date"
msgstr "Date"
-#: app/templates/pages/dashboard.html:114 app/templates/pages/dashboard.html:198
-#: app/templates/pages/my_teams.html:84
+#: app/templates/pages/dashboard.html:114
+#: app/templates/pages/dashboard.html:198 app/templates/pages/my_teams.html:84
msgid "Upcoming Matches"
msgstr "Upcoming Matches"
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:202
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:90
#: app/templates/pages/notes.html:69 app/templates/pages/team_matches.html:25
#: app/templates/pages/teams.html:132 app/templates/pages/view_tryout.html:315
msgid "Match"
msgstr "Match"
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:202
-#: app/templates/pages/dashboard.html:249 app/templates/pages/dashboard.html:285
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:249
+#: app/templates/pages/dashboard.html:285
#: app/templates/pages/dashboard.html:321 app/templates/pages/notes.html:78
msgid "Tryout"
msgstr "Tryout"
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:202
#: app/templates/pages/dashboard.html:285
msgid "Date & Time"
msgstr "Date & Time"
-#: app/templates/pages/dashboard.html:145 app/templates/pages/dashboard.html:169
+#: app/templates/pages/dashboard.html:145
+#: app/templates/pages/dashboard.html:169
#: app/templates/pages/dashboard.html:273
msgid "My Tryouts"
msgstr "My Tryouts"
@@ -1331,7 +1369,8 @@ msgstr "My Evaluations"
msgid "Evaluations Done"
msgstr "Evaluations Done"
-#: app/templates/pages/dashboard.html:238 app/templates/pages/one_on_one.html:85
+#: app/templates/pages/dashboard.html:238
+#: app/templates/pages/one_on_one.html:85
msgid "Pending"
msgstr "Pending"
@@ -1376,17 +1415,19 @@ msgstr "Top Rated Players"
msgid "Avg Score"
msgstr "Avg Score"
-#: app/templates/pages/dashboard.html:373 app/templates/pages/view_tryout.html:526
+#: app/templates/pages/dashboard.html:373
+#: app/templates/pages/view_tryout.html:526
msgid "No evaluations yet."
msgstr "No evaluations yet."
-#: app/templates/pages/edit_profile.html:2 app/templates/pages/edit_profile.html:3
-#: app/templates/pages/profile.html:12
+#: app/templates/pages/edit_profile.html:2
+#: app/templates/pages/edit_profile.html:3 app/templates/pages/profile.html:12
msgid "Edit Profile"
msgstr "Edit Profile"
-#: app/templates/pages/edit_profile.html:33 app/templates/pages/edit_user.html:43
-#: app/templates/pages/profile.html:63 app/templates/pages/register.html:83
+#: app/templates/pages/edit_profile.html:33
+#: app/templates/pages/edit_user.html:43 app/templates/pages/profile.html:63
+#: app/templates/pages/register.html:83
msgid "E-Sports Profile"
msgstr "E-Sports Profile"
@@ -1394,62 +1435,77 @@ msgstr "E-Sports Profile"
msgid "Update your competitive gaming profile for tryouts."
msgstr "Update your competitive gaming profile for tryouts."
-#: app/templates/pages/edit_profile.html:37 app/templates/pages/register.html:87
+#: app/templates/pages/edit_profile.html:37
+#: app/templates/pages/register.html:87
msgid "Games You Play"
msgstr "Games You Play"
-#: app/templates/pages/edit_profile.html:47 app/templates/pages/register.html:101
+#: app/templates/pages/edit_profile.html:47
+#: app/templates/pages/register.html:101
msgid "Select all games you're signing in for."
msgstr "Select all games you're signing in for."
-#: app/templates/pages/edit_profile.html:53 app/templates/pages/edit_user.html:61
+#: app/templates/pages/edit_profile.html:53
+#: app/templates/pages/edit_user.html:61
msgid "Gamertags for TRN"
msgstr "Gamertags for TRN"
#: app/templates/pages/edit_profile.html:54
-msgid "Enter your gamertag for each selected game to link to your Tracker Network profile."
-msgstr "Enter your gamertag for each selected game to link to your Tracker Network profile."
+msgid ""
+"Enter your gamertag for each selected game to link to your Tracker "
+"Network profile."
+msgstr ""
+"Enter your gamertag for each selected game to link to your Tracker "
+"Network profile."
-#: app/templates/pages/edit_profile.html:62 app/templates/pages/edit_user.html:70
-#: app/templates/pages/edit_user.html:71 app/templates/pages/view_user.html:58
+#: app/templates/pages/edit_profile.html:62
+#: app/templates/pages/edit_user.html:70 app/templates/pages/edit_user.html:71
+#: app/templates/pages/view_user.html:58
msgid "Gamertag"
msgstr "Gamertag"
-#: app/templates/pages/edit_profile.html:67 app/templates/pages/edit_user.html:75
-#: app/templates/pages/view_user.html:59
+#: app/templates/pages/edit_profile.html:67
+#: app/templates/pages/edit_user.html:75 app/templates/pages/view_user.html:59
msgid "Platform"
msgstr "Platform"
-#: app/templates/pages/edit_profile.html:69 app/templates/pages/edit_user.html:77
+#: app/templates/pages/edit_profile.html:69
+#: app/templates/pages/edit_user.html:77
msgid "Select Platform"
msgstr "Select Platform"
-#: app/templates/pages/edit_profile.html:83 app/templates/pages/edit_user.html:91
+#: app/templates/pages/edit_profile.html:83
+#: app/templates/pages/edit_user.html:91
msgid "Discord Username"
msgstr "Discord Username"
-#: app/templates/pages/edit_profile.html:84 app/templates/pages/edit_user.html:92
+#: app/templates/pages/edit_profile.html:84
+#: app/templates/pages/edit_user.html:92
msgid "e.g. Name#1234"
msgstr "e.g. Name#1234"
-#: app/templates/pages/edit_profile.html:87 app/templates/pages/edit_user.html:95
+#: app/templates/pages/edit_profile.html:87
+#: app/templates/pages/edit_user.html:95
msgid "(for DMs)"
msgstr "(for DMs)"
-#: app/templates/pages/edit_profile.html:88 app/templates/pages/edit_user.html:96
+#: app/templates/pages/edit_profile.html:88
+#: app/templates/pages/edit_user.html:96
msgid "Numeric ID (e.g. 123456789012345678)"
msgstr "Numeric ID (e.g. 123456789012345678)"
-#: app/templates/pages/edit_profile.html:89 app/templates/pages/edit_user.html:97
+#: app/templates/pages/edit_profile.html:89
+#: app/templates/pages/edit_user.html:97
msgid "Enable Developer Mode in Discord → Right-click profile → Copy ID"
msgstr "Enable Developer Mode in Discord → Right-click profile → Copy ID"
-#: app/templates/pages/edit_profile.html:94 app/templates/pages/edit_user.html:100
+#: app/templates/pages/edit_profile.html:94
+#: app/templates/pages/edit_user.html:100
msgid "League OS Connection"
msgstr "League OS Connection"
-#: app/templates/pages/edit_profile.html:95 app/templates/pages/edit_user.html:101
-#: app/templates/pages/register.html:131
+#: app/templates/pages/edit_profile.html:95
+#: app/templates/pages/edit_user.html:101 app/templates/pages/register.html:131
msgid "League OS profile link or ID"
msgstr "League OS profile link or ID"
@@ -1465,7 +1521,8 @@ msgstr "Leave blank to keep your current password."
msgid "New Password"
msgstr "New Password"
-#: app/templates/pages/edit_profile.html:104 app/templates/pages/edit_user.html:107
+#: app/templates/pages/edit_profile.html:104
+#: app/templates/pages/edit_user.html:107
msgid "Enter new password"
msgstr "Enter new password"
@@ -1498,8 +1555,12 @@ msgid "Player Evaluation"
msgstr "Player Evaluation"
#: app/templates/pages/evaluate_player.html:24
-msgid "You have already evaluated this player. Your previous scores are shown below."
-msgstr "You have already evaluated this player. Your previous scores are shown below."
+msgid ""
+"You have already evaluated this player. Your previous scores are shown "
+"below."
+msgstr ""
+"You have already evaluated this player. Your previous scores are shown "
+"below."
#: app/templates/pages/evaluate_player.html:33
msgid "Mecanics (1-10)"
@@ -1541,7 +1602,8 @@ msgstr "Mental (1-10)"
msgid "Recommended Position"
msgstr "Recommended Position"
-#: app/templates/pages/evaluate_player.html:109 app/templates/pages/view_tryout.html:274
+#: app/templates/pages/evaluate_player.html:109
+#: app/templates/pages/view_tryout.html:274
msgid "-- Select Position --"
msgstr "-- Select Position --"
@@ -1561,51 +1623,63 @@ msgstr "Enter your evaluation notes..."
msgid "Add note for this player"
msgstr "Add note for this player"
-#: app/templates/pages/evaluate_player.html:147 app/templates/pages/view_tryout.html:493
+#: app/templates/pages/evaluate_player.html:147
+#: app/templates/pages/view_tryout.html:493
msgid "Evaluator"
msgstr "Evaluator"
-#: app/templates/pages/evaluate_player.html:148 app/templates/pages/view_tryout.html:494
+#: app/templates/pages/evaluate_player.html:148
+#: app/templates/pages/view_tryout.html:494
msgid "Mecanics"
msgstr "Mecanics"
-#: app/templates/pages/evaluate_player.html:149 app/templates/pages/view_tryout.html:495
+#: app/templates/pages/evaluate_player.html:149
+#: app/templates/pages/view_tryout.html:495
msgid "Cohesion"
msgstr "Cohesion"
-#: app/templates/pages/evaluate_player.html:150 app/templates/pages/view_tryout.html:496
+#: app/templates/pages/evaluate_player.html:150
+#: app/templates/pages/view_tryout.html:496
msgid "Communication"
msgstr "Communication"
-#: app/templates/pages/evaluate_player.html:151 app/templates/pages/view_tryout.html:497
+#: app/templates/pages/evaluate_player.html:151
+#: app/templates/pages/view_tryout.html:497
msgid "Gamesense"
msgstr "Gamesense"
-#: app/templates/pages/evaluate_player.html:152 app/templates/pages/view_tryout.html:498
+#: app/templates/pages/evaluate_player.html:152
+#: app/templates/pages/view_tryout.html:498
msgid "Versatility"
msgstr "Versatility"
-#: app/templates/pages/evaluate_player.html:153 app/templates/pages/view_tryout.html:499
+#: app/templates/pages/evaluate_player.html:153
+#: app/templates/pages/view_tryout.html:499
msgid "Discipline"
msgstr "Discipline"
-#: app/templates/pages/evaluate_player.html:154 app/templates/pages/view_tryout.html:500
+#: app/templates/pages/evaluate_player.html:154
+#: app/templates/pages/view_tryout.html:500
msgid "Analysis"
msgstr "Analysis"
-#: app/templates/pages/evaluate_player.html:155 app/templates/pages/view_tryout.html:501
+#: app/templates/pages/evaluate_player.html:155
+#: app/templates/pages/view_tryout.html:501
msgid "Sport Ethics"
msgstr "Sport Ethics"
-#: app/templates/pages/evaluate_player.html:156 app/templates/pages/view_tryout.html:502
+#: app/templates/pages/evaluate_player.html:156
+#: app/templates/pages/view_tryout.html:502
msgid "Mental"
msgstr "Mental"
-#: app/templates/pages/evaluate_player.html:157 app/templates/pages/view_tryout.html:503
+#: app/templates/pages/evaluate_player.html:157
+#: app/templates/pages/view_tryout.html:503
msgid "Overall"
msgstr "Overall"
-#: app/templates/pages/evaluate_player.html:158 app/templates/pages/my_teams.html:54
+#: app/templates/pages/evaluate_player.html:158
+#: app/templates/pages/my_teams.html:54
#: app/templates/pages/view_tryout.html:280
msgid "Position"
msgstr "Position"
@@ -1654,7 +1728,8 @@ msgstr "Player vs Player"
msgid "Player Scrim"
msgstr "Player Scrim"
-#: app/templates/pages/match_form.html:48 app/templates/pages/team_match_form.html:17
+#: app/templates/pages/match_form.html:48
+#: app/templates/pages/team_match_form.html:17
msgid "Match Title"
msgstr "Match Title"
@@ -1662,21 +1737,25 @@ msgstr "Match Title"
msgid "e.g., Alpha vs Bravo Scrimmage"
msgstr "e.g., Alpha vs Bravo Scrimmage"
-#: app/templates/pages/match_form.html:62 app/templates/pages/team_match_form.html:63
+#: app/templates/pages/match_form.html:62
+#: app/templates/pages/team_match_form.html:63
msgid "Scheduled"
msgstr "Scheduled"
-#: app/templates/pages/match_form.html:63 app/templates/pages/team_match_form.html:64
+#: app/templates/pages/match_form.html:63
+#: app/templates/pages/team_match_form.html:64
#: app/templates/pages/view_tryout.html:23
msgid "Completed"
msgstr "Completed"
-#: app/templates/pages/match_form.html:64 app/templates/pages/team_match_form.html:65
+#: app/templates/pages/match_form.html:64
+#: app/templates/pages/team_match_form.html:65
msgid "Cancelled"
msgstr "Cancelled"
#: app/templates/pages/match_form.html:69 app/templates/pages/my_teams.html:94
-#: app/templates/pages/team_match_form.html:54 app/templates/pages/team_matches.html:30
+#: app/templates/pages/team_match_form.html:54
+#: app/templates/pages/team_matches.html:30
#: app/templates/pages/tryout_form.html:49
msgid "Location"
msgstr "Location"
@@ -1691,11 +1770,11 @@ msgstr "Select Match Time"
#: app/templates/pages/match_form.html:79
msgid ""
-"Click time slots consecutively to set match duration. Players available in all "
-"selected time blocks are shown below."
+"Click time slots consecutively to set match duration. Players available "
+"in all selected time blocks are shown below."
msgstr ""
-"Click time slots consecutively to set match duration. Players available in all "
-"selected time blocks are shown below."
+"Click time slots consecutively to set match duration. Players available "
+"in all selected time blocks are shown below."
#: app/templates/pages/match_form.html:80
msgid "Reset time selection"
@@ -1709,17 +1788,20 @@ msgstr "Reset Time"
msgid "Loading..."
msgstr "Loading..."
-#: app/templates/pages/match_form.html:103 app/templates/pages/one_on_one.html:140
+#: app/templates/pages/match_form.html:103
+#: app/templates/pages/one_on_one.html:140
#: app/templates/pages/team_match_form.html:40
msgid "Start Time"
msgstr "Start Time"
-#: app/templates/pages/match_form.html:107 app/templates/pages/one_on_one.html:146
+#: app/templates/pages/match_form.html:107
+#: app/templates/pages/one_on_one.html:146
#: app/templates/pages/team_match_form.html:45
msgid "End Time"
msgstr "End Time"
-#: app/templates/pages/match_form.html:114 app/templates/pages/tryout_form.html:103
+#: app/templates/pages/match_form.html:114
+#: app/templates/pages/tryout_form.html:103
msgid "Description"
msgstr "Description"
@@ -1731,7 +1813,8 @@ msgstr "Optional notes about this match"
msgid "Select Teams"
msgstr "Select Teams"
-#: app/templates/pages/match_form.html:125 app/templates/pages/match_form.html:219
+#: app/templates/pages/match_form.html:125
+#: app/templates/pages/match_form.html:219
msgid "Team 1"
msgstr "Team 1"
@@ -1739,7 +1822,8 @@ msgstr "Team 1"
msgid "-- Select Team 1 --"
msgstr "-- Select Team 1 --"
-#: app/templates/pages/match_form.html:134 app/templates/pages/match_form.html:231
+#: app/templates/pages/match_form.html:134
+#: app/templates/pages/match_form.html:231
msgid "Team 2"
msgstr "Team 2"
@@ -1747,16 +1831,18 @@ msgstr "Team 2"
msgid "-- Select Team 2 --"
msgstr "-- Select Team 2 --"
-#: app/templates/pages/match_form.html:158 app/templates/pages/match_form.html:184
+#: app/templates/pages/match_form.html:158
+#: app/templates/pages/match_form.html:184
msgid "Click to toggle presence"
msgstr "Click to toggle presence"
-#: app/templates/pages/match_form.html:164 app/templates/pages/match_form.html:190
-#: app/templates/pages/teams.html:197
+#: app/templates/pages/match_form.html:164
+#: app/templates/pages/match_form.html:190 app/templates/pages/teams.html:197
msgid "No players assigned"
msgstr "No players assigned"
-#: app/templates/pages/match_form.html:201 app/templates/pages/match_form.html:243
+#: app/templates/pages/match_form.html:201
+#: app/templates/pages/match_form.html:243
msgid "Select Players"
msgstr "Select Players"
@@ -1773,8 +1859,12 @@ msgid "Select players then click Randomize to split them into teams."
msgstr "Select players then click Randomize to split them into teams."
#: app/templates/pages/match_form.html:226
-msgid "All registered players are shown. Click time slots to filter available players."
-msgstr "All registered players are shown. Click time slots to filter available players."
+msgid ""
+"All registered players are shown. Click time slots to filter available "
+"players."
+msgstr ""
+"All registered players are shown. Click time slots to filter available "
+"players."
#: app/templates/pages/match_form.html:246
msgid "Green indicators show player availability for the match date/time"
@@ -1819,13 +1909,16 @@ msgid "No players on this team."
msgstr "No players on this team."
#: app/templates/pages/my_teams.html:93 app/templates/pages/notes.html:124
-#: app/templates/pages/one_on_one.html:71 app/templates/pages/team_matches.html:29
+#: app/templates/pages/one_on_one.html:71
+#: app/templates/pages/team_matches.html:29
#: app/templates/pages/view_tryout.html:319
msgid "Time"
msgstr "Time"
-#: app/templates/pages/my_teams.html:95 app/templates/pages/team_match_form.html:115
-#: app/templates/pages/team_matches.html:31 app/templates/pages/view_tryout.html:320
+#: app/templates/pages/my_teams.html:95
+#: app/templates/pages/team_match_form.html:115
+#: app/templates/pages/team_matches.html:31
+#: app/templates/pages/view_tryout.html:320
msgid "Presence"
msgstr "Presence"
@@ -1851,8 +1944,8 @@ msgid "Notes"
msgstr "Notes"
#: app/templates/pages/notes.html:12 app/templates/pages/one_on_one.html:11
-#: app/templates/pages/player_personal_notes.html:55 app/templates/pages/team_notes.html:2
-#: app/templates/pages/team_notes.html:3
+#: app/templates/pages/player_personal_notes.html:55
+#: app/templates/pages/team_notes.html:2 app/templates/pages/team_notes.html:3
msgid "Team Notes"
msgstr "Team Notes"
@@ -1890,8 +1983,12 @@ msgid "Context (Optional)"
msgstr "Context (Optional)"
#: app/templates/pages/notes.html:65
-msgid "Link this note to a specific match, tryout, or team for better organization."
-msgstr "Link this note to a specific match, tryout, or team for better organization."
+msgid ""
+"Link this note to a specific match, tryout, or team for better "
+"organization."
+msgstr ""
+"Link this note to a specific match, tryout, or team for better "
+"organization."
#: app/templates/pages/notes.html:71
msgid "-- Select Match --"
@@ -1957,15 +2054,18 @@ msgstr "Content Preview"
msgid "Recent Personal Notes"
msgstr "Recent Personal Notes"
-#: app/templates/pages/notes.html:243 app/templates/pages/player_personal_notes.html:27
+#: app/templates/pages/notes.html:243
+#: app/templates/pages/player_personal_notes.html:27
msgid "From match"
msgstr "From match"
-#: app/templates/pages/notes.html:246 app/templates/pages/player_personal_notes.html:32
+#: app/templates/pages/notes.html:246
+#: app/templates/pages/player_personal_notes.html:32
msgid "From team"
msgstr "From team"
-#: app/templates/pages/notes.html:249 app/templates/pages/player_personal_notes.html:37
+#: app/templates/pages/notes.html:249
+#: app/templates/pages/player_personal_notes.html:37
msgid "From tryout"
msgstr "From tryout"
@@ -1973,23 +2073,30 @@ msgstr "From tryout"
msgid "One on One"
msgstr "One on One"
-#: app/templates/pages/one_on_one.html:28 app/templates/pages/player_personal_notes.html:72
-msgid "No team notes have been added yet. Your coach will post improvement suggestions here."
-msgstr "No team notes have been added yet. Your coach will post improvement suggestions here."
+#: app/templates/pages/one_on_one.html:28
+#: app/templates/pages/player_personal_notes.html:72
+msgid ""
+"No team notes have been added yet. Your coach will post improvement "
+"suggestions here."
+msgstr ""
+"No team notes have been added yet. Your coach will post improvement "
+"suggestions here."
-#: app/templates/pages/one_on_one.html:36 app/templates/pages/personal_notes.html:2
+#: app/templates/pages/one_on_one.html:36
+#: app/templates/pages/personal_notes.html:2
#: app/templates/pages/personal_notes.html:3
#: app/templates/pages/player_personal_notes.html:11
msgid "Personal Notes"
msgstr "Personal Notes"
-#: app/templates/pages/one_on_one.html:53 app/templates/pages/player_personal_notes.html:47
+#: app/templates/pages/one_on_one.html:53
+#: app/templates/pages/player_personal_notes.html:47
msgid ""
-"No personal notes have been added yet. Your coach may provide individual feedback "
-"here."
+"No personal notes have been added yet. Your coach may provide individual "
+"feedback here."
msgstr ""
-"No personal notes have been added yet. Your coach may provide individual feedback "
-"here."
+"No personal notes have been added yet. Your coach may provide individual "
+"feedback here."
#: app/templates/pages/one_on_one.html:62
msgid "My One on One Requests"
@@ -2024,7 +2131,8 @@ msgstr "Select Date"
msgid "-- Select Date First --"
msgstr "-- Select Date First --"
-#: app/templates/pages/one_on_one.html:148 app/templates/pages/one_on_one.html:271
+#: app/templates/pages/one_on_one.html:148
+#: app/templates/pages/one_on_one.html:271
msgid "-- Select Start Time First --"
msgstr "-- Select Start Time First --"
@@ -2037,8 +2145,12 @@ msgid "Send Request"
msgstr "Send Request"
#: app/templates/pages/one_on_one.html:165
-msgid "You need to be assigned to a team with a coach to request a One on One session."
-msgstr "You need to be assigned to a team with a coach to request a One on One session."
+msgid ""
+"You need to be assigned to a team with a coach to request a One on One "
+"session."
+msgstr ""
+"You need to be assigned to a team with a coach to request a One on One "
+"session."
#: app/templates/pages/one_on_one.html:246
msgid "-- Select Start Time --"
@@ -2123,11 +2235,11 @@ msgstr "My Disponibilities"
#: app/templates/pages/profile.html:191
msgid ""
-"Select your available time blocks for matches (5pm to 12am). Green = selected, Gray ="
-" available to select."
+"Select your available time blocks for matches (5pm to 12am). Green = "
+"selected, Gray = available to select."
msgstr ""
-"Select your available time blocks for matches (5pm to 12am). Green = selected, Gray ="
-" available to select."
+"Select your available time blocks for matches (5pm to 12am). Green = "
+"selected, Gray = available to select."
#: app/templates/pages/profile.html:197
msgid "Save Disponibilities"
@@ -2138,8 +2250,12 @@ msgid "My Coaching Availability"
msgstr "My Coaching Availability"
#: app/templates/pages/profile.html:212
-msgid "Select time slots when you're available for One on One sessions (8am to 10pm)."
-msgstr "Select time slots when you're available for One on One sessions (8am to 10pm)."
+msgid ""
+"Select time slots when you're available for One on One sessions (8am to "
+"10pm)."
+msgstr ""
+"Select time slots when you're available for One on One sessions (8am to "
+"10pm)."
#: app/templates/pages/profile.html:454
msgid "Click or click-and-drag to select your available hours"
@@ -2179,11 +2295,11 @@ msgstr "Discord Connection"
#: app/templates/pages/register.html:34
msgid ""
-"Connect your Discord account to automatically fill your gamertags from your connected"
-" game accounts."
+"Connect your Discord account to automatically fill your gamertags from "
+"your connected game accounts."
msgstr ""
-"Connect your Discord account to automatically fill your gamertags from your connected"
-" game accounts."
+"Connect your Discord account to automatically fill your gamertags from "
+"your connected game accounts."
#: app/templates/pages/register.html:52
msgid "Connected"
@@ -2194,8 +2310,12 @@ msgid "Reconnect"
msgstr "Reconnect"
#: app/templates/pages/register.html:63
-msgid "Discord connected. Game connections have been used to pre-fill your profile below."
-msgstr "Discord connected. Game connections have been used to pre-fill your profile below."
+msgid ""
+"Discord connected. Game connections have been used to pre-fill your "
+"profile below."
+msgstr ""
+"Discord connected. Game connections have been used to pre-fill your "
+"profile below."
#: app/templates/pages/register.html:69
msgid "Connect Discord Account"
@@ -2285,7 +2405,8 @@ msgstr "Team Roster (auto-included)"
msgid "No players on this team. Add players in the Teams page first."
msgstr "No players on this team. Add players in the Teams page first."
-#: app/templates/pages/team_match_form.html:107 app/templates/pages/view_tryout.html:318
+#: app/templates/pages/team_match_form.html:107
+#: app/templates/pages/view_tryout.html:318
msgid "Participants"
msgstr "Participants"
@@ -2293,7 +2414,8 @@ msgstr "Participants"
msgid "No participants recorded."
msgstr "No participants recorded."
-#: app/templates/pages/team_matches.html:2 app/templates/pages/team_matches.html:3
+#: app/templates/pages/team_matches.html:2
+#: app/templates/pages/team_matches.html:3
msgid "Team Matches"
msgstr "Team Matches"
@@ -2371,7 +2493,8 @@ msgid "Create Team"
msgstr "Create Team"
#: app/templates/pages/teams.html:64 app/templates/pages/users.html:50
-#: app/templates/pages/view_tryout.html:29 app/templates/pages/view_tryout.html:453
+#: app/templates/pages/view_tryout.html:29
+#: app/templates/pages/view_tryout.html:453
msgid "Edit"
msgstr "Edit"
@@ -2483,7 +2606,8 @@ msgstr "Tryout Title"
msgid "e.g., Spring Season Tryouts"
msgstr "e.g., Spring Season Tryouts"
-#: app/templates/pages/tryout_form.html:29 app/templates/pages/view_user.html:57
+#: app/templates/pages/tryout_form.html:29
+#: app/templates/pages/view_user.html:57
msgid "Game"
msgstr "Game"
@@ -2584,7 +2708,8 @@ msgstr "Delete %(name)s? This cannot be undone."
msgid "Tryout Details"
msgstr "Tryout Details"
-#: app/templates/pages/view_tryout.html:14 app/templates/pages/view_tryout.html:300
+#: app/templates/pages/view_tryout.html:14
+#: app/templates/pages/view_tryout.html:300
msgid "Schedule Match"
msgstr "Schedule Match"
@@ -2594,11 +2719,11 @@ msgstr "In Progress"
#: app/templates/pages/view_tryout.html:33
msgid ""
-"Delete this entire tryout? This removes all its matches, teams, registrations and "
-"evaluations."
+"Delete this entire tryout? This removes all its matches, teams, "
+"registrations and evaluations."
msgstr ""
-"Delete this entire tryout? This removes all its matches, teams, registrations and "
-"evaluations."
+"Delete this entire tryout? This removes all its matches, teams, "
+"registrations and evaluations."
#: app/templates/pages/view_tryout.html:36
msgid "Delete Tryout"
@@ -2639,11 +2764,11 @@ msgstr "Evaluate player"
#: app/templates/pages/view_tryout.html:202
#, python-format
msgid ""
-"Remove %(name)s from this tryout? They will also be removed from every team and match"
-" within it."
+"Remove %(name)s from this tryout? They will also be removed from every "
+"team and match within it."
msgstr ""
-"Remove %(name)s from this tryout? They will also be removed from every team and match"
-" within it."
+"Remove %(name)s from this tryout? They will also be removed from every "
+"team and match within it."
#: app/templates/pages/view_tryout.html:204
msgid "Remove player from tryout"
@@ -2719,3 +2844,24 @@ msgstr "View Profile"
#~ msgid "One on One request from %(value)s has been approved!"
#~ msgstr ""
+#~ msgid ""
+#~ "Account is locked due to too many"
+#~ " failed attempts. Please try again in"
+#~ " %(remaining)s minute(s)."
+#~ msgstr ""
+#~ "Account is locked due to too many"
+#~ " failed attempts. Please try again in"
+#~ " %(remaining)s minute(s)."
+
+#~ msgid ""
+#~ "Account locked after %(attempts)s failed "
+#~ "attempts. Please try again in "
+#~ "%(minutes)s minutes."
+#~ msgstr ""
+#~ "Account locked after %(attempts)s failed "
+#~ "attempts. Please try again in "
+#~ "%(minutes)s minutes."
+
+#~ msgid "Login unsuccessful. %(remaining)s attempt(s) remaining before lockout."
+#~ msgstr "Login unsuccessful. %(remaining)s attempt(s) remaining before lockout."
+
diff --git a/app/translations/fr/LC_MESSAGES/messages.mo b/app/translations/fr/LC_MESSAGES/messages.mo
index 163ef8b..a128182 100644
Binary files a/app/translations/fr/LC_MESSAGES/messages.mo and b/app/translations/fr/LC_MESSAGES/messages.mo differ
diff --git a/app/translations/fr/LC_MESSAGES/messages.po b/app/translations/fr/LC_MESSAGES/messages.po
index f534e30..509c34d 100644
--- a/app/translations/fr/LC_MESSAGES/messages.po
+++ b/app/translations/fr/LC_MESSAGES/messages.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: team-tryouts VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2026-08-07 22:03-0400\n"
+"POT-Creation-Date: 2026-08-08 14:58-0400\n"
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
"Last-Translator: FULL NAME \n"
"Language: fr\n"
@@ -20,16 +20,18 @@ msgstr ""
"Generated-By: Babel 2.18.0\n"
#: app/validators.py:43
-msgid "Password must be at least 8 characters with uppercase, lowercase, and a number."
+msgid ""
+"Password must be at least 8 characters with uppercase, lowercase, and a "
+"number."
msgstr ""
-"Le mot de passe doit compter au moins 8 caractères, dont une majuscule, une minuscule"
-" et un chiffre."
+"Le mot de passe doit compter au moins 8 caractères, dont une majuscule, "
+"une minuscule et un chiffre."
#: app/validators.py:62
msgid "Username must be 3-30 characters (letters, numbers, underscore, hyphen)."
msgstr ""
-"Le nom d’utilisateur doit compter de 3 à 30 caractères (lettres, chiffres, tiret bas,"
-" trait d’union)."
+"Le nom d’utilisateur doit compter de 3 à 30 caractères (lettres, "
+"chiffres, tiret bas, trait d’union)."
#: app/validators.py:81
msgid "Invalid Discord username format."
@@ -59,7 +61,8 @@ msgstr "Le nom d’utilisateur doit compter de 3 à 80 caractères."
msgid "Email must be 120 characters or less."
msgstr "L’adresse courriel ne doit pas dépasser 120 caractères."
-#: app/validators.py:199 app/validators.py:266 app/validators.py:299 app/validators.py:365
+#: app/validators.py:199 app/validators.py:266 app/validators.py:299
+#: app/validators.py:365
msgid "Full name is required."
msgstr "Le nom complet est obligatoire."
@@ -99,97 +102,78 @@ msgstr "Les points ne doivent pas dépasser 2000 caractères."
msgid "Day must be 0 (Monday) to 6 (Sunday)."
msgstr "Le jour doit aller de 0 (lundi) à 6 (dimanche)."
-#: app/routes/auth.py:129 app/routes/auth.py:258 app/routes/users.py:46
-#: app/routes/users.py:649
+#: app/routes/auth.py:169 app/routes/auth.py:297 app/routes/users.py:49
+#: app/routes/users.py:653
#, python-format
msgid "%(field)s: %(msg)s"
msgstr "%(field)s : %(msg)s"
-#: app/routes/auth.py:141
-#, python-format
-msgid ""
-"Account is locked due to too many failed attempts. Please try again in %(remaining)s "
-"minute(s)."
-msgstr ""
-"Compte verrouillé après trop de tentatives échouées. Réessayez dans %(remaining)s "
-"minute(s)."
-
-#: app/routes/auth.py:151
+#: app/routes/auth.py:187
msgid "This account has been deactivated."
msgstr "Ce compte a été désactivé."
-#: app/routes/auth.py:179
+#: app/routes/auth.py:225
#, python-format
msgid "Welcome back, %(username)s!"
msgstr "Bon retour, %(username)s !"
-#: app/routes/auth.py:192
-#, python-format
+#: app/routes/auth.py:246
msgid ""
-"Account locked after %(attempts)s failed attempts. Please try again in %(minutes)s "
-"minutes."
+"Login unsuccessful. Please check your username and password, or ask a "
+"president for help."
msgstr ""
-"Compte verrouillé après %(attempts)s tentatives échouées. Réessayez dans %(minutes)s "
-"minutes."
+"Échec de la connexion. Vérifiez le nom d’utilisateur et le mot de passe, ou "
+"demandez de l’aide à un président."
-#: app/routes/auth.py:201
-#, python-format
-msgid "Login unsuccessful. %(remaining)s attempt(s) remaining before lockout."
-msgstr "Échec de la connexion. Il reste %(remaining)s tentative(s) avant le verrouillage."
-
-#: app/routes/auth.py:208
-msgid "Login unsuccessful. Please check username and password."
-msgstr "Échec de la connexion. Vérifiez le nom d’utilisateur et le mot de passe."
-
-#: app/routes/auth.py:239
+#: app/routes/auth.py:278
msgid "Incorrect CAPTCHA answer. Please try again."
msgstr "Réponse au CAPTCHA incorrecte. Veuillez réessayer."
-#: app/routes/auth.py:281 app/routes/users.py:317
+#: app/routes/auth.py:320 app/routes/users.py:336
msgid "Username already exists."
msgstr "Ce nom d’utilisateur est déjà pris."
-#: app/routes/auth.py:293 app/routes/users.py:321
+#: app/routes/auth.py:332 app/routes/users.py:340
msgid "Email already registered."
msgstr "Cette adresse courriel est déjà enregistrée."
-#: app/routes/auth.py:339
+#: app/routes/auth.py:378
msgid "Your account has been created! You can now log in."
msgstr "Votre compte a été créé. Vous pouvez maintenant vous connecter."
-#: app/routes/auth.py:365
+#: app/routes/auth.py:404
msgid "Discord OAuth2 is not configured."
msgstr "La connexion Discord n’est pas configurée."
-#: app/routes/auth.py:405
+#: app/routes/auth.py:444
msgid ""
-"Discord authorization could not be verified. Please start the connection again from "
-"this page."
+"Discord authorization could not be verified. Please start the connection "
+"again from this page."
msgstr ""
-"L’autorisation Discord n’a pas pu être vérifiée. Relancez la connexion depuis cette "
-"page."
+"L’autorisation Discord n’a pas pu être vérifiée. Relancez la connexion "
+"depuis cette page."
-#: app/routes/auth.py:413
+#: app/routes/auth.py:452
msgid "Discord authorization failed. No code received."
msgstr "L’autorisation Discord a échoué : aucun code reçu."
-#: app/routes/auth.py:437
+#: app/routes/auth.py:476
msgid "Failed to connect to Discord. Please try again."
msgstr "Impossible de joindre Discord. Veuillez réessayer."
-#: app/routes/auth.py:441
+#: app/routes/auth.py:480
msgid "Failed to obtain Discord access token."
msgstr "Impossible d’obtenir le jeton d’accès Discord."
-#: app/routes/auth.py:456
+#: app/routes/auth.py:495
msgid "Failed to fetch Discord user profile."
msgstr "Impossible de récupérer le profil Discord."
-#: app/routes/auth.py:503
+#: app/routes/auth.py:542
msgid "Discord account connected! Your profile has been pre-filled."
msgstr "Compte Discord connecté. Votre profil a été pré-rempli."
-#: app/routes/auth.py:521
+#: app/routes/auth.py:565
msgid "You have been logged out."
msgstr "Vous avez été déconnecté."
@@ -221,15 +205,16 @@ msgstr "Évaluation mise à jour."
msgid "Evaluation submitted successfully!"
msgstr "Évaluation enregistrée."
-#: app/routes/evaluations.py:215 app/routes/teams.py:249 app/routes/teams.py:280
-#: app/routes/teams.py:311 app/routes/teams.py:336 app/routes/teams.py:361
-#: app/routes/teams.py:393 app/routes/tryouts.py:341 app/routes/tryouts.py:357
-#: app/routes/tryouts.py:376 app/routes/tryouts.py:413 app/routes/tryouts.py:448
+#: app/routes/evaluations.py:215 app/routes/teams.py:236
+#: app/routes/teams.py:267 app/routes/teams.py:298 app/routes/teams.py:323
+#: app/routes/teams.py:348 app/routes/teams.py:380 app/routes/tryouts.py:341
+#: app/routes/tryouts.py:357 app/routes/tryouts.py:376
+#: app/routes/tryouts.py:413 app/routes/tryouts.py:448
#: app/routes/tryouts.py:467
msgid "Permission denied."
msgstr "Accès refusé."
-#: app/routes/main.py:43
+#: app/routes/main.py:44
msgid "That language is not available."
msgstr "Cette langue n’est pas disponible."
@@ -239,18 +224,20 @@ msgstr "Vous n’avez pas les droits pour planifier des matchs pour cette sélec
#: app/routes/matches.py:205 app/routes/matches.py:336
msgid "This tryout has ended. Matches can no longer be created or modified."
-msgstr "Cette sélection est terminée. Les matchs ne peuvent plus être créés ni modifiés."
+msgstr ""
+"Cette sélection est terminée. Les matchs ne peuvent plus être créés ni "
+"modifiés."
#: app/routes/matches.py:224
msgid "Start time is required. Please select a time slot."
msgstr "L’heure de début est obligatoire. Choisissez une plage horaire."
-#: app/routes/matches.py:231 app/routes/matches.py:359 app/routes/team_matches.py:139
-#: app/routes/team_matches.py:222
+#: app/routes/matches.py:231 app/routes/matches.py:359
+#: app/routes/team_matches.py:123 app/routes/team_matches.py:206
msgid "Invalid date format."
msgstr "Format de date invalide."
-#: app/routes/matches.py:246 app/routes/team_matches.py:156
+#: app/routes/matches.py:246 app/routes/team_matches.py:140
msgid "Invalid time format."
msgstr "Format d’heure invalide."
@@ -258,7 +245,7 @@ msgstr "Format d’heure invalide."
msgid "Match scheduled successfully!"
msgstr "Match planifié."
-#: app/routes/matches.py:332 app/routes/team_matches.py:209
+#: app/routes/matches.py:332 app/routes/team_matches.py:193
msgid "You do not have permission to edit this match."
msgstr "Vous n’avez pas les droits pour modifier ce match."
@@ -266,11 +253,11 @@ msgstr "Vous n’avez pas les droits pour modifier ce match."
msgid "Start time is required."
msgstr "L’heure de début est obligatoire."
-#: app/routes/matches.py:461 app/routes/team_matches.py:245
+#: app/routes/matches.py:461 app/routes/team_matches.py:229
msgid "Match updated successfully!"
msgstr "Match mis à jour."
-#: app/routes/matches.py:506 app/routes/team_matches.py:259
+#: app/routes/matches.py:506 app/routes/team_matches.py:243
msgid "You do not have permission to delete this match."
msgstr "Vous n’avez pas les droits pour supprimer ce match."
@@ -278,158 +265,158 @@ msgstr "Vous n’avez pas les droits pour supprimer ce match."
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."
-#: app/routes/matches.py:521 app/routes/team_matches.py:263
+#: app/routes/matches.py:521 app/routes/team_matches.py:247
msgid "Match deleted successfully."
msgstr "Match supprimé."
-#: app/routes/team_matches.py:97
+#: app/routes/team_matches.py:81
msgid "You do not have permission to schedule matches for this team."
msgstr "Vous n’avez pas les droits pour planifier des matchs pour cette équipe."
-#: app/routes/team_matches.py:132
+#: app/routes/team_matches.py:116
msgid "Date is required."
msgstr "La date est obligatoire."
-#: app/routes/team_matches.py:195
+#: app/routes/team_matches.py:179
#, python-format
msgid "Team match \"%(title)s\" scheduled successfully!"
msgstr "Match d’équipe « %(title)s » planifié."
-#: app/routes/teams.py:43
+#: app/routes/teams.py:28
msgid "Use My Team(s) to view your teams."
msgstr "Utilisez « Mon ou mes équipes » pour consulter vos équipes."
-#: app/routes/teams.py:46
+#: app/routes/teams.py:31
msgid "You do not have permission to view teams."
msgstr "Vous n’avez pas les droits pour consulter les équipes."
-#: app/routes/teams.py:61
+#: app/routes/teams.py:48
msgid "This page is for players."
msgstr "Cette page est réservée aux joueurs."
-#: app/routes/teams.py:103
+#: app/routes/teams.py:90
msgid "You do not have permission to create teams."
msgstr "Vous n’avez pas les droits pour créer une équipe."
-#: app/routes/teams.py:111 app/routes/teams.py:156
+#: app/routes/teams.py:98 app/routes/teams.py:143
msgid "Team name is required."
msgstr "Le nom de l’équipe est obligatoire."
-#: app/routes/teams.py:116 app/routes/teams.py:161
+#: app/routes/teams.py:103 app/routes/teams.py:148
#, python-format
msgid "Team \"%(name)s\" already exists."
msgstr "L’équipe « %(name)s » existe déjà."
-#: app/routes/teams.py:138
+#: app/routes/teams.py:125
#, python-format
msgid "Team \"%(name)s\" created successfully!"
msgstr "Équipe « %(name)s » créée."
-#: app/routes/teams.py:148
+#: app/routes/teams.py:135
msgid "You do not have permission to edit this team."
msgstr "Vous n’avez pas les droits pour modifier cette équipe."
-#: app/routes/teams.py:199
+#: app/routes/teams.py:186
#, python-format
msgid "Team \"%(name)s\" updated successfully!"
msgstr "Équipe « %(name)s » mise à jour."
-#: app/routes/teams.py:208
+#: app/routes/teams.py:195
msgid "You do not have permission to delete teams."
msgstr "Vous n’avez pas les droits pour supprimer une équipe."
-#: app/routes/teams.py:239
+#: app/routes/teams.py:226
#, python-format
msgid "Team \"%(name)s\" deleted successfully."
msgstr "Équipe « %(name)s » supprimée."
-#: app/routes/teams.py:254
+#: app/routes/teams.py:241
msgid "Please select a coach."
msgstr "Veuillez choisir un coach."
-#: app/routes/teams.py:259
+#: app/routes/teams.py:246
msgid "Only coaches can be assigned as coach."
msgstr "Seuls les coachs peuvent être assignés comme coach."
-#: app/routes/teams.py:263
+#: app/routes/teams.py:250
#, python-format
msgid "%(username)s is already a coach of %(name)s."
msgstr "%(username)s est déjà coach de %(name)s."
-#: app/routes/teams.py:270
+#: app/routes/teams.py:257
#, python-format
msgid "%(username)s added as coach of %(name)s."
msgstr "%(username)s a été ajouté comme coach de %(name)s."
-#: app/routes/teams.py:285
+#: app/routes/teams.py:272
msgid "Please select a manager."
msgstr "Veuillez choisir un gérant."
-#: app/routes/teams.py:290
+#: app/routes/teams.py:277
msgid "Only managers can be assigned as manager."
msgstr "Seuls les gérants peuvent être assignés comme gérant."
-#: app/routes/teams.py:294
+#: app/routes/teams.py:281
#, python-format
msgid "%(username)s is already a manager of %(name)s."
msgstr "%(username)s est déjà gérant de %(name)s."
-#: app/routes/teams.py:301
+#: app/routes/teams.py:288
#, python-format
msgid "%(username)s added as manager of %(name)s."
msgstr "%(username)s a été ajouté comme gérant de %(name)s."
-#: app/routes/teams.py:326
+#: app/routes/teams.py:313
#, python-format
msgid "Coach removed from %(name)s."
msgstr "Coach retiré de %(name)s."
-#: app/routes/teams.py:351
+#: app/routes/teams.py:338
#, python-format
msgid "Manager removed from %(name)s."
msgstr "Gérant retiré de %(name)s."
-#: app/routes/teams.py:367 app/routes/tryouts.py:380 app/routes/tryouts.py:478
+#: app/routes/teams.py:354 app/routes/tryouts.py:380 app/routes/tryouts.py:478
msgid "Please select a player."
msgstr "Veuillez choisir un joueur."
-#: app/routes/teams.py:372
+#: app/routes/teams.py:359
msgid "Can only assign players to teams."
msgstr "Seuls des joueurs peuvent être assignés à une équipe."
-#: app/routes/teams.py:377
+#: app/routes/teams.py:364
#, python-format
msgid "%(username)s is already on %(name)s."
msgstr "%(username)s fait déjà partie de %(name)s."
-#: app/routes/teams.py:383
+#: app/routes/teams.py:370
#, python-format
msgid "%(username)s added to %(name)s!"
msgstr "%(username)s a été ajouté à %(name)s."
-#: app/routes/teams.py:399 app/routes/teams.py:462
+#: app/routes/teams.py:386 app/routes/teams.py:449
#, python-format
msgid "%(username)s is not on %(name)s."
msgstr "%(username)s ne fait pas partie de %(name)s."
-#: app/routes/teams.py:404
+#: app/routes/teams.py:391
#, python-format
msgid "%(username)s removed from %(name)s."
msgstr "%(username)s a été retiré de %(name)s."
-#: app/routes/teams.py:434 app/routes/teams.py:452
+#: app/routes/teams.py:421 app/routes/teams.py:439
msgid "You do not have permission to add notes to this team."
msgstr "Vous n’avez pas les droits pour ajouter des notes à cette équipe."
-#: app/routes/teams.py:442
+#: app/routes/teams.py:429
msgid "Team notes added successfully!"
msgstr "Notes d’équipe ajoutées."
-#: app/routes/teams.py:457 app/routes/users.py:1227 app/routes/users.py:1269
+#: app/routes/teams.py:444 app/routes/users.py:1241 app/routes/users.py:1283
msgid "Can only add notes for players."
msgstr "Il n’est possible d’ajouter des notes que pour des joueurs."
-#: app/routes/teams.py:470
+#: app/routes/teams.py:457
#, python-format
msgid "Note added for %(username)s!"
msgstr "Note ajoutée pour %(username)s."
@@ -543,11 +530,11 @@ msgstr "Vous n’avez pas les droits pour supprimer cette sélection."
msgid "Tryout deleted successfully."
msgstr "Sélection supprimée."
-#: app/routes/users.py:116
+#: app/routes/users.py:119
msgid "Only the president can manage users."
msgstr "Seul le président peut gérer les utilisateurs."
-#: app/routes/users.py:128
+#: app/routes/users.py:131
msgid "Only the president can edit users."
msgstr "Seul le président peut modifier des utilisateurs."
@@ -555,193 +542,197 @@ msgstr "Seul le président peut modifier des utilisateurs."
msgid "Email already in use by another account."
msgstr "Cette adresse courriel est déjà utilisée par un autre compte."
-#: app/routes/users.py:175
+#: app/routes/users.py:178
msgid "You cannot change your own role. Ask another president to do it."
msgstr ""
-"Vous ne pouvez pas modifier votre propre rôle. Demandez à un autre président de le "
-"faire."
+"Vous ne pouvez pas modifier votre propre rôle. Demandez à un autre "
+"président de le faire."
-#: app/routes/users.py:186
-msgid "This is the last active president. Promote another account before changing this one."
+#: app/routes/users.py:189
+msgid ""
+"This is the last active president. Promote another account before "
+"changing this one."
msgstr ""
-"C’est le dernier président actif. Promouvez un autre compte avant de modifier celui-"
-"ci."
+"C’est le dernier président actif. Promouvez un autre compte avant de "
+"modifier celui-ci."
-#: app/routes/users.py:232
+#: app/routes/users.py:251
#, python-format
msgid "User %(username)s updated successfully!"
msgstr "Utilisateur %(username)s mis à jour."
-#: app/routes/users.py:247
+#: app/routes/users.py:266
msgid "Only the president can delete users."
msgstr "Seul le président peut supprimer des utilisateurs."
-#: app/routes/users.py:251
+#: app/routes/users.py:270
msgid "You cannot delete your own account."
msgstr "Vous ne pouvez pas supprimer votre propre compte."
-#: app/routes/users.py:288
+#: app/routes/users.py:307
#, python-format
msgid "User %(deleted_username)s has been removed."
msgstr "L’utilisateur %(deleted_username)s a été supprimé."
-#: app/routes/users.py:297
+#: app/routes/users.py:316
msgid "Only the president can create users."
msgstr "Seul le président peut créer des utilisateurs."
-#: app/routes/users.py:336
+#: app/routes/users.py:355
#, python-format
msgid "User %(full_name)s created as %(role)s!"
msgstr "Utilisateur %(full_name)s créé avec le rôle %(role)s."
-#: app/routes/users.py:393
+#: app/routes/users.py:412
msgid "Username already taken."
msgstr "Ce nom d’utilisateur est déjà pris."
-#: app/routes/users.py:399
+#: app/routes/users.py:418
msgid "Email already in use."
msgstr "Cette adresse courriel est déjà utilisée."
-#: app/routes/users.py:424
+#: app/routes/users.py:443
msgid "Profile updated successfully!"
msgstr "Profil mis à jour."
-#: app/routes/users.py:629
+#: app/routes/users.py:641
msgid "Only presidents, managers, and coaches can upload contracts."
msgstr "Seuls les présidents, gérants et coachs peuvent téléverser un contrat."
-#: app/routes/users.py:656
+#: app/routes/users.py:660
msgid "You do not have permission to upload a contract for this player."
msgstr "Vous n’avez pas les droits pour téléverser un contrat pour ce joueur."
-#: app/routes/users.py:660 app/routes/users.py:665 app/routes/users.py:717
-#: app/routes/users.py:722
+#: app/routes/users.py:664 app/routes/users.py:669 app/routes/users.py:721
+#: app/routes/users.py:726
msgid "No file selected."
msgstr "Aucun fichier sélectionné."
-#: app/routes/users.py:668
+#: app/routes/users.py:672
msgid "Only PDF files are allowed for contracts."
msgstr "Seuls les fichiers PDF sont acceptés pour les contrats."
-#: app/routes/users.py:701
+#: app/routes/users.py:705
#, python-format
msgid "Contract uploaded successfully for %(username)s!"
msgstr "Contrat téléversé pour %(username)s."
-#: app/routes/users.py:713
+#: app/routes/users.py:717
msgid "Only the player can upload their signed contract."
msgstr "Seul le joueur peut téléverser son contrat signé."
-#: app/routes/users.py:733
+#: app/routes/users.py:737
msgid "Signed contract uploaded successfully!"
msgstr "Contrat signé téléversé."
-#: app/routes/users.py:743 app/routes/users.py:754
+#: app/routes/users.py:747 app/routes/users.py:758
msgid "You do not have permission to download this contract."
msgstr "Vous n’avez pas les droits pour télécharger ce contrat."
-#: app/routes/users.py:757
+#: app/routes/users.py:761
msgid "No signed contract available."
msgstr "Aucun contrat signé disponible."
-#: app/routes/users.py:824
+#: app/routes/users.py:828
msgid "Only players can request One on One sessions."
msgstr "Seuls les joueurs peuvent demander une rencontre individuelle."
-#: app/routes/users.py:832
+#: app/routes/users.py:841
msgid "You do not have a coach assigned to your team."
msgstr "Aucun coach n’est assigné à votre équipe."
-#: app/routes/users.py:859
+#: app/routes/users.py:868
msgid "Cannot request One on One - no coach assigned."
msgstr "Impossible de demander une rencontre : aucun coach assigné."
-#: app/routes/users.py:867
+#: app/routes/users.py:876
msgid "Invalid date or time format."
msgstr "Format de date ou d’heure invalide."
-#: app/routes/users.py:881
+#: app/routes/users.py:890
msgid "The requested time is not within the coach's availability."
msgstr "L’horaire demandé ne correspond à aucune disponibilité du coach."
-#: app/routes/users.py:904
+#: app/routes/users.py:913
msgid "Your One on One request has been submitted!"
msgstr "Votre demande de rencontre a été envoyée."
-#: app/routes/users.py:939
+#: app/routes/users.py:948
msgid "Only coaches can accept One on One requests."
msgstr "Seuls les coachs peuvent accepter une demande de rencontre."
-#: app/routes/users.py:945 app/routes/users.py:986
+#: app/routes/users.py:954 app/routes/users.py:995
msgid "This request is not for you."
msgstr "Cette demande ne vous est pas destinée."
-#: app/routes/users.py:949 app/routes/users.py:990
+#: app/routes/users.py:958 app/routes/users.py:999
msgid "This request has already been processed."
msgstr "Cette demande a déjà été traitée."
-#: app/routes/users.py:971
+#: app/routes/users.py:980
#, python-format
msgid "One on One request from %(player)s has been approved!"
msgstr "La demande de rencontre de %(player)s a été approuvée."
-#: app/routes/users.py:980
+#: app/routes/users.py:989
msgid "Only coaches can reject One on One requests."
msgstr "Seuls les coachs peuvent refuser une demande de rencontre."
-#: app/routes/users.py:1017
+#: app/routes/users.py:1026
#, python-format
msgid "One on One request from %(player)s has been rejected."
msgstr "La demande de rencontre de %(player)s a été refusée."
-#: app/routes/users.py:1030
+#: app/routes/users.py:1039
msgid "This page is for players only."
msgstr "Cette page est réservée aux joueurs."
-#: app/routes/users.py:1061
+#: app/routes/users.py:1070
msgid "Only coaches can manage availability."
msgstr "Seuls les coachs peuvent gérer leurs disponibilités."
-#: app/routes/users.py:1123
+#: app/routes/users.py:1132
msgid "Only coaches can access the notes dashboard."
msgstr "Seuls les coachs ont accès au tableau des notes."
-#: app/routes/users.py:1184
+#: app/routes/users.py:1196
msgid "Only coaches can manage team notes."
msgstr "Seuls les coachs peuvent gérer les notes d’équipe."
-#: app/routes/users.py:1189
+#: app/routes/users.py:1202
msgid "You are not assigned to a team."
msgstr "Vous n’êtes assigné à aucune équipe."
-#: app/routes/users.py:1201
+#: app/routes/users.py:1215
msgid "Team notes saved successfully!"
msgstr "Notes d’équipe enregistrées."
-#: app/routes/users.py:1215
+#: app/routes/users.py:1229
msgid "Only coaches can manage personal notes."
msgstr "Seuls les coachs peuvent gérer les notes personnelles."
-#: app/routes/users.py:1222 app/routes/users.py:1264 app/routes/users.py:1314
-#: app/routes/users.py:1365
+#: app/routes/users.py:1236 app/routes/users.py:1278 app/routes/users.py:1328
+#: app/routes/users.py:1379
msgid "Player and content are required."
msgstr "Le joueur et le contenu sont obligatoires."
-#: app/routes/users.py:1231 app/routes/users.py:1273 app/routes/users.py:1318
-#: app/routes/users.py:1369
+#: app/routes/users.py:1245 app/routes/users.py:1287 app/routes/users.py:1332
+#: app/routes/users.py:1383
msgid "You can only write notes about players you work with."
-msgstr "Vous ne pouvez écrire des notes que sur les joueurs avec qui vous travaillez."
+msgstr ""
+"Vous ne pouvez écrire des notes que sur les joueurs avec qui vous "
+"travaillez."
-#: app/routes/users.py:1241 app/routes/users.py:1286
+#: app/routes/users.py:1255 app/routes/users.py:1300
#, python-format
msgid "Note added for %(username)s."
msgstr "Note ajoutée pour %(username)s."
-#: app/routes/users.py:1254 app/routes/users.py:1299 app/routes/users.py:1349
+#: app/routes/users.py:1268 app/routes/users.py:1313 app/routes/users.py:1363
msgid "Only coaches can add personal notes."
msgstr "Seuls les coachs peuvent ajouter des notes personnelles."
-#: app/routes/users.py:1329 app/routes/users.py:1380
+#: app/routes/users.py:1343 app/routes/users.py:1394
msgid "Note added successfully."
msgstr "Note ajoutée."
@@ -759,9 +750,11 @@ msgstr "400 — Requête incorrecte"
#: app/templates/errors/400.html:10
msgid ""
-"The request could not be understood by the server. Please check your input and try "
-"again."
-msgstr "Le serveur n’a pas pu interpréter la requête. Vérifiez votre saisie et réessayez."
+"The request could not be understood by the server. Please check your "
+"input and try again."
+msgstr ""
+"Le serveur n’a pas pu interpréter la requête. Vérifiez votre saisie et "
+"réessayez."
#: app/templates/errors/400.html:12 app/templates/errors/403.html:12
#: app/templates/errors/429.html:12
@@ -782,11 +775,11 @@ msgstr "403 — Accès refusé"
#: app/templates/errors/403.html:10
msgid ""
-"You do not have permission to access this resource. If you believe this is an error, "
-"please contact an administrator."
+"You do not have permission to access this resource. If you believe this "
+"is an error, please contact an administrator."
msgstr ""
-"Vous n’avez pas les droits d’accès à cette ressource. Si vous pensez qu’il s’agit "
-"d’une erreur, contactez un administrateur."
+"Vous n’avez pas les droits d’accès à cette ressource. Si vous pensez "
+"qu’il s’agit d’une erreur, contactez un administrateur."
#: app/templates/errors/404.html:2
msgid "404 Not Found"
@@ -801,7 +794,9 @@ msgid "404 — Not Found"
msgstr "404 — Page introuvable"
#: app/templates/errors/404.html:10
-msgid "The page you are looking for does not exist. It may have been moved or deleted."
+msgid ""
+"The page you are looking for does not exist. It may have been moved or "
+"deleted."
msgstr "La page demandée n’existe pas. Elle a peut-être été déplacée ou supprimée."
#: app/templates/errors/404.html:12
@@ -821,10 +816,12 @@ msgid "429 — Too Many Requests"
msgstr "429 — Trop de requêtes"
#: app/templates/errors/429.html:10
-msgid "You have sent too many requests in a short period. Please wait a moment and try again."
+msgid ""
+"You have sent too many requests in a short period. Please wait a moment "
+"and try again."
msgstr ""
-"Vous avez envoyé trop de requêtes en peu de temps. Patientez un instant puis "
-"réessayez."
+"Vous avez envoyé trop de requêtes en peu de temps. Patientez un instant "
+"puis réessayez."
#: app/templates/errors/500.html:2
msgid "500 Server Error"
@@ -840,11 +837,11 @@ msgstr "500 — Erreur interne du serveur"
#: app/templates/errors/500.html:10
msgid ""
-"Something went wrong on our end. The error has been logged and will be investigated. "
-"Please try again later."
+"Something went wrong on our end. The error has been logged and will be "
+"investigated. Please try again later."
msgstr ""
-"Une erreur est survenue de notre côté. Elle a été journalisée et sera examinée. "
-"Veuillez réessayer dans un instant."
+"Une erreur est survenue de notre côté. Elle a été journalisée et sera "
+"examinée. Veuillez réessayer dans un instant."
#: app/templates/errors/500.html:12
msgid "Try Again"
@@ -870,7 +867,8 @@ msgid "Calendar"
msgstr "Calendrier"
#: app/templates/layouts/base.html:52 app/templates/pages/dashboard.html:43
-#: app/templates/pages/evaluations.html:2 app/templates/pages/evaluations.html:3
+#: app/templates/pages/evaluations.html:2
+#: app/templates/pages/evaluations.html:3
msgid "Evaluations"
msgstr "Évaluations"
@@ -888,7 +886,8 @@ msgstr "Gestion des équipes"
msgid "Manage Users"
msgstr "Gestion des utilisateurs"
-#: app/templates/layouts/base.html:83 app/templates/pages/player_personal_notes.html:2
+#: app/templates/layouts/base.html:83
+#: app/templates/pages/player_personal_notes.html:2
#: app/templates/pages/player_personal_notes.html:3
msgid "My Notes"
msgstr "Mes notes"
@@ -938,16 +937,19 @@ msgid "Add Personal Note"
msgstr "Ajouter une note personnelle"
#: app/templates/pages/add_note.html:47 app/templates/pages/contracts.html:25
-#: app/templates/pages/dashboard.html:249 app/templates/pages/dashboard.html:363
-#: app/templates/pages/my_teams.html:52 app/templates/pages/notes.html:122
+#: app/templates/pages/dashboard.html:249
+#: app/templates/pages/dashboard.html:363 app/templates/pages/my_teams.html:52
+#: app/templates/pages/notes.html:122
#: app/templates/pages/players_to_evaluate.html:16
-#: app/templates/pages/team_match_form.html:114 app/templates/pages/teams.html:145
-#: app/templates/pages/view_tryout.html:148 app/templates/pages/view_tryout.html:492
+#: app/templates/pages/team_match_form.html:114
+#: app/templates/pages/teams.html:145 app/templates/pages/view_tryout.html:148
+#: app/templates/pages/view_tryout.html:492
msgid "Player"
msgstr "Joueur"
#: app/templates/pages/add_note.html:49 app/templates/pages/teams.html:216
-#: app/templates/pages/upload_contract.html:18 app/templates/pages/view_tryout.html:124
+#: app/templates/pages/upload_contract.html:18
+#: app/templates/pages/view_tryout.html:124
msgid "-- Select a player --"
msgstr "-- Choisir un joueur --"
@@ -988,8 +990,10 @@ msgstr "-- Aucune équipe --"
msgid "Team Notes (Reference)"
msgstr "Notes d’équipe (référence)"
-#: app/templates/pages/add_note.html:120 app/templates/pages/evaluate_player.html:131
-#: app/templates/pages/notes.html:100 app/templates/pages/personal_notes.html:36
+#: app/templates/pages/add_note.html:120
+#: app/templates/pages/evaluate_player.html:131
+#: app/templates/pages/notes.html:100
+#: app/templates/pages/personal_notes.html:36
#: app/templates/pages/view_tryout.html:303
msgid "Add Note"
msgstr "Ajouter une note"
@@ -1070,11 +1074,13 @@ msgstr "Détail de l’événement"
msgid "Confirm"
msgstr "Confirmer"
-#: app/templates/pages/calendar.html:102 app/templates/pages/team_matches.html:102
+#: app/templates/pages/calendar.html:102
+#: app/templates/pages/team_matches.html:102
msgid "Delete Match"
msgstr "Supprimer le match"
-#: app/templates/pages/calendar.html:105 app/templates/pages/team_matches.html:97
+#: app/templates/pages/calendar.html:105
+#: app/templates/pages/team_matches.html:97
msgid "Edit Match"
msgstr "Modifier le match"
@@ -1093,19 +1099,24 @@ msgstr "Définir vos disponibilités hebdomadaires"
#: app/templates/pages/coach_availability.html:10
msgid "Select time slots when you're available for One on One sessions"
-msgstr "Choisissez les plages où vous êtes disponible pour des rencontres individuelles"
+msgstr ""
+"Choisissez les plages où vous êtes disponible pour des rencontres "
+"individuelles"
-#: app/templates/pages/coach_availability.html:14 app/templates/pages/profile.html:216
+#: app/templates/pages/coach_availability.html:14
+#: app/templates/pages/profile.html:216
msgid "Loading availability grid..."
msgstr "Chargement de la grille de disponibilités..."
-#: app/templates/pages/coach_availability.html:19 app/templates/pages/profile.html:200
-#: app/templates/pages/profile.html:220
+#: app/templates/pages/coach_availability.html:19
+#: app/templates/pages/profile.html:200 app/templates/pages/profile.html:220
msgid "Clear All"
msgstr "Tout effacer"
-#: app/templates/pages/contracts.html:9 app/templates/pages/upload_contract.html:2
-#: app/templates/pages/upload_contract.html:3 app/templates/pages/upload_contract.html:39
+#: app/templates/pages/contracts.html:9
+#: app/templates/pages/upload_contract.html:2
+#: app/templates/pages/upload_contract.html:3
+#: app/templates/pages/upload_contract.html:39
msgid "Upload Contract"
msgstr "Téléverser un contrat"
@@ -1123,14 +1134,17 @@ msgid "Contract"
msgstr "Contrat"
#: app/templates/pages/contracts.html:28 app/templates/pages/dashboard.html:95
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:175
-#: app/templates/pages/dashboard.html:202 app/templates/pages/dashboard.html:321
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:175
+#: app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:321
#: app/templates/pages/match_form.html:60 app/templates/pages/my_teams.html:53
#: app/templates/pages/notes.html:126 app/templates/pages/one_on_one.html:73
#: app/templates/pages/players_to_evaluate.html:19
-#: app/templates/pages/team_match_form.html:61 app/templates/pages/team_matches.html:32
-#: app/templates/pages/teams.html:146 app/templates/pages/users.html:23
-#: app/templates/pages/view_tryout.html:149 app/templates/pages/view_tryout.html:321
+#: app/templates/pages/team_match_form.html:61
+#: app/templates/pages/team_matches.html:32 app/templates/pages/teams.html:146
+#: app/templates/pages/users.html:23 app/templates/pages/view_tryout.html:149
+#: app/templates/pages/view_tryout.html:321
msgid "Status"
msgstr "Statut"
@@ -1139,7 +1153,8 @@ msgid "Uploaded"
msgstr "Téléversé le"
#: app/templates/pages/contracts.html:30 app/templates/pages/dashboard.html:175
-#: app/templates/pages/notes.html:127 app/templates/pages/players_to_evaluate.html:20
+#: app/templates/pages/notes.html:127
+#: app/templates/pages/players_to_evaluate.html:20
#: app/templates/pages/team_matches.html:33 app/templates/pages/teams.html:151
#: app/templates/pages/users.html:25 app/templates/pages/view_tryout.html:154
#: app/templates/pages/view_tryout.html:323
@@ -1172,35 +1187,43 @@ msgid "No contracts found"
msgstr "Aucun contrat"
#: app/templates/pages/contracts.html:74
-msgid "No contracts have been uploaded for you yet. Contact your coach or manager."
+msgid ""
+"No contracts have been uploaded for you yet. Contact your coach or "
+"manager."
msgstr ""
-"Aucun contrat n’a encore été téléversé pour vous. Contactez votre coach ou votre "
-"gérant."
+"Aucun contrat n’a encore été téléversé pour vous. Contactez votre coach "
+"ou votre gérant."
#: app/templates/pages/contracts.html:76
-msgid "No contracts have been uploaded yet. Upload a contract using the button above."
+msgid ""
+"No contracts have been uploaded yet. Upload a contract using the button "
+"above."
msgstr "Aucun contrat n’a encore été téléversé. Utilisez le bouton ci-dessus."
#: app/templates/pages/contracts.html:96
msgid "Select Signed Contract File"
msgstr "Choisir le fichier du contrat signé"
-#: app/templates/pages/contracts.html:98 app/templates/pages/upload_contract.html:28
+#: app/templates/pages/contracts.html:98
+#: app/templates/pages/upload_contract.html:28
msgid "Accepted formats: PDF, DOC, DOCX, JPG, PNG"
msgstr "Formats acceptés : PDF, DOC, DOCX, JPG, PNG"
-#: app/templates/pages/contracts.html:101 app/templates/pages/match_form.html:265
-#: app/templates/pages/notes.html:189 app/templates/pages/teams.html:48
-#: app/templates/pages/teams.html:295 app/templates/pages/view_tryout.html:239
+#: app/templates/pages/contracts.html:101
+#: app/templates/pages/match_form.html:265 app/templates/pages/notes.html:189
+#: app/templates/pages/teams.html:48 app/templates/pages/teams.html:295
+#: app/templates/pages/view_tryout.html:239
msgid "Cancel"
msgstr "Annuler"
-#: app/templates/pages/create_user.html:2 app/templates/pages/create_user.html:3
+#: app/templates/pages/create_user.html:2
+#: app/templates/pages/create_user.html:3
#: app/templates/pages/create_user.html:47
msgid "Create User"
msgstr "Créer l’utilisateur"
-#: app/templates/pages/create_user.html:13 app/templates/pages/edit_profile.html:17
+#: app/templates/pages/create_user.html:13
+#: app/templates/pages/edit_profile.html:17
#: app/templates/pages/edit_user.html:13 app/templates/pages/register.html:10
msgid "Full Name"
msgstr "Nom complet"
@@ -1209,9 +1232,9 @@ msgstr "Nom complet"
msgid "Enter full name"
msgstr "Saisir le nom complet"
-#: app/templates/pages/create_user.html:17 app/templates/pages/edit_profile.html:13
-#: app/templates/pages/login.html:7 app/templates/pages/register.html:15
-#: app/templates/pages/users.html:20
+#: app/templates/pages/create_user.html:17
+#: app/templates/pages/edit_profile.html:13 app/templates/pages/login.html:7
+#: app/templates/pages/register.html:15 app/templates/pages/users.html:20
msgid "Username"
msgstr "Nom d’utilisateur"
@@ -1219,7 +1242,8 @@ msgstr "Nom d’utilisateur"
msgid "Choose username"
msgstr "Choisir un nom d’utilisateur"
-#: app/templates/pages/create_user.html:23 app/templates/pages/edit_profile.html:23
+#: app/templates/pages/create_user.html:23
+#: app/templates/pages/edit_profile.html:23
#: app/templates/pages/edit_user.html:17 app/templates/pages/register.html:20
#: app/templates/pages/teams.html:148 app/templates/pages/users.html:21
msgid "Email"
@@ -1229,7 +1253,8 @@ msgstr "Courriel"
msgid "Enter email"
msgstr "Saisir le courriel"
-#: app/templates/pages/create_user.html:27 app/templates/pages/edit_profile.html:27
+#: app/templates/pages/create_user.html:27
+#: app/templates/pages/edit_profile.html:27
#: app/templates/pages/edit_user.html:23 app/templates/pages/teams.html:149
msgid "Phone"
msgstr "Téléphone"
@@ -1238,8 +1263,9 @@ msgstr "Téléphone"
msgid "Phone number"
msgstr "Numéro de téléphone"
-#: app/templates/pages/create_user.html:31 app/templates/pages/dashboard.html:74
-#: app/templates/pages/edit_user.html:27 app/templates/pages/users.html:22
+#: app/templates/pages/create_user.html:31
+#: app/templates/pages/dashboard.html:74 app/templates/pages/edit_user.html:27
+#: app/templates/pages/users.html:22
msgid "Role"
msgstr "Rôle"
@@ -1268,7 +1294,8 @@ msgstr "Total des sélections"
msgid "Active Tryouts"
msgstr "Sélections en cours"
-#: app/templates/pages/dashboard.html:61 app/templates/pages/view_tryout.html:21
+#: app/templates/pages/dashboard.html:61
+#: app/templates/pages/view_tryout.html:21
msgid "Upcoming"
msgstr "À venir"
@@ -1293,38 +1320,45 @@ msgid "Title"
msgstr "Titre"
#: app/templates/pages/dashboard.html:95 app/templates/pages/dashboard.html:175
-#: app/templates/pages/dashboard.html:249 app/templates/pages/dashboard.html:321
+#: app/templates/pages/dashboard.html:249
+#: app/templates/pages/dashboard.html:321
#: app/templates/pages/match_form.html:55 app/templates/pages/my_teams.html:92
#: app/templates/pages/notes.html:123 app/templates/pages/one_on_one.html:70
-#: app/templates/pages/team_match_form.html:34 app/templates/pages/team_matches.html:28
+#: app/templates/pages/team_match_form.html:34
+#: app/templates/pages/team_matches.html:28
#: app/templates/pages/view_tryout.html:317
msgid "Date"
msgstr "Date"
-#: app/templates/pages/dashboard.html:114 app/templates/pages/dashboard.html:198
-#: app/templates/pages/my_teams.html:84
+#: app/templates/pages/dashboard.html:114
+#: app/templates/pages/dashboard.html:198 app/templates/pages/my_teams.html:84
msgid "Upcoming Matches"
msgstr "Matchs à venir"
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:202
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:90
#: app/templates/pages/notes.html:69 app/templates/pages/team_matches.html:25
#: app/templates/pages/teams.html:132 app/templates/pages/view_tryout.html:315
msgid "Match"
msgstr "Match"
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:202
-#: app/templates/pages/dashboard.html:249 app/templates/pages/dashboard.html:285
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:249
+#: app/templates/pages/dashboard.html:285
#: app/templates/pages/dashboard.html:321 app/templates/pages/notes.html:78
msgid "Tryout"
msgstr "Sélection"
-#: app/templates/pages/dashboard.html:118 app/templates/pages/dashboard.html:202
+#: app/templates/pages/dashboard.html:118
+#: app/templates/pages/dashboard.html:202
#: app/templates/pages/dashboard.html:285
msgid "Date & Time"
msgstr "Date et heure"
-#: app/templates/pages/dashboard.html:145 app/templates/pages/dashboard.html:169
+#: app/templates/pages/dashboard.html:145
+#: app/templates/pages/dashboard.html:169
#: app/templates/pages/dashboard.html:273
msgid "My Tryouts"
msgstr "Mes sélections"
@@ -1341,7 +1375,8 @@ msgstr "Mes évaluations"
msgid "Evaluations Done"
msgstr "Évaluations réalisées"
-#: app/templates/pages/dashboard.html:238 app/templates/pages/one_on_one.html:85
+#: app/templates/pages/dashboard.html:238
+#: app/templates/pages/one_on_one.html:85
msgid "Pending"
msgstr "En attente"
@@ -1386,17 +1421,19 @@ msgstr "Joueurs les mieux notés"
msgid "Avg Score"
msgstr "Note moyenne"
-#: app/templates/pages/dashboard.html:373 app/templates/pages/view_tryout.html:526
+#: app/templates/pages/dashboard.html:373
+#: app/templates/pages/view_tryout.html:526
msgid "No evaluations yet."
msgstr "Aucune évaluation pour l’instant."
-#: app/templates/pages/edit_profile.html:2 app/templates/pages/edit_profile.html:3
-#: app/templates/pages/profile.html:12
+#: app/templates/pages/edit_profile.html:2
+#: app/templates/pages/edit_profile.html:3 app/templates/pages/profile.html:12
msgid "Edit Profile"
msgstr "Modifier le profil"
-#: app/templates/pages/edit_profile.html:33 app/templates/pages/edit_user.html:43
-#: app/templates/pages/profile.html:63 app/templates/pages/register.html:83
+#: app/templates/pages/edit_profile.html:33
+#: app/templates/pages/edit_user.html:43 app/templates/pages/profile.html:63
+#: app/templates/pages/register.html:83
msgid "E-Sports Profile"
msgstr "Profil e-sport"
@@ -1404,66 +1441,79 @@ msgstr "Profil e-sport"
msgid "Update your competitive gaming profile for tryouts."
msgstr "Mettez à jour votre profil de joueur compétitif pour les sélections."
-#: app/templates/pages/edit_profile.html:37 app/templates/pages/register.html:87
+#: app/templates/pages/edit_profile.html:37
+#: app/templates/pages/register.html:87
msgid "Games You Play"
msgstr "Jeux auxquels vous jouez"
-#: app/templates/pages/edit_profile.html:47 app/templates/pages/register.html:101
+#: app/templates/pages/edit_profile.html:47
+#: app/templates/pages/register.html:101
msgid "Select all games you're signing in for."
msgstr "Sélectionnez tous les jeux pour lesquels vous vous inscrivez."
-#: app/templates/pages/edit_profile.html:53 app/templates/pages/edit_user.html:61
+#: app/templates/pages/edit_profile.html:53
+#: app/templates/pages/edit_user.html:61
msgid "Gamertags for TRN"
msgstr "Pseudos pour Tracker Network"
#: app/templates/pages/edit_profile.html:54
-msgid "Enter your gamertag for each selected game to link to your Tracker Network profile."
+msgid ""
+"Enter your gamertag for each selected game to link to your Tracker "
+"Network profile."
msgstr ""
-"Saisissez votre pseudo pour chaque jeu sélectionné afin de le lier à votre profil "
-"Tracker Network."
+"Saisissez votre pseudo pour chaque jeu sélectionné afin de le lier à "
+"votre profil Tracker Network."
-#: app/templates/pages/edit_profile.html:62 app/templates/pages/edit_user.html:70
-#: app/templates/pages/edit_user.html:71 app/templates/pages/view_user.html:58
+#: app/templates/pages/edit_profile.html:62
+#: app/templates/pages/edit_user.html:70 app/templates/pages/edit_user.html:71
+#: app/templates/pages/view_user.html:58
msgid "Gamertag"
msgstr "Pseudo de jeu"
-#: app/templates/pages/edit_profile.html:67 app/templates/pages/edit_user.html:75
-#: app/templates/pages/view_user.html:59
+#: app/templates/pages/edit_profile.html:67
+#: app/templates/pages/edit_user.html:75 app/templates/pages/view_user.html:59
msgid "Platform"
msgstr "Plateforme"
-#: app/templates/pages/edit_profile.html:69 app/templates/pages/edit_user.html:77
+#: app/templates/pages/edit_profile.html:69
+#: app/templates/pages/edit_user.html:77
msgid "Select Platform"
msgstr "Choisir une plateforme"
-#: app/templates/pages/edit_profile.html:83 app/templates/pages/edit_user.html:91
+#: app/templates/pages/edit_profile.html:83
+#: app/templates/pages/edit_user.html:91
msgid "Discord Username"
msgstr "Nom d’utilisateur Discord"
-#: app/templates/pages/edit_profile.html:84 app/templates/pages/edit_user.html:92
+#: app/templates/pages/edit_profile.html:84
+#: app/templates/pages/edit_user.html:92
msgid "e.g. Name#1234"
msgstr "ex. : Nom#1234"
-#: app/templates/pages/edit_profile.html:87 app/templates/pages/edit_user.html:95
+#: app/templates/pages/edit_profile.html:87
+#: app/templates/pages/edit_user.html:95
msgid "(for DMs)"
msgstr "(pour les messages privés)"
-#: app/templates/pages/edit_profile.html:88 app/templates/pages/edit_user.html:96
+#: app/templates/pages/edit_profile.html:88
+#: app/templates/pages/edit_user.html:96
msgid "Numeric ID (e.g. 123456789012345678)"
msgstr "Identifiant numérique (ex. : 123456789012345678)"
-#: app/templates/pages/edit_profile.html:89 app/templates/pages/edit_user.html:97
+#: app/templates/pages/edit_profile.html:89
+#: app/templates/pages/edit_user.html:97
msgid "Enable Developer Mode in Discord → Right-click profile → Copy ID"
msgstr ""
-"Activez le mode développeur dans Discord → clic droit sur le profil → Copier "
-"l’identifiant"
+"Activez le mode développeur dans Discord → clic droit sur le profil → "
+"Copier l’identifiant"
-#: app/templates/pages/edit_profile.html:94 app/templates/pages/edit_user.html:100
+#: app/templates/pages/edit_profile.html:94
+#: app/templates/pages/edit_user.html:100
msgid "League OS Connection"
msgstr "Connexion League OS"
-#: app/templates/pages/edit_profile.html:95 app/templates/pages/edit_user.html:101
-#: app/templates/pages/register.html:131
+#: app/templates/pages/edit_profile.html:95
+#: app/templates/pages/edit_user.html:101 app/templates/pages/register.html:131
msgid "League OS profile link or ID"
msgstr "Lien ou identifiant du profil League OS"
@@ -1479,7 +1529,8 @@ msgstr "Laissez vide pour conserver votre mot de passe actuel."
msgid "New Password"
msgstr "Nouveau mot de passe"
-#: app/templates/pages/edit_profile.html:104 app/templates/pages/edit_user.html:107
+#: app/templates/pages/edit_profile.html:104
+#: app/templates/pages/edit_user.html:107
msgid "Enter new password"
msgstr "Saisir le nouveau mot de passe"
@@ -1512,8 +1563,12 @@ msgid "Player Evaluation"
msgstr "Évaluation du joueur"
#: app/templates/pages/evaluate_player.html:24
-msgid "You have already evaluated this player. Your previous scores are shown below."
-msgstr "Vous avez déjà évalué ce joueur. Vos notes précédentes sont affichées ci-dessous."
+msgid ""
+"You have already evaluated this player. Your previous scores are shown "
+"below."
+msgstr ""
+"Vous avez déjà évalué ce joueur. Vos notes précédentes sont affichées ci-"
+"dessous."
#: app/templates/pages/evaluate_player.html:33
msgid "Mecanics (1-10)"
@@ -1555,7 +1610,8 @@ msgstr "Mental (1-10)"
msgid "Recommended Position"
msgstr "Poste recommandé"
-#: app/templates/pages/evaluate_player.html:109 app/templates/pages/view_tryout.html:274
+#: app/templates/pages/evaluate_player.html:109
+#: app/templates/pages/view_tryout.html:274
msgid "-- Select Position --"
msgstr "-- Choisir un poste --"
@@ -1575,51 +1631,63 @@ msgstr "Vos notes d’évaluation..."
msgid "Add note for this player"
msgstr "Ajouter une note pour ce joueur"
-#: app/templates/pages/evaluate_player.html:147 app/templates/pages/view_tryout.html:493
+#: app/templates/pages/evaluate_player.html:147
+#: app/templates/pages/view_tryout.html:493
msgid "Evaluator"
msgstr "Évaluateur"
-#: app/templates/pages/evaluate_player.html:148 app/templates/pages/view_tryout.html:494
+#: app/templates/pages/evaluate_player.html:148
+#: app/templates/pages/view_tryout.html:494
msgid "Mecanics"
msgstr "Mécaniques"
-#: app/templates/pages/evaluate_player.html:149 app/templates/pages/view_tryout.html:495
+#: app/templates/pages/evaluate_player.html:149
+#: app/templates/pages/view_tryout.html:495
msgid "Cohesion"
msgstr "Cohésion"
-#: app/templates/pages/evaluate_player.html:150 app/templates/pages/view_tryout.html:496
+#: app/templates/pages/evaluate_player.html:150
+#: app/templates/pages/view_tryout.html:496
msgid "Communication"
msgstr "Communication"
-#: app/templates/pages/evaluate_player.html:151 app/templates/pages/view_tryout.html:497
+#: app/templates/pages/evaluate_player.html:151
+#: app/templates/pages/view_tryout.html:497
msgid "Gamesense"
msgstr "Sens du jeu"
-#: app/templates/pages/evaluate_player.html:152 app/templates/pages/view_tryout.html:498
+#: app/templates/pages/evaluate_player.html:152
+#: app/templates/pages/view_tryout.html:498
msgid "Versatility"
msgstr "Polyvalence"
-#: app/templates/pages/evaluate_player.html:153 app/templates/pages/view_tryout.html:499
+#: app/templates/pages/evaluate_player.html:153
+#: app/templates/pages/view_tryout.html:499
msgid "Discipline"
msgstr "Discipline"
-#: app/templates/pages/evaluate_player.html:154 app/templates/pages/view_tryout.html:500
+#: app/templates/pages/evaluate_player.html:154
+#: app/templates/pages/view_tryout.html:500
msgid "Analysis"
msgstr "Analyse"
-#: app/templates/pages/evaluate_player.html:155 app/templates/pages/view_tryout.html:501
+#: app/templates/pages/evaluate_player.html:155
+#: app/templates/pages/view_tryout.html:501
msgid "Sport Ethics"
msgstr "Éthique sportive"
-#: app/templates/pages/evaluate_player.html:156 app/templates/pages/view_tryout.html:502
+#: app/templates/pages/evaluate_player.html:156
+#: app/templates/pages/view_tryout.html:502
msgid "Mental"
msgstr "Mental"
-#: app/templates/pages/evaluate_player.html:157 app/templates/pages/view_tryout.html:503
+#: app/templates/pages/evaluate_player.html:157
+#: app/templates/pages/view_tryout.html:503
msgid "Overall"
msgstr "Global"
-#: app/templates/pages/evaluate_player.html:158 app/templates/pages/my_teams.html:54
+#: app/templates/pages/evaluate_player.html:158
+#: app/templates/pages/my_teams.html:54
#: app/templates/pages/view_tryout.html:280
msgid "Position"
msgstr "Poste"
@@ -1668,7 +1736,8 @@ msgstr "Joueur contre joueur"
msgid "Player Scrim"
msgstr "Scrim entre joueurs"
-#: app/templates/pages/match_form.html:48 app/templates/pages/team_match_form.html:17
+#: app/templates/pages/match_form.html:48
+#: app/templates/pages/team_match_form.html:17
msgid "Match Title"
msgstr "Titre du match"
@@ -1676,21 +1745,25 @@ msgstr "Titre du match"
msgid "e.g., Alpha vs Bravo Scrimmage"
msgstr "ex. : Scrim Alpha contre Bravo"
-#: app/templates/pages/match_form.html:62 app/templates/pages/team_match_form.html:63
+#: app/templates/pages/match_form.html:62
+#: app/templates/pages/team_match_form.html:63
msgid "Scheduled"
msgstr "Planifié"
-#: app/templates/pages/match_form.html:63 app/templates/pages/team_match_form.html:64
+#: app/templates/pages/match_form.html:63
+#: app/templates/pages/team_match_form.html:64
#: app/templates/pages/view_tryout.html:23
msgid "Completed"
msgstr "Terminé"
-#: app/templates/pages/match_form.html:64 app/templates/pages/team_match_form.html:65
+#: app/templates/pages/match_form.html:64
+#: app/templates/pages/team_match_form.html:65
msgid "Cancelled"
msgstr "Annulé"
#: app/templates/pages/match_form.html:69 app/templates/pages/my_teams.html:94
-#: app/templates/pages/team_match_form.html:54 app/templates/pages/team_matches.html:30
+#: app/templates/pages/team_match_form.html:54
+#: app/templates/pages/team_matches.html:30
#: app/templates/pages/tryout_form.html:49
msgid "Location"
msgstr "Lieu"
@@ -1705,11 +1778,12 @@ msgstr "Choisir l’heure du match"
#: app/templates/pages/match_form.html:79
msgid ""
-"Click time slots consecutively to set match duration. Players available in all "
-"selected time blocks are shown below."
+"Click time slots consecutively to set match duration. Players available "
+"in all selected time blocks are shown below."
msgstr ""
-"Cliquez des plages consécutives pour définir la durée du match. Les joueurs "
-"disponibles sur toutes les plages choisies apparaissent ci-dessous."
+"Cliquez des plages consécutives pour définir la durée du match. Les "
+"joueurs disponibles sur toutes les plages choisies apparaissent ci-"
+"dessous."
#: app/templates/pages/match_form.html:80
msgid "Reset time selection"
@@ -1723,17 +1797,20 @@ msgstr "Réinitialiser l’heure"
msgid "Loading..."
msgstr "Chargement..."
-#: app/templates/pages/match_form.html:103 app/templates/pages/one_on_one.html:140
+#: app/templates/pages/match_form.html:103
+#: app/templates/pages/one_on_one.html:140
#: app/templates/pages/team_match_form.html:40
msgid "Start Time"
msgstr "Heure de début"
-#: app/templates/pages/match_form.html:107 app/templates/pages/one_on_one.html:146
+#: app/templates/pages/match_form.html:107
+#: app/templates/pages/one_on_one.html:146
#: app/templates/pages/team_match_form.html:45
msgid "End Time"
msgstr "Heure de fin"
-#: app/templates/pages/match_form.html:114 app/templates/pages/tryout_form.html:103
+#: app/templates/pages/match_form.html:114
+#: app/templates/pages/tryout_form.html:103
msgid "Description"
msgstr "Description"
@@ -1745,7 +1822,8 @@ msgstr "Notes facultatives sur ce match"
msgid "Select Teams"
msgstr "Choisir les équipes"
-#: app/templates/pages/match_form.html:125 app/templates/pages/match_form.html:219
+#: app/templates/pages/match_form.html:125
+#: app/templates/pages/match_form.html:219
msgid "Team 1"
msgstr "Équipe 1"
@@ -1753,7 +1831,8 @@ msgstr "Équipe 1"
msgid "-- Select Team 1 --"
msgstr "-- Choisir l’équipe 1 --"
-#: app/templates/pages/match_form.html:134 app/templates/pages/match_form.html:231
+#: app/templates/pages/match_form.html:134
+#: app/templates/pages/match_form.html:231
msgid "Team 2"
msgstr "Équipe 2"
@@ -1761,16 +1840,18 @@ msgstr "Équipe 2"
msgid "-- Select Team 2 --"
msgstr "-- Choisir l’équipe 2 --"
-#: app/templates/pages/match_form.html:158 app/templates/pages/match_form.html:184
+#: app/templates/pages/match_form.html:158
+#: app/templates/pages/match_form.html:184
msgid "Click to toggle presence"
msgstr "Cliquer pour basculer la présence"
-#: app/templates/pages/match_form.html:164 app/templates/pages/match_form.html:190
-#: app/templates/pages/teams.html:197
+#: app/templates/pages/match_form.html:164
+#: app/templates/pages/match_form.html:190 app/templates/pages/teams.html:197
msgid "No players assigned"
msgstr "Aucun joueur assigné"
-#: app/templates/pages/match_form.html:201 app/templates/pages/match_form.html:243
+#: app/templates/pages/match_form.html:201
+#: app/templates/pages/match_form.html:243
msgid "Select Players"
msgstr "Choisir des joueurs"
@@ -1785,20 +1866,22 @@ msgstr "Répartir au hasard"
#: app/templates/pages/match_form.html:214
msgid "Select players then click Randomize to split them into teams."
msgstr ""
-"Choisissez des joueurs puis cliquez sur « Répartir au hasard » pour former les "
-"équipes."
+"Choisissez des joueurs puis cliquez sur « Répartir au hasard » pour "
+"former les équipes."
#: app/templates/pages/match_form.html:226
-msgid "All registered players are shown. Click time slots to filter available players."
+msgid ""
+"All registered players are shown. Click time slots to filter available "
+"players."
msgstr ""
-"Tous les joueurs inscrits sont affichés. Cliquez des plages horaires pour filtrer "
-"ceux qui sont disponibles."
+"Tous les joueurs inscrits sont affichés. Cliquez des plages horaires pour"
+" filtrer ceux qui sont disponibles."
#: app/templates/pages/match_form.html:246
msgid "Green indicators show player availability for the match date/time"
msgstr ""
-"Les indicateurs verts signalent les joueurs disponibles à la date et à l’heure du "
-"match"
+"Les indicateurs verts signalent les joueurs disponibles à la date et à "
+"l’heure du match"
#: app/templates/pages/match_form.html:625
msgid "Click time slots consecutively to set match duration"
@@ -1839,13 +1922,16 @@ msgid "No players on this team."
msgstr "Aucun joueur dans cette équipe."
#: app/templates/pages/my_teams.html:93 app/templates/pages/notes.html:124
-#: app/templates/pages/one_on_one.html:71 app/templates/pages/team_matches.html:29
+#: app/templates/pages/one_on_one.html:71
+#: app/templates/pages/team_matches.html:29
#: app/templates/pages/view_tryout.html:319
msgid "Time"
msgstr "Heure"
-#: app/templates/pages/my_teams.html:95 app/templates/pages/team_match_form.html:115
-#: app/templates/pages/team_matches.html:31 app/templates/pages/view_tryout.html:320
+#: app/templates/pages/my_teams.html:95
+#: app/templates/pages/team_match_form.html:115
+#: app/templates/pages/team_matches.html:31
+#: app/templates/pages/view_tryout.html:320
msgid "Presence"
msgstr "Présence"
@@ -1871,8 +1957,8 @@ msgid "Notes"
msgstr "Notes"
#: app/templates/pages/notes.html:12 app/templates/pages/one_on_one.html:11
-#: app/templates/pages/player_personal_notes.html:55 app/templates/pages/team_notes.html:2
-#: app/templates/pages/team_notes.html:3
+#: app/templates/pages/player_personal_notes.html:55
+#: app/templates/pages/team_notes.html:2 app/templates/pages/team_notes.html:3
msgid "Team Notes"
msgstr "Notes d’équipe"
@@ -1910,8 +1996,12 @@ msgid "Context (Optional)"
msgstr "Contexte (facultatif)"
#: app/templates/pages/notes.html:65
-msgid "Link this note to a specific match, tryout, or team for better organization."
-msgstr "Liez cette note à un match, une sélection ou une équipe pour mieux vous y retrouver."
+msgid ""
+"Link this note to a specific match, tryout, or team for better "
+"organization."
+msgstr ""
+"Liez cette note à un match, une sélection ou une équipe pour mieux vous y"
+" retrouver."
#: app/templates/pages/notes.html:71
msgid "-- Select Match --"
@@ -1977,15 +2067,18 @@ msgstr "Aperçu du contenu"
msgid "Recent Personal Notes"
msgstr "Notes personnelles récentes"
-#: app/templates/pages/notes.html:243 app/templates/pages/player_personal_notes.html:27
+#: app/templates/pages/notes.html:243
+#: app/templates/pages/player_personal_notes.html:27
msgid "From match"
msgstr "Depuis le match"
-#: app/templates/pages/notes.html:246 app/templates/pages/player_personal_notes.html:32
+#: app/templates/pages/notes.html:246
+#: app/templates/pages/player_personal_notes.html:32
msgid "From team"
msgstr "Depuis l’équipe"
-#: app/templates/pages/notes.html:249 app/templates/pages/player_personal_notes.html:37
+#: app/templates/pages/notes.html:249
+#: app/templates/pages/player_personal_notes.html:37
msgid "From tryout"
msgstr "Depuis la sélection"
@@ -1993,25 +2086,30 @@ msgstr "Depuis la sélection"
msgid "One on One"
msgstr "Rencontre individuelle"
-#: app/templates/pages/one_on_one.html:28 app/templates/pages/player_personal_notes.html:72
-msgid "No team notes have been added yet. Your coach will post improvement suggestions here."
+#: app/templates/pages/one_on_one.html:28
+#: app/templates/pages/player_personal_notes.html:72
+msgid ""
+"No team notes have been added yet. Your coach will post improvement "
+"suggestions here."
msgstr ""
-"Aucune note d’équipe pour l’instant. Votre coach y publiera ses suggestions "
-"d’amélioration."
+"Aucune note d’équipe pour l’instant. Votre coach y publiera ses "
+"suggestions d’amélioration."
-#: app/templates/pages/one_on_one.html:36 app/templates/pages/personal_notes.html:2
+#: app/templates/pages/one_on_one.html:36
+#: app/templates/pages/personal_notes.html:2
#: app/templates/pages/personal_notes.html:3
#: app/templates/pages/player_personal_notes.html:11
msgid "Personal Notes"
msgstr "Notes personnelles"
-#: app/templates/pages/one_on_one.html:53 app/templates/pages/player_personal_notes.html:47
+#: app/templates/pages/one_on_one.html:53
+#: app/templates/pages/player_personal_notes.html:47
msgid ""
-"No personal notes have been added yet. Your coach may provide individual feedback "
-"here."
+"No personal notes have been added yet. Your coach may provide individual "
+"feedback here."
msgstr ""
-"Aucune note personnelle pour l’instant. Votre coach peut vous laisser des "
-"commentaires ici."
+"Aucune note personnelle pour l’instant. Votre coach peut vous laisser des"
+" commentaires ici."
#: app/templates/pages/one_on_one.html:62
msgid "My One on One Requests"
@@ -2046,7 +2144,8 @@ msgstr "Choisir une date"
msgid "-- Select Date First --"
msgstr "-- Choisissez d’abord une date --"
-#: app/templates/pages/one_on_one.html:148 app/templates/pages/one_on_one.html:271
+#: app/templates/pages/one_on_one.html:148
+#: app/templates/pages/one_on_one.html:271
msgid "-- Select Start Time First --"
msgstr "-- Choisissez d’abord l’heure de début --"
@@ -2059,10 +2158,12 @@ msgid "Send Request"
msgstr "Envoyer la demande"
#: app/templates/pages/one_on_one.html:165
-msgid "You need to be assigned to a team with a coach to request a One on One session."
+msgid ""
+"You need to be assigned to a team with a coach to request a One on One "
+"session."
msgstr ""
-"Vous devez être assigné à une équipe ayant un coach pour demander une rencontre "
-"individuelle."
+"Vous devez être assigné à une équipe ayant un coach pour demander une "
+"rencontre individuelle."
#: app/templates/pages/one_on_one.html:246
msgid "-- Select Start Time --"
@@ -2147,11 +2248,11 @@ msgstr "Mes disponibilités"
#: app/templates/pages/profile.html:191
msgid ""
-"Select your available time blocks for matches (5pm to 12am). Green = selected, Gray ="
-" available to select."
+"Select your available time blocks for matches (5pm to 12am). Green = "
+"selected, Gray = available to select."
msgstr ""
-"Choisissez vos plages disponibles pour les matchs (17 h à minuit). Vert = "
-"sélectionné, gris = disponible."
+"Choisissez vos plages disponibles pour les matchs (17 h à minuit). Vert ="
+" sélectionné, gris = disponible."
#: app/templates/pages/profile.html:197
msgid "Save Disponibilities"
@@ -2162,10 +2263,12 @@ msgid "My Coaching Availability"
msgstr "Mes disponibilités de coaching"
#: app/templates/pages/profile.html:212
-msgid "Select time slots when you're available for One on One sessions (8am to 10pm)."
+msgid ""
+"Select time slots when you're available for One on One sessions (8am to "
+"10pm)."
msgstr ""
-"Choisissez les plages où vous êtes disponible pour des rencontres individuelles (8 h "
-"à 22 h)."
+"Choisissez les plages où vous êtes disponible pour des rencontres "
+"individuelles (8 h à 22 h)."
#: app/templates/pages/profile.html:454
msgid "Click or click-and-drag to select your available hours"
@@ -2205,11 +2308,11 @@ msgstr "Connexion Discord"
#: app/templates/pages/register.html:34
msgid ""
-"Connect your Discord account to automatically fill your gamertags from your connected"
-" game accounts."
+"Connect your Discord account to automatically fill your gamertags from "
+"your connected game accounts."
msgstr ""
-"Connectez votre compte Discord pour remplir automatiquement vos pseudos à partir de "
-"vos comptes de jeu liés."
+"Connectez votre compte Discord pour remplir automatiquement vos pseudos à"
+" partir de vos comptes de jeu liés."
#: app/templates/pages/register.html:52
msgid "Connected"
@@ -2220,8 +2323,12 @@ msgid "Reconnect"
msgstr "Reconnecter"
#: app/templates/pages/register.html:63
-msgid "Discord connected. Game connections have been used to pre-fill your profile below."
-msgstr "Discord connecté. Vos comptes de jeu ont servi à pré-remplir le profil ci-dessous."
+msgid ""
+"Discord connected. Game connections have been used to pre-fill your "
+"profile below."
+msgstr ""
+"Discord connecté. Vos comptes de jeu ont servi à pré-remplir le profil "
+"ci-dessous."
#: app/templates/pages/register.html:69
msgid "Connect Discord Account"
@@ -2229,7 +2336,9 @@ msgstr "Connecter un compte Discord"
#: app/templates/pages/register.html:71
msgid "Connect to pre-fill your gamertags from Steam, Battle.net, Xbox, etc."
-msgstr "Connectez-vous pour pré-remplir vos pseudos depuis Steam, Battle.net, Xbox, etc."
+msgstr ""
+"Connectez-vous pour pré-remplir vos pseudos depuis Steam, Battle.net, "
+"Xbox, etc."
#: app/templates/pages/register.html:74
msgid "Discord Username (Manual)"
@@ -2311,7 +2420,8 @@ msgstr "Alignement (inclus automatiquement)"
msgid "No players on this team. Add players in the Teams page first."
msgstr "Aucun joueur dans cette équipe. Ajoutez-en d’abord depuis la page Équipes."
-#: app/templates/pages/team_match_form.html:107 app/templates/pages/view_tryout.html:318
+#: app/templates/pages/team_match_form.html:107
+#: app/templates/pages/view_tryout.html:318
msgid "Participants"
msgstr "Participants"
@@ -2319,7 +2429,8 @@ msgstr "Participants"
msgid "No participants recorded."
msgstr "Aucun participant enregistré."
-#: app/templates/pages/team_matches.html:2 app/templates/pages/team_matches.html:3
+#: app/templates/pages/team_matches.html:2
+#: app/templates/pages/team_matches.html:3
msgid "Team Matches"
msgstr "Matchs d’équipe"
@@ -2397,14 +2508,17 @@ msgid "Create Team"
msgstr "Créer l’équipe"
#: app/templates/pages/teams.html:64 app/templates/pages/users.html:50
-#: app/templates/pages/view_tryout.html:29 app/templates/pages/view_tryout.html:453
+#: app/templates/pages/view_tryout.html:29
+#: app/templates/pages/view_tryout.html:453
msgid "Edit"
msgstr "Modifier"
#: app/templates/pages/teams.html:66
#, python-format
msgid "Delete team %(name)s? It will be unassigned from any linked tryouts."
-msgstr "Supprimer l’équipe %(name)s ? Elle sera détachée de toutes les sélections liées."
+msgstr ""
+"Supprimer l’équipe %(name)s ? Elle sera détachée de toutes les sélections"
+" liées."
#: app/templates/pages/teams.html:69
msgid "Delete"
@@ -2496,14 +2610,14 @@ msgstr "Modifier l’équipe"
#: app/templates/pages/teams.html:280
msgid "Hold Ctrl/Cmd to select multiple. Only unassigned coaches shown."
msgstr ""
-"Maintenez Ctrl ou Cmd pour en choisir plusieurs. Seuls les coachs non assignés sont "
-"proposés."
+"Maintenez Ctrl ou Cmd pour en choisir plusieurs. Seuls les coachs non "
+"assignés sont proposés."
#: app/templates/pages/teams.html:291
msgid "Hold Ctrl/Cmd to select multiple. Only unassigned managers shown."
msgstr ""
-"Maintenez Ctrl ou Cmd pour en choisir plusieurs. Seuls les gérants non assignés sont "
-"proposés."
+"Maintenez Ctrl ou Cmd pour en choisir plusieurs. Seuls les gérants non "
+"assignés sont proposés."
#: app/templates/pages/tryout_form.html:23
msgid "Tryout Title"
@@ -2513,7 +2627,8 @@ msgstr "Titre de la sélection"
msgid "e.g., Spring Season Tryouts"
msgstr "ex. : Sélections de la saison printanière"
-#: app/templates/pages/tryout_form.html:29 app/templates/pages/view_user.html:57
+#: app/templates/pages/tryout_form.html:29
+#: app/templates/pages/view_user.html:57
msgid "Game"
msgstr "Jeu"
@@ -2614,7 +2729,8 @@ msgstr "Supprimer %(name)s ? Cette action est irréversible."
msgid "Tryout Details"
msgstr "Détail de la sélection"
-#: app/templates/pages/view_tryout.html:14 app/templates/pages/view_tryout.html:300
+#: app/templates/pages/view_tryout.html:14
+#: app/templates/pages/view_tryout.html:300
msgid "Schedule Match"
msgstr "Planifier un match"
@@ -2624,11 +2740,11 @@ msgstr "En cours"
#: app/templates/pages/view_tryout.html:33
msgid ""
-"Delete this entire tryout? This removes all its matches, teams, registrations and "
-"evaluations."
+"Delete this entire tryout? This removes all its matches, teams, "
+"registrations and evaluations."
msgstr ""
-"Supprimer entièrement cette sélection ? Cela supprime tous ses matchs, équipes, "
-"inscriptions et évaluations."
+"Supprimer entièrement cette sélection ? Cela supprime tous ses matchs, "
+"équipes, inscriptions et évaluations."
#: app/templates/pages/view_tryout.html:36
msgid "Delete Tryout"
@@ -2669,11 +2785,11 @@ msgstr "Évaluer le joueur"
#: app/templates/pages/view_tryout.html:202
#, python-format
msgid ""
-"Remove %(name)s from this tryout? They will also be removed from every team and match"
-" within it."
+"Remove %(name)s from this tryout? They will also be removed from every "
+"team and match within it."
msgstr ""
-"Retirer %(name)s de cette sélection ? Il sera aussi retiré de toutes ses équipes et "
-"de tous ses matchs."
+"Retirer %(name)s de cette sélection ? Il sera aussi retiré de toutes ses "
+"équipes et de tous ses matchs."
#: app/templates/pages/view_tryout.html:204
msgid "Remove player from tryout"
@@ -2749,3 +2865,27 @@ msgstr "Voir le profil"
#~ msgid "One on One request from %(value)s has been approved!"
#~ msgstr ""
+#~ msgid ""
+#~ "Account is locked due to too many"
+#~ " failed attempts. Please try again in"
+#~ " %(remaining)s minute(s)."
+#~ msgstr ""
+#~ "Compte verrouillé après trop de "
+#~ "tentatives échouées. Réessayez dans "
+#~ "%(remaining)s minute(s)."
+
+#~ msgid ""
+#~ "Account locked after %(attempts)s failed "
+#~ "attempts. Please try again in "
+#~ "%(minutes)s minutes."
+#~ msgstr ""
+#~ "Compte verrouillé après %(attempts)s "
+#~ "tentatives échouées. Réessayez dans "
+#~ "%(minutes)s minutes."
+
+#~ msgid "Login unsuccessful. %(remaining)s attempt(s) remaining before lockout."
+#~ msgstr ""
+#~ "Échec de la connexion. Il reste "
+#~ "%(remaining)s tentative(s) avant le "
+#~ "verrouillage."
+
diff --git a/tests/test_audit_logging.py b/tests/test_audit_logging.py
index a403f95..1bd9f11 100644
--- a/tests/test_audit_logging.py
+++ b/tests/test_audit_logging.py
@@ -70,7 +70,9 @@ class TestLoginEvents:
login('no-such-account', password='WrongPassword1')
assert _has_event(auth_log, 'login.failure.unknown_user')
- def test_a_lockout_is_recorded(self, app, client, make_user, login, auth_log):
+ def test_a_run_of_failures_is_recorded(self, app, client, make_user, login, auth_log):
+ """Renamed from account.locked with SEC-018: the window no longer
+ refuses the account owner, so 'locked' overstated what happened."""
user_id = make_user('player')
with app.app_context():
username = db.session.get(User, user_id).username
@@ -78,7 +80,7 @@ class TestLoginEvents:
for _ in range(5):
login(username, password='WrongPassword1')
- assert _has_event(auth_log, 'account.locked')
+ assert _has_event(auth_log, 'account.throttled')
def test_a_deactivated_account_attempt_is_recorded(
self, app, client, make_user, login, auth_log
@@ -96,7 +98,7 @@ class TestLoginEvents:
def test_logout_is_recorded(self, client, as_role, auth_log):
as_role('player')
- client.get('/auth/logout')
+ client.post('/auth/logout')
assert _has_event(auth_log, 'logout')
diff --git a/tests/test_auth_session.py b/tests/test_auth_session.py
index 3aace8d..4ad6e00 100644
--- a/tests/test_auth_session.py
+++ b/tests/test_auth_session.py
@@ -100,12 +100,44 @@ class TestLogout:
as_role('player')
assert client.get('/users/profile').status_code == 200
- client.get('/auth/logout')
+ client.post('/auth/logout')
response = client.get('/users/profile', follow_redirects=False)
assert response.status_code in (301, 302)
assert '/auth/login' in response.headers.get('Location', '')
+ def test_a_get_no_longer_logs_anyone_out(self, client, as_role):
+ """SEC-019 — a GET route carries no CSRF token, so any page could
+ sign the user out with
."""
+ as_role('player')
+
+ assert client.get('/auth/logout').status_code == 405
+ assert client.get('/users/profile').status_code == 200
+
+ def test_the_logout_control_carries_a_csrf_token(self, app_with_csrf, make_user, login):
+ """The nav entry is a form now; without the token it would 400 on
+ every user, and only in production where CSRF is on."""
+ client = app_with_csrf.test_client()
+ with app_with_csrf.app_context():
+ from app.extensions import hash_password
+ from app.models import Player
+ user = Player(username='navtest', password_hash=hash_password('Password123'),
+ role='player', full_name='Nav Test', email='nav@example.test')
+ db.session.add(user)
+ db.session.commit()
+
+ page = client.get('/auth/login').get_data(as_text=True)
+ token = re.search(r'name="csrf_token" value="([^"]+)"', page).group(1)
+ client.post('/auth/login', data={'username': 'navtest',
+ 'password': 'Password123',
+ 'csrf_token': token})
+
+ body = client.get('/users/profile').get_data(as_text=True)
+ form = re.search(
+ r'