🚧 Code tweak

This commit is contained in:
Manuel Cillero 2024-11-29 14:45:35 +01:00
parent 4e4d372255
commit f3ee4e2413
2 changed files with 43 additions and 53 deletions

View file

@ -3,13 +3,9 @@
//! These settings are loaded from [TOML](https://toml.io) files as `key = value` pairs and mapped
//! into type-safe structures with predefined values.
//!
//! The [Twelve-Factor App](https://12factor.net/config) methodology defines **application
//! configuration as everything that varies across deployments**, such as development, staging,
//! or production environments.
//!
//! Storing configuration values as code constants violates this methodology. `PageTop` advocates
//! for a **strict separation between code and configuration**, ensuring configuration varies per
//! deployment while the code remains constant.
//! Following the [Twelve-Factor App](https://12factor.net/config) methodology, `PageTop` separates
//! code from configuration. This approach allows configurations to vary across deployments, such as
//! development, staging, or production, without changing the codebase.
//!
//!
//! # Loading configuration settings
@ -20,22 +16,32 @@
//! `PageTop` automatically loads configuration settings by reading the following TOML files in
//! order (all files are optional):
//!
//! 1. **config/common.toml**: Contains settings shared across all environments. These values can be
//! overridden by the subsequent files.
//! 1. **config/common.toml**, for settings shared across all environments. This approach simplifies
//! maintenance by centralizing common configuration values.
//!
//! 2. **config/{file}.toml**, where `{file}` corresponds to the environment variable
//! 2. **config/{rm}.toml**, where `{rm}` corresponds to the environment variable
//! `PAGETOP_RUN_MODE`:
//!
//! * If `PAGETOP_RUN_MODE` is not set, it defaults to `default`, and `PageTop` attempts to load
//! *config/default.toml* if available.
//!
//! * This enables separate configurations for environments like *devel.toml*, *staging.toml*,
//! or *production.toml*, or setups such as *server1.toml*. Only one file will be loaded.
//! * Useful for environment-specific configurations, ensuring that each environment
//! (e.g., development, staging, production) has its own settings without affecting others,
//! such as API keys, URLs, or performance-related adjustments.
//!
//! * These files are suitable for storing sensitive values like passwords. Avoid committing
//! them to Git for security reasons.
//! 3. **config/local.{rm}.toml**, useful for local machine-specific configurations:
//!
//! 3. **config/local.toml**: Used to add or override settings from the previous files.
//! * This file allows you to add or override settings specific to the environment. For example,
//! `local.devel.toml` for development or `local.production.toml` for production tweaks.
//!
//! * It enables developers to tailor settings for their machines within a given environment and
//! is typically not shared or committed to version control systems.
//!
//! 4. **config/local.toml**, for general local settings across all environments, ideal for quick
//! adjustments or temporary values not tied to any specific environment.
//!
//! The configuration settings are merged in the order listed above, with later files overriding
//! earlier ones if there are conflicts.
//!
//!
//! # Adding configuration settings
@ -128,8 +134,8 @@ use std::sync::LazyLock;
use std::env;
use std::path::Path;
/// Original configuration values in `key = value` pairs gathered from configuration files.
pub static CONFIG_DATA: LazyLock<ConfigData> = LazyLock::new(|| {
/// Original values read from configuration files in `key = value` pairs.
pub static CONFIG_VALUES: LazyLock<ConfigData> = LazyLock::new(|| {
// Identify the configuration directory.
let config_dir = env::var("CARGO_MANIFEST_DIR")
.map(|manifest_dir| {
@ -145,11 +151,11 @@ pub static CONFIG_DATA: LazyLock<ConfigData> = LazyLock::new(|| {
// Execution mode based on the environment variable PAGETOP_RUN_MODE, defaults to 'default'.
let rm = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| "default".into());
// Initialize settings.
let mut settings = ConfigData::default();
// Initialize config values.
let mut values = ConfigData::default();
// Merge (optional) configuration files and set the execution mode.
settings
values
// First, add the common configuration for all environments. Defaults to 'common.toml'.
.merge(File::with_name(&concat_string!(config_dir, "/common.toml")).required(false))
.expect("Failed to merge common configuration (common.toml)")
@ -159,14 +165,14 @@ pub static CONFIG_DATA: LazyLock<ConfigData> = LazyLock::new(|| {
// Add reserved local configuration for the environment. Defaults to 'local.default.toml'.
.merge(File::with_name(&concat_string!(config_dir, "/local.", rm, ".toml")).required(false))
.expect("Failed to merge reserved local environment configuration")
// Add the general reserved local configuration. Defaults to 'local.toml'.
// Add common reserved local configuration. Defaults to 'local.toml'.
.merge(File::with_name(&concat_string!(config_dir, "/local.toml")).required(false))
.expect("Failed to merge general reserved local configuration")
// Save the execution mode.
.set("app.run_mode", rm)
.expect("Failed to set application run mode");
settings
values
});
#[macro_export]
@ -177,7 +183,7 @@ macro_rules! include_config {
"[`", stringify!($Settings), "`] type."
)]
pub static $SETTINGS: std::sync::LazyLock<$Settings> = std::sync::LazyLock::new(|| {
let mut settings = $crate::config::CONFIG_DATA.clone();
let mut settings = $crate::config::CONFIG_VALUES.clone();
$(
settings.set_default($key, $value).unwrap();
)*

View file

@ -96,7 +96,6 @@ use fluent_templates::StaticLoader as Locales;
use unic_langid::langid;
use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::LazyLock;
@ -195,12 +194,13 @@ enum L10nOp {
#[derive(AutoDefault)]
pub struct L10n {
op: L10nOp,
locales: Option<&'static Locales>,
#[default(&LOCALES_PAGETOP)]
locales: &'static Locales,
args: HashMap<String, FluentValue<'static>>,
}
impl L10n {
pub fn n<S: Into<Cow<'static, str>>>(text: S) -> Self {
pub fn n(text: impl Into<String>) -> Self {
L10n {
op: L10nOp::Text(text.into().to_string()),
..Default::default()
@ -210,7 +210,6 @@ impl L10n {
pub fn l(key: impl Into<String>) -> Self {
L10n {
op: L10nOp::Translate(key.into()),
locales: Some(&LOCALES_PAGETOP),
..Default::default()
}
}
@ -218,7 +217,7 @@ impl L10n {
pub fn t(key: impl Into<String>, locales: &'static Locales) -> Self {
L10n {
op: L10nOp::Translate(key.into()),
locales: Some(locales),
locales,
..Default::default()
}
}
@ -229,23 +228,13 @@ impl L10n {
self
}
pub fn add_args(mut self, args: HashMap<String, String>) -> Self {
pub fn with_args(mut self, args: HashMap<String, String>) -> Self {
for (k, v) in args {
self.args.insert(k, FluentValue::from(v));
}
self
}
pub fn with_count(mut self, key: impl Into<String>, count: usize) -> Self {
self.args.insert(key.into(), FluentValue::from(count));
self
}
pub fn with_date(mut self, key: impl Into<String>, date: impl Into<String>) -> Self {
self.args.insert(key.into(), FluentValue::from(date.into()));
self
}
pub fn get(&self) -> Option<String> {
self.using(&DEFAULT_LANGID)
}
@ -254,29 +243,24 @@ impl L10n {
match &self.op {
L10nOp::None => None,
L10nOp::Text(text) => Some(text.to_owned()),
L10nOp::Translate(key) => match self.locales {
Some(locales) => {
if self.args.is_empty() {
locales.try_lookup(langid, key)
} else {
locales.try_lookup_with_args(langid, key, &self.args)
}
L10nOp::Translate(key) => {
if self.args.is_empty() {
self.locales.try_lookup(langid, key)
} else {
self.locales.try_lookup_with_args(langid, key, &self.args)
}
None => None,
},
}
}
}
/// Escapes translated text using the default language identifier.
pub fn markup(&self) -> Markup {
let content = self.get().unwrap_or_default();
PreEscaped(content)
PreEscaped(self.get().unwrap_or_default())
}
/// Escapes translated text using the specified language identifier.
pub fn escaped(&self, langid: &LanguageIdentifier) -> Markup {
let content = self.using(langid).unwrap_or_default();
PreEscaped(content)
PreEscaped(self.using(langid).unwrap_or_default())
}
}
@ -287,6 +271,6 @@ impl fmt::Display for L10n {
L10nOp::Text(text) => text.clone(),
L10nOp::Translate(key) => self.get().unwrap_or_else(|| format!("No <{}>", key)),
};
write!(f, "{}", content)
write!(f, "{content}")
}
}