more externalization of strings
All checks were successful
CI/CD Pipeline / test (push) Successful in 5m58s
CI/CD Pipeline / deploy (push) Successful in 3m58s

This commit is contained in:
Philipp Hofer 2025-04-21 11:50:47 +02:00
parent ffbcf04da7
commit cb6f8a258a
3 changed files with 208 additions and 97 deletions

View File

@ -1,5 +1,25 @@
_version: 1 _version: 1
# Ascii: https://www.asciiart.eu/text-to-ascii-art banner
total_points: "Gesamtpunkte"
rank: "Rang"
logout: "Ausloggen"
save: "Speichern"
change_that_below: "Das kannst du hier ändern ⤵️"
add: "Hinzufügen"
#
# #####
# # # ##### ## ##### # #### # #
# # # # # # # # # ## #
# ##### # # # # # # # # # #
# # # ###### # # # # # # #
# # # # # # # # # # # ##
# ##### # # # # # #### # #
#
stations: "Stationen" stations: "Stationen"
station_create: "Station erstellen"
stations_expl_without_first_word: "sind festgelegte Orte mit spezifischen Aufgaben." stations_expl_without_first_word: "sind festgelegte Orte mit spezifischen Aufgaben."
station_warning_not_assigned_route: "Noch keiner Route zugeordnet" # should be short -> tooltip station_warning_not_assigned_route: "Noch keiner Route zugeordnet" # should be short -> tooltip
station_confirm_deletion: "Bist du sicher, dass die Station gelöscht werden soll? Das kann _NICHT_ mehr rückgängig gemacht werden." station_confirm_deletion: "Bist du sicher, dass die Station gelöscht werden soll? Das kann _NICHT_ mehr rückgängig gemacht werden."
@ -11,5 +31,85 @@ station_create_err_duplicate_name: "Station %{name} konnte _NICHT_ erstellt werd
station_delete_succ: "Station %{name} erfolgreich gelöscht" station_delete_succ: "Station %{name} erfolgreich gelöscht"
station_delete_err_nonexisting: "Station mit ID %{id} konnte nicht gelöscht werden, da sie nicht existiert" station_delete_err_nonexisting: "Station mit ID %{id} konnte nicht gelöscht werden, da sie nicht existiert"
station_delete_err_already_used: "Station %{name} konnte nicht gelöscht werden, da sie bereits verwendet wird (%{err})" station_delete_err_already_used: "Station %{name} konnte nicht gelöscht werden, da sie bereits verwendet wird (%{err})"
routes: "Routen" station_has_not_rated_team_yet: "Station hat Team noch nicht bewertet" # should be short -> tooltip
station_move_up: "%{name} nach vor reihen" # should be short -> tooltip
#
# #######
# # ###### ## # #
# # # # # ## ##
# # ##### # # # ## #
# # # ###### # #
# # # # # # #
# # ###### # # # #
#
team: "Team"
teams: "Teams" teams: "Teams"
go_to_teams: "Zu den Teams"
#
# # #
# # # # #### # # #### #### #### ##### ######
# # # # # # # # # # # # # # # #
# ####### # # ###### #### # # # # # #####
# # # # # ### # # # # # # ##### #
# # # # # # # # # # # # # # # # #
# # # # #### # # #### #### #### # # ######
#
highscore: "Highscore"
#
# #
# # # ##### # # # # #
# # # # # ## ## # ## #
# # # # # # ## # # # # #
# ####### # # # # # # # #
# # # # # # # # # ##
# # # ##### # # # # #
#
admins: "Admins"
#
# ######
# # # #### # # ##### ######
# # # # # # # # #
# ###### # # # # # #####
# # # # # # # # #
# # # # # # # # #
# # # #### #### # ######
#
route: "Route"
routes: "Routen"
route_new: "Neue Route"
route_name: "Routenname"
route_name_edit: "Routennamen bearbeiten"
route_has_no_station_assigned: "Keine Station zugeteilt" # should be short -> tooltip
route_confirm_deletion: "Bist du sicher, dass die Route gelöscht werden soll? Das kann _NICHT_ mehr rückgängig gemacht werden."
no_routes: "Es gibt noch keine Routen."
route_create_succ: "Route %{name} erfolgreich erstellt"
route_create_err_duplicate_name: "Route %{name} konnte _NICHT_ erstellt werden, da es bereits eine Route mit diesem Namen gibt (%{err})!"
route_delete_succ: "Route %{name} erfolgreich gelöscht"
route_delete_err_nonexisting: "Route mit ID %{id} konnte nicht gelöscht werden, da sie nicht existiert"
route_delete_err_already_used: "Route %{name} konnte nicht gelöscht werden, da sie bereits verwendet wird (%{err})"
cant_assign_station_to_route_because_no_stations_exist: "Bevor du einer Route Stationen zuweisen kannst, musst du die Stationen erstellen"
route_has_no_stations_yet: "Diese Route hat noch keine Stationen zugewiesen."
confirm_remove_station_from_route: "Bist du sicher, dass die Station von der Route entfernt werden soll?"
select_station_to_add_to_route: "Hinzuzufügende Station auswählen"
teams_with_this_route: "Teams mit dieser Route"
no_team_with_this_route: "Noch kein Team ist dieser Route zugeteilt"
route_update_err_nonexisting: "Route mit ID %{id} konnte nicht bearbeitet werden, da sie nicht existiert"
route_new_name: "Route %{old} heißt ab sofort %{new}."
route_cant_add_nonexisting_station: "Station mit ID {id} konnte nicht der Route %{route} hinzugefügt werden, da die Station nicht existiert"
station_added_to_route: "Station %{station} wurde erfolgreich der Route %{route} hinzugefügt"
station_can_only_be_added_once_to_route: "Station %{station} kann nur 1x der Route %{route} hinzugefügt werden (%{err})"
cant_remove_station_from_nonexisting_route: "Konnte keine Station von der Route mit ID %{id} entfernen, da diese Route nicht existiert."
cant_remove_nonexisting_station_from_route: "Konnte Station mit der ID %{id} nicht von der Route %{route} entfernen, da die Station nicht existiert."
station_deleted_from_route: "Station %{station} wurde von der Route %{route} gelöscht"
cant_remove_station_from_route_if_not_included: "Station %{station} kann nicht von der Route %{route} gelöscht werden, da diese nicht auf der Route liegt."
cant_move_nonexisting_station: "Konnte Station mit der ID %{id} nicht in der Route %{route} verschieben, da die Station nicht existiert."
station_succ_moved_in_route: "Station %{station} wurde in der Route %{route} erfolgreich vorgereiht"
cant_move_station_in_route_if_not_included: "Station %{station} kann in der Route %{route} nicht vorgereiht werden, da diese nicht auf der Route liegt."

