diff --git a/leptos_i18n_parser/Cargo.toml b/leptos_i18n_parser/Cargo.toml index c94d7d73..853440a2 100644 --- a/leptos_i18n_parser/Cargo.toml +++ b/leptos_i18n_parser/Cargo.toml @@ -12,10 +12,10 @@ readme = "../README.md" icu = "1.5" serde = { version = "1", features = ["rc"] } serde_json = { version = "1" } -serde_yaml = { version = "0.9", optional = true } +serde_yaml = { version = "0.9" } toml = "0.8" fixed_decimal = { version = "0.5", features = ["ryu"] } -json5 = { version = "0.4", optional = true } +json5 = { version = "0.4" } quote = { version = "1", optional = true } syn = { version = "2.0", optional = true } proc-macro2 = { version = "1", optional = true } @@ -24,8 +24,8 @@ proc-macro2 = { version = "1", optional = true } default = ["json_files"] quote = ["dep:quote", "dep:syn", "dep:proc-macro2"] json_files = [] -yaml_files = ["dep:serde_yaml"] -json5_files = ["dep:json5"] +yaml_files = [] +json5_files = [] plurals = [] format_datetime = [] format_list = [] diff --git a/leptos_i18n_parser/src/parse_locales/error.rs b/leptos_i18n_parser/src/parse_locales/error.rs index 0019509b..ad7b99b7 100644 --- a/leptos_i18n_parser/src/parse_locales/error.rs +++ b/leptos_i18n_parser/src/parse_locales/error.rs @@ -114,6 +114,8 @@ pub enum Error { locale: Key, key_path: KeyPath, }, + NoFileFormats, + MultipleFilesFormats, } impl Display for Error { @@ -204,6 +206,8 @@ impl Display for Error { Error::PluralsAtNormalKey { key_path, locale } => write!(f, "In locale {:?} at key \"{}\", Found plurals but a key of that name is already present.", locale, key_path), Error::DisabledFormatter { locale, key_path, formatter } => write!(f, "{}, at key \"{}\" in locale {:?}", formatter.err_message(), key_path, locale), Error::DisabledPlurals { locale, key_path } => write!(f, "Plurals are not enabled, enable the \"plurals\" feature to use them, at key \"{}\" in locale {:?}", key_path, locale), + Error::NoFileFormats => write!(f, "No file formats has been provided for leptos_i18n. Supported formats are: json, json5 and yaml."), + Error::MultipleFilesFormats => write!(f, "Multiple file formats have been provided for leptos_i18n, choose only one. Supported formats are: json, json5 and yaml."), } } } diff --git a/leptos_i18n_parser/src/parse_locales/locale.rs b/leptos_i18n_parser/src/parse_locales/locale.rs index e0a292ab..3ba907d3 100644 --- a/leptos_i18n_parser/src/parse_locales/locale.rs +++ b/leptos_i18n_parser/src/parse_locales/locale.rs @@ -15,106 +15,71 @@ use super::ranges::RangeType; use super::warning::{Warning, Warnings}; use super::{ForeignKeysPaths, StringIndexer, VAR_COUNT_KEY}; -macro_rules! define_by_format { - (json => $($tt:tt)*) => { - #[cfg(all(feature = "json_files", not(any(feature = "yaml_files", feature = "json5_files"))))] - $($tt)* - }; - (yaml => $($tt:tt)*) => { - #[cfg(all(feature = "yaml_files", not(any(feature = "json_files", feature = "json5_files"))))] - $($tt)* - }; - (json5 => $($tt:tt)*) => { - #[cfg(all(feature = "json5_files", not(any(feature = "json_files", feature = "yaml_files"))))] - $($tt)* - }; - (none => $($tt:tt)*) => { - #[cfg(not(any(feature = "json_files", feature = "yaml_files", feature = "json5_files")))] - $($tt)* - }; - // This is attrocious, found a better way fgs - (multiple => $($tt:tt)*) => { - #[cfg(any(all(feature = "json_files", feature = "yaml_files"), all(feature = "json_files", feature = "json5_files"), all(feature = "yaml_files", feature = "json5_files")))] - $($tt)* - } -} - -macro_rules! define_error { - ($ident:ident => $t:ty) => { - define_by_format!($ident => pub type SerdeError = $t;); - }; -} - -macro_rules! define_files_exts { - ($ident:ident => $($lit:literal),*) => { - define_by_format!($ident => const FILE_EXTS: &[&str] = &[$($lit,)*];); - }; - ($ident:ident) => { - define_by_format!($ident => const FILE_EXTS: &[&str] = &[];); - }; -} - -#[cfg(feature = "json5_files")] #[derive(Debug)] -pub enum Json5Error { - Serde(json5::Error), +pub enum SerdeError { + Json(serde_json::Error), + Yaml(serde_yaml::Error), + Json5(json5::Error), Io(std::io::Error), + None, + Multiple, } -#[cfg(feature = "json5_files")] -impl std::fmt::Display for Json5Error { +impl std::fmt::Display for SerdeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Json5Error::Serde(error) => std::fmt::Display::fmt(error, f), - Json5Error::Io(error) => std::fmt::Display::fmt(error, f), + SerdeError::Json(error) => std::fmt::Display::fmt(error, f), + SerdeError::Yaml(error) => std::fmt::Display::fmt(error, f), + SerdeError::Json5(error) => std::fmt::Display::fmt(error, f), + SerdeError::Io(error) => std::fmt::Display::fmt(error, f), + SerdeError::None => write!(f, "No file formats has been provided for leptos_i18n. Supported formats are: json, json5 and yaml."), + SerdeError::Multiple => write!(f, "Multiple file formats have been provided for leptos_i18n, choose only one. Supported formats are: json, json5 and yaml."), } } } -define_error!(json => serde_json::Error); -define_error!(json5 => Json5Error); -define_error!(yaml => serde_yaml::Error); -define_error!(none => &'static str); // whatever impl Display -define_error!(multiple => &'static str); // whatever impl Display - -define_files_exts!(json => "json"); -define_files_exts!(json5 => "json5"); -define_files_exts!(yaml => "yaml", "yml"); -define_files_exts!(none); -define_files_exts!(multiple); - -define_by_format!(json => - fn de_inner(locale_file: R, seed: LocaleSeed) -> Result { - let mut deserializer = serde_json::Deserializer::from_reader(locale_file); - serde::de::DeserializeSeed::deserialize(seed, &mut deserializer) - } -); -define_by_format!(json5 => - fn de_inner(mut locale_file: R, seed: LocaleSeed) -> Result { - let mut buff = String::new(); - Read::read_to_string(&mut locale_file, &mut buff).map_err(Json5Error::Io)?; - let mut deserializer = json5::Deserializer::from_str(&buff).map_err(Json5Error::Serde)?; - serde::de::DeserializeSeed::deserialize(seed, &mut deserializer).map_err(Json5Error::Serde) - } -); -define_by_format!(yaml => - fn de_inner(locale_file: R, seed: LocaleSeed) -> Result { - let deserializer = serde_yaml::Deserializer::from_reader(locale_file); - serde::de::DeserializeSeed::deserialize(seed, deserializer) - } -); -define_by_format!(none => - fn de_inner(locale_file: R, seed: LocaleSeed) -> Result { - let _ = (locale_file, seed); - compile_error!("No file format has been provided for leptos_i18n, supported formats are: json and yaml") +const fn get_files_exts() -> &'static [&'static str] { + if cfg!(feature = "json_files") { + &["json"] + } else if cfg!(feature = "yaml_files") { + &["yaml", "yml"] + } else if cfg!(feature = "json5_files") { + &["json5"] + } else { + &[] } -); -define_by_format!(multiple => - fn de_inner(locale_file: R, seed: LocaleSeed) -> Result { - let _ = (locale_file, seed); - compile_error!("Multiple file format have been provided for leptos_i18n, choose only one, supported formats are: json and yaml") +} + +const FILE_EXTS: &[&str] = get_files_exts(); + +fn de_inner_json(locale_file: R, seed: LocaleSeed) -> Result { + let mut deserializer = serde_json::Deserializer::from_reader(locale_file); + serde::de::DeserializeSeed::deserialize(seed, &mut deserializer).map_err(SerdeError::Json) +} + +fn de_inner_json5(mut locale_file: R, seed: LocaleSeed) -> Result { + let mut buff = String::new(); + Read::read_to_string(&mut locale_file, &mut buff).map_err(SerdeError::Io)?; + let mut deserializer = json5::Deserializer::from_str(&buff).map_err(SerdeError::Json5)?; + serde::de::DeserializeSeed::deserialize(seed, &mut deserializer).map_err(SerdeError::Json5) +} + +fn de_inner_yaml(locale_file: R, seed: LocaleSeed) -> Result { + let deserializer = serde_yaml::Deserializer::from_reader(locale_file); + serde::de::DeserializeSeed::deserialize(seed, deserializer).map_err(SerdeError::Yaml) +} + +fn de_inner(locale_file: R, seed: LocaleSeed) -> Result { + if cfg!(feature = "json_files") { + de_inner_json(locale_file, seed) + } else if cfg!(feature = "yaml_files") { + de_inner_yaml(locale_file, seed) + } else if cfg!(feature = "json5_files") { + de_inner_json5(locale_file, seed) + } else { + unreachable!() } -); +} #[derive(Debug, Clone, PartialEq)] pub struct Locale { @@ -216,7 +181,18 @@ fn find_file(path: &mut PathBuf) -> Result { }; } - Err(Error::LocaleFileNotFound(errs)) + #[allow(clippy::const_is_empty)] + if !FILE_EXTS.is_empty() { + Err(Error::LocaleFileNotFound(errs)) + } else if cfg!(any( + feature = "json_files", + feature = "yaml_files", + feature = "json5_files" + )) { + Err(Error::MultipleFilesFormats) + } else { + Err(Error::NoFileFormats) + } } impl InterpolOrLit {