pub(crate) mod errors;
pub mod extensions;
pub mod parser;
use errors::LocaleError;
pub use extensions::{ExtensionType, ExtensionsMap};
use std::str::FromStr;
pub use unic_langid_impl::CharacterDirection;
pub use unic_langid_impl::{subtags, LanguageIdentifier};
#[derive(Debug, Default, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
pub struct Locale {
pub id: LanguageIdentifier,
pub extensions: extensions::ExtensionsMap,
}
type PartsTuple = (
subtags::Language,
Option<subtags::Script>,
Option<subtags::Region>,
Vec<subtags::Variant>,
String,
);
impl Locale {
pub fn from_bytes(v: &[u8]) -> Result<Self, LocaleError> {
Ok(parser::parse_locale(v)?)
}
pub fn from_parts(
language: subtags::Language,
script: Option<subtags::Script>,
region: Option<subtags::Region>,
variants: &[subtags::Variant],
extensions: Option<extensions::ExtensionsMap>,
) -> Self {
let id = LanguageIdentifier::from_parts(language, script, region, variants);
Locale {
id,
extensions: extensions.unwrap_or_default(),
}
}
pub const unsafe fn from_raw_parts_unchecked(
language: subtags::Language,
script: Option<subtags::Script>,
region: Option<subtags::Region>,
variants: Option<Box<[subtags::Variant]>>,
extensions: extensions::ExtensionsMap,
) -> Self {
let id = LanguageIdentifier::from_raw_parts_unchecked(language, script, region, variants);
Self { id, extensions }
}
pub fn into_parts(self) -> PartsTuple {
let (lang, region, script, variants) = self.id.into_parts();
(lang, region, script, variants, self.extensions.to_string())
}
pub fn matches<O: AsRef<Self>>(
&self,
other: &O,
self_as_range: bool,
other_as_range: bool,
) -> bool {
let other = other.as_ref();
if !self.extensions.private.is_empty() || !other.extensions.private.is_empty() {
return false;
}
self.id.matches(&other.id, self_as_range, other_as_range)
}
}
impl FromStr for Locale {
type Err = LocaleError;
fn from_str(source: &str) -> Result<Self, Self::Err> {
Ok(parser::parse_locale(source)?)
}
}
impl From<LanguageIdentifier> for Locale {
fn from(id: LanguageIdentifier) -> Self {
Locale {
id,
extensions: ExtensionsMap::default(),
}
}
}
impl From<Locale> for LanguageIdentifier {
fn from(value: Locale) -> Self {
value.id
}
}
impl AsRef<LanguageIdentifier> for Locale {
fn as_ref(&self) -> &LanguageIdentifier {
&self.id
}
}
impl AsRef<Locale> for Locale {
#[inline(always)]
fn as_ref(&self) -> &Locale {
self
}
}
impl std::fmt::Display for Locale {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}{}", self.id, self.extensions)
}
}
pub fn canonicalize<S: AsRef<[u8]>>(input: S) -> Result<String, LocaleError> {
let locale = Locale::from_bytes(input.as_ref())?;
Ok(locale.to_string())
}