View File

@ -30,7 +30,7 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
let content = html! { let content = html! {
h1 { h1 {
a href="/admin" { "↩️" } a href="/admin" { "↩️" }
"Highscore" (t!("highscore"))
} }
@for (idx, route) in routes.into_iter().enumerate() { @for (idx, route) in routes.into_iter().enumerate() {
details open[idx==0] { details open[idx==0] {
@ -40,15 +40,15 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
table { table {
thead { thead {
tr { tr {
td { "Team" } td { (t!("team")) }
@for station in route.stations(&db).await { @for station in route.stations(&db).await {
td { td {
(station) (station)
} }
} }
td { "Gesamtpunkte" } td { (t!("total_points")) }
td { "Rang" } td { (t!("rank")) }
td { "Team" } td { (t!("team")) }
} }
} }
tbody { tbody {
@ -74,7 +74,7 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
({total_points += points;""}) ({total_points += points;""})
(points) (points)
}@else { }@else {
em data-placement="bottom" data-tooltip="Station hat Team noch nicht bewertet" { em data-placement="bottom" data-tooltip=(t!("station_has_not_rated_team_yet")) {
"?" "?"
} }
} }
@ -116,7 +116,7 @@ async fn index(session: Session) -> Markup {
} }
ul { ul {
a href="/auth/logout" { a href="/auth/logout" {
"Ausloggen" (t!("logout"))
} }
} }
} }
@ -139,12 +139,12 @@ async fn index(session: Session) -> Markup {
} }
li { li {
a role="button" href="/admin/highscore" { a role="button" href="/admin/highscore" {
"Highscore" (t!("highscore"))
} }
} }
li { li {
a href="/admin/user" { a href="/admin/user" {
"Admins" (t!("admins"))
} }
} }
} }

View File

@ -1,5 +1,5 @@
use super::Route; use super::Route;
use crate::{admin::station::Station, err, page, succ, AppState}; use crate::{admin::station::Station, er, page, suc, AppState};
use axum::{ use axum::{
extract::State, extract::State,
response::{IntoResponse, Redirect}, response::{IntoResponse, Redirect},
@ -32,7 +32,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
@for route in &routes{ @for route in &routes{
li { li {
@if route.stations(&db).await.is_empty() { @if route.stations(&db).await.is_empty() {
em data-tooltip="Keine Stationen zugeteilt" { em data-tooltip=(t!("route_has_no_station_assigned")) {
"⚠️" "⚠️"
} }
} }
@ -40,7 +40,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
(route.name) (route.name)
} }
a href=(format!("/admin/route/{}/delete", route.id)) a href=(format!("/admin/route/{}/delete", route.id))
onclick="return confirm('Bist du sicher, dass die Route gelöscht werden soll? Das kann _NICHT_ mehr rückgängig gemacht werden.');" { onclick=(format!("return confirm('{}');", t!("route_confirm_deletion"))) {
"🗑️" "🗑️"
} }
} }
@ -48,14 +48,16 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
} }
@if routes.is_empty() { @if routes.is_empty() {
article class="warning" { article class="warning" {
"Es gibt noch keine Routen. Das kannst du hier ändern ⤵️" (t!("no_routes"))
" "
(t!("change_that_below"))
} }
} }
h2 { "Neue Route" } h2 { (t!("route_new")) }
form action="/admin/route" method="post" { form action="/admin/route" method="post" {
fieldset role="group" { fieldset role="group" {
input type="text" name="name" placeholder="Routenname" required; input type="text" name="name" placeholder=(t!("route_name")) required;
input type="submit" value="Neue Route"; input type="submit" value=(t!("route_new"));
} }
} }
}; };
@ -73,11 +75,10 @@ async fn create(
Form(form): Form<CreateForm>, Form(form): Form<CreateForm>,
) -> impl IntoResponse { ) -> impl IntoResponse {
match Route::create(&db, &form.name).await { match Route::create(&db, &form.name).await {
Ok(()) => succ!(session, "Route '{}' erfolgreich erstellt!", form.name), Ok(()) => suc!(session, t!("route_create_succ", name = form.name)),
Err(e) => err!( Err(e) => er!(
session, session,
"Route '{}' konnte _NICHT_ erstellt werden, da es bereits eine Route mit diesem Namen gibt ({e})!", t!("route_create_err_duplicate_name", name = form.name, err = e)
form.name
), ),
} }
@ -90,20 +91,16 @@ async fn delete(
axum::extract::Path(id): axum::extract::Path<i64>, axum::extract::Path(id): axum::extract::Path<i64>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let Some(route) = Route::find_by_id(&db, id).await else { let Some(route) = Route::find_by_id(&db, id).await else {
err!( er!(session, t!("route_delete_err_nonexisting"));
session,
"Route mit ID {id} konnte nicht gelöscht werden, da sie nicht existiert"
);
return Redirect::to("/admin/route"); return Redirect::to("/admin/route");
}; };
match route.delete(&db).await { match route.delete(&db).await {
Ok(()) => succ!(session, "Route '{}' erfolgreich gelöscht!", route.name), Ok(()) => suc!(session, t!("route_delete_succ")),
Err(e) => err!( Err(e) => er!(
session, session,
"Route '{}' kann nicht gelöscht werden, da sie bereits verwendet wird. ({e})", t!("route_delete_err_already_used", name = route.name, err = e)
route.name
), ),
} }
@ -116,10 +113,7 @@ async fn view(
axum::extract::Path(id): axum::extract::Path<i64>, axum::extract::Path(id): axum::extract::Path<i64>,
) -> Result<Markup, impl IntoResponse> { ) -> Result<Markup, impl IntoResponse> {
let Some(route) = Route::find_by_id(&db, id).await else { let Some(route) = Route::find_by_id(&db, id).await else {
err!( er!(session, t!("route_delete_err_nonexisting"));
session,
"Route mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert"
);
return Err(Redirect::to("/admin/route")); return Err(Redirect::to("/admin/route"));
}; };
@ -132,29 +126,34 @@ async fn view(
let content = html! { let content = html! {
h1 { h1 {
a href="/admin/route" { "↩️" } a href="/admin/route" { "↩️" }
"Route " (route.name) (t!("route"))
" "
(route.name)
} }
article { article {
details { details {
summary { "Routenname bearbeiten ✏️" } summary { (t!("route_name_edit")) "✏️" }
form action=(format!("/admin/route/{}/name", route.id)) method="post" { form action=(format!("/admin/route/{}/name", route.id)) method="post" {
input type="text" name="name" value=(route.name) required; input type="text" name="name" value=(route.name) required;
input type="submit" value="Speichern"; input type="submit" value=(t!("save"));
} }
} }
} }
h2 { "Stationen" } h2 { (t!("stations")) }
@if cur_stations.is_empty() { @if cur_stations.is_empty() {
@if stations_not_in_route.is_empty() { @if stations_not_in_route.is_empty() {
article class="error" { article class="error" {
(PreEscaped("Bevor du einer Route Stationen zuweisen kannst, musst du die Stationen erstellen &rarr; ")) (t!("cant_assign_station_to_route_because_no_stations_exist"))
(PreEscaped(" &rarr; "))
a role="button" href="/admin/station" { a role="button" href="/admin/station" {
"Station erstellen" (t!("station_create"))
} }
} }
} @else { } @else {
article class="warning" { article class="warning" {
"Diese Route hat noch keine Stationen zugewiesen. Das kannst du hier ändern ⤵️" (t!("route_has_no_stations_yet"))
" "
(t!("change_that_below"))
} }
} }
} @else { } @else {
@ -164,13 +163,13 @@ async fn view(
(station) (station)
@if idx > 0 { @if idx > 0 {
a href=(format!("/admin/route/{}/move-station-higher/{}", route.id, station.id)){ a href=(format!("/admin/route/{}/move-station-higher/{}", route.id, station.id)){
em data-tooltip=(format!("{} nach vor reihen", station.name)) { em data-tooltip=(t!("station_move_up", name = station.name)) {
"⬆️" "⬆️"
} }
} }
} }
a href=(format!("/admin/route/{}/delete-station/{}", route.id, station.id)) a href=(format!("/admin/route/{}/delete-station/{}", route.id, station.id))
onclick="return confirm('Bist du sicher, dass die Station von der Route entfernt werden soll?');" { onclick=(format!("return confirm('{}');", t!("confirm_remove_station_from_route"))) {
"🗑️" "🗑️"
} }
} }
@ -179,22 +178,22 @@ async fn view(
} }
@if !stations_not_in_route.is_empty(){ @if !stations_not_in_route.is_empty(){
form action=(format!("/admin/route/{}/add-station", route.id)) method="post" { form action=(format!("/admin/route/{}/add-station", route.id)) method="post" {
select name="station" aria-label="Hinzuzufügende Station auswählen" required { select name="station" aria-label=(t!("select_station_to_add_to_route")) required {
@for station in &stations_not_in_route { @for station in &stations_not_in_route {
option value=(station.id) { option value=(station.id) {
(station.name) (station.name)
} }
} }
input type="submit" value="Hinzufügen"; input type="submit" value=(t!("add"));
} }
} }
} }
h2 { "Teams mit dieser Route" } h2 { (t!("teams_with_this_route")) }
@if teams.is_empty() { @if teams.is_empty() {
article { article {
"Noch keine Team ist dieser Route zugeteilt." (t!("no_team_with_this_route"))
a role="button" href="/admin/team" { a role="button" href="/admin/team" {
"Zu den Teams" (t!("go_to_teams"))
} }
} }
@ -225,21 +224,16 @@ async fn update_name(
Form(form): Form<UpdateNameForm>, Form(form): Form<UpdateNameForm>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let Some(route) = Route::find_by_id(&db, id).await else { let Some(route) = Route::find_by_id(&db, id).await else {
err!( er!(session, t!("route_update_err_nonexisting", id = id));
session,
"Route mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert"
);
return Redirect::to("/admin/route"); return Redirect::to("/admin/route");
}; };
route.update_name(&db, &form.name).await; route.update_name(&db, &form.name).await;
succ!( suc!(
session, session,
"Route '{}' heißt ab sofort {}.", t!("route_new_name", old = route.name, new = form.name)
route.name,
form.name
); );
Redirect::to(&format!("/admin/route/{id}")) Redirect::to(&format!("/admin/route/{id}"))
@ -256,34 +250,40 @@ async fn add_station(
Form(form): Form<AddStationForm>, Form(form): Form<AddStationForm>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let Some(route) = Route::find_by_id(&db, id).await else { let Some(route) = Route::find_by_id(&db, id).await else {
err!( er!(session, t!("route_update_err_nonexisting", id = id));
session,
"Route mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert"
);
return Redirect::to("/admin/route"); return Redirect::to("/admin/route");
}; };
let Some(station) = Station::find_by_id(&db, form.station).await else { let Some(station) = Station::find_by_id(&db, form.station).await else {
err!( er!(
session, session,
"Station mit ID {id} konnte nicht hinzugefügt werden, da sie nicht existiert" t!(
"route_cant_add_nonexisting_station",
id = form.station,
route = route.name
)
); );
return Redirect::to(&format!("/admin/route/{id}")); return Redirect::to(&format!("/admin/route/{id}"));
}; };
match route.add_station(&db, &station).await { match route.add_station(&db, &station).await {
Ok(()) => succ!( Ok(()) => suc!(
session, session,
"Station {} wurde der Route {} hinzugefügt", t!(
station.name, "station_added_to_route",
route.name station = station.name,
route = route.name
)
), ),
Err(e) => err!( Err(e) => er!(
session, session,
"Station {} kann nur 1x der Route {} hinzugefügt werden. ({e})", t!(
station.name, "station_can_only_be_added_once_to_route",
route.name station = station.name,
route = route.name,
err = e
)
), ),
} }
@ -296,36 +296,43 @@ async fn delete_station(
axum::extract::Path((route_id, station_id)): axum::extract::Path<(i64, i64)>, axum::extract::Path((route_id, station_id)): axum::extract::Path<(i64, i64)>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let Some(route) = Route::find_by_id(&db, route_id).await else { let Some(route) = Route::find_by_id(&db, route_id).await else {
err!( er!(
session, session,
"Konnte keine Station von Route mit ID {route_id} entfernen, da diese Route nicht existiert." t!("cant_remove_station_from_nonexisting_route", id = route_id)
); );
return Redirect::to("/admin/route"); return Redirect::to("/admin/route");
}; };
let Some(station) = Station::find_by_id(&db, station_id).await else { let Some(station) = Station::find_by_id(&db, station_id).await else {
err!( er!(
session, session,
"Konnte Station mit der ID {station_id} nicht von der Route {} entfernen, da die Station nicht existiert.", t!(
route.name "cant_remove_nonexisting_station_from_route",
id = station_id,
route = route.name
)
); );
return Redirect::to(&format!("/admin/route/{route_id}")); return Redirect::to(&format!("/admin/route/{route_id}"));
}; };
if route.delete_station(&db, &station).await { if route.delete_station(&db, &station).await {
succ!( suc!(
session, session,
"Station '{}' wurde von der Route '{}' gelöscht", t!(
station.name, "station_deleted_from_route",
route.name station = station.name,
route = route.name
)
); );
} else { } else {
err!( er!(
session, session,
"Station '{}' konnte nicht von der Route '{}' gelöscht werden, da diese nicht auf dieser Route liegt", t!(
station.name, "cant_remove_station_from_route_if_not_included",
route.name station = station.name,
route = route.name
)
); );
} }
@ -338,36 +345,40 @@ async fn move_station_higher(
axum::extract::Path((route_id, station_id)): axum::extract::Path<(i64, i64)>, axum::extract::Path((route_id, station_id)): axum::extract::Path<(i64, i64)>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let Some(route) = Route::find_by_id(&db, route_id).await else { let Some(route) = Route::find_by_id(&db, route_id).await else {
err!( er!(session, t!("route_update_err_nonexisting", id = route_id));
session,
"Konnte keine Station von Route mit ID {route_id} verschieben, da diese Route nicht existiert."
);
return Redirect::to("/admin/route"); return Redirect::to("/admin/route");
}; };
let Some(station) = Station::find_by_id(&db, station_id).await else { let Some(station) = Station::find_by_id(&db, station_id).await else {
err!( er!(
session, session,
"Konnte Station mit der ID {station_id} nicht in der Route {} verschieben, da die Station nicht existiert.", t!(
route.name "cant_move_nonexisting_station",
id = station_id,
route = route.name
)
); );
return Redirect::to(&format!("/admin/route/{route_id}")); return Redirect::to(&format!("/admin/route/{route_id}"));
}; };
if route.move_station_higher(&db, &station).await { if route.move_station_higher(&db, &station).await {
succ!( suc!(
session, session,
"Station '{}' wurde in der Route '{}' erfolgreich vorgereiht", t!(
station.name, "station_succ_moved_in_route",
route.name station = station.name,
route = route.name
)
); );
} else { } else {
err!( er!(
session, session,
"Station '{}' konnte in der Route '{}' nicht vorgereiht werden, da diese nicht auf dieser Route liegt", t!(
station.name, "cant_move_station_in_route_if_not_included",
route.name station = station.name,
route = route.name
)
); );
} }