chore: update translation
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Baoshuo Ren 2023-02-12 19:23:23 +08:00
parent 2fb8f10084
commit 0298f95726
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
11 changed files with 81 additions and 48 deletions

View File

@ -8,7 +8,7 @@ $time_form = new UOJForm('time');
$time_form->addInput( $time_form->addInput(
'name', 'name',
[ [
'label' => '比赛标题', 'label' => UOJLocale::get('contests::contest name'),
'default_value' => 'New Contest', 'default_value' => 'New Contest',
'validator_php' => function ($name, &$vdata) { 'validator_php' => function ($name, &$vdata) {
if ($name == '') { if ($name == '') {
@ -35,8 +35,8 @@ $time_form->addInput(
'start_time', 'start_time',
[ [
'div_class' => 'mt-2', 'div_class' => 'mt-2',
'label' => '开始时间', 'label' => UOJLocale::get('contests::start time'),
'default_value' => date("Y-m-d H:i:s"), 'default_value' => UOJTime::$time_now_str,
'validator_php' => function ($str, &$vdata) { 'validator_php' => function ($str, &$vdata) {
try { try {
$vdata['start_time'] = new DateTime($str); $vdata['start_time'] = new DateTime($str);
@ -52,8 +52,9 @@ $time_form->addInput(
'last_min', 'last_min',
[ [
'div_class' => 'mt-2', 'div_class' => 'mt-2',
'label' => '时长(单位:分钟)', 'label' => UOJLocale::get('contests::duration'),
'default_value' => '180', 'default_value' => '180',
'help' => '单位为分钟。',
'validator_php' => function ($str, &$vdata) { 'validator_php' => function ($str, &$vdata) {
if (!validateUInt($str)) { if (!validateUInt($str)) {
return '必须为一个整数'; return '必须为一个整数';

View File

@ -66,33 +66,33 @@ if (UOJContest::cur()) {
$tabs_info = [ $tabs_info = [
'dashboard' => [ 'dashboard' => [
'name' => UOJLocale::get('contests::contest dashboard'), 'name' => UOJLocale::get('contests::contest dashboard'),
'url' => '/contest/' . UOJContest::info('id'), 'url' => UOJContest::cur()->getUri(),
], ],
'submissions' => [ 'submissions' => [
'name' => UOJLocale::get('contests::contest submissions'), 'name' => UOJLocale::get('contests::contest submissions'),
'url' => '/contest/' . UOJContest::info('id') . '/submissions', 'url' => UOJContest::cur()->getUri('/submissions'),
], ],
'standings' => [ 'standings' => [
'name' => UOJLocale::get('contests::contest standings'), 'name' => UOJLocale::get('contests::contest standings'),
'url' => '/contest/' . UOJContest::info('id') . '/standings', 'url' => UOJContest::cur()->getUri('/standings'),
], ],
]; ];
if (UOJContest::cur()->progress() > CONTEST_TESTING) { if (UOJContest::cur()->progress() > CONTEST_TESTING) {
$tabs_info['after_contest_standings'] = [ $tabs_info['after_contest_standings'] = [
'name' => UOJLocale::get('contests::after contest standings'), 'name' => UOJLocale::get('contests::after contest standings'),
'url' => '/contest/' . UOJContest::info('id') . '/after_contest_standings', 'url' => UOJContest::cur()->getUri('/after_contest_standings'),
]; ];
$tabs_info['self_reviews'] = [ $tabs_info['self_reviews'] = [
'name' => UOJLocale::get('contests::contest self reviews'), 'name' => UOJLocale::get('contests::contest self reviews'),
'url' => '/contest/' . UOJContest::info('id') . '/self_reviews', 'url' => UOJContest::cur()->getUri('/self_reviews'),
]; ];
} }
if (UOJContest::cur()->userCanManage(Auth::user())) { if (UOJContest::cur()->userCanManage(Auth::user())) {
$tabs_info['backstage'] = [ $tabs_info['backstage'] = [
'name' => UOJLocale::get('contests::contest backstage'), 'name' => UOJLocale::get('contests::contest backstage'),
'url' => '/contest/' . UOJContest::info('id') . '/backstage', 'url' => UOJContest::cur()->getUri('/backstage'),
]; ];
} }
} }
@ -200,7 +200,7 @@ if ($custom_test_enabled) {
} }
if (empty($submission_requirement)) { if (empty($submission_requirement)) {
$no_more_submission = '当前题目未配置提交文件,请联系管理员!'; $no_more_submission = UOJLocale::get('problems::cannot submit');
} }
if ($pre_submit_check_ret === true && !$no_more_submission) { if ($pre_submit_check_ret === true && !$no_more_submission) {
@ -220,7 +220,7 @@ if ($pre_submit_check_ret === true && !$no_more_submission) {
'handleUpload' 'handleUpload'
); );
$zip_answer_form->extra_validators[] = $submission_extra_validator; $zip_answer_form->extra_validators[] = $submission_extra_validator;
$zip_answer_form->succ_href = $is_participating ? '/contest/' . UOJContest::info('id') . '/submissions' : '/submissions'; $zip_answer_form->succ_href = $is_participating ? UOJContest::cur()->getUri('/submissions') : '/submissions';
$zip_answer_form->runAtServer(); $zip_answer_form->runAtServer();
} }
@ -257,7 +257,7 @@ if ($pre_submit_check_ret === true && !$no_more_submission) {
} }
$answer_form->extra_validator = $submission_extra_validator; $answer_form->extra_validator = $submission_extra_validator;
$answer_form->succ_href = $is_participating ? '/contest/' . UOJContest::info('id') . '/submissions' : '/submissions'; $answer_form->succ_href = $is_participating ? UOJContest::cur()->getUri('/submissions') : '/submissions';
$answer_form->runAtServer(); $answer_form->runAtServer();
} }
@ -302,9 +302,9 @@ if (UOJContest::cur()) {
} }
?> ?>
<div class="text-center small"> <div class="text-center small">
时间限制: <?= $time_limit ? "$time_limit s" : "N/A" ?> <?= UOJLocale::get('problems::time limit') ?>: <?= $time_limit ? "$time_limit s" : "N/A" ?>
&emsp; &emsp;
空间限制: <?= $memory_limit ? "$memory_limit MB" : "N/A" ?> <?= UOJLocale::get('problems::memory limit') ?>: <?= $memory_limit ? "$memory_limit MB" : "N/A" ?>
</div> </div>
<hr> <hr>
@ -319,7 +319,7 @@ if (UOJContest::cur()) {
<hr> <hr>
<article class="mt-3 markdown-body remote-content"> <article class="mt-3 markdown-body remote-content">
<?= UOJProblem::cur()->queryContent()['remote_content'] ?> <?= $problem_content['remote_content'] ?>
</article> </article>
<?php endif ?> <?php endif ?>
</div> </div>
@ -370,8 +370,15 @@ if (UOJContest::cur()) {
<?php endif ?> <?php endif ?>
</div> </div>
</div> </div>
<div class="card-footer bg-transparent"> <div class="list-group list-group-flush">
比赛评价:<?= UOJContest::cur()->getZanBlock() ?> <li class="list-group-item d-flex justify-content-between align-items-center">
<span class="flex-shrink-0">
<?= UOJLocale::get('appraisal') ?>
</span>
<span>
<?= UOJContest::cur()->getZanBlock() ?>
</span>
</li>
</div> </div>
</div> </div>
<?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?> <?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>
@ -406,7 +413,7 @@ if (UOJContest::cur()) {
<?php endif ?> <?php endif ?>
<?php if (!UOJContest::cur() || UOJContest::cur()->progress() >= CONTEST_FINISHED) : ?> <?php if (!UOJContest::cur() || UOJContest::cur()->progress() >= CONTEST_FINISHED) : ?>
<li class="nav-item text-start"> <li class="nav-item text-start">
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab"> <a href="<?= UOJProblem::cur()->getUri('/solution') ?>" class="nav-link">
<i class="bi bi-journal-bookmark"></i> <i class="bi bi-journal-bookmark"></i>
<?= UOJLocale::get('problems::solutions') ?> <?= UOJLocale::get('problems::solutions') ?>
</a> </a>
@ -420,14 +427,14 @@ if (UOJContest::cur()) {
</li> </li>
<?php if (UOJContest::cur() && UOJContest::cur()->userCanSeeProblemStatistics(Auth::user())) : ?> <?php if (UOJContest::cur() && UOJContest::cur()->userCanSeeProblemStatistics(Auth::user())) : ?>
<li class="nav-item text-start"> <li class="nav-item text-start">
<a class="nav-link" href="/contest/<?= UOJContest::info('id') ?>/problem/<?= $problem['id'] ?>/statistics"> <a class="nav-link" href="<?= UOJContestProblem::cur()->getUri('/statistics') ?>">
<i class="bi bi-graph-up"></i> <i class="bi bi-graph-up"></i>
<?= UOJLocale::get('problems::statistics') ?> <?= UOJLocale::get('problems::statistics') ?>
</a> </a>
</li> </li>
<?php elseif (!UOJContest::cur()) : ?> <?php elseif (!UOJContest::cur()) : ?>
<li class="nav-item text-start"> <li class="nav-item text-start">
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/statistics"> <a class="nav-link" href="<?= UOJProblem::cur()->getUri('/statistics') ?>">
<i class="bi bi-graph-up"></i> <i class="bi bi-graph-up"></i>
<?= UOJLocale::get('problems::statistics') ?> <?= UOJLocale::get('problems::statistics') ?>
</a> </a>
@ -435,7 +442,7 @@ if (UOJContest::cur()) {
<?php endif ?> <?php endif ?>
<?php if (UOJProblem::cur()->userCanManage(Auth::user())) : ?> <?php if (UOJProblem::cur()->userCanManage(Auth::user())) : ?>
<li class="nav-item text-start"> <li class="nav-item text-start">
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab"> <a class="nav-link" href="<?= UOJProblem::cur()->getUri('/manage/statement') ?>">
<i class="bi bi-sliders"></i> <i class="bi bi-sliders"></i>
<?= UOJLocale::get('problems::manage') ?> <?= UOJLocale::get('problems::manage') ?>
</a> </a>
@ -457,7 +464,7 @@ if (UOJContest::cur()) {
</li> </li>
<li class="list-group-item d-flex justify-content-between align-items-center"> <li class="list-group-item d-flex justify-content-between align-items-center">
<span class="flex-shrink-0"> <span class="flex-shrink-0">
题目来源 <?= UOJLocale::get('problems::problem source') ?>
</span> </span>
<span> <span>
<?= UOJProblem::cur()->getProviderLink() ?> <?= UOJProblem::cur()->getProviderLink() ?>
@ -520,21 +527,23 @@ if (UOJContest::cur()) {
<!-- 附件 --> <!-- 附件 -->
<div class="card mb-2"> <div class="card mb-2">
<div class="card-header fw-bold">附件</div> <div class="card-header fw-bold">
<?= UOJLocale::get('problems::attachments') ?>
</div>
<div class="list-group list-group-flush"> <div class="list-group list-group-flush">
<?php if (UOJProblem::cur()->userCanDownloadTestData(Auth::user())) : ?> <?php if (UOJProblem::cur()->userCanDownloadTestData(Auth::user())) : ?>
<a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJProblem::cur()->getMainDataUri()) ?>"> <a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJProblem::cur()->getMainDataUri()) ?>">
<i class="bi bi-hdd-stack"></i> <i class="bi bi-hdd-stack"></i>
测试数据 <?= UOJLocale::get('problems::test data') ?>
</a> </a>
<?php endif ?> <?php endif ?>
<a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJProblem::cur()->getAttachmentUri()) ?>"> <a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJProblem::cur()->getAttachmentUri()) ?>">
<i class="bi bi-download"></i> <i class="bi bi-download"></i>
附件下载 <?= UOJLocale::get('problems::attachments download') ?>
</a> </a>
<a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJProblem::cur()->getResourcesBaseUri()) ?>"> <a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJProblem::cur()->getResourcesBaseUri()) ?>">
<i class="bi bi-folder2-open"></i> <i class="bi bi-folder2-open"></i>
相关资源 <?= UOJLocale::get('problems::resources') ?>
</a> </a>
</div> </div>
</div> </div>

View File

@ -67,33 +67,33 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
$tabs_info = [ $tabs_info = [
'dashboard' => [ 'dashboard' => [
'name' => UOJLocale::get('contests::contest dashboard'), 'name' => UOJLocale::get('contests::contest dashboard'),
'url' => '/contest/' . UOJContest::info('id'), 'url' => UOJContest::cur()->getUri(),
], ],
'submissions' => [ 'submissions' => [
'name' => UOJLocale::get('contests::contest submissions'), 'name' => UOJLocale::get('contests::contest submissions'),
'url' => '/contest/' . UOJContest::info('id') . '/submissions', 'url' => UOJContest::cur()->getUri('/submissions'),
], ],
'standings' => [ 'standings' => [
'name' => UOJLocale::get('contests::contest standings'), 'name' => UOJLocale::get('contests::contest standings'),
'url' => '/contest/' . UOJContest::info('id') . '/standings', 'url' => UOJContest::cur()->getUri('/standings'),
], ],
]; ];
if (UOJContest::cur()->progress() > CONTEST_TESTING) { if (UOJContest::cur()->progress() > CONTEST_TESTING) {
$tabs_info['after_contest_standings'] = [ $tabs_info['after_contest_standings'] = [
'name' => UOJLocale::get('contests::after contest standings'), 'name' => UOJLocale::get('contests::after contest standings'),
'url' => '/contest/' . UOJContest::info('id') . '/after_contest_standings', 'url' => UOJContest::cur()->getUri('/after_contest_standings'),
]; ];
$tabs_info['self_reviews'] = [ $tabs_info['self_reviews'] = [
'name' => UOJLocale::get('contests::contest self reviews'), 'name' => UOJLocale::get('contests::contest self reviews'),
'url' => '/contest/' . UOJContest::info('id') . '/self_reviews', 'url' => UOJContest::cur()->getUri('/self_reviews'),
]; ];
} }
if (UOJContest::cur()->userCanManage(Auth::user())) { if (UOJContest::cur()->userCanManage(Auth::user())) {
$tabs_info['backstage'] = [ $tabs_info['backstage'] = [
'name' => UOJLocale::get('contests::contest backstage'), 'name' => UOJLocale::get('contests::contest backstage'),
'url' => '/contest/' . UOJContest::info('id') . '/backstage', 'url' => UOJContest::cur()->getUri('/backstage'),
]; ];
} }
?> ?>
@ -104,7 +104,6 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
<div class="card card-default mb-2"> <div class="card card-default mb-2">
<div class="card-body"> <div class="card-body">
<h1 class="text-center"> <h1 class="text-center">
<?php if (UOJContest::cur()) : ?> <?php if (UOJContest::cur()) : ?>
<?= UOJProblem::cur()->getTitle(['with' => 'letter', 'simplify' => true]) ?> <?= UOJProblem::cur()->getTitle(['with' => 'letter', 'simplify' => true]) ?>
@ -115,7 +114,9 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
<hr /> <hr />
<h2 class="text-center"><?= UOJLocale::get('problems::accepted submissions') ?></h2> <h2 class="text-center">
<?= UOJLocale::get('problems::accepted submissions') ?>
</h2>
<div class="text-end mb-2"> <div class="text-end mb-2">
<div class="btn-group btn-group-sm"> <div class="btn-group btn-group-sm">
<a href="<?= UOJContext::requestURI() ?>" class="btn btn-secondary btn-xs <?= $submissions_sort_by_choice == 'time' ? 'active' : '' ?>" id="submissions-sort-by-run-time"> <a href="<?= UOJContext::requestURI() ?>" class="btn btn-secondary btn-xs <?= $submissions_sort_by_choice == 'time' ? 'active' : '' ?>" id="submissions-sort-by-run-time">
@ -265,8 +266,15 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
<?php endif ?> <?php endif ?>
</div> </div>
</div> </div>
<div class="card-footer bg-transparent"> <div class="list-group list-group-flush">
比赛评价:<?= UOJContest::cur()->getZanBlock() ?> <li class="list-group-item d-flex justify-content-between align-items-center">
<span class="flex-shrink-0">
<?= UOJLocale::get('appraisal') ?>
</span>
<span>
<?= UOJContest::cur()->getZanBlock() ?>
</span>
</li>
</div> </div>
</div> </div>
<?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?> <?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>

View File

@ -16,7 +16,6 @@ return [
'groups' => 'Groups', 'groups' => 'Groups',
'add new group' => 'Add new group', 'add new group' => 'Add new group',
'group announcement' => 'Group Announcement', 'group announcement' => 'Group Announcement',
'group announcements' => 'Group Announcements',
'users count' => 'Users', 'users count' => 'Users',
'submissions' => 'Submissions', 'submissions' => 'Submissions',
'hacks' => 'Hack!', 'hacks' => 'Hack!',

View File

@ -16,7 +16,6 @@ return [
'groups' => '小组', 'groups' => '小组',
'add new group' => '添加新小组', 'add new group' => '添加新小组',
'group announcement' => '小组公告', 'group announcement' => '小组公告',
'group announcements' => '小组公告',
'users count' => '用户数量', 'users count' => '用户数量',
'submissions' => '提交记录', 'submissions' => '提交记录',
'hacks' => 'Hack!', 'hacks' => 'Hack!',

View File

@ -2,6 +2,7 @@
return [ return [
'new contest' => 'New Contest', 'new contest' => 'New Contest',
'current or upcoming contests' => 'Current or upcoming contests', 'current or upcoming contests' => 'Current or upcoming contests',
'upcoming contests' => 'Upcoming contests',
'ended contests' => 'Ended contests', 'ended contests' => 'Ended contests',
'back to the contest' => 'Back to the contest', 'back to the contest' => 'Back to the contest',
'contest' => 'Contest', 'contest' => 'Contest',

View File

@ -2,6 +2,7 @@
return [ return [
'new contest' => '新建比赛', 'new contest' => '新建比赛',
'current or upcoming contests' => '正在进行或即将到来的比赛', 'current or upcoming contests' => '正在进行或即将到来的比赛',
'upcoming contests' => '即将到来的比赛',
'ended contests' => '已结束的比赛', 'ended contests' => '已结束的比赛',
'back to the contest' => '返回比赛', 'back to the contest' => '返回比赛',
'contest' => '比赛', 'contest' => '比赛',

View File

@ -22,6 +22,7 @@ return [
'solutions' => 'Solutions', 'solutions' => 'Solutions',
'statistics' => 'Statistics', 'statistics' => 'Statistics',
'run' => 'Run', 'run' => 'Run',
'problem source' => 'Problem Source',
'source code' => 'Source code', 'source code' => 'Source code',
'text file' => 'Text file', 'text file' => 'Text file',
'zip file upload introduction' => function($str) { 'zip file upload introduction' => function($str) {
@ -56,4 +57,11 @@ return [
'tags' => 'Tags', 'tags' => 'Tags',
'historical score' => 'Historical Score', 'historical score' => 'Historical Score',
'uploader' => 'Uploader', 'uploader' => 'Uploader',
'time limit' => 'Time limit',
'memory limit' => 'Memory limit',
'attachments' => 'Attachments',
'test data' => 'Test data',
'attachments download' => 'Attachments download',
'resources' => 'Resources',
'cannot submit' => 'This problem doesn\'t configured <code>submission_requirement</code>, so it cannot be submitted temporarily.',
]; ];

View File

@ -21,6 +21,7 @@ return [
'submissions statistics' => '统计提交情况', 'submissions statistics' => '统计提交情况',
'statistics' => '统计', 'statistics' => '统计',
'solutions' => '题解', 'solutions' => '题解',
'problem source' => '题目来源',
'run' => '运行', 'run' => '运行',
'source code' => '源代码', 'source code' => '源代码',
'text file' => '文本文件', 'text file' => '文本文件',
@ -56,4 +57,11 @@ return [
'tags' => '标签', 'tags' => '标签',
'historical score' => '历史分数', 'historical score' => '历史分数',
'uploader' => '上传者', 'uploader' => '上传者',
'time limit' => '时间限制',
'memory limit' => '内存限制',
'attachments' => '附件',
'test data' => '测试数据',
'attachments download' => '附件下载',
'resources' => '相关资源',
'cannot submit' => '当前题目未配置 <code>submission_requirement</code>,暂时无法提交。'
]; ];

View File

@ -115,7 +115,7 @@ class UOJGroup {
DB::lc(), "select list_id from groups_assignments", DB::lc(), "select list_id from groups_assignments",
"where", [ "where", [
"group_id" => $this->info['id'], "group_id" => $this->info['id'],
["end_time", ">=", DB::raw("addtime(now(), '-72:00:00')")], ["end_time", ">=", DB::now()],
], ],
"order by end_time desc, list_id asc", "order by end_time desc, list_id asc",
$limit == -1 ? "" : DB::limit($limit), $limit == -1 ? "" : DB::limit($limit),

View File

@ -8,8 +8,8 @@ $parsedown = HTML::parsedown(['username_with_color' => true]);
<?php $groups = UOJGroup::queryGroupsOfUser(Auth::user()); ?> <?php $groups = UOJGroup::queryGroupsOfUser(Auth::user()); ?>
<?php if (!empty($groups)) : ?> <?php if (!empty($groups)) : ?>
<div class="card card-default mb-2" id="group-user-announcements"> <div class="card card-default mb-2" id="group-user-announcements">
<div class="card-header fw-bold bg-transparent"> <div class="card-header fw-bold">
<?= UOJLocale::get('group announcements') ?> <?= UOJLocale::get('groups') ?>
</div> </div>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<?php foreach ($groups as $group) : ?> <?php foreach ($groups as $group) : ?>
@ -36,12 +36,11 @@ $parsedown = HTML::parsedown(['username_with_color' => true]);
$assignments = array_merge($assignments, array_map(fn ($x) => UOJGroupAssignment::query($x, $group), $group->getActiveAssignmentIds())); $assignments = array_merge($assignments, array_map(fn ($x) => UOJGroupAssignment::query($x, $group), $group->getActiveAssignmentIds()));
} }
usort($assignments, fn ($a, $b) => $b->info['end_time']->getTimestamp() - $a->info['end_time']->getTimestamp()); usort($assignments, fn ($a, $b) => $a->info['end_time']->getTimestamp() - $b->info['end_time']->getTimestamp());
$assignments = array_slice($assignments, 0, 5);
?> ?>
<?php if (!empty($assignments)) : ?> <?php if (!empty($assignments)) : ?>
<div class="card card-default mb-2" id="group-assignments"> <div class="card card-default mb-2" id="group-assignments">
<div class="card-header fw-bold bg-transparent"> <div class="card-header fw-bold">
<?= UOJLocale::get('assignments') ?> <?= UOJLocale::get('assignments') ?>
</div> </div>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
@ -65,8 +64,8 @@ $parsedown = HTML::parsedown(['username_with_color' => true]);
<?php if (!isset($upcoming_contests_hidden)) : ?> <?php if (!isset($upcoming_contests_hidden)) : ?>
<?php $upcoming_contests = UOJContest::queryUpcomingContests(Auth::user(), 5); ?> <?php $upcoming_contests = UOJContest::queryUpcomingContests(Auth::user(), 5); ?>
<div class="card card-default mb-2" id="group-user-announcements"> <div class="card card-default mb-2" id="group-user-announcements">
<div class="card-header fw-bold bg-transparent"> <div class="card-header fw-bold">
近期比赛 <?= UOJLocale::get('contests::upcoming contests') ?>
</div> </div>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<?php foreach ($upcoming_contests as $contest) : ?> <?php foreach ($upcoming_contests as $contest) : ?>