✨ (pagetop): Mejora la elección de zona horaria
- Nuevas opciones `app.timezone_regions`, `app.timezone_order` y `app.timezone_per_user` para limitar y ordenar las regiones ofrecidas y decidir si cada usuario puede tener su propia zona horaria. - Añade `TzRegion` y `TimezoneOrder`; `Timezone::supported_by_region()` devuelve ahora `TzRegion` y excluye los alias de la base IANA que repiten otra zona (tzdata 2025b). - Añade `Timezone::is_supported_in()` para validar con otras regiones. - `SelectTimezone` admite `with_regions()`, `with_order()` y `with_utc_offset()`, muestra nombres legibles y conserva la zona actual aunque ya no se ofrezca. - `app.timezone` se resuelve sin distinguir mayúsculas. - pagetop-user no ofrece idioma ni zona horaria si no se aplican y conserva lo guardado; acepta la zona actual aunque ya no se ofrezca.
This commit is contained in:
parent
f819181872
commit
346714ab29
19 changed files with 1257 additions and 131 deletions
57
src/global/timezone_order.rs
Normal file
57
src/global/timezone_order.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use crate::AutoDefault;
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
/// Criterios para ordenar las regiones de zonas horarias que se ofrecen para elegir.
|
||||
///
|
||||
/// Se obtiene de [`global::SETTINGS.app.timezone_order`](crate::global::App::timezone_order) y
|
||||
/// determina el orden de los grupos de [`Timezone::supported_by_region()`]. Es también el orden
|
||||
/// por defecto de [`form::SelectTimezone`], que puede cambiarse con `with_order()`. En todos los
|
||||
/// casos el grupo *"Etc"* (`Etc/UTC`) va siempre al final.
|
||||
///
|
||||
/// [`Timezone::supported_by_region()`]: crate::datetime::Timezone::supported_by_region
|
||||
/// [`form::SelectTimezone`]: crate::base::component::form::SelectTimezone
|
||||
#[derive(AutoDefault, Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum TimezoneOrder {
|
||||
/// Primero la región de la zona horaria del sitio y luego el resto, de la más cercana a la más
|
||||
/// lejana según su desfase horario. Es el comportamiento por defecto.
|
||||
#[default]
|
||||
Nearest,
|
||||
/// Por nombre de la región. [`form::SelectTimezone`] las ordena por su nombre traducido al
|
||||
/// idioma de la página, sin distinguir mayúsculas ni acentos;
|
||||
/// `Timezone::supported_by_region()`, que no depende del idioma, por su nombre IANA.
|
||||
///
|
||||
/// [`form::SelectTimezone`]: crate::base::component::form::SelectTimezone
|
||||
Alphabetical,
|
||||
/// En el orden en que se indican las regiones, en
|
||||
/// [`global::SETTINGS.app.timezone_regions`](crate::global::App::timezone_regions) o con
|
||||
/// `SelectTimezone::with_regions()`; si no se indica ninguna región válida, por nombre, como
|
||||
/// `TimezoneOrder::Alphabetical`.
|
||||
Listed,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TimezoneOrder {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let raw = String::deserialize(deserializer)?;
|
||||
let result = match raw.trim().to_ascii_lowercase().as_str() {
|
||||
"nearest" => Self::Nearest,
|
||||
"alphabetical" => Self::Alphabetical,
|
||||
"listed" => Self::Listed,
|
||||
_ => {
|
||||
let default = Self::default();
|
||||
println!(
|
||||
concat!(
|
||||
"\nInvalid value \"{}\" for [app].timezone_order. ",
|
||||
"Using \"{:?}\". Check settings.",
|
||||
),
|
||||
raw, default,
|
||||
);
|
||||
default
|
||||
}
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue