diff --git a/Cargo.lock b/Cargo.lock
index 4a74692..e8141b1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2734,9 +2734,11 @@ dependencies = [
"icu",
"icu_locid",
"icu_provider",
+ "intl-memoizer",
"serde 1.0.193",
"serde_yaml",
"sys-locale",
+ "thiserror",
"unic-langid",
]
diff --git a/l10n/Cargo.toml b/l10n/Cargo.toml
index 40e2d30..3cdf475 100644
--- a/l10n/Cargo.toml
+++ b/l10n/Cargo.toml
@@ -15,9 +15,11 @@ fluent = { version = "0.16" }
icu_locid = { version = "1" }
icu_provider = { version = "1" }
icu = { version = "1" }
+intl-memoizer = { version = "*" }
serde = { version = "1", features = [ "derive" ] }
serde_yaml = { version = "0.9" }
sys-locale = { version = "0.3" }
+thiserror = { version = "1" }
unic-langid = { version = "*" }
[[bin]]
diff --git a/l10n/src/lib.rs b/l10n/src/lib.rs
index b970bc8..65ee465 100644
--- a/l10n/src/lib.rs
+++ b/l10n/src/lib.rs
@@ -1,12 +1,13 @@
use chrono::{Datelike, NaiveDate, Timelike};
use chrono_tz::Tz;
use fixed_decimal::FixedDecimal;
-use fluent::{FluentBundle, FluentResource};
-use fluent_ergonomics::FluentErgo;
+use fluent::{bundle::FluentBundle, FluentResource};
use icu::{datetime::options::length, decimal::FixedDecimalFormatter, locid::Locale};
use icu_provider::DataLocale;
-use std::{collections::HashMap, ops::Deref, path::Path};
+use std::{fs::File, io::Read, ops::Deref};
use sys_locale::get_locale;
+use thiserror::Error;
+use unic_langid::LanguageIdentifierError;
// Re-exports. I'm doing these so that clients of this library don't have to go tracking down
// additional structures
@@ -46,7 +47,9 @@ impl Deref for NonEmptyList {
}
}
+#[derive(Debug, Error)]
pub enum L10NError {
+ #[error("Unparsable Locale")]
UnparsableLocale,
}
@@ -56,6 +59,33 @@ impl From for L10NError {
}
}
+#[derive(Debug, Error)]
+pub enum FileLoadError {
+ #[error("Unparsable Locale")]
+ UnparsableLocale,
+
+ #[error("Source string file not found")]
+ FileNotFound,
+
+ #[error("The Fluent file is malformed")]
+ FluentParseError,
+
+ #[error("An unknown IO error was found")]
+ IOError(std::io::Error),
+}
+
+impl From for FileLoadError {
+ fn from(_: LanguageIdentifierError) -> Self {
+ Self::UnparsableLocale
+ }
+}
+
+impl From for FileLoadError {
+ fn from(err: std::io::Error) -> Self {
+ Self::IOError(err)
+ }
+}
+
// Potential Message structure.
//
// Let's assume the application has an enumeration that implements Message. For each element of the
@@ -74,7 +104,7 @@ pub trait Message {
pub struct L10N {
messages_root: std::path::PathBuf,
- message_bundles: Vec>,
+ message_bundles: Vec>,
locales: NonEmptyList,
zone: chrono_tz::Tz,
@@ -95,34 +125,39 @@ impl L10N {
let english_phrases = FluentResource::try_new
*/
- let message_bundles = {
- /*
- let mut english_messages = messages_root.clone();
- english_messages.push("en-US.ftl");
-
- let langid: unic_langid::LanguageIdentifier = english.to_string().parse().unwrap();
- let mut messages = FluentErgo::new(&[langid.clone()]);
- let _ = messages.add_from_file(langid, &english_messages);
-
- vec![messages]
- */
- vec![]
- };
-
- Self {
+ let mut s = Self {
messages_root,
- message_bundles,
+ message_bundles: vec![],
locales,
zone,
- }
+ };
+
+ s.load_messages_from_file("en-US".to_owned()).unwrap();
+
+ s
}
- pub fn load_messages_from_file(
- &mut self,
- locale: String,
- path: &Path,
- ) -> Result<(), L10NError> {
- unimplemented!()
+ fn load_messages_from_file(&mut self, locale: String) -> Result<(), FileLoadError> {
+ let langid: unic_langid::LanguageIdentifier = locale.parse()?;
+
+ let mut path = self.messages_root.clone();
+ path.push(locale);
+ path.set_extension("ftl");
+ println!("{:?}", path);
+
+ let mut buffer = Vec::new();
+ let mut f = File::open(path)?;
+ f.read_to_end(&mut buffer)?;
+ let text = String::from_utf8(buffer).unwrap();
+ match FluentResource::try_new(text) {
+ Ok(resource) => {
+ let mut bundle = FluentBundle::new_concurrent(vec![langid]);
+ let _ = bundle.add_resource(resource);
+ self.message_bundles.push(bundle);
+ Ok(())
+ }
+ Err((_, _error)) => Err(FileLoadError::FluentParseError),
+ }
}
// Now, whenever the user changes the locales, the list of messages has to change. How do we
@@ -165,9 +200,15 @@ impl L10N {
// }
pub fn tr(&self, message: impl Message) -> String {
- let msg = self.message_bundles[0].get_message(message.msgid()).and_then(|msg| msg.value()).unwrap();
+ println!("message: {}", message.msgid());
+ let msg = self.message_bundles[0]
+ .get_message(message.msgid())
+ .and_then(|msg| msg.value())
+ .unwrap();
let mut errors = vec![];
- self.message_bundles[0].format_pattern(msg, message.args().as_ref(), &mut errors).to_string()
+ self.message_bundles[0]
+ .format_pattern(msg, message.args().as_ref(), &mut errors)
+ .to_string()
}
pub fn format_date_time_utc(