diff --git a/.gitignore b/.gitignore index 174e213..b8c3764 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target .env -links.db +links.db* launch.json settings.json links.session.sql diff --git a/Cargo.lock b/Cargo.lock index e470088..3129fa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "actix-codec" version = "0.3.0" @@ -412,6 +422,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "arc-swap" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d7d63395147b81a9e570bcc6243aaf71c017bd666d4909cfef0085bdda8d73" + [[package]] name = "argonautica" version = "0.2.0" @@ -1037,6 +1053,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "dotenv" version = "0.15.0" @@ -1126,6 +1148,99 @@ dependencies = [ "miniz_oxide 0.4.3", ] +[[package]] +name = "fluent" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960ac6317b829b94c67f9a774e8b56db388405e174855a5a84d4b461ff85b281" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3cc2d1c59a0daaa93bb346db97e1ebad1067c5ffedc1af8b937a9d8caa6a77" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "ouroboros", + "rustc-hash", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784f660373ea898f712a7e67b43f35bf79608d46112747c29767d087611d716b" + +[[package]] +name = "fluent-template-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3051f88dd918b30a994177acc8f3b8b0b399c98ca5aa2ab985e79070a8841592" +dependencies = [ + "flume", + "ignore", + "once_cell", + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn", + "unic-langid", +] + +[[package]] +name = "fluent-templates" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fa6b2186b959236019d67fb839f036c83a799edd4389c505678ca1b8d41e9ed" +dependencies = [ + "arc-swap", + "fluent", + "fluent-bundle", + "fluent-langneg", + "fluent-syntax", + "fluent-template-macros", + "flume", + "heck", + "ignore", + "lazy_static", + "log", + "once_cell", + "serde_json", + "snafu", + "tera", + "unic-langid", +] + +[[package]] +name = "flume" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531a685ab99b8f60a271b44d5dd1a76e55124a8c9fa0407b7a8e9cd172d5b588" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project 1.0.4", + "spinning_top", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1327,8 +1442,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1589,6 +1706,26 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "intl-memoizer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf" +dependencies = [ + "tinystr", + "unic-langid", +] + [[package]] name = "iovec" version = "0.1.4" @@ -1848,6 +1985,15 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "nanorand" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1378b66f7c93a1c0f8464a19bf47df8795083842e5090f4b7305973d5a22d0" +dependencies = [ + "getrandom 0.2.2", +] + [[package]] name = "net2" version = "0.2.37" @@ -1957,6 +2103,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "ouroboros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d5c203fe8d786d9d7bec8203cbbff3eb2cf8410c0d70cfd05b3d5f5d545da" +dependencies = [ + "ouroboros_macro", + "stable_deref_trait", +] + +[[package]] +name = "ouroboros_macro" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129943a960e6a08c7e70ca5a09f113c273fe7f10ae8420992c78293e3dffdf65" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn", +] + [[package]] name = "parking_lot" version = "0.11.1" @@ -2145,6 +2314,30 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn", + "version_check 0.9.2", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "version_check 0.9.2", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -2187,6 +2380,8 @@ dependencies = [ "chrono", "clap", "dotenv", + "fluent-langneg", + "fluent-templates", "image", "qrcode", "rand 0.8.3", @@ -2566,6 +2761,12 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.2.3" @@ -2820,6 +3021,27 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +[[package]] +name = "snafu" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" +dependencies = [ + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn", +] + [[package]] name = "socket2" version = "0.3.19" @@ -2837,6 +3059,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spinning_top" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e529d73e80d64b5f2631f9035113347c578a1c9c7774b83a2b880788459ab36" +dependencies = [ + "lock_api", +] + [[package]] name = "sqlformat" version = "0.1.6" @@ -2941,6 +3172,12 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "standback" version = "0.2.14" @@ -3220,6 +3457,12 @@ dependencies = [ "syn", ] +[[package]] +name = "tinystr" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1" + [[package]] name = "tinyvec" version = "1.1.1" @@ -3365,6 +3608,15 @@ dependencies = [ "trust-dns-proto", ] +[[package]] +name = "type-map" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" +dependencies = [ + "rustc-hash", +] + [[package]] name = "typenum" version = "1.12.0" @@ -3398,6 +3650,49 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" +[[package]] +name = "unic-langid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73328fcd730a030bdb19ddf23e192187a6b01cd98be6d3140622a89129459ce5" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a4a8eeaf0494862c1404c95ec2f4c33a2acff5076f64314b465e3ddae1b934d" +dependencies = [ + "tinystr", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f980d6d87e8805f2836d64b4138cc95aa7986fa63b1f51f67d5fbff64dd6e5" +dependencies = [ + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29396ffd97e27574c3e01368b1a64267d3064969e4848e2e130ff668be9daa9f" +dependencies = [ + "proc-macro-hack", + "quote 1.0.8", + "syn", + "unic-langid-impl", +] + [[package]] name = "unic-segment" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 2757899..9f9640a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,8 @@ image = "0.23" rand="0.8" rpassword = "5.0" clap = "2.33" +fluent-templates = { version = "0.6", features = ["tera"] } +fluent-langneg ="0.13" [build-dependencies] actix-web-static-files = "3.0" diff --git a/locales/de/main.ftl b/locales/de/main.ftl new file mode 100644 index 0000000..59aa6dc --- /dev/null +++ b/locales/de/main.ftl @@ -0,0 +1,36 @@ +list-links = Link Liste +add-link = Link hinzufügen +invite-user = Benutzer einladen +list-users = Liste der Benutzer +welcome-user = Herzlich willkommen {$username} +logout = Abmelden +login = Login + +not-found = Dieser Link existiert nicht, oder wurde gelöscht. + +edit-link-headline = Zu editierender Link: {$linktitle} +edit-link = Link Editieren +link-description = Beschreibung +link-target = Link Ziel +link-code = Link Code +shortlink = Shortlink +qr-code = QR-code + +danger-zone = Achtung! +danger-zone-text = Verändern Sie den Code von bereits veröffentlichten Links nicht. Sollte es dennoch geschehen werden veröffentlichte links unbenutzbar. Wird das Linkziel verändert, so zeigen auch die bereits veröffentlichten Links auf das neue Ziel. + +save-edits = Speichere die Veränderungen +delete-link = Diesen Link löschen + +edit-user-headline = Benutzereinstellungen von: {$username} +username = Benutzername +email = Email +password = Passwort +password-placeholder = Leer lassen um das Passwort nicht zu ändern +save-user = Benutzer speichern +edit-user = Benutzer editieren +make-user-admin = Zum Administrator befördern +make-user-regular = Zurückstufen zum normalen Nutzer + +userid = Benutzernummer +statistics = Statistik \ No newline at end of file diff --git a/locales/en/main.ftl b/locales/en/main.ftl new file mode 100644 index 0000000..713ab87 --- /dev/null +++ b/locales/en/main.ftl @@ -0,0 +1,36 @@ +list-links = List of existing links +add-link = Add a new link +invite-user = Invite a new user +list-users = List of existing users +welcome-user = Welcome {$username} +logout = Logout +login = Login + +not-found = This Link has not been found or has been deleted + +edit-link-headline = Edit link: {$linktitle} +edit-link = Edit link +link-description = Description +link-target = Link target +link-code = Link code +shortlink = Shortlink + +danger-zone = Danger Zone! +danger-zone-text = Do not change the code of links that are published. If you do so the published links will become invalid! If you change the target the published links will point to the new target. + +save-edits = Save edits +delete-link = Delete this link + +user-headline = User Settings of: {$username} +edit-user-headline = Change Settings of: {$username} +username = Username +email = Email +password = Password +password-placeholder = Leave this empty to keep the current password +save-user = Save this user +edit-user = Edit this user +make-user-admin = Promote to admin +make-user-regular = Demote to regular + +userid = User ID +statistics = Statistics \ No newline at end of file diff --git a/migrations/20210318172317_initialmigration.up.sql b/migrations/20210318172317_initialmigration.sql similarity index 100% rename from migrations/20210318172317_initialmigration.up.sql rename to migrations/20210318172317_initialmigration.sql diff --git a/migrations/20210330103013_addinglanguage.sql b/migrations/20210330103013_addinglanguage.sql new file mode 100644 index 0000000..b4adf6c --- /dev/null +++ b/migrations/20210330103013_addinglanguage.sql @@ -0,0 +1,5 @@ +-- Add migration script here +ALTER TABLE + users +ADD + COLUMN language Text NOT NULL DEFAULT "en"; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9171ffe..b07076e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ use std::{fmt::Display, path::PathBuf, str::FromStr}; use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{web, App, HttpResponse, HttpServer}; +use fluent_templates::{static_loader, FluentLoader}; use qrcode::types::QrError; use sqlx::{Pool, Sqlite}; use tera::Tera; @@ -188,9 +189,20 @@ impl ServerConfig { } include!(concat!(env!("OUT_DIR"), "/generated.rs")); + +static_loader! { + static LOCALES = { + locales: "./locales", + fallback_language: "en", + }; +} + fn build_tera() -> Tera { let mut tera = Tera::default(); + // Add translation support + tera.register_function("fluent", FluentLoader::new(&*LOCALES)); + tera.add_raw_templates(vec![ ("admin.html", include_str!("../templates/admin.html")), ("base.html", include_str!("../templates/base.html")), @@ -311,7 +323,11 @@ async fn webservice(server_config: ServerConfig) -> std::io::Result<()> { web::post().to(views::process_edit_profile), ), ) - .route("/set_admin/{user_id}", web::get().to(views::toggle_admin)), + .route("/set_admin/{user_id}", web::get().to(views::toggle_admin)) + .route( + "/set_language/{language}", + web::get().to(views::set_language), + ), ) .service( web::scope("/delete").service( diff --git a/src/models.rs b/src/models.rs index 43605e0..ba7bbb4 100644 --- a/src/models.rs +++ b/src/models.rs @@ -11,6 +11,7 @@ pub struct User { pub email: String, pub password: String, pub role: i64, + pub language: String, } impl User { @@ -62,6 +63,7 @@ impl User { .await?; Ok(()) } + pub(crate) async fn toggle_admin( self, server_config: &ServerConfig, @@ -73,6 +75,21 @@ impl User { Ok(()) } + pub(crate) async fn set_language( + self, + server_config: &ServerConfig, + new_language: &str, + ) -> Result<(), ServerError> { + sqlx::query!( + "UPDATE users SET language = ? where id = ?", + new_language, + self.id + ) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } + pub(crate) async fn count_admins(server_config: &ServerConfig) -> Result { let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2") .fetch_one(&server_config.db_pool) diff --git a/src/queries.rs b/src/queries.rs index 8575845..c30c348 100644 --- a/src/queries.rs +++ b/src/queries.rs @@ -81,6 +81,7 @@ pub(crate) async fn list_all_allowed( users.username as usern, users.email as uemail, users.role as urole, + users.language as ulang, count(clicks.id) as counter from links @@ -107,6 +108,7 @@ pub(crate) async fn list_all_allowed( email: v.get("uemail"), password: "invalid".to_owned(), role: v.get("urole"), + language: v.get("ulang"), }, clicks: Count { number: v.get("counter"), /* count is never None */ @@ -244,6 +246,7 @@ pub(crate) async fn update_user( email: data.email.clone(), password, role: unmodified_user.role, + language: unmodified_user.language, }; new_user.update_user(server_config).await?; let changed_user = User::get_user(uid, server_config).await?; @@ -302,6 +305,26 @@ pub(crate) async fn toggle_admin( } } +pub(crate) async fn set_language( + id: &Identity, + lang_code: &str, + server_config: &ServerConfig, +) -> Result<(), ServerError> { + match lang_code { + "de" | "en" => match authenticate(id, server_config).await? { + Role::Admin { user } | Role::Regular { user } => { + user.set_language(server_config, lang_code).await + } + Role::Disabled | Role::NotAuthenticated => { + Err(ServerError::User("Not Allowed".to_owned())) + } + }, + _ => Err(ServerError::User( + "This language is not supported!".to_owned(), + )), + } +} + /// Get one link if permissions are accordingly. pub(crate) async fn get_link( id: &Identity, diff --git a/src/views.rs b/src/views.rs index d64eaff..e0b0573 100644 --- a/src/views.rs +++ b/src/views.rs @@ -3,9 +3,14 @@ use std::time::SystemTime; use actix_identity::Identity; use actix_web::{ http::header::{CacheControl, CacheDirective, ContentType, Expires}, - web, HttpResponse, + web, HttpRequest, HttpResponse, }; use argonautica::Verifier; +use fluent_langneg::{ + convert_vec_str_to_langids_lossy, negotiate_languages, parse_accepted_languages, + NegotiationStrategy, +}; +use fluent_templates::LanguageIdentifier; use image::{DynamicImage, ImageOutputFormat, Luma}; use qrcode::{render::svg, QrCode}; use tera::{Context, Tera}; @@ -27,6 +32,35 @@ fn redirect_builder(target: &str) -> HttpResponse { .body(format!("Redirect to {}", target)) } +fn detect_language(request: &HttpRequest) -> Result { + let requested = parse_accepted_languages( + request + .headers() + .get(actix_web::http::header::ACCEPT_LANGUAGE) + .ok_or_else(|| ServerError::User("Failed to get Accept_Language".to_owned()))? + .to_str() + .map_err(|_| { + ServerError::User("Failed to convert Accept_language to str".to_owned()) + })?, + ); + let available = convert_vec_str_to_langids_lossy(&["de", "en"]); + let default: LanguageIdentifier = "en" + .parse() + .map_err(|_| ServerError::User("Failed to parse a langid.".to_owned()))?; + + let supported = negotiate_languages( + &requested, + &available, + Some(&default), + NegotiationStrategy::Filtering, + ); + let languagecode = supported + .get(0) + .map_or("en".to_string(), std::string::ToString::to_string); + println!("Detected the language: {}", &languagecode); + Ok(languagecode) +} + /// Show the list of all available links if a user is authenticated pub(crate) async fn index( tera: web::Data, @@ -248,12 +282,26 @@ pub(crate) async fn toggle_admin( ))) } +pub(crate) async fn set_language( + data: web::Path, + config: web::Data, + id: Identity, +) -> Result { + queries::set_language(&id, &data.0, &config).await?; + Ok(redirect_builder("/admin/index/")) +} + pub(crate) async fn login( tera: web::Data, id: Identity, + config: web::Data, + req: HttpRequest, ) -> Result { + let language_code = detect_language(&req)?; + slog_info!(config.log, "Detected languagecode: {}", &language_code); let mut data = Context::new(); data.insert("title", "Login"); + data.insert("language", &language_code); if let Some(_id) = id.identity() { return Ok(redirect_builder("/admin/index/")); @@ -304,6 +352,7 @@ pub(crate) async fn redirect( tera: web::Data, config: web::Data, data: web::Path, + req: HttpRequest, ) -> Result { slog_info!(config.log, "Redirecting to {:?}", data); let link = queries::get_link_simple(&data.0, &config).await; @@ -323,6 +372,8 @@ pub(crate) async fn redirect( ); let mut data = Context::new(); data.insert("title", "Wurde gel\u{f6}scht"); + let language = detect_language(&req)?; + data.insert("language", &language); let rendered = tera.render("not_found.html", &data)?; Ok(HttpResponse::NotFound().body(rendered)) } diff --git a/templates/admin.html b/templates/admin.html index 649b3cd..8f6bb65 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -11,14 +11,19 @@
{% block admin %} diff --git a/templates/edit_link.html b/templates/edit_link.html index b2f95b2..cfa1af7 100644 --- a/templates/edit_link.html +++ b/templates/edit_link.html @@ -2,26 +2,26 @@ {% block admin %}
-

Link Editieren: {{ link.title }}

+

{{ fluent(key="edit-link-headline", lang=user.language, linktitle=link.title) }}

- +
- +
- +
-

Achtung!

-

Werden schon veröffentlichte Links gelöscht oder editiert sind die Links z.B. aus einem Buch - nicht mehr gültig! UNBEDINGT VERMEIDEN!

- - Delete +

{{ fluent(key="danger-zone", lang=user.language) }}

+

{{ fluent(key="danger-zone-text", lang=user.language) }}

+ + {{ fluent(key="delete-link", lang=user.language) + }}
diff --git a/templates/edit_profile.html b/templates/edit_profile.html index 60e5861..069867a 100644 --- a/templates/edit_profile.html +++ b/templates/edit_profile.html @@ -2,21 +2,27 @@ {% block admin %}
-

Profil von {{user.username}}

+

{{ fluent(key="edit-user-headline", lang=user.language, username=user.username) }} +

- +
- +
- - + +
- +

 

diff --git a/templates/index.html b/templates/index.html index e81308b..7f7c276 100644 --- a/templates/index.html +++ b/templates/index.html @@ -11,16 +11,20 @@ - Kürzel + {{ fluent(key="link-code", lang=user.language) + }} - Ziellink + {{ fluent(key="link-target", lang=user.language) + }} - Benutzername + {{ fluent(key="username", lang=user.language) + }} - Statistik + {{ fluent(key="statistics", lang=user.language) + }} {% for links_user in links_per_users %} diff --git a/templates/index_users.html b/templates/index_users.html index 4931148..f65b4e2 100644 --- a/templates/index_users.html +++ b/templates/index_users.html @@ -11,13 +11,16 @@ - Kürzel + {{ fluent(key="userid", lang=user.language) + }} - Emailadresse + {{ fluent(key="email", lang=user.language) + }} - Benutzername + {{ fluent(key="username", lang=user.language) + }} {% for user in users %} diff --git a/templates/login.html b/templates/login.html index 6bcc718..16681c7 100644 --- a/templates/login.html +++ b/templates/login.html @@ -4,14 +4,16 @@
- +
- +
- +

 

diff --git a/templates/not_found.html b/templates/not_found.html index e4cd887..6502453 100644 --- a/templates/not_found.html +++ b/templates/not_found.html @@ -2,7 +2,7 @@ {% block content %}
-

This Link has not been found or has been deleted

+

{{ fluent(key="not-found", lang=language) }}

 

{% endblock %} \ No newline at end of file diff --git a/templates/signup.html b/templates/signup.html index e41beb1..8a30413 100644 --- a/templates/signup.html +++ b/templates/signup.html @@ -4,18 +4,22 @@
- +
- +
- +
- +

 

diff --git a/templates/submission.html b/templates/submission.html index aeda5f8..b60da0d 100644 --- a/templates/submission.html +++ b/templates/submission.html @@ -4,15 +4,18 @@
- +
- +
- +
diff --git a/templates/view_link.html b/templates/view_link.html index 80fef2d..6e68661 100644 --- a/templates/view_link.html +++ b/templates/view_link.html @@ -5,24 +5,29 @@

{{ link.title }}

- + - + - + - + - +
Beschreibung:{{ fluent(key="link-description", lang=user.language) + }}: {{ link.title }}
Code:{{ fluent(key="link-code", lang=user.language) + }}: {{ link.code }}
Kurzlink:{{ fluent(key="shortlink", lang=user.language) + }}: {{ protocol }}://{{ host }}/{{ link.code }}
Ziel:{{ fluent(key="link-target", lang=user.language) + }}: {{ link.target }}
QR-Code{{ fluent(key="qr-code", lang=user.language) + }} {{ qr | trim_start_matches(pat= '.*?>') @@ -33,7 +38,8 @@
{% if user.role == 2 or user.id == link.author %} {% endif %}
diff --git a/templates/view_profile.html b/templates/view_profile.html index 22de951..2dd026c 100644 --- a/templates/view_profile.html +++ b/templates/view_profile.html @@ -2,31 +2,39 @@ {% block admin %}
-

Profil von {{viewed_user.username}}

+

{{ fluent(key="user-headline", lang=user.language, username=user.username) }}

- +
- +
{% if user.role == 2 or user.id == viewed_user.id %}
- +
{% endif %} {% if user.role == 2 or user.id == viewed_user.id %}
- Editieren + {{ fluent(key="edit-user", lang=user.language) + }} {% if user.role == 2 and viewed_user.role == 1 %} - Zum Admin machen + {{ fluent(key="make-user-admin", + lang=user.language) + }} {% endif %} - {% if user.role == 2 and viewed_user.role == 2 %} - Zum Normalo machen + {% if user.role == 2 and viewed_user.role == 2 and not user.id == viewed_user.id %} + {{ fluent(key="make-user-regular", + lang=user.language) + }} {% endif %}
{% endif %}