use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use std::path::Path;
use mf2_catalog::Dir;
use mf2_runtime::{BidiStrategy, FormatError, Formatter, TimeZone};
use super::{Catalogs, Error, LocaleSource};
use crate::{CatalogFile, Corpus, Message};
pub struct NativeI18n {
catalogs: Catalogs,
active: usize,
source: LocaleSource,
}
impl fmt::Debug for NativeI18n {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NativeI18n")
.field("locale", &self.locale())
.field("locale_source", &self.source)
.field("catalogs", &self.catalogs)
.finish_non_exhaustive()
}
}
impl NativeI18n {
pub fn embedded(corpus: &'static Corpus) -> Result<Self, Error> {
Ok(NativeI18n::with(Catalogs::embedded(corpus)?))
}
pub fn from_directory(
corpus: &'static Corpus,
directory: impl AsRef<Path>,
) -> Result<Self, Error> {
Ok(NativeI18n::with(Catalogs::files(
corpus,
directory.as_ref(),
false,
)?))
}
fn with(catalogs: Catalogs) -> NativeI18n {
let (active, source) = catalogs.system_choice();
NativeI18n {
catalogs,
active,
source,
}
}
#[must_use]
pub fn locale(&self) -> &'static str {
self.catalogs.tag(self.active)
}
#[must_use]
pub const fn locale_source(&self) -> LocaleSource {
self.source
}
#[must_use]
pub fn dir(&self) -> Dir {
self.catalogs.dir(self.active)
}
#[must_use]
pub const fn source_locale(&self) -> &'static str {
self.catalogs.corpus().source_locale()
}
pub fn available_locales(&self) -> impl ExactSizeIterator<Item = &'static str> + use<> {
self.catalogs.corpus().locales().iter().map(|(tag, _)| *tag)
}
pub fn set_locale(&mut self, locale: &str) -> Result<(), Error> {
self.active = self
.catalogs
.index(locale)
.ok_or_else(|| Error::UnknownLocale(locale.to_owned()))?;
self.source = LocaleSource::Explicit;
Ok(())
}
#[must_use]
pub const fn bidi(&self) -> BidiStrategy {
self.catalogs.bidi()
}
pub const fn set_bidi(&mut self, bidi: BidiStrategy) {
self.catalogs.set_bidi(bidi);
}
#[must_use]
pub const fn time_zone(&self) -> TimeZone {
self.catalogs.time_zone()
}
pub const fn set_time_zone(&mut self, zone: TimeZone) {
self.catalogs.set_time_zone(zone);
}
#[must_use]
pub fn formatter(&self) -> Option<Formatter<'_>> {
self.catalogs.formatter_at(self.active)
}
#[must_use]
pub fn format(&self, message: &impl Message) -> String {
self.catalogs.format_at(self.active, message)
}
#[must_use]
pub fn format_with_errors(&self, message: &impl Message) -> (String, Vec<FormatError>) {
self.catalogs.format_at_with_errors(self.active, message)
}
#[must_use]
pub fn catalog_file_name(&self, locale: &str) -> Option<&'static str> {
let tag = self.catalogs.tag(self.catalogs.index(locale)?);
self.catalogs
.corpus()
.catalogs()
.iter()
.find(|f| f.tag() == tag)
.map(CatalogFile::file_name)
}
}