diff --git a/pagetop/src/app.rs b/pagetop/src/app.rs index ca0fc6be..8e3c75f2 100644 --- a/pagetop/src/app.rs +++ b/pagetop/src/app.rs @@ -33,8 +33,8 @@ impl Application { // Inicia registro de trazas y eventos. LazyStatic::force(&trace::TRACING); - // Valida el identificador de idioma. - LazyStatic::force(&locale::LANGID); + // Valida el identificador global de idioma. + LazyStatic::force(&locale::DEFAULT_LANGID); #[cfg(feature = "database")] // Conecta con la base de datos. diff --git a/pagetop/src/core/component/context.rs b/pagetop/src/core/component/context.rs index a68fe290..dec94143 100644 --- a/pagetop/src/core/component/context.rs +++ b/pagetop/src/core/component/context.rs @@ -1,6 +1,6 @@ use crate::core::module::{all::theme_by_single_name, ThemeStaticRef}; use crate::html::{html, Assets, IdentifierValue, JavaScript, Markup, StyleSheet}; -use crate::locale::{LanguageIdentifier, LANGID}; +use crate::locale::{LanguageIdentifier, DEFAULT_LANGID}; use crate::server::HttpRequest; use crate::{concat_string, config, util, LazyStatic}; @@ -14,6 +14,7 @@ static DEFAULT_THEME: LazyStatic = }); pub enum ContextOp { + LangId(&'static LanguageIdentifier), Theme(&'static str), Request(Option), AddStyleSheet(StyleSheet), @@ -24,7 +25,7 @@ pub enum ContextOp { #[rustfmt::skip] pub struct RenderContext { - language : &'static LanguageIdentifier, + langid : &'static LanguageIdentifier, theme : ThemeStaticRef, request : Option, stylesheets: Assets, @@ -37,7 +38,7 @@ impl Default for RenderContext { #[rustfmt::skip] fn default() -> Self { RenderContext { - language : &LANGID, + langid : &DEFAULT_LANGID, theme : *DEFAULT_THEME, request : None, stylesheets: Assets::::new(), @@ -55,6 +56,9 @@ impl RenderContext { pub fn alter(&mut self, op: ContextOp) -> &mut Self { match op { + ContextOp::LangId(langid) => { + self.langid = langid; + } ContextOp::Theme(theme_name) => { self.theme = theme_by_single_name(theme_name).unwrap_or(*DEFAULT_THEME); } @@ -84,8 +88,8 @@ impl RenderContext { /// Context GETTERS. - pub(crate) fn language(&self) -> &LanguageIdentifier { - self.language + pub(crate) fn langid(&self) -> &LanguageIdentifier { + self.langid } pub(crate) fn theme(&self) -> ThemeStaticRef { diff --git a/pagetop/src/core/component/l10n.rs b/pagetop/src/core/component/l10n.rs index d369ac99..10e504da 100644 --- a/pagetop/src/core/component/l10n.rs +++ b/pagetop/src/core/component/l10n.rs @@ -32,7 +32,7 @@ impl ComponentTrait for L10n { (PreEscaped(translate( self.key(), Locale::Using( - rcx.language(), + rcx.langid(), locales, &self.args().iter().fold(HashMap::new(), |mut args, (key, value)| { args.insert(key.to_string(), value.to_owned().into()); @@ -44,7 +44,7 @@ impl ComponentTrait for L10n { (translate( self.key(), Locale::Using( - rcx.language(), + rcx.langid(), locales, &self.args().iter().fold(HashMap::new(), |mut args, (key, value)| { args.insert(key.to_string(), value.to_owned().into()); diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index da6b498c..f97ed3a6 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -94,47 +94,46 @@ use crate::html::{Markup, PreEscaped}; use crate::{args, config, trace, LazyStatic}; -use unic_langid::langid; - pub use fluent_templates; pub use fluent_templates::fluent_bundle::FluentValue; pub use fluent_templates::{static_loader as static_locale, Loader, StaticLoader as Locales}; -pub use unic_langid::LanguageIdentifier; +pub use unic_langid::{langid, CharacterDirection, LanguageIdentifier}; use std::collections::HashMap; static LANGUAGES: LazyStatic> = LazyStatic::new(|| { args![ "en" => (langid!("en-US"), "English"), - "en-US" => (langid!("en-US"), "English (...)"), + "en-GB" => (langid!("en-GB"), "English (British)"), + "en-US" => (langid!("en-US"), "English (United States)"), "es" => (langid!("es-ES"), "Spanish"), "es-ES" => (langid!("es-ES"), "Spanish (Spain)") ] }); -static DEFAULT_LANGID: LazyStatic = LazyStatic::new(|| langid!("en-US")); +static FALLBACK_LANGID: LazyStatic = LazyStatic::new(|| langid!("en-US")); /// Almacena el Identificador de Idioma Unicode /// ([Unicode Language Identifier](https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) -/// para la aplicación, obtenido de `SETTINGS.app.language`. -pub static LANGID: LazyStatic<&LanguageIdentifier> = - LazyStatic::new( - || match LANGUAGES.get(config::SETTINGS.app.language.as_str()) { - Some((langid, _)) => langid, - _ => { - trace::warn!( - "{}, {} \"{}\"! {}, {}", - "Failed to parse language", - "unrecognized Unicode Language Identifier", - config::SETTINGS.app.language, - "Using \"en-US\"", - "check the settings file", - ); - &*DEFAULT_LANGID - } - }, - ); +/// global para la aplicación a partir de `SETTINGS.app.language`. +pub(crate) static DEFAULT_LANGID: LazyStatic<&LanguageIdentifier> = + LazyStatic::new(|| langid_for(config::SETTINGS.app.language.as_str())); + +pub fn langid_for(language: &str) -> &LanguageIdentifier { + match LANGUAGES.get(language) { + Some((langid, _)) => langid, + _ => { + trace::warn!( + "{} \"{}\"! {}", + "Failed to set language. Unicode Language Identifier", + config::SETTINGS.app.language, + "is not accepted. Using \"en-US\", check the settings file", + ); + &*FALLBACK_LANGID + } + } +} pub enum Locale<'a> { From(&'a Locales), @@ -157,8 +156,8 @@ pub fn e(key: &str, locale: Locale) -> Markup { #[inline] pub(crate) fn translate(key: &str, locale: Locale) -> String { match locale { - Locale::From(locales) => locales.lookup(&LANGID, key), - Locale::With(locales, args) => locales.lookup_with_args(&LANGID, key, args), + Locale::From(locales) => locales.lookup(&DEFAULT_LANGID, key), + Locale::With(locales, args) => locales.lookup_with_args(&DEFAULT_LANGID, key, args), Locale::Using(langid, locales, args) => locales.lookup_with_args(langid, key, args), } .unwrap_or(key.to_string()) diff --git a/pagetop/src/response/page/definition.rs b/pagetop/src/response/page/definition.rs index eae78720..44567fb2 100644 --- a/pagetop/src/response/page/definition.rs +++ b/pagetop/src/response/page/definition.rs @@ -2,43 +2,18 @@ use super::{BeforeRenderPageHook, ResultPage, HOOK_BEFORE_RENDER_PAGE}; use crate::core::component::*; use crate::core::hook::{action_ref, run_actions}; -use crate::html::{html, AttributeValue, Classes, ClassesOp, Favicon, Markup, DOCTYPE}; +use crate::html::{html, Classes, ClassesOp, Favicon, Markup, DOCTYPE}; +use crate::locale::{langid_for, CharacterDirection, LanguageIdentifier}; use crate::response::fatal_error::FatalError; -use crate::{config, fn_builder, locale, server, trace, LazyStatic}; +use crate::{fn_builder, server}; use std::collections::HashMap; -static DEFAULT_DIRECTION: LazyStatic> = LazyStatic::new(|| { - let direction = config::SETTINGS.app.direction.to_lowercase(); - match direction.as_str() { - "auto" => Some("auto".to_owned()), - "ltr" => Some("ltr".to_owned()), - "rtl" => Some("rtl".to_owned()), - "" => None, - _ => { - trace::warn!( - "Text direction \"{}\" not valid, {}", - config::SETTINGS.app.direction, - "check the settings file" - ); - None - } - } -}); - -pub enum TextDirection { - Auto, - LeftToRight, - RightToLeft, -} - type PageTitle = OneComponent; type PageDescription = OneComponent; #[rustfmt::skip] pub struct Page { - language : AttributeValue, - direction : AttributeValue, title : PageTitle, description : PageDescription, metadata : Vec<(&'static str, &'static str)>, @@ -54,11 +29,6 @@ impl Default for Page { #[rustfmt::skip] fn default() -> Self { Page { - language : AttributeValue::new().with_value(locale::LANGID.language.as_str()), - direction : match &*DEFAULT_DIRECTION { - Some(direction) => AttributeValue::new().with_value(direction), - _ => AttributeValue::new(), - }, title : PageTitle::new(), description : PageDescription::new(), metadata : Vec::new(), @@ -82,18 +52,8 @@ impl Page { // Page BUILDER. #[fn_builder] - pub fn alter_language(&mut self, language: &str) -> &mut Self { - self.language.alter_value(language); - self - } - - #[fn_builder] - pub fn alter_direction(&mut self, dir: TextDirection) -> &mut Self { - self.direction.alter_value(match dir { - TextDirection::Auto => "auto", - TextDirection::LeftToRight => "ltr", - TextDirection::RightToLeft => "rtl", - }); + pub fn alter_language(&mut self, language: &'static str) -> &mut Self { + self.context.alter(ContextOp::LangId(langid_for(language))); self } @@ -162,12 +122,8 @@ impl Page { // Page GETTERS. - pub fn language(&self) -> &AttributeValue { - &self.language - } - - pub fn direction(&self) -> &AttributeValue { - &self.direction + pub fn langid(&self) -> &LanguageIdentifier { + &self.context.langid() } pub fn title(&mut self) -> String { @@ -220,9 +176,14 @@ impl Page { let head = self.context.theme().render_page_head(self); // Finalmente, renderizar la página. + let lang = self.langid().language.as_str(); + let dir = match self.langid().character_direction() { + CharacterDirection::LTR => "ltr", + CharacterDirection::RTL => "rtl", + }; Ok(html! { (DOCTYPE) - html lang=[self.language().get()] dir=[self.direction().get()] { + html lang=(lang) dir=(dir) { (head) (body) }