From 0613278f7a4942a27acd9af7a97d9bcaf1fa1ad3 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sat, 21 Oct 2023 20:33:20 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20code=20removing?= =?UTF-8?q?=20L10n=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/src/base/component.rs | 4 +- pagetop/src/base/component/anchor.rs | 9 +- pagetop/src/base/component/block.rs | 10 +- pagetop/src/base/component/branding.rs | 30 ++--- pagetop/src/base/component/form/button.rs | 13 +- pagetop/src/base/component/form/input.rs | 19 ++- pagetop/src/base/component/heading.rs | 20 ++-- pagetop/src/base/component/l10n.rs | 119 ------------------- pagetop/src/base/component/menu/item.rs | 31 +++-- pagetop/src/base/component/menu/menu_main.rs | 3 +- pagetop/src/base/component/menu/submenu.rs | 9 +- pagetop/src/base/component/paragraph.rs | 14 ++- pagetop/src/base/component/powered_by.rs | 23 ++-- pagetop/src/base/component/translate.rs | 40 +++++++ pagetop/src/core/module/definition.rs | 2 +- pagetop/src/response/fatal_error.rs | 2 +- pagetop/src/response/page.rs | 29 ++--- 17 files changed, 148 insertions(+), 229 deletions(-) delete mode 100644 pagetop/src/base/component/l10n.rs create mode 100644 pagetop/src/base/component/translate.rs diff --git a/pagetop/src/base/component.rs b/pagetop/src/base/component.rs index 4fa00504..6ce6c84f 100644 --- a/pagetop/src/base/component.rs +++ b/pagetop/src/base/component.rs @@ -82,8 +82,8 @@ impl ToString for BreakPoint { mod html; pub use html::{Html, COMPONENT_BASE_HTML}; -mod l10n; -pub use l10n::{L10n, COMPONENT_BASE_L10N}; +mod translate; +pub use translate::{Translate, COMPONENT_BASE_TRANSLATE}; mod wrapper; pub use wrapper::{Wrapper, WrapperType, COMPONENT_BASE_WRAPPER}; diff --git a/pagetop/src/base/component/anchor.rs b/pagetop/src/base/component/anchor.rs index b632b91c..4c302db7 100644 --- a/pagetop/src/base/component/anchor.rs +++ b/pagetop/src/base/component/anchor.rs @@ -21,7 +21,6 @@ pub enum AnchorTarget { } type AnchorIcon = TypedComponent; -type AnchorHtml = TypedComponent; #[rustfmt::skip] #[derive(Default)] @@ -32,7 +31,7 @@ pub struct Anchor { classes : OptionClasses, anchor_type: AnchorType, href : OptionString, - html : AnchorHtml, + html : OptionTranslate, left_icon : AnchorIcon, right_icon : AnchorIcon, target : AnchorTarget, @@ -77,7 +76,7 @@ impl ComponentTrait for Anchor { target=[target] { (self.left_icon().prepare(cx)) - " " span { (self.html().prepare(cx)) } " " + " " span { (self.html().escaped(cx.langid())) } " " (self.right_icon().prepare(cx)) } }) @@ -147,7 +146,7 @@ impl Anchor { #[fn_builder] pub fn alter_html(&mut self, html: L10n) -> &mut Self { - self.html.set(html); + self.html.alter_value(html); self } @@ -189,7 +188,7 @@ impl Anchor { &self.href } - pub fn html(&self) -> &AnchorHtml { + pub fn html(&self) -> &OptionTranslate { &self.html } diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index f74314a3..60cb01fa 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -4,8 +4,6 @@ new_handle!(COMPONENT_BASE_BLOCK); actions_for_component!(Block); -type BlockTitle = TypedComponent; - #[rustfmt::skip] #[derive(Default)] pub struct Block { @@ -13,7 +11,7 @@ pub struct Block { renderable: Renderable, id : OptionId, classes : OptionClasses, - title : BlockTitle, + title : OptionTranslate, stuff : ArcComponents, template : String, } @@ -47,7 +45,7 @@ impl ComponentTrait for Block { let id = cx.required_id::(self.id()); PrepareMarkup::With(html! { div id=(id) class=[self.classes().get()] { - @if let Some(title) = self.title().get().into_string(cx) { + @if let Some(title) = self.title().using(cx.langid()) { h2 class="block-title" { (title) } } div class="block-body" { @@ -91,7 +89,7 @@ impl Block { #[fn_builder] pub fn alter_title(&mut self, title: L10n) -> &mut Self { - self.title.set(title); + self.title.alter_value(title); self } @@ -118,7 +116,7 @@ impl Block { &self.classes } - pub fn title(&self) -> &BlockTitle { + pub fn title(&self) -> &OptionTranslate { &self.title } diff --git a/pagetop/src/base/component/branding.rs b/pagetop/src/base/component/branding.rs index 07725875..4804abe3 100644 --- a/pagetop/src/base/component/branding.rs +++ b/pagetop/src/base/component/branding.rs @@ -1,17 +1,15 @@ use crate::prelude::*; -use crate::LOCALES_PAGETOP; new_handle!(COMPONENT_BASE_BRANDING); -type SiteSlogan = TypedComponent; type SiteLogo = TypedComponent; #[rustfmt::skip] pub struct Branding { weight : Weight, renderable: Renderable, - name : String, - slogan : SiteSlogan, + app_name : String, + slogan : OptionTranslate, logo : SiteLogo, frontpage : FnContextualPath, } @@ -22,8 +20,8 @@ impl Default for Branding { Branding { weight : Weight::default(), renderable: Renderable::default(), - name : config::SETTINGS.app.name.to_owned(), - slogan : SiteSlogan::default(), + app_name : config::SETTINGS.app.name.to_owned(), + slogan : OptionTranslate::default(), logo : SiteLogo::default(), frontpage : |_| "/", } @@ -52,8 +50,8 @@ impl ComponentTrait for Branding { } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let title = L10n::t("site_home", &LOCALES_PAGETOP).prepare(cx); - let slogan = self.slogan().prepare(cx); + let title = L10n::l("site_home").using(cx.langid()); + let slogan = self.slogan().using(cx.langid()).unwrap_or_default(); PrepareMarkup::With(html! { div id=[self.id()] { div class="pt-branding__wrapper" { @@ -62,7 +60,9 @@ impl ComponentTrait for Branding { } div class="pt-branding__text" { div class="pt-branding__name" { - a href=(self.frontpage()(cx)) title=(title) rel="home" { (self.name()) } + a href=(self.frontpage()(cx)) title=[title] rel="home" { + (self.app_name()) + } } @if !slogan.is_empty() { div class="pt-branding__slogan" { @@ -92,14 +92,14 @@ impl Branding { } #[fn_builder] - pub fn alter_name(&mut self, name: impl Into) -> &mut Self { - self.name = name.into(); + pub fn alter_app_name(&mut self, app_name: impl Into) -> &mut Self { + self.app_name = app_name.into(); self } #[fn_builder] pub fn alter_slogan(&mut self, slogan: L10n) -> &mut Self { - self.slogan = SiteSlogan::with(slogan); + self.slogan.alter_value(slogan); self } @@ -117,11 +117,11 @@ impl Branding { // Branding GETTERS. - pub fn name(&self) -> &String { - &self.name + pub fn app_name(&self) -> &String { + &self.app_name } - pub fn slogan(&self) -> &SiteSlogan { + pub fn slogan(&self) -> &OptionTranslate { &self.slogan } diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index 7cb6b498..98f4fba6 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -10,8 +10,6 @@ pub enum ButtonType { Reset, } -type ButtonValue = TypedComponent; - #[rustfmt::skip] #[derive(Default)] pub struct Button { @@ -20,7 +18,7 @@ pub struct Button { classes : OptionClasses, button_type: ButtonType, name : OptionString, - value : ButtonValue, + value : OptionTranslate, autofocus : OptionString, disabled : OptionString, template : String, @@ -50,18 +48,17 @@ impl ComponentTrait for Button { ButtonType::Reset => "reset", }; let id = self.name().get().map(|name| concat_string!("edit-", name)); - let value = self.value().prepare(cx); PrepareMarkup::With(html! { button type=(button_type) id=[id] class=[self.classes().get()] name=[self.name().get()] - value=(value) + value=[self.value().using(cx.langid())] autofocus=[self.autofocus().get()] disabled=[self.disabled().get()] { - (value) + (self.value().escaped(cx.langid())) } }) } @@ -116,7 +113,7 @@ impl Button { #[fn_builder] pub fn alter_value(&mut self, value: L10n) -> &mut Self { - self.value.set(value); + self.value.alter_value(value); self } @@ -158,7 +155,7 @@ impl Button { &self.name } - pub fn value(&self) -> &ButtonValue { + pub fn value(&self) -> &OptionTranslate { &self.value } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index d5ec5a00..f7668079 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -13,9 +13,6 @@ pub enum InputType { Url, } -type InputLabel = TypedComponent; -type InputHelpText = TypedComponent; - #[rustfmt::skip] #[derive(Default)] pub struct Input { @@ -25,7 +22,7 @@ pub struct Input { input_type : InputType, name : OptionName, value : OptionString, - label : InputLabel, + label : OptionTranslate, size : Option, minlength : Option, maxlength : Option, @@ -35,7 +32,7 @@ pub struct Input { disabled : OptionString, readonly : OptionString, required : OptionString, - help_text : InputHelpText, + help_text : OptionTranslate, template : String, } @@ -70,8 +67,8 @@ impl ComponentTrait for Input { InputType::Url => "url", }; let id = self.name().get().map(|name| concat_string!("edit-", name)); - let label = self.label().prepare(cx); - let description = self.help_text().prepare(cx); + let label = self.label().using(cx.langid()).unwrap_or_default(); + let description = self.help_text().using(cx.langid()).unwrap_or_default(); PrepareMarkup::With(html! { div class=[self.classes().get()] { @if !label.is_empty() { @@ -195,7 +192,7 @@ impl Input { #[fn_builder] pub fn alter_label(&mut self, label: L10n) -> &mut Self { - self.label.set(label); + self.label.alter_value(label); self } @@ -270,7 +267,7 @@ impl Input { #[fn_builder] pub fn alter_help_text(&mut self, help_text: L10n) -> &mut Self { - self.help_text.set(help_text); + self.help_text.alter_value(help_text); self } @@ -298,7 +295,7 @@ impl Input { &self.value } - pub fn label(&self) -> &InputLabel { + pub fn label(&self) -> &OptionTranslate { &self.label } @@ -338,7 +335,7 @@ impl Input { &self.required } - pub fn help_text(&self) -> &InputHelpText { + pub fn help_text(&self) -> &OptionTranslate { &self.help_text } diff --git a/pagetop/src/base/component/heading.rs b/pagetop/src/base/component/heading.rs index 449073c9..dc9e7aa9 100644 --- a/pagetop/src/base/component/heading.rs +++ b/pagetop/src/base/component/heading.rs @@ -25,8 +25,6 @@ pub enum HeadingDisplay { Subtitle, } -type HeadingText = TypedComponent; - #[rustfmt::skip] #[derive(Default)] pub struct Heading { @@ -35,7 +33,7 @@ pub struct Heading { id : OptionId, classes : OptionClasses, heading_type: HeadingType, - text : HeadingText, + text : OptionTranslate, display : HeadingDisplay, template : String, } @@ -65,12 +63,12 @@ impl ComponentTrait for Heading { let id = self.id(); let classes = self.classes().get(); PrepareMarkup::With(html! { @match &self.heading_type() { - HeadingType::H1 => h1 id=[id] class=[classes] { (self.text().prepare(cx)) }, - HeadingType::H2 => h2 id=[id] class=[classes] { (self.text().prepare(cx)) }, - HeadingType::H3 => h3 id=[id] class=[classes] { (self.text().prepare(cx)) }, - HeadingType::H4 => h4 id=[id] class=[classes] { (self.text().prepare(cx)) }, - HeadingType::H5 => h5 id=[id] class=[classes] { (self.text().prepare(cx)) }, - HeadingType::H6 => h6 id=[id] class=[classes] { (self.text().prepare(cx)) }, + HeadingType::H1 => h1 id=[id] class=[classes] { (self.text().escaped(cx.langid())) }, + HeadingType::H2 => h2 id=[id] class=[classes] { (self.text().escaped(cx.langid())) }, + HeadingType::H3 => h3 id=[id] class=[classes] { (self.text().escaped(cx.langid())) }, + HeadingType::H4 => h4 id=[id] class=[classes] { (self.text().escaped(cx.langid())) }, + HeadingType::H5 => h5 id=[id] class=[classes] { (self.text().escaped(cx.langid())) }, + HeadingType::H6 => h6 id=[id] class=[classes] { (self.text().escaped(cx.langid())) }, }}) } } @@ -146,7 +144,7 @@ impl Heading { #[fn_builder] pub fn alter_text(&mut self, text: L10n) -> &mut Self { - self.text.set(text); + self.text.alter_value(text); self } @@ -185,7 +183,7 @@ impl Heading { &self.heading_type } - pub fn text(&self) -> &HeadingText { + pub fn text(&self) -> &OptionTranslate { &self.text } diff --git a/pagetop/src/base/component/l10n.rs b/pagetop/src/base/component/l10n.rs deleted file mode 100644 index eab57bf3..00000000 --- a/pagetop/src/base/component/l10n.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::prelude::*; - -use std::collections::HashMap; - -new_handle!(COMPONENT_BASE_L10N); - -#[derive(Default)] -pub enum L10nOp { - #[default] - None, - Text(&'static str), - Translated(&'static str, &'static Locales), - Escaped(&'static str, &'static Locales), -} - -#[derive(Default)] -pub struct L10n { - op: L10nOp, - args: HashMap<&'static str, String>, -} - -impl ComponentTrait for L10n { - fn new() -> Self { - L10n::default() - } - - fn handle(&self) -> Handle { - COMPONENT_BASE_L10N - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - match self.op() { - L10nOp::None => PrepareMarkup::None, - L10nOp::Text(text) => PrepareMarkup::Text(text), - L10nOp::Translated(key, locales) => PrepareMarkup::With(html! { - (locales - .lookup_with_args( - cx.langid(), - key, - &self.args().iter().fold(HashMap::new(), |mut args, (key, value)| { - args.insert(key.to_string(), value.to_owned().into()); - args - }) - ) - .unwrap_or(key.to_string()) - ) - }), - L10nOp::Escaped(key, locales) => PrepareMarkup::With(html! { - (PreEscaped(locales - .lookup_with_args( - cx.langid(), - key, - &self.args().iter().fold(HashMap::new(), |mut args, (key, value)| { - args.insert(key.to_string(), value.to_owned().into()); - args - }) - ) - .unwrap_or(key.to_string()) - )) - }), - } - } -} - -impl L10n { - pub fn n(text: &'static str) -> Self { - L10n { - op: L10nOp::Text(text), - ..Default::default() - } - } - - pub fn t(key: &'static str, locales: &'static Locales) -> Self { - L10n { - op: L10nOp::Translated(key, locales), - ..Default::default() - } - } - - pub fn e(key: &'static str, locales: &'static Locales) -> Self { - L10n { - op: L10nOp::Escaped(key, locales), - ..Default::default() - } - } - - // L10n BUILDER. - - #[fn_builder] - pub fn alter_op(&mut self, op: L10nOp) -> &mut Self { - self.op = op; - self - } - - #[fn_builder] - pub fn alter_arg(&mut self, arg: &'static str, value: impl Into) -> &mut Self { - self.args.insert(arg, value.into()); - self - } - - pub fn clear_args(&mut self) -> &mut Self { - self.args.drain(); - self - } - - // L10n GETTERS. - - pub fn op(&self) -> &L10nOp { - &self.op - } - - pub fn args(&self) -> &HashMap<&str, String> { - &self.args - } - - pub fn into_string(&self, cx: &mut Context) -> Option { - self.prepare_component(cx).into_string() - } -} diff --git a/pagetop/src/base/component/menu/item.rs b/pagetop/src/base/component/menu/item.rs index 5e16fdd5..546fdf4f 100644 --- a/pagetop/src/base/component/menu/item.rs +++ b/pagetop/src/base/component/menu/item.rs @@ -4,11 +4,10 @@ use super::{Megamenu, Submenu}; new_handle!(COMPONENT_BASE_MENU_ITEM); -type Label = TypedComponent; +type Label = L10n; type Content = TypedComponent; type SubmenuItems = TypedComponent; type MegamenuGroups = TypedComponent; -type Description = TypedComponent; #[derive(Default)] pub enum ItemType { @@ -30,7 +29,7 @@ pub struct Item { weight : Weight, renderable : Renderable, item_type : ItemType, - description: Description, + description: OptionTranslate, } impl ComponentTrait for Item { @@ -51,27 +50,27 @@ impl ComponentTrait for Item { } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let description = self.description.get().into_string(cx); + let description = self.description.using(cx.langid()); match self.item_type() { ItemType::Void => PrepareMarkup::None, ItemType::Label(label) => PrepareMarkup::With(html! { li class="pt-menu__label" { span title=[description] { - (label.prepare(cx)) + (label.escaped(cx.langid())) } } }), ItemType::Link(label, path) => PrepareMarkup::With(html! { li class="pt-menu__link" { a href=(path(cx)) title=[description] { - (label.prepare(cx)) + (label.escaped(cx.langid())) } } }), ItemType::LinkBlank(label, path) => PrepareMarkup::With(html! { li class="pt-menu__link" { a href=(path(cx)) title=[description] target="_blank" { - (label.prepare(cx)) + (label.escaped(cx.langid())) } } }), @@ -83,7 +82,7 @@ impl ComponentTrait for Item { ItemType::Submenu(label, submenu) => PrepareMarkup::With(html! { li class="pt-menu__children" { a href="#" title=[description] { - (label.prepare(cx)) i class="pt-menu__icon bi-chevron-down" {} + (label.escaped(cx.langid())) i class="pt-menu__icon bi-chevron-down" {} } div class="pt-menu__subs" { (submenu.prepare(cx)) @@ -93,7 +92,7 @@ impl ComponentTrait for Item { ItemType::Megamenu(label, megamenu) => PrepareMarkup::With(html! { li class="pt-menu__children" { a href="#" title=[description] { - (label.prepare(cx)) i class="pt-menu__icon bi-chevron-down" {} + (label.escaped(cx.langid())) i class="pt-menu__icon bi-chevron-down" {} } div class="pt-menu__subs pt-menu__mega" { (megamenu.prepare(cx)) @@ -107,21 +106,21 @@ impl ComponentTrait for Item { impl Item { pub fn label(label: L10n) -> Self { Item { - item_type: ItemType::Label(Label::with(label)), + item_type: ItemType::Label(label), ..Default::default() } } pub fn link(label: L10n, path: FnContextualPath) -> Self { Item { - item_type: ItemType::Link(Label::with(label), path), + item_type: ItemType::Link(label, path), ..Default::default() } } pub fn link_blank(label: L10n, path: FnContextualPath) -> Self { Item { - item_type: ItemType::LinkBlank(Label::with(label), path), + item_type: ItemType::LinkBlank(label, path), ..Default::default() } } @@ -135,14 +134,14 @@ impl Item { pub fn submenu(label: L10n, submenu: Submenu) -> Self { Item { - item_type: ItemType::Submenu(Label::with(label), SubmenuItems::with(submenu)), + item_type: ItemType::Submenu(label, SubmenuItems::with(submenu)), ..Default::default() } } pub fn megamenu(label: L10n, megamenu: Megamenu) -> Self { Item { - item_type: ItemType::Megamenu(Label::with(label), MegamenuGroups::with(megamenu)), + item_type: ItemType::Megamenu(label, MegamenuGroups::with(megamenu)), ..Default::default() } } @@ -163,7 +162,7 @@ impl Item { #[fn_builder] pub fn alter_description(&mut self, text: L10n) -> &mut Self { - self.description.set(text); + self.description.alter_value(text); self } @@ -173,7 +172,7 @@ impl Item { &self.item_type } - pub fn description(&self) -> &Description { + pub fn description(&self) -> &OptionTranslate { &self.description } } diff --git a/pagetop/src/base/component/menu/menu_main.rs b/pagetop/src/base/component/menu/menu_main.rs index 1dbad575..04767626 100644 --- a/pagetop/src/base/component/menu/menu_main.rs +++ b/pagetop/src/base/component/menu/menu_main.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use crate::LOCALES_PAGETOP; use super::Item; @@ -68,7 +67,7 @@ impl ComponentTrait for Menu { button type="button" class="pt-menu__trigger" - title=[L10n::t("menu_toggle", &LOCALES_PAGETOP).into_string(cx)] + title=[L10n::l("menu_toggle").using(cx.langid())] { span {} span {} span {} } diff --git a/pagetop/src/base/component/menu/submenu.rs b/pagetop/src/base/component/menu/submenu.rs index 37eff01d..07ff5504 100644 --- a/pagetop/src/base/component/menu/submenu.rs +++ b/pagetop/src/base/component/menu/submenu.rs @@ -4,7 +4,6 @@ use super::Item; new_handle!(COMPONENT_BASE_MENU_SUBMENU); -type TitleSubmenu = TypedComponent; type Items = TypedComponents; #[rustfmt::skip] @@ -13,7 +12,7 @@ pub struct Submenu { weight : Weight, renderable: Renderable, id : OptionId, - title : TitleSubmenu, + title : OptionTranslate, items : Items, } @@ -41,7 +40,7 @@ impl ComponentTrait for Submenu { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { div id=[self.id()] class="pt-menu__items" { - @if let Some(title) = self.title().get().into_string(cx) { + @if let Some(title) = self.title().using(cx.langid()) { h4 class="pt-menu__title" { (title) } } ul { @@ -75,7 +74,7 @@ impl Submenu { #[fn_builder] pub fn alter_title(&mut self, title: L10n) -> &mut Self { - self.title.set(title); + self.title.alter_value(title); self } @@ -92,7 +91,7 @@ impl Submenu { // Submenu GETTERS. - pub fn title(&self) -> &TitleSubmenu { + pub fn title(&self) -> &OptionTranslate { &self.title } diff --git a/pagetop/src/base/component/paragraph.rs b/pagetop/src/base/component/paragraph.rs index b804d2a5..39d54a8c 100644 --- a/pagetop/src/base/component/paragraph.rs +++ b/pagetop/src/base/component/paragraph.rs @@ -60,7 +60,11 @@ impl ComponentTrait for Paragraph { impl Paragraph { pub fn with(component: impl ComponentTrait) -> Self { - Paragraph::new().with_component(component) + Paragraph::new().add_component(component) + } + + pub fn translated(l10n: L10n) -> Self { + Paragraph::new().add_translated(l10n) } // Paragraph BUILDER. @@ -89,11 +93,17 @@ impl Paragraph { self } - pub fn with_component(mut self, component: impl ComponentTrait) -> Self { + pub fn add_component(mut self, component: impl ComponentTrait) -> Self { self.stuff.alter(ArcOp::Add(ArcComponent::with(component))); self } + pub fn add_translated(mut self, l10n: L10n) -> Self { + self.stuff + .alter(ArcOp::Add(ArcComponent::with(Translate::with(l10n)))); + self + } + #[fn_builder] pub fn alter_components(&mut self, op: ArcOp) -> &mut Self { self.stuff.alter(op); diff --git a/pagetop/src/base/component/powered_by.rs b/pagetop/src/base/component/powered_by.rs index e3b03262..8600a402 100644 --- a/pagetop/src/base/component/powered_by.rs +++ b/pagetop/src/base/component/powered_by.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use crate::LOCALES_PAGETOP; new_handle!(COMPONENT_BASE_POWEREDBY); @@ -51,10 +50,10 @@ impl ComponentTrait for PoweredBy { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { let logo = match self.logo() { PoweredByLogo::Color => { - let logo_txt = L10n::t("pagetop_logo", &LOCALES_PAGETOP); + let logo_txt = &L10n::l("pagetop_logo").using(cx.langid()); html! { - span class="pt-pagetop__logo" aria-label=[logo_txt.into_string(cx)] { - img src="/base/pagetop-logo.svg" alt=[logo_txt.into_string(cx)] {} + span class="pt-pagetop__logo" aria-label=[logo_txt] { + img src="/base/pagetop-logo.svg" alt=[logo_txt] {} } } } @@ -64,17 +63,19 @@ impl ComponentTrait for PoweredBy { _ => html! {}, }; - let mut credits = L10n::e("poweredby_pagetop", &LOCALES_PAGETOP).with_arg( - "pagetop_link", - "PageTop", - ); + let credits = L10n::l("poweredby_pagetop") + .with_arg( + "pagetop_link", + "PageTop", + ) + .escaped(cx.langid()); PrepareMarkup::With(html! { div id=[self.id()] { @if let Some(c) = self.copyright() { span class="copyright" { (c) "." } " " } - span class="powered" { (credits.prepare(cx)) " " (logo) } + span class="powered" { (credits) " " (logo) } } }) } @@ -120,10 +121,10 @@ impl PoweredBy { // PoweredBy PRIVATE. fn logo_line(&self, r: u8, g: u8, b: u8, cx: &mut Context) -> Markup { - let logo_txt = L10n::t("pagetop_logo", &LOCALES_PAGETOP); + let logo_txt = L10n::l("pagetop_logo").using(cx.langid()); let logo_rgb = format!("rgb({},{},{})", r, g, b); html! { - span class="pt-pagetop__logo" aria-label=[logo_txt.into_string(cx)] { + span class="pt-pagetop__logo" aria-label=[logo_txt] { svg viewBox="0 0 1614 1614" xmlns="http://www.w3.org/2000/svg" role="img" { path fill=(logo_rgb) d="M 1573,357 L 1415,357 C 1400,357 1388,369 1388,383 L 1388,410 1335,410 1335,357 C 1335,167 1181,13 992,13 L 621,13 C 432,13 278,167 278,357 L 278,410 225,410 225,383 C 225,369 213,357 198,357 L 40,357 C 25,357 13,369 13,383 L 13,648 C 13,662 25,674 40,674 L 198,674 C 213,674 225,662 225,648 L 225,621 278,621 278,1256 C 278,1446 432,1600 621,1600 L 992,1600 C 1181,1600 1335,1446 1335,1256 L 1335,621 1388,621 1388,648 C 1388,662 1400,674 1415,674 L 1573,674 C 1588,674 1600,662 1600,648 L 1600,383 C 1600,369 1588,357 1573,357 L 1573,357 1573,357 Z M 66,410 L 172,410 172,621 66,621 66,410 66,410 Z M 1282,357 L 1282,488 C 1247,485 1213,477 1181,464 L 1196,437 C 1203,425 1199,409 1186,401 1174,394 1158,398 1150,411 L 1133,440 C 1105,423 1079,401 1056,376 L 1075,361 C 1087,352 1089,335 1079,324 1070,313 1054,311 1042,320 L 1023,335 C 1000,301 981,263 967,221 L 1011,196 C 1023,189 1028,172 1021,160 1013,147 997,143 984,150 L 953,168 C 945,136 941,102 940,66 L 992,66 C 1152,66 1282,197 1282,357 L 1282,357 1282,357 Z M 621,66 L 674,66 674,225 648,225 C 633,225 621,237 621,251 621,266 633,278 648,278 L 674,278 674,357 648,357 C 633,357 621,369 621,383 621,398 633,410 648,410 L 674,410 674,489 648,489 C 633,489 621,501 621,516 621,530 633,542 648,542 L 664,542 C 651,582 626,623 600,662 583,653 563,648 542,648 469,648 410,707 410,780 410,787 411,794 412,801 388,805 361,806 331,806 L 331,357 C 331,197 461,66 621,66 L 621,66 621,66 Z M 621,780 C 621,824 586,859 542,859 498,859 463,824 463,780 463,736 498,701 542,701 586,701 621,736 621,780 L 621,780 621,780 Z M 225,463 L 278,463 278,569 225,569 225,463 225,463 Z M 992,1547 L 621,1547 C 461,1547 331,1416 331,1256 L 331,859 C 367,859 400,858 431,851 454,888 495,912 542,912 615,912 674,853 674,780 674,747 662,718 642,695 675,645 706,594 720,542 L 780,542 C 795,542 807,530 807,516 807,501 795,489 780,489 L 727,489 727,410 780,410 C 795,410 807,398 807,383 807,369 795,357 780,357 L 727,357 727,278 780,278 C 795,278 807,266 807,251 807,237 795,225 780,225 L 727,225 727,66 887,66 C 889,111 895,155 905,196 L 869,217 C 856,224 852,240 859,253 864,261 873,266 882,266 887,266 891,265 895,263 L 921,248 C 937,291 958,331 983,367 L 938,403 C 926,412 925,429 934,440 939,447 947,450 954,450 960,450 966,448 971,444 L 1016,408 C 1043,438 1074,465 1108,485 L 1084,527 C 1076,539 1081,555 1093,563 1098,565 1102,566 1107,566 1116,566 1125,561 1129,553 L 1155,509 C 1194,527 1237,538 1282,541 L 1282,1256 C 1282,1416 1152,1547 992,1547 L 992,1547 992,1547 Z M 1335,463 L 1388,463 1388,569 1335,569 1335,463 1335,463 Z M 1441,410 L 1547,410 1547,621 1441,621 1441,410 1441,410 Z" {} path fill=(logo_rgb) d="M 1150,1018 L 463,1018 C 448,1018 436,1030 436,1044 L 436,1177 C 436,1348 545,1468 701,1468 L 912,1468 C 1068,1468 1177,1348 1177,1177 L 1177,1044 C 1177,1030 1165,1018 1150,1018 L 1150,1018 1150,1018 Z M 912,1071 L 1018,1071 1018,1124 912,1124 912,1071 912,1071 Z M 489,1071 L 542,1071 542,1124 489,1124 489,1071 489,1071 Z M 701,1415 L 700,1415 C 701,1385 704,1352 718,1343 731,1335 759,1341 795,1359 802,1363 811,1363 818,1359 854,1341 882,1335 895,1343 909,1352 912,1385 913,1415 L 912,1415 701,1415 701,1415 701,1415 Z M 1124,1177 C 1124,1296 1061,1384 966,1408 964,1365 958,1320 922,1298 894,1281 856,1283 807,1306 757,1283 719,1281 691,1298 655,1320 649,1365 647,1408 552,1384 489,1296 489,1177 L 569,1177 C 583,1177 595,1165 595,1150 L 595,1071 859,1071 859,1150 C 859,1165 871,1177 886,1177 L 1044,1177 C 1059,1177 1071,1165 1071,1150 L 1071,1071 1124,1071 1124,1177 1124,1177 1124,1177 Z" {} diff --git a/pagetop/src/base/component/translate.rs b/pagetop/src/base/component/translate.rs new file mode 100644 index 00000000..0e658172 --- /dev/null +++ b/pagetop/src/base/component/translate.rs @@ -0,0 +1,40 @@ +use crate::prelude::*; + +new_handle!(COMPONENT_BASE_TRANSLATE); + +#[derive(Default)] +pub struct Translate(L10n); + +impl ComponentTrait for Translate { + fn new() -> Self { + Translate::default() + } + + fn handle(&self) -> Handle { + COMPONENT_BASE_TRANSLATE + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(self.l10n().escaped(cx.langid())) + } +} + +impl Translate { + pub fn with(l10n: L10n) -> Self { + Translate(l10n) + } + + // Translate BUILDER. + + #[fn_builder] + pub fn alter_l10n(&mut self, l10n: L10n) -> &mut Self { + self.0 = l10n; + self + } + + // Translate GETTERS. + + pub fn l10n(&self) -> &L10n { + &self.0 + } +} diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index b81fe75d..dd7f9d30 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -1,6 +1,6 @@ -use crate::base::component::L10n; use crate::core::action::Action; use crate::core::theme::ThemeRef; +use crate::locale::L10n; use crate::{actions, service, util, Handle}; #[cfg(feature = "database")] diff --git a/pagetop/src/response/fatal_error.rs b/pagetop/src/response/fatal_error.rs index 3994b91c..7c2fce9f 100644 --- a/pagetop/src/response/fatal_error.rs +++ b/pagetop/src/response/fatal_error.rs @@ -3,7 +3,7 @@ pub use error403::ERROR_403; mod error404; pub use error404::ERROR_404; -use crate::base::component::L10n; +use crate::locale::L10n; use crate::response::{page::Page, ResponseError}; use crate::service::http::{header::ContentType, StatusCode}; use crate::service::{HttpRequest, HttpResponse}; diff --git a/pagetop/src/response/page.rs b/pagetop/src/response/page.rs index 7398d9f1..efdd60fe 100644 --- a/pagetop/src/response/page.rs +++ b/pagetop/src/response/page.rs @@ -1,9 +1,11 @@ use crate::base::action::page::{run_actions_after_prepare_body, run_actions_before_prepare_body}; -use crate::base::component::L10n; -use crate::core::component::{ArcComponent, ComponentTrait, TypedComponent}; +use crate::core::component::{ArcComponent, ComponentTrait}; use crate::core::component::{Context, ContextOp}; use crate::core::theme::ComponentsRegions; -use crate::html::{html, ClassesOp, Favicon, Markup, OptionClasses, OptionId, DOCTYPE}; +use crate::html::{ + html, ClassesOp, Favicon, Markup, OptionClasses, OptionId, OptionTranslate, DOCTYPE, +}; +use crate::locale::L10n; use crate::response::fatal_error::FatalError; use crate::{fn_builder, service}; @@ -11,13 +13,10 @@ use unic_langid::CharacterDirection; pub use actix_web::Result as ResultPage; -type PageTitle = TypedComponent; -type PageDescription = TypedComponent; - #[rustfmt::skip] pub struct Page { - title : PageTitle, - description : PageDescription, + title : OptionTranslate, + description : OptionTranslate, metadata : Vec<(&'static str, &'static str)>, properties : Vec<(&'static str, &'static str)>, favicon : Option, @@ -31,8 +30,8 @@ impl Page { #[rustfmt::skip] pub fn new(request: service::HttpRequest) -> Self { Page { - title : PageTitle::new(), - description : PageDescription::new(), + title : OptionTranslate::new(), + description : OptionTranslate::new(), metadata : Vec::new(), properties : Vec::new(), favicon : None, @@ -47,13 +46,13 @@ impl Page { #[fn_builder] pub fn alter_title(&mut self, title: L10n) -> &mut Self { - self.title.set(title); + self.title.alter_value(title); self } #[fn_builder] pub fn alter_description(&mut self, description: L10n) -> &mut Self { - self.description.set(description); + self.description.alter_value(description); self } @@ -102,11 +101,13 @@ impl Page { // Page GETTERS. pub fn title(&mut self) -> String { - self.title.prepare(&mut self.context).into_string() + self.title.using(self.context.langid()).unwrap_or_default() } pub fn description(&mut self) -> String { - self.description.prepare(&mut self.context).into_string() + self.description + .using(self.context.langid()) + .unwrap_or_default() } pub fn metadata(&self) -> &Vec<(&str, &str)> {