Merge pull request #6 from enaut/WIP--translations
Make the page translatable
This commit is contained in:
commit
053992e30c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
/target
|
/target
|
||||||
.env
|
.env
|
||||||
links.db
|
links.db*
|
||||||
launch.json
|
launch.json
|
||||||
settings.json
|
settings.json
|
||||||
links.session.sql
|
links.session.sql
|
||||||
|
295
Cargo.lock
generated
295
Cargo.lock
generated
@ -1,5 +1,15 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# 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]]
|
[[package]]
|
||||||
name = "actix-codec"
|
name = "actix-codec"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -412,6 +422,12 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"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]]
|
[[package]]
|
||||||
name = "argonautica"
|
name = "argonautica"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1037,6 +1053,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenv"
|
name = "dotenv"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
@ -1126,6 +1148,99 @@ dependencies = [
|
|||||||
"miniz_oxide 0.4.3",
|
"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]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -1327,8 +1442,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1589,6 +1706,26 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"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]]
|
[[package]]
|
||||||
name = "iovec"
|
name = "iovec"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@ -1848,6 +1985,15 @@ dependencies = [
|
|||||||
"ws2_32-sys",
|
"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]]
|
[[package]]
|
||||||
name = "net2"
|
name = "net2"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
@ -1957,6 +2103,29 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
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]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@ -2145,6 +2314,30 @@ version = "0.2.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
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]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.19"
|
version = "0.5.19"
|
||||||
@ -2187,6 +2380,8 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"fluent-langneg",
|
||||||
|
"fluent-templates",
|
||||||
"image",
|
"image",
|
||||||
"qrcode",
|
"qrcode",
|
||||||
"rand 0.8.3",
|
"rand 0.8.3",
|
||||||
@ -2566,6 +2761,12 @@ version = "0.1.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
|
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -2820,6 +3021,27 @@ version = "1.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
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]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.3.19"
|
version = "0.3.19"
|
||||||
@ -2837,6 +3059,15 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
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]]
|
[[package]]
|
||||||
name = "sqlformat"
|
name = "sqlformat"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@ -2941,6 +3172,12 @@ dependencies = [
|
|||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "standback"
|
name = "standback"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -3220,6 +3457,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinystr"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -3365,6 +3608,15 @@ dependencies = [
|
|||||||
"trust-dns-proto",
|
"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]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.12.0"
|
version = "1.12.0"
|
||||||
@ -3398,6 +3650,49 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
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]]
|
[[package]]
|
||||||
name = "unic-segment"
|
name = "unic-segment"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -33,6 +33,8 @@ image = "0.23"
|
|||||||
rand="0.8"
|
rand="0.8"
|
||||||
rpassword = "5.0"
|
rpassword = "5.0"
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
|
fluent-templates = { version = "0.6", features = ["tera"] }
|
||||||
|
fluent-langneg ="0.13"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
actix-web-static-files = "3.0"
|
actix-web-static-files = "3.0"
|
||||||
|
36
locales/de/main.ftl
Normal file
36
locales/de/main.ftl
Normal file
@ -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
|
36
locales/en/main.ftl
Normal file
36
locales/en/main.ftl
Normal file
@ -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
|
5
migrations/20210330103013_addinglanguage.sql
Normal file
5
migrations/20210330103013_addinglanguage.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
-- Add migration script here
|
||||||
|
ALTER TABLE
|
||||||
|
users
|
||||||
|
ADD
|
||||||
|
COLUMN language Text NOT NULL DEFAULT "en";
|
18
src/main.rs
18
src/main.rs
@ -25,6 +25,7 @@ use std::{fmt::Display, path::PathBuf, str::FromStr};
|
|||||||
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
||||||
use actix_web::{web, App, HttpResponse, HttpServer};
|
use actix_web::{web, App, HttpResponse, HttpServer};
|
||||||
|
|
||||||
|
use fluent_templates::{static_loader, FluentLoader};
|
||||||
use qrcode::types::QrError;
|
use qrcode::types::QrError;
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
@ -188,9 +189,20 @@ impl ServerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||||
|
|
||||||
|
static_loader! {
|
||||||
|
static LOCALES = {
|
||||||
|
locales: "./locales",
|
||||||
|
fallback_language: "en",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn build_tera() -> Tera {
|
fn build_tera() -> Tera {
|
||||||
let mut tera = Tera::default();
|
let mut tera = Tera::default();
|
||||||
|
|
||||||
|
// Add translation support
|
||||||
|
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
|
||||||
|
|
||||||
tera.add_raw_templates(vec![
|
tera.add_raw_templates(vec![
|
||||||
("admin.html", include_str!("../templates/admin.html")),
|
("admin.html", include_str!("../templates/admin.html")),
|
||||||
("base.html", include_str!("../templates/base.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),
|
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(
|
.service(
|
||||||
web::scope("/delete").service(
|
web::scope("/delete").service(
|
||||||
|
@ -11,6 +11,7 @@ pub struct User {
|
|||||||
pub email: String,
|
pub email: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub role: i64,
|
pub role: i64,
|
||||||
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
@ -62,6 +63,7 @@ impl User {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn toggle_admin(
|
pub(crate) async fn toggle_admin(
|
||||||
self,
|
self,
|
||||||
server_config: &ServerConfig,
|
server_config: &ServerConfig,
|
||||||
@ -73,6 +75,21 @@ impl User {
|
|||||||
Ok(())
|
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<Count, ServerError> {
|
pub(crate) async fn count_admins(server_config: &ServerConfig) -> Result<Count, ServerError> {
|
||||||
let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2")
|
let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2")
|
||||||
.fetch_one(&server_config.db_pool)
|
.fetch_one(&server_config.db_pool)
|
||||||
|
@ -81,6 +81,7 @@ pub(crate) async fn list_all_allowed(
|
|||||||
users.username as usern,
|
users.username as usern,
|
||||||
users.email as uemail,
|
users.email as uemail,
|
||||||
users.role as urole,
|
users.role as urole,
|
||||||
|
users.language as ulang,
|
||||||
count(clicks.id) as counter
|
count(clicks.id) as counter
|
||||||
from
|
from
|
||||||
links
|
links
|
||||||
@ -107,6 +108,7 @@ pub(crate) async fn list_all_allowed(
|
|||||||
email: v.get("uemail"),
|
email: v.get("uemail"),
|
||||||
password: "invalid".to_owned(),
|
password: "invalid".to_owned(),
|
||||||
role: v.get("urole"),
|
role: v.get("urole"),
|
||||||
|
language: v.get("ulang"),
|
||||||
},
|
},
|
||||||
clicks: Count {
|
clicks: Count {
|
||||||
number: v.get("counter"), /* count is never None */
|
number: v.get("counter"), /* count is never None */
|
||||||
@ -244,6 +246,7 @@ pub(crate) async fn update_user(
|
|||||||
email: data.email.clone(),
|
email: data.email.clone(),
|
||||||
password,
|
password,
|
||||||
role: unmodified_user.role,
|
role: unmodified_user.role,
|
||||||
|
language: unmodified_user.language,
|
||||||
};
|
};
|
||||||
new_user.update_user(server_config).await?;
|
new_user.update_user(server_config).await?;
|
||||||
let changed_user = User::get_user(uid, 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.
|
/// Get one link if permissions are accordingly.
|
||||||
pub(crate) async fn get_link(
|
pub(crate) async fn get_link(
|
||||||
id: &Identity,
|
id: &Identity,
|
||||||
|
53
src/views.rs
53
src/views.rs
@ -3,9 +3,14 @@ use std::time::SystemTime;
|
|||||||
use actix_identity::Identity;
|
use actix_identity::Identity;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
http::header::{CacheControl, CacheDirective, ContentType, Expires},
|
http::header::{CacheControl, CacheDirective, ContentType, Expires},
|
||||||
web, HttpResponse,
|
web, HttpRequest, HttpResponse,
|
||||||
};
|
};
|
||||||
use argonautica::Verifier;
|
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 image::{DynamicImage, ImageOutputFormat, Luma};
|
||||||
use qrcode::{render::svg, QrCode};
|
use qrcode::{render::svg, QrCode};
|
||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
@ -27,6 +32,35 @@ fn redirect_builder(target: &str) -> HttpResponse {
|
|||||||
.body(format!("Redirect to {}", target))
|
.body(format!("Redirect to {}", target))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn detect_language(request: &HttpRequest) -> Result<String, ServerError> {
|
||||||
|
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
|
/// Show the list of all available links if a user is authenticated
|
||||||
pub(crate) async fn index(
|
pub(crate) async fn index(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
@ -248,12 +282,26 @@ pub(crate) async fn toggle_admin(
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn set_language(
|
||||||
|
data: web::Path<String>,
|
||||||
|
config: web::Data<crate::ServerConfig>,
|
||||||
|
id: Identity,
|
||||||
|
) -> Result<HttpResponse, ServerError> {
|
||||||
|
queries::set_language(&id, &data.0, &config).await?;
|
||||||
|
Ok(redirect_builder("/admin/index/"))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn login(
|
pub(crate) async fn login(
|
||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
|
config: web::Data<crate::ServerConfig>,
|
||||||
|
req: HttpRequest,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
|
let language_code = detect_language(&req)?;
|
||||||
|
slog_info!(config.log, "Detected languagecode: {}", &language_code);
|
||||||
let mut data = Context::new();
|
let mut data = Context::new();
|
||||||
data.insert("title", "Login");
|
data.insert("title", "Login");
|
||||||
|
data.insert("language", &language_code);
|
||||||
|
|
||||||
if let Some(_id) = id.identity() {
|
if let Some(_id) = id.identity() {
|
||||||
return Ok(redirect_builder("/admin/index/"));
|
return Ok(redirect_builder("/admin/index/"));
|
||||||
@ -304,6 +352,7 @@ pub(crate) async fn redirect(
|
|||||||
tera: web::Data<Tera>,
|
tera: web::Data<Tera>,
|
||||||
config: web::Data<crate::ServerConfig>,
|
config: web::Data<crate::ServerConfig>,
|
||||||
data: web::Path<String>,
|
data: web::Path<String>,
|
||||||
|
req: HttpRequest,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
slog_info!(config.log, "Redirecting to {:?}", data);
|
slog_info!(config.log, "Redirecting to {:?}", data);
|
||||||
let link = queries::get_link_simple(&data.0, &config).await;
|
let link = queries::get_link_simple(&data.0, &config).await;
|
||||||
@ -323,6 +372,8 @@ pub(crate) async fn redirect(
|
|||||||
);
|
);
|
||||||
let mut data = Context::new();
|
let mut data = Context::new();
|
||||||
data.insert("title", "Wurde gel\u{f6}scht");
|
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)?;
|
let rendered = tera.render("not_found.html", &data)?;
|
||||||
Ok(HttpResponse::NotFound().body(rendered))
|
Ok(HttpResponse::NotFound().body(rendered))
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,19 @@
|
|||||||
<div class="admin">
|
<div class="admin">
|
||||||
<nav>
|
<nav>
|
||||||
<ol>
|
<ol>
|
||||||
<li><a href="/admin/index/">Link Liste</a></li>
|
<li><a href="/admin/index/">{{ fluent(key="list-links", lang=user.language) }}</a>
|
||||||
<li><a href="/admin/submit/">Link Hinzufügen</a></li>
|
|
||||||
{% if user.role == 2 %}<li><a href="/admin/signup/">Einladen</a></li>
|
|
||||||
<li><a href="/admin/view/users/">Benutzer</a></li>{% endif %}
|
|
||||||
<li style="float:right"><a href="/admin/logout/">Abmelden</a></li>
|
|
||||||
<li style="float:right">
|
|
||||||
<div class="willkommen">Herzlich willkommen {{ user.username }}</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<li><a href="/admin/submit/">{{ fluent(key="add-link", lang=user.language) }}</a></li>
|
||||||
|
{% if user.role == 2 %}<li><a href="/admin/signup/">{{ fluent(key="invite-user", lang=user.language) }}</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="/admin/view/users/">{{ fluent(key="list-users", lang=user.language) }}</a></li>{% endif %}
|
||||||
|
<li style="float:right"><a href="/admin/logout/">{{ fluent(key="logout", lang=user.language) }}</a></li>
|
||||||
|
<li style="float:right">
|
||||||
|
<div class="willkommen">{{ fluent(key="welcome-user", lang=user.language, username=user.username) }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li style="float:right"><a href="/admin/edit/set_language/en">en</a></li>
|
||||||
|
<li style="float:right"><a href="/admin/edit/set_language/de">de</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
{% block admin %}
|
{% block admin %}
|
||||||
|
@ -2,26 +2,26 @@
|
|||||||
|
|
||||||
{% block admin %}
|
{% block admin %}
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<h1>Link Editieren: {{ link.title }}</h1>
|
<h1>{{ fluent(key="edit-link-headline", lang=user.language, linktitle=link.title) }}</h1>
|
||||||
<form action="" method="POST">
|
<form action="" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="title">Beschreibung:</label>
|
<label for="title">{{ fluent(key="link-description", lang=user.language) }}:</label>
|
||||||
<input type="text" name="title" value="{{ link.title }}">
|
<input type="text" name="title" value="{{ link.title }}">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="target">Ziel:</label>
|
<label for="target">{{ fluent(key="link-target", lang=user.language) }}:</label>
|
||||||
<input type="text" name="target" value="{{link.target}}">
|
<input type="text" name="target" value="{{link.target}}">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="code">Code:</label>
|
<label for="code">{{ fluent(key="link-code", lang=user.language) }}:</label>
|
||||||
<input type="text" name="code" value="{{link.code}}">
|
<input type="text" name="code" value="{{link.code}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="actions danger">
|
<div class="actions danger">
|
||||||
<h2>Achtung!</h2>
|
<h2>{{ fluent(key="danger-zone", lang=user.language) }}</h2>
|
||||||
<h3>Werden schon veröffentlichte Links gelöscht oder editiert sind die Links z.B. aus einem Buch
|
<h3>{{ fluent(key="danger-zone-text", lang=user.language) }}</h3>
|
||||||
nicht mehr gültig! UNBEDINGT VERMEIDEN!</h3>
|
<input type="submit" value='{{ fluent(key="save-edits", lang=user.language) }}'>
|
||||||
<input type="submit" value="Speichern">
|
<a class="button" href="/admin/delete/link/{{link.code}}">{{ fluent(key="delete-link", lang=user.language)
|
||||||
<a class="button" href="/admin/delete/link/{{link.code}}">Delete</a>
|
}}</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,21 +2,27 @@
|
|||||||
|
|
||||||
{% block admin %}
|
{% block admin %}
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<h1>Profil von {{user.username}}</h1>
|
<h1>{{ fluent(key="edit-user-headline", lang=user.language, username=user.username) }}
|
||||||
|
</h1>
|
||||||
<form action="" method="POST">
|
<form action="" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="username">Benutzername:</label>
|
<label for="username">{{ fluent(key="username", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="username" value="{{ user.username }}">
|
<input type="text" name="username" value="{{ user.username }}">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="email">E-mail:</label>
|
<label for="email">{{ fluent(key="email", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="email" name="email" value="{{ user.email }}">
|
<input type="email" name="email" value="{{ user.email }}">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort:</label>
|
<label for="password">{{ fluent(key="password", lang=user.language)
|
||||||
<input type="password" name="password" placeholder="Leer lassen um nichts zu ändern">
|
}}:</label>
|
||||||
|
<input type="password" name="password" placeholder='{{ fluent(key="password-placeholder", lang=user.language)
|
||||||
|
}}'>
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" value="Speichern">
|
<input type="submit" value='{{ fluent(key="save-user", lang=user.language)
|
||||||
|
}}'>
|
||||||
</form>
|
</form>
|
||||||
<h2> </h2>
|
<h2> </h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,16 +11,20 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
Kürzel
|
{{ fluent(key="link-code", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Ziellink
|
{{ fluent(key="link-target", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Benutzername
|
{{ fluent(key="username", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Statistik
|
{{ fluent(key="statistics", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for links_user in links_per_users %}
|
{% for links_user in links_per_users %}
|
||||||
|
@ -11,13 +11,16 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
Kürzel
|
{{ fluent(key="userid", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Emailadresse
|
{{ fluent(key="email", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Benutzername
|
{{ fluent(key="username", lang=user.language)
|
||||||
|
}}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
|
@ -4,14 +4,16 @@
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<form action="" method="POST">
|
<form action="" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="username">Benutzername:</label>
|
<label for="username">{{ fluent(key="username", lang=language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="username">
|
<input type="text" name="username">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort:</label>
|
<label for="password">{{ fluent(key="password", lang=language)
|
||||||
|
}}:</label>
|
||||||
<input type="password" name="password">
|
<input type="password" name="password">
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" value="Login">
|
<input type="submit" value='{{ fluent(key="login", lang=language) }}'>
|
||||||
</form>
|
</form>
|
||||||
<h2> </h2>
|
<h2> </h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<h3>This Link has not been found or has been deleted</h3>
|
<h3>{{ fluent(key="not-found", lang=language) }}</h3>
|
||||||
<h2> </h2>
|
<h2> </h2>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -4,18 +4,22 @@
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<form action="" method="POST">
|
<form action="" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="username">Benutzername:</label>
|
<label for="username">{{ fluent(key="username", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="username">
|
<input type="text" name="username">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="email">E-mail:</label>
|
<label for="email">{{ fluent(key="email", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="email" name="email">
|
<input type="email" name="email">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort:</label>
|
<label for="password">{{ fluent(key="password", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="password" name="password">
|
<input type="password" name="password">
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" value="Einladen">
|
<input type="submit" value='{{ fluent(key="invite-user", lang=user.language)
|
||||||
|
}}'>
|
||||||
</form>
|
</form>
|
||||||
<h2> </h2>
|
<h2> </h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,15 +4,18 @@
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<form action="" method="POST">
|
<form action="" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="title">Beschreibung:</label>
|
<label for="title">{{ fluent(key="link-description", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="title">
|
<input type="text" name="title">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="target">Ziel:</label>
|
<label for="target">{{ fluent(key="link-target", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="target">
|
<input type="text" name="target">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="code">Code:</label>
|
<label for="code">{{ fluent(key="link-code", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="code">
|
<input type="text" name="code">
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" value="Submit">
|
<input type="submit" value="Submit">
|
||||||
|
@ -5,24 +5,29 @@
|
|||||||
<h1>{{ link.title }}</h1>
|
<h1>{{ link.title }}</h1>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Beschreibung:</td>
|
<td>{{ fluent(key="link-description", lang=user.language)
|
||||||
|
}}:</td>
|
||||||
<td>{{ link.title }}</td>
|
<td>{{ link.title }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Code:</td>
|
<td>{{ fluent(key="link-code", lang=user.language)
|
||||||
|
}}:</td>
|
||||||
<td>{{ link.code }}</td>
|
<td>{{ link.code }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Kurzlink:</td>
|
<td>{{ fluent(key="shortlink", lang=user.language)
|
||||||
|
}}:</td>
|
||||||
<td><a href="{{ protocol }}://{{ host }}/{{ link.code }}">{{ protocol }}://{{ host }}/{{ link.code }}</a>
|
<td><a href="{{ protocol }}://{{ host }}/{{ link.code }}">{{ protocol }}://{{ host }}/{{ link.code }}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Ziel:</td>
|
<td>{{ fluent(key="link-target", lang=user.language)
|
||||||
|
}}:</td>
|
||||||
<td>{{ link.target }}</td>
|
<td>{{ link.target }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>QR-Code</td>
|
<td>{{ fluent(key="qr-code", lang=user.language)
|
||||||
|
}}</td>
|
||||||
<td><a href="/admin/download/png/{{ link.code }}" download="{{ link.title | slugify }}.png">
|
<td><a href="/admin/download/png/{{ link.code }}" download="{{ link.title | slugify }}.png">
|
||||||
{{ qr | trim_start_matches(pat=
|
{{ qr | trim_start_matches(pat=
|
||||||
'.*?>')
|
'.*?>')
|
||||||
@ -33,7 +38,8 @@
|
|||||||
</table>
|
</table>
|
||||||
{% if user.role == 2 or user.id == link.author %}
|
{% if user.role == 2 or user.id == link.author %}
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a class="button" href="/admin/edit/link/{{ link.code }}">Editieren</a>
|
<a class="button" href="/admin/edit/link/{{ link.code }}">{{ fluent(key="edit-link", lang=user.language)
|
||||||
|
}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,31 +2,39 @@
|
|||||||
|
|
||||||
{% block admin %}
|
{% block admin %}
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<h1>Profil von {{viewed_user.username}}</h1>
|
<h1>{{ fluent(key="user-headline", lang=user.language, username=user.username) }}</h1>
|
||||||
<form action="" method="POST">
|
<form action="" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<label for="username">Benutzername:</label>
|
<label for="username">{{ fluent(key="username", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="text" name="username" value="{{ viewed_user.username }}" readonly>
|
<input type="text" name="username" value="{{ viewed_user.username }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="email">E-mail:</label>
|
<label for="email">{{ fluent(key="email", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="email" name="email" value="{{ viewed_user.email }}" readonly>
|
<input type="email" name="email" value="{{ viewed_user.email }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
{% if user.role == 2 or user.id == viewed_user.id %}
|
{% if user.role == 2 or user.id == viewed_user.id %}
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort:</label>
|
<label for="password">{{ fluent(key="password", lang=user.language)
|
||||||
|
}}:</label>
|
||||||
<input type="password" name="password" value="verschlüsselt" readonly>
|
<input type="password" name="password" value="verschlüsselt" readonly>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
{% if user.role == 2 or user.id == viewed_user.id %}
|
{% if user.role == 2 or user.id == viewed_user.id %}
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a class="button" href="/admin/edit/profile/{{ viewed_user.id }}">Editieren</a>
|
<a class="button" href="/admin/edit/profile/{{ viewed_user.id }}">{{ fluent(key="edit-user", lang=user.language)
|
||||||
|
}}</a>
|
||||||
{% if user.role == 2 and viewed_user.role == 1 %}
|
{% if user.role == 2 and viewed_user.role == 1 %}
|
||||||
<a class="button" href="/admin/edit/set_admin/{{ viewed_user.id }}">Zum Admin machen</a>
|
<a class="button" href="/admin/edit/set_admin/{{ viewed_user.id }}">{{ fluent(key="make-user-admin",
|
||||||
|
lang=user.language)
|
||||||
|
}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.role == 2 and viewed_user.role == 2 %}
|
{% if user.role == 2 and viewed_user.role == 2 and not user.id == viewed_user.id %}
|
||||||
<a class="button" href="/admin/edit/set_admin/{{ viewed_user.id }}">Zum Normalo machen</a>
|
<a class="button" href="/admin/edit/set_admin/{{ viewed_user.id }}">{{ fluent(key="make-user-regular",
|
||||||
|
lang=user.language)
|
||||||
|
}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user