added i18n
This commit is contained in:
271
Cargo.lock
generated
271
Cargo.lock
generated
@@ -2,6 +2,12 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accept-language"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
@@ -129,9 +135,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum"
|
name = "axum"
|
||||||
version = "0.8.8"
|
version = "0.8.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
|
checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum-core",
|
"axum-core",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -179,6 +185,28 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-extra"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"axum-core",
|
||||||
|
"bytes",
|
||||||
|
"cookie",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"mime",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
@@ -353,6 +381,17 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cookie"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
"time",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@@ -437,6 +476,15 @@ dependencies = [
|
|||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deunicode"
|
name = "deunicode"
|
||||||
version = "1.6.2"
|
version = "1.6.2"
|
||||||
@@ -491,6 +539,85 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-bundle"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4"
|
||||||
|
dependencies = [
|
||||||
|
"fluent-langneg",
|
||||||
|
"fluent-syntax",
|
||||||
|
"intl-memoizer",
|
||||||
|
"intl_pluralrules",
|
||||||
|
"rustc-hash",
|
||||||
|
"self_cell",
|
||||||
|
"smallvec",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-langneg"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0"
|
||||||
|
dependencies = [
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-syntax"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-template-macros"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6b1dac7e7f07f8a60aa844f616bede13deeffaf24e9e35ae9e4979a7dac4a5c"
|
||||||
|
dependencies = [
|
||||||
|
"flume",
|
||||||
|
"ignore",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-templates"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d48ac2b8e7c3a2198fc584af78e674d15dacdede8a6cebb686c844713f7d0ba"
|
||||||
|
dependencies = [
|
||||||
|
"fluent-bundle",
|
||||||
|
"fluent-langneg",
|
||||||
|
"fluent-syntax",
|
||||||
|
"fluent-template-macros",
|
||||||
|
"flume",
|
||||||
|
"heck",
|
||||||
|
"ignore",
|
||||||
|
"intl-memoizer",
|
||||||
|
"log",
|
||||||
|
"serde_json",
|
||||||
|
"tera",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flume"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
|
||||||
|
dependencies = [
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -983,6 +1110,25 @@ dependencies = [
|
|||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "intl-memoizer"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f"
|
||||||
|
dependencies = [
|
||||||
|
"type-map",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "intl_pluralrules"
|
||||||
|
version = "7.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
|
||||||
|
dependencies = [
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.12.0"
|
version = "2.12.0"
|
||||||
@@ -1170,6 +1316,12 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@@ -1363,6 +1515,12 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
@@ -1372,6 +1530,12 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-hack"
|
||||||
|
version = "0.5.20+deprecated"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
@@ -1767,6 +1931,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "self_cell"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
@@ -1875,10 +2045,13 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
|||||||
name = "slimes-website"
|
name = "slimes-website"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"accept-language",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
|
"axum-extra",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"fluent-templates",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1917,6 +2090,15 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spinning_top"
|
name = "spinning_top"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -2067,6 +2249,37 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"itoa",
|
||||||
|
"num-conv",
|
||||||
|
"powerfmt",
|
||||||
|
"serde_core",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
|
||||||
|
dependencies = [
|
||||||
|
"num-conv",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -2074,6 +2287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
|
"serde_core",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2312,6 +2526,15 @@ version = "0.2.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "type-map"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
@@ -2324,6 +2547,49 @@ version = "0.1.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unic-langid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
|
||||||
|
dependencies = [
|
||||||
|
"unic-langid-impl",
|
||||||
|
"unic-langid-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unic-langid-impl"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
|
||||||
|
dependencies = [
|
||||||
|
"tinystr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unic-langid-macros"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
"tinystr",
|
||||||
|
"unic-langid-impl",
|
||||||
|
"unic-langid-macros-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unic-langid-macros-impl"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"unic-langid-impl",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
@@ -2922,6 +3188,7 @@ version = "0.11.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"serde",
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
"zerovec-derive",
|
"zerovec-derive",
|
||||||
|
|||||||
@@ -18,3 +18,6 @@ serde = { version = "1.0.228", features = ["derive"] }
|
|||||||
chrono = { version = "0.4.44", features = ["serde"] }
|
chrono = { version = "0.4.44", features = ["serde"] }
|
||||||
reqwest = { version = "0.13.2", features = ["json"] }
|
reqwest = { version = "0.13.2", features = ["json"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
|
fluent-templates = { version = "0.14.0", features = ["tera"] }
|
||||||
|
axum-extra = { version = "0.12.6", features = ["cookie"] }
|
||||||
|
accept-language = "3.1.0"
|
||||||
|
|||||||
67
locales/en.ftl
Normal file
67
locales/en.ftl
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
lang = en
|
||||||
|
nav-leaderboard = Leaderboard
|
||||||
|
nav-analytics = Analytics
|
||||||
|
nav-source-header = Source Code
|
||||||
|
nav-lang-header = Language
|
||||||
|
nav-cli-title = CLI + Server
|
||||||
|
nav-cli-desc = Core lib, CLI and API monorepo
|
||||||
|
nav-web-title = Website
|
||||||
|
nav-web-desc = This very website
|
||||||
|
nav-gui-title = GUI Version
|
||||||
|
nav-gui-desc = Experimental Cross-platform GUI
|
||||||
|
footer-text = Slimes
|
||||||
|
|
||||||
|
home-title = Benchmark Reports
|
||||||
|
home-experimental = Experimental
|
||||||
|
home-experimental-tooltip = Show Android clients
|
||||||
|
home-sort-by = Sort by:
|
||||||
|
home-order-desc = Descending
|
||||||
|
home-order-asc = Ascending
|
||||||
|
|
||||||
|
sort-score = Score
|
||||||
|
sort-single = Single Thread
|
||||||
|
sort-multi = Multi Thread
|
||||||
|
sort-ram = RAM Amount
|
||||||
|
sort-threads = Thread Count
|
||||||
|
sort-time = Time Ago
|
||||||
|
|
||||||
|
sort-desc-score = (Singlethread + Multithread) / 2
|
||||||
|
sort-desc-single = Single-core efficiency
|
||||||
|
sort-desc-multi = Multi-core efficiency
|
||||||
|
sort-desc-ram = System memory capacity
|
||||||
|
sort-desc-threads = Total logical cores
|
||||||
|
sort-desc-time = Newest reports first
|
||||||
|
|
||||||
|
table-cpu-score = CPU Score
|
||||||
|
table-threads = Threads
|
||||||
|
table-ram = RAM
|
||||||
|
table-os = OS
|
||||||
|
table-hostname = Hostname
|
||||||
|
table-time = Time
|
||||||
|
table-note = Note
|
||||||
|
badge-new = NEW
|
||||||
|
|
||||||
|
details-back = Back to Leaderboard
|
||||||
|
details-device = Device { $sig }
|
||||||
|
details-report-id = ID
|
||||||
|
details-version = VERSION
|
||||||
|
details-mac = MAC
|
||||||
|
details-reported = REPORTED
|
||||||
|
details-cpu-score = CPU Score
|
||||||
|
details-perf-breakdown = CPU Performance breakdown
|
||||||
|
details-single = Single-Thread
|
||||||
|
details-multi = Multi-Thread
|
||||||
|
details-threads = Threads
|
||||||
|
|
||||||
|
analytics-title = Benchmark Analytics
|
||||||
|
analytics-insights = Insights from { $count } benchmarks
|
||||||
|
analytics-ram-eff = RAM Efficiency
|
||||||
|
analytics-ram-eff-desc = Avg Score per GB RAM
|
||||||
|
analytics-cpu-eff = CPU Thread Efficiency
|
||||||
|
analytics-cpu-eff-desc = Avg Score per Thread
|
||||||
|
analytics-chart-dist = Score Distribution
|
||||||
|
analytics-chart-os-count = Reports by Operating System
|
||||||
|
analytics-chart-os-avg = Avg Score by Operating System
|
||||||
|
analytics-chart-os-max = Highest Score by Operating System
|
||||||
|
analytics-chart-os-min = Lowest Score by Operating System
|
||||||
|
analytics-full-view = Full View
|
||||||
67
locales/fr.ftl
Normal file
67
locales/fr.ftl
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
lang = fr
|
||||||
|
nav-leaderboard = Classement
|
||||||
|
nav-analytics = Statistiques
|
||||||
|
nav-source-header = Code Source
|
||||||
|
nav-lang-header = Langue
|
||||||
|
nav-cli-title = CLI + Serveur
|
||||||
|
nav-cli-desc = Lib principale, CLI et API
|
||||||
|
nav-web-title = Site Web
|
||||||
|
nav-web-desc = Ce site même
|
||||||
|
nav-gui-title = Version GUI
|
||||||
|
nav-gui-desc = GUI multiplateforme expérimentale
|
||||||
|
footer-text = Slimes
|
||||||
|
|
||||||
|
home-title = Rapports de Benchmark
|
||||||
|
home-experimental = Expérimental
|
||||||
|
home-experimental-tooltip = Afficher les clients Android
|
||||||
|
home-sort-by = Trier par :
|
||||||
|
home-order-desc = Décroissant
|
||||||
|
home-order-asc = Croissant
|
||||||
|
|
||||||
|
sort-score = Score
|
||||||
|
sort-single = Singlethread
|
||||||
|
sort-multi = Multithread
|
||||||
|
sort-ram = Quantité de RAM
|
||||||
|
sort-threads = Nombre de threads
|
||||||
|
sort-time = Temps
|
||||||
|
|
||||||
|
sort-desc-score = (Singlethread + Multithread) / 2
|
||||||
|
sort-desc-single = Efficacité singlethread
|
||||||
|
sort-desc-multi = Efficacité multithread
|
||||||
|
sort-desc-ram = Capacité mémoire système
|
||||||
|
sort-desc-threads = Total des coeurs logiques
|
||||||
|
sort-desc-time = Rapports les plus récents
|
||||||
|
|
||||||
|
table-cpu-score = Score CPU
|
||||||
|
table-threads = Threads
|
||||||
|
table-ram = RAM
|
||||||
|
table-os = Système
|
||||||
|
table-hostname = Nom d'hôte
|
||||||
|
table-time = Temps
|
||||||
|
table-note = Note
|
||||||
|
badge-new = NOUVEAU
|
||||||
|
|
||||||
|
details-back = Retour au classement
|
||||||
|
details-device = Machine { $sig }
|
||||||
|
details-report-id = ID
|
||||||
|
details-version = VERSION
|
||||||
|
details-mac = MAC
|
||||||
|
details-reported = ENVOYÉ
|
||||||
|
details-cpu-score = Score CPU
|
||||||
|
details-perf-breakdown = Détails des performances CPU
|
||||||
|
details-single = Mono-thread
|
||||||
|
details-multi = Multi-thread
|
||||||
|
details-threads = Threads
|
||||||
|
|
||||||
|
analytics-title = Statistiques de Benchmark
|
||||||
|
analytics-insights = Aperçu de { $count } benchmarks
|
||||||
|
analytics-ram-eff = Efficacité RAM
|
||||||
|
analytics-ram-eff-desc = Score moyen par Go de RAM
|
||||||
|
analytics-cpu-eff = Efficacité CPU
|
||||||
|
analytics-cpu-eff-desc = Score moyen par thread
|
||||||
|
analytics-chart-dist = Distribution des scores
|
||||||
|
analytics-chart-os-count = Rapports par système d'exploitation
|
||||||
|
analytics-chart-os-avg = Score moyen par système d'exploitation
|
||||||
|
analytics-chart-os-max = Score le plus élevé par système
|
||||||
|
analytics-chart-os-min = Score le plus bas par système
|
||||||
|
analytics-full-view = Plein écran
|
||||||
@@ -1,20 +1,26 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query, State},
|
extract::{Path, Query, State},
|
||||||
|
http::HeaderMap,
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
};
|
};
|
||||||
|
use axum_extra::extract::CookieJar;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use reqwest::StatusCode;
|
use reqwest::{StatusCode, header::REFERER};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, sync::Arc, time::Instant};
|
use std::{collections::HashMap, sync::Arc, time::Instant};
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
|
|
||||||
use crate::{AppState, TEMPLATES};
|
use crate::{
|
||||||
|
AppState, TEMPLATES,
|
||||||
|
i18n::{Lang, get_available_languages},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct SortParams {
|
pub struct Params {
|
||||||
pub sort: Option<String>,
|
pub sort: Option<String>,
|
||||||
pub order: Option<String>,
|
pub order: Option<String>,
|
||||||
pub experimental: Option<String>,
|
pub experimental: Option<String>,
|
||||||
|
pub lang: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
@@ -189,10 +195,37 @@ async fn get_cached_reports(state: &AppState) -> Result<Vec<Report>, (StatusCode
|
|||||||
Ok(fresh_reports)
|
Ok(fresh_reports)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_lang_handler(
|
||||||
|
Path(lang): Path<String>,
|
||||||
|
jar: CookieJar,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let cookie = axum_extra::extract::cookie::Cookie::build(("lang", lang))
|
||||||
|
.path("/")
|
||||||
|
// .max_age(value)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let redirect_url = headers
|
||||||
|
.get(REFERER)
|
||||||
|
.and_then(|val| val.to_str().ok())
|
||||||
|
.unwrap_or("/");
|
||||||
|
|
||||||
|
(jar.add(cookie), axum::response::Redirect::to(redirect_url))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_common_context(context: &mut Context, lang: &str) {
|
||||||
|
context.insert("lang", lang);
|
||||||
|
context.insert("available_languages", &get_available_languages());
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn home_handler(
|
pub async fn home_handler(
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
Query(params): Query<SortParams>,
|
jar: CookieJar,
|
||||||
|
headers: HeaderMap,
|
||||||
|
Query(params): Query<Params>,
|
||||||
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
||||||
|
let lang = Lang::resolve(&jar, &headers);
|
||||||
|
|
||||||
let raw_reports = get_cached_reports(&state).await?;
|
let raw_reports = get_cached_reports(&state).await?;
|
||||||
let mut reports = process_reports(raw_reports);
|
let mut reports = process_reports(raw_reports);
|
||||||
|
|
||||||
@@ -220,6 +253,7 @@ pub async fn home_handler(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
|
add_common_context(&mut context, &lang);
|
||||||
context.insert("reports", &reports);
|
context.insert("reports", &reports);
|
||||||
context.insert("title", &state.app_name);
|
context.insert("title", &state.app_name);
|
||||||
context.insert("current_sort", &sort_field);
|
context.insert("current_sort", &sort_field);
|
||||||
@@ -227,6 +261,7 @@ pub async fn home_handler(
|
|||||||
context.insert("show_experimental", &show_experimental);
|
context.insert("show_experimental", &show_experimental);
|
||||||
context.insert("current_page", "leaderboard");
|
context.insert("current_page", "leaderboard");
|
||||||
context.insert("prefix", "");
|
context.insert("prefix", "");
|
||||||
|
context.insert("lang", &lang);
|
||||||
|
|
||||||
match TEMPLATES.render("index.html", &context) {
|
match TEMPLATES.render("index.html", &context) {
|
||||||
Ok(html) => Ok(Html(html)),
|
Ok(html) => Ok(Html(html)),
|
||||||
@@ -237,13 +272,17 @@ pub async fn home_handler(
|
|||||||
pub async fn report_details_handler(
|
pub async fn report_details_handler(
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
Path(id): Path<u64>,
|
Path(id): Path<u64>,
|
||||||
|
jar: CookieJar,
|
||||||
|
headers: HeaderMap,
|
||||||
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
||||||
|
let lang = Lang::resolve(&jar, &headers);
|
||||||
|
|
||||||
// Check if the report exists in our current cache to avoid API call
|
// Check if the report exists in our current cache to avoid API call
|
||||||
{
|
{
|
||||||
let cache = state.reports_cache.read().await;
|
let cache = state.reports_cache.read().await;
|
||||||
if let Some(c) = &*cache {
|
if let Some(c) = &*cache {
|
||||||
if let Some(report) = c.data.iter().find(|r| r.id == id) {
|
if let Some(report) = c.data.iter().find(|r| r.id == id) {
|
||||||
return render_details(report.clone(), &state).await;
|
return render_details(report.clone(), &state, &lang).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,14 +296,16 @@ pub async fn report_details_handler(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::NOT_FOUND, format!("Report not found: {}", e)))?;
|
.map_err(|e| (StatusCode::NOT_FOUND, format!("Report not found: {}", e)))?;
|
||||||
|
|
||||||
render_details(report, &state).await
|
render_details(report, &state, &lang).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn render_details(
|
async fn render_details(
|
||||||
report: Report,
|
report: Report,
|
||||||
state: &AppState,
|
state: &AppState,
|
||||||
|
lang: &str,
|
||||||
) -> Result<impl IntoResponse + use<>, (StatusCode, String)> {
|
) -> Result<impl IntoResponse + use<>, (StatusCode, String)> {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
|
add_common_context(&mut context, lang);
|
||||||
context.insert("report", &report);
|
context.insert("report", &report);
|
||||||
context.insert(
|
context.insert(
|
||||||
"title",
|
"title",
|
||||||
@@ -303,7 +344,11 @@ pub struct AnalyticsData {
|
|||||||
|
|
||||||
pub async fn analytics_handler(
|
pub async fn analytics_handler(
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
|
jar: CookieJar,
|
||||||
|
headers: HeaderMap,
|
||||||
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
||||||
|
let lang = Lang::resolve(&jar, &headers);
|
||||||
|
|
||||||
let raw_reports = get_cached_reports(&state).await?;
|
let raw_reports = get_cached_reports(&state).await?;
|
||||||
let reports = process_reports(raw_reports);
|
let reports = process_reports(raw_reports);
|
||||||
|
|
||||||
@@ -416,6 +461,7 @@ pub async fn analytics_handler(
|
|||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
|
add_common_context(&mut context, &lang);
|
||||||
context.insert("title", &format!("Analytics | {}", state.app_name));
|
context.insert("title", &format!("Analytics | {}", state.app_name));
|
||||||
context.insert("json_data", &json_data);
|
context.insert("json_data", &json_data);
|
||||||
context.insert("data", &data);
|
context.insert("data", &data);
|
||||||
|
|||||||
46
src/i18n.rs
Normal file
46
src/i18n.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
use axum_extra::extract::CookieJar;
|
||||||
|
use fluent_templates::{Loader, static_loader};
|
||||||
|
use reqwest::header::ACCEPT_LANGUAGE;
|
||||||
|
|
||||||
|
static_loader! {
|
||||||
|
pub static LOCALES = {
|
||||||
|
locales: "./locales",
|
||||||
|
fallback_language: "en",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Lang;
|
||||||
|
impl Lang {
|
||||||
|
pub fn resolve(jar: &CookieJar, headers: &axum::http::HeaderMap) -> String {
|
||||||
|
if let Some(lang_cookie) = jar.get("lang").map(|c| c.value().to_string()) {
|
||||||
|
return lang_cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(accept_lang) = headers.get(ACCEPT_LANGUAGE).and_then(|h| h.to_str().ok()) {
|
||||||
|
let preferred: Vec<&str> = accept_lang
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.split(';').next().unwrap_or("").trim())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let available = get_available_languages();
|
||||||
|
for lang in preferred {
|
||||||
|
// Exact match (e.g., "en-US")
|
||||||
|
if available.iter().any(|a| a == lang) {
|
||||||
|
return lang.to_string();
|
||||||
|
}
|
||||||
|
// Base match (e.g., "en" from "en-US")
|
||||||
|
let base = lang.split('-').next().unwrap_or("");
|
||||||
|
if available.iter().any(|a| a == base) {
|
||||||
|
return base.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"en".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_available_languages() -> Vec<String> {
|
||||||
|
LOCALES.locales().map(|id| id.to_string()).collect()
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use axum::{Router, routing::get};
|
use axum::{Router, routing::get};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use fluent_templates::FluentLoader;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::{
|
use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@@ -10,8 +11,12 @@ use tokio::sync::RwLock;
|
|||||||
|
|
||||||
mod handlers;
|
mod handlers;
|
||||||
use handlers::home_handler;
|
use handlers::home_handler;
|
||||||
|
mod i18n;
|
||||||
|
|
||||||
use crate::handlers::{Report, analytics_handler, report_details_handler};
|
use crate::{
|
||||||
|
handlers::{Report, analytics_handler, report_details_handler, set_lang_handler},
|
||||||
|
i18n::LOCALES,
|
||||||
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref TEMPLATES: Tera = {
|
pub static ref TEMPLATES: Tera = {
|
||||||
@@ -27,6 +32,7 @@ lazy_static! {
|
|||||||
),
|
),
|
||||||
])
|
])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
|
||||||
tera
|
tera
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -76,6 +82,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.route("/", get(home_handler))
|
.route("/", get(home_handler))
|
||||||
.route("/report/{id}", get(report_details_handler))
|
.route("/report/{id}", get(report_details_handler))
|
||||||
.route("/analytics", get(analytics_handler))
|
.route("/analytics", get(analytics_handler))
|
||||||
|
.route("/set-lang/{lang}", get(set_lang_handler))
|
||||||
.with_state(shared_state);
|
.with_state(shared_state);
|
||||||
|
|
||||||
let addr = if cli.host {
|
let addr = if cli.host {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="{{ fluent(key='lang', lang=lang) }}">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
@@ -15,33 +15,58 @@
|
|||||||
<div class="nav-left">
|
<div class="nav-left">
|
||||||
<span class="nav-logo">Slimes 🧪</span>
|
<span class="nav-logo">Slimes 🧪</span>
|
||||||
<div class="nav-links">
|
<div class="nav-links">
|
||||||
<a href="{{ prefix }}./" class="{% if current_page == 'leaderboard' %}active{% endif %}">Leaderboard</a>
|
<a href="{{ prefix }}./" class="{% if current_page == 'leaderboard' %}active{% endif %}">{{ fluent(key="nav-leaderboard", lang=lang) }}</a>
|
||||||
<a href="{{ prefix }}analytics" class="{% if current_page == 'analytics' %}active{% endif %}">Analytics</a>
|
<a href="{{ prefix }}analytics" class="{% if current_page == 'analytics' %}active{% endif %}">{{ fluent(key="nav-analytics", lang=lang) }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-right">
|
<div class="nav-right">
|
||||||
<div class="dropdown" id="githubDropdown">
|
<div class="dropdown">
|
||||||
<button class="dropdown-trigger" onclick="toggleDropdown(event)" aria-label="Git Repositories">
|
<button class="dropdown-trigger" onclick="toggleDropdown(event)" aria-label="Git Repositories">
|
||||||
<i class="fa-brands fa-git-alt fa-lg"></i>
|
<i class="fa-brands fa-git-alt fa-lg"></i>
|
||||||
<i class="fa-solid fa-chevron-down chevron"></i>
|
<i class="fa-solid fa-chevron-down chevron"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<div class="dropdown-header">Source Code</div>
|
<div class="dropdown-header">{{ fluent(key="nav-source-header", lang=lang) }}</div>
|
||||||
<a href="https://git.alatreon.org/strawberries/slimes" target="_blank" rel="noopener">
|
<a href="https://git.alatreon.org/strawberries/slimes" target="_blank" rel="noopener">
|
||||||
<span class="link-title"><i class="fa-solid fa-terminal fa-fw"></i> CLI + Server</span>
|
<span class="link-title"><i class="fa-solid fa-terminal fa-fw"></i> {{ fluent(key="nav-cli-title", lang=lang) }}</span>
|
||||||
<span class="link-desc">Core lib, CLI and API monorepo</span>
|
<span class="link-desc">{{ fluent(key="nav-cli-desc", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://git.alatreon.org/strawberries/slimes-website" target="_blank" rel="noopener">
|
<a href="https://git.alatreon.org/strawberries/slimes-website" target="_blank" rel="noopener">
|
||||||
<span class="link-title"><i class="fa-solid fa-globe fa-fw"></i> Website</span>
|
<span class="link-title"><i class="fa-solid fa-globe fa-fw"></i> {{ fluent(key="nav-web-title", lang=lang) }}</span>
|
||||||
<span class="link-desc">This very website</span>
|
<span class="link-desc">{{ fluent(key="nav-web-desc", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://git.alatreon.org/strawberries/slimes-gui" target="_blank" rel="noopener">
|
<a href="https://git.alatreon.org/strawberries/slimes-gui" target="_blank" rel="noopener">
|
||||||
<span class="link-title"><i class="fa-solid fa-window-restore fa-fw"></i> GUI Version</span>
|
<span class="link-title"><i class="fa-solid fa-window-restore fa-fw"></i> {{ fluent(key="nav-gui-title", lang=lang) }}</span>
|
||||||
<span class="link-desc">Experimental Cross-platform GUI</span>
|
<span class="link-desc">{{ fluent(key="nav-gui-desc", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropdown-trigger" onclick="toggleDropdown(event)" aria-label="Language">
|
||||||
|
<i class="fa-solid fa-globe fa-lg"></i>
|
||||||
|
<i class="fa-solid fa-chevron-down chevron"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<div class="dropdown-header">{{ fluent(key="nav-lang-header", lang=lang) }}</div>
|
||||||
|
{% for l in available_languages %}
|
||||||
|
<a href="/set-lang/{{ l }}" {% if l == lang %}class="active"{% endif %}>
|
||||||
|
{{ l | upper }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="dropdown"> -->
|
||||||
|
<!-- <button class="dropdown-trigger"> -->
|
||||||
|
<!-- <i class="fa-solid fa-language"></i> {{ lang | truncate(length=2, end="") | upper }} -->
|
||||||
|
<!-- </button> -->
|
||||||
|
<!-- <div class="dropdown-menu"> -->
|
||||||
|
<!-- <a href="/set-lang/en-US">English</a> -->
|
||||||
|
<!-- <a href="/set-lang/fr-FR">Français</a> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- </div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -49,23 +74,33 @@
|
|||||||
<main>
|
<main>
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
<footer>{{ now() | date(format="%Y") }} - Slimes</footer>
|
<footer>{{ now() | date(format="%Y") }} - {{ fluent(key="footer-text", lang=lang) }}</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function toggleDropdown(event) {
|
function toggleDropdown(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dropdown = document.getElementById('githubDropdown');
|
|
||||||
dropdown.classList.toggle('open');
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onclick = function(event) {
|
const dropdown = event.currentTarget.closest('.dropdown');
|
||||||
if (!event.target.closest('#githubDropdown')) {
|
const isOpen = dropdown.classList.contains('open');
|
||||||
const dropdown = document.getElementById('githubDropdown');
|
|
||||||
if (dropdown && dropdown.classList.contains('open')) {
|
// close all
|
||||||
dropdown.classList.remove('open');
|
document.querySelectorAll('.dropdown.open').forEach(d => {
|
||||||
}
|
d.classList.remove('open');
|
||||||
|
});
|
||||||
|
|
||||||
|
// reopen clicked one if was closed
|
||||||
|
if (!isOpen) {
|
||||||
|
dropdown.classList.add('open');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('click', (event) => {
|
||||||
|
if (!event.target.closest('.dropdown')) {
|
||||||
|
document.querySelectorAll('.dropdown.open').forEach(d => {
|
||||||
|
d.classList.remove('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
@@ -93,6 +128,14 @@
|
|||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-logo {
|
.nav-logo {
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
@@ -227,7 +270,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
<!-- .nav-links { display: none; } -->
|
/* .nav-links { display: none; } */
|
||||||
.nav-left { gap: 1rem; }
|
.nav-left { gap: 1rem; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
{% macro chart_card(id, title) %}
|
{% macro chart_card(id, title) %}
|
||||||
<div class="chart-card">
|
<div class="chart-card">
|
||||||
<button class="expand-btn" onclick="openFullView('{{ id }}', '{{ title }}')">
|
<button class="expand-btn" onclick="openFullView(`{{ id }}`, `{{ title }}`)">
|
||||||
<i class="fa-solid fa-expand"></i> Full View
|
<i class="fa-solid fa-expand"></i> {{ fluent(key="analytics-full-view", lang=lang) }}
|
||||||
</button>
|
</button>
|
||||||
<h3>{{ title }}</h3>
|
<h3>{{ title }}</h3>
|
||||||
<canvas id="{{ id }}"></canvas>
|
<canvas id="{{ id }}"></canvas>
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>Benchmark Analytics</h2>
|
<h2>{{ fluent(key="analytics-title", lang=lang) }}</h2>
|
||||||
<p style="text-align: center; color: var(--text-muted);">Insights from {{ data.total_reports }} benchmarks</p>
|
<p style="text-align: center; color: var(--text-muted);">{{ fluent(key="analytics-insights", lang=lang, count=data.total_reports) }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="chartModal" class="modal">
|
<div id="chartModal" class="modal">
|
||||||
@@ -34,21 +34,21 @@
|
|||||||
|
|
||||||
<div class="analytics-grid">
|
<div class="analytics-grid">
|
||||||
<div class="fact-card">
|
<div class="fact-card">
|
||||||
<span class="fact-title">RAM Efficiency</span>
|
<span class="fact-title">{{ fluent(key="analytics-ram-eff", lang=lang) }}</span>
|
||||||
<span class="fact-value">{{ data.avg_score_per_gb | round(precision=1) }}</span>
|
<span class="fact-value">{{ data.avg_score_per_gb | round(precision=1) }}</span>
|
||||||
<span class="fact-label">Avg Score per GB RAM</span>
|
<span class="fact-label">{{ fluent(key="analytics-ram-eff-desc", lang=lang) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="fact-card">
|
<div class="fact-card">
|
||||||
<span class="fact-title">CPU Thread Efficiency</span>
|
<span class="fact-title">{{ fluent(key="analytics-cpu-eff", lang=lang) }}</span>
|
||||||
<span class="fact-value">{{ data.avg_score_per_thread | round(precision=1) }}</span>
|
<span class="fact-value">{{ data.avg_score_per_thread | round(precision=1) }}</span>
|
||||||
<span class="fact-label">Avg Score per Thread</span>
|
<span class="fact-label">{{ fluent(key="analytics-cpu-eff-desc", lang=lang) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ self::chart_card(id="distChart", title="Score Distribution") }}
|
{{ self::chart_card(id="distChart", title=fluent(key="analytics-chart-dist", lang=lang)) }}
|
||||||
{{ self::chart_card(id="osCountChart", title="Reports by Operating System") }}
|
{{ self::chart_card(id="osCountChart", title=fluent(key="analytics-chart-os-count", lang=lang)) }}
|
||||||
{{ self::chart_card(id="osChart", title="Avg Score by Operating System") }}
|
{{ self::chart_card(id="osChart", title=fluent(key="analytics-chart-os-avg", lang=lang)) }}
|
||||||
{{ self::chart_card(id="osMaxChart", title="Highest Score by Operating System") }}
|
{{ self::chart_card(id="osMaxChart", title=fluent(key="analytics-chart-os-max", lang=lang)) }}
|
||||||
{{ self::chart_card(id="osMinChart", title="Lowest Score by Operating System") }}
|
{{ self::chart_card(id="osMinChart", title=fluent(key="analytics-chart-os-min", lang=lang)) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
@@ -244,6 +244,10 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expand-btn i {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.expand-btn:hover {
|
.expand-btn:hover {
|
||||||
background: var(--primary-soft);
|
background: var(--primary-soft);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="back-nav">
|
<div class="back-nav">
|
||||||
<a href="../">← Back to Leaderboard</a>
|
<a href="../">← {{ fluent(key="details-back", lang=lang) }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-card">
|
<div class="report-card">
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
{% if report.slimes["Hostname"] %}
|
{% if report.slimes["Hostname"] %}
|
||||||
{{ report.slimes["Hostname"].0 }}
|
{{ report.slimes["Hostname"].0 }}
|
||||||
{% else %}
|
{% else %}
|
||||||
Device {{ report.signature | truncate(length=10) }}
|
{{ fluent(key="details-device", lang=lang, sig=report.signature | truncate(length=10)) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@@ -21,22 +21,22 @@
|
|||||||
<div class="meta-container">
|
<div class="meta-container">
|
||||||
<div class="meta-group system-context">
|
<div class="meta-group system-context">
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<span class="label">ID</span>
|
<span class="label">{{ fluent(key="details-report-id", lang=lang) }}</span>
|
||||||
<span class="value">#{{ report.id }}</span>
|
<span class="value">#{{ report.id }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<span class="label">VERSION</span>
|
<span class="label">{{ fluent(key="details-version", lang=lang) }}</span>
|
||||||
<span class="value">v{{ report.client_version }}</span>
|
<span class="value">v{{ report.client_version }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="meta-group hardware-context">
|
<div class="meta-group hardware-context">
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<span class="label">MAC</span>
|
<span class="label">{{ fluent(key="details-mac", lang=lang) }}</span>
|
||||||
<span class="value">{{ report.mac_address }}</span>
|
<span class="value">{{ report.mac_address }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<span class="label">REPORTED</span>
|
<span class="label">{{ fluent(key="details-reported", lang=lang) }}</span>
|
||||||
<span class="value">{{ time_ago }}</span>
|
<span class="value">{{ time_ago }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,25 +45,25 @@
|
|||||||
|
|
||||||
<div class="score-container">
|
<div class="score-container">
|
||||||
<div class="score-value">{{ score }}</div>
|
<div class="score-value">{{ score }}</div>
|
||||||
<div class="score-label">CPU Score</div>
|
<div class="score-label">{{ fluent(key="details-cpu-score", lang=lang) }}</div>
|
||||||
<div class="score-note">(mt+st)/2</div>
|
<div class="score-note">(mt+st)/2</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-grid">
|
<div class="report-grid">
|
||||||
<div class="info-section">
|
<div class="info-section">
|
||||||
<h3>Performance Breakdown</h3>
|
<h3>{{ fluent(key="details-perf-breakdown", lang=lang) }}</h3>
|
||||||
<div class="bench-stats">
|
<div class="bench-stats">
|
||||||
<div class="stat-row">
|
<div class="stat-row">
|
||||||
<span>Single-Thread</span>
|
<span>{{ fluent(key="details-single", lang=lang) }}</span>
|
||||||
<strong>{{ report.benchmark.single_thread.score }}</strong>
|
<strong>{{ report.benchmark.single_thread.score }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-row">
|
<div class="stat-row">
|
||||||
<span>Multi-Thread</span>
|
<span>{{ fluent(key="details-multi", lang=lang) }}</span>
|
||||||
<strong>{{ report.benchmark.multi_thread.score }}</strong>
|
<strong>{{ report.benchmark.multi_thread.score }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-row">
|
<div class="stat-row">
|
||||||
<span>Threads</span>
|
<span>{{ fluent(key="details-threads", lang=lang) }}</span>
|
||||||
<strong>{{ report.benchmark.logical_cores }}</strong>
|
<strong>{{ report.benchmark.logical_cores }}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,64 +2,64 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>Benchmark Reports</h2>
|
<h2>{{ fluent(key="home-title", lang=lang) }}</h2>
|
||||||
|
|
||||||
<div class="table-controls">
|
<div class="table-controls">
|
||||||
<form id="sortForm" method="get" action="">
|
<form id="sortForm" method="get" action="">
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="switch-ui" title="Show Android clients">
|
<label class="switch-ui" title="{{ fluent(key='home-experimental-tooltip', lang=lang) }}">
|
||||||
<input type="checkbox" name="experimental" value="true"
|
<input type="checkbox" name="experimental" value="true"
|
||||||
onchange="this.form.submit()"
|
onchange="this.form.submit()"
|
||||||
{% if show_experimental %}checked{% endif %}>
|
{% if show_experimental %}checked{% endif %}>
|
||||||
<span class="slider"></span>
|
<span class="slider"></span>
|
||||||
</label>
|
</label>
|
||||||
<span class="switch-text">Experimental</span>
|
<span class="switch-text">{{ fluent(key="home-experimental", lang=lang) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden" name="sort" id="sortInput" value="{{ current_sort }}">
|
<input type="hidden" name="sort" id="sortInput" value="{{ current_sort }}">
|
||||||
<input type="hidden" name="order" id="orderInput" value="{{ current_order }}">
|
<input type="hidden" name="order" id="orderInput" value="{{ current_order }}">
|
||||||
|
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label>Sort by:</label>
|
<label>{{ fluent(key="home-sort-by", lang=lang) }}</label>
|
||||||
<div class="dropdown" id="sortDropdown">
|
<div class="dropdown" id="sortDropdown">
|
||||||
<button class="dropdown-trigger select-styled" type="button" onclick="toggleSortDropdown(event)">
|
<button class="dropdown-trigger select-styled" type="button" onclick="toggleSortDropdown(event)">
|
||||||
<span>
|
<span>
|
||||||
{% if current_sort == "score" %}Score
|
{% if current_sort == "score" %}{{ fluent(key="sort-score", lang=lang) }}
|
||||||
{% elif current_sort == "single" %}Single Thread
|
{% elif current_sort == "single" %}{{ fluent(key="sort-single", lang=lang) }}
|
||||||
{% elif current_sort == "multi" %}Multi Thread
|
{% elif current_sort == "multi" %}{{ fluent(key="sort-multi", lang=lang) }}
|
||||||
{% elif current_sort == "ram" %}RAM Amount
|
{% elif current_sort == "ram" %}{{ fluent(key="sort-ram", lang=lang) }}
|
||||||
{% elif current_sort == "threads" %}Thread Count
|
{% elif current_sort == "threads" %}{{ fluent(key="sort-threads", lang=lang) }}
|
||||||
{% elif current_sort == "time" %}Time Ago
|
{% elif current_sort == "time" %}{{ fluent(key="sort-time", lang=lang) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
<i class="fa-solid fa-chevron-down chevron"></i>
|
<i class="fa-solid fa-chevron-down chevron"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<div class="dropdown-header">Sort Benchmarks By</div>
|
<div class="dropdown-header">{{ fluent(key="home-sort-by", lang=lang) }}</div>
|
||||||
<a href="javascript:void(0)" onclick="selectSort('score')">
|
<a href="javascript:void(0)" onclick="selectSort('score')">
|
||||||
<span class="link-title"><i class="fa-solid fa-award fa-fw"></i> Score</span>
|
<span class="link-title"><i class="fa-solid fa-award fa-fw"></i> {{ fluent(key="sort-score", lang=lang) }}</span>
|
||||||
<span class="link-desc">(Singlethread + Multithread) / 2</span>
|
<span class="link-desc">{{ fluent(key="sort-desc-score", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:void(0)" onclick="selectSort('single')">
|
<a href="javascript:void(0)" onclick="selectSort('single')">
|
||||||
<span class="link-title"><i class="fa-solid fa-microchip fa-fw"></i> Singlethread</span>
|
<span class="link-title"><i class="fa-solid fa-microchip fa-fw"></i> {{ fluent(key="sort-single", lang=lang) }}</span>
|
||||||
<span class="link-desc">Single-core efficiency</span>
|
<span class="link-desc">{{ fluent(key="sort-desc-single", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:void(0)" onclick="selectSort('multi')">
|
<a href="javascript:void(0)" onclick="selectSort('multi')">
|
||||||
<span class="link-title"><i class="fa-solid fa-microchip fa-fw"></i> Multithread</span>
|
<span class="link-title"><i class="fa-solid fa-microchip fa-fw"></i> {{ fluent(key="sort-multi", lang=lang) }}</span>
|
||||||
<span class="link-desc">Multi-core efficiency</span>
|
<span class="link-desc">{{ fluent(key="sort-desc-multi", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:void(0)" onclick="selectSort('ram')">
|
<a href="javascript:void(0)" onclick="selectSort('ram')">
|
||||||
<span class="link-title"><i class="fa-solid fa-memory fa-fw"></i> RAM Amount</span>
|
<span class="link-title"><i class="fa-solid fa-memory fa-fw"></i> {{ fluent(key="sort-ram", lang=lang) }}</span>
|
||||||
<span class="link-desc">System memory capacity</span>
|
<span class="link-desc">{{ fluent(key="sort-desc-ram", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:void(0)" onclick="selectSort('threads')">
|
<a href="javascript:void(0)" onclick="selectSort('threads')">
|
||||||
<span class="link-title"><i class="fa-solid fa-microchip fa-fw"></i> Thread Count</span>
|
<span class="link-title"><i class="fa-solid fa-microchip fa-fw"></i> {{ fluent(key="sort-threads", lang=lang) }}</span>
|
||||||
<span class="link-desc">Total logical cores</span>
|
<span class="link-desc">{{ fluent(key="sort-desc-threads", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:void(0)" onclick="selectSort('time')">
|
<a href="javascript:void(0)" onclick="selectSort('time')">
|
||||||
<span class="link-title"><i class="fa-solid fa-clock fa-fw"></i> Time Ago</span>
|
<span class="link-title"><i class="fa-solid fa-clock fa-fw"></i> {{ fluent(key="sort-time", lang=lang) }}</span>
|
||||||
<span class="link-desc">Newest reports first</span>
|
<span class="link-desc">{{ fluent(key="sort-desc-time", lang=lang) }}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<button type="button" class="order-toggle" onclick="toggleOrder()">
|
<button type="button" class="order-toggle" onclick="toggleOrder()">
|
||||||
<span>
|
<span>
|
||||||
{% if current_order == "desc" %}Descending{% else %}Ascending{% endif %}
|
{% if current_order == "desc" %}{{ fluent(key="home-order-desc", lang=lang) }}{% else %}{{ fluent(key="home-order-asc", lang=lang) }}{% endif %}
|
||||||
</span>
|
</span>
|
||||||
<i class="fa-solid {% if current_order == 'desc' %}fa-arrow-down-wide-short{% else %}fa-arrow-up-short-wide{% endif %}"></i>
|
<i class="fa-solid {% if current_order == 'desc' %}fa-arrow-down-wide-short{% else %}fa-arrow-up-short-wide{% endif %}"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -81,13 +81,13 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="rank-header"></th>
|
<th class="rank-header"></th>
|
||||||
<th>CPU Score</th>
|
<th>{{ fluent(key="table-cpu-score", lang=lang) }}</th>
|
||||||
<th>Threads</th>
|
<th>{{ fluent(key="table-threads", lang=lang) }}</th>
|
||||||
<th>RAM</th>
|
<th>{{ fluent(key="table-ram", lang=lang) }}</th>
|
||||||
<th>OS</th>
|
<th>{{ fluent(key="table-os", lang=lang) }}</th>
|
||||||
<th>Hostname</th>
|
<th>{{ fluent(key="table-hostname", lang=lang) }}</th>
|
||||||
<th>Time</th>
|
<th>{{ fluent(key="table-time", lang=lang) }}</th>
|
||||||
<th>Note</th>
|
<th>{{ fluent(key="table-note", lang=lang) }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
<td data-label="Hostname">{{ report.hostname }}</td>
|
<td data-label="Hostname">{{ report.hostname }}</td>
|
||||||
<td data-label="Time">{{ report.time_ago }}
|
<td data-label="Time">{{ report.time_ago }}
|
||||||
{% if report.is_new %}
|
{% if report.is_new %}
|
||||||
<span class="new-badge">NEW</span>
|
<span class="new-badge">{{ fluent(key="badge-new", lang=lang) }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td data-label="Note" class="signature-cell">{{ report.signature }}</td>
|
<td data-label="Note" class="signature-cell">{{ report.signature }}</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user