diff --git a/Cargo.lock b/Cargo.lock index 30e0083..87bcb55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", "opaque-debug", @@ -87,6 +87,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.9.0" @@ -133,12 +139,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -160,7 +160,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen", ] @@ -192,6 +192,18 @@ dependencies = [ "cipher", ] +[[package]] +name = "current_locale" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0be8ddcccda8be68d8e31a421ceea7c79857404daa052434ae30ce2f402cd10" +dependencies = [ + "libc", + "objc", + "objc-foundation", + "winapi", +] + [[package]] name = "digest" version = "0.9.0" @@ -211,6 +223,70 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + [[package]] name = "fastrand" version = "1.8.0" @@ -293,11 +369,21 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] +[[package]] +name = "gettext-ng" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2c86be871deb255ef65fc8395048a2505912c595f1eddc4da03aeb6fda5cf34" +dependencies = [ + "byteorder", + "encoding", +] + [[package]] name = "h2" version = "0.3.14" @@ -453,7 +539,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -483,7 +569,16 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", ] [[package]] @@ -492,12 +587,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" - [[package]] name = "mime" version = "0.3.16" @@ -569,6 +658,35 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2b2cbbfd8defa51ff24450a61d73b3ff3e158484ddd274a883e886e6fbaa78" +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "once_cell" version = "1.14.0" @@ -625,7 +743,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "opaque-debug", "universal-hash", @@ -763,7 +881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -775,7 +893,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.3", ] @@ -833,7 +951,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -996,7 +1114,7 @@ version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", "pin-project-lite", "tracing-core", @@ -1107,21 +1225,6 @@ name = "usdpl-back" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58928ed65332c30b9b9be5140fcdab97e45db679a5845d829aa26492765272e5" -dependencies = [ - "async-recursion", - "async-trait", - "bytes", - "hex", - "log", - "obfstr", - "tokio", - "usdpl-core 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "warp", -] - -[[package]] -name = "usdpl-back" -version = "0.8.0" dependencies = [ "async-recursion", "async-trait", @@ -1135,12 +1238,20 @@ dependencies = [ ] [[package]] -name = "usdpl-core" -version = "0.6.0" +name = "usdpl-back" +version = "0.9.0" dependencies = [ - "aes-gcm-siv", - "base64", - "hex-literal", + "async-recursion", + "async-trait", + "bytes", + "current_locale", + "gettext-ng", + "hex", + "log", + "obfstr", + "tokio", + "usdpl-core 0.9.0", + "warp", ] [[package]] @@ -1153,25 +1264,33 @@ dependencies = [ "base64", ] +[[package]] +name = "usdpl-core" +version = "0.9.0" +dependencies = [ + "aes-gcm-siv", + "base64", + "hex-literal", +] + [[package]] name = "usdpl-front" -version = "0.7.0" +version = "0.9.0" dependencies = [ "console_error_panic_hook", "hex", "js-sys", "obfstr", - "usdpl-core 0.6.0", + "usdpl-core 0.9.0", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", "web-sys", - "wee_alloc", ] [[package]] name = "usdpl-rs" -version = "0.6.0" +version = "0.9.0" [[package]] name = "utf-8" @@ -1237,7 +1356,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -1262,7 +1381,7 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -1331,18 +1450,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "wee_alloc" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "memory_units", - "winapi", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 4a6023f..9830661 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "usdpl-rs" -version = "0.6.0" +version = "0.9.0" authors = ["NGnius (Graham) "] edition = "2021" license = "GPL-3.0-only" diff --git a/usdpl-back/Cargo.toml b/usdpl-back/Cargo.toml index 908d2b4..dafdd0a 100644 --- a/usdpl-back/Cargo.toml +++ b/usdpl-back/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "usdpl-back" -version = "0.8.0" +version = "0.9.0" edition = "2021" license = "GPL-3.0-only" repository = "https://github.com/NGnius/usdpl-rs" @@ -8,14 +8,15 @@ readme = "README.md" description = "Universal Steam Deck Plugin Library back-end" [features] -default = ["blocking"] +default = ["blocking", "translate"] decky = ["usdpl-core/decky"] crankshaft = ["usdpl-core/crankshaft"] blocking = ["tokio", "tokio/rt", "tokio/rt-multi-thread"] # synchronous API for async functionality, using tokio encrypt = ["usdpl-core/encrypt", "obfstr", "hex"] +translate = ["usdpl-core/translate", "gettext-ng"] [dependencies] -usdpl-core = { version = "0.6.0", path = "../usdpl-core"} +usdpl-core = { version = "0.9.0", path = "../usdpl-core"} log = "0.4" @@ -31,3 +32,6 @@ async-recursion = "1.0.0" # encryption helpers obfstr = { version = "0.3", optional = true } hex = { version = "0.4", optional = true } + +# translations +gettext-ng = { version = "0.4.1", optional = true } diff --git a/usdpl-back/src/instance.rs b/usdpl-back/src/instance.rs index 1d7dbe1..a9284eb 100644 --- a/usdpl-back/src/instance.rs +++ b/usdpl-back/src/instance.rs @@ -118,14 +118,16 @@ impl Instance { } else { socket::Packet::Invalid } - } + }, socket::Packet::Many(packets) => { let mut result = Vec::with_capacity(packets.len()); for packet in packets { result.push(Self::handle_call(packet, handlers).await); } socket::Packet::Many(result) - } + }, + #[cfg(feature = "translate")] + socket::Packet::Language(lang) => socket::Packet::Translations(get_all_translations(lang)), _ => socket::Packet::Invalid, } } @@ -221,6 +223,32 @@ impl Instance { } } +#[cfg(feature = "translate")] +fn get_all_translations(language: String) -> Vec<(String, Vec)> { + log::debug!("Loading translations for language `{}`...", language); + let result = load_locale(&language); + match result { + Ok(catalog) => { + let map = catalog.nalltext(); + let mut result = Vec::with_capacity(map.len()); + for (key, val) in map.iter() { + result.push((key.to_owned().into(), val.iter().map(|x| x.into()).collect())); + } + result + }, + Err(e) => { + log::error!("Failed to load translations for language `{}`: {}", language, e); + vec![] + } + } +} + +#[cfg(feature = "translate")] +fn load_locale(lang: &str) -> Result { + let file = std::fs::File::open(lang).map_err(|e| gettext_ng::Error::Io(e))?; + gettext_ng::Catalog::parse(file) +} + #[cfg(test)] mod tests { #[allow(unused_imports)] diff --git a/usdpl-core/Cargo.toml b/usdpl-core/Cargo.toml index c0624e2..22dfb5d 100644 --- a/usdpl-core/Cargo.toml +++ b/usdpl-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "usdpl-core" -version = "0.6.0" +version = "0.9.0" edition = "2021" license = "GPL-3.0-only" repository = "https://github.com/NGnius/usdpl-rs" @@ -12,6 +12,7 @@ default = [] decky = [] crankshaft = [] encrypt = ["aes-gcm-siv"] +translate = [] [dependencies] base64 = "0.13" diff --git a/usdpl-core/src/serdes/dump_impl.rs b/usdpl-core/src/serdes/dump_impl.rs index b52757f..a74f08c 100644 --- a/usdpl-core/src/serdes/dump_impl.rs +++ b/usdpl-core/src/serdes/dump_impl.rs @@ -24,6 +24,48 @@ impl Dumpable for Vec { } } +impl Dumpable for (T0, T1) { + fn dump(&self, buffer: &mut dyn Write) -> Result { + Ok( + self.0.dump(buffer)? + + self.1.dump(buffer)? + ) + } +} + +impl Dumpable for (T0, T1, T2) { + fn dump(&self, buffer: &mut dyn Write) -> Result { + Ok( + self.0.dump(buffer)? + + self.1.dump(buffer)? + + self.2.dump(buffer)? + ) + } +} + +impl Dumpable for (T0, T1, T2, T3) { + fn dump(&self, buffer: &mut dyn Write) -> Result { + Ok( + self.0.dump(buffer)? + + self.1.dump(buffer)? + + self.2.dump(buffer)? + + self.3.dump(buffer)? + ) + } +} + +impl Dumpable for (T0, T1, T2, T3, T4) { + fn dump(&self, buffer: &mut dyn Write) -> Result { + Ok( + self.0.dump(buffer)? + + self.1.dump(buffer)? + + self.2.dump(buffer)? + + self.3.dump(buffer)? + + self.4.dump(buffer)? + ) + } +} + impl Dumpable for bool { fn dump(&self, buffer: &mut dyn Write) -> Result { buffer.write(&[*self as u8]).map_err(DumpError::Io) @@ -97,6 +139,11 @@ mod tests { &[3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 5, 0, 0, 0, 116, 101, 115, 116, 50] } + test_impl! {tuple2_dump_test, (0u8, 1u8), 2, &[0, 1]} + test_impl! {tuple3_dump_test, (0u8, 1u8, 2u8), 3, &[0, 1, 2]} + test_impl! {tuple4_dump_test, (0u8, 1u8, 2u8, 3u8), 4, &[0, 1, 2, 3]} + test_impl! {tuple5_dump_test, (0u8, 1u8, 2u8, 3u8, 4u8), 5, &[0, 1, 2, 3, 4]} + test_impl! {bool_true_dump_test, true, 1, &[1]} test_impl! {bool_false_dump_test, false, 1, &[0]} diff --git a/usdpl-core/src/serdes/load_impl.rs b/usdpl-core/src/serdes/load_impl.rs index d05537b..2e37097 100644 --- a/usdpl-core/src/serdes/load_impl.rs +++ b/usdpl-core/src/serdes/load_impl.rs @@ -38,6 +38,56 @@ impl Loadable for Vec { } } +impl Loadable for (T0, T1) { + fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { + let (t0, len0) = T0::load(buffer)?; + let (t1, len1) = T1::load(buffer)?; + Ok(( + (t0, t1), + len0 + len1 + )) + } +} + +impl Loadable for (T0, T1, T2) { + fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { + let (t0, len0) = T0::load(buffer)?; + let (t1, len1) = T1::load(buffer)?; + let (t2, len2) = T2::load(buffer)?; + Ok(( + (t0, t1, t2), + len0 + len1 + len2 + )) + } +} + +impl Loadable for (T0, T1, T2, T3) { + fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { + let (t0, len0) = T0::load(buffer)?; + let (t1, len1) = T1::load(buffer)?; + let (t2, len2) = T2::load(buffer)?; + let (t3, len3) = T3::load(buffer)?; + Ok(( + (t0, t1, t2, t3), + len0 + len1 + len2 + len3 + )) + } +} + +impl Loadable for (T0, T1, T2, T3, T4) { + fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { + let (t0, len0) = T0::load(buffer)?; + let (t1, len1) = T1::load(buffer)?; + let (t2, len2) = T2::load(buffer)?; + let (t3, len3) = T3::load(buffer)?; + let (t4, len4) = T4::load(buffer)?; + Ok(( + (t0, t1, t2, t3, t4), + len0 + len1 + len2 + len3 + len4 + )) + } +} + impl Loadable for bool { fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError> { let mut byte = [u8::MAX; 1]; @@ -121,6 +171,8 @@ mod tests { ] } + test_impl! {tuple2_load_test, [0, 1], (u8, u8), 2, (0, 1)} + test_impl! {bool_true_load_test, [1], bool, 1, true} test_impl! {bool_false_load_test, [0], bool, 1, false} diff --git a/usdpl-core/src/socket.rs b/usdpl-core/src/socket.rs index a0d19ab..5a28762 100644 --- a/usdpl-core/src/socket.rs +++ b/usdpl-core/src/socket.rs @@ -39,6 +39,12 @@ pub enum Packet { Bad, /// Many packets merged into one Many(Vec), + /// Translation data dump + #[cfg(feature = "translate")] + Translations(Vec<(String, Vec)>), + /// Request translations for language + #[cfg(feature = "translate")] + Language(String), } impl Packet { @@ -53,6 +59,10 @@ impl Packet { Self::Unsupported => 6, Self::Bad => 7, Self::Many(_) => 8, + #[cfg(feature = "translate")] + Self::Translations(_) => 9, + #[cfg(feature = "translate")] + Self::Language(_) => 10, } } } @@ -82,7 +92,17 @@ impl Loadable for Packet { 8 => { let (obj, len) = <_>::load(buf)?; (Self::Many(obj), len) - } + }, + #[cfg(feature = "translate")] + 9 => { + let (obj, len) = <_>::load(buf)?; + (Self::Translations(obj), len) + }, + #[cfg(feature = "translate")] + 10 => { + let (obj, len) = <_>::load(buf)?; + (Self::Language(obj), len) + }, _ => return Err(LoadError::InvalidData), }; result.1 += 1; @@ -102,6 +122,10 @@ impl Dumpable for Packet { Self::Unsupported => Ok(0), Self::Bad => return Err(DumpError::Unsupported), Self::Many(v) => v.dump(buf), + #[cfg(feature = "translate")] + Self::Translations(tr) => tr.dump(buf), + #[cfg(feature = "translate")] + Self::Language(l) => l.dump(buf), }?; Ok(size1 + result) } diff --git a/usdpl-front/Cargo.toml b/usdpl-front/Cargo.toml index 294a42e..bd0611a 100644 --- a/usdpl-front/Cargo.toml +++ b/usdpl-front/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "usdpl-front" -version = "0.7.0" +version = "0.9.0" authors = ["NGnius (Graham) "] edition = "2021" license = "GPL-3.0-only" @@ -12,11 +12,12 @@ description = "Universal Steam Deck Plugin Library front-end designed for WASM" crate-type = ["cdylib", "rlib"] [features] -default = [] +default = ["translate"] decky = ["usdpl-core/decky"] crankshaft = ["usdpl-core/crankshaft"] debug = ["console_error_panic_hook"] encrypt = ["usdpl-core/encrypt", "obfstr", "hex"] +translate = ["usdpl-core/translate"] [dependencies] wasm-bindgen = "0.2" @@ -28,13 +29,6 @@ wasm-bindgen-futures = "0.4" # code size when deploying. console_error_panic_hook = { version = "0.1.6", optional = true } -# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size -# compared to the default allocator's ~10K. It is slower than the default -# allocator, however. -# -# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now. -wee_alloc = { version = "0.4.5", optional = true } - web-sys = { version = "0.3", features = [ #'Headers', 'Request', @@ -48,7 +42,7 @@ js-sys = { version = "0.3" } obfstr = { version = "0.3", optional = true } hex = { version = "0.4", optional = true } -usdpl-core = { version = "0.6.0", path = "../usdpl-core" } +usdpl-core = { version = "0.9.0", path = "../usdpl-core" } [dev-dependencies] wasm-bindgen-test = { version = "0.3.13" } diff --git a/usdpl-front/src/connection.rs b/usdpl-front/src/connection.rs index 08bccaf..a41979a 100644 --- a/usdpl-front/src/connection.rs +++ b/usdpl-front/src/connection.rs @@ -16,13 +16,14 @@ use usdpl_core::socket; #[cfg(feature = "encrypt")] const NONCE: [u8; socket::NONCE_SIZE]= [0u8; socket::NONCE_SIZE]; -pub async fn send_js( +pub async fn send_recv_packet( id: u64, packet: socket::Packet, port: u16, #[cfg(feature = "encrypt")] key: Vec, -) -> Result, JsValue> { +) -> Result { + let mut opts = RequestInit::new(); opts.method("POST"); opts.mode(RequestMode::Cors); @@ -53,34 +54,31 @@ pub async fn send_js( crate::imports::console_log(&format!("Received base64 `{}` len:{}", rust_str, rust_str.len())); #[cfg(not(feature = "encrypt"))] - match socket::Packet::load_base64(rust_str.as_bytes()) + {Ok(socket::Packet::load_base64(rust_str.as_bytes()) .map_err(super::convert::str_to_js)? - .0 - { - socket::Packet::CallResponse(resp) => Ok(resp.response), - _ => { - //imports::console_warn(&format!("USDPL warning: Got non-call-response message from {}", resp.url())); - Err(format!( - "Expected call response message from {}, got something else", - resp.url() - ) - .into()) - } - } + .0)} #[cfg(feature = "encrypt")] - match socket::Packet::load_encrypted(rust_str.as_bytes(), key.as_slice(), &NONCE) + {Ok(socket::Packet::load_encrypted(rust_str.as_bytes(), key.as_slice(), &NONCE) .map_err(super::convert::str_to_js)? - .0 + .0)} +} + +pub async fn send_call( + id: u64, + packet: socket::Packet, + port: u16, + #[cfg(feature = "encrypt")] + key: Vec, +) -> Result, JsValue> { + let packet = send_recv_packet(id, packet, port, #[cfg(feature = "encrypt")] key).await?; + + match packet { socket::Packet::CallResponse(resp) => Ok(resp.response), _ => { //imports::console_warn(&format!("USDPL warning: Got non-call-response message from {}", resp.url())); - Err(format!( - "Expected call response message from {}, got something else", - resp.url() - ) - .into()) + Err("Expected call response message, got something else".into()) } } } diff --git a/usdpl-front/src/lib.rs b/usdpl-front/src/lib.rs index 4631fcc..4aa80b3 100644 --- a/usdpl-front/src/lib.rs +++ b/usdpl-front/src/lib.rs @@ -16,11 +16,18 @@ use usdpl_core::{socket::Packet, RemoteCall}; //const REMOTE_CALL_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); //const REMOTE_PORT: std::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(31337); -static mut CTX: UsdplContext = UsdplContext { port: 31337, id: 1, -#[cfg(feature = "encrypt")] key: Vec::new() }; +static mut CTX: UsdplContext = UsdplContext { + port: 31337, + id: 1, + #[cfg(feature = "encrypt")] + key: Vec::new(), +}; static mut CACHE: Option> = None; +#[cfg(feature = "translate")] +static mut TRANSLATIONS: Option>> = None; + #[cfg(feature = "encrypt")] fn encryption_key() -> Vec { hex::decode(obfstr::obfstr!(env!("USDPL_ENCRYPTION_KEY"))).unwrap() @@ -52,11 +59,6 @@ fn increment_id() -> u64 { current_id } -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global allocator. -#[cfg(feature = "wee_alloc")] -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - /// Initialize the front-end library #[wasm_bindgen] pub fn init_usdpl(port: u16) { @@ -123,7 +125,7 @@ pub async fn call_backend(name: String, parameters: Vec) -> JsValue { let port = get_port(); #[cfg(feature = "debug")] imports::console_log(&format!("USDPL: Got port {}", port)); - let results = connection::send_js( + let results = connection::send_call( next_id, Packet::Call(RemoteCall { id: next_id, @@ -152,3 +154,66 @@ pub async fn call_backend(name: String, parameters: Vec) -> JsValue { } results_js.into() } + +/// Initialize translation strings for the front-end +#[wasm_bindgen] +pub async fn init_tr(locale: String) { + let next_id = increment_id(); + match connection::send_recv_packet( + next_id, + Packet::Language(locale.clone()), + get_port(), + #[cfg(feature = "encrypt")] + get_key() + ).await { + Ok(Packet::Translations(translations)) => { + #[cfg(feature = "debug")] + imports::console_log(&format!("USDPL: Got translations for {}", locale)); + // convert translations into map + let mut tr_map = std::collections::HashMap::with_capacity(translations.len()); + for (key, val) in translations { + tr_map.insert(key, val); + } + unsafe { TRANSLATIONS = Some(tr_map) } + }, + Ok(_) => { + #[cfg(feature = "debug")] + imports::console_error(&format!("USDPL: Got wrong packet response for init_tr")); + unsafe { TRANSLATIONS = None } + }, + #[allow(unused_variables)] + Err(e) => { + #[cfg(feature = "debug")] + imports::console_error(&format!("USDPL: Got wrong error for init_tr: {}", e)); + unsafe { TRANSLATIONS = None } + } + } +} + +/// Translate a phrase, equivalent to tr_n(msg_id, 0) +#[wasm_bindgen] +pub fn tr(msg_id: String) -> String { + if let Some(translations) = unsafe { TRANSLATIONS.as_ref().unwrap().get(&msg_id) } { + if let Some(translated) = translations.get(0) { + translated.to_owned() + } else { + msg_id + } + } else { + msg_id + } +} + +/// Translate a phrase, retrieving the plural form for `n` items +#[wasm_bindgen] +pub fn tr_n(msg_id: String, n: usize) -> String { + if let Some(translations) = unsafe { TRANSLATIONS.as_ref().unwrap().get(&msg_id) } { + if let Some(translated) = translations.get(n) { + translated.to_owned() + } else { + msg_id + } + } else { + msg_id + } +}