diff --git a/src/system/locale/iso_3166.rs b/src/system/locale/iso_3166.rs index f0b5937..47f740e 100644 --- a/src/system/locale/iso_3166.rs +++ b/src/system/locale/iso_3166.rs @@ -7,6 +7,8 @@ use serde::Deserialize; +use super::Territory; + /// Wrap the document stream from JSON into referenced /// entries in the input text #[derive(Deserialize)] @@ -43,6 +45,26 @@ pub struct Entry<'a> { pub official_name: Option<&'a str>, } +impl From<&Entry<'_>> for Territory { + fn from(value: &Entry) -> Self { + if let Some(display) = value.official_name { + Self { + code: value.code3.into(), + code2: value.code2.into(), + display_name: display.into(), + flag: value.flag.into(), + } + } else { + Self { + code: value.code3.into(), + code2: value.code2.into(), + display_name: value.name.into(), + flag: value.flag.into(), + } + } + } +} + #[cfg(test)] mod tests { use super::Document; diff --git a/src/system/locale/iso_639_2.rs b/src/system/locale/iso_639_2.rs new file mode 100644 index 0000000..e1d073b --- /dev/null +++ b/src/system/locale/iso_639_2.rs @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Copyright © 2024 Serpent OS Developers +// +// SPDX-License-Identifier: MPL-2.0 + +//! Parsing for ISO-639 files from iso-codes +//! Essentially, loading of languages + +use serde::Deserialize; + +use super::Language; + +/// JSON document for ISO-639-2 +#[derive(Deserialize)] +pub struct Document<'a> { + #[serde(rename = "639-2", borrow)] + pub entries: Vec>, +} + +/// A single entry in the JSON document +#[derive(Deserialize)] +pub struct Entry<'a> { + #[serde(rename = "alpha_2", borrow)] + pub code2: Option<&'a str>, + + #[serde(rename = "alpha_3", borrow)] + pub code3: &'a str, + + /// Official display name + #[serde(borrow)] + pub name: &'a str, + + /// Common name (optional) + #[serde(borrow)] + pub common_name: Option<&'a str>, + + /// Three letter bibliographic + pub bibliographic: Option<&'a str>, +} + +impl From<&Entry<'_>> for Language { + /// Convert iso entry into Language + fn from(value: &Entry<'_>) -> Self { + Self { + code: value.code3.into(), + code2: value.code2.map(|v| v.into()), + display_name: value.name.into(), + inverted_name: None, + } + } +} + +#[cfg(test)] +mod tests { + use super::Document; + + #[test] + fn load_iso_639_2() { + const TEST_DATA: &str = r#" + { + "639-2": [ + { + "alpha_2": "gd", + "alpha_3": "gla", + "name": "Gaelic; Scottish Gaelic" + }, + { + "alpha_2": "ga", + "alpha_3": "gle", + "name": "Irish" + }, + { + "alpha_2": "gl", + "alpha_3": "glg", + "name": "Galician" + } + ] + } + "#; + + let loaded = serde_json::from_str::(TEST_DATA).expect("Failed to decode ISO-639-2 data"); + let ga = loaded + .entries + .iter() + .find(|i| i.code3 == "gle") + .expect("Failed to find GLE"); + assert_eq!(ga.name, "Irish"); + } +} diff --git a/src/system/locale/iso_639.rs b/src/system/locale/iso_639_3.rs similarity index 54% rename from src/system/locale/iso_639.rs rename to src/system/locale/iso_639_3.rs index 1e3c424..b649d14 100644 --- a/src/system/locale/iso_639.rs +++ b/src/system/locale/iso_639_3.rs @@ -2,44 +2,16 @@ // // SPDX-License-Identifier: MPL-2.0 -//! Parsing for ISO-639 files from iso-codes -//! Essentially, loading of languages - +//! Parsing for ISO-639-3 JSON files use serde::Deserialize; -/// Wrap the document stream from JSON into referenced -/// entries in the input text -#[derive(Deserialize)] -pub struct DocumentTwoCode<'a> { - #[serde(rename = "639-2", borrow)] - pub entries: Vec>, -} - -/// A two-letter code entry -#[derive(Deserialize)] -pub struct EntryTwoCode<'a> { - #[serde(rename = "alpha_2", borrow)] - pub code2: Option<&'a str>, - - #[serde(rename = "alpha_3", borrow)] - pub code3: &'a str, - - /// Official display name - #[serde(borrow)] - pub name: &'a str, - - /// Common name (optional) - #[serde(borrow)] - pub common_name: Option<&'a str>, - - /// Three letter bibliographic - pub bibliographic: Option<&'a str>, -} +use super::Language; +/// JSON document for 639-3 #[derive(Deserialize)] -pub struct DocumentThreeCode<'a> { +pub struct Document<'a> { #[serde(rename = "639-3", borrow)] - pub entries: Vec>, + pub entries: Vec>, } /// Language scope @@ -71,8 +43,9 @@ pub enum Kind { Special, } +/// Single entry in the JSON document #[derive(Deserialize)] -pub struct EntryThreeCode<'a> { +pub struct Entry<'a> { /// Three letter code #[serde(rename = "alpha_3", borrow)] pub code: &'a str, @@ -104,45 +77,28 @@ pub struct EntryThreeCode<'a> { pub common_name: Option<&'a str>, } -#[cfg(test)] -mod tests { - use super::{DocumentThreeCode, DocumentTwoCode, Kind, Scope}; - - #[test] - fn load_2() { - const TEST_DATA: &str = r#" - { - "639-2": [ - { - "alpha_2": "gd", - "alpha_3": "gla", - "name": "Gaelic; Scottish Gaelic" - }, - { - "alpha_2": "ga", - "alpha_3": "gle", - "name": "Irish" - }, - { - "alpha_2": "gl", - "alpha_3": "glg", - "name": "Galician" - } - ] +impl From<&Entry<'_>> for Language { + fn from(value: &Entry<'_>) -> Self { + let display = if let Some(name) = value.common_name { + name.into() + } else { + value.name.into() + }; + Self { + code: value.code.into(), + code2: value.code2.map(|v| v.into()), + display_name: display, + inverted_name: value.inverted_name.map(|v| v.into()), } - "#; - - let loaded = serde_json::from_str::(TEST_DATA).expect("Failed to decode ISO-639 2-code data"); - let ga = loaded - .entries - .iter() - .find(|i| i.code3 == "gle") - .expect("Failed to find GLE"); - assert_eq!(ga.name, "Irish"); } +} + +#[cfg(test)] +mod tests { + use super::{Document, Kind, Scope}; #[test] - fn load_3() { + fn load_iso_639_3() { const TEST_DATA: &str = r#" { "639-3": [ @@ -170,8 +126,7 @@ mod tests { } "#; - let loaded = - serde_json::from_str::(TEST_DATA).expect("Failed to decode ISO-639 3-code data"); + let loaded = serde_json::from_str::(TEST_DATA).expect("Failed to decode ISO-639-3 data"); let ga = loaded .entries .iter() diff --git a/src/system/locale/mod.rs b/src/system/locale/mod.rs index 1a10aa8..e34ac7e 100644 --- a/src/system/locale/mod.rs +++ b/src/system/locale/mod.rs @@ -2,8 +2,45 @@ // // SPDX-License-Identifier: MPL-2.0 +use std::fmt; + use thiserror::Error; +/// Locale joins Territory + Language +#[derive(Debug)] +pub struct Locale<'a> { + pub name: String, + pub display_name: String, + pub language: &'a Language, + pub territory: &'a Territory, + pub modifier: Option, + pub codeset: Option, +} + +impl fmt::Display for Locale<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.display_name) + } +} + +/// Sane representation for UI purposes +#[derive(PartialEq, Eq, Debug)] +pub struct Territory { + pub code: String, + pub code2: String, + pub display_name: String, + pub flag: String, +} + +/// Simplistic language representation +#[derive(PartialEq, Eq, Debug)] +pub struct Language { + pub code: String, + pub code2: Option, + pub display_name: String, + pub inverted_name: Option, +} + #[derive(Debug, Error)] pub enum Error { #[error("io: {0}")] @@ -14,6 +51,7 @@ pub enum Error { } mod iso_3166; -mod iso_639; +mod iso_639_2; +mod iso_639_3; mod registry; diff --git a/src/system/locale/registry.rs b/src/system/locale/registry.rs index c4e6252..307bba2 100644 --- a/src/system/locale/registry.rs +++ b/src/system/locale/registry.rs @@ -4,10 +4,9 @@ //! Registry of languages and territories. -use core::fmt; use std::{collections::HashMap, fs}; -use super::{iso_3166, iso_639, Error}; +use super::{iso_3166, iso_639_2, iso_639_3, Error, Language, Locale, Territory}; /// All ISO codes are expected to live in this location const ISO_CODES_BASE: &str = "/usr/share/iso-codes/json"; @@ -20,89 +19,6 @@ pub struct Registry { languages_lookup: HashMap, } -/// Locale joins Territory + Language -#[derive(Debug)] -pub struct Locale<'a> { - pub name: String, - pub display_name: String, - pub language: &'a Language, - pub territory: &'a Territory, - pub modifier: Option, - pub codeset: Option, -} - -impl fmt::Display for Locale<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.display_name) - } -} - -/// Sane representation for UI purposes -#[derive(PartialEq, Eq, Debug)] -pub struct Territory { - pub code: String, - pub code2: String, - pub display_name: String, - pub flag: String, -} - -impl From<&iso_3166::Entry<'_>> for Territory { - fn from(value: &iso_3166::Entry) -> Self { - if let Some(display) = value.official_name { - Self { - code: value.code3.into(), - code2: value.code2.into(), - display_name: display.into(), - flag: value.flag.into(), - } - } else { - Self { - code: value.code3.into(), - code2: value.code2.into(), - display_name: value.name.into(), - flag: value.flag.into(), - } - } - } -} - -/// Simplistic language representation -#[derive(PartialEq, Eq, Debug)] -pub struct Language { - pub code: String, - pub code2: Option, - pub display_name: String, - pub inverted_name: Option, -} - -impl From<&iso_639::EntryTwoCode<'_>> for Language { - /// Convert iso entry into Language - fn from(value: &iso_639::EntryTwoCode<'_>) -> Self { - Self { - code: value.code3.into(), - code2: value.code2.map(|v| v.into()), - display_name: value.name.into(), - inverted_name: None, - } - } -} - -impl From<&iso_639::EntryThreeCode<'_>> for Language { - fn from(value: &iso_639::EntryThreeCode<'_>) -> Self { - let display = if let Some(name) = value.common_name { - name.into() - } else { - value.name.into() - }; - Self { - code: value.code.into(), - code2: value.code2.map(|v| v.into()), - display_name: display, - inverted_name: value.inverted_name.map(|v| v.into()), - } - } -} - impl Registry { /// Create a new locale registry from the system iso-code JSON definitions pub fn new() -> Result { @@ -146,7 +62,7 @@ impl Registry { fn load_languages_2() -> Result, Error> { let languages = format!("{}/iso_639-2.json", ISO_CODES_BASE); let contents = fs::read_to_string(languages)?; - let parser = serde_json::from_str::(&contents)?; + let parser = serde_json::from_str::(&contents)?; Ok(parser.entries.iter().map(|e| e.into()).collect::>()) } @@ -155,7 +71,7 @@ impl Registry { fn load_languages_3() -> Result, Error> { let languages = format!("{}/iso_639-3.json", ISO_CODES_BASE); let contents = fs::read_to_string(languages)?; - let parser = serde_json::from_str::(&contents)?; + let parser = serde_json::from_str::(&contents)?; Ok(parser.entries.iter().map(|e| e.into()).collect::>()) }