🎨 Nueov enfoque para las funciones de traducción
This commit is contained in:
parent
7691bf4b2f
commit
71b0b0889d
11 changed files with 110 additions and 93 deletions
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
|||
|
||||
define_handle!(MODULE_ADMIN);
|
||||
|
||||
define_locale!("src/locales");
|
||||
define_locale!(LOCALE_ADMIN, "src/locales");
|
||||
|
||||
mod summary;
|
||||
|
||||
|
|
@ -14,11 +14,11 @@ impl ModuleTrait for Admin {
|
|||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
l("module_name")
|
||||
t("module_name", Locale::From(&LOCALE_ADMIN))
|
||||
}
|
||||
|
||||
fn description(&self) -> Option<String> {
|
||||
Some(l("module_description"))
|
||||
Some(t("module_description", Locale::From(&LOCALE_ADMIN)))
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use super::l;
|
||||
use super::LOCALE_ADMIN;
|
||||
use pagetop::prelude::*;
|
||||
use pagetop_megamenu::component::{MegaMenu, MegaMenuItem};
|
||||
use pagetop_minimal::component::*;
|
||||
|
||||
pub async fn summary(request: server::HttpRequest) -> ResultPage<Markup, FatalError> {
|
||||
let top_menu = MegaMenu::new()
|
||||
.with_item(MegaMenuItem::label(l("module_name").as_str()))
|
||||
.with_item(MegaMenuItem::label(
|
||||
t("module_name", Locale::From(&LOCALE_ADMIN)).as_str(),
|
||||
))
|
||||
.with_item(MegaMenuItem::link("Opción 2", "https://www.google.es"))
|
||||
.with_item(MegaMenuItem::link_blank(
|
||||
"Opción 3",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
|||
|
||||
define_handle!(THEME_BOOTSIER);
|
||||
|
||||
define_locale!("src/locales");
|
||||
define_locale!(LOCALE_BOOTSIER, "src/locales");
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bootsier.rs"));
|
||||
|
||||
|
|
@ -53,15 +53,15 @@ impl ThemeTrait for Bootsier {
|
|||
alt="Caution!";
|
||||
div class="media-body" {
|
||||
h1 class="display-4" { ("RESOURCE NOT FOUND") }
|
||||
p class="lead" { (l("e404-description")) }
|
||||
p class="lead" { (t("e404-description", Locale::From(&LOCALE_BOOTSIER))) }
|
||||
hr class="my-4";
|
||||
p { (l("e404-description")) }
|
||||
p { (t("e404-description", Locale::From(&LOCALE_BOOTSIER))) }
|
||||
a
|
||||
class="btn btn-primary btn-lg"
|
||||
href="/"
|
||||
role="button"
|
||||
{
|
||||
(l("back-homepage"))
|
||||
(t("back-homepage", Locale::From(&LOCALE_BOOTSIER)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use pagetop_minimal::component::*;
|
|||
|
||||
define_handle!(MODULE_DEMOHOME);
|
||||
|
||||
define_locale!("src/locales");
|
||||
define_locale!(LOCALE_DEMOHOME, "src/locales");
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/homedemo.rs"));
|
||||
|
||||
|
|
@ -15,11 +15,11 @@ impl ModuleTrait for HomeDemo {
|
|||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
l("module_name")
|
||||
t("module_name", Locale::From(&LOCALE_DEMOHOME))
|
||||
}
|
||||
|
||||
fn description(&self) -> Option<String> {
|
||||
Some(l("module_description"))
|
||||
Some(t("module_description", Locale::From(&LOCALE_DEMOHOME)))
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<ModuleStaticRef> {
|
||||
|
|
@ -34,7 +34,7 @@ impl ModuleTrait for HomeDemo {
|
|||
|
||||
async fn demo(request: server::HttpRequest) -> ResultPage<Markup, FatalError> {
|
||||
Page::new(request)
|
||||
.with_title(l("page_title").as_str())
|
||||
.with_title(t("page_title", Locale::From(&LOCALE_DEMOHOME)).as_str())
|
||||
.with_context(ContextOp::AddStyleSheet(StyleSheet::located(
|
||||
"/homedemo/css/styles.css",
|
||||
)))
|
||||
|
|
@ -56,43 +56,46 @@ fn hello_world() -> Container {
|
|||
.with_size(grid::ColumnSize::Is5of12)
|
||||
.with_component(
|
||||
Heading::h1(html! {
|
||||
(l("page_title"))
|
||||
(t("page_title", Locale::From(&LOCALE_DEMOHOME)))
|
||||
})
|
||||
.with_display(HeadingDisplay::Medium),
|
||||
)
|
||||
.with_component(
|
||||
Paragraph::with(html! {
|
||||
(e("hello_intro", &args![
|
||||
(e("hello_intro", Locale::With(&LOCALE_DEMOHOME, &args![
|
||||
"app" => format!(
|
||||
"<span class=\"app-name\">{}</span>",
|
||||
&config::SETTINGS.app.name,
|
||||
)
|
||||
]))
|
||||
])))
|
||||
})
|
||||
.with_display(ParagraphDisplay::Small),
|
||||
)
|
||||
.with_component(Paragraph::with(html! {
|
||||
(e("hello_powered", &args![
|
||||
(e("hello_powered", Locale::With(&LOCALE_DEMOHOME, &args![
|
||||
"pagetop" => format!(
|
||||
"<a href=\"{}\" target=\"_blank\">{}</a>",
|
||||
"https://pagetop.cillero.es",
|
||||
"PageTop",
|
||||
)
|
||||
]))
|
||||
])))
|
||||
}))
|
||||
.with_component(
|
||||
Anchor::button(
|
||||
"https://github.com/manuelcillero/pagetop",
|
||||
html! { (l("hello_code")) },
|
||||
html! { (t("hello_code", Locale::From(&LOCALE_DEMOHOME))) },
|
||||
)
|
||||
.with_target(AnchorTarget::Blank)
|
||||
.with_left_icon(Icon::with("git"))
|
||||
.with_classes(ClassesOp::Add, "code-link"),
|
||||
)
|
||||
.with_component(
|
||||
Anchor::link("#welcome", html! { (l("hello_welcome")) })
|
||||
.with_left_icon(Icon::with("arrow-down-circle-fill"))
|
||||
.with_classes(ClassesOp::Add, "welcome-link"),
|
||||
Anchor::link(
|
||||
"#welcome",
|
||||
html! { (t("hello_welcome", Locale::From(&LOCALE_DEMOHOME))) },
|
||||
)
|
||||
.with_left_icon(Icon::with("arrow-down-circle-fill"))
|
||||
.with_classes(ClassesOp::Add, "welcome-link"),
|
||||
),
|
||||
)
|
||||
.with_column(
|
||||
|
|
@ -108,26 +111,28 @@ fn welcome() -> Container {
|
|||
.with_id("welcome")
|
||||
.with_classes(ClassesOp::Add, "welcome-col-text")
|
||||
.with_component(Heading::h2(html! {
|
||||
(l("welcome_page"))
|
||||
(t("welcome_page", Locale::From(&LOCALE_DEMOHOME)))
|
||||
}))
|
||||
.with_component(
|
||||
Heading::h3(html! {
|
||||
(e("welcome_subtitle", &args![
|
||||
(e("welcome_subtitle", Locale::With(&LOCALE_DEMOHOME, &args![
|
||||
"app" => format!(
|
||||
"<span class=\"app-name\">{}</span>",
|
||||
&config::SETTINGS.app.name
|
||||
)
|
||||
]))
|
||||
])))
|
||||
})
|
||||
.with_display(HeadingDisplay::Subtitle),
|
||||
)
|
||||
.with_component(
|
||||
Paragraph::with(html! {
|
||||
(l("welcome_text1"))
|
||||
(t("welcome_text1", Locale::From(&LOCALE_DEMOHOME)))
|
||||
})
|
||||
.with_display(ParagraphDisplay::Small),
|
||||
)
|
||||
.with_component(Paragraph::with(html! { (l("welcome_text2")) }))
|
||||
.with_component(Paragraph::with(
|
||||
html! { (t("welcome_text2", Locale::From(&LOCALE_DEMOHOME))) },
|
||||
))
|
||||
}
|
||||
|
||||
fn about_pagetop() -> Container {
|
||||
|
|
@ -143,25 +148,25 @@ fn about_pagetop() -> Container {
|
|||
grid::Column::new()
|
||||
.with_classes(ClassesOp::Add, "pagetop-col-text")
|
||||
.with_component(Heading::h2(html! {
|
||||
(l("pagetop_title"))
|
||||
(t("pagetop_title", Locale::From(&LOCALE_DEMOHOME)))
|
||||
}))
|
||||
.with_component(
|
||||
Paragraph::with(html! {
|
||||
(l("pagetop_text1"))
|
||||
(t("pagetop_text1", Locale::From(&LOCALE_DEMOHOME)))
|
||||
})
|
||||
.with_display(ParagraphDisplay::Small),
|
||||
)
|
||||
.with_component(Paragraph::with(html! {
|
||||
(l("pagetop_text2"))
|
||||
(t("pagetop_text2", Locale::From(&LOCALE_DEMOHOME)))
|
||||
}))
|
||||
.with_component(Paragraph::with(html! {
|
||||
(e("pagetop_text3", &args![
|
||||
(e("pagetop_text3", Locale::With(&LOCALE_DEMOHOME, &args![
|
||||
"pagetop_website" => format!(
|
||||
"<a href=\"{}\" target=\"_blank\">{}</a>",
|
||||
"https://docs.rs/pagetop/latest/pagetop",
|
||||
l("pagetop_website"),
|
||||
t("pagetop_website", Locale::From(&LOCALE_DEMOHOME)),
|
||||
)
|
||||
]))
|
||||
])))
|
||||
})),
|
||||
),
|
||||
)
|
||||
|
|
@ -174,17 +179,17 @@ fn promo_pagetop() -> Container {
|
|||
grid::Column::new()
|
||||
.with_classes(ClassesOp::Add, "promo-col-text")
|
||||
.with_component(Heading::h2(html! {
|
||||
(l("pagetop_promo_title"))
|
||||
(t("pagetop_promo_title", Locale::From(&LOCALE_DEMOHOME)))
|
||||
}))
|
||||
.with_component(
|
||||
Paragraph::with(html! {
|
||||
(e("pagetop_promo_text1", &args![
|
||||
(e("pagetop_promo_text1", Locale::With(&LOCALE_DEMOHOME, &args![
|
||||
"pagetop" => format!(
|
||||
"<a href=\"{}\" target=\"_blank\">{}</a>",
|
||||
"https://crates.io/crates/pagetop",
|
||||
"PageTop",
|
||||
)
|
||||
]))
|
||||
])))
|
||||
})
|
||||
.with_display(ParagraphDisplay::Small),
|
||||
),
|
||||
|
|
@ -211,16 +216,16 @@ fn reporting_issues() -> Container {
|
|||
.with_classes(ClassesOp::Add, "reporting-col-text")
|
||||
.with_size(grid::ColumnSize::Is6of12)
|
||||
.with_component(Heading::h2(html! {
|
||||
(l("report_problems_title"))
|
||||
(t("report_problems_title", Locale::From(&LOCALE_DEMOHOME)))
|
||||
}))
|
||||
.with_component(
|
||||
Paragraph::with(html! {
|
||||
(l("report_problems_text1"))
|
||||
(t("report_problems_text1", Locale::From(&LOCALE_DEMOHOME)))
|
||||
})
|
||||
.with_display(ParagraphDisplay::Small),
|
||||
)
|
||||
.with_component(Paragraph::with(html! {
|
||||
(l("report_problems_text2"))
|
||||
(t("report_problems_text2", Locale::From(&LOCALE_DEMOHOME)))
|
||||
})),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ mod escape;
|
|||
mod generate;
|
||||
mod parse;
|
||||
|
||||
use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||
use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use quote::quote;
|
||||
|
||||
pub fn expand(input: TokenStream) -> TokenStream {
|
||||
|
|
@ -27,7 +27,7 @@ pub fn expand(input: TokenStream) -> TokenStream {
|
|||
),
|
||||
_ => quote!(
|
||||
pagetop::html::PreEscaped(#output_ident)
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
quote!({
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ impl Generator {
|
|||
),
|
||||
_ => quote!(
|
||||
pagetop::html::html_private::render_to!(&#expr, &mut #output_ident);
|
||||
)
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
|||
|
||||
define_handle!(MODULE_MENU);
|
||||
|
||||
define_locale!("src/module/menu/locales");
|
||||
define_locale!(LOCALE_MENU, "src/module/menu/locales");
|
||||
|
||||
pub struct Menu;
|
||||
|
||||
|
|
@ -12,10 +12,10 @@ impl ModuleTrait for Menu {
|
|||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
l("module_name")
|
||||
t("module_name", Locale::From(&LOCALE_MENU))
|
||||
}
|
||||
|
||||
fn description(&self) -> Option<String> {
|
||||
Some(l("module_description"))
|
||||
Some(t("module_description", Locale::From(&LOCALE_MENU)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
|||
|
||||
define_handle!(MODULE_NODE);
|
||||
|
||||
define_locale!("src/locales");
|
||||
define_locale!(LOCALE_NODE, "src/locales");
|
||||
|
||||
//mod entity;
|
||||
mod migration;
|
||||
|
|
@ -15,11 +15,11 @@ impl ModuleTrait for Node {
|
|||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
l("module_name")
|
||||
t("module_name", Locale::From(&LOCALE_NODE))
|
||||
}
|
||||
|
||||
fn description(&self) -> Option<String> {
|
||||
Some(l("module_description"))
|
||||
Some(t("module_description", Locale::From(&LOCALE_NODE)))
|
||||
}
|
||||
|
||||
fn configure_service(&self, cfg: &mut server::web::ServiceConfig) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use pagetop_minimal::component::*;
|
|||
|
||||
define_handle!(MODULE_USER);
|
||||
|
||||
define_locale!("src/locales");
|
||||
define_locale!(LOCALE_USER, "src/locales");
|
||||
|
||||
mod migration;
|
||||
|
||||
|
|
@ -15,11 +15,11 @@ impl ModuleTrait for User {
|
|||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
l("module_name")
|
||||
t("module_name", Locale::From(&LOCALE_USER))
|
||||
}
|
||||
|
||||
fn description(&self) -> Option<String> {
|
||||
Some(l("module_description"))
|
||||
Some(t("module_description", Locale::From(&LOCALE_USER)))
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<ModuleStaticRef> {
|
||||
|
|
@ -58,13 +58,14 @@ fn form_login() -> Form {
|
|||
.with_element(
|
||||
form_element::Input::textfield()
|
||||
.with_name("name")
|
||||
.with_label(l("username").as_str())
|
||||
.with_label(t("username", Locale::From(&LOCALE_USER)).as_str())
|
||||
.with_help_text(
|
||||
t(
|
||||
"username_help",
|
||||
&args![
|
||||
"app" => config::SETTINGS.app.name.to_owned()
|
||||
],
|
||||
Locale::With(
|
||||
&LOCALE_USER,
|
||||
&args!["app" => config::SETTINGS.app.name.to_owned()],
|
||||
),
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
|
|
@ -73,8 +74,10 @@ fn form_login() -> Form {
|
|||
.with_element(
|
||||
form_element::Input::password()
|
||||
.with_name("pass")
|
||||
.with_label(l("password").as_str())
|
||||
.with_help_text(l("password_help").as_str()),
|
||||
.with_label(t("password", Locale::From(&LOCALE_USER)).as_str())
|
||||
.with_help_text(t("password_help", Locale::From(&LOCALE_USER)).as_str()),
|
||||
)
|
||||
.with_element(form_element::Button::submit(l("login").as_str()))
|
||||
.with_element(form_element::Button::submit(
|
||||
t("login", Locale::From(&LOCALE_USER)).as_str(),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,36 +71,36 @@
|
|||
//! Una vez hayas creado tu directorio de recursos FTL, sólo tienes que usar la poderosa macro
|
||||
//! [`define_locale!`](crate::define_locale) para integrar fácilmente tus recursos de localización.
|
||||
//!
|
||||
//! Esta macro crea dos funciones para el ámbito donde se ejecuta. Por un lado la función `l()` para
|
||||
//! traducciones directas de etiquetas. Y por otro la función `t()` para traducciones que requieren
|
||||
//! argumentos:
|
||||
//! Luego sólo tendrás que usar la función `t()` para realizar tus traducciones:
|
||||
//!
|
||||
//! ```
|
||||
//! use pagetop::{args, define_locale};
|
||||
//! use pagetop::{args, define_locale, t};
|
||||
//!
|
||||
//! define_locale!("en-US");
|
||||
//! define_locale!(LOCALE_SAMPLE, "src/locales");
|
||||
//!
|
||||
//! fn demo() {
|
||||
//! println!("* {}", l("hello-world"));
|
||||
//! println!("* {}", t("hello-world", &args![]));
|
||||
//! println!("* {}", t("hello-user", &args!["userName" => "Julia"]));
|
||||
//! println!("* {}", l("hello-world", Locale::From(&LOCALE_SAMPLE)));
|
||||
//! println!("* {}", t("hello-user", Locale::With(&LOCALE_SAMPLE, &args!["userName" => "Julia"])));
|
||||
//!
|
||||
//! let args = args![
|
||||
//! "userName" => "Roberto",
|
||||
//! "photoCount" => 3,
|
||||
//! "userGender" => "male"
|
||||
//! ];
|
||||
//! println!("* {}\n", t("shared-photos", &args));
|
||||
//! println!("* {}\n", t("shared-photos", Locale::With(&LOCALE_SAMPLE, &args)));
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::html::{Markup, PreEscaped};
|
||||
use crate::{config, trace, LazyStatic};
|
||||
|
||||
use unic_langid::LanguageIdentifier;
|
||||
|
||||
pub use fluent_templates;
|
||||
pub use fluent_templates::fluent_bundle::FluentValue;
|
||||
pub use fluent_templates::{static_loader as static_locale, Loader as Locale};
|
||||
pub use fluent_templates::{static_loader as static_locale, Loader, StaticLoader as Locales};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Almacena el Identificador de Idioma Unicode
|
||||
/// ([Unicode Language Identifier](https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier))
|
||||
|
|
@ -124,11 +124,11 @@ pub static LANGID: LazyStatic<LanguageIdentifier> =
|
|||
#[macro_export]
|
||||
/// Define un conjunto de elementos de localización y funciones locales de traducción.
|
||||
macro_rules! define_locale {
|
||||
( $dir_locales:literal $(, $core_locales:literal)? ) => {
|
||||
( $LOCALES:ident, $dir_locales:literal $(, $core_locales:literal)? ) => {
|
||||
use $crate::locale::*;
|
||||
|
||||
static_locale! {
|
||||
static LOCALES = {
|
||||
static $LOCALES = {
|
||||
locales: $dir_locales,
|
||||
$( core_locales: $core_locales, )?
|
||||
fallback_language: "en-US",
|
||||
|
|
@ -137,28 +137,33 @@ macro_rules! define_locale {
|
|||
customise: |bundle| bundle.set_use_isolating(false),
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn l(key: &str) -> String {
|
||||
LOCALES.lookup(&LANGID, key).unwrap_or(key.to_string())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn t(
|
||||
key: &str,
|
||||
args: &std::collections::HashMap<String, FluentValue>
|
||||
) -> String {
|
||||
LOCALES.lookup_with_args(&LANGID, key, args).unwrap_or(key.to_string())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn e(
|
||||
key: &str,
|
||||
args: &std::collections::HashMap<String, FluentValue>
|
||||
) -> $crate::html::PreEscaped<String> {
|
||||
$crate::html::PreEscaped(
|
||||
LOCALES.lookup_with_args(&LANGID, key, args).unwrap_or(key.to_string())
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub enum Locale<'a> {
|
||||
From(&'a Locales),
|
||||
With(&'a Locales, &'a HashMap<String, FluentValue<'a>>),
|
||||
Lang(&'a Locales, &'a LanguageIdentifier),
|
||||
Using(
|
||||
&'a Locales,
|
||||
&'a LanguageIdentifier,
|
||||
&'a HashMap<String, FluentValue<'a>>,
|
||||
),
|
||||
}
|
||||
|
||||
pub fn t(key: &str, locale: Locale) -> String {
|
||||
match locale {
|
||||
Locale::From(locales) => locales.lookup(&LANGID, key).unwrap_or(key.to_string()),
|
||||
Locale::With(locales, args) => locales
|
||||
.lookup_with_args(&LANGID, key, args)
|
||||
.unwrap_or(key.to_string()),
|
||||
Locale::Lang(locales, langid) => locales.lookup(langid, key).unwrap_or(key.to_string()),
|
||||
Locale::Using(locales, langid, args) => locales
|
||||
.lookup_with_args(langid, key, args)
|
||||
.unwrap_or(key.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e(key: &str, locale: Locale) -> Markup {
|
||||
PreEscaped(t(key, locale))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ pub use crate::config;
|
|||
|
||||
pub use crate::trace;
|
||||
|
||||
pub use crate::locale::*;
|
||||
|
||||
pub use crate::html::*;
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue