//! handle the loading of a `Language` use crate::{ path::{LangPath, LANG_EXTENSION, LANG_MANIFEST_FILE}, Fonts, Language, LanguageMetadata, }; use deunicode::deunicode; use hashbrown::hash_map::HashMap; use ron::de::from_reader; use serde::{Deserialize, Serialize}; use std::{fs, path::PathBuf}; /// Raw localization metadata from LANG_MANIFEST_FILE file /// See `Language` for more info on each attributes #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) struct RawManifest { pub(crate) convert_utf8_to_ascii: bool, pub(crate) fonts: Fonts, pub(crate) metadata: LanguageMetadata, } /// Raw localization data from one specific file /// These structs are meant to be merged into a Language #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) struct RawFragment { pub(crate) string_map: HashMap, pub(crate) vector_map: HashMap>, } pub(crate) struct RawLanguage { pub(crate) manifest: RawManifest, pub(crate) fragments: HashMap>, } #[derive(Debug)] pub(crate) enum RawError { RonError(ron::Error), } pub(crate) fn load_manifest(path: &LangPath) -> Result { let manifest_file = path.file(LANG_MANIFEST_FILE); tracing::debug!(?manifest_file, "manifest loading"); let f = fs::File::open(&manifest_file)?; let manifest: RawManifest = from_reader(f).map_err(RawError::RonError)?; // verify that the folder name `de_DE` matches the value inside the metadata! assert_eq!( manifest.metadata.language_identifier, path.language_identifier() ); Ok(manifest) } pub(crate) fn load_raw_language( path: &LangPath, manifest: RawManifest, ) -> Result, common_assets::Error> { //get List of files let files = path.fragments()?; // Walk through each file in the directory let mut fragments = HashMap::new(); for sub_path in files { let f = fs::File::open(path.sub_path(&sub_path))?; let fragment = from_reader(f).map_err(RawError::RonError)?; fragments.insert(sub_path, fragment); } Ok(RawLanguage { manifest, fragments, }) } impl From> for Language { fn from(raw: RawLanguage) -> Self { let mut string_map = HashMap::new(); let mut vector_map = HashMap::new(); for (_, fragment) in raw.fragments { string_map.extend(fragment.string_map); vector_map.extend(fragment.vector_map); } let convert_utf8_to_ascii = raw.manifest.convert_utf8_to_ascii; // Update the text if UTF-8 to ASCII conversion is enabled if convert_utf8_to_ascii { for value in string_map.values_mut() { *value = deunicode(value); } for value in vector_map.values_mut() { *value = value.iter().map(|s| deunicode(s)).collect(); } } let mut metadata = raw.manifest.metadata; metadata.language_name = deunicode(&metadata.language_name); Self { string_map, vector_map, convert_utf8_to_ascii, fonts: raw.manifest.fonts, metadata, } } } impl core::fmt::Display for RawError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { RawError::RonError(e) => write!(f, "{}", e), } } } impl std::error::Error for RawError {} impl From for common_assets::Error { fn from(e: RawError) -> Self { Self::Conversion(Box::new(e)) } } impl common_assets::Asset for RawManifest { type Loader = common_assets::RonLoader; const EXTENSION: &'static str = LANG_EXTENSION; } impl common_assets::Asset for RawFragment { type Loader = common_assets::RonLoader; const EXTENSION: &'static str = LANG_EXTENSION; }