// Localization + ContentCountry. The DEFAULT Localization is ("en", "GB") // — not en-US, not the system locale. NPE's Localization.java exposes // ~100 country codes; we ship a small in-source set today and grow as // needed. use std::fmt; #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Localization { language_code: String, country_code: Option, } impl Localization { pub fn new(language_code: impl Into, country_code: Option) -> Self { Self { language_code: language_code.into(), country_code } } pub fn from_localization_code(code: &str) -> Option { let (lang, country) = code.split_once('-').unwrap_or((code, "")); if lang.is_empty() { return None; } Some(Self { language_code: lang.to_string(), country_code: if country.is_empty() { None } else { Some(country.to_string()) }, }) } pub fn language_code(&self) -> &str { &self.language_code } pub fn country_code(&self) -> Option<&str> { self.country_code.as_deref() } pub fn localization_code(&self) -> String { match &self.country_code { Some(c) => format!("{}-{}", self.language_code, c), None => self.language_code.clone(), } } } impl Default for Localization { fn default() -> Self { Self::new("en", Some("GB".into())) } } impl fmt::Display for Localization { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.localization_code()) } } #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct ContentCountry { country_code: String, } impl ContentCountry { pub fn new(country_code: impl Into) -> Self { Self { country_code: country_code.into() } } pub fn country_code(&self) -> &str { &self.country_code } } impl Default for ContentCountry { fn default() -> Self { Self::new("GB") } } impl fmt::Display for ContentCountry { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.country_code) } } #[cfg(test)] mod tests { use super::*; #[test] fn default_is_en_gb() { let l = Localization::default(); assert_eq!(l.language_code(), "en"); assert_eq!(l.country_code(), Some("GB")); assert_eq!(l.localization_code(), "en-GB"); } #[test] fn parse_localization_code() { let l = Localization::from_localization_code("en-US").unwrap(); assert_eq!(l.language_code(), "en"); assert_eq!(l.country_code(), Some("US")); let l = Localization::from_localization_code("de").unwrap(); assert_eq!(l.language_code(), "de"); assert_eq!(l.country_code(), None); assert!(Localization::from_localization_code("").is_none()); } }