Añade componentes básicos traducibles Html/Text

This commit is contained in:
Manuel Cillero 2023-05-30 19:13:13 +02:00
parent 6c76e3519c
commit 1d83bbc80a
20 changed files with 243 additions and 369 deletions

View file

@ -17,8 +17,6 @@ pub(crate) use all::common_components;
mod renderable;
pub use renderable::{IsRenderable, Renderable};
mod html_markup;
pub use html_markup::HtmlMarkup;
mod l10n;
pub use l10n::L10n;
mod basic;
pub use basic::{Html, COMPONENT_HTML};
pub use basic::{Text, COMPONENT_TEXT};

View file

@ -0,0 +1,143 @@
use crate::core::component::{AnyComponent, ComponentTrait, RenderContext};
use crate::html::{html, Markup, PreEscaped};
use crate::locale::{translate, Locale, Locales};
use crate::{define_handle, fn_builder, paste, Handle};
use std::collections::HashMap;
macro_rules! basic_components {
( $($COMPONENT_HANDLE:ident: $Component:ty => $TypeValue:ty),* ) => { $( paste! {
define_handle!($COMPONENT_HANDLE);
pub enum [< $Component Op >] {
None,
Value($TypeValue),
Translated(&'static str, &'static Locales),
Escaped(&'static str, &'static Locales),
}
pub struct $Component {
op: [< $Component Op >],
args: HashMap<&'static str, String>,
}
impl Default for $Component {
fn default() -> Self {
$Component {
op: [< $Component Op >]::None,
args: HashMap::new(),
}
}
}
impl ComponentTrait for $Component {
fn new() -> Self {
$Component::default()
}
fn handle(&self) -> Handle {
$COMPONENT_HANDLE
}
fn default_render(&self, rcx: &mut RenderContext) -> Markup {
match self.op() {
[< $Component Op >]::None => html! {},
[< $Component Op >]::Value(value) => html! { (value) },
[< $Component Op >]::Translated(key, locales) => html! {
(translate(
key,
Locale::Using(
rcx.langid(),
locales,
&self.args().iter().fold(HashMap::new(), |mut args, (key, value)| {
args.insert(key.to_string(), value.to_owned().into());
args
})
)
))
},
[< $Component Op >]::Escaped(key, locales) => html! {
(PreEscaped(translate(
key,
Locale::Using(
rcx.langid(),
locales,
&self.args().iter().fold(HashMap::new(), |mut args, (key, value)| {
args.insert(key.to_string(), value.to_owned().into());
args
})
)
)))
},
}
}
fn as_ref_any(&self) -> &dyn AnyComponent {
self
}
fn as_mut_any(&mut self) -> &mut dyn AnyComponent {
self
}
}
impl $Component {
pub fn n(value: $TypeValue) -> Self {
$Component {
op: [< $Component Op >]::Value(value),
..Default::default()
}
}
pub fn t(key: &'static str, locales: &'static Locales) -> Self {
$Component {
op: [< $Component Op >]::Translated(key, locales),
..Default::default()
}
}
pub fn e(key: &'static str, locales: &'static Locales) -> Self {
$Component {
op: [< $Component Op >]::Escaped(key, locales),
..Default::default()
}
}
// $Component BUILDER.
#[fn_builder]
pub fn alter_op(&mut self, op: [< $Component Op >]) -> &mut Self {
self.op = op;
self
}
#[fn_builder]
pub fn alter_arg(&mut self, arg: &'static str, value: String) -> &mut Self {
self.args.insert(arg, value);
self
}
pub fn clear_args(&mut self) -> &mut Self {
self.args.drain();
self
}
// $Component GETTERS.
pub fn op(&self) -> &[< $Component Op >] {
&self.op
}
pub fn args(&self) -> &HashMap<&str, String> {
&self.args
}
}
} )* };
}
basic_components!(
COMPONENT_HTML: Html => Markup,
COMPONENT_TEXT: Text => &'static str
);

View file

@ -1,46 +0,0 @@
use crate::core::component::{AnyComponent, ComponentTrait, RenderContext};
use crate::html::{html, Markup};
use crate::{define_handle, Handle};
define_handle!(HTML_MARKUP);
pub struct HtmlMarkup {
pub markup: Markup,
}
impl Default for HtmlMarkup {
fn default() -> Self {
HtmlMarkup { markup: html! {} }
}
}
impl ComponentTrait for HtmlMarkup {
fn new() -> Self {
HtmlMarkup::default()
}
fn handle(&self) -> Handle {
HTML_MARKUP
}
fn default_render(&self, _rcx: &mut RenderContext) -> Markup {
html! {
(self.markup)
}
}
fn as_ref_any(&self) -> &dyn AnyComponent {
self
}
fn as_mut_any(&mut self) -> &mut dyn AnyComponent {
self
}
}
impl HtmlMarkup {
pub fn with(mut self, html: Markup) -> Self {
self.markup = html;
self
}
}

View file

