feat: translate web interface to Russian
Deploy Telegram Bot / build-and-push (push) Failing after 3m5s
Deploy Telegram Bot / deploy (push) Has been skipped

This commit is contained in:
2026-04-17 15:40:35 +03:00
parent 55bc0dedb7
commit 116f1f5b0e
10 changed files with 77 additions and 67 deletions
@@ -7,7 +7,7 @@
<main> <main>
<div class="top-row px-4"> <div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a> <a href="https://github.com/Toutsu/GmRelayBot" target="_blank">О проекте</a>
</div> </div>
<article class="content px-4"> <article class="content px-4">
@@ -17,7 +17,7 @@
</div> </div>
<div id="blazor-error-ui" data-nosnippet> <div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred. Произошла непредвиденная ошибка.
<a href="." class="reload">Reload</a> <a href="." class="reload">Перезагрузить</a>
<span class="dismiss">🗙</span> <span class="dismiss">🗙</span>
</div> </div>
@@ -4,7 +4,7 @@
</div> </div>
</div> </div>
<input type="checkbox" title="Navigation menu" class="navbar-toggler" /> <input type="checkbox" title="Навигационное меню" class="navbar-toggler" />
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()"> <div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
<nav class="nav flex-column"> <nav class="nav flex-column">
@@ -12,7 +12,7 @@
<Authorized> <Authorized>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Dashboard <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Панель управления
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3 mt-auto"> <div class="nav-item px-3 mt-auto">
@@ -24,7 +24,7 @@
<form action="/auth/logout" method="post"> <form action="/auth/logout" method="post">
<AntiforgeryToken /> <AntiforgeryToken />
<button type="submit" class="nav-link btn btn-link text-light text-start w-100 p-0 shadow-none border-0"> <button type="submit" class="nav-link btn btn-link text-light text-start w-100 p-0 shadow-none border-0">
<span class="bi bi-box-arrow-right" aria-hidden="true"></span> Logout <span class="bi bi-box-arrow-right" aria-hidden="true"></span> Выйти
</button> </button>
</form> </form>
</div> </div>
@@ -32,7 +32,7 @@
<NotAuthorized> <NotAuthorized>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="login"> <NavLink class="nav-link" href="login">
<span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> Login <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> Войти
</NavLink> </NavLink>
</div> </div>
</NotAuthorized> </NotAuthorized>
@@ -7,25 +7,25 @@
<div></div> <div></div>
</div> </div>
<p class="components-reconnect-first-attempt-visible"> <p class="components-reconnect-first-attempt-visible">
Rejoining the server... Переподключение к серверу...
</p> </p>
<p class="components-reconnect-repeated-attempt-visible"> <p class="components-reconnect-repeated-attempt-visible">
Rejoin failed... trying again in <span id="components-seconds-to-next-attempt"></span> seconds. Подключение не удалось... повторная попытка через <span id="components-seconds-to-next-attempt"></span> сек.
</p> </p>
<p class="components-reconnect-failed-visible"> <p class="components-reconnect-failed-visible">
Failed to rejoin.<br />Please retry or reload the page. Не удалось переподключиться.<br />Пожалуйста, повторите попытку или перезагрузите страницу.
</p> </p>
<button id="components-reconnect-button" class="components-reconnect-failed-visible"> <button id="components-reconnect-button" class="components-reconnect-failed-visible">
Retry Повторить
</button> </button>
<p class="components-pause-visible"> <p class="components-pause-visible">
The session has been paused by the server. Сессия была приостановлена сервером.
</p> </p>
<p class="components-resume-failed-visible"> <p class="components-resume-failed-visible">
Failed to resume the session.<br />Please retry or reload the page. Не удалось возобновить сессию.<br />Пожалуйста, повторите попытку или перезагрузите страницу.
</p> </p>
<button id="components-resume-button" class="components-pause-visible components-resume-failed-visible"> <button id="components-resume-button" class="components-pause-visible components-resume-failed-visible">
Resume Возобновить
</button> </button>
</div> </div>
</dialog> </dialog>
@@ -6,21 +6,21 @@
@inject SessionService SessionService @inject SessionService SessionService
@inject NavigationManager Navigation @inject NavigationManager Navigation
<PageTitle>Edit Session - GM-Relay</PageTitle> <PageTitle>Редактирование сессии - GM-Relay</PageTitle>
<div class="container mt-4"> <div class="container mt-4">
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Dashboard</a></li> <li class="breadcrumb-item"><a href="/">Главная</a></li>
<li class="breadcrumb-item active">Edit Session</li> <li class="breadcrumb-item active">Редактирование сессии</li>
</ol> </ol>
</nav> </nav>
<h2>Edit Session</h2> <h2>Редактирование сессии</h2>
@if (session == null) @if (session == null)
{ {
<p>Loading session details...</p> <p>Загрузка деталей сессии...</p>
} }
else else
{ {
@@ -28,27 +28,27 @@
<div class="card-body"> <div class="card-body">
<EditForm Model="@model" OnValidSubmit="HandleSubmit"> <EditForm Model="@model" OnValidSubmit="HandleSubmit">
<div class="mb-3"> <div class="mb-3">
<label class="form-label font-weight-bold">Game Title</label> <label class="form-label font-weight-bold">Название игры</label>
<InputText @bind-Value="model.Title" class="form-control" placeholder="e.g. D&D 5e: Dragon's Hoard" /> <InputText @bind-Value="model.Title" class="form-control" placeholder="например, D&D 5e: Dragon's Hoard" />
<div class="form-text">Changing this will update all sessions in the same batch.</div> <div class="form-text">Изменение этого поля обновит все сессии в одной группе.</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label font-weight-bold">Scheduled Time (Moscow UTC+3)</label> <label class="form-label font-weight-bold">Запланированное время (МСК UTC+3)</label>
<input type="datetime-local" @bind="model.ScheduledAtLocal" class="form-control" /> <input type="datetime-local" @bind="model.ScheduledAtLocal" class="form-control" />
<div class="form-text">Current: @session.ScheduledAt.FormatMoscow()</div> <div class="form-text">Текущее: @session.ScheduledAt.FormatMoscow()</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label font-weight-bold">Join Link</label> <label class="form-label font-weight-bold">Ссылка для подключения</label>
<InputText @bind-Value="model.JoinLink" class="form-control" placeholder="Discord or VTT link" /> <InputText @bind-Value="model.JoinLink" class="form-control" placeholder="Ссылка на Discord или VTT" />
</div> </div>
<div class="mt-4"> <div class="mt-4">
<button type="submit" class="btn btn-success" disabled="@isSubmitting"> <button type="submit" class="btn btn-success" disabled="@isSubmitting">
@(isSubmitting ? "Saving..." : "Save Changes") @(isSubmitting ? "Сохранение..." : "Сохранить изменения")
</button> </button>
<button type="button" class="btn btn-outline-secondary ms-2" @onclick="GoBack">Cancel</button> <button type="button" class="btn btn-outline-secondary ms-2" @onclick="GoBack">Отмена</button>
</div> </div>
</EditForm> </EditForm>
</div> </div>
@@ -96,7 +96,7 @@
} }
catch (Exception ex) catch (Exception ex)
{ {
errorMessage = "Failed to save changes: " + ex.Message; errorMessage = "Не удалось сохранить изменения: " + ex.Message;
} }
finally finally
{ {
+10 -10
View File
@@ -1,27 +1,27 @@
@page "/Error" @page "/Error"
@using System.Diagnostics @using System.Diagnostics
<PageTitle>Error</PageTitle> <PageTitle>Ошибка</PageTitle>
<h1 class="text-danger">Error.</h1> <h1 class="text-danger">Ошибка.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2> <h2 class="text-danger">Произошла ошибка при обработке вашего запроса.</h2>
@if (ShowRequestId) @if (ShowRequestId)
{ {
<p> <p>
<strong>Request ID:</strong> <code>@RequestId</code> <strong>ID запроса:</strong> <code>@RequestId</code>
</p> </p>
} }
<h3>Development Mode</h3> <h3>Режим разработки</h3>
<p> <p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred. Переключение на среду <strong>Development</strong> отобразит более подробную информацию о произошедшей ошибке.
</p> </p>
<p> <p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong> <strong>Среда Development не должна быть включена для развернутых приложений.</strong>
It can result in displaying sensitive information from exceptions to end users. Это может привести к отображению конфиденциальной информации из исключений конечным пользователям.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong> Для локальной отладки включите среду <strong>Development</strong>, установив переменную среды <strong>ASPNETCORE_ENVIRONMENT</strong> в значение <strong>Development</strong>
and restarting the app. и перезапустите приложение.
</p> </p>
@code{ @code{
@@ -5,26 +5,26 @@
@attribute [Authorize] @attribute [Authorize]
@inject SessionService SessionService @inject SessionService SessionService
<PageTitle>Group Sessions - GM-Relay</PageTitle> <PageTitle>Сессии группы - GM-Relay</PageTitle>
<div class="container mt-4"> <div class="container mt-4">
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Dashboard</a></li> <li class="breadcrumb-item"><a href="/">Главная</a></li>
<li class="breadcrumb-item active">Group Sessions</li> <li class="breadcrumb-item active">Сессии группы</li>
</ol> </ol>
</nav> </nav>
<h2>Upcoming Sessions</h2> <h2>Предстоящие игры</h2>
<div class="mt-4"> <div class="mt-4">
@if (sessions == null) @if (sessions == null)
{ {
<p>Loading sessions...</p> <p>Загрузка сессий...</p>
} }
else if (sessions.Count == 0) else if (sessions.Count == 0)
{ {
<div class="alert alert-info">No upcoming sessions found for this group.</div> <div class="alert alert-info">Для этой группы не найдено предстоящих сессий.</div>
} }
else else
{ {
@@ -32,11 +32,11 @@
<table class="table table-hover align-middle"> <table class="table table-hover align-middle">
<thead class="table-light"> <thead class="table-light">
<tr> <tr>
<th>Title</th> <th>Название</th>
<th>Time (MSK)</th> <th>Время (МСК)</th>
<th>Status</th> <th>Статус</th>
<th>Link</th> <th>Ссылка</th>
<th>Action</th> <th>Действие</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -46,11 +46,11 @@
<td>@session.Title</td> <td>@session.Title</td>
<td>@session.ScheduledAt.FormatMoscow()</td> <td>@session.ScheduledAt.FormatMoscow()</td>
<td> <td>
<span class="badge @GetStatusClass(session.Status)">@session.Status</span> <span class="badge @GetStatusClass(session.Status)">@TranslateStatus(session.Status)</span>
</td> </td>
<td><a href="@session.JoinLink" target="_blank" class="text-truncate d-inline-block" style="max-width: 150px;">Link</a></td> <td><a href="@session.JoinLink" target="_blank" class="text-truncate d-inline-block" style="max-width: 150px;">Ссылка</a></td>
<td> <td>
<a href="/session/edit/@session.Id" class="btn btn-sm btn-outline-secondary">Edit</a> <a href="/session/edit/@session.Id" class="btn btn-sm btn-outline-secondary">Изменить</a>
</td> </td>
</tr> </tr>
} }
@@ -77,4 +77,14 @@
SessionStatus.ConfirmationSent => "bg-warning text-dark", SessionStatus.ConfirmationSent => "bg-warning text-dark",
_ => "bg-secondary" _ => "bg-secondary"
}; };
private string TranslateStatus(string status) => status switch
{
SessionStatus.Recruiting => "Набор",
SessionStatus.RecruitmentClosed => "Набор закрыт",
SessionStatus.ConfirmationSent => "Ждем подтверждения",
SessionStatus.Confirmed => "Подтверждено",
SessionStatus.Cancelled => "Отменено",
_ => status
};
} }
+7 -7
View File
@@ -6,23 +6,23 @@
@inject SessionService SessionService @inject SessionService SessionService
@inject AuthenticationStateProvider AuthStateProvider @inject AuthenticationStateProvider AuthStateProvider
<PageTitle>Dashboard - GM-Relay</PageTitle> <PageTitle>Панель управления - GM-Relay</PageTitle>
<div class="container mt-4"> <div class="container mt-4">
<h2>Welcome, @userName!</h2> <h2>Добро пожаловать, @userName!</h2>
<p class="text-muted">Select a group to manage your game sessions.</p> <p class="text-muted">Выберите группу для управления играми.</p>
<div class="row mt-4"> <div class="row mt-4">
@if (groups == null) @if (groups == null)
{ {
<p>Loading groups...</p> <p>Загрузка групп...</p>
} }
else if (groups.Count == 0) else if (groups.Count == 0)
{ {
<div class="col-12"> <div class="col-12">
<div class="card bg-light"> <div class="card bg-light">
<div class="card-body text-center"> <div class="card-body text-center">
<p class="mb-0">You don't have any groups registered yet. Use the bot in a Telegram group first!</p> <p class="mb-0">У вас еще нет зарегистрированных групп. Сначала добавьте бота в группу Telegram!</p>
</div> </div>
</div> </div>
</div> </div>
@@ -36,7 +36,7 @@
<div class="card-body"> <div class="card-body">
<h5 class="card-title">@group.Name</h5> <h5 class="card-title">@group.Name</h5>
<p class="card-text text-muted">ID: @group.TelegramChatId</p> <p class="card-text text-muted">ID: @group.TelegramChatId</p>
<a href="/group/@group.Id" class="btn btn-primary">View Sessions</a> <a href="/group/@group.Id" class="btn btn-primary">Посмотреть игры</a>
</div> </div>
</div> </div>
</div> </div>
@@ -53,7 +53,7 @@
{ {
var authState = await AuthStateProvider.GetAuthenticationStateAsync(); var authState = await AuthStateProvider.GetAuthenticationStateAsync();
var user = authState.User; var user = authState.User;
userName = user.Identity?.Name ?? "Game Master"; userName = user.Identity?.Name ?? "Мастер Игры";
var telegramIdClaim = user.FindFirst("TelegramId")?.Value; var telegramIdClaim = user.FindFirst("TelegramId")?.Value;
if (long.TryParse(telegramIdClaim, out var telegramId)) if (long.TryParse(telegramIdClaim, out var telegramId))
+4 -4
View File
@@ -3,18 +3,18 @@
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IConfiguration Configuration @inject IConfiguration Configuration
<PageTitle>Login - GM-Relay</PageTitle> <PageTitle>Вход - GM-Relay</PageTitle>
<div class="container"> <div class="container">
<div class="row justify-content-center mt-5"> <div class="row justify-content-center mt-5">
<div class="col-md-6 text-center"> <div class="col-md-6 text-center">
<h3>GM-Relay Control Panel</h3> <h3>Панель управления GM-Relay</h3>
<p class="text-muted">Please log in as a Game Master to manage your sessions.</p> <p class="text-muted">Пожалуйста, войдите как Мастер Игры для управления сессиями.</p>
<div class="mt-4"> <div class="mt-4">
@if (Navigation.Uri.Contains("error=auth_failed")) @if (Navigation.Uri.Contains("error=auth_failed"))
{ {
<div class="alert alert-danger">Authentication failed. Please try again.</div> <div class="alert alert-danger">Ошибка аутентификации. Пожалуйста, попробуйте снова.</div>
} }
@* Telegram Login Widget *@ @* Telegram Login Widget *@
@@ -1,5 +1,5 @@
@page "/not-found" @page "/not-found"
@layout MainLayout @layout MainLayout
<h3>Not Found</h3> <h3>Не найдено</h3>
<p>Sorry, the content you are looking for does not exist.</p> <p>Извините, страница, которую вы ищете, не существует.</p>
+1 -1
View File
@@ -10,7 +10,7 @@
} }
else else
{ {
<p role="alert">You are not authorized to access this resource.</p> <p role="alert">У вас нет прав для доступа к этому ресурсу.</p>
} }
</NotAuthorized> </NotAuthorized>
</AuthorizeRouteView> </AuthorizeRouteView>