diff --git a/Cargo.lock b/Cargo.lock index 7333566..e6f3974 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1126,9 +1126,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -1720,9 +1720,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -2134,7 +2134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a2a4764cc1f8d961d802af27193c6f4f0124bd0e76e8393cf818e18880f0524" dependencies = [ "argon2", - "getrandom 0.2.15", + "getrandom 0.2.16", "password-hash", "rand_core 0.6.4", ] @@ -2462,7 +2462,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2509,7 +2509,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -2586,7 +2586,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -2643,8 +2643,6 @@ dependencies = [ [[package]] name = "rust-i18n" version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b6307cde881492032919adf26e254981604a6657b339ae23cce8358e9ee203" dependencies = [ "globwalk", "once_cell", @@ -2657,8 +2655,6 @@ dependencies = [ [[package]] name = "rust-i18n-macro" version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0dc724669fe2ddbbec5ed9daea8147a9030de87ebb46fdc7bb9315701d9912" dependencies = [ "glob", "once_cell", @@ -2674,8 +2670,6 @@ dependencies = [ [[package]] name = "rust-i18n-support" version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47501de04282525d0192c4b4133f9e3574e1fab3542ddc7bb109ff773dc108b" dependencies = [ "arc-swap", "base62", diff --git a/Cargo.toml b/Cargo.toml index 00e19e7..2da5a83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ serde = "1.0" sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "macros", "chrono"] } tokio = { version = "1.44", features = ["macros", "rt-multi-thread"] } tower-sessions = "0.14" -rust-i18n = "3" +#rust-i18n = { version = "3", features = [ "log-miss-tr" ] } +rust-i18n = { path="/home/ph/rust-i18n" } thiserror = "2.0" async-trait = "0.1" password-auth = "1.0" @@ -37,3 +38,7 @@ typst-pdf = "0.13" [dev-dependencies] axum-test = "17.3" + +[package.metadata.i18n] +available-locales = ["de-AT"] +default-locale = "de-AT" diff --git a/locales/de-AT.yml b/locales/de-AT.yml index 9cf2e52..4db45df 100644 --- a/locales/de-AT.yml +++ b/locales/de-AT.yml @@ -24,6 +24,7 @@ run_restarted: "Stationslauf erfolgreich wieder aufgenommen" come_home_with_these_groups: "Gruppen mitnehmen" station_info: "Schön, dass du uns als Stationsbetreuer hilfst." info_crewless_station: "Wenn das eine unbemannte Station ist, wähle hier 0 Personen aus. Dann werden dieser Station keine Startteams zugeteilt und es wird kein PDF generiert." +time: "Uhrzeit" # # ###### @@ -34,15 +35,15 @@ info_crewless_station: "Wenn das eine unbemannte Station ist, wähle hier 0 Pers # # # # ## ## # # # # # # # ## # # # ###### ###### # # ###### # # # #### # # #### # -rating: "Bewertung" ratings: "Bewertungen" +rate_crewless_stations: "Unbemannte Stationen bewerten" invalid_rating_code: "Falscher Quick-Login-Link. Bitte nochmal scannen oder neu eingeben." infos: "Infos" station_has_no_teams_to_take_to_start: "Nachdem es offiziell losgeht kannst du gleich direkt zu deiner Station gehen, du musst keine Teams mitnehmen." station_should_take_one_teams_to_start: "Nachdem es offiziell losgeht, nimm bitte folgendes Team am Anfang zu deiner Station mit:" station_should_take_n_teams_to_start: "Nachdem es offiziell losgeht, nimm bitte folgende %{amount} Teams am Anfang zu deiner Station mit:" your_station_is_here: "Deine Station befindet sich hier:" -station_ready: "Sobald du bei deiner Station bist und bereit zu starten bist, drücke diesen Button damit wir Bescheid wissen" +button_station_ready: "Sobald du bei deiner Station bist und bereit zu starten bist, drücke diesen Button damit wir Bescheid wissen" station_not_yet_ready: "Bin mit der Station doch noch nicht bereit..." one_team_should_come_to_station: "Insgesamt sollte 1 Team zu deiner Station kommen." n_teams_should_come_to_station: "Insgesamt sollten %{amount} Teams zu deiner Station kommen." @@ -116,8 +117,9 @@ confirm_station_cancel_team_finished: "Bist du sicher, dass das Team noch nicht # station: "Station" stations: "Stationen" +nonexisting_station: "Station mit ID %{id} existiert nicht." station_url: "Stations-Link" -station_url_info: "Diesen Link nur Betreuern der Station #{station} geben! Mit diesem Link erhält man die Berechtigung, Teams zu bewerten." +station_url_info: "Diesen Link nur Betreuern der Station %{station} geben! Mit diesem Link erhält man die Berechtigung, Teams zu bewerten." login_link: "Login-Link" station_name_edit: "Routennamen bearbeiten" go_to_stations: "Zu den Stationen" @@ -166,6 +168,11 @@ location_deleted: "Standort für die Station %{station} wurde erfolgreich gelös progress: "Fortschritt" station_team_progress: "%{arrived}/%{total} (davon %{waiting} wartend + %{active} aktiv)" station_ready: "Station bereit!" +first_station: "Erste Station" +first_station_expl: "Die erste Station wird beim Anlegen eines Team automatisch an diejenige Station vergeben, die aktuell am wenigsten Startteams hat. Diese Zuteilung kannst du hier auch manuell verändern." +new_team_name: "Team %{old} heißt ab sofort %{new}" +notes_edited: "Notizen für das Team %{team} erfolgreich geändert" +amount_teammembers_edited: "Anzahl an Mitglieder für das Team %{team} erfolgreich geändert" # @@ -179,10 +186,39 @@ station_ready: "Station bereit!" # team: "Team" teams: "Teams" +nonexisting_team: "Team mit ID %{id} existiert nicht." select_team: "Team auswählen" +new_team: "Neues Team" +edit_teamname: "Teamname bearbeiten" +teamname: "Teamname" go_to_teams: "Zu den Teams" not_yet_started: "nocht nicht gestartet" not_yet_done: "nocht nicht fertig" +team_created: "Team %{team} erstellt" +team_deleted: "Team %{team} gelöscht" +add_new_note: "Neue Notiz hinzufügen" +team_not_created_duplicate_name: "Team %{team} konnte nicht erstellt werden, da es bereits ein Team mit diesem Namen gibt (%{err})" +team_not_created_no_station_in_route: "Team %{team} konnte nicht erstellt werden, da in der angegebenen Route %{route} keine Station vorkommt und daher die Startstation nicht festgelegt werden kann." +team_not_deleted_already_in_use: "Team %{team} kann nicht gelöscht werden, da es bereits verwendet wird. (%{err})" +amount_teammembers: "Anzahl Teammitglieder" +not_sure_about_amount_team: "Ich weiß noch nicht wv. Personen dieses Team beherbergt." +select_station: "Station auswählen" +already_has_1_start_team: "schon 1 Startteam" +already_has_n_start_team: "schon %{amount} Startteams" +last_station: "Letzte Station" +route_edited: "Team %{team} läuft ab sofort die Route %{route}. Auch die erste Station hat sich dadurch auf %{first_station} verändert" +team_not_edited_route_has_no_stations: "Team %{team} kann nicht zur Route %{route} zugeteilt werden, da diese Route noch keine Station hat und daher die Startstation nicht festgelegt werden kann." +first_station_not_edited_not_on_route: "Konnte Station %{station} nicht als erste Station dem Team %{team} zuteilen, weil dieses Team bei Route %{route} mitläuft und die Station nicht auf dieser Route liegt." +last_station_not_edited_not_on_route: "Konnte Station %{station} nicht als letzte Station dem Team %{team} zuteilen, weil dieses Team bei Route %{route} mitläuft und die Station nicht auf dieser Route liegt." +changed_first_station: "Erste Station des Teams %{team} ist ab sofort Station %{station}" +changed_last_station: "Letzte Station des Teams %{team} ist ab sofort Station %{station}" +last_contact_team: "Letzter Stationskontakt der Teams" +not_yet_seen: "Noch nicht gesehen" +no_teams: "Es gibt noch keine Teams." +route_needed_before_creating_teams: "Bevor du ein Team erstellen kannst, musst du zumindest eine Route erstellen, die das Team gehen kann" +have_i_lost_groups: "Hab ich eine Gruppe verloren? 😳" +confirm_delete_team: "Bist du sicher, dass das Team gelöscht werden soll? Das kann _NICHT_ mehr rückgängig gemacht werden." + # @@ -239,8 +275,11 @@ confirm_admin_delete: "Bist du sicher, dass der User gelöscht werden soll? Das # route: "Route" routes: "Routen" +nonexisting_route: "Route mit ID %{id} existiert nicht." route_new: "Neue Route" route_name: "Routenname" +create_route: "Route erstellen" +select_route: "Route auswählen" 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." @@ -258,7 +297,7 @@ 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" +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." diff --git a/src/admin/route/web.rs b/src/admin/route/web.rs index bc8a75b..2a2da0e 100644 --- a/src/admin/route/web.rs +++ b/src/admin/route/web.rs @@ -1,12 +1,12 @@ use super::Route; -use crate::{AppState, admin::station::Station, er, page, suc}; +use crate::{admin::station::Station, er, page, suc, AppState}; use axum::{ - Form, Router, extract::State, response::{IntoResponse, Redirect}, routing::{get, post}, + Form, Router, }; -use maud::{Markup, PreEscaped, html}; +use maud::{html, Markup, PreEscaped}; use serde::Deserialize; use sqlx::SqlitePool; use std::sync::Arc; @@ -91,13 +91,12 @@ async fn delete( axum::extract::Path(id): axum::extract::Path, ) -> impl IntoResponse { let Some(route) = Route::find_by_id(&db, id).await else { - er!(session, t!("route_delete_err_nonexisting")); - + er!(session, t!("route_delete_err_nonexisting", id = id)); return Redirect::to("/admin/route"); }; match route.delete(&db).await { - Ok(()) => suc!(session, t!("route_delete_succ")), + Ok(()) => suc!(session, t!("route_delete_succ", name = route.name)), Err(e) => er!( session, t!("route_delete_err_already_used", name = route.name, err = e) @@ -113,8 +112,7 @@ async fn view( axum::extract::Path(id): axum::extract::Path, ) -> Result { let Some(route) = Route::find_by_id(&db, id).await else { - er!(session, t!("route_delete_err_nonexisting")); - + er!(session, t!("route_delete_err_nonexisting", id = id)); return Err(Redirect::to("/admin/route")); }; diff --git a/src/admin/station/web.rs b/src/admin/station/web.rs index f0081ed..55e3ebd 100644 --- a/src/admin/station/web.rs +++ b/src/admin/station/web.rs @@ -128,7 +128,7 @@ async fn view( @if !station.crewless() { tr { th scope="row" { - (t!("station_link")) + (t!("station_url")) article class="warning" { (t!("station_url_info", station=station.name)) } @@ -584,7 +584,7 @@ async fn update_location_clear( station.update_location_clear(&db).await; - suc!(session, t!("location_changed", station = station.name)); + suc!(session, t!("location_deleted", station = station.name)); Redirect::to(&format!("/admin/station/{id}")) } diff --git a/src/admin/team/web.rs b/src/admin/team/web.rs index 52292bb..724a9ae 100644 --- a/src/admin/team/web.rs +++ b/src/admin/team/web.rs @@ -1,10 +1,10 @@ use super::{CreateError, LastContactTeam, Team}; use crate::{ admin::{route::Route, station::Station}, - err, + er, models::rating::Rating, partials::page, - pl, succ, AppState, + suc, AppState, }; use axum::{ extract::State, @@ -30,36 +30,32 @@ async fn create( Form(form): Form, ) -> impl IntoResponse { let Some(route) = Route::find_by_id(&db, form.route_id).await else { - err!( - session, - "Team mit {} konnte nicht erstellt werden, da keine Route mit ID {} existiert", - form.name, - form.route_id - ); + er!(session, t!("nonexisting_route", id = form.route_id)); return Redirect::to("/admin/team"); }; let id = match Team::create(&db, &form.name, &route).await { Ok(id) => { - succ!(session, "Team '{}' erfolgreich erstellt!", form.name); + suc!(session, t!("team_created", team = form.name)); id } Err(CreateError::DuplicateName(e)) => { - err!( + er!( session, - "Team '{}' konnte _NICHT_ erstellt werden, da es bereits ein Team mit diesem Namen gibt ({e})!", - form.name + t!("team_not_created_duplicate_name", team = form.name, err = e) ); return Redirect::to("/admin/team"); } Err(CreateError::NoStationForRoute) => { - err!( + er!( session, - "Team '{}' konnte _NICHT_ erstellt werden, da in der angegebenen Route '{}' noch keine Stationen vorkommen", - form.name, - route.name + t!( + "team_not_created_no_station_in_route", + team = form.name, + route = route.name + ) ); return Redirect::to("/admin/team"); @@ -75,20 +71,15 @@ async fn delete( axum::extract::Path(id): axum::extract::Path, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht gelöscht werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; match team.delete(&db).await { - Ok(()) => succ!(session, "Team '{}' erfolgreich gelöscht!", team.name), - Err(e) => err!( + Ok(()) => suc!(session, t!("team_deleted", team = team.name)), + Err(e) => er!( session, - "Team '{}' kann nicht gelöscht werden, da sie bereits verwendet wird. ({e})", - team.name + t!("team_not_deleted_already_in_use", team = team.name, err = e) ), } @@ -99,15 +90,19 @@ async fn quick(db: Arc, team: &Team, stations: Vec, redirec html! { h1 { a href=(format!("/admin/team/{}", team.id)) { "↩️" } - "Bewertungen Team " (team.name) + (t!("ratings")) + " " + (t!("team")) + " " + (team.name) } form action=(format!("/admin/team/{}/quick", team.id)) method="post" { input type="hidden" name="redirect" value=(redirect); table { thead { tr { - th { "Station" } - th { "Punkte" } + th { (t!("station")) } + th { (t!("points")) } } } tbody { @@ -122,11 +117,11 @@ async fn quick(db: Arc, team: &Team, stations: Vec, redirec @if let Some(rating) = Rating::find_by_team_and_station(&db, team, station).await { a href=(format!("/s/{}/{}", station.id, station.pw)){ @if let Some(points) = rating.points { - em data-tooltip="Schon eingetragen" { + em data-tooltip=(t!("already_entered")) { (points) } } @else { - em data-tooltip="Team gerade bei Station" { "?" } + em data-tooltip=(t!("team_currently_at_station")) { "?" } } } } @else { @@ -138,7 +133,7 @@ async fn quick(db: Arc, team: &Team, stations: Vec, redirec } } } - input type="submit" value="Speichern"; + input type="submit" value=(t!("save")); } } } @@ -148,11 +143,7 @@ async fn quick_crewless( axum::extract::Path(id): axum::extract::Path, ) -> Result { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Err(Redirect::to("/admin/team")); }; @@ -169,11 +160,7 @@ async fn quick_all( axum::extract::Path(id): axum::extract::Path, ) -> Result { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Err(Redirect::to("/admin/team")); }; @@ -197,11 +184,7 @@ async fn quick_post( Form(form): Form, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; @@ -231,7 +214,13 @@ async fn quick_post( .await .is_some() { - ret.push_str(&format!("Skipped rating for station {} because this station already has a rating for team {}", station.name, team.name)); + let msg: String = t!( + "error_rating_team_already_rated", + team = team.name, + station = station.name + ) + .into(); + ret.push_str(&msg); continue; } @@ -245,12 +234,9 @@ async fn quick_post( } if amount_succ == 0 { - succ!( - session, - "Du hast keine Bewertungen eingegeben... Spaßvogel!" - ); + suc!(session, t!("funny_you_entered_no_rating")); } else { - succ!(session, "Erfolgreich {amount_succ} Bewertungen eingetragen"); + suc!(session, t!("entered_n_ratings", amount = amount_succ)); } Redirect::to(&format!("/admin/team/{id}/quick{}", form.redirect)) @@ -262,11 +248,7 @@ async fn view( axum::extract::Path(id): axum::extract::Path, ) -> Result { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Err(Redirect::to("/admin/team")); }; let first_station = team.first_station(&db).await; @@ -279,14 +261,19 @@ async fn view( let content = html! { h1 { a href="/admin/team" { "↩️" } - "Team " (team.name) + (t!("team")) + " " + (team.name) } article { details { - summary { "Teamnamen bearbeiten ✏️" } + summary { + (t!("edit_teamname")) + " ✏️" + } form action=(format!("/admin/team/{}/name", team.id)) method="post" { input type="text" name="name" value=(team.name) required; - input type="submit" value="Speichern"; + input type="submit" value=(t!("save")); } } @@ -294,7 +281,7 @@ async fn view( table { tbody { tr { - th scope="row" { "Notizen" }; + th scope="row" { (t!("notes")) }; td { @match &team.notes { Some(notes) => { @@ -303,22 +290,22 @@ async fn view( summary { "✏️" } form action=(format!("/admin/team/{}/notes", team.id)) method="post" { textarea name="notes" required rows="10" { (notes) }; - input type="submit" value="Speichern"; + input type="submit" value=(t!("save")); } } }, None => details { - summary { "Neue Notiz hinzufügen" } + summary { (t!("add_new_note")) } form action=(format!("/admin/team/{}/notes", team.id)) method="post" { textarea name="notes" required rows="10" {}; - input type="submit" value="Speichern"; + input type="submit" value=(t!("save")); } } } } } tr { - th scope="row" { "Anzahl Teammitglieder" }; + th scope="row" { (t!("amount_teammembers")) }; td { @match team.amount_people { Some(amount) => (amount), @@ -328,11 +315,11 @@ async fn view( summary { "✏️" } form action=(format!("/admin/team/{}/amount-people", team.id)) method="post" { input type="number" name="amount_people" min="0" max="10"; - input type="submit" value="Speichern"; + input type="submit" value=(t!("save")); } a href=(format!("/admin/team/{}/amount-people-reset", team.id)) { button class="error" { - em data-tooltip="Ich weiß noch nicht wv. Personen dieses Team beherbergt." { + em data-tooltip=(t!("not_sure_about_amount_team")) { "?" } } @@ -341,7 +328,7 @@ async fn view( } } tr { - th scope="row" { "Route" }; + th scope="row" { (t!("route")) }; td { a href=(format!("/admin/route/{}", &team.route(&db).await.id)) { (&team.route(&db).await.name) @@ -350,7 +337,7 @@ async fn view( details { summary { "✏️" } form action=(format!("/admin/team/{}/update-route", team.id)) method="post" { - select name="route_id" aria-label="Route auswählen" required { + select name="route_id" aria-label=(t!("select_route")) required { @for route in &routes { @if route.id != team.route(&db).await.id { option value=(route.id) { @@ -359,7 +346,7 @@ async fn view( } } } - input type="submit" value="Team speichern"; + input type="submit" value=(t!("save")); } } } @@ -367,9 +354,9 @@ async fn view( } tr { th scope="row" { - "Erste Station" + (t!("first_station")) article { - "Die erste Station wird beim Anlegen eines Team automatisch an diejenige Station vergeben, die aktuell am wenigsten Startteams hat. Diese Zuteilung kannst du hier auch manuell verändern." + (t!("first_station_expl")) } }; td { @@ -380,20 +367,24 @@ async fn view( details { summary { "✏️" } form action=(format!("/admin/team/{}/update-first-station", team.id)) method="post" { - select name="first_station_id" aria-label="Station auswählen" required { + select name="first_station_id" aria-label=(t!("select_station")) required { @for station in &stations { @if station.id != first_station.id { option value=(station.id) { (station.name) @let amount_start_teams = Team::all_with_first_station(&db, station).await.len(); @if amount_start_teams > 0 { - (format!(" (schon {amount_start_teams} {})", pl(amount_start_teams, "Startteam", "s"))) + @if amount_start_teams == 1 { + (t!("already_has_1_start_team")) + }@else{ + (t!("already_has_n_start_team", amount=amount_start_teams)) + } } } } } } - input type="submit" value="Station speichern"; + input type="submit" value=(t!("save")); } } } @@ -402,7 +393,7 @@ async fn view( @if let Some(last_station) = last_station { tr { th scope="row" { - "Letzte Station" + (t!("last_station")) }; td { a href=(format!("/admin/station/{}", last_station.id)) { @@ -412,7 +403,7 @@ async fn view( details { summary { "✏️" } form action=(format!("/admin/team/{}/update-last-station", team.id)) method="post" { - select name="last_station_id" aria-label="Station auswählen" required { + select name="last_station_id" aria-label=(t!("select_station")) required { @for station in &stations { @if station.id != last_station.id { option value=(station.id) { @@ -421,7 +412,7 @@ async fn view( } } } - input type="submit" value="Station speichern"; + input type="submit" value=(t!("save")); } } } @@ -433,13 +424,13 @@ async fn view( } a href=(format!("/admin/team/{}/quick", team.id)){ button { - "Bewertungen" + (t!("ratings")) } } hr; a href=(format!("/admin/team/{}/quick/crewless", team.id)){ button { - "Unbemannte Bewertungen" + (t!("rate_crewless_stations")) } } }; @@ -457,21 +448,15 @@ async fn update_name( Form(form): Form, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; team.update_name(&db, &form.name).await; - succ!( + suc!( session, - "Team '{}' heißt ab sofort '{}'.", - team.name, - form.name + t!("new_team_name", old = team.name, new = form.name) ); Redirect::to(&format!("/admin/team/{id}")) @@ -488,21 +473,13 @@ async fn update_notes( Form(form): Form, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; team.update_notes(&db, &form.notes).await; - succ!( - session, - "Notizen für das Team '{}' wurden erfolgreich bearbeitet!", - team.name - ); + suc!(session, t!("notes_edited", team = team.name)); Redirect::to(&format!("/admin/team/{id}")) } @@ -518,21 +495,13 @@ async fn update_amount_people( Form(form): Form, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; team.update_amount_people(&db, form.amount_people).await; - succ!( - session, - "Anzahl an Mitglieder für das Team '{}' wurden erfolgreich bearbeitet!", - team.name - ); + suc!(session, t!("amount_teammembers_edited", team = team.name)); Redirect::to(&format!("/admin/team/{id}")) } @@ -549,38 +518,32 @@ async fn update_route( ) -> impl IntoResponse { // TODO: move sanity checks into mod.rs let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; let Some(route) = Route::find_by_id(&db, form.route_id).await else { - err!( - session, - "Konnte Team mit ID {id} konnte nicht zur Route mit ID {} bearbeiten, da diese Route nicht existiert.", - form.route_id - ); - + er!(session, t!("nonexisting_route", id = form.route_id)); return Redirect::to(&format!("/admin/team/{id}")); }; match team.update_route(&db, &route).await { - Ok(new_first_station_name) => succ!( + Ok(new_first_station_name) => suc!( session, - "Team '{}' läuft ab sofort die Route '{}'. Auch die erste Station hat sich dadurch auf {} verändert!!", - team.name, - route.name, - new_first_station_name + t!( + "route_edited", + team = team.name, + route = route.name, + first_station = new_first_station_name + ) ), - Err(()) => err!( + Err(()) => er!( session, - "Konnte für das Team {} nicht die Route {} auswählen, da Route {} keine Stationen zugeteilt hat.", - team.name, - route.name, - route.name + t!( + "team_not_edited_route_has_no_stations", + team = team.name, + route = route.name + ) ), } @@ -598,33 +561,28 @@ async fn update_first_station( Form(form): Form, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; let Some(station) = Station::find_by_id(&db, form.first_station_id).await else { - err!( + er!( session, - "Konnte die erste Station (ID={}) des Teams mit ID {} nicht bearbeiten, da diese Station nicht existiert.", - form.first_station_id, - team.id + t!("nonexisting_station", id = form.first_station_id) ); return Redirect::to(&format!("/admin/team/{id}")); }; if !station.is_in_route(&db, &team.route(&db).await).await { - err!( + er!( session, - "Konnte Station {} nicht dem Team {} hinzufügen, weil dieses Team bei Route {} und nicht bei Route {} mitläuft.", - station.name, - team.name, - team.route(&db).await.name, - team.name + t!( + "first_station_not_edited_not_on_route", + station = station.name, + team = team.name, + route = team.route(&db).await.name + ) ); return Redirect::to(&format!("/admin/team/{id}")); @@ -632,11 +590,13 @@ async fn update_first_station( team.update_first_station(&db, &station).await; - succ!( + suc!( session, - "Erste Station des Teams {} ist ab sofort {}", - team.name, - station.name + t!( + "changed_first_station", + team = team.name, + station = station.name + ) ); Redirect::to(&format!("/admin/team/{id}")) @@ -653,33 +613,27 @@ async fn update_last_station( Form(form): Form, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; let Some(station) = Station::find_by_id(&db, form.last_station_id).await else { - err!( + er!( session, - "Konnte die letzte Station (ID={}) des Teams mit ID {} nicht bearbeiten, da diese Station nicht existiert.", - form.last_station_id, - team.id + t!("nonexisting_station", id = form.last_station_id) ); - return Redirect::to(&format!("/admin/team/{id}")); }; if !station.is_in_route(&db, &team.route(&db).await).await { - err!( + er!( session, - "Konnte Station {} nicht dem Team {} hinzufügen, weil dieses Team bei Route {} und nicht bei Route {} mitläuft.", - station.name, - team.name, - team.route(&db).await.name, - team.name + t!( + "last_station_not_edited_not_on_route", + station = station.name, + team = team.name, + route = team.route(&db).await.name + ) ); return Redirect::to(&format!("/admin/team/{id}")); @@ -687,11 +641,13 @@ async fn update_last_station( team.update_last_station(&db, &station).await; - succ!( + suc!( session, - "Letzte Station des Teams {} ist ab sofort {}", - team.name, - station.name + t!( + "changed_last_station", + team = team.name, + station = station.name + ) ); Redirect::to(&format!("/admin/team/{id}")) @@ -703,21 +659,13 @@ async fn update_amount_people_reset( axum::extract::Path(id): axum::extract::Path, ) -> impl IntoResponse { let Some(team) = Team::find_by_id(&db, id).await else { - err!( - session, - "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" - ); - + er!(session, t!("nonexisting_team", id = id)); return Redirect::to("/admin/team"); }; team.update_amount_people_reset(&db).await; - succ!( - session, - "Anzahl an Mitglieder für das Team '{}' wurden erfolgreich bearbeitet!", - team.name - ); + suc!(session, t!("amount_teammembers_edited", team = team.name)); Redirect::to(&format!("/admin/team/{id}")) } @@ -728,15 +676,15 @@ async fn lost(State(db): State>, session: Session) -> Markup { let content = html! { h1 { a href="/admin/team" { "↩️" } - "Teams: Letzter Kontakt" + (t!("last_contact_team")) } div class="overflow-auto" { table { thead { tr { - td { "Gruppe" } - td { "Uhrzeit" } - td { "Station" } + td { (t!("team")) } + td { (t!("time")) } + td { (t!("station")) } } } tbody { @@ -751,7 +699,7 @@ async fn lost(State(db): State>, session: Session) -> Markup { @if let Some(time) = lost.local_last_contact() { (time) }@else{ - "Noch nicht gesehen" + (t!("not_yet_seen")) } } td { @@ -760,7 +708,7 @@ async fn lost(State(db): State>, session: Session) -> Markup { (station.name) } }@else{ - "Noch nicht gesehen" + (t!("not_yet_seen")) } } } @@ -780,10 +728,10 @@ async fn index(State(db): State>, session: Session) -> Markup { let content = html! { h1 { a href="/admin" { "↩️" } - "Teams" + (t!("teams")) } article { - em { "Teams " } + em { (t!("teams")) } "sind eine Menge an Personen, die verschiedene " a href="/admin/station" { "Stationen" } " ablaufen. Welche Stationen, entscheidet sich je nachdem, welcher " @@ -792,46 +740,47 @@ async fn index(State(db): State>, session: Session) -> Markup { } @if teams.is_empty() { article class="warning" { - "Es gibt noch keine Teams. " + (t!("no_teams")) @if !routes.is_empty() { - "Das kannst du hier ändern ⤵️" + (t!("change_that_below")) } } } article { - h2 { "Neues Team" } + h2 { (t!("new_team")) } @if routes.is_empty() { article class="error" { - (PreEscaped("Bevor du ein Team erstellen kannst, musst du zumindest eine Route erstellen, die das Team gehen kann → ")) + (t!("route_needed_before_creating_teams")) + (PreEscaped(" → ")) a role="button" href="/admin/route" { - "Route erstellen" + (t!("create_route")) } } } @else { form action="/admin/team" method="post" { @if routes.len() == 1 { fieldset role="group" { - input type="text" name="name" placeholder="Teamnamen" required; + input type="text" name="name" placeholder=(t!("teamname")) required; input type="hidden" name="route_id" value=(routes[0].id) ; input type="submit" value="Neues Team"; } } @else { - input type="text" name="name" placeholder="Teamnamen" required; - select name="route_id" aria-label="Route auswählen" required { + input type="text" name="name" placeholder=(t!("teamname")) required; + select name="route_id" aria-label=(t!("select_route")) required { @for route in &routes { option value=(route.id) { (route.name) } } } - input type="submit" value="Neues Team"; + input type="submit" value=(t!("new_team")); } } } } a href="/admin/team/lost" { button class="outline" { - "Hab ich eine Gruppe verloren? 😳" + (t!("have_i_lost_groups")) } } @for route in &routes { @@ -843,7 +792,7 @@ async fn index(State(db): State>, session: Session) -> Markup { (team.name) } a href=(format!("/admin/team/{}/delete", team.id)) - onclick="return confirm('Bist du sicher, dass das Team gelöscht werden soll? Das kann _NICHT_ mehr rückgängig gemacht werden.');" { + onclick=(format!("return confirm('{}');", t!("confirm_delete_team"))) { "🗑️" } } diff --git a/src/admin/user/web.rs b/src/admin/user/web.rs index fc1771f..2d4d334 100644 --- a/src/admin/user/web.rs +++ b/src/admin/user/web.rs @@ -27,7 +27,7 @@ async fn create( id } Err(e) => { - er!(session, t!("user_create_err", err = e)); + er!(session, t!("user_create_error", name = form.name, err = e)); return Redirect::to("/admin/user"); } @@ -48,12 +48,12 @@ async fn delete( }; match user.delete(&db).await { - Ok(()) => suc!(session, t!("user_deleted", user = user.name)), + Ok(()) => suc!(session, t!("user_deleted", name = user.name)), Err(e) => er!( session, t!( "user_delete_error_already_in_use", - user = user.name, + name = user.name, err = e ) ), diff --git a/src/lib.rs b/src/lib.rs index 8439237..addeba4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,14 +48,6 @@ pub fn url() -> String { env::var("URL").unwrap() } -pub(crate) fn pl(amount: usize, single: &str, append: &str) -> String { - if amount == 1 { - single.into() - } else { - format!("{single}{append}") - } -} - #[macro_export] macro_rules! err { ($session:expr, $fmt:expr $(, $arg:expr)*) => { @@ -201,7 +193,7 @@ async fn set_pw( if correct_code != code { er!( session, - t!("cant_updaet_pw_with_wrong_code", user = user.name) + t!("cant_update_pw_with_wrong_code", user = user.name) ); return Err(Redirect::to("/")); } diff --git a/src/station.rs b/src/station.rs index 16d905e..8ca76cd 100644 --- a/src/station.rs +++ b/src/station.rs @@ -138,7 +138,7 @@ async fn view( @if station.ready { (t!("station_not_yet_ready")) } @else { - button { (t!("station_ready")) } + button { (t!("button_station_ready")) } } } } @@ -512,7 +512,7 @@ async fn team_finished( }; match station.team_finished(&db, &team).await { - Ok(()) => suc!(session, t!("team_added_to_finished")), + Ok(()) => suc!(session, t!("team_added_to_finished", team = team.name)), Err(e) => err!(session, "{e}"), } @@ -538,7 +538,7 @@ async fn remove_left( }; match station.remove_team_left(&db, &team).await { - Ok(()) => suc!(session, t!("team_removed_from_finished")), + Ok(()) => suc!(session, t!("team_removed_from_finished", team = team.name)), Err(e) => err!(session, "{e}"), }