diff --git a/Cargo.lock b/Cargo.lock index 114c8d0b..50d1f3e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,6 +454,7 @@ dependencies = [ "gloo-events 0.2.0", "gloo-file 0.3.0", "gloo-history 0.2.2", + "gloo-intl", "gloo-net 0.5.0", "gloo-render 0.2.0", "gloo-storage 0.3.0", @@ -588,6 +589,14 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-intl" +version = "0.1.0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "gloo-net" version = "0.3.1" @@ -598,7 +607,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils 0.1.7", - "http", + "http 0.2.11", "js-sys", "pin-project", "serde", @@ -785,7 +794,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", "indexmap 2.1.0", "slab", "tokio", @@ -814,7 +823,7 @@ dependencies = [ "base64", "bytes", "headers-core", - "http", + "http 0.2.11", "httpdate", "mime", "sha1", @@ -826,7 +835,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.11", ] [[package]] @@ -852,6 +861,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -859,7 +879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.11", "pin-project-lite", ] @@ -886,7 +906,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.11", "http-body", "httparse", "httpdate", @@ -1049,7 +1069,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.11", "httparse", "log", "memchr", @@ -1699,7 +1719,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.11", "httparse", "log", "rand", @@ -1787,7 +1807,7 @@ dependencies = [ "futures-channel", "futures-util", "headers", - "http", + "http 0.2.11", "hyper", "log", "mime", diff --git a/Cargo.toml b/Cargo.toml index 74e8fedc..62461b23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ gloo-utils = { version = "0.2", path = "crates/utils", optional = true } gloo-history = { version = "0.2", path = "crates/history", optional = true } gloo-worker = { version = "0.5", path = "crates/worker", optional = true } gloo-net = { version = "0.5", path = "crates/net", optional = true } +gloo-intl = { version = "0.1", path = "crates/intl", optional = true } [features] default = [ @@ -38,6 +39,7 @@ default = [ "history", "worker", "net", + "intl", ] futures = [ "timers", @@ -58,6 +60,7 @@ utils = ["gloo-utils"] history = ["gloo-history"] worker = ["gloo-worker"] net = ["gloo-net"] +intl = ["gloo-intl"] [workspace] members = [ @@ -73,6 +76,7 @@ members = [ "crates/worker", "crates/worker-macros", "crates/net", + "crates/intl", "examples/markdown", "examples/clock", diff --git a/crates/intl/Cargo.toml b/crates/intl/Cargo.toml new file mode 100644 index 00000000..d066f882 --- /dev/null +++ b/crates/intl/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "gloo-intl" +version = "0.1.0" +authors = [ + "Rust and WebAssembly Working Group", + # "Mendy Berger", +] +edition = "2021" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rustwasm/gloo" +description = "Clean Intl API for WASM Apps" +readme = "README.md" +keywords = ["intl", "i18l", "Internationalization", "localization"] +categories = ["wasm", "api-bindings"] + +[dependencies] +wasm-bindgen = "0.2" +js-sys = "0.3" diff --git a/crates/intl/README.md b/crates/intl/README.md new file mode 100644 index 00000000..eb9839d9 --- /dev/null +++ b/crates/intl/README.md @@ -0,0 +1,24 @@ +
+ +

gloo-intl

+ +

+ Crates.io version + Download + docs.rs docs +

+ +

+ API Docs + | + Contributing + | + Chat +

+ + Built with 🦀🕸 by The Rust and WebAssembly Working Group +
+ +Wraps common `js_sys` Intl with a cleaner API. + +See the API docs to learn more diff --git a/crates/intl/src/date_time_format.rs b/crates/intl/src/date_time_format.rs new file mode 100644 index 00000000..5a184bde --- /dev/null +++ b/crates/intl/src/date_time_format.rs @@ -0,0 +1,103 @@ +use super::utils::options; + +pub struct DateTimeFormat { + js: js_sys::Intl::DateTimeFormat, +} + +// TODO: Add a `new` method that takes a strongly types locale. Maybe an enum. +impl DateTimeFormat { + /// New DateTimeFormat instance from locale &str. + pub fn new_str(locale: &str, options: Options) -> Self { + let locales = js_sys::Array::of1(&wasm_bindgen::JsValue::from_str(locale)); + Self::new_js_array(locales, options) + } + /// New DateTimeFormat instance from js_sys::Array of locales. + pub fn new_js_array(locales: js_sys::Array, options: Options) -> Self { + let options = options.to_js_object(); + let js = js_sys::Intl::DateTimeFormat::new(&locales, &options); + Self { js } + } + /// Corresponds to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format + pub fn format(&self, date: &js_sys::Date) -> String { + self.js + .format() + .call1(&self.js, &date.into()) + .unwrap() + .as_string() + .unwrap() + } +} + +/// Corresponds to the options in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat +// TODO: add all options here. +#[derive(Clone, Default)] +pub struct Options { + pub year: Option, + pub month: Option, + pub day: Option, + pub hour: Option, + pub minute: Option, + pub second: Option, +} +impl Options { + // TODO: should be a derive macro? + fn to_js_object(&self) -> js_sys::Object { + let output = js_sys::Object::new(); + if let Some(year) = &self.year { + pro(&output, "year", year.string_rep()); + } + if let Some(month) = &self.month { + pro(&output, "month", month.string_rep()); + } + if let Some(day) = &self.day { + pro(&output, "day", day.string_rep()); + } + if let Some(hour) = &self.hour { + pro(&output, "hour", hour.string_rep()); + } + if let Some(minute) = &self.minute { + pro(&output, "minute", minute.string_rep()); + } + if let Some(second) = &self.second { + pro(&output, "second", second.string_rep()); + } + output + } +} + +fn pro(obj: &js_sys::Object, key: &str, value: &str) { + js_sys::Reflect::set( + &obj, + &wasm_bindgen::JsValue::from_str(key), + &wasm_bindgen::JsValue::from_str(value), + ) + .unwrap(); +} + +options!(Year, { + Numeric: "numeric", + Digit2: "2-digit", +}); +options!(Month, { + Numeric: "numeric", + Digit2: "2-digit", + Long: "long", + Short: "short", + Narrow: "narrow", +}); +options!(Day, { + Numeric: "numeric", + Digit2: "2-digit", +}); +options!(Hour, { + Numeric: "numeric", + Digit2: "2-digit", +}); +options!(Minute, { + Numeric: "numeric", + Digit2: "2-digit", +}); +options!(Second, { + Numeric: "numeric", + Digit2: "2-digit", +}); diff --git a/crates/intl/src/lib.rs b/crates/intl/src/lib.rs new file mode 100644 index 00000000..4e1cce19 --- /dev/null +++ b/crates/intl/src/lib.rs @@ -0,0 +1,4 @@ +pub mod date_time_format; +pub mod number_format; + +mod utils; diff --git a/crates/intl/src/number_format.rs b/crates/intl/src/number_format.rs new file mode 100644 index 00000000..b769e811 --- /dev/null +++ b/crates/intl/src/number_format.rs @@ -0,0 +1,84 @@ +use super::utils::options; + +pub struct NumberFormat { + js: js_sys::Intl::NumberFormat, +} + +// TODO: Add a `new` method that takes a strongly types locale. Maybe an enum. +impl NumberFormat { + /// New NumberFormat instance from locale &str. + pub fn new_str(locale: &str, options: Options) -> Self { + let locales = js_sys::Array::of1(&wasm_bindgen::JsValue::from_str(locale)); + Self::new_js_array(locales, options) + } + /// New NumberFormat instance from js_sys::Array of locales. + pub fn new_js_array(locales: js_sys::Array, options: Options) -> Self { + let options = options.to_js_object(); + let js = js_sys::Intl::NumberFormat::new(&locales, &options); + Self { js } + } + /// Corresponds to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/format + pub fn format(&self, number: T) -> String + where + T: Into, + { + let number: f64 = number.into(); + self.js + .format() + .call1(&self.js, &number.into()) + .unwrap() + .as_string() + .unwrap() + } +} + +/// Corresponds to the options in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat +// TODO: add all options here. +#[derive(Clone, Default)] +pub struct Options { + pub style: Option