🍻 Tercera revista a las traducciones por contexto
This commit is contained in:
parent
88d6ce2a72
commit
dd443ca375
21 changed files with 415 additions and 252 deletions
|
|
@ -4,6 +4,9 @@ pub use context::{ContextOp, RenderContext};
|
|||
mod definition;
|
||||
pub use definition::{component_mut, component_ref, AnyComponent, BaseComponent, ComponentTrait};
|
||||
|
||||
mod default;
|
||||
pub(crate) use default::DefaultComponent;
|
||||
|
||||
mod arc;
|
||||
pub use arc::ComponentArc;
|
||||
|
||||
|
|
@ -19,3 +22,6 @@ pub use renderable::{IsRenderable, Renderable};
|
|||
|
||||
mod html_markup;
|
||||
pub use html_markup::HtmlMarkup;
|
||||
|
||||
mod l10n;
|
||||
pub use l10n::L10n;
|
||||
|
|
|
|||
|
|
@ -1,32 +1,45 @@
|
|||
use crate::core::component::{ComponentTrait, RenderContext};
|
||||
use crate::core::component::{ComponentTrait, DefaultComponent, RenderContext};
|
||||
use crate::html::{html, Markup};
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ComponentArc(Option<Arc<RwLock<dyn ComponentTrait>>>);
|
||||
#[derive(Clone)]
|
||||
pub struct ComponentArc(Arc<RwLock<dyn ComponentTrait>>);
|
||||
|
||||
impl Default for ComponentArc {
|
||||
fn default() -> Self {
|
||||
ComponentArc(Arc::new(RwLock::new(DefaultComponent)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentArc {
|
||||
pub fn new(component: impl ComponentTrait) -> Self {
|
||||
ComponentArc(Some(Arc::new(RwLock::new(component))))
|
||||
pub fn new() -> Self {
|
||||
ComponentArc::default()
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, component: impl ComponentTrait) {
|
||||
self.0 = Some(Arc::new(RwLock::new(component)));
|
||||
pub fn new_with(component: impl ComponentTrait) -> Self {
|
||||
ComponentArc(Arc::new(RwLock::new(component)))
|
||||
}
|
||||
|
||||
pub fn set(&mut self, component: impl ComponentTrait) {
|
||||
self.0 = Arc::new(RwLock::new(component));
|
||||
}
|
||||
|
||||
pub fn weight(&self) -> isize {
|
||||
match &self.0 {
|
||||
Some(component) => component.read().unwrap().weight(),
|
||||
_ => 0,
|
||||
}
|
||||
self.0.read().unwrap().weight()
|
||||
}
|
||||
|
||||
// ComponentArc RENDER.
|
||||
|
||||
pub fn render(&self, rcx: &mut RenderContext) -> Markup {
|
||||
html! {
|
||||
@if let Some(component) = &self.0 {
|
||||
(component.write().unwrap().render(rcx))
|
||||
}
|
||||
self.0.write().unwrap().render(rcx)
|
||||
}
|
||||
|
||||
pub fn optional_render(&self, rcx: &mut RenderContext) -> Option<Markup> {
|
||||
let render = self.0.write().unwrap().render(rcx).into_string();
|
||||
if !render.trim().is_empty() {
|
||||
return Some(html! { (render) });
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl ComponentsBundle {
|
|||
}
|
||||
|
||||
pub fn add(&mut self, component: impl ComponentTrait) {
|
||||
self.0.push(ComponentArc::new(component));
|
||||
self.0.push(ComponentArc::new_with(component));
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
|
|
|
|||
18
pagetop/src/core/component/default.rs
Normal file
18
pagetop/src/core/component/default.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use crate::core::component::{AnyComponent, ComponentTrait};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DefaultComponent;
|
||||
|
||||
impl ComponentTrait for DefaultComponent {
|
||||
fn new() -> Self {
|
||||
DefaultComponent::default()
|
||||
}
|
||||
|
||||
fn as_ref_any(&self) -> &dyn AnyComponent {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_mut_any(&mut self) -> &mut dyn AnyComponent {
|
||||
self
|
||||
}
|
||||
}
|
||||
138
pagetop/src/core/component/l10n.rs
Normal file
138
pagetop/src/core/component/l10n.rs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
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.language(),
|
||||
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.language(),
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
use super::ModuleTrait;
|
||||
|
||||
use crate::config;
|
||||
use crate::core::component::{ComponentTrait, RenderContext};
|
||||
use crate::html::{html, Favicon, Markup};
|
||||
use crate::response::page::Page;
|
||||
use crate::{concat_string, config};
|
||||
|
||||
pub type ThemeStaticRef = &'static dyn ThemeTrait;
|
||||
|
||||
|
|
@ -17,20 +17,21 @@ pub trait ThemeTrait: ModuleTrait + Send + Sync {
|
|||
}
|
||||
|
||||
fn render_page_head(&self, page: &mut Page) -> Markup {
|
||||
let title = page.title();
|
||||
let description = page.description();
|
||||
let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no";
|
||||
html! {
|
||||
head {
|
||||
meta charset="utf-8";
|
||||
|
||||
@match page.title().get() {
|
||||
Some(t) => title {
|
||||
(concat_string!(config::SETTINGS.app.name, " | ", t))
|
||||
},
|
||||
None => title { (config::SETTINGS.app.name) }
|
||||
@if !title.is_empty() {
|
||||
title { (config::SETTINGS.app.name) (" | ") (title) }
|
||||
} @else {
|
||||
title { (config::SETTINGS.app.name) }
|
||||
}
|
||||
|
||||
@if let Some(d) = page.description().get() {
|
||||
meta name="description" content=(d);
|
||||
@if !description.is_empty() {
|
||||
meta name="description" content=(description);
|
||||
}
|
||||
|
||||
meta name="viewport" content=(viewport);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ pub use error403::ERROR_403;
|
|||
mod error404;
|
||||
pub use error404::ERROR_404;
|
||||
|
||||
use crate::core::component::L10n;
|
||||
use crate::response::{page::Page, ResponseError};
|
||||
use crate::server::http::{header::ContentType, StatusCode};
|
||||
use crate::server::{HttpRequest, HttpResponse};
|
||||
|
|
@ -31,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("Error FORBIDDEN")
|
||||
.with_title(L10n::n("Error FORBIDDEN"))
|
||||
.with_this_in("region-content", error403::Error403)
|
||||
.with_template("error")
|
||||
.render()
|
||||
|
|
@ -45,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("Error RESOURCE NOT FOUND")
|
||||
.with_title(L10n::n("Error RESOURCE NOT FOUND"))
|
||||
.with_this_in("region-content", error404::Error404)
|
||||
.with_template("error")
|
||||
.render()
|
||||
|
|
|
|||
|
|
@ -32,12 +32,15 @@ pub enum TextDirection {
|
|||
RightToLeft,
|
||||
}
|
||||
|
||||
pub type PageTitle = ComponentArc;
|
||||
pub type PageDescription = ComponentArc;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub struct Page {
|
||||
language : AttributeValue,
|
||||
direction : AttributeValue,
|
||||
title : AttributeValue,
|
||||
description : AttributeValue,
|
||||
title : PageTitle,
|
||||
description : PageDescription,
|
||||
metadata : Vec<(&'static str, &'static str)>,
|
||||
properties : Vec<(&'static str, &'static str)>,
|
||||
favicon : Option<Favicon>,
|
||||
|
|
@ -56,8 +59,8 @@ impl Default for Page {
|
|||
Some(direction) => AttributeValue::new().with_value(direction),
|
||||
_ => AttributeValue::new(),
|
||||
},
|
||||
title : AttributeValue::new(),
|
||||
description : AttributeValue::new(),
|
||||
title : PageTitle::new(),
|
||||
description : PageDescription::new(),
|
||||
metadata : Vec::new(),
|
||||
properties : Vec::new(),
|
||||
favicon : None,
|
||||
|
|
@ -95,14 +98,14 @@ impl Page {
|
|||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn alter_title(&mut self, title: &str) -> &mut Self {
|
||||
self.title.alter_value(title);
|
||||
pub fn alter_title(&mut self, title: L10n) -> &mut Self {
|
||||
self.title.set(title);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn alter_description(&mut self, description: &str) -> &mut Self {
|
||||
self.description.alter_value(description);
|
||||
pub fn alter_description(&mut self, description: L10n) -> &mut Self {
|
||||
self.description.set(description);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -167,12 +170,12 @@ impl Page {
|
|||
&self.direction
|
||||
}
|
||||
|
||||
pub fn title(&self) -> &AttributeValue {
|
||||
&self.title
|
||||
pub fn title(&mut self) -> String {
|
||||
self.title.render(&mut self.context).into_string()
|
||||
}
|
||||
|
||||
pub fn description(&self) -> &AttributeValue {
|
||||
&self.description
|
||||
pub fn description(&mut self) -> String {
|
||||
self.description.render(&mut self.context).into_string()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> &Vec<(&str, &str)> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue