From ea22b4ce7a2a089eb3824870561e555c65a2eb1b Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sat, 19 Apr 2025 21:40:47 +0200 Subject: start on localization --- server/src/routes/locale.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ server/src/routes/mod.rs | 1 + server/src/routes/ui/home.rs | 25 +++++++++++--------- 3 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 server/src/routes/locale.rs (limited to 'server/src') diff --git a/server/src/routes/locale.rs b/server/src/routes/locale.rs new file mode 100644 index 0000000..cdf25d5 --- /dev/null +++ b/server/src/routes/locale.rs @@ -0,0 +1,54 @@ +use jellybase::locale::Language; +use rocket::{ + outcome::Outcome, + request::{self, FromRequest}, + Request, +}; +use std::ops::Deref; + +pub struct AcceptLanguage(pub Language); +impl Deref for AcceptLanguage { + type Target = Language; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl<'r> FromRequest<'r> for AcceptLanguage { + type Error = (); + + fn from_request<'life0, 'async_trait>( + request: &'r Request<'life0>, + ) -> ::core::pin::Pin< + Box< + dyn ::core::future::Future> + + ::core::marker::Send + + 'async_trait, + >, + > + where + 'r: 'async_trait, + 'life0: 'async_trait, + Self: 'async_trait, + { + Box::pin(async move { + Outcome::Success(AcceptLanguage( + request + .headers() + .get_one("accept-language") + .and_then(|h| { + h.split(",") + .filter_map(|e| { + let code = e.split(";").next()?; + let code = code.split_once("-").unwrap_or((code, "")).0; + match code { + "en" => Some(Language::English), + _ => None, + } + }) + .next() + }) + .unwrap_or(Language::English), + )) + }) + } +} diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index e909e15..90fa16d 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -68,6 +68,7 @@ pub mod playersync; pub mod stream; pub mod ui; pub mod userdata; +pub mod locale; #[macro_export] macro_rules! uri { diff --git a/server/src/routes/ui/home.rs b/server/src/routes/ui/home.rs index 3e002ee..ec28c7a 100644 --- a/server/src/routes/ui/home.rs +++ b/server/src/routes/ui/home.rs @@ -12,12 +12,13 @@ use crate::{ database::Database, routes::{ api::AcceptJson, + locale::AcceptLanguage, ui::{error::MyResult, layout::DynLayoutPage}, }, }; use anyhow::Context; use chrono::{Datelike, Utc}; -use jellybase::CONF; +use jellybase::{locale::tr, CONF}; use jellycommon::{api::ApiHomeResponse, user::WatchedState, NodeID, NodeKind, Rating, Visibility}; use rocket::{get, serde::json::Json, Either, State}; @@ -26,7 +27,9 @@ pub fn r_home( sess: Session, db: &State, aj: AcceptJson, + lang: AcceptLanguage, ) -> MyResult>> { + let AcceptLanguage(lang) = lang; let mut items = db.list_nodes_with_udata(&sess.user.name)?; let mut toplevel = db @@ -40,7 +43,7 @@ pub fn r_home( let mut categories = Vec::<(String, Vec<_>)>::new(); categories.push(( - "Continue Watching".to_string(), + tr(lang, "home.bin.continue_watching", &[]).to_string(), items .iter() .filter(|(_, u)| matches!(u.watched, WatchedState::Progress(_))) @@ -48,7 +51,7 @@ pub fn r_home( .collect(), )); categories.push(( - "Your Watchlist".to_string(), + tr(lang, "home.bin.watchlist", &[]).to_string(), items .iter() .filter(|(_, u)| matches!(u.watched, WatchedState::Pending)) @@ -61,7 +64,7 @@ pub fn r_home( items.sort_by_key(|(n, _)| n.release_date.map(|d| -d).unwrap_or(i64::MAX)); categories.push(( - "Latest in Videos".to_string(), + tr(lang, "home.bin.latest_video", &[]).to_string(), items .iter() .filter(|(n, _)| matches!(n.kind, NodeKind::Video)) @@ -70,7 +73,7 @@ pub fn r_home( .collect(), )); categories.push(( - "Latest in Music".to_string(), + tr(lang, "home.bin.latest_music", &[]).to_string(), items .iter() .filter(|(n, _)| matches!(n.kind, NodeKind::Music)) @@ -79,7 +82,7 @@ pub fn r_home( .collect(), )); categories.push(( - "Latest in Short form".to_string(), + tr(lang, "home.bin.latest_short_form", &[]).to_string(), items .iter() .filter(|(n, _)| matches!(n.kind, NodeKind::ShortFormVideo)) @@ -96,7 +99,7 @@ pub fn r_home( }); categories.push(( - "Top Rated".to_string(), + tr(lang, "home.bin.max_rating", &[]).to_string(), items .iter() .take(16) @@ -113,7 +116,7 @@ pub fn r_home( }); categories.push(( - "Today's Picks".to_string(), + tr(lang, "home.bin.daily_random", &[]).to_string(), (0..16) .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) .collect(), @@ -123,7 +126,7 @@ pub fn r_home( let mut items = items.clone(); items.retain(|(_, u)| matches!(u.watched, WatchedState::Watched)); categories.push(( - "Watch again".to_string(), + tr(lang, "home.bin.watch_again", &[]).to_string(), (0..16) .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) .collect(), @@ -132,7 +135,7 @@ pub fn r_home( items.retain(|(n, _)| matches!(n.kind, NodeKind::Music)); categories.push(( - "Discover Music".to_string(), + tr(lang, "home.bin.daily_random_music", &[]).to_string(), (0..16) .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) .collect(), @@ -145,7 +148,7 @@ pub fn r_home( })) } else { Either::Left(LayoutPage { - title: "Home".to_string(), + title: tr(lang, "home", &[]).to_string(), content: markup::new! { h2 { "Explore " @CONF.brand } ul.children.hlist {@for (node, udata) in &toplevel { -- cgit v1.2.3-70-g09d2