feat(perf): borner les vues de liste, et choisir le motif une bonne fois
MNT-14. Chaque vue de liste faisait .all() sur sa table. L'audit evaluait l'impact a nul -- justement, a l'echelle d'une association etudiante -- et recommandait de choisir le motif maintenant plutot que de le retro-adapter plus tard. C'est ce que ceci est. Applique a list_users, list_evaluations et team_matches.list_matches. Pour cette derniere, la pagination borne aussi la boucle sur les participants, qui est le N+1 que le constat designait comme le premier a se degrader. Trois decisions, parce que ce sont celles qui se prennent deux fois differemment sinon. error_out=False : les numeros de page arrivent par l'URL, donc ?page=999 est une chose qu'on tape ou qu'un signet perime contient. Le defaut de Flask-SQLAlchemy y repond par un 404, ce qui est deroutant pour quelqu'un qui est simplement alle une page trop loin. Un plafond sur per_page : c'est aussi un parametre d'URL, et sans plafond ?per_page=100000 redonne a la main exactement la requete non bornee que la pagination existe pour empecher. page_url est un global Jinja plutot qu'une valeur que chaque vue passe. Ce qui se rate avec des liens de pagination, c'est le reste de la chaine de requete : la liste d'evaluations porte sort et order, celle des matchs d'equipe porte team_id, et un lien qui les perd reinitialise silencieusement la vue que la personne regardait. Les deux tests qui l'epinglent tombent si page_url cesse de les recopier -- verifie par mutation. Les tris sont completes par une cle unique : une requete paginee sans ORDER BY stable peut montrer la meme ligne deux fois et jamais une autre. Au passage, huit entrees fuzzy corrigees dans les catalogues, dont deux laissees par le commit SEC-16 : une entree fuzzy est ignoree a l'execution, donc ces messages retombaient en anglais. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -27,6 +27,7 @@ from werkzeug.exceptions import HTTPException
|
|||||||
|
|
||||||
from app import i18n
|
from app import i18n
|
||||||
from app.extensions import babel, csrf, db, limiter, login_manager
|
from app.extensions import babel, csrf, db, limiter, login_manager
|
||||||
|
from app.pagination import page_url
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -391,6 +392,12 @@ def create_app(config=None):
|
|||||||
'locale_names': i18n.LOCALE_NAMES,
|
'locale_names': i18n.LOCALE_NAMES,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Used by layouts/_pagination.html. A global rather than something each
|
||||||
|
# listing passes, because the thing that goes wrong with pagination links
|
||||||
|
# is dropping the rest of the query string — `sort`, `order`, `team_id` —
|
||||||
|
# and that is easier to get right once than in four templates (MNT-14).
|
||||||
|
app.jinja_env.globals['page_url'] = page_url
|
||||||
|
|
||||||
# Configure structured logging
|
# Configure structured logging
|
||||||
from app.logging_config import configure_logging
|
from app.logging_config import configure_logging
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
"""Bounding what a list view loads (MNT-14).
|
||||||
|
|
||||||
|
Every list view ran `.all()` on its table and handed the whole thing to a
|
||||||
|
template. The audit rated the impact as nil — correctly, at the scale of a
|
||||||
|
student club — and recommended choosing the pattern now rather than
|
||||||
|
retro-fitting one later. This is that pattern, in one place, so that the
|
||||||
|
next list added to the application has something to copy.
|
||||||
|
|
||||||
|
Two decisions worth stating, because both are the kind that get made twice
|
||||||
|
differently otherwise.
|
||||||
|
|
||||||
|
**`error_out=False`.** Page numbers arrive in the URL, so `?page=999` is a
|
||||||
|
thing a person can type or a stale bookmark can hold. Flask-SQLAlchemy's
|
||||||
|
default answers it with a 404, which is a confusing thing to show someone
|
||||||
|
who has simply gone one page too far. An empty page is honest and the
|
||||||
|
controls take them back.
|
||||||
|
|
||||||
|
**A cap on `per_page`.** It is also a URL parameter, and without a ceiling
|
||||||
|
`?per_page=100000` re-creates by hand exactly the unbounded query this
|
||||||
|
module exists to prevent — the sort of thing that turns a listing into a
|
||||||
|
cheap way to make the server work hard.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from flask import request, url_for
|
||||||
|
|
||||||
|
#: Rows per page when nothing asks otherwise.
|
||||||
|
DEFAULT_PER_PAGE = 50
|
||||||
|
|
||||||
|
#: Ceiling on the `per_page` query parameter. Generous enough that anyone
|
||||||
|
#: wanting "everything" on one screen gets it for any realistic table, low
|
||||||
|
#: enough that the query stays bounded.
|
||||||
|
MAX_PER_PAGE = 200
|
||||||
|
|
||||||
|
|
||||||
|
def paginate(query, per_page=DEFAULT_PER_PAGE):
|
||||||
|
"""Return one page of `query`, honouring `?page=` and `?per_page=`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: A SQLAlchemy query, already ordered. Ordering matters: a
|
||||||
|
paginated query without ORDER BY may return the same row on two
|
||||||
|
pages and never return another.
|
||||||
|
per_page: Default page size for this listing.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
flask_sqlalchemy.pagination.Pagination
|
||||||
|
"""
|
||||||
|
page = request.args.get('page', 1, type=int) or 1
|
||||||
|
requested = request.args.get('per_page', per_page, type=int) or per_page
|
||||||
|
size = max(1, min(requested, MAX_PER_PAGE))
|
||||||
|
return query.paginate(page=max(1, page), per_page=size, error_out=False)
|
||||||
|
|
||||||
|
|
||||||
|
def page_url(page):
|
||||||
|
"""URL of the current listing at another page number.
|
||||||
|
|
||||||
|
Rebuilt from the live request rather than composed in the template,
|
||||||
|
because the part that gets forgotten is the rest of the query string:
|
||||||
|
the evaluations list carries `sort` and `order`, the team matches list
|
||||||
|
carries `team_id`. A pagination link that drops them silently resets the
|
||||||
|
view the person was looking at.
|
||||||
|
"""
|
||||||
|
args = request.args.to_dict()
|
||||||
|
args.pop('page', None)
|
||||||
|
return url_for(request.endpoint, page=page, **(request.view_args or {}), **args)
|
||||||
@@ -21,6 +21,7 @@ from app.models import (
|
|||||||
TryoutRegistration,
|
TryoutRegistration,
|
||||||
User,
|
User,
|
||||||
)
|
)
|
||||||
|
from app.pagination import paginate
|
||||||
from app.validators import EvaluationSchema
|
from app.validators import EvaluationSchema
|
||||||
|
|
||||||
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
|
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
|
||||||
@@ -69,12 +70,11 @@ def list_evaluations():
|
|||||||
sort_expr = sort_expr.desc()
|
sort_expr = sort_expr.desc()
|
||||||
|
|
||||||
if isinstance(user, Admin):
|
if isinstance(user, Admin):
|
||||||
evaluations = (
|
evaluations_page = paginate(
|
||||||
Evaluation.query.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id)
|
Evaluation.query.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id)
|
||||||
.outerjoin(player_alias, Evaluation.player_id == player_alias.id)
|
.outerjoin(player_alias, Evaluation.player_id == player_alias.id)
|
||||||
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id)
|
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id)
|
||||||
.order_by(sort_expr)
|
.order_by(sort_expr, Evaluation.id)
|
||||||
.all()
|
|
||||||
)
|
)
|
||||||
avg_scores = (
|
avg_scores = (
|
||||||
db.session.query(
|
db.session.query(
|
||||||
@@ -99,19 +99,19 @@ def list_evaluations():
|
|||||||
# can_evaluate() is true for the four remaining roles. The former
|
# can_evaluate() is true for the four remaining roles. The former
|
||||||
# `else` branch listed evaluations *received* — a player's view,
|
# `else` branch listed evaluations *received* — a player's view,
|
||||||
# unreachable from this point (ARCH-007).
|
# unreachable from this point (ARCH-007).
|
||||||
evaluations = (
|
evaluations_page = paginate(
|
||||||
Evaluation.query.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id)
|
Evaluation.query.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id)
|
||||||
.outerjoin(player_alias, Evaluation.player_id == player_alias.id)
|
.outerjoin(player_alias, Evaluation.player_id == player_alias.id)
|
||||||
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id)
|
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id)
|
||||||
.filter(Evaluation.evaluator_id == user.id)
|
.filter(Evaluation.evaluator_id == user.id)
|
||||||
.order_by(sort_expr)
|
.order_by(sort_expr, Evaluation.id)
|
||||||
.all()
|
|
||||||
)
|
)
|
||||||
player_scores = {}
|
player_scores = {}
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'pages/evaluations.html',
|
'pages/evaluations.html',
|
||||||
evaluations=evaluations,
|
evaluations=evaluations_page.items,
|
||||||
|
pagination=evaluations_page,
|
||||||
player_scores=player_scores,
|
player_scores=player_scores,
|
||||||
sort_column=sort_column,
|
sort_column=sort_column,
|
||||||
sort_order=sort_order,
|
sort_order=sort_order,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from app.models import (
|
|||||||
TeamMatchParticipant,
|
TeamMatchParticipant,
|
||||||
TeamPlayer,
|
TeamPlayer,
|
||||||
)
|
)
|
||||||
|
from app.pagination import paginate
|
||||||
from app.permissions import can_manage_org_team, coach_org_teams, visible_org_teams
|
from app.permissions import can_manage_org_team, coach_org_teams, visible_org_teams
|
||||||
from app.routes.matches import default_end_time
|
from app.routes.matches import default_end_time
|
||||||
from app.services.scheduling import notify_participants, zip_participants
|
from app.services.scheduling import notify_participants, zip_participants
|
||||||
@@ -68,7 +69,10 @@ def list_matches():
|
|||||||
if filter_team_id:
|
if filter_team_id:
|
||||||
matches_query = matches_query.filter(TeamMatch.org_team_id == filter_team_id)
|
matches_query = matches_query.filter(TeamMatch.org_team_id == filter_team_id)
|
||||||
|
|
||||||
matches = matches_query.order_by(TeamMatch.date.desc()).all()
|
# Pagination also bounds the per-match participant loop below, which is
|
||||||
|
# the N+1 the constat pointed at (MNT-10 combined with MNT-14).
|
||||||
|
matches_page = paginate(matches_query.order_by(TeamMatch.date.desc(), TeamMatch.id))
|
||||||
|
matches = matches_page.items
|
||||||
|
|
||||||
match_data = []
|
match_data = []
|
||||||
for tm in matches:
|
for tm in matches:
|
||||||
@@ -92,7 +96,11 @@ def list_matches():
|
|||||||
)
|
)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'pages/team_matches.html', teams=teams, match_data=match_data, now=datetime.utcnow()
|
'pages/team_matches.html',
|
||||||
|
teams=teams,
|
||||||
|
match_data=match_data,
|
||||||
|
pagination=matches_page,
|
||||||
|
now=datetime.utcnow(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ from app.models import (
|
|||||||
User,
|
User,
|
||||||
UserGamertag,
|
UserGamertag,
|
||||||
)
|
)
|
||||||
|
from app.pagination import paginate
|
||||||
from app.routes.users._shared import (
|
from app.routes.users._shared import (
|
||||||
USER_CLASS_MAP,
|
USER_CLASS_MAP,
|
||||||
flash_validation_errors,
|
flash_validation_errors,
|
||||||
@@ -54,8 +55,11 @@ def list_users():
|
|||||||
flash(_('Only the president can manage users.'), 'danger')
|
flash(_('Only the president can manage users.'), 'danger')
|
||||||
return redirect(url_for('main.dashboard'))
|
return redirect(url_for('main.dashboard'))
|
||||||
|
|
||||||
users = User.query.order_by(User.role, User.username).all()
|
# Ordered before paginated, and by a unique-enough key: a paginated
|
||||||
return render_template('pages/users.html', users=users, roles=USER_TYPES)
|
# query without a stable ORDER BY can show the same row twice and never
|
||||||
|
# show another (MNT-14).
|
||||||
|
page = paginate(User.query.order_by(User.role, User.username, User.id))
|
||||||
|
return render_template('pages/users.html', users=page.items, pagination=page, roles=USER_TYPES)
|
||||||
|
|
||||||
|
|
||||||
@users_bp.route('/<int:user_id>/edit', methods=['GET', 'POST'])
|
@users_bp.route('/<int:user_id>/edit', methods=['GET', 'POST'])
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{#
|
||||||
|
Pagination controls (MNT-14).
|
||||||
|
|
||||||
|
Import and call:
|
||||||
|
{% import 'layouts/_pagination.html' as pager %}
|
||||||
|
{{ pager.controls(pagination) }}
|
||||||
|
|
||||||
|
`page_url` is a Jinja global registered in app.py; it rebuilds the current
|
||||||
|
URL at another page number, keeping the rest of the query string. That is
|
||||||
|
the part that gets forgotten — dropping `sort` or `team_id` from a
|
||||||
|
pagination link silently resets the view someone was looking at.
|
||||||
|
|
||||||
|
Plain <a> links only: no inline handler, nothing for CSP to refuse
|
||||||
|
(tests/test_csp.py).
|
||||||
|
#}
|
||||||
|
|
||||||
|
{% macro controls(pagination) %}
|
||||||
|
{% if pagination.pages > 1 %}
|
||||||
|
<nav class="pagination" aria-label="{{ _('Pagination') }}">
|
||||||
|
{% if pagination.has_prev %}
|
||||||
|
<a class="btn btn-secondary btn-sm" href="{{ page_url(pagination.prev_num) }}"
|
||||||
|
rel="prev">« {{ _('Previous') }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="btn btn-secondary btn-sm is-disabled" aria-disabled="true">« {{ _('Previous') }}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="pagination-status">
|
||||||
|
{{ _('Page %(page)s of %(pages)s', page=pagination.page, pages=pagination.pages) }}
|
||||||
|
·
|
||||||
|
{{ _('%(total)s in total', total=pagination.total) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if pagination.has_next %}
|
||||||
|
<a class="btn btn-secondary btn-sm" href="{{ page_url(pagination.next_num) }}"
|
||||||
|
rel="next">{{ _('Next') }} »</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="btn btn-secondary btn-sm is-disabled" aria-disabled="true">{{ _('Next') }} »</span>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "layouts/base.html" %}
|
{% extends "layouts/base.html" %}
|
||||||
|
{% import 'layouts/_pagination.html' as pager %}
|
||||||
{% block title %}{{ _('Evaluations') }} - TryoutPro{% endblock %}
|
{% block title %}{{ _('Evaluations') }} - TryoutPro{% endblock %}
|
||||||
{% block page_title %}{{ _('Evaluations') }}{% endblock %}
|
{% block page_title %}{{ _('Evaluations') }}{% endblock %}
|
||||||
{% block breadcrumb %}<span class="breadcrumb">Home / Evaluations</span>{% endblock %}
|
{% block breadcrumb %}<span class="breadcrumb">Home / Evaluations</span>{% endblock %}
|
||||||
@@ -101,6 +102,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{{ pager.controls(pagination) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "layouts/base.html" %}
|
{% extends "layouts/base.html" %}
|
||||||
|
{% import 'layouts/_pagination.html' as pager %}
|
||||||
{% block title %}{{ _('Team Matches') }} - TryoutPro{% endblock %}
|
{% block title %}{{ _('Team Matches') }} - TryoutPro{% endblock %}
|
||||||
{% block page_title %}{{ _('Team Matches') }}{% endblock %}
|
{% block page_title %}{{ _('Team Matches') }}{% endblock %}
|
||||||
{% block breadcrumb %}<span class="breadcrumb">Home / Team Matches</span>{% endblock %}
|
{% block breadcrumb %}<span class="breadcrumb">Home / Team Matches</span>{% endblock %}
|
||||||
@@ -122,6 +123,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{{ pager.controls(pagination) }}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "layouts/base.html" %}
|
{% extends "layouts/base.html" %}
|
||||||
|
{% import 'layouts/_pagination.html' as pager %}
|
||||||
{% block title %}{{ _('Manage Users') }} - TryoutPro{% endblock %}
|
{% block title %}{{ _('Manage Users') }} - TryoutPro{% endblock %}
|
||||||
{% block page_title %}{{ _('Manage Users') }}{% endblock %}
|
{% block page_title %}{{ _('Manage Users') }}{% endblock %}
|
||||||
{% block breadcrumb %}<span class="breadcrumb">Home / Users</span>{% endblock %}
|
{% block breadcrumb %}<span class="breadcrumb">Home / Users</span>{% endblock %}
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{{ pager.controls(pagination) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Binary file not shown.
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: team-tryouts VERSION\n"
|
"Project-Id-Version: team-tryouts VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2026-08-11 18:57-0400\n"
|
"POT-Creation-Date: 2026-08-11 20:15-0400\n"
|
||||||
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
|
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -19,7 +19,7 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.18.0\n"
|
"Generated-By: Babel 2.18.0\n"
|
||||||
|
|
||||||
#: app/app.py:555
|
#: app/app.py:562
|
||||||
msgid "Please log in to access this page."
|
msgid "Please log in to access this page."
|
||||||
msgstr "Please log in to access this page."
|
msgstr "Please log in to access this page."
|
||||||
|
|
||||||
@@ -90,95 +90,127 @@ msgstr "Player must be selected."
|
|||||||
msgid "Notes must be 2000 characters or less."
|
msgid "Notes must be 2000 characters or less."
|
||||||
msgstr "Notes must be 2000 characters or less."
|
msgstr "Notes must be 2000 characters or less."
|
||||||
|
|
||||||
#: app/validators.py:476
|
#: app/validators.py:482
|
||||||
msgid "Date must be in YYYY-MM-DD format."
|
msgid "Date must be in YYYY-MM-DD format."
|
||||||
msgstr "Date must be in YYYY-MM-DD format."
|
msgstr "Date must be in YYYY-MM-DD format."
|
||||||
|
|
||||||
#: app/validators.py:481 app/validators.py:508
|
#: app/validators.py:483
|
||||||
|
msgid "A date is required."
|
||||||
|
msgstr "A date is required."
|
||||||
|
|
||||||
|
#: app/validators.py:489 app/validators.py:554
|
||||||
msgid "Start time must be in HH:MM format."
|
msgid "Start time must be in HH:MM format."
|
||||||
msgstr "Start time must be in HH:MM format."
|
msgstr "Start time must be in HH:MM format."
|
||||||
|
|
||||||
#: app/validators.py:485
|
#: app/validators.py:490 app/validators.py:555
|
||||||
|
msgid "A start time is required."
|
||||||
|
msgstr "A start time is required."
|
||||||
|
|
||||||
|
#: app/validators.py:496
|
||||||
msgid "End time must be in HH:MM format."
|
msgid "End time must be in HH:MM format."
|
||||||
msgstr "End time must be in HH:MM format."
|
msgstr "End time must be in HH:MM format."
|
||||||
|
|
||||||
#: app/validators.py:488
|
#: app/validators.py:497
|
||||||
|
msgid "An end time is required."
|
||||||
|
msgstr "An end time is required."
|
||||||
|
|
||||||
|
#: app/validators.py:501
|
||||||
msgid "Points must be 2000 characters or less."
|
msgid "Points must be 2000 characters or less."
|
||||||
msgstr "Points must be 2000 characters or less."
|
msgstr "Points must be 2000 characters or less."
|
||||||
|
|
||||||
#: app/validators.py:504
|
#: app/validators.py:516
|
||||||
|
msgid "End time must be after start time."
|
||||||
|
msgstr "End time must be after start time."
|
||||||
|
|
||||||
|
#: app/validators.py:545 app/validators.py:547
|
||||||
msgid "Day must be 0 (Monday) to 6 (Sunday)."
|
msgid "Day must be 0 (Monday) to 6 (Sunday)."
|
||||||
msgstr "Day must be 0 (Monday) to 6 (Sunday)."
|
msgstr "Day must be 0 (Monday) to 6 (Sunday)."
|
||||||
|
|
||||||
#: app/validators.py:535
|
#: app/validators.py:548
|
||||||
|
msgid "A day is required."
|
||||||
|
msgstr "A day is required."
|
||||||
|
|
||||||
|
#: app/validators.py:583
|
||||||
msgid "Player selection is malformed."
|
msgid "Player selection is malformed."
|
||||||
msgstr "Player selection is malformed."
|
msgstr "Player selection is malformed."
|
||||||
|
|
||||||
#: app/validators.py:561 app/validators.py:671
|
#: app/validators.py:609 app/validators.py:719
|
||||||
msgid "A title is required."
|
msgid "A title is required."
|
||||||
msgstr "A title is required."
|
msgstr "A title is required."
|
||||||
|
|
||||||
#: app/validators.py:570
|
#: app/validators.py:618
|
||||||
msgid "Invalid date format."
|
msgid "Invalid date format."
|
||||||
msgstr "Invalid date format."
|
msgstr "Invalid date format."
|
||||||
|
|
||||||
#: app/validators.py:575 app/validators.py:582
|
#: app/validators.py:623 app/validators.py:630
|
||||||
msgid "Invalid time format."
|
msgid "Invalid time format."
|
||||||
msgstr "Invalid time format."
|
msgstr "Invalid time format."
|
||||||
|
|
||||||
#: app/validators.py:576
|
#: app/validators.py:624
|
||||||
msgid "Start time is required. Please select a time slot."
|
msgid "Start time is required. Please select a time slot."
|
||||||
msgstr "Start time is required. Please select a time slot."
|
msgstr "Start time is required. Please select a time slot."
|
||||||
|
|
||||||
#: app/validators.py:590
|
#: app/validators.py:638
|
||||||
msgid "Unknown match status."
|
msgid "Unknown match status."
|
||||||
msgstr "Unknown match status."
|
msgstr "Unknown match status."
|
||||||
|
|
||||||
#: app/validators.py:606
|
#: app/validators.py:654
|
||||||
msgid "The end time must come after the start time."
|
msgid "The end time must come after the start time."
|
||||||
msgstr "The end time must come after the start time."
|
msgstr "The end time must come after the start time."
|
||||||
|
|
||||||
#: app/validators.py:620
|
#: app/validators.py:668
|
||||||
msgid "Unknown match type."
|
msgid "Unknown match type."
|
||||||
msgstr "Unknown match type."
|
msgstr "Unknown match type."
|
||||||
|
|
||||||
#: app/validators.py:632
|
#: app/validators.py:680
|
||||||
msgid "A team cannot play against itself."
|
msgid "A team cannot play against itself."
|
||||||
msgstr "A team cannot play against itself."
|
msgstr "A team cannot play against itself."
|
||||||
|
|
||||||
#: app/validators.py:680
|
#: app/validators.py:728
|
||||||
msgid "Unknown game."
|
msgid "Unknown game."
|
||||||
msgstr "Unknown game."
|
msgstr "Unknown game."
|
||||||
|
|
||||||
#: app/validators.py:685
|
#: app/validators.py:733
|
||||||
msgid "Invalid start date format."
|
msgid "Invalid start date format."
|
||||||
msgstr "Invalid start date format."
|
msgstr "Invalid start date format."
|
||||||
|
|
||||||
#: app/validators.py:686
|
#: app/validators.py:734
|
||||||
msgid "A start date is required."
|
msgid "A start date is required."
|
||||||
msgstr "A start date is required."
|
msgstr "A start date is required."
|
||||||
|
|
||||||
#: app/validators.py:692
|
#: app/validators.py:740
|
||||||
msgid "Invalid end date format."
|
msgid "Invalid end date format."
|
||||||
msgstr "Invalid end date format."
|
msgstr "Invalid end date format."
|
||||||
|
|
||||||
#: app/validators.py:700
|
#: app/validators.py:748
|
||||||
msgid "A tryout must allow at least one player."
|
msgid "A tryout must allow at least one player."
|
||||||
msgstr "A tryout must allow at least one player."
|
msgstr "A tryout must allow at least one player."
|
||||||
|
|
||||||
#: app/validators.py:703
|
#: app/validators.py:751
|
||||||
msgid "The player limit must be a whole number."
|
msgid "The player limit must be a whole number."
|
||||||
msgstr "The player limit must be a whole number."
|
msgstr "The player limit must be a whole number."
|
||||||
|
|
||||||
#: app/validators.py:715
|
#: app/validators.py:763
|
||||||
msgid "End date cannot be before start date."
|
msgid "End date cannot be before start date."
|
||||||
msgstr "End date cannot be before start date."
|
msgstr "End date cannot be before start date."
|
||||||
|
|
||||||
#: app/validators.py:724
|
#: app/validators.py:790 app/validators.py:791
|
||||||
|
msgid "Team name is required."
|
||||||
|
msgstr "Team name is required."
|
||||||
|
|
||||||
|
#: app/validators.py:797
|
||||||
|
msgid "Invalid coach selection."
|
||||||
|
msgstr "Invalid coach selection."
|
||||||
|
|
||||||
|
#: app/validators.py:803
|
||||||
|
msgid "Invalid manager selection."
|
||||||
|
msgstr "Invalid manager selection."
|
||||||
|
|
||||||
|
#: app/validators.py:815
|
||||||
msgid "Scores run from 1 to 10."
|
msgid "Scores run from 1 to 10."
|
||||||
msgstr "Scores run from 1 to 10."
|
msgstr "Scores run from 1 to 10."
|
||||||
|
|
||||||
#: app/validators.py:725
|
#: app/validators.py:816
|
||||||
msgid "A score must be a whole number from 1 to 10."
|
msgid "A score must be a whole number from 1 to 10."
|
||||||
msgstr "A score must be a whole number from 1 to 10."
|
msgstr "A score must be a whole number from 1 to 10."
|
||||||
|
|
||||||
@@ -203,11 +235,11 @@ msgstr ""
|
|||||||
msgid "Your registration could not be processed. Please try again."
|
msgid "Your registration could not be processed. Please try again."
|
||||||
msgstr "Your registration could not be processed. Please try again."
|
msgstr "Your registration could not be processed. Please try again."
|
||||||
|
|
||||||
#: app/routes/auth.py:388 app/routes/users/accounts.py:325
|
#: app/routes/auth.py:388 app/routes/users/accounts.py:329
|
||||||
msgid "Username already exists."
|
msgid "Username already exists."
|
||||||
msgstr "Username already exists."
|
msgstr "Username already exists."
|
||||||
|
|
||||||
#: app/routes/auth.py:392 app/routes/users/accounts.py:329
|
#: app/routes/auth.py:392 app/routes/users/accounts.py:333
|
||||||
msgid "Email already registered."
|
msgid "Email already registered."
|
||||||
msgstr "Email already registered."
|
msgstr "Email already registered."
|
||||||
|
|
||||||
@@ -251,7 +283,7 @@ msgstr "Discord account connected! Your profile has been pre-filled."
|
|||||||
msgid "You have been logged out."
|
msgid "You have been logged out."
|
||||||
msgstr "You have been logged out."
|
msgstr "You have been logged out."
|
||||||
|
|
||||||
#: app/routes/evaluations.py:36
|
#: app/routes/evaluations.py:37
|
||||||
msgid "You do not have permission to view evaluations."
|
msgid "You do not have permission to view evaluations."
|
||||||
msgstr "You do not have permission to view evaluations."
|
msgstr "You do not have permission to view evaluations."
|
||||||
|
|
||||||
@@ -279,9 +311,9 @@ msgstr "Evaluation submitted successfully!"
|
|||||||
msgid "Evaluation updated!"
|
msgid "Evaluation updated!"
|
||||||
msgstr "Evaluation updated!"
|
msgstr "Evaluation updated!"
|
||||||
|
|
||||||
#: app/routes/evaluations.py:210 app/routes/teams.py:289
|
#: app/routes/evaluations.py:210 app/routes/teams.py:305
|
||||||
#: app/routes/teams.py:330 app/routes/teams.py:371 app/routes/teams.py:396
|
#: app/routes/teams.py:346 app/routes/teams.py:387 app/routes/teams.py:412
|
||||||
#: app/routes/teams.py:421 app/routes/teams.py:456 app/routes/tryouts.py:437
|
#: app/routes/teams.py:437 app/routes/teams.py:472 app/routes/tryouts.py:437
|
||||||
#: app/routes/tryouts.py:453 app/routes/tryouts.py:473
|
#: app/routes/tryouts.py:453 app/routes/tryouts.py:473
|
||||||
#: app/routes/tryouts.py:512 app/routes/tryouts.py:548
|
#: app/routes/tryouts.py:512 app/routes/tryouts.py:548
|
||||||
#: app/routes/tryouts.py:567
|
#: app/routes/tryouts.py:567
|
||||||
@@ -304,15 +336,15 @@ msgstr "This tryout has ended. Matches can no longer be created or modified."
|
|||||||
msgid "Match scheduled successfully!"
|
msgid "Match scheduled successfully!"
|
||||||
msgstr "Match scheduled successfully!"
|
msgstr "Match scheduled successfully!"
|
||||||
|
|
||||||
#: app/routes/matches.py:444 app/routes/team_matches.py:212
|
#: app/routes/matches.py:444 app/routes/team_matches.py:220
|
||||||
msgid "You do not have permission to edit this match."
|
msgid "You do not have permission to edit this match."
|
||||||
msgstr "You do not have permission to edit this match."
|
msgstr "You do not have permission to edit this match."
|
||||||
|
|
||||||
#: app/routes/matches.py:539 app/routes/team_matches.py:242
|
#: app/routes/matches.py:539 app/routes/team_matches.py:250
|
||||||
msgid "Match updated successfully!"
|
msgid "Match updated successfully!"
|
||||||
msgstr "Match updated successfully!"
|
msgstr "Match updated successfully!"
|
||||||
|
|
||||||
#: app/routes/matches.py:575 app/routes/team_matches.py:257
|
#: app/routes/matches.py:575 app/routes/team_matches.py:265
|
||||||
msgid "You do not have permission to delete this match."
|
msgid "You do not have permission to delete this match."
|
||||||
msgstr "You do not have permission to delete this match."
|
msgstr "You do not have permission to delete this match."
|
||||||
|
|
||||||
@@ -320,155 +352,151 @@ msgstr "You do not have permission to delete this match."
|
|||||||
msgid "This tryout has ended. Matches can no longer be deleted."
|
msgid "This tryout has ended. Matches can no longer be deleted."
|
||||||
msgstr "This tryout has ended. Matches can no longer be deleted."
|
msgstr "This tryout has ended. Matches can no longer be deleted."
|
||||||
|
|
||||||
#: app/routes/matches.py:591 app/routes/team_matches.py:261
|
#: app/routes/matches.py:591 app/routes/team_matches.py:269
|
||||||
msgid "Match deleted successfully."
|
msgid "Match deleted successfully."
|
||||||
msgstr "Match deleted successfully."
|
msgstr "Match deleted successfully."
|
||||||
|
|
||||||
#: app/routes/team_matches.py:105
|
#: app/routes/team_matches.py:113
|
||||||
msgid "You do not have permission to schedule matches for this team."
|
msgid "You do not have permission to schedule matches for this team."
|
||||||
msgstr "You do not have permission to schedule matches for this team."
|
msgstr "You do not have permission to schedule matches for this team."
|
||||||
|
|
||||||
#: app/routes/team_matches.py:197
|
#: app/routes/team_matches.py:205
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team match \"%(title)s\" scheduled successfully!"
|
msgid "Team match \"%(title)s\" scheduled successfully!"
|
||||||
msgstr "Team match \"%(title)s\" scheduled successfully!"
|
msgstr "Team match \"%(title)s\" scheduled successfully!"
|
||||||
|
|
||||||
#: app/routes/teams.py:41
|
#: app/routes/teams.py:44
|
||||||
msgid "Use My Team(s) to view your teams."
|
msgid "Use My Team(s) to view your teams."
|
||||||
msgstr "Use My Team(s) to view your teams."
|
msgstr "Use My Team(s) to view your teams."
|
||||||
|
|
||||||
#: app/routes/teams.py:44
|
#: app/routes/teams.py:47
|
||||||
msgid "You do not have permission to view teams."
|
msgid "You do not have permission to view teams."
|
||||||
msgstr "You do not have permission to view teams."
|
msgstr "You do not have permission to view teams."
|
||||||
|
|
||||||
#: app/routes/teams.py:71
|
#: app/routes/teams.py:74
|
||||||
msgid "This page is for players."
|
msgid "This page is for players."
|
||||||
msgstr "This page is for players."
|
msgstr "This page is for players."
|
||||||
|
|
||||||
#: app/routes/teams.py:124
|
#: app/routes/teams.py:150
|
||||||
msgid "You do not have permission to create teams."
|
msgid "You do not have permission to create teams."
|
||||||
msgstr "You do not have permission to create teams."
|
msgstr "You do not have permission to create teams."
|
||||||
|
|
||||||
#: app/routes/teams.py:132 app/routes/teams.py:177
|
#: app/routes/teams.py:161 app/routes/teams.py:203
|
||||||
msgid "Team name is required."
|
|
||||||
msgstr "Team name is required."
|
|
||||||
|
|
||||||
#: app/routes/teams.py:137 app/routes/teams.py:182
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" already exists."
|
msgid "Team \"%(name)s\" already exists."
|
||||||
msgstr "Team \"%(name)s\" already exists."
|
msgstr "Team \"%(name)s\" already exists."
|
||||||
|
|
||||||
#: app/routes/teams.py:159
|
#: app/routes/teams.py:182
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" created successfully!"
|
msgid "Team \"%(name)s\" created successfully!"
|
||||||
msgstr "Team \"%(name)s\" created successfully!"
|
msgstr "Team \"%(name)s\" created successfully!"
|
||||||
|
|
||||||
#: app/routes/teams.py:169
|
#: app/routes/teams.py:192
|
||||||
msgid "You do not have permission to edit this team."
|
msgid "You do not have permission to edit this team."
|
||||||
msgstr "You do not have permission to edit this team."
|
msgstr "You do not have permission to edit this team."
|
||||||
|
|
||||||
#: app/routes/teams.py:220
|
#: app/routes/teams.py:236
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" updated successfully!"
|
msgid "Team \"%(name)s\" updated successfully!"
|
||||||
msgstr "Team \"%(name)s\" updated successfully!"
|
msgstr "Team \"%(name)s\" updated successfully!"
|
||||||
|
|
||||||
#: app/routes/teams.py:248
|
#: app/routes/teams.py:264
|
||||||
msgid "You do not have permission to delete teams."
|
msgid "You do not have permission to delete teams."
|
||||||
msgstr "You do not have permission to delete teams."
|
msgstr "You do not have permission to delete teams."
|
||||||
|
|
||||||
#: app/routes/teams.py:279
|
#: app/routes/teams.py:295
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" deleted successfully."
|
msgid "Team \"%(name)s\" deleted successfully."
|
||||||
msgstr "Team \"%(name)s\" deleted successfully."
|
msgstr "Team \"%(name)s\" deleted successfully."
|
||||||
|
|
||||||
#: app/routes/teams.py:294
|
#: app/routes/teams.py:310
|
||||||
msgid "Please select a coach."
|
msgid "Please select a coach."
|
||||||
msgstr "Please select a coach."
|
msgstr "Please select a coach."
|
||||||
|
|
||||||
#: app/routes/teams.py:299
|
#: app/routes/teams.py:315
|
||||||
msgid "Only coaches can be assigned as coach."
|
msgid "Only coaches can be assigned as coach."
|
||||||
msgstr "Only coaches can be assigned as coach."
|
msgstr "Only coaches can be assigned as coach."
|
||||||
|
|
||||||
#: app/routes/teams.py:305
|
#: app/routes/teams.py:321
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is already a coach of %(name)s."
|
msgid "%(username)s is already a coach of %(name)s."
|
||||||
msgstr "%(username)s is already a coach of %(name)s."
|
msgstr "%(username)s is already a coach of %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:318
|
#: app/routes/teams.py:334
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s added as coach of %(name)s."
|
msgid "%(username)s added as coach of %(name)s."
|
||||||
msgstr "%(username)s added as coach of %(name)s."
|
msgstr "%(username)s added as coach of %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:335
|
#: app/routes/teams.py:351
|
||||||
msgid "Please select a manager."
|
msgid "Please select a manager."
|
||||||
msgstr "Please select a manager."
|
msgstr "Please select a manager."
|
||||||
|
|
||||||
#: app/routes/teams.py:340
|
#: app/routes/teams.py:356
|
||||||
msgid "Only managers can be assigned as manager."
|
msgid "Only managers can be assigned as manager."
|
||||||
msgstr "Only managers can be assigned as manager."
|
msgstr "Only managers can be assigned as manager."
|
||||||
|
|
||||||
#: app/routes/teams.py:346
|
#: app/routes/teams.py:362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is already a manager of %(name)s."
|
msgid "%(username)s is already a manager of %(name)s."
|
||||||
msgstr "%(username)s is already a manager of %(name)s."
|
msgstr "%(username)s is already a manager of %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:359
|
#: app/routes/teams.py:375
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s added as manager of %(name)s."
|
msgid "%(username)s added as manager of %(name)s."
|
||||||
msgstr "%(username)s added as manager of %(name)s."
|
msgstr "%(username)s added as manager of %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:386
|
#: app/routes/teams.py:402
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Coach removed from %(name)s."
|
msgid "Coach removed from %(name)s."
|
||||||
msgstr "Coach removed from %(name)s."
|
msgstr "Coach removed from %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:411
|
#: app/routes/teams.py:427
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Manager removed from %(name)s."
|
msgid "Manager removed from %(name)s."
|
||||||
msgstr "Manager removed from %(name)s."
|
msgstr "Manager removed from %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:427 app/routes/tryouts.py:477 app/routes/tryouts.py:578
|
#: app/routes/teams.py:443 app/routes/tryouts.py:477 app/routes/tryouts.py:578
|
||||||
msgid "Please select a player."
|
msgid "Please select a player."
|
||||||
msgstr "Please select a player."
|
msgstr "Please select a player."
|
||||||
|
|
||||||
#: app/routes/teams.py:432
|
#: app/routes/teams.py:448
|
||||||
msgid "Can only assign players to teams."
|
msgid "Can only assign players to teams."
|
||||||
msgstr "Can only assign players to teams."
|
msgstr "Can only assign players to teams."
|
||||||
|
|
||||||
#: app/routes/teams.py:438
|
#: app/routes/teams.py:454
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is already on %(name)s."
|
msgid "%(username)s is already on %(name)s."
|
||||||
msgstr "%(username)s is already on %(name)s."
|
msgstr "%(username)s is already on %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:446
|
#: app/routes/teams.py:462
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s added to %(name)s!"
|
msgid "%(username)s added to %(name)s!"
|
||||||
msgstr "%(username)s added to %(name)s!"
|
msgstr "%(username)s added to %(name)s!"
|
||||||
|
|
||||||
#: app/routes/teams.py:463 app/routes/teams.py:537
|
#: app/routes/teams.py:479 app/routes/teams.py:553
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is not on %(name)s."
|
msgid "%(username)s is not on %(name)s."
|
||||||
msgstr "%(username)s is not on %(name)s."
|
msgstr "%(username)s is not on %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:471
|
#: app/routes/teams.py:487
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s removed from %(name)s."
|
msgid "%(username)s removed from %(name)s."
|
||||||
msgstr "%(username)s removed from %(name)s."
|
msgstr "%(username)s removed from %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:508 app/routes/teams.py:526
|
#: app/routes/teams.py:524 app/routes/teams.py:542
|
||||||
msgid "You do not have permission to add notes to this team."
|
msgid "You do not have permission to add notes to this team."
|
||||||
msgstr "You do not have permission to add notes to this team."
|
msgstr "You do not have permission to add notes to this team."
|
||||||
|
|
||||||
#: app/routes/teams.py:516
|
#: app/routes/teams.py:532
|
||||||
msgid "Team notes added successfully!"
|
msgid "Team notes added successfully!"
|
||||||
msgstr "Team notes added successfully!"
|
msgstr "Team notes added successfully!"
|
||||||
|
|
||||||
#: app/routes/teams.py:531 app/routes/users/notes.py:207
|
#: app/routes/teams.py:547 app/routes/users/notes.py:207
|
||||||
#: app/routes/users/notes.py:250
|
#: app/routes/users/notes.py:250
|
||||||
msgid "Can only add notes for players."
|
msgid "Can only add notes for players."
|
||||||
msgstr "Can only add notes for players."
|
msgstr "Can only add notes for players."
|
||||||
|
|
||||||
#: app/routes/teams.py:547
|
#: app/routes/teams.py:563
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Note added for %(username)s!"
|
msgid "Note added for %(username)s!"
|
||||||
msgstr "Note added for %(username)s!"
|
msgstr "Note added for %(username)s!"
|
||||||
@@ -582,23 +610,23 @@ msgstr "Only PDF files are allowed for contracts."
|
|||||||
msgid "That file is not a PDF, whatever its name says."
|
msgid "That file is not a PDF, whatever its name says."
|
||||||
msgstr "That file is not a PDF, whatever its name says."
|
msgstr "That file is not a PDF, whatever its name says."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:54
|
#: app/routes/users/accounts.py:55
|
||||||
msgid "Only the president can manage users."
|
msgid "Only the president can manage users."
|
||||||
msgstr "Only the president can manage users."
|
msgstr "Only the president can manage users."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:66
|
#: app/routes/users/accounts.py:70
|
||||||
msgid "Only the president can edit users."
|
msgid "Only the president can edit users."
|
||||||
msgstr "Only the president can edit users."
|
msgstr "Only the president can edit users."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:107
|
#: app/routes/users/accounts.py:111
|
||||||
msgid "Email already in use by another account."
|
msgid "Email already in use by another account."
|
||||||
msgstr "Email already in use by another account."
|
msgstr "Email already in use by another account."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:118
|
#: app/routes/users/accounts.py:122
|
||||||
msgid "You cannot change your own role. Ask another president to do it."
|
msgid "You cannot change your own role. Ask another president to do it."
|
||||||
msgstr "You cannot change your own role. Ask another president to do it."
|
msgstr "You cannot change your own role. Ask another president to do it."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:131
|
#: app/routes/users/accounts.py:135
|
||||||
msgid ""
|
msgid ""
|
||||||
"This is the last active president. Promote another account before "
|
"This is the last active president. Promote another account before "
|
||||||
"changing this one."
|
"changing this one."
|
||||||
@@ -606,34 +634,34 @@ msgstr ""
|
|||||||
"This is the last active president. Promote another account before "
|
"This is the last active president. Promote another account before "
|
||||||
"changing this one."
|
"changing this one."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:210
|
#: app/routes/users/accounts.py:214
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User %(username)s updated successfully!"
|
msgid "User %(username)s updated successfully!"
|
||||||
msgstr "User %(username)s updated successfully!"
|
msgstr "User %(username)s updated successfully!"
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:231
|
#: app/routes/users/accounts.py:235
|
||||||
msgid "Only the president can delete users."
|
msgid "Only the president can delete users."
|
||||||
msgstr "Only the president can delete users."
|
msgstr "Only the president can delete users."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:235
|
#: app/routes/users/accounts.py:239
|
||||||
msgid "You cannot delete your own account."
|
msgid "You cannot delete your own account."
|
||||||
msgstr "You cannot delete your own account."
|
msgstr "You cannot delete your own account."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:294
|
#: app/routes/users/accounts.py:298
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User %(deleted_username)s has been removed."
|
msgid "User %(deleted_username)s has been removed."
|
||||||
msgstr "User %(deleted_username)s has been removed."
|
msgstr "User %(deleted_username)s has been removed."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:305
|
#: app/routes/users/accounts.py:309
|
||||||
msgid "Only the president can create users."
|
msgid "Only the president can create users."
|
||||||
msgstr "Only the president can create users."
|
msgstr "Only the president can create users."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:353
|
#: app/routes/users/accounts.py:357
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User %(full_name)s created as %(role)s!"
|
msgid "User %(full_name)s created as %(role)s!"
|
||||||
msgstr "User %(full_name)s created as %(role)s!"
|
msgstr "User %(full_name)s created as %(role)s!"
|
||||||
|
|
||||||
#: app/routes/users/availability.py:187
|
#: app/routes/users/availability.py:210
|
||||||
msgid "Only coaches can manage availability."
|
msgid "Only coaches can manage availability."
|
||||||
msgstr "Only coaches can manage availability."
|
msgstr "Only coaches can manage availability."
|
||||||
|
|
||||||
@@ -714,52 +742,48 @@ msgstr "Only coaches can add personal notes."
|
|||||||
msgid "Note added successfully."
|
msgid "Note added successfully."
|
||||||
msgstr "Note added successfully."
|
msgstr "Note added successfully."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:20
|
#: app/routes/users/one_on_one.py:23
|
||||||
msgid "Only players can request One on One sessions."
|
msgid "Only players can request One on One sessions."
|
||||||
msgstr "Only players can request One on One sessions."
|
msgstr "Only players can request One on One sessions."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:33
|
#: app/routes/users/one_on_one.py:36
|
||||||
msgid "You do not have a coach assigned to your team."
|
msgid "You do not have a coach assigned to your team."
|
||||||
msgstr "You do not have a coach assigned to your team."
|
msgstr "You do not have a coach assigned to your team."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:68
|
#: app/routes/users/one_on_one.py:67
|
||||||
msgid "Cannot request One on One - no coach assigned."
|
msgid "Cannot request One on One - no coach assigned."
|
||||||
msgstr "Cannot request One on One - no coach assigned."
|
msgstr "Cannot request One on One - no coach assigned."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:76
|
#: app/routes/users/one_on_one.py:93
|
||||||
msgid "Invalid date or time format."
|
|
||||||
msgstr "Invalid date or time format."
|
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:90
|
|
||||||
msgid "The requested time is not within the coach's availability."
|
msgid "The requested time is not within the coach's availability."
|
||||||
msgstr "The requested time is not within the coach's availability."
|
msgstr "The requested time is not within the coach's availability."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:118
|
#: app/routes/users/one_on_one.py:121
|
||||||
msgid "Your One on One request has been submitted!"
|
msgid "Your One on One request has been submitted!"
|
||||||
msgstr "Your One on One request has been submitted!"
|
msgstr "Your One on One request has been submitted!"
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:163
|
#: app/routes/users/one_on_one.py:166
|
||||||
msgid "Only coaches can accept One on One requests."
|
msgid "Only coaches can accept One on One requests."
|
||||||
msgstr "Only coaches can accept One on One requests."
|
msgstr "Only coaches can accept One on One requests."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:169 app/routes/users/one_on_one.py:219
|
#: app/routes/users/one_on_one.py:172 app/routes/users/one_on_one.py:222
|
||||||
msgid "This request is not for you."
|
msgid "This request is not for you."
|
||||||
msgstr "This request is not for you."
|
msgstr "This request is not for you."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:173 app/routes/users/one_on_one.py:223
|
#: app/routes/users/one_on_one.py:176 app/routes/users/one_on_one.py:226
|
||||||
msgid "This request has already been processed."
|
msgid "This request has already been processed."
|
||||||
msgstr "This request has already been processed."
|
msgstr "This request has already been processed."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:200
|
#: app/routes/users/one_on_one.py:203
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "One on One request from %(player)s has been approved!"
|
msgid "One on One request from %(player)s has been approved!"
|
||||||
msgstr "One on One request from %(player)s has been approved!"
|
msgstr "One on One request from %(player)s has been approved!"
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:213
|
#: app/routes/users/one_on_one.py:216
|
||||||
msgid "Only coaches can reject One on One requests."
|
msgid "Only coaches can reject One on One requests."
|
||||||
msgstr "Only coaches can reject One on One requests."
|
msgstr "Only coaches can reject One on One requests."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:255
|
#: app/routes/users/one_on_one.py:258
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "One on One request from %(player)s has been rejected."
|
msgid "One on One request from %(player)s has been rejected."
|
||||||
msgstr "One on One request from %(player)s has been rejected."
|
msgstr "One on One request from %(player)s has been rejected."
|
||||||
@@ -897,6 +921,30 @@ msgstr "Try Again"
|
|||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Language"
|
msgstr "Language"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:19
|
||||||
|
msgid "Pagination"
|
||||||
|
msgstr "Pagination"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:22
|
||||||
|
#: app/templates/layouts/_pagination.html:24
|
||||||
|
msgid "Previous"
|
||||||
|
msgstr "Previous"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:28
|
||||||
|
#, python-format
|
||||||
|
msgid "Page %(page)s of %(pages)s"
|
||||||
|
msgstr "Page %(page)s of %(pages)s"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:30
|
||||||
|
#, python-format
|
||||||
|
msgid "%(total)s in total"
|
||||||
|
msgstr "%(total)s in total"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:35
|
||||||
|
#: app/templates/layouts/_pagination.html:37
|
||||||
|
msgid "Next"
|
||||||
|
msgstr "Next"
|
||||||
|
|
||||||
#: app/templates/layouts/base.html:48 app/templates/layouts/base.html:154
|
#: app/templates/layouts/base.html:48 app/templates/layouts/base.html:154
|
||||||
#: app/templates/pages/dashboard.html:2 app/templates/pages/dashboard.html:3
|
#: app/templates/pages/dashboard.html:2 app/templates/pages/dashboard.html:3
|
||||||
msgid "Dashboard"
|
msgid "Dashboard"
|
||||||
@@ -913,8 +961,8 @@ msgid "Calendar"
|
|||||||
msgstr "Calendar"
|
msgstr "Calendar"
|
||||||
|
|
||||||
#: app/templates/layouts/base.html:67 app/templates/pages/dashboard.html:43
|
#: app/templates/layouts/base.html:67 app/templates/pages/dashboard.html:43
|
||||||
#: app/templates/pages/evaluations.html:2
|
|
||||||
#: app/templates/pages/evaluations.html:3
|
#: app/templates/pages/evaluations.html:3
|
||||||
|
#: app/templates/pages/evaluations.html:4
|
||||||
msgid "Evaluations"
|
msgid "Evaluations"
|
||||||
msgstr "Evaluations"
|
msgstr "Evaluations"
|
||||||
|
|
||||||
@@ -927,8 +975,8 @@ msgstr "My Team(s)"
|
|||||||
msgid "Manage Teams"
|
msgid "Manage Teams"
|
||||||
msgstr "Manage Teams"
|
msgstr "Manage Teams"
|
||||||
|
|
||||||
#: app/templates/layouts/base.html:90 app/templates/pages/users.html:2
|
#: app/templates/layouts/base.html:90 app/templates/pages/users.html:3
|
||||||
#: app/templates/pages/users.html:3
|
#: app/templates/pages/users.html:4
|
||||||
msgid "Manage Users"
|
msgid "Manage Users"
|
||||||
msgstr "Manage Users"
|
msgstr "Manage Users"
|
||||||
|
|
||||||
@@ -1121,12 +1169,12 @@ msgid "Confirm"
|
|||||||
msgstr "Confirm"
|
msgstr "Confirm"
|
||||||
|
|
||||||
#: app/templates/pages/calendar.html:102
|
#: app/templates/pages/calendar.html:102
|
||||||
#: app/templates/pages/team_matches.html:102
|
#: app/templates/pages/team_matches.html:103
|
||||||
msgid "Delete Match"
|
msgid "Delete Match"
|
||||||
msgstr "Delete Match"
|
msgstr "Delete Match"
|
||||||
|
|
||||||
#: app/templates/pages/calendar.html:105
|
#: app/templates/pages/calendar.html:105
|
||||||
#: app/templates/pages/team_matches.html:97
|
#: app/templates/pages/team_matches.html:98
|
||||||
msgid "Edit Match"
|
msgid "Edit Match"
|
||||||
msgstr "Edit Match"
|
msgstr "Edit Match"
|
||||||
|
|
||||||
@@ -1169,7 +1217,7 @@ msgid "Contract Dropbox"
|
|||||||
msgstr "Contract Dropbox"
|
msgstr "Contract Dropbox"
|
||||||
|
|
||||||
#: app/templates/pages/contracts.html:26 app/templates/pages/notes.html:87
|
#: app/templates/pages/contracts.html:26 app/templates/pages/notes.html:87
|
||||||
#: app/templates/pages/team_matches.html:26
|
#: app/templates/pages/team_matches.html:27
|
||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Team"
|
msgstr "Team"
|
||||||
|
|
||||||
@@ -1186,8 +1234,8 @@ msgstr "Contract"
|
|||||||
#: app/templates/pages/notes.html:126 app/templates/pages/one_on_one.html:73
|
#: 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/players_to_evaluate.html:19
|
||||||
#: app/templates/pages/team_match_form.html:61
|
#: app/templates/pages/team_match_form.html:61
|
||||||
#: app/templates/pages/team_matches.html:32 app/templates/pages/teams.html:146
|
#: app/templates/pages/team_matches.html:33 app/templates/pages/teams.html:146
|
||||||
#: app/templates/pages/users.html:23 app/templates/pages/view_tryout.html:149
|
#: app/templates/pages/users.html:24 app/templates/pages/view_tryout.html:149
|
||||||
#: app/templates/pages/view_tryout.html:321
|
#: app/templates/pages/view_tryout.html:321
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
@@ -1199,8 +1247,8 @@ msgstr "Uploaded"
|
|||||||
#: app/templates/pages/contracts.html:30 app/templates/pages/dashboard.html:175
|
#: app/templates/pages/contracts.html:30 app/templates/pages/dashboard.html:175
|
||||||
#: app/templates/pages/notes.html:127
|
#: app/templates/pages/notes.html:127
|
||||||
#: app/templates/pages/players_to_evaluate.html:20
|
#: app/templates/pages/players_to_evaluate.html:20
|
||||||
#: app/templates/pages/team_matches.html:33 app/templates/pages/teams.html:151
|
#: app/templates/pages/team_matches.html:34 app/templates/pages/teams.html:151
|
||||||
#: app/templates/pages/users.html:25 app/templates/pages/view_tryout.html:154
|
#: app/templates/pages/users.html:26 app/templates/pages/view_tryout.html:154
|
||||||
#: app/templates/pages/view_tryout.html:323
|
#: app/templates/pages/view_tryout.html:323
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Actions"
|
msgstr "Actions"
|
||||||
@@ -1280,7 +1328,7 @@ msgstr "Enter full name"
|
|||||||
|
|
||||||
#: app/templates/pages/create_user.html:17
|
#: app/templates/pages/create_user.html:17
|
||||||
#: app/templates/pages/edit_profile.html:13 app/templates/pages/login.html:7
|
#: 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/register.html:15 app/templates/pages/users.html:21
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "Username"
|
msgstr "Username"
|
||||||
|
|
||||||
@@ -1291,7 +1339,7 @@ msgstr "Choose username"
|
|||||||
#: app/templates/pages/create_user.html:23
|
#: app/templates/pages/create_user.html:23
|
||||||
#: app/templates/pages/edit_profile.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/edit_user.html:17 app/templates/pages/register.html:20
|
||||||
#: app/templates/pages/teams.html:148 app/templates/pages/users.html:21
|
#: app/templates/pages/teams.html:148 app/templates/pages/users.html:22
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Email"
|
msgstr "Email"
|
||||||
|
|
||||||
@@ -1311,7 +1359,7 @@ msgstr "Phone number"
|
|||||||
|
|
||||||
#: app/templates/pages/create_user.html:31
|
#: app/templates/pages/create_user.html:31
|
||||||
#: app/templates/pages/dashboard.html:74 app/templates/pages/edit_user.html:27
|
#: app/templates/pages/dashboard.html:74 app/templates/pages/edit_user.html:27
|
||||||
#: app/templates/pages/users.html:22
|
#: app/templates/pages/users.html:23
|
||||||
msgid "Role"
|
msgid "Role"
|
||||||
msgstr "Role"
|
msgstr "Role"
|
||||||
|
|
||||||
@@ -1349,11 +1397,11 @@ msgstr "Upcoming"
|
|||||||
msgid "Recent Users"
|
msgid "Recent Users"
|
||||||
msgstr "Recent Users"
|
msgstr "Recent Users"
|
||||||
|
|
||||||
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:19
|
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:20
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:24
|
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:25
|
||||||
msgid "Joined"
|
msgid "Joined"
|
||||||
msgstr "Joined"
|
msgstr "Joined"
|
||||||
|
|
||||||
@@ -1371,7 +1419,7 @@ msgstr "Title"
|
|||||||
#: app/templates/pages/match_form.html:55 app/templates/pages/my_teams.html:92
|
#: 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/notes.html:123 app/templates/pages/one_on_one.html:70
|
||||||
#: app/templates/pages/team_match_form.html:34
|
#: app/templates/pages/team_match_form.html:34
|
||||||
#: app/templates/pages/team_matches.html:28
|
#: app/templates/pages/team_matches.html:29
|
||||||
#: app/templates/pages/view_tryout.html:317
|
#: app/templates/pages/view_tryout.html:317
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Date"
|
msgstr "Date"
|
||||||
@@ -1384,7 +1432,7 @@ msgstr "Upcoming Matches"
|
|||||||
#: app/templates/pages/dashboard.html:118
|
#: app/templates/pages/dashboard.html:118
|
||||||
#: app/templates/pages/dashboard.html:202
|
#: app/templates/pages/dashboard.html:202
|
||||||
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:90
|
#: 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/notes.html:69 app/templates/pages/team_matches.html:26
|
||||||
#: app/templates/pages/teams.html:132 app/templates/pages/view_tryout.html:315
|
#: app/templates/pages/teams.html:132 app/templates/pages/view_tryout.html:315
|
||||||
msgid "Match"
|
msgid "Match"
|
||||||
msgstr "Match"
|
msgstr "Match"
|
||||||
@@ -1439,7 +1487,7 @@ msgid "My Next Matches"
|
|||||||
msgstr "My Next Matches"
|
msgstr "My Next Matches"
|
||||||
|
|
||||||
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:91
|
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:91
|
||||||
#: app/templates/pages/team_matches.html:27
|
#: app/templates/pages/team_matches.html:28
|
||||||
msgid "Opponent"
|
msgid "Opponent"
|
||||||
msgstr "Opponent"
|
msgstr "Opponent"
|
||||||
|
|
||||||
@@ -1736,7 +1784,7 @@ msgstr "Overall"
|
|||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
#: app/templates/pages/evaluations.html:96
|
#: app/templates/pages/evaluations.html:97
|
||||||
msgid "No evaluations yet"
|
msgid "No evaluations yet"
|
||||||
msgstr "No evaluations yet"
|
msgstr "No evaluations yet"
|
||||||
|
|
||||||
@@ -1807,7 +1855,7 @@ msgstr "Cancelled"
|
|||||||
|
|
||||||
#: app/templates/pages/match_form.html:69 app/templates/pages/my_teams.html:94
|
#: 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_match_form.html:54
|
||||||
#: app/templates/pages/team_matches.html:30
|
#: app/templates/pages/team_matches.html:31
|
||||||
#: app/templates/pages/tryout_form.html:49
|
#: app/templates/pages/tryout_form.html:49
|
||||||
msgid "Location"
|
msgid "Location"
|
||||||
msgstr "Location"
|
msgstr "Location"
|
||||||
@@ -1962,14 +2010,14 @@ msgstr "No players on this team."
|
|||||||
|
|
||||||
#: app/templates/pages/my_teams.html:93 app/templates/pages/notes.html:124
|
#: app/templates/pages/my_teams.html:93 app/templates/pages/notes.html:124
|
||||||
#: app/templates/pages/one_on_one.html:71
|
#: app/templates/pages/one_on_one.html:71
|
||||||
#: app/templates/pages/team_matches.html:29
|
#: app/templates/pages/team_matches.html:30
|
||||||
#: app/templates/pages/view_tryout.html:319
|
#: app/templates/pages/view_tryout.html:319
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Time"
|
msgstr "Time"
|
||||||
|
|
||||||
#: app/templates/pages/my_teams.html:95
|
#: app/templates/pages/my_teams.html:95
|
||||||
#: app/templates/pages/team_match_form.html:115
|
#: app/templates/pages/team_match_form.html:115
|
||||||
#: app/templates/pages/team_matches.html:31
|
#: app/templates/pages/team_matches.html:32
|
||||||
#: app/templates/pages/view_tryout.html:320
|
#: app/templates/pages/view_tryout.html:320
|
||||||
msgid "Presence"
|
msgid "Presence"
|
||||||
msgstr "Presence"
|
msgstr "Presence"
|
||||||
@@ -2462,28 +2510,28 @@ msgstr "Participants"
|
|||||||
msgid "No participants recorded."
|
msgid "No participants recorded."
|
||||||
msgstr "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:3
|
||||||
|
#: app/templates/pages/team_matches.html:4
|
||||||
msgid "Team Matches"
|
msgid "Team Matches"
|
||||||
msgstr "Team Matches"
|
msgstr "Team Matches"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:10
|
#: app/templates/pages/team_matches.html:11
|
||||||
msgid "+ Schedule Match"
|
msgid "+ Schedule Match"
|
||||||
msgstr "+ Schedule Match"
|
msgstr "+ Schedule Match"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:100
|
#: app/templates/pages/team_matches.html:101
|
||||||
msgid "Delete this match?"
|
msgid "Delete this match?"
|
||||||
msgstr "Delete this match?"
|
msgstr "Delete this match?"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:131
|
#: app/templates/pages/team_matches.html:133
|
||||||
msgid "No Team Matches"
|
msgid "No Team Matches"
|
||||||
msgstr "No Team Matches"
|
msgstr "No Team Matches"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:132
|
#: app/templates/pages/team_matches.html:134
|
||||||
msgid "Regular season matches have not been scheduled yet."
|
msgid "Regular season matches have not been scheduled yet."
|
||||||
msgstr "Regular season matches have not been scheduled yet."
|
msgstr "Regular season matches have not been scheduled yet."
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:136
|
#: app/templates/pages/team_matches.html:138
|
||||||
msgid "-- Schedule a Match --"
|
msgid "-- Schedule a Match --"
|
||||||
msgstr "-- Schedule a Match --"
|
msgstr "-- Schedule a Match --"
|
||||||
|
|
||||||
@@ -2540,7 +2588,7 @@ msgstr "-- No manager assigned --"
|
|||||||
msgid "Create Team"
|
msgid "Create Team"
|
||||||
msgstr "Create Team"
|
msgstr "Create Team"
|
||||||
|
|
||||||
#: app/templates/pages/teams.html:64 app/templates/pages/users.html:50
|
#: app/templates/pages/teams.html:64 app/templates/pages/users.html:51
|
||||||
#: app/templates/pages/view_tryout.html:29
|
#: app/templates/pages/view_tryout.html:29
|
||||||
#: app/templates/pages/view_tryout.html:453
|
#: app/templates/pages/view_tryout.html:453
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
@@ -2743,11 +2791,11 @@ msgstr "Notes (Optional)"
|
|||||||
msgid "Add any notes about this contract..."
|
msgid "Add any notes about this contract..."
|
||||||
msgstr "Add any notes about this contract..."
|
msgstr "Add any notes about this contract..."
|
||||||
|
|
||||||
#: app/templates/pages/users.html:8
|
#: app/templates/pages/users.html:9
|
||||||
msgid "Add User"
|
msgid "Add User"
|
||||||
msgstr "Add User"
|
msgstr "Add User"
|
||||||
|
|
||||||
#: app/templates/pages/users.html:53
|
#: app/templates/pages/users.html:54
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Delete %(name)s? This cannot be undone."
|
msgid "Delete %(name)s? This cannot be undone."
|
||||||
msgstr "Delete %(name)s? This cannot be undone."
|
msgstr "Delete %(name)s? This cannot be undone."
|
||||||
@@ -2925,3 +2973,6 @@ msgstr "View Profile"
|
|||||||
#~ msgid "Invalid end time format."
|
#~ msgid "Invalid end time format."
|
||||||
#~ msgstr "Invalid end time format."
|
#~ msgstr "Invalid end time format."
|
||||||
|
|
||||||
|
#~ msgid "Invalid date or time format."
|
||||||
|
#~ msgstr "Invalid date or time format."
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: team-tryouts VERSION\n"
|
"Project-Id-Version: team-tryouts VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2026-08-11 18:57-0400\n"
|
"POT-Creation-Date: 2026-08-11 20:15-0400\n"
|
||||||
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
|
"PO-Revision-Date: 2026-08-07 20:22-0400\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
@@ -19,7 +19,7 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.18.0\n"
|
"Generated-By: Babel 2.18.0\n"
|
||||||
|
|
||||||
#: app/app.py:555
|
#: app/app.py:562
|
||||||
msgid "Please log in to access this page."
|
msgid "Please log in to access this page."
|
||||||
msgstr "Veuillez vous connecter pour accéder à cette page."
|
msgstr "Veuillez vous connecter pour accéder à cette page."
|
||||||
|
|
||||||
@@ -92,95 +92,127 @@ msgstr "Vous devez choisir un joueur."
|
|||||||
msgid "Notes must be 2000 characters or less."
|
msgid "Notes must be 2000 characters or less."
|
||||||
msgstr "Les notes ne doivent pas dépasser 2000 caractères."
|
msgstr "Les notes ne doivent pas dépasser 2000 caractères."
|
||||||
|
|
||||||
#: app/validators.py:476
|
#: app/validators.py:482
|
||||||
msgid "Date must be in YYYY-MM-DD format."
|
msgid "Date must be in YYYY-MM-DD format."
|
||||||
msgstr "La date doit être au format AAAA-MM-JJ."
|
msgstr "La date doit être au format AAAA-MM-JJ."
|
||||||
|
|
||||||
#: app/validators.py:481 app/validators.py:508
|
#: app/validators.py:483
|
||||||
|
msgid "A date is required."
|
||||||
|
msgstr "Une date est requise."
|
||||||
|
|
||||||
|
#: app/validators.py:489 app/validators.py:554
|
||||||
msgid "Start time must be in HH:MM format."
|
msgid "Start time must be in HH:MM format."
|
||||||
msgstr "L’heure de début doit être au format HH:MM."
|
msgstr "L’heure de début doit être au format HH:MM."
|
||||||
|
|
||||||
#: app/validators.py:485
|
#: app/validators.py:490 app/validators.py:555
|
||||||
|
msgid "A start time is required."
|
||||||
|
msgstr "Une heure de début est requise."
|
||||||
|
|
||||||
|
#: app/validators.py:496
|
||||||
msgid "End time must be in HH:MM format."
|
msgid "End time must be in HH:MM format."
|
||||||
msgstr "L’heure de fin doit être au format HH:MM."
|
msgstr "L’heure de fin doit être au format HH:MM."
|
||||||
|
|
||||||
#: app/validators.py:488
|
#: app/validators.py:497
|
||||||
|
msgid "An end time is required."
|
||||||
|
msgstr "Une heure de fin est requise."
|
||||||
|
|
||||||
|
#: app/validators.py:501
|
||||||
msgid "Points must be 2000 characters or less."
|
msgid "Points must be 2000 characters or less."
|
||||||
msgstr "Les points ne doivent pas dépasser 2000 caractères."
|
msgstr "Les points ne doivent pas dépasser 2000 caractères."
|
||||||
|
|
||||||
#: app/validators.py:504
|
#: app/validators.py:516
|
||||||
|
msgid "End time must be after start time."
|
||||||
|
msgstr "L'heure de fin doit être postérieure à l'heure de début."
|
||||||
|
|
||||||
|
#: app/validators.py:545 app/validators.py:547
|
||||||
msgid "Day must be 0 (Monday) to 6 (Sunday)."
|
msgid "Day must be 0 (Monday) to 6 (Sunday)."
|
||||||
msgstr "Le jour doit aller de 0 (lundi) à 6 (dimanche)."
|
msgstr "Le jour doit aller de 0 (lundi) à 6 (dimanche)."
|
||||||
|
|
||||||
#: app/validators.py:535
|
#: app/validators.py:548
|
||||||
|
msgid "A day is required."
|
||||||
|
msgstr "Un jour est requis."
|
||||||
|
|
||||||
|
#: app/validators.py:583
|
||||||
msgid "Player selection is malformed."
|
msgid "Player selection is malformed."
|
||||||
msgstr "La sélection de joueurs est mal formée."
|
msgstr "La sélection de joueurs est mal formée."
|
||||||
|
|
||||||
#: app/validators.py:561 app/validators.py:671
|
#: app/validators.py:609 app/validators.py:719
|
||||||
msgid "A title is required."
|
msgid "A title is required."
|
||||||
msgstr "Un titre est requis."
|
msgstr "Un titre est requis."
|
||||||
|
|
||||||
#: app/validators.py:570
|
#: app/validators.py:618
|
||||||
msgid "Invalid date format."
|
msgid "Invalid date format."
|
||||||
msgstr "Format de date invalide."
|
msgstr "Format de date invalide."
|
||||||
|
|
||||||
#: app/validators.py:575 app/validators.py:582
|
#: app/validators.py:623 app/validators.py:630
|
||||||
msgid "Invalid time format."
|
msgid "Invalid time format."
|
||||||
msgstr "Format d’heure invalide."
|
msgstr "Format d’heure invalide."
|
||||||
|
|
||||||
#: app/validators.py:576
|
#: app/validators.py:624
|
||||||
msgid "Start time is required. Please select a time slot."
|
msgid "Start time is required. Please select a time slot."
|
||||||
msgstr "L’heure de début est obligatoire. Choisissez une plage horaire."
|
msgstr "L’heure de début est obligatoire. Choisissez une plage horaire."
|
||||||
|
|
||||||
#: app/validators.py:590
|
#: app/validators.py:638
|
||||||
msgid "Unknown match status."
|
msgid "Unknown match status."
|
||||||
msgstr "Statut de match inconnu."
|
msgstr "Statut de match inconnu."
|
||||||
|
|
||||||
#: app/validators.py:606
|
#: app/validators.py:654
|
||||||
msgid "The end time must come after the start time."
|
msgid "The end time must come after the start time."
|
||||||
msgstr "L'heure de fin doit être postérieure à l'heure de début."
|
msgstr "L'heure de fin doit être postérieure à l'heure de début."
|
||||||
|
|
||||||
#: app/validators.py:620
|
#: app/validators.py:668
|
||||||
msgid "Unknown match type."
|
msgid "Unknown match type."
|
||||||
msgstr "Type de match inconnu."
|
msgstr "Type de match inconnu."
|
||||||
|
|
||||||
#: app/validators.py:632
|
#: app/validators.py:680
|
||||||
msgid "A team cannot play against itself."
|
msgid "A team cannot play against itself."
|
||||||
msgstr "Une équipe ne peut pas jouer contre elle-même."
|
msgstr "Une équipe ne peut pas jouer contre elle-même."
|
||||||
|
|
||||||
#: app/validators.py:680
|
#: app/validators.py:728
|
||||||
msgid "Unknown game."
|
msgid "Unknown game."
|
||||||
msgstr "Jeu inconnu."
|
msgstr "Jeu inconnu."
|
||||||
|
|
||||||
#: app/validators.py:685
|
#: app/validators.py:733
|
||||||
msgid "Invalid start date format."
|
msgid "Invalid start date format."
|
||||||
msgstr "Format de date de début invalide."
|
msgstr "Format de date de début invalide."
|
||||||
|
|
||||||
#: app/validators.py:686
|
#: app/validators.py:734
|
||||||
msgid "A start date is required."
|
msgid "A start date is required."
|
||||||
msgstr "Une date de début est requise."
|
msgstr "Une date de début est requise."
|
||||||
|
|
||||||
#: app/validators.py:692
|
#: app/validators.py:740
|
||||||
msgid "Invalid end date format."
|
msgid "Invalid end date format."
|
||||||
msgstr "Format de date de fin invalide."
|
msgstr "Format de date de fin invalide."
|
||||||
|
|
||||||
#: app/validators.py:700
|
#: app/validators.py:748
|
||||||
msgid "A tryout must allow at least one player."
|
msgid "A tryout must allow at least one player."
|
||||||
msgstr "Une sélection doit accepter au moins un joueur."
|
msgstr "Une sélection doit accepter au moins un joueur."
|
||||||
|
|
||||||
#: app/validators.py:703
|
#: app/validators.py:751
|
||||||
msgid "The player limit must be a whole number."
|
msgid "The player limit must be a whole number."
|
||||||
msgstr "La limite de joueurs doit être un nombre entier."
|
msgstr "La limite de joueurs doit être un nombre entier."
|
||||||
|
|
||||||
#: app/validators.py:715
|
#: app/validators.py:763
|
||||||
msgid "End date cannot be before start date."
|
msgid "End date cannot be before start date."
|
||||||
msgstr "La date de fin ne peut pas précéder la date de début."
|
msgstr "La date de fin ne peut pas précéder la date de début."
|
||||||
|
|
||||||
#: app/validators.py:724
|
#: app/validators.py:790 app/validators.py:791
|
||||||
|
msgid "Team name is required."
|
||||||
|
msgstr "Le nom de l’équipe est obligatoire."
|
||||||
|
|
||||||
|
#: app/validators.py:797
|
||||||
|
msgid "Invalid coach selection."
|
||||||
|
msgstr "Sélection de coach invalide."
|
||||||
|
|
||||||
|
#: app/validators.py:803
|
||||||
|
msgid "Invalid manager selection."
|
||||||
|
msgstr "Sélection de gérant invalide."
|
||||||
|
|
||||||
|
#: app/validators.py:815
|
||||||
msgid "Scores run from 1 to 10."
|
msgid "Scores run from 1 to 10."
|
||||||
msgstr "Les notes vont de 1 à 10."
|
msgstr "Les notes vont de 1 à 10."
|
||||||
|
|
||||||
#: app/validators.py:725
|
#: app/validators.py:816
|
||||||
msgid "A score must be a whole number from 1 to 10."
|
msgid "A score must be a whole number from 1 to 10."
|
||||||
msgstr "Une note doit être un nombre entier de 1 à 10."
|
msgstr "Une note doit être un nombre entier de 1 à 10."
|
||||||
|
|
||||||
@@ -205,11 +237,11 @@ msgstr ""
|
|||||||
msgid "Your registration could not be processed. Please try again."
|
msgid "Your registration could not be processed. Please try again."
|
||||||
msgstr "Votre inscription n'a pas pu être traitée. Veuillez réessayer."
|
msgstr "Votre inscription n'a pas pu être traitée. Veuillez réessayer."
|
||||||
|
|
||||||
#: app/routes/auth.py:388 app/routes/users/accounts.py:325
|
#: app/routes/auth.py:388 app/routes/users/accounts.py:329
|
||||||
msgid "Username already exists."
|
msgid "Username already exists."
|
||||||
msgstr "Ce nom d’utilisateur est déjà pris."
|
msgstr "Ce nom d’utilisateur est déjà pris."
|
||||||
|
|
||||||
#: app/routes/auth.py:392 app/routes/users/accounts.py:329
|
#: app/routes/auth.py:392 app/routes/users/accounts.py:333
|
||||||
msgid "Email already registered."
|
msgid "Email already registered."
|
||||||
msgstr "Cette adresse courriel est déjà enregistrée."
|
msgstr "Cette adresse courriel est déjà enregistrée."
|
||||||
|
|
||||||
@@ -253,7 +285,7 @@ msgstr "Compte Discord connecté. Votre profil a été pré-rempli."
|
|||||||
msgid "You have been logged out."
|
msgid "You have been logged out."
|
||||||
msgstr "Vous avez été déconnecté."
|
msgstr "Vous avez été déconnecté."
|
||||||
|
|
||||||
#: app/routes/evaluations.py:36
|
#: app/routes/evaluations.py:37
|
||||||
msgid "You do not have permission to view evaluations."
|
msgid "You do not have permission to view evaluations."
|
||||||
msgstr "Vous n’avez pas les droits pour consulter les évaluations."
|
msgstr "Vous n’avez pas les droits pour consulter les évaluations."
|
||||||
|
|
||||||
@@ -281,9 +313,9 @@ msgstr "Évaluation enregistrée."
|
|||||||
msgid "Evaluation updated!"
|
msgid "Evaluation updated!"
|
||||||
msgstr "Évaluation mise à jour."
|
msgstr "Évaluation mise à jour."
|
||||||
|
|
||||||
#: app/routes/evaluations.py:210 app/routes/teams.py:289
|
#: app/routes/evaluations.py:210 app/routes/teams.py:305
|
||||||
#: app/routes/teams.py:330 app/routes/teams.py:371 app/routes/teams.py:396
|
#: app/routes/teams.py:346 app/routes/teams.py:387 app/routes/teams.py:412
|
||||||
#: app/routes/teams.py:421 app/routes/teams.py:456 app/routes/tryouts.py:437
|
#: app/routes/teams.py:437 app/routes/teams.py:472 app/routes/tryouts.py:437
|
||||||
#: app/routes/tryouts.py:453 app/routes/tryouts.py:473
|
#: app/routes/tryouts.py:453 app/routes/tryouts.py:473
|
||||||
#: app/routes/tryouts.py:512 app/routes/tryouts.py:548
|
#: app/routes/tryouts.py:512 app/routes/tryouts.py:548
|
||||||
#: app/routes/tryouts.py:567
|
#: app/routes/tryouts.py:567
|
||||||
@@ -308,15 +340,15 @@ msgstr ""
|
|||||||
msgid "Match scheduled successfully!"
|
msgid "Match scheduled successfully!"
|
||||||
msgstr "Match planifié."
|
msgstr "Match planifié."
|
||||||
|
|
||||||
#: app/routes/matches.py:444 app/routes/team_matches.py:212
|
#: app/routes/matches.py:444 app/routes/team_matches.py:220
|
||||||
msgid "You do not have permission to edit this match."
|
msgid "You do not have permission to edit this match."
|
||||||
msgstr "Vous n’avez pas les droits pour modifier ce match."
|
msgstr "Vous n’avez pas les droits pour modifier ce match."
|
||||||
|
|
||||||
#: app/routes/matches.py:539 app/routes/team_matches.py:242
|
#: app/routes/matches.py:539 app/routes/team_matches.py:250
|
||||||
msgid "Match updated successfully!"
|
msgid "Match updated successfully!"
|
||||||
msgstr "Match mis à jour."
|
msgstr "Match mis à jour."
|
||||||
|
|
||||||
#: app/routes/matches.py:575 app/routes/team_matches.py:257
|
#: app/routes/matches.py:575 app/routes/team_matches.py:265
|
||||||
msgid "You do not have permission to delete this match."
|
msgid "You do not have permission to delete this match."
|
||||||
msgstr "Vous n’avez pas les droits pour supprimer ce match."
|
msgstr "Vous n’avez pas les droits pour supprimer ce match."
|
||||||
|
|
||||||
@@ -324,155 +356,151 @@ msgstr "Vous n’avez pas les droits pour supprimer ce match."
|
|||||||
msgid "This tryout has ended. Matches can no longer be deleted."
|
msgid "This tryout has ended. Matches can no longer be deleted."
|
||||||
msgstr "Cette sélection est terminée. Les matchs ne peuvent plus être supprimés."
|
msgstr "Cette sélection est terminée. Les matchs ne peuvent plus être supprimés."
|
||||||
|
|
||||||
#: app/routes/matches.py:591 app/routes/team_matches.py:261
|
#: app/routes/matches.py:591 app/routes/team_matches.py:269
|
||||||
msgid "Match deleted successfully."
|
msgid "Match deleted successfully."
|
||||||
msgstr "Match supprimé."
|
msgstr "Match supprimé."
|
||||||
|
|
||||||
#: app/routes/team_matches.py:105
|
#: app/routes/team_matches.py:113
|
||||||
msgid "You do not have permission to schedule matches for this team."
|
msgid "You do not have permission to schedule matches for this team."
|
||||||
msgstr "Vous n’avez pas les droits pour planifier des matchs pour cette équipe."
|
msgstr "Vous n’avez pas les droits pour planifier des matchs pour cette équipe."
|
||||||
|
|
||||||
#: app/routes/team_matches.py:197
|
#: app/routes/team_matches.py:205
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team match \"%(title)s\" scheduled successfully!"
|
msgid "Team match \"%(title)s\" scheduled successfully!"
|
||||||
msgstr "Match d’équipe « %(title)s » planifié."
|
msgstr "Match d’équipe « %(title)s » planifié."
|
||||||
|
|
||||||
#: app/routes/teams.py:41
|
#: app/routes/teams.py:44
|
||||||
msgid "Use My Team(s) to view your teams."
|
msgid "Use My Team(s) to view your teams."
|
||||||
msgstr "Utilisez « Mon ou mes équipes » pour consulter vos équipes."
|
msgstr "Utilisez « Mon ou mes équipes » pour consulter vos équipes."
|
||||||
|
|
||||||
#: app/routes/teams.py:44
|
#: app/routes/teams.py:47
|
||||||
msgid "You do not have permission to view teams."
|
msgid "You do not have permission to view teams."
|
||||||
msgstr "Vous n’avez pas les droits pour consulter les équipes."
|
msgstr "Vous n’avez pas les droits pour consulter les équipes."
|
||||||
|
|
||||||
#: app/routes/teams.py:71
|
#: app/routes/teams.py:74
|
||||||
msgid "This page is for players."
|
msgid "This page is for players."
|
||||||
msgstr "Cette page est réservée aux joueurs."
|
msgstr "Cette page est réservée aux joueurs."
|
||||||
|
|
||||||
#: app/routes/teams.py:124
|
#: app/routes/teams.py:150
|
||||||
msgid "You do not have permission to create teams."
|
msgid "You do not have permission to create teams."
|
||||||
msgstr "Vous n’avez pas les droits pour créer une équipe."
|
msgstr "Vous n’avez pas les droits pour créer une équipe."
|
||||||
|
|
||||||
#: app/routes/teams.py:132 app/routes/teams.py:177
|
#: app/routes/teams.py:161 app/routes/teams.py:203
|
||||||
msgid "Team name is required."
|
|
||||||
msgstr "Le nom de l’équipe est obligatoire."
|
|
||||||
|
|
||||||
#: app/routes/teams.py:137 app/routes/teams.py:182
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" already exists."
|
msgid "Team \"%(name)s\" already exists."
|
||||||
msgstr "L’équipe « %(name)s » existe déjà."
|
msgstr "L’équipe « %(name)s » existe déjà."
|
||||||
|
|
||||||
#: app/routes/teams.py:159
|
#: app/routes/teams.py:182
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" created successfully!"
|
msgid "Team \"%(name)s\" created successfully!"
|
||||||
msgstr "Équipe « %(name)s » créée."
|
msgstr "Équipe « %(name)s » créée."
|
||||||
|
|
||||||
#: app/routes/teams.py:169
|
#: app/routes/teams.py:192
|
||||||
msgid "You do not have permission to edit this team."
|
msgid "You do not have permission to edit this team."
|
||||||
msgstr "Vous n’avez pas les droits pour modifier cette équipe."
|
msgstr "Vous n’avez pas les droits pour modifier cette équipe."
|
||||||
|
|
||||||
#: app/routes/teams.py:220
|
#: app/routes/teams.py:236
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" updated successfully!"
|
msgid "Team \"%(name)s\" updated successfully!"
|
||||||
msgstr "Équipe « %(name)s » mise à jour."
|
msgstr "Équipe « %(name)s » mise à jour."
|
||||||
|
|
||||||
#: app/routes/teams.py:248
|
#: app/routes/teams.py:264
|
||||||
msgid "You do not have permission to delete teams."
|
msgid "You do not have permission to delete teams."
|
||||||
msgstr "Vous n’avez pas les droits pour supprimer une équipe."
|
msgstr "Vous n’avez pas les droits pour supprimer une équipe."
|
||||||
|
|
||||||
#: app/routes/teams.py:279
|
#: app/routes/teams.py:295
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Team \"%(name)s\" deleted successfully."
|
msgid "Team \"%(name)s\" deleted successfully."
|
||||||
msgstr "Équipe « %(name)s » supprimée."
|
msgstr "Équipe « %(name)s » supprimée."
|
||||||
|
|
||||||
#: app/routes/teams.py:294
|
#: app/routes/teams.py:310
|
||||||
msgid "Please select a coach."
|
msgid "Please select a coach."
|
||||||
msgstr "Veuillez choisir un coach."
|
msgstr "Veuillez choisir un coach."
|
||||||
|
|
||||||
#: app/routes/teams.py:299
|
#: app/routes/teams.py:315
|
||||||
msgid "Only coaches can be assigned as coach."
|
msgid "Only coaches can be assigned as coach."
|
||||||
msgstr "Seuls les coachs peuvent être assignés comme coach."
|
msgstr "Seuls les coachs peuvent être assignés comme coach."
|
||||||
|
|
||||||
#: app/routes/teams.py:305
|
#: app/routes/teams.py:321
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is already a coach of %(name)s."
|
msgid "%(username)s is already a coach of %(name)s."
|
||||||
msgstr "%(username)s est déjà coach de %(name)s."
|
msgstr "%(username)s est déjà coach de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:318
|
#: app/routes/teams.py:334
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s added as coach of %(name)s."
|
msgid "%(username)s added as coach of %(name)s."
|
||||||
msgstr "%(username)s a été ajouté comme coach de %(name)s."
|
msgstr "%(username)s a été ajouté comme coach de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:335
|
#: app/routes/teams.py:351
|
||||||
msgid "Please select a manager."
|
msgid "Please select a manager."
|
||||||
msgstr "Veuillez choisir un gérant."
|
msgstr "Veuillez choisir un gérant."
|
||||||
|
|
||||||
#: app/routes/teams.py:340
|
#: app/routes/teams.py:356
|
||||||
msgid "Only managers can be assigned as manager."
|
msgid "Only managers can be assigned as manager."
|
||||||
msgstr "Seuls les gérants peuvent être assignés comme gérant."
|
msgstr "Seuls les gérants peuvent être assignés comme gérant."
|
||||||
|
|
||||||
#: app/routes/teams.py:346
|
#: app/routes/teams.py:362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is already a manager of %(name)s."
|
msgid "%(username)s is already a manager of %(name)s."
|
||||||
msgstr "%(username)s est déjà gérant de %(name)s."
|
msgstr "%(username)s est déjà gérant de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:359
|
#: app/routes/teams.py:375
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s added as manager of %(name)s."
|
msgid "%(username)s added as manager of %(name)s."
|
||||||
msgstr "%(username)s a été ajouté comme gérant de %(name)s."
|
msgstr "%(username)s a été ajouté comme gérant de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:386
|
#: app/routes/teams.py:402
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Coach removed from %(name)s."
|
msgid "Coach removed from %(name)s."
|
||||||
msgstr "Coach retiré de %(name)s."
|
msgstr "Coach retiré de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:411
|
#: app/routes/teams.py:427
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Manager removed from %(name)s."
|
msgid "Manager removed from %(name)s."
|
||||||
msgstr "Gérant retiré de %(name)s."
|
msgstr "Gérant retiré de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:427 app/routes/tryouts.py:477 app/routes/tryouts.py:578
|
#: app/routes/teams.py:443 app/routes/tryouts.py:477 app/routes/tryouts.py:578
|
||||||
msgid "Please select a player."
|
msgid "Please select a player."
|
||||||
msgstr "Veuillez choisir un joueur."
|
msgstr "Veuillez choisir un joueur."
|
||||||
|
|
||||||
#: app/routes/teams.py:432
|
#: app/routes/teams.py:448
|
||||||
msgid "Can only assign players to teams."
|
msgid "Can only assign players to teams."
|
||||||
msgstr "Seuls des joueurs peuvent être assignés à une équipe."
|
msgstr "Seuls des joueurs peuvent être assignés à une équipe."
|
||||||
|
|
||||||
#: app/routes/teams.py:438
|
#: app/routes/teams.py:454
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is already on %(name)s."
|
msgid "%(username)s is already on %(name)s."
|
||||||
msgstr "%(username)s fait déjà partie de %(name)s."
|
msgstr "%(username)s fait déjà partie de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:446
|
#: app/routes/teams.py:462
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s added to %(name)s!"
|
msgid "%(username)s added to %(name)s!"
|
||||||
msgstr "%(username)s a été ajouté à %(name)s."
|
msgstr "%(username)s a été ajouté à %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:463 app/routes/teams.py:537
|
#: app/routes/teams.py:479 app/routes/teams.py:553
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s is not on %(name)s."
|
msgid "%(username)s is not on %(name)s."
|
||||||
msgstr "%(username)s ne fait pas partie de %(name)s."
|
msgstr "%(username)s ne fait pas partie de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:471
|
#: app/routes/teams.py:487
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(username)s removed from %(name)s."
|
msgid "%(username)s removed from %(name)s."
|
||||||
msgstr "%(username)s a été retiré de %(name)s."
|
msgstr "%(username)s a été retiré de %(name)s."
|
||||||
|
|
||||||
#: app/routes/teams.py:508 app/routes/teams.py:526
|
#: app/routes/teams.py:524 app/routes/teams.py:542
|
||||||
msgid "You do not have permission to add notes to this team."
|
msgid "You do not have permission to add notes to this team."
|
||||||
msgstr "Vous n’avez pas les droits pour ajouter des notes à cette équipe."
|
msgstr "Vous n’avez pas les droits pour ajouter des notes à cette équipe."
|
||||||
|
|
||||||
#: app/routes/teams.py:516
|
#: app/routes/teams.py:532
|
||||||
msgid "Team notes added successfully!"
|
msgid "Team notes added successfully!"
|
||||||
msgstr "Notes d’équipe ajoutées."
|
msgstr "Notes d’équipe ajoutées."
|
||||||
|
|
||||||
#: app/routes/teams.py:531 app/routes/users/notes.py:207
|
#: app/routes/teams.py:547 app/routes/users/notes.py:207
|
||||||
#: app/routes/users/notes.py:250
|
#: app/routes/users/notes.py:250
|
||||||
msgid "Can only add notes for players."
|
msgid "Can only add notes for players."
|
||||||
msgstr "Il n’est possible d’ajouter des notes que pour des joueurs."
|
msgstr "Il n’est possible d’ajouter des notes que pour des joueurs."
|
||||||
|
|
||||||
#: app/routes/teams.py:547
|
#: app/routes/teams.py:563
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Note added for %(username)s!"
|
msgid "Note added for %(username)s!"
|
||||||
msgstr "Note ajoutée pour %(username)s."
|
msgstr "Note ajoutée pour %(username)s."
|
||||||
@@ -586,25 +614,25 @@ msgstr "Seuls les fichiers PDF sont acceptés pour les contrats."
|
|||||||
msgid "That file is not a PDF, whatever its name says."
|
msgid "That file is not a PDF, whatever its name says."
|
||||||
msgstr "Ce fichier n’est pas un PDF, quel que soit son nom."
|
msgstr "Ce fichier n’est pas un PDF, quel que soit son nom."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:54
|
#: app/routes/users/accounts.py:55
|
||||||
msgid "Only the president can manage users."
|
msgid "Only the president can manage users."
|
||||||
msgstr "Seul le président peut gérer les utilisateurs."
|
msgstr "Seul le président peut gérer les utilisateurs."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:66
|
#: app/routes/users/accounts.py:70
|
||||||
msgid "Only the president can edit users."
|
msgid "Only the president can edit users."
|
||||||
msgstr "Seul le président peut modifier des utilisateurs."
|
msgstr "Seul le président peut modifier des utilisateurs."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:107
|
#: app/routes/users/accounts.py:111
|
||||||
msgid "Email already in use by another account."
|
msgid "Email already in use by another account."
|
||||||
msgstr "Cette adresse courriel est déjà utilisée par un autre compte."
|
msgstr "Cette adresse courriel est déjà utilisée par un autre compte."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:118
|
#: app/routes/users/accounts.py:122
|
||||||
msgid "You cannot change your own role. Ask another president to do it."
|
msgid "You cannot change your own role. Ask another president to do it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous ne pouvez pas modifier votre propre rôle. Demandez à un autre "
|
"Vous ne pouvez pas modifier votre propre rôle. Demandez à un autre "
|
||||||
"président de le faire."
|
"président de le faire."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:131
|
#: app/routes/users/accounts.py:135
|
||||||
msgid ""
|
msgid ""
|
||||||
"This is the last active president. Promote another account before "
|
"This is the last active president. Promote another account before "
|
||||||
"changing this one."
|
"changing this one."
|
||||||
@@ -612,34 +640,34 @@ msgstr ""
|
|||||||
"C’est le dernier président actif. Promouvez un autre compte avant de "
|
"C’est le dernier président actif. Promouvez un autre compte avant de "
|
||||||
"modifier celui-ci."
|
"modifier celui-ci."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:210
|
#: app/routes/users/accounts.py:214
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User %(username)s updated successfully!"
|
msgid "User %(username)s updated successfully!"
|
||||||
msgstr "Utilisateur %(username)s mis à jour."
|
msgstr "Utilisateur %(username)s mis à jour."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:231
|
#: app/routes/users/accounts.py:235
|
||||||
msgid "Only the president can delete users."
|
msgid "Only the president can delete users."
|
||||||
msgstr "Seul le président peut supprimer des utilisateurs."
|
msgstr "Seul le président peut supprimer des utilisateurs."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:235
|
#: app/routes/users/accounts.py:239
|
||||||
msgid "You cannot delete your own account."
|
msgid "You cannot delete your own account."
|
||||||
msgstr "Vous ne pouvez pas supprimer votre propre compte."
|
msgstr "Vous ne pouvez pas supprimer votre propre compte."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:294
|
#: app/routes/users/accounts.py:298
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User %(deleted_username)s has been removed."
|
msgid "User %(deleted_username)s has been removed."
|
||||||
msgstr "L’utilisateur %(deleted_username)s a été supprimé."
|
msgstr "L’utilisateur %(deleted_username)s a été supprimé."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:305
|
#: app/routes/users/accounts.py:309
|
||||||
msgid "Only the president can create users."
|
msgid "Only the president can create users."
|
||||||
msgstr "Seul le président peut créer des utilisateurs."
|
msgstr "Seul le président peut créer des utilisateurs."
|
||||||
|
|
||||||
#: app/routes/users/accounts.py:353
|
#: app/routes/users/accounts.py:357
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User %(full_name)s created as %(role)s!"
|
msgid "User %(full_name)s created as %(role)s!"
|
||||||
msgstr "Utilisateur %(full_name)s créé avec le rôle %(role)s."
|
msgstr "Utilisateur %(full_name)s créé avec le rôle %(role)s."
|
||||||
|
|
||||||
#: app/routes/users/availability.py:187
|
#: app/routes/users/availability.py:210
|
||||||
msgid "Only coaches can manage availability."
|
msgid "Only coaches can manage availability."
|
||||||
msgstr "Seuls les coachs peuvent gérer leurs disponibilités."
|
msgstr "Seuls les coachs peuvent gérer leurs disponibilités."
|
||||||
|
|
||||||
@@ -722,52 +750,48 @@ msgstr "Seuls les coachs peuvent ajouter des notes personnelles."
|
|||||||
msgid "Note added successfully."
|
msgid "Note added successfully."
|
||||||
msgstr "Note ajoutée."
|
msgstr "Note ajoutée."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:20
|
#: app/routes/users/one_on_one.py:23
|
||||||
msgid "Only players can request One on One sessions."
|
msgid "Only players can request One on One sessions."
|
||||||
msgstr "Seuls les joueurs peuvent demander une rencontre individuelle."
|
msgstr "Seuls les joueurs peuvent demander une rencontre individuelle."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:33
|
#: app/routes/users/one_on_one.py:36
|
||||||
msgid "You do not have a coach assigned to your team."
|
msgid "You do not have a coach assigned to your team."
|
||||||
msgstr "Aucun coach n’est assigné à votre équipe."
|
msgstr "Aucun coach n’est assigné à votre équipe."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:68
|
#: app/routes/users/one_on_one.py:67
|
||||||
msgid "Cannot request One on One - no coach assigned."
|
msgid "Cannot request One on One - no coach assigned."
|
||||||
msgstr "Impossible de demander une rencontre : aucun coach assigné."
|
msgstr "Impossible de demander une rencontre : aucun coach assigné."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:76
|
#: app/routes/users/one_on_one.py:93
|
||||||
msgid "Invalid date or time format."
|
|
||||||
msgstr "Format de date ou d’heure invalide."
|
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:90
|
|
||||||
msgid "The requested time is not within the coach's availability."
|
msgid "The requested time is not within the coach's availability."
|
||||||
msgstr "L’horaire demandé ne correspond à aucune disponibilité du coach."
|
msgstr "L’horaire demandé ne correspond à aucune disponibilité du coach."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:118
|
#: app/routes/users/one_on_one.py:121
|
||||||
msgid "Your One on One request has been submitted!"
|
msgid "Your One on One request has been submitted!"
|
||||||
msgstr "Votre demande de rencontre a été envoyée."
|
msgstr "Votre demande de rencontre a été envoyée."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:163
|
#: app/routes/users/one_on_one.py:166
|
||||||
msgid "Only coaches can accept One on One requests."
|
msgid "Only coaches can accept One on One requests."
|
||||||
msgstr "Seuls les coachs peuvent accepter une demande de rencontre."
|
msgstr "Seuls les coachs peuvent accepter une demande de rencontre."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:169 app/routes/users/one_on_one.py:219
|
#: app/routes/users/one_on_one.py:172 app/routes/users/one_on_one.py:222
|
||||||
msgid "This request is not for you."
|
msgid "This request is not for you."
|
||||||
msgstr "Cette demande ne vous est pas destinée."
|
msgstr "Cette demande ne vous est pas destinée."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:173 app/routes/users/one_on_one.py:223
|
#: app/routes/users/one_on_one.py:176 app/routes/users/one_on_one.py:226
|
||||||
msgid "This request has already been processed."
|
msgid "This request has already been processed."
|
||||||
msgstr "Cette demande a déjà été traitée."
|
msgstr "Cette demande a déjà été traitée."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:200
|
#: app/routes/users/one_on_one.py:203
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "One on One request from %(player)s has been approved!"
|
msgid "One on One request from %(player)s has been approved!"
|
||||||
msgstr "La demande de rencontre de %(player)s a été approuvée."
|
msgstr "La demande de rencontre de %(player)s a été approuvée."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:213
|
#: app/routes/users/one_on_one.py:216
|
||||||
msgid "Only coaches can reject One on One requests."
|
msgid "Only coaches can reject One on One requests."
|
||||||
msgstr "Seuls les coachs peuvent refuser une demande de rencontre."
|
msgstr "Seuls les coachs peuvent refuser une demande de rencontre."
|
||||||
|
|
||||||
#: app/routes/users/one_on_one.py:255
|
#: app/routes/users/one_on_one.py:258
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "One on One request from %(player)s has been rejected."
|
msgid "One on One request from %(player)s has been rejected."
|
||||||
msgstr "La demande de rencontre de %(player)s a été refusée."
|
msgstr "La demande de rencontre de %(player)s a été refusée."
|
||||||
@@ -903,6 +927,30 @@ msgstr "Réessayer"
|
|||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Langue"
|
msgstr "Langue"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:19
|
||||||
|
msgid "Pagination"
|
||||||
|
msgstr "Pagination"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:22
|
||||||
|
#: app/templates/layouts/_pagination.html:24
|
||||||
|
msgid "Previous"
|
||||||
|
msgstr "Précédent"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:28
|
||||||
|
#, python-format
|
||||||
|
msgid "Page %(page)s of %(pages)s"
|
||||||
|
msgstr "Page %(page)s sur %(pages)s"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:30
|
||||||
|
#, python-format
|
||||||
|
msgid "%(total)s in total"
|
||||||
|
msgstr "%(total)s au total"
|
||||||
|
|
||||||
|
#: app/templates/layouts/_pagination.html:35
|
||||||
|
#: app/templates/layouts/_pagination.html:37
|
||||||
|
msgid "Next"
|
||||||
|
msgstr "Suivant"
|
||||||
|
|
||||||
#: app/templates/layouts/base.html:48 app/templates/layouts/base.html:154
|
#: app/templates/layouts/base.html:48 app/templates/layouts/base.html:154
|
||||||
#: app/templates/pages/dashboard.html:2 app/templates/pages/dashboard.html:3
|
#: app/templates/pages/dashboard.html:2 app/templates/pages/dashboard.html:3
|
||||||
msgid "Dashboard"
|
msgid "Dashboard"
|
||||||
@@ -919,8 +967,8 @@ msgid "Calendar"
|
|||||||
msgstr "Calendrier"
|
msgstr "Calendrier"
|
||||||
|
|
||||||
#: app/templates/layouts/base.html:67 app/templates/pages/dashboard.html:43
|
#: app/templates/layouts/base.html:67 app/templates/pages/dashboard.html:43
|
||||||
#: app/templates/pages/evaluations.html:2
|
|
||||||
#: app/templates/pages/evaluations.html:3
|
#: app/templates/pages/evaluations.html:3
|
||||||
|
#: app/templates/pages/evaluations.html:4
|
||||||
msgid "Evaluations"
|
msgid "Evaluations"
|
||||||
msgstr "Évaluations"
|
msgstr "Évaluations"
|
||||||
|
|
||||||
@@ -933,8 +981,8 @@ msgstr "Mon ou mes équipes"
|
|||||||
msgid "Manage Teams"
|
msgid "Manage Teams"
|
||||||
msgstr "Gestion des équipes"
|
msgstr "Gestion des équipes"
|
||||||
|
|
||||||
#: app/templates/layouts/base.html:90 app/templates/pages/users.html:2
|
#: app/templates/layouts/base.html:90 app/templates/pages/users.html:3
|
||||||
#: app/templates/pages/users.html:3
|
#: app/templates/pages/users.html:4
|
||||||
msgid "Manage Users"
|
msgid "Manage Users"
|
||||||
msgstr "Gestion des utilisateurs"
|
msgstr "Gestion des utilisateurs"
|
||||||
|
|
||||||
@@ -1127,12 +1175,12 @@ msgid "Confirm"
|
|||||||
msgstr "Confirmer"
|
msgstr "Confirmer"
|
||||||
|
|
||||||
#: app/templates/pages/calendar.html:102
|
#: app/templates/pages/calendar.html:102
|
||||||
#: app/templates/pages/team_matches.html:102
|
#: app/templates/pages/team_matches.html:103
|
||||||
msgid "Delete Match"
|
msgid "Delete Match"
|
||||||
msgstr "Supprimer le match"
|
msgstr "Supprimer le match"
|
||||||
|
|
||||||
#: app/templates/pages/calendar.html:105
|
#: app/templates/pages/calendar.html:105
|
||||||
#: app/templates/pages/team_matches.html:97
|
#: app/templates/pages/team_matches.html:98
|
||||||
msgid "Edit Match"
|
msgid "Edit Match"
|
||||||
msgstr "Modifier le match"
|
msgstr "Modifier le match"
|
||||||
|
|
||||||
@@ -1177,7 +1225,7 @@ msgid "Contract Dropbox"
|
|||||||
msgstr "Dépôt de contrats"
|
msgstr "Dépôt de contrats"
|
||||||
|
|
||||||
#: app/templates/pages/contracts.html:26 app/templates/pages/notes.html:87
|
#: app/templates/pages/contracts.html:26 app/templates/pages/notes.html:87
|
||||||
#: app/templates/pages/team_matches.html:26
|
#: app/templates/pages/team_matches.html:27
|
||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Équipe"
|
msgstr "Équipe"
|
||||||
|
|
||||||
@@ -1194,8 +1242,8 @@ msgstr "Contrat"
|
|||||||
#: app/templates/pages/notes.html:126 app/templates/pages/one_on_one.html:73
|
#: 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/players_to_evaluate.html:19
|
||||||
#: app/templates/pages/team_match_form.html:61
|
#: app/templates/pages/team_match_form.html:61
|
||||||
#: app/templates/pages/team_matches.html:32 app/templates/pages/teams.html:146
|
#: app/templates/pages/team_matches.html:33 app/templates/pages/teams.html:146
|
||||||
#: app/templates/pages/users.html:23 app/templates/pages/view_tryout.html:149
|
#: app/templates/pages/users.html:24 app/templates/pages/view_tryout.html:149
|
||||||
#: app/templates/pages/view_tryout.html:321
|
#: app/templates/pages/view_tryout.html:321
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Statut"
|
msgstr "Statut"
|
||||||
@@ -1207,8 +1255,8 @@ msgstr "Téléversé le"
|
|||||||
#: app/templates/pages/contracts.html:30 app/templates/pages/dashboard.html:175
|
#: app/templates/pages/contracts.html:30 app/templates/pages/dashboard.html:175
|
||||||
#: app/templates/pages/notes.html:127
|
#: app/templates/pages/notes.html:127
|
||||||
#: app/templates/pages/players_to_evaluate.html:20
|
#: app/templates/pages/players_to_evaluate.html:20
|
||||||
#: app/templates/pages/team_matches.html:33 app/templates/pages/teams.html:151
|
#: app/templates/pages/team_matches.html:34 app/templates/pages/teams.html:151
|
||||||
#: app/templates/pages/users.html:25 app/templates/pages/view_tryout.html:154
|
#: app/templates/pages/users.html:26 app/templates/pages/view_tryout.html:154
|
||||||
#: app/templates/pages/view_tryout.html:323
|
#: app/templates/pages/view_tryout.html:323
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Actions"
|
msgstr "Actions"
|
||||||
@@ -1286,7 +1334,7 @@ msgstr "Saisir le nom complet"
|
|||||||
|
|
||||||
#: app/templates/pages/create_user.html:17
|
#: app/templates/pages/create_user.html:17
|
||||||
#: app/templates/pages/edit_profile.html:13 app/templates/pages/login.html:7
|
#: 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/register.html:15 app/templates/pages/users.html:21
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "Nom d’utilisateur"
|
msgstr "Nom d’utilisateur"
|
||||||
|
|
||||||
@@ -1297,7 +1345,7 @@ msgstr "Choisir un nom d’utilisateur"
|
|||||||
#: app/templates/pages/create_user.html:23
|
#: app/templates/pages/create_user.html:23
|
||||||
#: app/templates/pages/edit_profile.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/edit_user.html:17 app/templates/pages/register.html:20
|
||||||
#: app/templates/pages/teams.html:148 app/templates/pages/users.html:21
|
#: app/templates/pages/teams.html:148 app/templates/pages/users.html:22
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Courriel"
|
msgstr "Courriel"
|
||||||
|
|
||||||
@@ -1317,7 +1365,7 @@ msgstr "Numéro de téléphone"
|
|||||||
|
|
||||||
#: app/templates/pages/create_user.html:31
|
#: app/templates/pages/create_user.html:31
|
||||||
#: app/templates/pages/dashboard.html:74 app/templates/pages/edit_user.html:27
|
#: app/templates/pages/dashboard.html:74 app/templates/pages/edit_user.html:27
|
||||||
#: app/templates/pages/users.html:22
|
#: app/templates/pages/users.html:23
|
||||||
msgid "Role"
|
msgid "Role"
|
||||||
msgstr "Rôle"
|
msgstr "Rôle"
|
||||||
|
|
||||||
@@ -1355,11 +1403,11 @@ msgstr "À venir"
|
|||||||
msgid "Recent Users"
|
msgid "Recent Users"
|
||||||
msgstr "Utilisateurs récents"
|
msgstr "Utilisateurs récents"
|
||||||
|
|
||||||
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:19
|
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:20
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:24
|
#: app/templates/pages/dashboard.html:74 app/templates/pages/users.html:25
|
||||||
msgid "Joined"
|
msgid "Joined"
|
||||||
msgstr "Inscrit le"
|
msgstr "Inscrit le"
|
||||||
|
|
||||||
@@ -1377,7 +1425,7 @@ msgstr "Titre"
|
|||||||
#: app/templates/pages/match_form.html:55 app/templates/pages/my_teams.html:92
|
#: 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/notes.html:123 app/templates/pages/one_on_one.html:70
|
||||||
#: app/templates/pages/team_match_form.html:34
|
#: app/templates/pages/team_match_form.html:34
|
||||||
#: app/templates/pages/team_matches.html:28
|
#: app/templates/pages/team_matches.html:29
|
||||||
#: app/templates/pages/view_tryout.html:317
|
#: app/templates/pages/view_tryout.html:317
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Date"
|
msgstr "Date"
|
||||||
@@ -1390,7 +1438,7 @@ msgstr "Matchs à venir"
|
|||||||
#: app/templates/pages/dashboard.html:118
|
#: app/templates/pages/dashboard.html:118
|
||||||
#: app/templates/pages/dashboard.html:202
|
#: app/templates/pages/dashboard.html:202
|
||||||
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:90
|
#: 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/notes.html:69 app/templates/pages/team_matches.html:26
|
||||||
#: app/templates/pages/teams.html:132 app/templates/pages/view_tryout.html:315
|
#: app/templates/pages/teams.html:132 app/templates/pages/view_tryout.html:315
|
||||||
msgid "Match"
|
msgid "Match"
|
||||||
msgstr "Match"
|
msgstr "Match"
|
||||||
@@ -1445,7 +1493,7 @@ msgid "My Next Matches"
|
|||||||
msgstr "Mes prochains matchs"
|
msgstr "Mes prochains matchs"
|
||||||
|
|
||||||
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:91
|
#: app/templates/pages/dashboard.html:285 app/templates/pages/my_teams.html:91
|
||||||
#: app/templates/pages/team_matches.html:27
|
#: app/templates/pages/team_matches.html:28
|
||||||
msgid "Opponent"
|
msgid "Opponent"
|
||||||
msgstr "Adversaire"
|
msgstr "Adversaire"
|
||||||
|
|
||||||
@@ -1744,7 +1792,7 @@ msgstr "Global"
|
|||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Poste"
|
msgstr "Poste"
|
||||||
|
|
||||||
#: app/templates/pages/evaluations.html:96
|
#: app/templates/pages/evaluations.html:97
|
||||||
msgid "No evaluations yet"
|
msgid "No evaluations yet"
|
||||||
msgstr "Aucune évaluation"
|
msgstr "Aucune évaluation"
|
||||||
|
|
||||||
@@ -1815,7 +1863,7 @@ msgstr "Annulé"
|
|||||||
|
|
||||||
#: app/templates/pages/match_form.html:69 app/templates/pages/my_teams.html:94
|
#: 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_match_form.html:54
|
||||||
#: app/templates/pages/team_matches.html:30
|
#: app/templates/pages/team_matches.html:31
|
||||||
#: app/templates/pages/tryout_form.html:49
|
#: app/templates/pages/tryout_form.html:49
|
||||||
msgid "Location"
|
msgid "Location"
|
||||||
msgstr "Lieu"
|
msgstr "Lieu"
|
||||||
@@ -1975,14 +2023,14 @@ msgstr "Aucun joueur dans cette équipe."
|
|||||||
|
|
||||||
#: app/templates/pages/my_teams.html:93 app/templates/pages/notes.html:124
|
#: app/templates/pages/my_teams.html:93 app/templates/pages/notes.html:124
|
||||||
#: app/templates/pages/one_on_one.html:71
|
#: app/templates/pages/one_on_one.html:71
|
||||||
#: app/templates/pages/team_matches.html:29
|
#: app/templates/pages/team_matches.html:30
|
||||||
#: app/templates/pages/view_tryout.html:319
|
#: app/templates/pages/view_tryout.html:319
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Heure"
|
msgstr "Heure"
|
||||||
|
|
||||||
#: app/templates/pages/my_teams.html:95
|
#: app/templates/pages/my_teams.html:95
|
||||||
#: app/templates/pages/team_match_form.html:115
|
#: app/templates/pages/team_match_form.html:115
|
||||||
#: app/templates/pages/team_matches.html:31
|
#: app/templates/pages/team_matches.html:32
|
||||||
#: app/templates/pages/view_tryout.html:320
|
#: app/templates/pages/view_tryout.html:320
|
||||||
msgid "Presence"
|
msgid "Presence"
|
||||||
msgstr "Présence"
|
msgstr "Présence"
|
||||||
@@ -2477,28 +2525,28 @@ msgstr "Participants"
|
|||||||
msgid "No participants recorded."
|
msgid "No participants recorded."
|
||||||
msgstr "Aucun participant enregistré."
|
msgstr "Aucun participant enregistré."
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:2
|
|
||||||
#: app/templates/pages/team_matches.html:3
|
#: app/templates/pages/team_matches.html:3
|
||||||
|
#: app/templates/pages/team_matches.html:4
|
||||||
msgid "Team Matches"
|
msgid "Team Matches"
|
||||||
msgstr "Matchs d’équipe"
|
msgstr "Matchs d’équipe"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:10
|
#: app/templates/pages/team_matches.html:11
|
||||||
msgid "+ Schedule Match"
|
msgid "+ Schedule Match"
|
||||||
msgstr "+ Planifier un match"
|
msgstr "+ Planifier un match"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:100
|
#: app/templates/pages/team_matches.html:101
|
||||||
msgid "Delete this match?"
|
msgid "Delete this match?"
|
||||||
msgstr "Supprimer ce match ?"
|
msgstr "Supprimer ce match ?"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:131
|
#: app/templates/pages/team_matches.html:133
|
||||||
msgid "No Team Matches"
|
msgid "No Team Matches"
|
||||||
msgstr "Aucun match d’équipe"
|
msgstr "Aucun match d’équipe"
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:132
|
#: app/templates/pages/team_matches.html:134
|
||||||
msgid "Regular season matches have not been scheduled yet."
|
msgid "Regular season matches have not been scheduled yet."
|
||||||
msgstr "Aucun match de saison régulière n’a encore été planifié."
|
msgstr "Aucun match de saison régulière n’a encore été planifié."
|
||||||
|
|
||||||
#: app/templates/pages/team_matches.html:136
|
#: app/templates/pages/team_matches.html:138
|
||||||
msgid "-- Schedule a Match --"
|
msgid "-- Schedule a Match --"
|
||||||
msgstr "-- Planifier un match --"
|
msgstr "-- Planifier un match --"
|
||||||
|
|
||||||
@@ -2555,7 +2603,7 @@ msgstr "-- Aucun gérant assigné --"
|
|||||||
msgid "Create Team"
|
msgid "Create Team"
|
||||||
msgstr "Créer l’équipe"
|
msgstr "Créer l’équipe"
|
||||||
|
|
||||||
#: app/templates/pages/teams.html:64 app/templates/pages/users.html:50
|
#: app/templates/pages/teams.html:64 app/templates/pages/users.html:51
|
||||||
#: app/templates/pages/view_tryout.html:29
|
#: app/templates/pages/view_tryout.html:29
|
||||||
#: app/templates/pages/view_tryout.html:453
|
#: app/templates/pages/view_tryout.html:453
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
@@ -2764,11 +2812,11 @@ msgstr "Notes (facultatives)"
|
|||||||
msgid "Add any notes about this contract..."
|
msgid "Add any notes about this contract..."
|
||||||
msgstr "Notes éventuelles sur ce contrat..."
|
msgstr "Notes éventuelles sur ce contrat..."
|
||||||
|
|
||||||
#: app/templates/pages/users.html:8
|
#: app/templates/pages/users.html:9
|
||||||
msgid "Add User"
|
msgid "Add User"
|
||||||
msgstr "Ajouter un utilisateur"
|
msgstr "Ajouter un utilisateur"
|
||||||
|
|
||||||
#: app/templates/pages/users.html:53
|
#: app/templates/pages/users.html:54
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Delete %(name)s? This cannot be undone."
|
msgid "Delete %(name)s? This cannot be undone."
|
||||||
msgstr "Supprimer %(name)s ? Cette action est irréversible."
|
msgstr "Supprimer %(name)s ? Cette action est irréversible."
|
||||||
@@ -2949,3 +2997,6 @@ msgstr "Voir le profil"
|
|||||||
#~ msgid "Invalid end time format."
|
#~ msgid "Invalid end time format."
|
||||||
#~ msgstr "Format d’heure de fin invalide."
|
#~ msgstr "Format d’heure de fin invalide."
|
||||||
|
|
||||||
|
#~ msgid "Invalid date or time format."
|
||||||
|
#~ msgstr "Format de date ou d’heure invalide."
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
"""Bounded list views, and the links between their pages.
|
||||||
|
|
||||||
|
MNT-14. Every list view ran `.all()` on its table. The audit rated the impact
|
||||||
|
as nil at the scale of a student club and recommended choosing the pattern
|
||||||
|
now rather than retro-fitting one — which is what this is.
|
||||||
|
|
||||||
|
The tests worth having are not "does page 2 exist". They are the three ways
|
||||||
|
pagination is normally got wrong:
|
||||||
|
|
||||||
|
- a link that drops the rest of the query string, silently resetting the
|
||||||
|
sort or the filter the person was using;
|
||||||
|
- `?page=999` answering 404 to someone who went one page too far;
|
||||||
|
- `?per_page=100000`, which hands back by hand exactly the unbounded query
|
||||||
|
the pagination was added to prevent.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.extensions import db
|
||||||
|
from app.pagination import DEFAULT_PER_PAGE, MAX_PER_PAGE
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def many_users(app, make_user):
|
||||||
|
"""Enough accounts to need a second page at a small per_page."""
|
||||||
|
for _index in range(7):
|
||||||
|
make_user('player')
|
||||||
|
return 7
|
||||||
|
|
||||||
|
|
||||||
|
class TestTheUserList:
|
||||||
|
def test_per_page_bounds_the_rows(self, app, client, as_role, many_users):
|
||||||
|
as_role('admin')
|
||||||
|
|
||||||
|
response = client.get('/users?per_page=3')
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
# One <tr> per user in the body, plus the header row.
|
||||||
|
rows = re.findall(r'<tr[ >]', response.get_data(as_text=True))
|
||||||
|
assert len(rows) <= 4, 'the page returned more rows than per_page allows'
|
||||||
|
|
||||||
|
def test_the_second_page_holds_different_people(self, app, client, as_role, many_users):
|
||||||
|
as_role('admin')
|
||||||
|
|
||||||
|
first = client.get('/users?per_page=3').get_data(as_text=True)
|
||||||
|
second = client.get('/users?per_page=3&page=2').get_data(as_text=True)
|
||||||
|
|
||||||
|
assert first != second
|
||||||
|
|
||||||
|
def test_a_page_past_the_end_is_empty_not_a_404(self, app, client, as_role, many_users):
|
||||||
|
"""Page numbers come from the URL, so a stale bookmark is a normal
|
||||||
|
thing to receive. Flask-SQLAlchemy's default answers it with a 404."""
|
||||||
|
as_role('admin')
|
||||||
|
|
||||||
|
response = client.get('/users?page=999')
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_per_page_is_capped(self, app, client, as_role, many_users):
|
||||||
|
"""Without the cap, `?per_page=100000` is the unbounded query again."""
|
||||||
|
as_role('admin')
|
||||||
|
|
||||||
|
response = client.get(f'/users?per_page={MAX_PER_PAGE * 100}')
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_a_nonsense_page_does_not_crash(self, app, client, as_role, many_users):
|
||||||
|
as_role('admin')
|
||||||
|
|
||||||
|
assert client.get('/users?page=abc').status_code == 200
|
||||||
|
assert client.get('/users?page=-4').status_code == 200
|
||||||
|
assert client.get('/users?per_page=0').status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
class TestThePageLinksKeepTheQueryString:
|
||||||
|
"""The failure that is easy to ship and hard to notice: the person sorts
|
||||||
|
a column, clicks "next", and lands on an unsorted page 2."""
|
||||||
|
|
||||||
|
def test_evaluations_links_carry_the_sort(self, app, client, as_role, make_user):
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from app.models import Evaluation, Tryout
|
||||||
|
|
||||||
|
# One evaluation per player: the table has a unique constraint on
|
||||||
|
# (tryout, player, evaluator), which is DB-006 working as intended.
|
||||||
|
player_ids = [make_user('player') for _ in range(3)]
|
||||||
|
admin_id = as_role('admin')
|
||||||
|
with app.app_context():
|
||||||
|
tryout = Tryout(
|
||||||
|
title='Spring',
|
||||||
|
game='Valorant',
|
||||||
|
date=date(2030, 4, 1),
|
||||||
|
created_by=admin_id,
|
||||||
|
)
|
||||||
|
db.session.add(tryout)
|
||||||
|
db.session.flush()
|
||||||
|
for player_id in player_ids:
|
||||||
|
db.session.add(
|
||||||
|
Evaluation(
|
||||||
|
tryout_id=tryout.id,
|
||||||
|
player_id=player_id,
|
||||||
|
evaluator_id=admin_id,
|
||||||
|
overall_score=5,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
body = client.get('/evaluations?sort=player&order=asc&per_page=1').get_data(as_text=True)
|
||||||
|
|
||||||
|
links = re.findall(r'href="([^"]*page=\d+[^"]*)"', body)
|
||||||
|
assert links, 'no pagination link was rendered; this test proves nothing'
|
||||||
|
assert all('sort=player' in link for link in links), (
|
||||||
|
f'a page link dropped the sort: {links}'
|
||||||
|
)
|
||||||
|
assert all('order=asc' in link for link in links)
|
||||||
|
|
||||||
|
def test_team_matches_links_carry_the_team_filter(self, app, client, as_role, make_user):
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from app.models import OrgTeam, TeamMatch
|
||||||
|
|
||||||
|
admin_id = as_role('admin')
|
||||||
|
with app.app_context():
|
||||||
|
team = OrgTeam(name='Varsity', created_by=admin_id)
|
||||||
|
db.session.add(team)
|
||||||
|
db.session.flush()
|
||||||
|
team_id = team.id
|
||||||
|
for index in range(3):
|
||||||
|
db.session.add(
|
||||||
|
TeamMatch(
|
||||||
|
title=f'Match {index}',
|
||||||
|
date=date(2030, 5, 1),
|
||||||
|
org_team_id=team_id,
|
||||||
|
created_by=admin_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
body = client.get(f'/team-matches?team_id={team_id}&per_page=1').get_data(as_text=True)
|
||||||
|
|
||||||
|
links = re.findall(r'href="([^"]*page=\d+[^"]*)"', body)
|
||||||
|
assert links, 'no pagination link was rendered; this test proves nothing'
|
||||||
|
assert all(f'team_id={team_id}' in link for link in links), (
|
||||||
|
f'a page link dropped the team filter: {links}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestTheControlsStayOutOfTheWayWhenThereIsOnePage:
|
||||||
|
def test_no_controls_for_a_short_list(self, app, client, as_role):
|
||||||
|
as_role('admin')
|
||||||
|
|
||||||
|
body = client.get('/users').get_data(as_text=True)
|
||||||
|
|
||||||
|
assert 'aria-label' not in body or 'page=2' not in body
|
||||||
|
|
||||||
|
|
||||||
|
class TestTheDefault:
|
||||||
|
def test_it_is_a_page_size_not_the_whole_table(self):
|
||||||
|
assert 0 < DEFAULT_PER_PAGE <= MAX_PER_PAGE
|
||||||
Reference in New Issue
Block a user