@ -1,138 +0,0 @@
use crate::core::component::{AnyComponent, ComponentTrait, RenderContext};
use crate::html::{html, Markup, PreEscaped};
use crate::locale::{translate, Locale, Locales};
use crate::{define_handle, fn_builder, Handle};
use std::collections::HashMap;
define_handle!(COMPONENT_L10N);
#[rustfmt::skip]
#[derive(Default)]
pub struct L10n {
key : &'static str,
locales: Option<&'static Locales>,
args : HashMap<&'static str, String>,
escaped: bool,
}
impl ComponentTrait for L10n {
fn new() -> Self {
L10n::default()
}
fn handle(&self) -> Handle {
COMPONENT_L10N
}
fn default_render(&self, rcx: &mut RenderContext) -> Markup {
if let Some(locales) = self.locales() {
html! {
@if self.escaped() {
(PreEscaped(translate(
self.key(),
Locale::Using(
rcx.langid(),
locales,
&self.args().iter().fold(HashMap::new(), |mut args, (key, value)| {
args.insert(key.to_string(), value.to_owned().into());
args
})
)
)))
} @else {
(translate(
self.key(),
Locale::Using(
rcx.langid(),
locales,
&self.args().iter().fold(HashMap::new(), |mut args, (key, value)| {
args.insert(key.to_string(), value.to_owned().into());
args
})
)
))
}
}
} else {
html! { (self.key()) }
}
}
fn as_ref_any(&self) -> &dyn AnyComponent {
self
}
fn as_mut_any(&mut self) -> &mut dyn AnyComponent {
self
}
}
impl L10n {
pub fn n(text: &'static str) -> Self {
L10n {
key: text,
..Default::default()
}
}
pub fn t(key: &'static str, locales: &'static Locales) -> Self {
L10n {
key,
locales: Some(locales),
..Default::default()
}
}
pub fn e(key: &'static str, locales: &'static Locales) -> Self {
L10n {
key,
locales: Some(locales),
escaped: true,
..Default::default()
}
}
// HtmL10n BUILDER.
#[fn_builder]
pub fn alter_key(&mut self, key: &'static str) -> &mut Self {
self.key = key;
self
}
#[fn_builder]
pub fn alter_locales(&mut self, locales: &'static Locales) -> &mut Self {
self.locales = Some(locales);
self
}
#[fn_builder]
pub fn alter_arg(&mut self, arg: &'static str, value: String) -> &mut Self {
self.args.insert(arg, value);
self
}
pub fn clear_args(&mut self) -> &mut Self {
self.args.drain();
self
}
// HtmL10n GETTERS.
pub fn key(&self) -> &str {
self.key
}
pub fn locales(&self) -> Option<&Locales> {
self.locales
}
pub fn args(&self) -> &HashMap<&str, String> {
&self.args
}
pub fn escaped(&self) -> bool {
self.escaped
}
}

View file

@ -94,8 +94,9 @@
//! println!("* {}\n", _t("shared-photos", Locale::With(&LOCALE_SAMPLE, &args)));
//! }
//! ```
//! Aunque normalmente usarás el componente [L10n](crate::core::component::L10n) para añadir textos
//! traducibles en las respuestas web según el contexto del renderizado.
//! Aunque preferirás usar normalmente los componentes básicos [Text](crate::core::component::Text)
//! y [Html](crate::core::component::Html) para incluir, en respuestas a las peticiones web, textos
//! y contenidos opcionalmente traducibles según el contexto de renderizado.
use crate::html::{Markup, PreEscaped};
use crate::{args, config, trace, LazyStatic};

View file

@ -3,7 +3,7 @@ pub use error403::ERROR_403;
mod error404;
pub use error404::ERROR_404;
use crate::core::component::L10n;
use crate::core::component::Text;
use crate::response::{page::Page, ResponseError};
use crate::server::http::{header::ContentType, StatusCode};
use crate::server::{HttpRequest, HttpResponse};
@ -32,7 +32,7 @@ impl fmt::Display for FatalError {
FatalError::AccessDenied(request) => {
let error_page = Page::new(request.clone());
if let Ok(page) = error_page
.with_title(L10n::n("Error FORBIDDEN"))
.with_title(Text::n("Error FORBIDDEN"))
.with_this_in("region-content", error403::Error403)
.with_template("error")
.render()
@ -46,7 +46,7 @@ impl fmt::Display for FatalError {
FatalError::NotFound(request) => {
let error_page = Page::new(request.clone());
if let Ok(page) = error_page
.with_title(L10n::n("Error RESOURCE NOT FOUND"))
.with_title(Text::n("Error RESOURCE NOT FOUND"))
.with_this_in("region-content", error404::Error404)
.with_template("error")
.render()

View file

@ -11,8 +11,8 @@ use unic_langid::CharacterDirection;
use std::collections::HashMap;
type PageTitle = OneComponent<L10n>;
type PageDescription = OneComponent<L10n>;
type PageTitle = OneComponent<Text>;
type PageDescription = OneComponent<Text>;
#[rustfmt::skip]
pub struct Page {
@ -60,13 +60,13 @@ impl Page {
}
#[fn_builder]
pub fn alter_title(&mut self, title: L10n) -> &mut Self {
pub fn alter_title(&mut self, title: Text) -> &mut Self {
self.title.set(title);
self
}
#[fn_builder]
pub fn alter_description(&mut self, description: L10n) -> &mut Self {
pub fn alter_description(&mut self, description: Text) -> &mut Self {
self.description.set(description);
self
}