diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc42c666..bcef4b69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -227,8 +227,7 @@ jobs: - csr-complete - ssr-hydrate-actix - ssr-hydrate-axum - - ssr-islands-axum - - system-gtk + # TODO: re-add 'ssr-islands-axum' and 'system-gtk' toolchain: - stable - nightly diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bb5242d6..940a71ab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,9 +36,9 @@ repos: - id: clippy alias: clippy-no-features name: clippy-no-features - args: [ + args: + [ --exclude=leptos-fluent-ssr-hydrate-axum-example, - --exclude=leptos-fluent-ssr-islands-axum-example, # TODO: excluded by Leptos bug --workspace, --, -D, @@ -87,7 +87,6 @@ repos: [ "--features=ssr,actix", --exclude=leptos-fluent-ssr-hydrate-axum-example, - --exclude=leptos-fluent-ssr-islands-axum-example, --exclude=leptos-fluent-csr-complete-example, --exclude=leptos-fluent-csr-minimal-example, --workspace, @@ -116,7 +115,6 @@ repos: --exclude=leptos-fluent-ssr-hydrate-actix-example, --exclude=leptos-fluent-csr-complete-example, --exclude=leptos-fluent-csr-minimal-example, - --exclude=leptos-fluent-ssr-islands-axum-example, --workspace, --, -D, diff --git a/CHANGELOG.md b/CHANGELOG.md index 564df98b..d6998aee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,76 @@ # CHANGELOG -## [Unreleased] - 0.2.0 +## 2024-12-17 - [0.2.0] ### Breaking changes -- The feature `json` is not enabled by default anymore. Now leptos-fluent - does not includes features by default, so you don't need to use - `default-features = false` in your `Cargo.toml` file. +#### Require Leptos v0.7 + +Support for Leptos v0.6 has been dropped. Now leptos-fluent requires +Leptos v0.7. + +#### Declarative API + +Previously, the `leptos_fluent!` macro was providing the I18n context +using `provide_context`, so the app was configured as: + +```rust +#[component] +fn App() -> impl IntoView { + leptos_fluent! { + // ... + } + + view! { + // ... + } +} +``` + +Now a `children` option has been added to the macro and need to be used +to declare a I18n component: + +```rust +#[component] +fn I18n(children: Children) -> impl IntoView { + leptos_fluent! { + children: children(), + // ... + } +} + +#[component] +fn App() -> impl IntoView { + view! { + + // ... + + } +} +``` + +By this way `leptos_fluent!` does not return the I18n context anymore. + +#### No more double curly braces + +Support for deprecated double curly braces syntax for the `leptos_fluent!` +macro has been removed. Use single curly braces instead: + +```rust +leptos_fluent! { + // ... +} +``` + +#### No more default features + +The feature `json` is not enabled by default anymore. Now leptos-fluent +does not includes features by default, so you don't need to use +`default-features = false` in your `Cargo.toml` file. + +#### `SsrHtmlTag` component removed + +The deprecated `SsrHtmlTag` component has been removed. ## 2024-11-15 - [0.1.26] @@ -552,7 +616,7 @@ version to `0.1` during installation. - Added all ISO-639-1 and ISO-639-2 languages. -[Unreleased]: https://github.com/mondeja/leptos-fluent/compare/v0.1.26...master +[0.2.0]: https://github.com/mondeja/leptos-fluent/compare/v0.1.26...v0.2.0 [0.1.26]: https://github.com/mondeja/leptos-fluent/compare/v0.1.25...v0.1.26 [0.1.25]: https://github.com/mondeja/leptos-fluent/compare/v0.1.24...v0.1.25 [0.1.24]: https://github.com/mondeja/leptos-fluent/compare/v0.1.23...v0.1.24 diff --git a/Cargo.lock b/Cargo.lock index 84687f8c..f1dfd157 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -205,7 +205,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -261,10 +261,16 @@ dependencies = [ ] [[package]] -name = "allocator-api2" -version = "0.2.21" +name = "any_spawner" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +checksum = "41058deaa38c9d9dd933d6d238d825227cffa668e2839b52879f6619c63eee3b" +dependencies = [ + "futures", + "thiserror 2.0.7", + "tokio", + "wasm-bindgen-futures", +] [[package]] name = "anyhow" @@ -273,14 +279,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] -name = "async-recursion" -version = "1.1.1" +name = "async-lock" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", + "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -291,37 +297,37 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] name = "attribute-derive" -version = "0.9.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1ee502851995027b06f99f5ffbeffa1406b38d0b318a1ebfa469332c6cbafd" +checksum = "0053e96dd3bec5b4879c23a138d6ef26f2cb936c9cdc96274ac2b9ed44b5bb54" dependencies = [ "attribute-derive-macro", "derive-where", "manyhow", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] name = "attribute-derive-macro" -version = "0.9.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3601467f634cfe36c4780ca9c75dea9a5b34529c1f2810676a337e7e0997f954" +checksum = "463b53ad0fd5b460af4b1915fe045ff4d946d025fb6c4dc3337752eaa980f71b" dependencies = [ "collection_literals", "interpolator", "manyhow", - "proc-macro-utils 0.8.0", + "proc-macro-utils", "proc-macro2", "quote", "quote-use", - "syn 2.0.90", + "syn", ] [[package]] @@ -359,7 +365,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", "tracing", @@ -486,61 +492,6 @@ dependencies = [ "bytes", ] -[[package]] -name = "cached" -version = "0.45.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eb5776f28a149524d1d8623035760b4454ec881e8cf3838fa8d7e1b11254b3" -dependencies = [ - "cached_proc_macro", - "cached_proc_macro_types", - "hashbrown 0.13.2", - "instant", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cached_proc_macro" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "cached_proc_macro_types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" - -[[package]] -name = "cairo-rs" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae50b5510d86cf96ac2370e66d8dc960882f3df179d6a5a1e52bd94a1416c0f7" -dependencies = [ - "bitflags", - "cairo-sys-rs", - "glib", - "libc", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18b6bb8e43c7eb0f2aac7976afe0c61b6f5fc2ab7bc4c139537ea56c92290df" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - [[package]] name = "camino" version = "1.1.9" @@ -567,16 +518,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "cfg-expr" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -584,38 +525,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "ciborium" -version = "0.2.2" +name = "codee" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +checksum = "5d3ad3122b0001c7f140cf4d605ef9a9e2c24d96ab0b4fb4347b76de2425f445" dependencies = [ - "ciborium-io", - "ciborium-ll", "serde", + "serde_json", + "thiserror 1.0.69", ] [[package]] -name = "ciborium-io" -version = "0.2.2" +name = "collection_literals" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" +checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271" [[package]] -name = "ciborium-ll" -version = "0.2.2" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "ciborium-io", - "half", + "crossbeam-utils", ] -[[package]] -name = "collection_literals" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271" - [[package]] name = "config" version = "0.14.1" @@ -659,6 +593,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "const_str_slice_concat" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b" + [[package]] name = "convert_case" version = "0.4.0" @@ -703,15 +643,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -737,12 +668,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - [[package]] name = "crypto-common" version = "0.1.6" @@ -771,48 +696,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a74858bcfe44b22016cb49337d7b6f04618c58e5dbfdef61b06b8c434324a0bc" -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] - [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", + "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", @@ -836,7 +727,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -849,7 +740,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.90", + "syn", ] [[package]] @@ -891,7 +782,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -906,6 +797,15 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "either_of" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1e2e7b8b6deaf1ae68f1d8796dec8732cff85d27fdbf4bc4460145a067ed0b" +dependencies = [ + "pin-project-lite", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -922,13 +822,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "field-offset" -version = "0.3.6" +name = "event-listener" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ - "memoffset", - "rustc_version", + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener", + "pin-project-lite", ] [[package]] @@ -951,7 +862,7 @@ dependencies = [ "fluent-syntax", "intl-memoizer", "intl_pluralrules", - "rustc-hash", + "rustc-hash 1.1.0", "self_cell 0.10.3", "smallvec", "unic-langid", @@ -984,7 +895,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn", "unic-langid", "walkdir", ] @@ -1062,6 +973,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -1078,7 +990,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -1111,63 +1023,6 @@ dependencies = [ "slab", ] -[[package]] -name = "gdk-pixbuf" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6efc7705f7863d37b12ad6974cbb310d35d054f5108cdc1e69037742f573c4c" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67f2587c9202bf997476bbba6aaed4f78a11538a2567df002a5f57f5331d0b5c" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk4" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75933c4a86e8a2428814d367e22c733304fdfabc87f415750fd2f55409b6ee48" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk4-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk4-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20af0656d543aed3e57ac4120ef76d091c3c42ab1e0507a8febde7cd005640e2" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1185,10 +1040,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -1197,80 +1050,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "gio" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a517657589a174be9f60c667f1fec8b7ac82ed5db4ebf56cf073a3b5955d8e2e" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "pin-project-lite", - "smallvec", -] - -[[package]] -name = "gio-sys" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16e55573888c1802b8fd169201cadee4e3fd4c889bfb23c9fa652a7945335da" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "windows-sys 0.59.0", -] - -[[package]] -name = "glib" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f969edf089188d821a30cde713b6f9eb08b20c63fc2e584aba2892a7984a8cc0" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "smallvec", -] - -[[package]] -name = "glib-macros" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" -dependencies = [ - "heck", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "glib-sys" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b360ff0f90d71de99095f79c526a5888c9c92fc9ee1b19da06c6f5e75f0c2a53" -dependencies = [ - "libc", - "system-deps", -] - [[package]] name = "glob" version = "0.3.1" @@ -1286,8 +1065,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1336,121 +1115,10 @@ dependencies = [ ] [[package]] -name = "gobject-sys" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a56235e971a63bfd75abb13ef70064e1346388723422a68580d8a6fbac6423" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "graphene-rs" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39d3bcd2e24fd9c2874a56f277b72c03e728de9bdc95a8d4ef4c962f10ced98" -dependencies = [ - "glib", - "graphene-sys", - "libc", -] - -[[package]] -name = "graphene-sys" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a68d39515bf340e879b72cecd4a25c1332557757ada6e8aba8654b4b81d23a" -dependencies = [ - "glib-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gsk4" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b36933c1e79df378aa6e606576e680358a9582ed8c16f33e94899636e6fa6df6" -dependencies = [ - "cairo-rs", - "gdk4", - "glib", - "graphene-rs", - "gsk4-sys", - "libc", - "pango", -] - -[[package]] -name = "gsk4-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0877a9d485bd9ba5262b0c9bce39e63750e525e3aebeb359d271ca1f0e111f1d" -dependencies = [ - "cairo-sys-rs", - "gdk4-sys", - "glib-sys", - "gobject-sys", - "graphene-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk4" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9376d14d7e33486c54823a42bef296e882b9f25cb4c52b52f4d1d57bbadb5b6d" -dependencies = [ - "cairo-rs", - "field-offset", - "futures-channel", - "gdk-pixbuf", - "gdk4", - "gio", - "glib", - "graphene-rs", - "gsk4", - "gtk4-macros", - "gtk4-sys", - "libc", - "pango", -] - -[[package]] -name = "gtk4-macros" -version = "0.9.3" +name = "guardian" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c518d5dd41c57385c7cd30af52e261820c897fc1144e558bb88c303d048ae2" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "gtk4-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e653b0a9001ba9be1ffddb9373bfe9a111f688222f5aeee2841481300d91b55a" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk4-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "graphene-sys", - "gsk4-sys", - "libc", - "pango-sys", - "system-deps", -] +checksum = "493913a18c0d7bebb75127a26a432162c59edbe06f6cf712001e3e769345e8b5" [[package]] name = "h2" @@ -1471,31 +1139,11 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" - [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -1504,10 +1152,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] -name = "heck" -version = "0.5.0" +name = "hermit-abi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "html-escape" @@ -1587,6 +1235,22 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hydration_context" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef13071fe13b55c85fe2b70246d2e3b49d2c6a764fd3e0edaf262cc385ff1854" +dependencies = [ + "futures", + "js-sys", + "once_cell", + "or_poisoned", + "pin-project-lite", + "serde", + "throw_error", + "wasm-bindgen", +] + [[package]] name = "hyper" version = "1.5.2" @@ -1737,15 +1401,9 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "1.0.3" @@ -1777,7 +1435,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.9", + "regex-automata", "same-file", "walkdir", "winapi-util", @@ -1799,15 +1457,6 @@ dependencies = [ "hashbrown 0.15.2", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "interpolator" version = "0.5.0" @@ -1841,9 +1490,9 @@ checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -1890,28 +1539,37 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "leptos" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cbb3237c274dadf00dcc27db96c52601b40375117178fb24a991cda073624f0" +checksum = "ba5046c590aea121f6ad5e71fcb75453a933425d39527b9a3b1b295235afc8df" dependencies = [ + "any_spawner", + "base64", "cfg-if", + "either_of", + "futures", + "hydration_context", "leptos_config", "leptos_dom", + "leptos_hot_reload", "leptos_macro", - "leptos_reactive", "leptos_server", + "oco_ref", + "or_poisoned", + "paste", + "rand", + "reactive_graph", + "rustc-hash 2.1.0", + "send_wrapper", "serde", - "serde_json", + "serde_qs", "server_fn", - "tracing", + "slotmap", + "tachys", + "thiserror 2.0.7", + "throw_error", "typed-builder", "typed-builder-macro", "wasm-bindgen", @@ -1920,7 +1578,7 @@ dependencies = [ [[package]] name = "leptos-fluent" -version = "0.1.26" +version = "0.2.0" dependencies = [ "current_locale", "directories", @@ -1961,31 +1619,18 @@ dependencies = [ "leptos-fluent", "leptos-fluent-csr-complete-example", "leptos-fluent-csr-minimal-example", + "leptos_meta", "tests-helpers", "wasm-bindgen", "wasm-bindgen-test", "web-sys", ] -[[package]] -name = "leptos-fluent-gtk-example" -version = "0.1.0" -dependencies = [ - "fluent-templates", - "gtk4", - "leptos", - "leptos-fluent", - "system-deps", - "tracing", - "tracing-appender", - "tracing-subscriber", -] - [[package]] name = "leptos-fluent-macros" -version = "0.1.26" +version = "0.2.0" dependencies = [ - "cfg-expr 0.15.8", + "cfg-expr", "current_platform", "fluent-syntax", "fluent-templates", @@ -1999,7 +1644,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "syn 2.0.90", + "syn", "tracing", "trybuild", "walkdir", @@ -2028,72 +1673,52 @@ dependencies = [ "axum", "console_error_panic_hook", "fluent-templates", - "http 1.2.0", - "leptos", - "leptos-fluent", - "leptos_axum", - "leptos_meta", - "leptos_router", - "thiserror 1.0.69", - "tokio", - "tower 0.4.13", - "tower-http", - "wasm-bindgen", -] - -[[package]] -name = "leptos-fluent-ssr-islands-axum-example" -version = "0.1.0" -dependencies = [ - "axum", - "console_error_panic_hook", - "fluent-templates", - "http 1.2.0", "leptos", "leptos-fluent", "leptos_axum", "leptos_meta", "leptos_router", - "serde", - "thiserror 1.0.69", "tokio", - "tower 0.4.13", - "tower-http", "wasm-bindgen", ] [[package]] name = "leptos_actix" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29155efba54ab8c6c3038ce2608500b4aa5d8be04330e5fa08d0fe7cae85308c" +checksum = "0d1babe3599368d0b39e4f7907ddef36d53c54ef310c491d65ff2948ba11ef77" dependencies = [ + "actix-files", "actix-http", "actix-web", + "any_spawner", + "dashmap", "futures", + "hydration_context", "leptos", "leptos_integration_utils", "leptos_macro", "leptos_meta", "leptos_router", + "once_cell", "parking_lot", - "regex", + "send_wrapper", "serde_json", "server_fn", "tokio", - "tracing", ] [[package]] name = "leptos_axum" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910681b920c48a43508b2bd0261bdb67c4ef9456a0b3613f956a0d30e832e9de" +checksum = "7b0d388392939f629c45b8c7bcc83997cb6c6026813b57f50953651ad5be63d8" dependencies = [ + "any_spawner", "axum", - "cfg-if", + "dashmap", "futures", - "http-body-util", + "hydration_context", "leptos", "leptos_integration_utils", "leptos_macro", @@ -2101,61 +1726,45 @@ dependencies = [ "leptos_router", "once_cell", "parking_lot", - "serde_json", "server_fn", "tokio", - "tokio-util", - "tracing", + "tower", + "tower-http", ] [[package]] name = "leptos_config" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ed778611380ddea47568ac6ad6ec5158d39b5bd59e6c4dcd24efc15dc3dc0d" +checksum = "5e2d64c43e2554108c26da3127f8384d92ca76c6f0b7288d1c09c8cc68152064" dependencies = [ "config", "regex", "serde", - "thiserror 1.0.69", + "thiserror 2.0.7", "typed-builder", ] [[package]] name = "leptos_dom" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8401c46c86c1f4c16dcb7881ed319fcdca9cda9b9e78a6088955cb423afcf119" +checksum = "6c15aca81dc2edd040b51c46734f65c6f36e6ba8a31347c1354c94b958044ae0" dependencies = [ - "async-recursion", - "cfg-if", - "drain_filter_polyfill", - "futures", - "getrandom", - "html-escape", - "indexmap", - "itertools", "js-sys", - "leptos_reactive", - "once_cell", - "pad-adapter", - "paste", - "rustc-hash", - "serde", - "serde_json", - "server_fn", - "smallvec", - "tracing", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "tachys", "wasm-bindgen", - "wasm-bindgen-futures", "web-sys", ] [[package]] name = "leptos_hot_reload" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb53d4794240b684a2f4be224b84bee9e62d2abc498cf2bcd643cd565e01d96" +checksum = "0445f3a62696d2d66bef288911af34405718880b4b8dd6c5cfb7751fd8ffcc6b" dependencies = [ "anyhow", "camino", @@ -2165,29 +1774,30 @@ dependencies = [ "quote", "rstml", "serde", - "syn 2.0.90", + "syn", "walkdir", ] [[package]] name = "leptos_integration_utils" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a96976631c2225ec116a7bf9c0ed5bf6999a19fed33f5e3cbcf37af44c384dc" +checksum = "d293a2f64a558d4ca10ef01125d055134f3582f27c407102c4259bb54ca8b55b" dependencies = [ "futures", + "hydration_context", "leptos", "leptos_config", - "leptos_hot_reload", "leptos_meta", - "tracing", + "leptos_router", + "reactive_graph", ] [[package]] name = "leptos_macro" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b13bc3db70715cd8218c4535a5af3ae3c0e5fea6f018531fc339377b36bc0e0" +checksum = "92f690c955274f1722ee6c66463ace79301d53a8c2bf7f6e4e61b978ca239e20" dependencies = [ "attribute-derive", "cfg-if", @@ -2201,99 +1811,80 @@ dependencies = [ "quote", "rstml", "server_fn_macro", - "syn 2.0.90", - "tracing", + "syn", "uuid", ] [[package]] name = "leptos_meta" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25acc2f63cf91932013e400a95bf6e35e5d3dbb44a7b7e25a8e3057d12005b3b" -dependencies = [ - "cfg-if", - "indexmap", - "leptos", - "tracing", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "leptos_reactive" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4161acbf80f59219d8d14182371f57302bc7ff81ee41aba8ba1ff7295727f23" +checksum = "7c651d788bbbf1c57ee95dd3835f9d433b85a409b6256f338c3c7146eb8b7f53" dependencies = [ - "base64", - "cfg-if", "futures", "indexmap", - "js-sys", - "oco_ref", - "paste", - "pin-project", - "rustc-hash", - "self_cell 1.1.0", - "serde", - "serde-wasm-bindgen", - "serde_json", - "slotmap", - "thiserror 1.0.69", - "tokio", - "tracing", + "leptos", + "once_cell", + "or_poisoned", + "send_wrapper", "wasm-bindgen", - "wasm-bindgen-futures", "web-sys", ] [[package]] name = "leptos_router" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d71dea7d42c0d29c40842750232d3425ed1cf10e313a1f898076d20871dad32" +checksum = "32a4f1784486ebf36805dac22faee21e3e610aa64b6662a7386f065eeec27ae8" dependencies = [ - "cached", - "cfg-if", + "any_spawner", + "either_of", + "futures", "gloo-net", - "itertools", "js-sys", - "lazy_static", - "leptos", - "leptos_integration_utils", - "leptos_meta", - "linear-map", - "lru", + "leptos", + "leptos_router_macro", "once_cell", + "or_poisoned", "percent-encoding", - "regex", + "reactive_graph", "send_wrapper", - "serde", - "serde_json", - "serde_qs 0.13.0", - "thiserror 1.0.69", - "tracing", + "tachys", + "thiserror 2.0.7", "url", "wasm-bindgen", - "wasm-bindgen-futures", "web-sys", ] +[[package]] +name = "leptos_router_macro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee7ecef3f1c69b51864190c564e4873d84f200e44efb37934208f9525f02a5f" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", +] + [[package]] name = "leptos_server" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a97eb90a13f71500b831c7119ddd3bdd0d7ae0a6b0487cade4fddeed3b8c03f" +checksum = "93450589df3b3e398c7f5ea64d8f1c8369b1ba9b90e1f70f6cb996b8d443ca3e" dependencies = [ - "inventory", - "lazy_static", - "leptos_macro", - "leptos_reactive", + "any_spawner", + "base64", + "codee", + "futures", + "hydration_context", + "or_poisoned", + "reactive_graph", + "send_wrapper", "serde", + "serde_json", "server_fn", - "thiserror 1.0.69", - "tracing", + "tachys", ] [[package]] @@ -2317,10 +1908,6 @@ name = "linear-map" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" -dependencies = [ - "serde", - "serde_test", -] [[package]] name = "litemap" @@ -2361,15 +1948,6 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -[[package]] -name = "lru" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "malloc_buf" version = "0.0.6" @@ -2381,36 +1959,27 @@ dependencies = [ [[package]] name = "manyhow" -version = "0.10.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91ea592d76c0b6471965708ccff7e6a5d277f676b90ab31f4d3f3fc77fade64" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" dependencies = [ "manyhow-macros", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] name = "manyhow-macros" -version = "0.10.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64621e2c08f2576e4194ea8be11daf24ac01249a4f53cd8befcbb7077120ead" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" dependencies = [ - "proc-macro-utils 0.8.0", + "proc-macro-utils", "proc-macro2", "quote", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matchit" version = "0.7.3" @@ -2423,15 +1992,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -2502,6 +2062,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "next_tuple" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" + [[package]] name = "nom" version = "7.1.3" @@ -2512,22 +2078,22 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -2568,9 +2134,9 @@ dependencies = [ [[package]] name = "oco_ref" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51ebcefb2f0b9a5e0bea115532c8ae4215d1b01eff176d0f4ba4192895c2708" +checksum = "64b94982fe39a861561cf67ff17a7849f2cedadbbad960a797634032b7abb998" dependencies = [ "serde", "thiserror 1.0.69", @@ -2589,40 +2155,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pad-adapter" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63" - -[[package]] -name = "pango" -version = "0.20.7" +name = "or_poisoned" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e89bd74250a03a05cec047b43465469102af803be2bf5e5a1088f8b8455e087" -dependencies = [ - "gio", - "glib", - "libc", - "pango-sys", -] +checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd" [[package]] -name = "pango-sys" -version = "0.20.7" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71787e0019b499a5eda889279e4adb455a4f3fdd6870cd5ab7f4a5aa25df6699" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2696,7 +2238,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2727,7 +2269,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2770,16 +2312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.90", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", + "syn", ] [[package]] @@ -2824,6 +2357,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", + "syn", ] [[package]] @@ -2832,17 +2366,6 @@ version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" -[[package]] -name = "proc-macro-utils" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8" -dependencies = [ - "proc-macro2", - "quote", - "smallvec", -] - [[package]] name = "proc-macro-utils" version = "0.10.0" @@ -2871,7 +2394,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "version_check", "yansi", ] @@ -2901,10 +2424,10 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" dependencies = [ - "proc-macro-utils 0.10.0", + "proc-macro-utils", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2937,6 +2460,55 @@ dependencies = [ "getrandom", ] +[[package]] +name = "reactive_graph" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c27f54685c1416af1f323a0c40e71cbdae281a1ebc623591790d367222d0ac65" +dependencies = [ + "any_spawner", + "async-lock", + "futures", + "guardian", + "hydration_context", + "or_poisoned", + "pin-project-lite", + "rustc-hash 2.1.0", + "send_wrapper", + "serde", + "slotmap", + "thiserror 2.0.7", + "web-sys", +] + +[[package]] +name = "reactive_stores" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe3f866edc7647e19a68a229a2e5cc9730549836d722eeaa073116f2b07966e" +dependencies = [ + "guardian", + "itertools", + "or_poisoned", + "paste", + "reactive_graph", + "reactive_stores_macro", + "rustc-hash 2.1.0", +] + +[[package]] +name = "reactive_stores_macro" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d86e4f08f361b05d11422398cef4bc4cf356f2fdd2f06a96646b0e9cd902226" +dependencies = [ + "convert_case 0.6.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -2965,17 +2537,8 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -2986,7 +2549,7 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] [[package]] @@ -2995,12 +2558,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.5" @@ -3009,14 +2566,15 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rstml" -version = "0.11.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe542870b8f59dd45ad11d382e5339c9a1047cde059be136a7016095bbdefa77" +checksum = "51187e564f12336ef40cd04f6f4d805d6919188001dcf1e0a021898ea0fe28ce" dependencies = [ + "derive-where", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.90", + "syn", "syn_derive", "thiserror 1.0.69", ] @@ -3033,6 +2591,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc_version" version = "0.4.1" @@ -3114,17 +2678,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - [[package]] name = "serde_derive" version = "1.0.216" @@ -3133,7 +2686,7 @@ checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3158,17 +2711,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "serde_qs" version = "0.13.0" @@ -3189,15 +2731,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_test" -version = "1.0.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3225,14 +2758,13 @@ dependencies = [ [[package]] name = "server_fn" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fae7a3038a32e5a34ba32c6c45eb4852f8affaf8b794ebfcd4b1099e2d62ebe" +checksum = "033cb8014aa86a7ce0c6ee58d23dce1a078b2e320dc6c53bb439663993199b1f" dependencies = [ "actix-web", "axum", "bytes", - "ciborium", "const_format", "dashmap", "futures", @@ -3243,13 +2775,15 @@ dependencies = [ "inventory", "js-sys", "once_cell", + "pin-project-lite", "send_wrapper", "serde", "serde_json", - "serde_qs 0.12.0", + "serde_qs", "server_fn_macro_default", - "thiserror 1.0.69", - "tower 0.4.13", + "thiserror 2.0.7", + "throw_error", + "tower", "tower-layer", "url", "wasm-bindgen", @@ -3261,26 +2795,26 @@ dependencies = [ [[package]] name = "server_fn_macro" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaaf648c6967aef78177c0610478abb5a3455811f401f3c62d10ae9bd3901a1" +checksum = "0249e8a55ca464a1e69f02a95d562f2c65e92e301093a02ebf15d21f68f2a99e" dependencies = [ "const_format", "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn", "xxhash-rust", ] [[package]] name = "server_fn_macro_default" -version = "0.6.15" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2aa8119b558a17992e0ac1fd07f080099564f24532858811ce04f742542440" +checksum = "91c54a6d43cd0f3d2bdf0c85b6119f378b6b89d528159af9cde77f229faeecbc" dependencies = [ "server_fn_macro", - "syn 2.0.90", + "syn", ] [[package]] @@ -3305,15 +2839,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" @@ -3344,7 +2869,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ - "serde", "version_check", ] @@ -3376,23 +2900,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.90" @@ -3413,7 +2920,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3430,28 +2937,41 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] -name = "system-deps" -version = "7.0.3" +name = "tachys" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" +checksum = "8be68dfd4abf192e11a1bdd484239daa84ffa6fcd27c25cf4f011b2b0fb27ddb" dependencies = [ - "cfg-expr 0.17.2", - "heck", - "pkg-config", - "toml", - "version-compare", + "any_spawner", + "const_str_slice_concat", + "drain_filter_polyfill", + "either_of", + "futures", + "html-escape", + "indexmap", + "itertools", + "js-sys", + "linear-map", + "next_tuple", + "oco_ref", + "once_cell", + "or_poisoned", + "parking_lot", + "paste", + "reactive_graph", + "reactive_stores", + "rustc-hash 2.1.0", + "send_wrapper", + "slotmap", + "throw_error", + "wasm-bindgen", + "web-sys", ] -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - [[package]] name = "target-triple" version = "0.1.3" @@ -3473,6 +2993,7 @@ version = "0.1.0" dependencies = [ "js-sys", "leptos", + "leptos_meta", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3504,7 +3025,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3515,17 +3036,16 @@ checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] -name = "thread_local" -version = "1.1.8" +name = "throw_error" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "e4ef8bf264c6ae02a065a4a16553283f0656bd6266fc1fcb09fd2e6b5e91427b" dependencies = [ - "cfg-if", - "once_cell", + "pin-project-lite", ] [[package]] @@ -3595,7 +3115,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3607,8 +3127,6 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "futures-util", - "hashbrown 0.14.5", "pin-project-lite", "tokio", ] @@ -3647,21 +3165,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.2" @@ -3680,9 +3183,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ "bitflags", "bytes", @@ -3727,18 +3230,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror 1.0.69", - "time", - "tracing-subscriber", -] - [[package]] name = "tracing-attributes" version = "0.1.28" @@ -3747,7 +3238,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3759,22 +3250,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "thread_local", - "tracing", - "tracing-core", -] - [[package]] name = "trybuild" version = "1.0.101" @@ -3796,27 +3271,27 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] name = "typed-builder" -version = "0.18.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" +checksum = "7e14ed59dc8b7b26cacb2a92bad2e8b1f098806063898ab42a3bd121d7d45e75" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.18.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" +checksum = "560b82d656506509d43abe30e0ba64c56b1953ab3d4fe7ba5902747a7a3cedd5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3870,7 +3345,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.90", + "syn", "unic-langid-impl", ] @@ -3948,12 +3423,6 @@ version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - [[package]] name = "version_check" version = "0.9.5" @@ -3997,7 +3466,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn", "wasm-bindgen-shared", ] @@ -4032,7 +3501,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4065,7 +3534,7 @@ checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -4323,7 +3792,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "synstructure", ] @@ -4345,7 +3814,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -4365,7 +3834,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "synstructure", ] @@ -4388,7 +3857,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 13154f2b..db202154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,6 @@ members = [ "examples/csr-minimal", "examples/ssr-hydrate-actix", "examples/ssr-hydrate-axum", - "examples/ssr-islands-axum", - "examples/system-gtk", ] resolver = "2" diff --git a/README.md b/README.md index cc6d0080..c8802795 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -leptos-fluent = "0.1" +leptos-fluent = "0.2" fluent-templates = "0.11" [features] @@ -75,7 +75,7 @@ You can use `leptos-fluent` as follows: ```rust use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, tr}; static_loader! { @@ -86,10 +86,11 @@ static_loader! { } #[component] -fn App() -> impl IntoView { +fn I18n(children: Children) -> impl IntoView { // See all options in the reference at // https://mondeja.github.io/leptos-fluent/leptos_fluent.html leptos_fluent! { + children: children(), // Path to the locales directory, relative to Cargo.toml. locales: "./locales", // Static translations struct provided by fluent-templates. @@ -174,11 +175,16 @@ fn App() -> impl IntoView { data_file_key: "my-app", // Set the language selected to a data file. set_language_to_data_file: true, - }; + } +} +#[component] +pub fn App() -> impl IntoView { view! { - - + + + + } } @@ -202,11 +208,13 @@ fn TranslatableComponent() -> impl IntoView { #[component] fn LanguageSelector() -> impl IntoView { // `expect_i18n()` to get the i18n context - // `i18n.languages` is a static array with the available languages - // `i18n.language.get()` to get the current language - // `lang.activate()` to set the current language + // `i18n.languages` exposes a static array with the available languages + // `i18n.language.read()` to get the current language + // `lang.activate()` or `i18n.language.set(lang)` to set the current language // `lang.is_active()` to check if a language is the current selected one + let i18n = expect_i18n(); + view! {
{ @@ -219,7 +227,7 @@ fn LanguageSelector() -> impl IntoView { name="language" value=lang checked=lang.is_active() - on:click=move |_| lang.activate() + on:click=move |_| i18n.language.set(lang) /> diff --git a/book/src/basic-usage.md b/book/src/basic-usage.md index 8fd5dbd6..96e17ad8 100644 --- a/book/src/basic-usage.md +++ b/book/src/basic-usage.md @@ -34,7 +34,7 @@ language-selected-is = El idioma seleccionado es { $lang }. ```rust // src/lib.rs use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, Language}; static_loader! { @@ -98,7 +98,7 @@ fn render_language(lang: &'static Language) -> impl IntoView { // src/main.rs pub fn main() { console_error_panic_hook::set_once(); - leptos::mount_to_body(minimal_example::App); + leptos::mount::mount_to_body(minimal_example::App); } ``` @@ -114,8 +114,8 @@ name = "minimal_example" path = "src/lib.rs" [dependencies] -leptos = { version = "0.6.12", features = ["csr"] } -leptos-fluent = "0.1" +leptos = { version = "0.7", features = ["csr"] } +leptos-fluent = "0.2" fluent-templates = "0.11" console_error_panic_hook = "0.1" @@ -163,7 +163,7 @@ The main difference is that [`move_tr!`] encapsulates the movement in a [`leptos::Signal`], strictly would be rewritten as: ```rust -leptos::Signal::derive(move || tr!("select-a-language")) +Signal::derive(move || tr!("select-a-language")) ``` ## Retrieving the [`I18n`] context diff --git a/book/src/faqs.md b/book/src/faqs.md index f3f6ddf5..20a92a81 100644 --- a/book/src/faqs.md +++ b/book/src/faqs.md @@ -263,7 +263,7 @@ accessed as context on server actions. Pass the translations as values if the bandwidth is not a problem or use your own statics on server side. ```rust -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{tr, Language}; /// Server action showing client-side translated message on console diff --git a/book/src/install.md b/book/src/install.md index 8bb09dff..25d99c73 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -10,7 +10,7 @@ For client side rendering apps install **leptos-fluent** and [`fluent-templates` ```toml [dependencies] -leptos-fluent = "0.1" +leptos-fluent = "0.2" fluent-templates = "0.11" ``` @@ -19,7 +19,7 @@ fluent-templates = "0.11" ```toml [dependencies] -leptos-fluent = { version = "0.1", default-features = false } +leptos-fluent = "0.2" fluent-templates = { version = "0.11", default-features = false, features = [ "macros", "walkdir" @@ -41,7 +41,7 @@ respective features set. ```toml [dependencies] -leptos-fluent = "0.1" +leptos-fluent = "0.2" fluent-templates = "0.11" [features] @@ -66,7 +66,7 @@ and enable the `system` feature: ```toml [dependencies] -leptos-fluent = { version = "0.1", features = ["system"] } +leptos-fluent = { version = "0.2", features = ["system"] } fluent-templates = "0.11" ``` @@ -95,7 +95,7 @@ feature: ```toml [dependencies] -leptos-fluent = { version = "0.1", features = ["nightly"] } +leptos-fluent = { version = "0.2", features = ["nightly"] } fluent-templates = "0.11" ``` @@ -110,7 +110,7 @@ enabled: ```toml [dependencies] fluent-templates = "0.11" -leptos-fluent = { version = "0.1", features = ["json5"], default-features = false } +leptos-fluent = { version = "0.2", features = ["json5"], default-features = false } ``` @@ -144,7 +144,7 @@ To enable [`tracing`] support, add the `tracing` feature to **leptos-fluent**: ```toml [dependencies] -leptos-fluent = { version = "0.1", features = ["tracing"] } +leptos-fluent = { version = "0.2", features = ["tracing"] } fluent-templates = "0.11" ``` @@ -155,3 +155,10 @@ See the [GTK example](https://github.com/mondeja/leptos-fluent/tree/master/examp [`fluent-templates`]: https://github.com/XAMPPRocky/fluent-templates [`cargo leptos`]: https://github.com/leptos-rs/cargo-leptos [`tracing`]: https://docs.rs/tracing/latest/tracing + +## Compatibility + +| **leptos-fluent** | **leptos** | +| ----------------- | ---------- | +| 0.2 | 0.7 | +| 0.1 | 0.6 | diff --git a/end2end/Cargo.toml b/end2end/Cargo.toml index d7ebc54f..57c8a869 100644 --- a/end2end/Cargo.toml +++ b/end2end/Cargo.toml @@ -20,7 +20,8 @@ web-sys = { version = "0.3", features = [ ] } wasm-bindgen = "0.2" wasm-bindgen-test = "0.3" -leptos = "0.6" +leptos = "0.7" +leptos_meta = "0.7" [package.metadata.cargo-machete] -ignored = ["fluent-templates"] +ignored = ["fluent-templates", "leptos_meta"] diff --git a/end2end/tests-helpers/Cargo.toml b/end2end/tests-helpers/Cargo.toml index c432c44a..376ac20c 100644 --- a/end2end/tests-helpers/Cargo.toml +++ b/end2end/tests-helpers/Cargo.toml @@ -5,8 +5,12 @@ version = "0.1.0" publish = false [dependencies] -leptos = "0.6" +leptos = "0.7" +leptos_meta = "0.7" web-sys = { version = "0.3", features = ["Navigator", "Storage"] } js-sys = "0.3" wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" + +[package.metadata.cargo-machete] +ignored = ["leptos_meta"] diff --git a/end2end/tests-helpers/src/lib.rs b/end2end/tests-helpers/src/lib.rs index a702c589..e2f5b13f 100644 --- a/end2end/tests-helpers/src/lib.rs +++ b/end2end/tests-helpers/src/lib.rs @@ -1,7 +1,7 @@ #[macro_export] macro_rules! mount { ($app:ident) => {{ - ::leptos::mount_to_body( + ::leptos::mount::mount_to_body( move || ::leptos::view! {
<$app/>
}, ); }}; @@ -11,11 +11,11 @@ macro_rules! mount { macro_rules! unmount { () => {{ use wasm_bindgen::JsCast; - ::leptos::document() + ::leptos::prelude::document() .body() .unwrap() .remove_child( - ::leptos::document() + ::leptos::prelude::document() .get_element_by_id("wrapper") .unwrap() .unchecked_ref(), @@ -26,7 +26,7 @@ macro_rules! unmount { pub async fn sleep(delay: i32) { let mut cb = |resolve: js_sys::Function, _reject: js_sys::Function| { - ::leptos::window() + ::leptos::prelude::window() .set_timeout_with_callback_and_timeout_and_arguments_0( &resolve, delay, ) @@ -38,7 +38,7 @@ pub async fn sleep(delay: i32) { } pub fn element_text(selector: &str) -> String { - ::leptos::document() + ::leptos::prelude::document() .query_selector(selector) .unwrap() .unwrap() @@ -48,7 +48,7 @@ pub fn element_text(selector: &str) -> String { pub fn input_by_id(id: &str) -> web_sys::HtmlInputElement { use wasm_bindgen::JsCast; - leptos::document() + leptos::prelude::document() .get_element_by_id(id) .unwrap() .unchecked_into::() @@ -56,7 +56,7 @@ pub fn input_by_id(id: &str) -> web_sys::HtmlInputElement { pub fn html() -> web_sys::HtmlHtmlElement { use wasm_bindgen::JsCast; - leptos::document() + leptos::prelude::document() .document_element() .unwrap() .unchecked_into::() diff --git a/end2end/tests/context_outside_reactive_ownership_tree.rs b/end2end/tests/context_outside_reactive_ownership_tree.rs index cebbc9c8..ae04fce2 100644 --- a/end2end/tests/context_outside_reactive_ownership_tree.rs +++ b/end2end/tests/context_outside_reactive_ownership_tree.rs @@ -1,8 +1,8 @@ /// See: /// - https://github.com/leptos-rs/leptos/issues/2852 /// - https://github.com/mondeja/leptos-fluent/issues/231 -use leptos::*; -use leptos_fluent::{expect_i18n, leptos_fluent}; +use leptos::{control_flow::Show, prelude::*}; +use leptos_fluent::{leptos_fluent, use_i18n}; use leptos_fluent_csr_minimal_example::TRANSLATIONS; use tests_helpers::{input_by_id, mount, unmount}; use wasm_bindgen_test::*; @@ -29,11 +29,12 @@ fn Child() -> impl IntoView {
() - .set_inner_text("CLICKED!"); + if use_i18n().is_some() { + ev.target() + .unwrap() + .unchecked_into::() + .set_inner_text("CLICKED!"); + } } > @@ -55,7 +56,7 @@ fn Child() -> impl IntoView { } #[wasm_bindgen_test] -async fn context_outise_reactive_ownership_tree() { +async fn context_outside_reactive_ownership_tree() { let fails_div = move || input_by_id("fails"); let success_div = move || input_by_id("success"); diff --git a/end2end/tests/cookie.rs b/end2end/tests/cookie.rs index bc642ca1..11608bb3 100644 --- a/end2end/tests/cookie.rs +++ b/end2end/tests/cookie.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{cookie, leptos_fluent}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, unmount}; diff --git a/end2end/tests/cookie_to_localstorage.rs b/end2end/tests/cookie_to_localstorage.rs index 507aa3ad..d176d4cb 100644 --- a/end2end/tests/cookie_to_localstorage.rs +++ b/end2end/tests/cookie_to_localstorage.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{cookie, leptos_fluent, localstorage}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, unmount}; diff --git a/end2end/tests/csr_complete.rs b/end2end/tests/csr_complete.rs index 7adcde46..006ba7b5 100644 --- a/end2end/tests/csr_complete.rs +++ b/end2end/tests/csr_complete.rs @@ -1,3 +1,4 @@ +use leptos::prelude::*; use leptos_fluent::localstorage; use leptos_fluent_csr_complete_example::App; use tests_helpers::{element_text, html, input_by_id, mount, sleep, unmount}; @@ -15,12 +16,15 @@ async fn csr_complete_example() { // translations working en().click(); + sleep(30).await; assert_eq!(element_text("p"), "Select a language:"); es().click(); + sleep(30).await; assert!(es().checked()); assert!(!en().checked()); assert_eq!(element_text("p"), "Selecciona un idioma:"); en().click(); + sleep(30).await; assert!(en().checked()); assert_eq!(element_text("p"), "Select a language:"); assert!(!es().checked()); @@ -46,8 +50,10 @@ async fn csr_complete_example() { localstorage::delete("language"); assert_eq!(localstorage::get("language"), None); es().click(); + sleep(30).await; assert_eq!(localstorage::get("language"), Some("es".to_string())); en().click(); + sleep(30).await; assert_eq!(localstorage::get("language"), Some("en".to_string())); localstorage::delete("language"); diff --git a/end2end/tests/csr_minimal.rs b/end2end/tests/csr_minimal.rs index 20f01582..18c3ce30 100644 --- a/end2end/tests/csr_minimal.rs +++ b/end2end/tests/csr_minimal.rs @@ -1,3 +1,4 @@ +use leptos::prelude::*; use leptos_fluent::localstorage; use leptos_fluent_csr_minimal_example::App; use tests_helpers::{element_text, html, input_by_id, mount, sleep, unmount}; @@ -17,6 +18,7 @@ async fn csr_minimal_example() { // translations working assert_eq!(element_text("p"), "Select a language:"); es().click(); + sleep(30).await; assert!(es().checked()); assert!(!en().checked()); assert_eq!(element_text("p"), "Selecciona un idioma:"); @@ -25,8 +27,10 @@ async fn csr_minimal_example() { localstorage::delete("language"); assert_eq!(localstorage::get("language"), None); en().click(); + sleep(30).await; assert_eq!(localstorage::get("language"), None); es().click(); + sleep(30).await; assert_eq!(localstorage::get("language"), None); // sync_html_tag_lang not activated @@ -34,9 +38,11 @@ async fn csr_minimal_example() { html().remove_attribute("lang").unwrap(); assert_eq!(html().lang(), "".to_string()); es().click(); + sleep(30).await; assert!(es().checked()); assert_eq!(html().lang(), "".to_string()); en().click(); + sleep(30).await; assert!(en().checked()); assert_eq!(html().lang(), "".to_string()); diff --git a/end2end/tests/localstorage.rs b/end2end/tests/localstorage.rs index 80819cb9..1af15c88 100644 --- a/end2end/tests/localstorage.rs +++ b/end2end/tests/localstorage.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{leptos_fluent, localstorage}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, unmount}; diff --git a/end2end/tests/localstorage_to_cookie.rs b/end2end/tests/localstorage_to_cookie.rs index 0237fd03..087557f9 100644 --- a/end2end/tests/localstorage_to_cookie.rs +++ b/end2end/tests/localstorage_to_cookie.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{cookie, leptos_fluent, localstorage}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, unmount}; diff --git a/end2end/tests/url_param.rs b/end2end/tests/url_param.rs index 6ecd14e1..254c1b92 100644 --- a/end2end/tests/url_param.rs +++ b/end2end/tests/url_param.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{leptos_fluent, url}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, sleep, unmount}; @@ -28,17 +28,17 @@ async fn test_url_param() { // set_language_to_url_param mount!(App); - assert_eq!(leptos::window().location().search().unwrap(), ""); + assert_eq!(leptos::prelude::window().location().search().unwrap(), ""); es().click(); sleep(30).await; assert_eq!( - leptos::window().location().search().unwrap(), + leptos::prelude::window().location().search().unwrap(), format!("?{URL_PARAM}=es") ); en().click(); sleep(30).await; assert_eq!( - leptos::window().location().search().unwrap(), + leptos::prelude::window().location().search().unwrap(), format!("?{URL_PARAM}=en") ); unmount!(); diff --git a/end2end/tests/url_param_to_cookie.rs b/end2end/tests/url_param_to_cookie.rs index e055c540..7017bedd 100644 --- a/end2end/tests/url_param_to_cookie.rs +++ b/end2end/tests/url_param_to_cookie.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{cookie, leptos_fluent, url}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, unmount}; diff --git a/end2end/tests/url_param_to_localstorage.rs b/end2end/tests/url_param_to_localstorage.rs index 83dee5d2..a058b88a 100644 --- a/end2end/tests/url_param_to_localstorage.rs +++ b/end2end/tests/url_param_to_localstorage.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{leptos_fluent, localstorage, url}; use leptos_fluent_csr_minimal_example::{LanguageSelector, TRANSLATIONS}; use tests_helpers::{element_text, input_by_id, mount, unmount}; diff --git a/examples/csr-complete/Cargo.toml b/examples/csr-complete/Cargo.toml index d9729943..17c83fa9 100644 --- a/examples/csr-complete/Cargo.toml +++ b/examples/csr-complete/Cargo.toml @@ -9,7 +9,7 @@ name = "leptos_fluent_csr_complete_example" path = "src/lib.rs" [dependencies] -leptos = { version = "0.6", features = ["csr"] } +leptos = { version = "0.7", features = ["csr"] } leptos-fluent = { path = "../../leptos-fluent", features = ["json"] } fluent-templates = { version = "0.11", default-features = false, features = [ "macros", diff --git a/examples/csr-complete/src/lib.rs b/examples/csr-complete/src/lib.rs index 268b9f06..97158da3 100644 --- a/examples/csr-complete/src/lib.rs +++ b/examples/csr-complete/src/lib.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, Language}; static_loader! { @@ -10,8 +10,9 @@ static_loader! { } #[component] -pub fn App() -> impl IntoView { +fn I18n(children: Children) -> impl IntoView { leptos_fluent! { + children: children(), translations: [TRANSLATIONS], languages: "./locales/languages.json", locales: "./locales", @@ -36,21 +37,26 @@ pub fn App() -> impl IntoView { initial_language_from_navigator_to_cookie: true, initial_language_from_navigator_to_localstorage: true, set_language_from_navigator: true, - }; + } +} - LanguageSelector +#[component] +pub fn App() -> impl IntoView { + view! { + + + + } } #[component] fn LanguageSelector() -> impl IntoView { - let i18n = expect_i18n(); - view! {

{move_tr!("select-a-language")}

{move || { - i18n.languages.iter().map(|lang| render_language(lang)).collect::>() + expect_i18n().languages.iter().map(|lang| render_language(lang)).collect::>() }}
@@ -58,13 +64,17 @@ fn LanguageSelector() -> impl IntoView {
  • - {move_tr!("html-tag-lang-is", { "lang" => i18n.language.get().id.to_string() })} + {move_tr!( + "html-tag-lang-is", { "lang" => expect_i18n().language.read().id.to_string() } + )}

    {move_tr!("add-es-en-url-param")}

  • - {move_tr!("html-tag-dir-is", { "dir" => i18n.language.get().dir.to_string() })} + {move_tr!( + "html-tag-dir-is", { "dir" => expect_i18n().language.read().dir.to_string() } + )}

@@ -74,6 +84,7 @@ fn LanguageSelector() -> impl IntoView { fn render_language(lang: &'static Language) -> impl IntoView { // Passed as atrribute, `Language` is converted to their code, // so ` impl IntoView { name="language" value=lang checked=lang.is_active() - on:click=move |_| lang.activate() + on:click=move |_| i18n.language.set(lang) type="radio" /> diff --git a/examples/csr-complete/src/main.rs b/examples/csr-complete/src/main.rs index cc810413..10632ad0 100644 --- a/examples/csr-complete/src/main.rs +++ b/examples/csr-complete/src/main.rs @@ -1,7 +1,4 @@ -use leptos::*; -use leptos_fluent_csr_complete_example::App; - pub fn main() { console_error_panic_hook::set_once(); - mount_to_body(App); + leptos::mount::mount_to_body(leptos_fluent_csr_complete_example::App); } diff --git a/examples/csr-minimal/Cargo.toml b/examples/csr-minimal/Cargo.toml index ce7b845a..bfd3fa4f 100644 --- a/examples/csr-minimal/Cargo.toml +++ b/examples/csr-minimal/Cargo.toml @@ -9,8 +9,8 @@ name = "leptos_fluent_csr_minimal_example" path = "src/lib.rs" [dependencies] -leptos = { version = "0.6", features = ["csr"] } -leptos-fluent = { path = "../../leptos-fluent", default-features = false } +leptos = { version = "0.7", features = ["csr"] } +leptos-fluent = { path = "../../leptos-fluent" } fluent-templates = { version = "0.11", default-features = false, features = [ "macros", "walkdir" diff --git a/examples/csr-minimal/src/lib.rs b/examples/csr-minimal/src/lib.rs index 00a04695..589b6860 100644 --- a/examples/csr-minimal/src/lib.rs +++ b/examples/csr-minimal/src/lib.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr}; static_loader! { @@ -10,13 +10,21 @@ static_loader! { } #[component] -pub fn App() -> impl IntoView { +pub fn I18n(children: Children) -> impl IntoView { leptos_fluent! { + children: children(), translations: [TRANSLATIONS], locales: "./locales", - }; + } +} - LanguageSelector +#[component] +pub fn App() -> impl IntoView { + view! { + + + + } } #[component] @@ -39,7 +47,7 @@ pub fn LanguageSelector() -> impl IntoView { name="language" value=lang checked=lang.is_active() - on:click=move |_| lang.activate() + on:click=move |_| i18n.language.set(lang) />
diff --git a/examples/csr-minimal/src/main.rs b/examples/csr-minimal/src/main.rs index 49c1ada7..e90ddf91 100644 --- a/examples/csr-minimal/src/main.rs +++ b/examples/csr-minimal/src/main.rs @@ -1,4 +1,4 @@ pub fn main() { console_error_panic_hook::set_once(); - leptos::mount_to_body(leptos_fluent_csr_minimal_example::App); + leptos::mount::mount_to_body(leptos_fluent_csr_minimal_example::App); } diff --git a/examples/ssr-hydrate-actix/Cargo.toml b/examples/ssr-hydrate-actix/Cargo.toml index c4708353..a19951a0 100644 --- a/examples/ssr-hydrate-actix/Cargo.toml +++ b/examples/ssr-hydrate-actix/Cargo.toml @@ -11,10 +11,10 @@ crate-type = ["cdylib", "rlib"] actix-files = { version = "0.6", optional = true } actix-web = { version = "4", optional = true } console_error_panic_hook = "0.1" -leptos = "0.6" -leptos_meta = "0.6" -leptos_actix = { version = "0.6", optional = true } -leptos_router = "0.6" +leptos = "0.7" +leptos_meta = "0.7" +leptos_actix = { version = "0.7", optional = true } +leptos_router = "0.7" leptos-fluent = { path = "../../leptos-fluent" } fluent-templates = { version = "0.11", default-features = false, features = [ "macros", @@ -23,11 +23,8 @@ fluent-templates = { version = "0.11", default-features = false, features = [ wasm-bindgen = "=0.2.99" [features] -csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"] hydrate = [ "leptos/hydrate", - "leptos_meta/hydrate", - "leptos_router/hydrate", "leptos-fluent/hydrate", ] ssr = [ diff --git a/examples/ssr-hydrate-actix/README.md b/examples/ssr-hydrate-actix/README.md index 3e971dbd..985ccad6 100644 --- a/examples/ssr-hydrate-actix/README.md +++ b/examples/ssr-hydrate-actix/README.md @@ -3,9 +3,3 @@ ```sh cargo leptos watch ``` - -This example can be also compiled with CSR support: - -```sh -trunk serve --open --features csr -``` diff --git a/examples/ssr-hydrate-actix/index.html b/examples/ssr-hydrate-actix/index.html deleted file mode 100644 index dfd44270..00000000 --- a/examples/ssr-hydrate-actix/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/examples/ssr-hydrate-actix/src/app.rs b/examples/ssr-hydrate-actix/src/app.rs index 726d85bf..375722d7 100644 --- a/examples/ssr-hydrate-actix/src/app.rs +++ b/examples/ssr-hydrate-actix/src/app.rs @@ -1,8 +1,11 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::{prelude::*, task::spawn}; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, tr, Language}; -use leptos_meta::*; -use leptos_router::*; +use leptos_meta::{provide_meta_context, Title}; +use leptos_router::{ + components::{FlatRoutes, Route, Router}, + StaticSegment, +}; static_loader! { static TRANSLATIONS = { @@ -12,9 +15,9 @@ static_loader! { } #[component] -pub fn App() -> impl IntoView { - provide_meta_context(); +fn I18n(children: Children) -> impl IntoView { leptos_fluent! { + children: children(), translations: [TRANSLATIONS], locales: "./locales", #[cfg(debug_assertions)] check_translations: "./src/**/*.rs", @@ -49,28 +52,31 @@ pub fn App() -> impl IntoView { initial_language_from_url_path_to_cookie: true, initial_language_from_url_path_to_localstorage: true, initial_language_from_url_path_to_server_function: set_language_server_function, - }; + } +} + +#[component] +pub fn App() -> impl IntoView { + provide_meta_context(); view! { - - - // content for this welcome page - <Router> - <main> - <Routes> - <Route path="" view=HomePage /> - <Route path="/en" view=HomePage /> - <Route path="/es" view=HomePage /> - <Route path="/*any" view=NotFound /> - </Routes> - </main> - </Router> + <I18n> + <Title text=move || tr!("welcome-to-leptos") /> + + <Router> + <main> + <FlatRoutes fallback=|| "Page not found."> + <Route path=StaticSegment("") view=Home /> + </FlatRoutes> + </main> + </Router> + </I18n> } } /// Renders the home page of your application. #[component] -fn HomePage() -> impl IntoView { +fn Home() -> impl IntoView { let i18n = expect_i18n(); view! { @@ -100,7 +106,7 @@ fn render_language(lang: &'static Language) -> impl IntoView { checked=lang.is_active() on:click=move |_| { lang.activate(); - spawn_local(async { + spawn(async { _ = show_hello_world( tr!("hello-world"), tr!("language", { "lang" => lang.name.to_string() }), diff --git a/examples/ssr-hydrate-actix/src/lib.rs b/examples/ssr-hydrate-actix/src/lib.rs index 8a56b9cd..30fd2930 100644 --- a/examples/ssr-hydrate-actix/src/lib.rs +++ b/examples/ssr-hydrate-actix/src/lib.rs @@ -5,5 +5,5 @@ pub mod app; pub fn hydrate() { use app::App; console_error_panic_hook::set_once(); - leptos::mount_to_body(App); + leptos::mount::hydrate_body(App); } diff --git a/examples/ssr-hydrate-actix/src/main.rs b/examples/ssr-hydrate-actix/src/main.rs index c7d9efa9..61393cf5 100644 --- a/examples/ssr-hydrate-actix/src/main.rs +++ b/examples/ssr-hydrate-actix/src/main.rs @@ -3,51 +3,64 @@ async fn main() -> std::io::Result<()> { use actix_files::Files; use actix_web::*; - use leptos::*; + use leptos::prelude::*; use leptos_actix::{generate_route_list, LeptosRoutes}; use leptos_fluent_ssr_hydrate_actix_example::app::App; + use leptos_meta::MetaTags; - let conf = get_configuration(None).await.unwrap(); + let conf = get_configuration(None).unwrap(); let addr = conf.leptos_options.site_addr; - let routes = generate_route_list(App); - #[allow(clippy::print_stdout)] - { - println!("listening on http://{}", &addr); - }; HttpServer::new(move || { + // Generate the list of routes in your Leptos App + let routes = generate_route_list(App); let leptos_options = &conf.leptos_options; - let site_root = &leptos_options.site_root; + let site_root = leptos_options.site_root.clone().to_string(); + + #[allow(clippy::print_stdout)] + { + println!("listening on http://{}", &addr); + }; App::new() // serve JS/WASM/CSS from `pkg` .service(Files::new("/pkg", format!("{site_root}/pkg"))) // serve other assets from the `assets` directory - .service(Files::new("/assets", site_root)) - .leptos_routes(leptos_options.to_owned(), routes.to_owned(), App) + .service(Files::new("/assets", &site_root)) + .leptos_routes(routes, { + let leptos_options = leptos_options.clone(); + move || { + view! { + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="utf-8" /> + <meta + name="viewport" + content="width=device-width, initial-scale=1" + /> + <AutoReload options=leptos_options.clone() /> + <HydrationScripts options=leptos_options.clone() /> + <MetaTags /> + </head> + <body> + <App /> + </body> + </html> + } + } + }) .app_data(web::Data::new(leptos_options.to_owned())) + //.wrap(middleware::Compress::default()) }) .bind(&addr)? .run() .await } -#[cfg(not(any(feature = "ssr", feature = "csr")))] +#[cfg(not(feature = "ssr"))] pub fn main() { // no client-side main function - // unless we want this to work with e.g., Trunk for pure client-side testing + // unless we want this to work with e.g., Trunk for a purely client-side app // see lib.rs for hydration function instead - // see optional feature `csr` instead -} - -#[cfg(all(not(feature = "ssr"), feature = "csr"))] -pub fn main() { - // a client-side main function is required for using `trunk serve` - // prefer using `cargo leptos serve` instead - // to run: `trunk serve --open --features csr` - use leptos_fluent_ssr_hydrate_actix_example::app::App; - - console_error_panic_hook::set_once(); - - leptos::mount_to_body(App); } diff --git a/examples/ssr-hydrate-axum/Cargo.toml b/examples/ssr-hydrate-axum/Cargo.toml index 0bfb84d5..f311a8f7 100644 --- a/examples/ssr-hydrate-axum/Cargo.toml +++ b/examples/ssr-hydrate-axum/Cargo.toml @@ -10,15 +10,11 @@ crate-type = ["cdylib", "rlib"] [dependencies] axum = { version = "0.7", optional = true } console_error_panic_hook = "0.1" -tower = { version = "0.4", optional = true, features = ["util"] } -tower-http = { version = "0.5", features = ["fs"], optional = true } -http = "1" -thiserror = "1" tokio = { version = "1", features = ["rt-multi-thread"], optional = true } -leptos = "0.6" -leptos_meta = "0.6" -leptos_axum = { version = "0.6", optional = true } -leptos_router = "0.6" +leptos = "0.7" +leptos_meta = "0.7" +leptos_axum = { version = "0.7", optional = true } +leptos_router = "0.7" leptos-fluent = { path = "../../leptos-fluent", features = [ "yaml" ], default-features = false } @@ -29,19 +25,15 @@ fluent-templates = { version = "0.11", default-features = false, features = [ wasm-bindgen = "=0.2.99" [features] -csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"] +csr = ["leptos/csr"] hydrate = [ "leptos/hydrate", - "leptos_meta/hydrate", - "leptos_router/hydrate", "leptos-fluent/hydrate", ] ssr = [ "dep:axum", "dep:tokio", "dep:leptos_axum", - "dep:tower", - "dep:tower-http", "leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr", diff --git a/examples/ssr-hydrate-axum/README.md b/examples/ssr-hydrate-axum/README.md index 844f9bfb..801103eb 100644 --- a/examples/ssr-hydrate-axum/README.md +++ b/examples/ssr-hydrate-axum/README.md @@ -3,9 +3,3 @@ ```sh cargo leptos watch ``` - -This example can be also compiled with CSR support: - -```sh -trunk serve --open --features csr -``` diff --git a/examples/ssr-hydrate-axum/index.html b/examples/ssr-hydrate-axum/index.html deleted file mode 100644 index dfd44270..00000000 --- a/examples/ssr-hydrate-axum/index.html +++ /dev/null @@ -1,7 +0,0 @@ -<!doctype html> -<html> - <head> - <link data-trunk rel="rust" data-wasm-opt="z" data-target-name="main" /> - </head> - <body></body> -</html> diff --git a/examples/ssr-hydrate-axum/locales/en/main.ftl b/examples/ssr-hydrate-axum/locales/en/main.ftl index 8ce537dc..6704b4d6 100644 --- a/examples/ssr-hydrate-axum/locales/en/main.ftl +++ b/examples/ssr-hydrate-axum/locales/en/main.ftl @@ -1,7 +1,3 @@ welcome-to-leptos = Welcome to Leptos! -some-errors-happened = Some errors happened -an-error-happened = An error happened -error-msg = Error message: { $msg } -error-code = Error code: { $code } -a-translated-header = A translated header not-found = Not found +select-a-language = Select a language: diff --git a/examples/ssr-hydrate-axum/locales/es/main.ftl b/examples/ssr-hydrate-axum/locales/es/main.ftl index 2c85ddaa..75a44946 100644 --- a/examples/ssr-hydrate-axum/locales/es/main.ftl +++ b/examples/ssr-hydrate-axum/locales/es/main.ftl @@ -1,7 +1,3 @@ welcome-to-leptos = Ā”Bienvenido a Leptos! -some-errors-happened = Ocurrieron algunos errores -an-error-happened = OcurriĆ³ un error -error-msg = Mensaje de error: { $msg } -error-code = CĆ³digo de error: { $code } -a-translated-header = Un encabezado traducido not-found = No encontrado +select-a-language = Selecciona un idioma: diff --git a/examples/ssr-hydrate-axum/src/app.rs b/examples/ssr-hydrate-axum/src/app.rs index d5f92943..ac4387a0 100644 --- a/examples/ssr-hydrate-axum/src/app.rs +++ b/examples/ssr-hydrate-axum/src/app.rs @@ -1,11 +1,30 @@ -use crate::error_template::{AppError, ErrorTemplate}; use fluent_templates::once_cell::sync::Lazy; -use fluent_templates::static_loader; -use fluent_templates::StaticLoader; -use leptos::*; +use fluent_templates::{static_loader, StaticLoader}; +use leptos::prelude::*; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, tr}; -use leptos_meta::Title; -use leptos_router::*; +use leptos_meta::{MetaTags, Title}; +use leptos_router::{ + components::{Route, Router, Routes}, + StaticSegment, +}; + +pub fn shell(options: LeptosOptions) -> impl IntoView { + view! { + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <AutoReload options=options.clone() /> + <HydrationScripts options /> + <MetaTags /> + </head> + <body> + <App /> + </body> + </html> + } +} static_loader! { static TRANSLATIONS = { @@ -17,8 +36,9 @@ static_loader! { pub static COMPOUND: &[&Lazy<StaticLoader>] = &[&TRANSLATIONS, &TRANSLATIONS]; #[component] -pub fn App() -> impl IntoView { +fn I18n(children: Children) -> impl IntoView { leptos_fluent! { + children: children(), translations: [TRANSLATIONS, TRANSLATIONS] + COMPOUND, locales: "./locales", check_translations: "./src/**/*.rs", @@ -41,33 +61,32 @@ pub fn App() -> impl IntoView { initial_language_from_navigator: true, initial_language_from_navigator_to_localstorage: true, initial_language_from_accept_language_header: true, - }; + } +} +#[component] +pub fn App() -> impl IntoView { view! { - <Title text=move || tr!("welcome-to-leptos") /> + <I18n> + <Title text=move || tr!("welcome-to-leptos") /> - // content for this welcome page - <Router fallback=|| { - let mut outside_errors = Errors::default(); - outside_errors.insert_with_default_key(AppError::NotFound); - view! { <ErrorTemplate outside_errors /> }.into_view() - }> - <main> - <Routes> - <Route path="" view=HomePage /> - </Routes> - </main> - </Router> + <Router> + <main> + <Routes fallback=|| tr!("not-found").into_view()> + <Route path=StaticSegment("/") view=Home /> + </Routes> + </main> + </Router> + </I18n> } } -/// Renders the home page of your application. #[component] -fn HomePage() -> impl IntoView { +fn Home() -> impl IntoView { let i18n = expect_i18n(); view! { - <h1>{move_tr!("welcome-to-leptos")}</h1> + <h1>{move_tr!("select-a-language")}</h1> <fieldset> {move || { diff --git a/examples/ssr-hydrate-axum/src/error_template.rs b/examples/ssr-hydrate-axum/src/error_template.rs deleted file mode 100644 index 57532eb7..00000000 --- a/examples/ssr-hydrate-axum/src/error_template.rs +++ /dev/null @@ -1,87 +0,0 @@ -use http::status::StatusCode; -use leptos::*; -use leptos_fluent::{move_tr, tr}; -use thiserror::Error; - -#[derive(Clone, Debug, Error)] -pub enum AppError { - #[error("Not Found")] - NotFound, -} - -impl AppError { - pub fn status_code(&self) -> StatusCode { - match self { - AppError::NotFound => StatusCode::NOT_FOUND, - } - } -} - -// A basic function to display errors served by the error boundaries. -// Feel free to do more complicated things here than just displaying the error. -#[component] -pub fn ErrorTemplate( - #[prop(optional)] outside_errors: Option<Errors>, - #[prop(optional)] errors: Option<RwSignal<Errors>>, -) -> impl IntoView { - let errors = match outside_errors { - Some(e) => create_rw_signal(e), - None => match errors { - Some(e) => e, - None => panic!("No Errors found and we expected errors!"), - }, - }; - // Get Errors from Signal - let errors = errors.get_untracked(); - - // Downcast lets us take a type that implements `std::error::Error` - let errors: Vec<AppError> = errors - .into_iter() - .filter_map(|(_k, v)| v.downcast_ref::<AppError>().cloned()) - .collect(); - #[allow(clippy::print_stdout)] - { - println!("Errors: {errors:#?}"); - }; - - // Only the response code for the first error is actually sent from the server - // this may be customized by the specific application - #[cfg(feature = "ssr")] - { - use leptos_axum::ResponseOptions; - let response = use_context::<ResponseOptions>(); - if let Some(response) = response { - response.set_status(errors[0].status_code()); - - let header_name = axum::http::header::HeaderName::from_static( - "some-localization", - ); - let header_value = axum::http::header::HeaderValue::from_str( - tr!("a-translated-header").as_str(), - ) - .unwrap(); - response.insert_header(header_name, header_value); - } - } - - view! { - <h1> - {if errors.len() > 1 { tr!("some-errors-happened") } else { tr!("an-error-happened") }} - </h1> - <For - // a function that returns the items we're iterating over; a signal is fine - each=move || { errors.clone().into_iter().enumerate() } - // a unique key for each item as a reference - key=|(index, _error)| *index - // renders each item to a view - children=move |error| { - let error_string = error.1.to_string(); - let error_code = error.1.status_code().to_string(); - view! { - <p>{move_tr!("error-msg", { "msg" => * error_string })}</p> - <p>{move_tr!("error-code", { "code" => error_code.clone() })}</p> - } - } - /> - } -} diff --git a/examples/ssr-hydrate-axum/src/fileserv.rs b/examples/ssr-hydrate-axum/src/fileserv.rs deleted file mode 100644 index cdb9b648..00000000 --- a/examples/ssr-hydrate-axum/src/fileserv.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::app::App; -use axum::response::Response as AxumResponse; -use axum::{ - body::Body, - extract::State, - http::{Request, Response, StatusCode}, - response::IntoResponse, -}; -use leptos::*; -use std::convert::Infallible; -use tower::util::ServiceExt; -use tower_http::services::{fs::ServeFileSystemResponseBody, ServeDir}; - -pub async fn file_and_error_handler( - State(options): State<LeptosOptions>, - req: Request<Body>, -) -> AxumResponse { - let root = options.site_root.clone(); - let (parts, body) = req.into_parts(); - - let mut static_parts = parts.clone(); - static_parts.headers.clear(); - if let Some(encodings) = parts.headers.get("accept-encoding") { - static_parts - .headers - .insert("accept-encoding", encodings.clone()); - } - - let res = get_static_file( - Request::from_parts(static_parts, Body::empty()), - &root, - ) - .await - .unwrap(); - - if res.status() == StatusCode::OK { - res.into_response() - } else { - let handler = - leptos_axum::render_app_to_stream(options.to_owned(), App); - handler(Request::from_parts(parts, body)) - .await - .into_response() - } -} - -async fn get_static_file( - request: Request<Body>, - root: &str, -) -> Result<Response<ServeFileSystemResponseBody>, Infallible> { - // `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot` - // This path is relative to the cargo root - ServeDir::new(root) - .precompressed_gzip() - .precompressed_br() - .oneshot(request) - .await -} diff --git a/examples/ssr-hydrate-axum/src/lib.rs b/examples/ssr-hydrate-axum/src/lib.rs index ae0bc029..30fd2930 100644 --- a/examples/ssr-hydrate-axum/src/lib.rs +++ b/examples/ssr-hydrate-axum/src/lib.rs @@ -1,12 +1,9 @@ pub mod app; -pub mod error_template; -#[cfg(feature = "ssr")] -pub mod fileserv; #[cfg(feature = "hydrate")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn hydrate() { use app::App; console_error_panic_hook::set_once(); - leptos::mount_to_body(App); + leptos::mount::hydrate_body(App); } diff --git a/examples/ssr-hydrate-axum/src/main.rs b/examples/ssr-hydrate-axum/src/main.rs index db2bbe22..30eaf453 100644 --- a/examples/ssr-hydrate-axum/src/main.rs +++ b/examples/ssr-hydrate-axum/src/main.rs @@ -1,23 +1,26 @@ -#[cfg(feature = "ssr")] +use axum::Router; +use leptos::prelude::*; +use leptos_axum::{generate_route_list, LeptosRoutes}; +use leptos_fluent_ssr_hydrate_axum_example::app::{shell, App}; + #[tokio::main] async fn main() { - use axum::Router; - use leptos::*; - use leptos_axum::{generate_route_list, LeptosRoutes}; - use leptos_fluent_ssr_hydrate_axum_example::app::App; - use leptos_fluent_ssr_hydrate_axum_example::fileserv::file_and_error_handler; - - let conf = get_configuration(None).await.unwrap(); + let conf = get_configuration(None).unwrap(); let leptos_options = conf.leptos_options; let addr = leptos_options.site_addr; let routes = generate_route_list(App); // build our application with a route let app = Router::new() - .leptos_routes(&leptos_options, routes, App) - .fallback(file_and_error_handler) + .leptos_routes(&leptos_options, routes, { + let leptos_options = leptos_options.clone(); + move || shell(leptos_options.clone()) + }) + .fallback(leptos_axum::file_and_error_handler(shell)) .with_state(leptos_options); + // run our app with hyper + // `axum::Server` is a re-export of `hyper::Server` let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); #[allow(clippy::print_stdout)] { @@ -28,22 +31,9 @@ async fn main() { .unwrap(); } -#[cfg(not(any(feature = "ssr", feature = "csr")))] +#[cfg(not(feature = "ssr"))] pub fn main() { // no client-side main function - // unless we want this to work with e.g., Trunk for pure client-side testing + // unless we want this to work with e.g., Trunk for a purely client-side app // see lib.rs for hydration function instead - // see optional feature `csr` instead -} - -#[cfg(all(not(feature = "ssr"), feature = "csr"))] -pub fn main() { - // a client-side main function is required for using `trunk serve` - // prefer using `cargo leptos serve` instead - // to run: `trunk serve --open --features csr` - use leptos_fluent_ssr_hydrate_axum_example::app::App; - - console_error_panic_hook::set_once(); - - leptos::mount_to_body(App); } diff --git a/examples/ssr-islands-axum/Cargo.toml b/examples/ssr-islands-axum/Cargo.toml deleted file mode 100644 index de784bbe..00000000 --- a/examples/ssr-islands-axum/Cargo.toml +++ /dev/null @@ -1,119 +0,0 @@ -[package] -name = "leptos-fluent-ssr-islands-axum-example" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -axum = { version = "0.7", optional = true } -console_error_panic_hook = "0.1" -leptos = { version = "0.6", features = ["experimental-islands"] } -leptos_axum = { version = "0.6", optional = true, features = [ - "experimental-islands", -] } -leptos_meta = { version = "0.6" } -leptos_router = { version = "0.6" } -tokio = { version = "1", features = ["rt-multi-thread"], optional = true } -tower = { version = "0.4", optional = true, features = ["util"] } -tower-http = { version = "0.5", features = ["fs"], optional = true } -wasm-bindgen = "=0.2.99" -thiserror = "1" -http = "1" -serde = "1" -leptos-fluent = { path = "../../leptos-fluent", features = ["json"] } -fluent-templates = { version = "0.11", default-features = false, features = [ - "macros", - "walkdir", -] } - -[features] -hydrate = [ - "leptos/hydrate", - "leptos_meta/hydrate", - "leptos_router/hydrate", - "leptos-fluent/hydrate", -] -ssr = [ - "dep:axum", - "dep:tokio", - "dep:tower", - "dep:tower-http", - "dep:leptos_axum", - "leptos/ssr", - "leptos_meta/ssr", - "leptos_router/ssr", - "leptos-fluent/ssr", - "leptos-fluent/axum", -] - -[package.metadata.leptos] -# Additional files your application could depends on. -# A change to any file in those directories will trigger a rebuild. -watch-additional-files = ["examples/ssr-islands-axum/locales"] - -# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name -output-name = "leptos-fluent-ssr-islands-axum-example" - -# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup. -site-root = "target/site-islands" - -# The site-root relative folder where all compiled output (JS, WASM and CSS) is written -# Defaults to pkg -site-pkg-dir = "pkg" - -# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css -style-file = "style/main.css" -# Assets source dir. All files found here will be copied and synchronized to site-root. -# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir. -# -# Optional. Env: LEPTOS_ASSETS_DIR. -assets-dir = "public" - -# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup. -site-addr = "127.0.0.1:3000" - -# The port to use for automatic reload monitoring -reload-port = 3001 - -# [Optional] Command to use when running end2end tests. It will run in the end2end dir. -# [Windows] for non-WSL use "npx.cmd playwright test" -# This binary name can be checked in Powershell with Get-Command npx -end2end-cmd = "npx playwright test" -end2end-dir = "end2end" - -# The browserlist query used for optimizing the CSS. -browserquery = "defaults" - -# The environment Leptos will run in, usually either "DEV" or "PROD" -env = "DEV" - -# The features to use when compiling the bin target -# -# Optional. Can be over-ridden with the command line parameter --bin-features -bin-features = ["ssr"] - -# If the --no-default-features flag should be used when compiling the bin target -# -# Optional. Defaults to false. -bin-default-features = false - -# The features to use when compiling the lib target -# -# Optional. Can be over-ridden with the command line parameter --lib-features -lib-features = ["hydrate"] - -# If the --no-default-features flag should be used when compiling the lib target -# -# Optional. Defaults to false. -lib-default-features = false - -# The profile to use for the lib target when compiling for release -# -# Optional. Defaults to "release". -lib-profile-release = "wasm-release" - -[package.metadata.cargo-machete] -ignored = ["serde"] # needed by Leptos to pass arguments to islands diff --git a/examples/ssr-islands-axum/README.md b/examples/ssr-islands-axum/README.md deleted file mode 100644 index 5321f6f7..00000000 --- a/examples/ssr-islands-axum/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# SSR example with Axum using islands for leptos-fluent - -When using the islands feature, the app is rendered as static HTML by default. -To enable interactivity, the `#[island]` macro must be applied selectively. -Typically, with an internationalization framework like `leptos-fluent`, nearly -every part of the website is translated reactively, which would require using -the `#[island]` macro extensively. - -However, this approach conflicts with one of the core principles of islands -architecture: islands should be as minimal and targeted as possible. - -To benefit from smaller WebAssembly (wasm) file sizes, this example opts to keep -all translations server-side, instead of using the dynamic translation updates -provided by `move_tr!`. The page is reloaded after a language change, ensuring -the translations are updated without excessive use of islands. - -To run: - -```sh -cargo leptos watch -``` diff --git a/examples/ssr-islands-axum/locales/client/en/main.ftl b/examples/ssr-islands-axum/locales/client/en/main.ftl deleted file mode 100644 index 503c138f..00000000 --- a/examples/ssr-islands-axum/locales/client/en/main.ftl +++ /dev/null @@ -1,2 +0,0 @@ -home = Home -page-2 = Page 2 diff --git a/examples/ssr-islands-axum/locales/client/es/main.ftl b/examples/ssr-islands-axum/locales/client/es/main.ftl deleted file mode 100644 index 751df60e..00000000 --- a/examples/ssr-islands-axum/locales/client/es/main.ftl +++ /dev/null @@ -1,2 +0,0 @@ -home = Inicio -page-2 = PĆ”gina 2 diff --git a/examples/ssr-islands-axum/locales/languages.json b/examples/ssr-islands-axum/locales/languages.json deleted file mode 100644 index 42a2eae0..00000000 --- a/examples/ssr-islands-axum/locales/languages.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - ["en", "EN"], - ["es", "ES"] -] diff --git a/examples/ssr-islands-axum/locales/server/en/main.ftl b/examples/ssr-islands-axum/locales/server/en/main.ftl deleted file mode 100644 index fcd38c83..00000000 --- a/examples/ssr-islands-axum/locales/server/en/main.ftl +++ /dev/null @@ -1,5 +0,0 @@ -welcome-to-leptos = Welcome to Leptos -select-language = Select a language -home-title = Welcome to the home page -page-2-title = Welcome to page 2 -click-me = Click me diff --git a/examples/ssr-islands-axum/locales/server/es/main.ftl b/examples/ssr-islands-axum/locales/server/es/main.ftl deleted file mode 100644 index 142ec829..00000000 --- a/examples/ssr-islands-axum/locales/server/es/main.ftl +++ /dev/null @@ -1,5 +0,0 @@ -welcome-to-leptos = Bienvenido a Leptos -select-language = Selecciona un idioma -home-title = Bienvenido a la pĆ”gina de inicio -page-2-title = Bienvenido a la pĆ”gina 2 -click-me = Haz click diff --git a/examples/ssr-islands-axum/public/favicon.ico b/examples/ssr-islands-axum/public/favicon.ico deleted file mode 100644 index 2ba8527c..00000000 Binary files a/examples/ssr-islands-axum/public/favicon.ico and /dev/null differ diff --git a/examples/ssr-islands-axum/src/app.rs b/examples/ssr-islands-axum/src/app.rs deleted file mode 100644 index 2c47bc4b..00000000 --- a/examples/ssr-islands-axum/src/app.rs +++ /dev/null @@ -1,283 +0,0 @@ -use crate::error_template::{AppError, ErrorTemplate}; -use fluent_templates::static_loader; -use leptos::*; -use leptos_fluent::{expect_i18n, leptos_fluent, tr, I18n}; -use leptos_meta::*; -use leptos_router::{Outlet, Route, Router, Routes}; - -static_loader! { - static SERVER_TRANSLATIONS = { - locales: "./locales/server", - fallback_language: "en", - }; -} - -static_loader! { - static CLIENT_TRANSLATIONS = { - locales: "./locales/client", - fallback_language: "en", - }; -} - -#[component] -pub fn App() -> impl IntoView { - // Provides context that manages stylesheets, titles, meta tags, etc. - provide_meta_context(); - provide_i18n_context(); - - view! { - <Stylesheet id="leptos" href="/pkg/leptos-fluent-ssr-islands-axum-example.css" /> - - <Title text=tr!("welcome-to-leptos") /> - - <Router fallback=|| { - let mut outside_errors = Errors::default(); - outside_errors.insert_with_default_key(AppError::NotFound); - view! { <ErrorTemplate outside_errors /> }.into_view() - }> - <Routes> - <Route path="" view=BodyView> - <Route path="" view=home::View /> - <Route path="/page-2" view=page_2::View /> - </Route> - </Routes> - </Router> - } -} - -pub fn provide_i18n_context() { - leptos_fluent! { - translations: [SERVER_TRANSLATIONS], - languages: "./locales/languages.json", - locales: "./locales/server", - sync_html_tag_lang: true, - sync_html_tag_dir: true, - cookie_name: "lang", - cookie_attrs: "SameSite=Strict; Secure; path=/; max-age=600", - initial_language_from_cookie: true, - url_param: "lang", - initial_language_from_url_param: true, - initial_language_from_url_param_to_cookie: true, - set_language_to_url_param: true, - initial_language_from_accept_language_header: true, - }; -} - -#[component] -pub fn BodyView() -> impl IntoView { - let i18n = expect_i18n(); - - // Reproviding the context after the header makes server - // translations available for `Outlet` - view! { - <header::View /> - {provide_context::<I18n>(i18n)} - <main> - <Outlet /> - </main> - } -} - -mod header { - use leptos::*; - use leptos_fluent::{expect_i18n, leptos_fluent, tr}; - use leptos_router::A; - - #[component] - pub fn View() -> impl IntoView { - view! { - <header> - <Archipelago> - <LargeMenu /> - <MobileMenu /> - </Archipelago> - </header> - } - } - - #[island] - fn Archipelago(children: Children) -> impl IntoView { - leptos_fluent! { - translations: [super::CLIENT_TRANSLATIONS], - languages: "./locales/languages.json", - locales: "./locales/client", - sync_html_tag_lang: true, - sync_html_tag_dir: true, - cookie_name: "lang", - cookie_attrs: "SameSite=Strict; Secure; path=/; max-age=600", - initial_language_from_cookie: true, - set_language_to_cookie: true, - url_param: "lang", - initial_language_from_url_param: true, - initial_language_from_url_param_to_cookie: true, - set_language_to_url_param: true, - }; - - // Children will be executed when the i18n context is ready. - // See https://book.leptos.dev/islands.html#passing-context-between-islands - // - // > Thatā€™s why in `HomePage`, I made `let tabs = move ||` a function, and - // > called it like `{tabs()}`: creating the tabs lazily this way meant that - // > the `Tabs` island would already have provided the `selected` context by - // > the time each `Tab` went looking for it. - children() - } - - #[component] - pub fn LargeMenu() -> impl IntoView { - view! { - <div class="header-large-menu"> - <A href="/">{tr!("home")}</A> - <A href="/page-2">{tr!("page-2")}</A> - <LanguageSelector name="desktop".into() /> - </div> - } - } - - #[component] - pub fn MobileMenu() -> impl IntoView { - view! { - <div class="header-mobile-menu"> - <MobileMenuButton> - <MobileMenuPanel> - <LanguageSelector name="mobile".into() /> - </MobileMenuPanel> - </MobileMenuButton> - </div> - } - } - - #[island] - pub fn MobileMenuButton(children: Children) -> impl IntoView { - let (is_mobile_menu_visible, set_mobile_menu_visibility) = - create_signal(false); - provide_context(is_mobile_menu_visible); - - view! { - <button - class="mobile-button" - on:click=move |_| { - set_mobile_menu_visibility.update(|is_visible| *is_visible = !*is_visible); - } - > - - <svg - fill="none" - viewBox="0 0 24 24" - stroke-width="1.5" - stroke="black" - aria-hidden="true" - style="width: 30px; height: 30px" - > - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" - ></path> - </svg> - </button> - <div - class="mobile-menu-panel-hidder" - class:hidden=move || !is_mobile_menu_visible.get() - on:click=move |_| { - set_mobile_menu_visibility.set(false); - } - ></div> - {children()} - } - } - - #[island] - pub fn MobileMenuPanel(children: Children) -> impl IntoView { - let is_mobile_menu_visible = expect_context::<ReadSignal<bool>>(); - - view! { - <div class="mobile-menu-panel" class:hidden=move || !is_mobile_menu_visible.get()> - <a href="/">{tr!("home")}</a> - <a href="/page-2">{tr!("page-2")}</a> - {children()} - </div> - } - } - - #[island] - fn LanguageSelector(#[allow(dead_code)] name: String) -> impl IntoView { - let i18n = expect_i18n(); - - // A page reload is necessary after changing the language because - // the translations are stored on the server. This ensures that all - // content is updated to reflect the selected language. - view! { - <div class="language-selector"> - {i18n - .languages - .iter() - .map(|lang| { - view! { - <div> - <input - type="radio" - name=format!("language-{}", name) - value=lang - checked=lang.is_active() - on:click=move |_| { - i18n.language.set(lang); - window() - .location() - .reload() - .expect("Failed to reload the page"); - } - /> - - <label>{lang.name}</label> - </div> - } - }) - .collect::<Vec<_>>()} - - </div> - } - } -} - -mod home { - use leptos::*; - use leptos_fluent::tr; - - #[component] - pub fn View() -> impl IntoView { - view! { - <h1>{tr!("home-title")}</h1> - <HomeCounter>{tr!("click-me")}</HomeCounter> - } - } - - #[island] - fn HomeCounter(children: Children) -> impl IntoView { - let (count, set_count) = create_signal(0); - let on_click = move |_| set_count.update(|count| *count += 1); - - view! { <button on:click=on_click>{children()} " - " {count}</button> } - } -} - -mod page_2 { - use leptos::*; - use leptos_fluent::tr; - - #[component] - pub fn View() -> impl IntoView { - view! { - <h1>{tr!("page-2-title")}</h1> - <Page2Counter>{tr!("click-me")}</Page2Counter> - } - } - - #[island] - fn Page2Counter(children: Children) -> impl IntoView { - let (count, set_count) = create_signal(0); - let on_click = move |_| set_count.update(|count| *count += 1); - - view! { <button on:click=on_click>{children()} " - " {count}</button> } - } -} diff --git a/examples/ssr-islands-axum/src/error_template.rs b/examples/ssr-islands-axum/src/error_template.rs deleted file mode 100644 index cd574f1a..00000000 --- a/examples/ssr-islands-axum/src/error_template.rs +++ /dev/null @@ -1,75 +0,0 @@ -use http::status::StatusCode; -use leptos::*; -use thiserror::Error; - -#[derive(Clone, Debug, Error)] -pub enum AppError { - #[error("Not Found")] - NotFound, -} - -impl AppError { - pub fn status_code(&self) -> StatusCode { - match self { - AppError::NotFound => StatusCode::NOT_FOUND, - } - } -} - -// A basic function to display errors served by the error boundaries. -// Feel free to do more complicated things here than just displaying the error. -#[component] -pub fn ErrorTemplate( - #[prop(optional)] outside_errors: Option<Errors>, - #[prop(optional)] errors: Option<RwSignal<Errors>>, -) -> impl IntoView { - let errors = match outside_errors { - Some(e) => create_rw_signal(e), - None => match errors { - Some(e) => e, - None => panic!("No Errors found and we expected errors!"), - }, - }; - // Get Errors from Signal - let errors = errors.get_untracked(); - - // Downcast lets us take a type that implements `std::error::Error` - let errors: Vec<AppError> = errors - .into_iter() - .filter_map(|(_k, v)| v.downcast_ref::<AppError>().cloned()) - .collect(); - #[allow(clippy::print_stdout)] - { - println!("Errors: {errors:#?}"); - }; - - // Only the response code for the first error is actually sent from the server - // this may be customized by the specific application - #[cfg(feature = "ssr")] - { - use leptos_axum::ResponseOptions; - let response = use_context::<ResponseOptions>(); - if let Some(response) = response { - response.set_status(errors[0].status_code()); - } - } - - view! { - <h1>{if errors.len() > 1 { "Errors" } else { "Error" }}</h1> - <For - // a function that returns the items we're iterating over; a signal is fine - each=move || { errors.clone().into_iter().enumerate() } - // a unique key for each item as a reference - key=|(index, _error)| *index - // renders each item to a view - children=move |error| { - let error_string = error.1.to_string(); - let error_code = error.1.status_code(); - view! { - <h2>{error_code.to_string()}</h2> - <p>"Error: " {error_string}</p> - } - } - /> - } -} diff --git a/examples/ssr-islands-axum/src/fileserv.rs b/examples/ssr-islands-axum/src/fileserv.rs deleted file mode 100644 index cdb9b648..00000000 --- a/examples/ssr-islands-axum/src/fileserv.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::app::App; -use axum::response::Response as AxumResponse; -use axum::{ - body::Body, - extract::State, - http::{Request, Response, StatusCode}, - response::IntoResponse, -}; -use leptos::*; -use std::convert::Infallible; -use tower::util::ServiceExt; -use tower_http::services::{fs::ServeFileSystemResponseBody, ServeDir}; - -pub async fn file_and_error_handler( - State(options): State<LeptosOptions>, - req: Request<Body>, -) -> AxumResponse { - let root = options.site_root.clone(); - let (parts, body) = req.into_parts(); - - let mut static_parts = parts.clone(); - static_parts.headers.clear(); - if let Some(encodings) = parts.headers.get("accept-encoding") { - static_parts - .headers - .insert("accept-encoding", encodings.clone()); - } - - let res = get_static_file( - Request::from_parts(static_parts, Body::empty()), - &root, - ) - .await - .unwrap(); - - if res.status() == StatusCode::OK { - res.into_response() - } else { - let handler = - leptos_axum::render_app_to_stream(options.to_owned(), App); - handler(Request::from_parts(parts, body)) - .await - .into_response() - } -} - -async fn get_static_file( - request: Request<Body>, - root: &str, -) -> Result<Response<ServeFileSystemResponseBody>, Infallible> { - // `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot` - // This path is relative to the cargo root - ServeDir::new(root) - .precompressed_gzip() - .precompressed_br() - .oneshot(request) - .await -} diff --git a/examples/ssr-islands-axum/src/lib.rs b/examples/ssr-islands-axum/src/lib.rs deleted file mode 100644 index f1c80ceb..00000000 --- a/examples/ssr-islands-axum/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub mod app; -pub mod error_template; -#[cfg(feature = "ssr")] -pub mod fileserv; - -#[cfg(feature = "hydrate")] -#[wasm_bindgen::prelude::wasm_bindgen] -pub fn hydrate() { - #[allow(unused_imports)] - use crate::app::*; - console_error_panic_hook::set_once(); - leptos::leptos_dom::HydrationCtx::stop_hydrating(); -} diff --git a/examples/ssr-islands-axum/src/main.rs b/examples/ssr-islands-axum/src/main.rs deleted file mode 100644 index 011847bc..00000000 --- a/examples/ssr-islands-axum/src/main.rs +++ /dev/null @@ -1,38 +0,0 @@ -#[cfg(feature = "ssr")] -#[tokio::main] -async fn main() { - use axum::Router; - use leptos::*; - use leptos_axum::{generate_route_list, LeptosRoutes}; - use leptos_fluent_ssr_islands_axum_example::app::*; - use leptos_fluent_ssr_islands_axum_example::fileserv::file_and_error_handler; - - // Setting get_configuration(None) means we'll be using cargo-leptos's env values - // For deployment these variables are: - // <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain> - // Alternately a file can be specified such as Some("Cargo.toml") - // The file would need to be included with the executable when moved to deployment - let conf = get_configuration(None).await.unwrap(); - let leptos_options = conf.leptos_options; - let addr = leptos_options.site_addr; - let routes = generate_route_list(App); - - // build our application with a route - let app = Router::new() - .leptos_routes(&leptos_options, routes, App) - .fallback(file_and_error_handler) - .with_state(leptos_options); - - let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); - logging::log!("listening on http://{}", &addr); - axum::serve(listener, app.into_make_service()) - .await - .unwrap(); -} - -#[cfg(not(feature = "ssr"))] -pub fn main() { - // no client-side main function - // unless we want this to work with e.g., Trunk for a purely client-side app - // see lib.rs for hydration function instead -} diff --git a/examples/ssr-islands-axum/style/main.css b/examples/ssr-islands-axum/style/main.css deleted file mode 100644 index a530a13f..00000000 --- a/examples/ssr-islands-axum/style/main.css +++ /dev/null @@ -1,77 +0,0 @@ -body { - font-family: sans-serif; -} - -header { - position: relative; - z-index: 20; - background-color: bisque; - padding: 10px; -} - -a { - margin-left: 5px; - margin-right: 5px; -} - -.hidden { - display: none !important; -} - -.header-large-menu { - display: none; - justify-content: center; - - @media (min-width: 1024px) { - display: flex; - } -} - -.header-mobile-menu { - display: flex; - justify-content: end; - - @media (min-width: 1024px) { - display: none; - } -} - -.mobile-button { - background: none; - border: none; - cursor: pointer; -} - -.mobile-menu-panel { - display: flex; - flex-direction: column; - background-color: bisque; - position: absolute; - top: 50px; - left: 28px; - right: 28px; - text-align: center; - border: 2px solid black; - border-radius: 5px; - padding-bottom: 5px; - z-index: 20; -} - -.mobile-menu-panel > * { - padding-top: 5px; -} - -.mobile-menu-panel-hidder { - position: fixed; - top: 0; - right: 0; - left: 0; - bottom: 0; - z-index: 10; - background-color: black; - opacity: 50%; -} - -.language-selector { - display: inline-flex; -} diff --git a/examples/system-gtk/Cargo.toml b/examples/system-gtk/Cargo.toml deleted file mode 100644 index 46c582b0..00000000 --- a/examples/system-gtk/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "leptos-fluent-gtk-example" -version = "0.1.0" -edition = "2021" - -[dependencies] -leptos = { version = "0.6", features = ["csr"] } -gtk = { version = "0.9", package = "gtk4" } -leptos-fluent = { path = "../../leptos-fluent", features = [ - "system", - "tracing" -] } -fluent-templates = { version = "0.11", default-features = false, features = [ - "macros", - "walkdir" -] } -tracing = { version = "0.1", default-features = false } -tracing-appender = "0.2" -tracing-subscriber = { version = "0.3", default-features = false, features = [ - "env-filter", - "ansi", -] } - -[build-dependencies] -system-deps = "7" - -[package.metadata.system-deps] -gtk4 = "4" diff --git a/examples/system-gtk/README.md b/examples/system-gtk/README.md deleted file mode 100644 index f61688e0..00000000 --- a/examples/system-gtk/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# GTK example for leptos-fluent - -You need to install GTK-4, in Ubuntu: - -```sh -sudo apt install libgtk-4-dev -``` - -## Build and run - -```sh -cd examples/system-gtk -cargo run -``` diff --git a/examples/system-gtk/build.rs b/examples/system-gtk/build.rs deleted file mode 100644 index eec6d526..00000000 --- a/examples/system-gtk/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - system_deps::Config::new().probe().unwrap(); -} diff --git a/examples/system-gtk/locales/en/main.ftl b/examples/system-gtk/locales/en/main.ftl deleted file mode 100644 index 30164d7d..00000000 --- a/examples/system-gtk/locales/en/main.ftl +++ /dev/null @@ -1 +0,0 @@ -count = Count: { $times } diff --git a/examples/system-gtk/locales/es/main.ftl b/examples/system-gtk/locales/es/main.ftl deleted file mode 100644 index 2acbcf65..00000000 --- a/examples/system-gtk/locales/es/main.ftl +++ /dev/null @@ -1 +0,0 @@ -count = Cuenta: { $times } diff --git a/examples/system-gtk/src/main.rs b/examples/system-gtk/src/main.rs deleted file mode 100644 index 2d5e4fb9..00000000 --- a/examples/system-gtk/src/main.rs +++ /dev/null @@ -1,119 +0,0 @@ -use fluent_templates::static_loader; -use gtk::{prelude::*, Application, ApplicationWindow, Button}; -use leptos::*; -use leptos_fluent::{expect_i18n, leptos_fluent, tr}; - -const APP_ID: &str = "dev.leptos.Counter"; - -static_loader! { - pub static TRANSLATIONS = { - locales: "./locales", - fallback_language: "en", - }; -} - -macro_rules! setup_logging { - () => { - let (non_blocking, _guard) = - tracing_appender::non_blocking(std::io::stdout()); - let filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive( - tracing::metadata::LevelFilter::TRACE.into(), - ) - .from_env() - .unwrap() - .add_directive("leptos_fluent_gtk_example=trace".parse().unwrap()) - .add_directive("leptos_fluent=trace".parse().unwrap()); - - tracing_subscriber::fmt() - .with_writer(non_blocking) - .with_env_filter(filter) - .init(); - }; -} - -#[tracing::instrument(level = "trace")] -fn main() { - setup_logging!(); - - let _ = create_runtime(); - // Create a new application - let app = Application::builder().application_id(APP_ID).build(); - - // Connect to "activate" signal of `app` - app.connect_activate(build_ui); - - let i18n = leptos_fluent! { - translations: [TRANSLATIONS], - locales: "./locales", - check_translations: "./src/**/*.rs", - initial_language_from_data_file: true, - initial_language_from_system: true, - initial_language_from_system_to_data_file: true, - set_language_to_data_file: true, - data_file_key: "leptos-fluent-gtk-example", - provide_meta_context: true, - }; - - tracing::info!("Macro parameters: {:?}", i18n.meta().unwrap()); - - // Run the application - app.run(); -} - -#[tracing::instrument(level = "trace", skip(app))] -fn build_ui(app: &Application) { - let button = counter_button(); - - let window = ApplicationWindow::builder() - .application(app) - .title("leptos-fluent + gtk4") - .child(&button) - .build(); - - window.present(); -} - -#[tracing::instrument(level = "trace")] -fn counter_button() -> Button { - let (value, set_value) = create_signal(0); - - // Create a button with label and margins - let button = Button::builder() - .margin_top(12) - .margin_bottom(12) - .margin_start(12) - .margin_end(12) - .build(); - - // Connect to "clicked" signal of `button` - button.connect_clicked(move |_| { - set_value.update(|value| *value += 1); - let i18n = expect_i18n(); - let new_lang = - match i18n.language.get_untracked().id.to_string().as_str() { - "en" => i18n.languages[1], - "es" => i18n.languages[0], - _ => i18n.languages[0], - }; - i18n.language.set(new_lang); - }); - - create_effect({ - let button = button.clone(); - tracing::debug!( - "Initial language set to \"{}\"", - expect_i18n().language.get_untracked().id - ); - move |_| { - tracing::debug!( - "New language set to \"{}\"", - expect_i18n().language.get_untracked().id - ); - button - .set_label(&tr!("count", { "times" => value.get_untracked()})); - } - }); - - button -} diff --git a/leptos-fluent-macros/Cargo.toml b/leptos-fluent-macros/Cargo.toml index 677e4f16..6dd86ac3 100644 --- a/leptos-fluent-macros/Cargo.toml +++ b/leptos-fluent-macros/Cargo.toml @@ -2,7 +2,7 @@ name = "leptos-fluent-macros" description = "Macros for leptos-fluent" edition.workspace = true -version = "0.1.26" +version = "0.2.0" license = "MIT" documentation.workspace = true repository.workspace = true @@ -40,7 +40,7 @@ tracing = { version = "0.1", optional = true } [dev-dependencies] trybuild = "1" -leptos = "0.6" +leptos = "0.7" leptos-fluent = { path = "../leptos-fluent" } [features] diff --git a/leptos-fluent-macros/src/languages.rs b/leptos-fluent-macros/src/languages.rs index f56e73ad..75c31f3b 100644 --- a/leptos-fluent-macros/src/languages.rs +++ b/leptos-fluent-macros/src/languages.rs @@ -354,7 +354,7 @@ fn generate_code_for_static_language( format!( concat!( "&::leptos_fluent::Language{{", - "id: ::fluent_templates::loader::langid!(\"{}\"),", + "id:&::fluent_templates::loader::langid!(\"{}\"),", "name:\"{}\",", "dir:{},", "flag:{}", diff --git a/leptos-fluent-macros/src/lib.rs b/leptos-fluent-macros/src/lib.rs index fb5e9371..f06a49df 100644 --- a/leptos-fluent-macros/src/lib.rs +++ b/leptos-fluent-macros/src/lib.rs @@ -35,7 +35,10 @@ use quote::quote; #[cfg(feature = "debug")] #[inline(always)] pub(crate) fn debug(msg: &str) { - println!("[leptos-fluent/debug] {}", msg); + #[allow(clippy::print_stdout)] + { + println!("[leptos-fluent/debug] {msg}"); + }; } /// Create the i18n context for internationalization. @@ -46,7 +49,7 @@ pub(crate) fn debug(msg: &str) { /// /// ```rust,ignore /// use fluent_templates::static_loader; -/// use leptos::*; +/// use leptos::prelude::*; /// use leptos_fluent::leptos_fluent; /// /// static_loader! { @@ -57,8 +60,9 @@ pub(crate) fn debug(msg: &str) { /// } /// /// #[component] -/// pub fn App() -> impl IntoView { +/// pub fn I18n(children: Children) -> impl IntoView { /// leptos_fluent! { +/// children: children(), /// translations: [TRANSLATIONS], /// languages: "./locales/languages.json", /// sync_html_tag_lang: true, @@ -78,10 +82,15 @@ pub(crate) fn debug(msg: &str) { /// cookie_attrs: "SameSite=Strict; Secure; path=/; max-age=2592000", /// initial_language_from_cookie: true, /// set_language_to_cookie: true, -/// }; +/// } +/// } /// +/// #[component] +/// fn App() -> impl IntoView { /// view! { -/// ... +/// <I18n> +/// <LanguageSelector/> +/// </I18n> /// } /// } /// ``` @@ -95,6 +104,7 @@ pub fn leptos_fluent( ) -> proc_macro::TokenStream { let I18nLoader { fluent_file_paths, + children, translations, languages, languages_path, @@ -298,7 +308,7 @@ pub fn leptos_fluent( // TODO: optimize checking if empty at compile time when literal let effect_quote = quote! { - ::leptos::create_effect(move |_| { + ::leptos::prelude::Effect::new(move |_| { if #set_language_to_data_file_quote.is_empty() { return; } @@ -450,7 +460,7 @@ pub fn leptos_fluent( .map(|param| { let ident = ¶m.ident; let effect_quote = quote! { - spawn_local(async move { + ::leptos::task::spawn(async move { let lang_result = #ident().await; if let Ok(maybe_lang) = lang_result { if let Some(l) = maybe_lang { @@ -459,7 +469,6 @@ pub fn leptos_fluent( #set_to_cookie_quote #set_to_localstorage_quote } - } } }); @@ -487,8 +496,8 @@ pub fn leptos_fluent( set_language_to_server_function.iter().map(|param| { let ident = ¶m.ident; let effect_quote = quote! { - ::leptos::create_effect(move |_| { - spawn_local(async { + ::leptos::prelude::Effect::new(move |_| { + ::leptos::task::spawn(async { _ = #ident(#get_language_quote.id.to_string()).await; }); }); @@ -508,7 +517,7 @@ pub fn leptos_fluent( match param.ident { Some(ref ident) => { let quote = quote! { - spawn_local(async move { + ::leptos::task::spawn(async move { _ = #ident(l.id.to_string()).await; }); }; @@ -595,7 +604,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "ssr", feature = "actix"))] let effect_quote = quote! { - if let Some(req) = ::leptos::use_context::<::actix_web::HttpRequest>() { + if let Some(req) = ::leptos::prelude::use_context::<::actix_web::HttpRequest>() { lang = ::leptos_fluent::l(#ident(&req.path()), &LANGUAGES); if let Some(l) = lang { #initial_language_from_url_path_to_server_function_quote @@ -605,7 +614,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "ssr", feature = "axum"))] let effect_quote = quote! { - if let Some(req) = ::leptos::use_context::<::axum::http::request::Parts>() { + if let Some(req) = ::leptos::prelude::use_context::<::axum::http::request::Parts>() { lang = ::leptos_fluent::l(#ident(&req.uri.path()), &LANGUAGES); if let Some(l) = lang { #initial_language_from_url_path_to_server_function_quote @@ -636,190 +645,73 @@ pub fn leptos_fluent( }; let sync_html_tag_quote: proc_macro2::TokenStream = { - // TODO: optimize code size // TODO: handle other attributes in Leptos v0.7 - // (in Leptos v0.6 attribute keys are static) - - // Calling `provide_meta_context()` to not show a warning - #[cfg(feature = "ssr")] - let previous_html_tag_attrs_quote = quote! {{ - ::leptos_fluent::leptos_meta::provide_meta_context(); - let html_tag_as_string = ::leptos_fluent::leptos_meta::use_head().html.as_string().unwrap_or("".to_string()); - let mut class: Option<::leptos::TextProp> = None; - let mut lang: Option<::leptos::TextProp> = None; - let mut dir: Option<::leptos::TextProp> = None; - for attr in html_tag_as_string.split(' ') { - let mut parts = attr.split('='); - let key = parts.next().unwrap_or(""); - let value = parts.next().unwrap_or(""); - if key == "class" { - class = Some(value.trim_matches('"').to_string().into()); - } else if key == "lang" { - lang = Some(value.trim_matches('"').to_string().into()); - } else if key == "dir" { - dir = Some(value.trim_matches('"').to_string().into()); - } - } - (class, lang, dir) - }}; - - let sync_html_tag_lang_effect_quote = { - #[cfg(feature = "ssr")] - { - let sync_html_tag_dir_bool_quote: proc_macro2::TokenStream = { - let quote = sync_html_tag_dir - .iter() - .map(|param| match param.expr { - Some(ref expr) => { - let q = quote! { #expr }; - match param.exprpath { - Some(ref path) => quote!(#path{#q}), - None => q, - } - } - None => quote! { false }, - }) - .collect::<proc_macro2::TokenStream>(); - - match quote.is_empty() { - true => quote! { false }, - false => quote! { #quote }, - } - }; - - quote! { - let l = #get_language_quote; - let (class, _, dir) = #previous_html_tag_attrs_quote; - ::leptos_fluent::leptos_meta::Html( - ::leptos_fluent::leptos_meta::HtmlProps { - lang: Some(l.id.to_string().into()), - dir: if #sync_html_tag_dir_bool_quote { - Some(l.dir.as_str().into()) - } else { - dir - }, - class, - attributes: Vec::new(), - } - ); - } - } - - #[cfg(not(feature = "ssr"))] - quote! { - ::leptos::create_effect(move |_| { - use leptos_fluent::web_sys::wasm_bindgen::JsCast; - _ = ::leptos::document() - .document_element() - .unwrap() - .unchecked_into::<::leptos_fluent::web_sys::HtmlElement>() - .set_attribute( - "lang", - &#get_language_quote.id.to_string() - ); - }); - } - }; - - let sync_html_tag_dir_effect_quote = { - #[cfg(feature = "ssr")] - { - let sync_html_tag_lang_bool_quote: proc_macro2::TokenStream = { - let quote = sync_html_tag_lang - .iter() - .map(|param| match param.expr { - Some(ref expr) => { - let q = quote! { #expr }; - match param.exprpath { - Some(ref path) => quote!(#path{#q}), - None => q, - } - } - None => quote! { false }, - }) - .collect::<proc_macro2::TokenStream>(); - - match quote.is_empty() { - true => quote! { false }, - false => quote! { #quote }, - } - }; - - quote! { - let l = #get_language_quote; - let (class, lang, _) = #previous_html_tag_attrs_quote; - ::leptos_fluent::leptos_meta::Html( - ::leptos_fluent::leptos_meta::HtmlProps { - lang: if #sync_html_tag_lang_bool_quote { - Some(l.id.to_string().into()) - } else { - lang - }, - dir: Some(l.dir.as_str().into()), - class, - attributes: Vec::new(), - } - ); - } - } - - #[cfg(not(feature = "ssr"))] - quote! { - ::leptos::create_effect(move |_| { - use leptos_fluent::web_sys::wasm_bindgen::JsCast; - _ = ::leptos::document() - .document_element() - .unwrap() - .unchecked_into::<::leptos_fluent::web_sys::HtmlElement>() - .set_attribute( - "dir", - &#get_language_quote.dir.as_str() - ); - }); - } - }; + // See https://github.com/leptos-rs/leptos/issues/2856 - let sync_html_tag_lang_quote: proc_macro2::TokenStream = - sync_html_tag_lang + let sync_html_tag_lang_bool_quote: proc_macro2::TokenStream = { + let quote = sync_html_tag_lang .iter() .map(|param| match param.expr { Some(ref expr) => { - let q = quote! { - if #expr { - #sync_html_tag_lang_effect_quote - } - }; + let q = quote! { #expr }; match param.exprpath { Some(ref path) => quote!(#path{#q}), None => q, } } - None => quote!(), + None => quote! { false }, }) - .collect(); + .collect::<proc_macro2::TokenStream>(); + + match quote.is_empty() { + true => quote! { false }, + false => quote! { #quote }, + } + }; - let sync_html_tag_dir_quote: proc_macro2::TokenStream = - sync_html_tag_dir + let sync_html_tag_dir_bool_quote: proc_macro2::TokenStream = { + let quote = sync_html_tag_dir .iter() .map(|param| match param.expr { Some(ref expr) => { - let q = quote! { - if #expr { - #sync_html_tag_dir_effect_quote - } - }; + let q = quote! { #expr }; match param.exprpath { Some(ref path) => quote!(#path{#q}), None => q, } } - None => quote!(), + None => quote! { false }, }) - .collect(); + .collect::<proc_macro2::TokenStream>(); - quote! { - #sync_html_tag_lang_quote - #sync_html_tag_dir_quote + match quote.is_empty() { + true => quote! { false }, + false => quote! { #quote }, + } + }; + + let attr_lang_quote = match sync_html_tag_lang_bool_quote.to_string() + == "false" + { + true => quote! {}, + false => quote! { attr:lang=|| #get_language_quote.id.to_string() }, + }; + let attr_dir_quote = match sync_html_tag_dir_bool_quote.to_string() + == "false" + { + true => quote! {}, + false => quote! { attr:dir=|| #get_language_quote.dir.as_str() }, + }; + + match attr_lang_quote.is_empty() && attr_dir_quote.is_empty() { + true => quote! {}, + false => quote! {{ + use ::leptos_fluent::leptos_meta::{provide_meta_context, Html}; + provide_meta_context(); + view! { + <Html #attr_lang_quote #attr_dir_quote/> + } + }}, } }; @@ -833,7 +725,7 @@ pub fn leptos_fluent( let sync_language_with_localstorage_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - ::leptos::create_effect(move |_| { + ::leptos::prelude::Effect::new(move |_| { ::leptos_fluent::localstorage::set( #localstorage_key_quote, &#get_language_quote.id.to_string() @@ -863,7 +755,7 @@ pub fn leptos_fluent( let initial_language_from_url_param_quote: proc_macro2::TokenStream = { #[cfg(feature = "hydrate")] let hydrate_rerender_quote = quote! { - ::leptos::create_effect(move |prev| { + ::leptos::prelude::Effect::new(move |prev: Option<()>| { if prev.is_none() { l.activate(); } @@ -942,7 +834,7 @@ pub fn leptos_fluent( .map(|param| match param.ident { Some(ref ident) => { let quote = quote! { - spawn_local(async move { + ::leptos::task::spawn(async move { _ = #ident(l.id.to_string()).await; }); }; @@ -991,7 +883,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "ssr", feature = "actix"))] let parse_language_quote = quote! { - if let Some(req) = ::leptos::use_context::<actix_web::HttpRequest>() { + if let Some(req) = ::leptos::prelude::use_context::<actix_web::HttpRequest>() { let uri_query = req.uri().query().unwrap_or(""); #lang_parser_quote } @@ -999,7 +891,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "ssr", feature = "axum"))] let parse_language_quote = quote! { - if let Some(req) = ::leptos::use_context::<::axum::http::request::Parts>() { + if let Some(req) = ::leptos::prelude::use_context::<::axum::http::request::Parts>() { let uri_query = req.uri.query().unwrap_or(""); #lang_parser_quote } @@ -1068,7 +960,7 @@ pub fn leptos_fluent( match param.ident { Some(ref ident) => { let quote = quote! { - spawn_local(async move { + ::leptos::task::spawn(async move { _ = #ident(l.id.to_string()).await; }); }; @@ -1120,7 +1012,7 @@ pub fn leptos_fluent( let sync_language_with_url_param_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - ::leptos::create_effect(move |_| { + ::leptos::prelude::Effect::new(move |_| { ::leptos_fluent::url::param::set( #url_param_quote, &#get_language_quote.id.to_string() @@ -1207,7 +1099,7 @@ pub fn leptos_fluent( match param.ident { Some(ref ident) => { let quote = quote! { - spawn_local(async move { + ::leptos::task::spawn(async move { _ = #ident(l.id.to_string()).await; }); }; @@ -1221,7 +1113,7 @@ pub fn leptos_fluent( }).collect(); let window_navigator_languages_quote = quote! { - let languages = ::leptos::window().navigator().languages().to_vec(); + let languages = ::leptos::prelude::window().navigator().languages().to_vec(); for raw_language in languages { let language = raw_language.as_string(); if language.is_none() { @@ -1270,8 +1162,8 @@ pub fn leptos_fluent( let effect_quote = quote! { use ::leptos_fluent::web_sys::wasm_bindgen::JsCast; let closure: Box<dyn FnMut(_)> = Box::new( - move |_: web_sys::Window| { - let languages = ::leptos::window().navigator().languages().to_vec(); + move |_: ::leptos_fluent::web_sys::Window| { + let languages = ::leptos::prelude::window().navigator().languages().to_vec(); for raw_language in languages { let language = raw_language.as_string(); if language.is_none() { @@ -1289,7 +1181,7 @@ pub fn leptos_fluent( let cb = ::leptos_fluent::web_sys::wasm_bindgen::closure::Closure::wrap( closure ); - ::leptos::window().add_event_listener_with_callback( + ::leptos::prelude::window().add_event_listener_with_callback( "languagechange", cb.as_ref().unchecked_ref() ).expect("Failed to add event listener for window languagechange"); @@ -1327,7 +1219,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "actix", feature = "ssr"))] let initial_language_from_accept_language_header_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - if let Some(req) = ::leptos::use_context::<::actix_web::HttpRequest>() { + if let Some(req) = ::leptos::prelude::use_context::<::actix_web::HttpRequest>() { let maybe_header = req .headers() .get(::actix_web::http::header::ACCEPT_LANGUAGE) @@ -1367,7 +1259,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "axum", feature = "ssr"))] let initial_language_from_accept_language_header_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - if let Some(req) = ::leptos::use_context::<::axum::http::request::Parts>() { + if let Some(req) = ::leptos::prelude::use_context::<::axum::http::request::Parts>() { let maybe_header = req .headers .get(::axum::http::header::ACCEPT_LANGUAGE) @@ -1419,7 +1311,7 @@ pub fn leptos_fluent( match param.ident { Some(ref ident) => { let quote = quote! { - spawn_local(async move { + ::leptos::task::spawn(async move { _ = #ident(l.id.to_string()).await; }); }; @@ -1492,7 +1384,7 @@ pub fn leptos_fluent( #[cfg(not(feature = "ssr"))] let sync_language_with_cookie_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - ::leptos::create_effect(move |_| { + ::leptos::prelude::Effect::new(move |_| { ::leptos_fluent::cookie::set( #cookie_name_quote, &#get_language_quote.id.to_string(), @@ -1532,7 +1424,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "ssr", feature = "actix"))] let initial_language_from_cookie_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - if let Some(req) = ::leptos::use_context::<::actix_web::HttpRequest>() { + if let Some(req) = ::leptos::prelude::use_context::<::actix_web::HttpRequest>() { let maybe_cookie = req .cookie(#cookie_name_quote) .and_then(|cookie| Some(cookie.value().to_string())); @@ -1573,7 +1465,7 @@ pub fn leptos_fluent( #[cfg(all(feature = "ssr", feature = "axum"))] let initial_language_from_cookie_quote: proc_macro2::TokenStream = { let effect_quote = quote! { - if let Some(req) = ::leptos::use_context::<::axum::http::request::Parts>() { + if let Some(req) = ::leptos::prelude::use_context::<::axum::http::request::Parts>() { let maybe_cookie = req .headers .get(::axum::http::header::COOKIE) @@ -1959,7 +1851,7 @@ pub fn leptos_fluent( provide_meta_context: true, #system_quote }; - ::leptos::provide_context::<::leptos_fluent::LeptosFluentMeta>(meta); + ::leptos::context::provide_context::<::leptos_fluent::LeptosFluentMeta>(meta); }; match param.exprpath { @@ -1973,7 +1865,6 @@ pub fn leptos_fluent( }; let other_quotes = quote! { - #sync_html_tag_quote #sync_language_with_server_function_quote #sync_language_with_localstorage_quote #sync_language_with_url_param_quote @@ -1984,42 +1875,66 @@ pub fn leptos_fluent( #leptos_fluent_provide_meta_context_quote }; - let debug_quote = quote! { - const LANGUAGES: [&::leptos_fluent::Language; #n_languages] = - #languages_quote; + let init_quote = quote! { + { + - let mut lang: Option<&'static ::leptos_fluent::Language> = None; - #initial_language_quote; + let mut lang: Option<&'static ::leptos_fluent::Language> = None; + #initial_language_quote; - let initial_lang = if let Some(l) = lang { - l - } else { - LANGUAGES[0] - }; + let initial_lang = if let Some(l) = lang { + l + } else { + LANGUAGES[0] + }; - let translations = ::std::rc::Rc::new(#translations_quote); - let mut i18n = ::leptos_fluent::I18n { - language: ::leptos::create_rw_signal(initial_lang), - languages: &LANGUAGES, - translations: ::leptos::Signal::derive(move || ::std::rc::Rc::clone(&translations)), - }; - ::leptos::provide_context::<::leptos_fluent::I18n>(i18n); + let i18n = ::leptos_fluent::I18n { + language: ::leptos::prelude::RwSignal::new(initial_lang), + languages: &LANGUAGES, + translations: ::leptos::prelude::Signal::derive(move || #translations_quote), + }; + ::leptos::context::provide_context::<::leptos_fluent::I18n>(i18n); + i18n + } }; - #[cfg(feature = "tracing")] - tracing::trace!("{}", debug_quote); + let children_quote: proc_macro2::TokenStream = children + .iter() + .map(|param| { + let expr = param.expr.as_ref().unwrap(); + match param.exprpath { + Some(ref path) => quote!(#path{#expr}), + None => quote!(#expr), + } + }) + .collect(); let quote = quote! { - { - #debug_quote + let i18n = { + const LANGUAGES: [&::leptos_fluent::Language; #n_languages] = + #languages_quote; + let i18n = #init_quote; #other_quotes i18n + }; + { + use ::leptos::context::Provider; + ::leptos::view! { + <Provider value={i18n}> + #sync_html_tag_quote + {#children_quote} + </Provider> + } } + }; #[cfg(feature = "debug")] debug(&format!("\n{}", "e.to_string())); + #[cfg(feature = "tracing")] + tracing::trace!("{}", "e.to_string()); + proc_macro::TokenStream::from(quote) } diff --git a/leptos-fluent-macros/src/loader.rs b/leptos-fluent-macros/src/loader.rs index 1b6d571f..0bb141c2 100644 --- a/leptos-fluent-macros/src/loader.rs +++ b/leptos-fluent-macros/src/loader.rs @@ -370,8 +370,21 @@ impl LitBool { } } +#[derive(Default)] +pub(crate) struct Expr { + pub expr: Option<syn::Expr>, + pub exprpath: Option<proc_macro2::TokenStream>, +} + +impl Expr { + pub fn new() -> Self { + Self::default() + } +} + pub(crate) struct I18nLoader { pub fluent_file_paths: FluentFilePaths, + pub children: Vec<Expr>, pub translations: Translations, pub languages: Vec<ParsedLanguage>, pub languages_path: Option<String>, @@ -432,6 +445,7 @@ impl Parse for I18nLoader { std::env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| "./".into()), ); + let mut children: Vec<Expr> = Vec::new(); let mut locales_path: Option<syn::LitStr> = None; let mut languages_path: Option<syn::LitStr> = None; let mut core_locales_path: Option<syn::LitStr> = None; @@ -593,7 +607,18 @@ impl Parse for I18nLoader { input.parse::<syn::Token![:]>()?; } - if k == "translations" { + if k == "children" { + let mut param = Expr::new(); + clone_runtime_exprpath!(exprpath, param); + parse_struct_field_init_shorthand!( + struct_field_init_shorthand, + param, + k, + children + ); + param.expr = Some(input.parse()?); + children.push(param); + } else if k == "translations" { struct_field_init_shorthand_not_supported!( struct_field_init_shorthand, k @@ -1475,6 +1500,7 @@ impl Parse for I18nLoader { Ok(Self { fluent_file_paths: fluent_resources_and_file_paths.1, + children, translations, languages, languages_path: languages_file_path, diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/check_translations_cfg_feature.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/check_translations_cfg_feature.rs index 3d4b0564..7e749990 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/check_translations_cfg_feature.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/check_translations_cfg_feature.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::move_tr; use leptos_fluent_macros::leptos_fluent; diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/double_curly_braces.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/double_curly_braces.rs index 64d30af9..e8ae5ea8 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/double_curly_braces.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/double_curly_braces.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty.rs index 93341881..fd78bb12 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; #[component] diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_parameter.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_parameter.rs index 415d3d6d..a3050719 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_parameter.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_parameter.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_value.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_value.rs index 31464629..38703d12 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_value.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/empty_value.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/invalid_parameter.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/invalid_parameter.rs index a32f666d..64c8edb5 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/invalid_parameter.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/invalid_parameter.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/locales_required.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/locales_required.rs index c42bfa8f..abad98fc 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/fail/locales_required.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/fail/locales_required.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/check_translations_cfg_not_debug.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/check_translations_cfg_not_debug.rs index 79a39b68..9a052fd1 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/check_translations_cfg_not_debug.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/check_translations_cfg_not_debug.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::move_tr; use leptos_fluent_macros::leptos_fluent; diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/compile_time_exprpath_target_predicate.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/compile_time_exprpath_target_predicate.rs index 35b79a85..9823b3df 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/compile_time_exprpath_target_predicate.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/compile_time_exprpath_target_predicate.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/complete.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/complete.rs index a7863ed9..5f7b6cf0 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/complete.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/complete.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/minimal.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/minimal.rs index da98685f..6ab5e771 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/minimal.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/minimal.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/multiple_cfg_conditional_cheks.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/multiple_cfg_conditional_cheks.rs index a26cd140..79b55bea 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/multiple_cfg_conditional_cheks.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/multiple_cfg_conditional_cheks.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/set_to_url_param_cfg_feature.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/set_to_url_param_cfg_feature.rs index aa7e647a..238dfdcc 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/set_to_url_param_cfg_feature.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/set_to_url_param_cfg_feature.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::move_tr; use leptos_fluent_macros::leptos_fluent; diff --git a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/struct_field_init_shorthand.rs b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/struct_field_init_shorthand.rs index 61007d0c..1d00b4ad 100644 --- a/leptos-fluent-macros/tests/ui/leptos_fluent/pass/struct_field_init_shorthand.rs +++ b/leptos-fluent-macros/tests/ui/leptos_fluent/pass/struct_field_init_shorthand.rs @@ -1,5 +1,5 @@ use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent_macros::leptos_fluent; static_loader! { diff --git a/leptos-fluent/Cargo.toml b/leptos-fluent/Cargo.toml index e25fb266..028c5047 100644 --- a/leptos-fluent/Cargo.toml +++ b/leptos-fluent/Cargo.toml @@ -2,7 +2,7 @@ name = "leptos-fluent" description = "Fluent framework for internationalization of Leptos applications" edition.workspace = true -version = "0.1.26" +version = "0.2.0" license = "MIT" documentation.workspace = true repository.workspace = true @@ -16,8 +16,8 @@ fluent-templates = { version = ">=0.9", default-features = false, features = [ "macros", "walkdir" ] } -leptos = "0.6" -leptos_meta = { version = "0.6", optional = true } +leptos = "0.7" +leptos_meta = "0.7" web-sys = { version = ">=0.1", features = [ "HtmlDocument", "Navigator", @@ -39,7 +39,7 @@ system = [ nightly = ["leptos-fluent-macros/nightly"] tracing = ["leptos-fluent-macros/tracing", "dep:tracing"] hydrate = ["leptos-fluent-macros/hydrate"] -ssr = ["leptos-fluent-macros/ssr", "dep:leptos_meta"] +ssr = ["leptos-fluent-macros/ssr"] actix = ["leptos-fluent-macros/actix"] axum = ["leptos-fluent-macros/axum"] json = ["leptos-fluent-macros/json"] diff --git a/leptos-fluent/README.md b/leptos-fluent/README.md index cc6d0080..c8802795 100644 --- a/leptos-fluent/README.md +++ b/leptos-fluent/README.md @@ -21,7 +21,7 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -leptos-fluent = "0.1" +leptos-fluent = "0.2" fluent-templates = "0.11" [features] @@ -75,7 +75,7 @@ You can use `leptos-fluent` as follows: ```rust use fluent_templates::static_loader; -use leptos::*; +use leptos::prelude::*; use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, tr}; static_loader! { @@ -86,10 +86,11 @@ static_loader! { } #[component] -fn App() -> impl IntoView { +fn I18n(children: Children) -> impl IntoView { // See all options in the reference at // https://mondeja.github.io/leptos-fluent/leptos_fluent.html leptos_fluent! { + children: children(), // Path to the locales directory, relative to Cargo.toml. locales: "./locales", // Static translations struct provided by fluent-templates. @@ -174,11 +175,16 @@ fn App() -> impl IntoView { data_file_key: "my-app", // Set the language selected to a data file. set_language_to_data_file: true, - }; + } +} +#[component] +pub fn App() -> impl IntoView { view! { - <TranslatableComponent /> - <LanguageSelector /> + <I18n> + <TranslatableComponent/> + <LanguageSelector/> + </I18n> } } @@ -202,11 +208,13 @@ fn TranslatableComponent() -> impl IntoView { #[component] fn LanguageSelector() -> impl IntoView { // `expect_i18n()` to get the i18n context - // `i18n.languages` is a static array with the available languages - // `i18n.language.get()` to get the current language - // `lang.activate()` to set the current language + // `i18n.languages` exposes a static array with the available languages + // `i18n.language.read()` to get the current language + // `lang.activate()` or `i18n.language.set(lang)` to set the current language // `lang.is_active()` to check if a language is the current selected one + let i18n = expect_i18n(); + view! { <fieldset> { @@ -219,7 +227,7 @@ fn LanguageSelector() -> impl IntoView { name="language" value=lang checked=lang.is_active() - on:click=move |_| lang.activate() + on:click=move |_| i18n.language.set(lang) /> <label for=lang>{lang.name}</label> </div> diff --git a/leptos-fluent/src/cookie.rs b/leptos-fluent/src/cookie.rs index 5776aa50..43e065fe 100644 --- a/leptos-fluent/src/cookie.rs +++ b/leptos-fluent/src/cookie.rs @@ -6,7 +6,7 @@ pub fn get(name: &str) -> Option<String> { tracing::trace!("Getting cookie \"{name}\" from browser"); use crate::web_sys::wasm_bindgen::JsCast; - let mut cookies = leptos::document() + let mut cookies = leptos::prelude::document() .dyn_into::<web_sys::HtmlDocument>() .unwrap() .cookie() @@ -44,7 +44,7 @@ pub fn get(name: &str) -> Option<String> { #[cfg(not(feature = "ssr"))] fn set_cookie(new_value: &str) { use crate::web_sys::wasm_bindgen::JsCast; - _ = leptos::document() + _ = leptos::prelude::document() .dyn_into::<web_sys::HtmlDocument>() .unwrap() .set_cookie(new_value); diff --git a/leptos-fluent/src/lib.rs b/leptos-fluent/src/lib.rs index 3fb0a736..ce0ea434 100644 --- a/leptos-fluent/src/lib.rs +++ b/leptos-fluent/src/lib.rs @@ -19,7 +19,7 @@ //! //! ```toml //! [dependencies] -//! leptos-fluent = "0.1" +//! leptos-fluent = "0.2" //! fluent-templates = "0.11" //! //! [features] @@ -73,7 +73,7 @@ //! //! ```rust,ignore //! use fluent_templates::static_loader; -//! use leptos::*; +//! use leptos::prelude::*; //! use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, tr}; //! //! static_loader! { @@ -84,10 +84,11 @@ //! } //! //! #[component] -//! fn App() -> impl IntoView { +//! fn I18n(children: Children) -> impl IntoView { //! // See all options in the reference at //! // https://mondeja.github.io/leptos-fluent/leptos_fluent.html //! leptos_fluent! { +//! children: children(), //! // Path to the locales directory, relative to Cargo.toml. //! locales: "./locales", //! // Static translations struct provided by fluent-templates. @@ -172,11 +173,16 @@ //! data_file_key: "my-app", //! // Set the language selected to a data file. //! set_language_to_data_file: true, -//! }; +//! } +//! } //! +//! #[component] +//! pub fn App() -> impl IntoView { //! view! { -//! <TranslatableComponent /> -//! <LanguageSelector /> +//! <I18n> +//! <TranslatableComponent/> +//! <LanguageSelector/> +//! </I18n> //! } //! } //! @@ -200,11 +206,13 @@ //! #[component] //! fn LanguageSelector() -> impl IntoView { //! // `expect_i18n()` to get the i18n context -//! // `i18n.languages` is a static array with the available languages -//! // `i18n.language.get()` to get the current language -//! // `lang.activate()` to set the current language +//! // `i18n.languages` exposes a static array with the available languages +//! // `i18n.language.read()` to get the current language +//! // `lang.activate()` or `i18n.language.set(lang)` to set the current language //! // `lang.is_active()` to check if a language is the current selected one //! +//! let i18n = expect_i18n(); +//! //! view! { //! <fieldset> //! { @@ -217,7 +225,7 @@ //! name="language" //! value=lang //! checked=lang.is_active() -//! on:click=move |_| lang.activate() +//! on:click=move |_| i18n.language.set(lang) //! /> //! <label for=lang>{lang.name}</label> //! </div> @@ -272,24 +280,27 @@ pub mod url; #[doc(hidden)] #[cfg(feature = "system")] pub extern crate current_locale; -#[cfg(feature = "ssr")] #[doc(hidden)] pub extern crate leptos_meta; #[doc(hidden)] pub extern crate web_sys; +pub use leptos_fluent_macros::leptos_fluent; use core::hash::{Hash, Hasher}; +use core::ops::Deref; use core::str::FromStr; use fluent_templates::{ fluent_bundle::FluentValue, loader::Loader, once_cell::sync::Lazy, LanguageIdentifier, StaticLoader, }; +#[cfg(feature = "nightly")] +use leptos::prelude::Get; use leptos::{ - use_context, with, Attribute, IntoAttribute, Oco, RwSignal, Signal, - SignalGet, SignalSet, + attr::AttributeValue, + prelude::{ + guards::ReadGuard, use_context, Read, RwSignal, Set, Signal, With, + }, }; -pub use leptos_fluent_macros::leptos_fluent; -use std::rc::Rc; /// Direction of the text #[derive(Debug)] @@ -325,7 +336,7 @@ pub struct Language { /// Language identifier /// /// Can be any valid language tag, such as `en`, `es`, `en-US`, `es-ES`, etc. - pub id: LanguageIdentifier, + pub id: &'static LanguageIdentifier, /// Language name /// /// The name of the language, such as `English`, `EspaƱol`, etc. @@ -340,14 +351,16 @@ pub struct Language { impl Language { /// Get if the language is the active language. #[inline(always)] - pub fn is_active(&self) -> bool { - self == expect_i18n().language.get() + pub fn is_active(&'static self) -> bool { + self == expect_i18n().language.read() } /// Set the language as the active language. #[inline(always)] pub fn activate(&'static self) { + ::leptos::logging::log!("Activating language: {:?}", self); expect_i18n().language.set(self); + ::leptos::logging::log!("Activated language: {:?}", self); } } @@ -357,6 +370,22 @@ impl PartialEq for Language { } } +// Implementation for `&Language == ReadGuard<&Language, Plain<&Language>>` +// +// This implementation is required to ensure symmetry with +// `ReadGuard<&Language, Plain<&Language>> == &Language`, implemented by Leptos. +// That implementation cannot be included in Leptos as it would generate +// the problem of transitive chains that criss-cross crate boundaries. +// See `PartiaEq` documentation. +impl<'a, Inner> PartialEq<ReadGuard<&'a Language, Inner>> for &Language +where + Inner: Deref<Target = &'a Language>, +{ + fn eq(&self, other: &ReadGuard<&'a Language, Inner>) -> bool { + self == other.deref() + } +} + impl Eq for Language {} impl Hash for Language { @@ -365,7 +394,7 @@ impl Hash for Language { // between different hydrate and SSR contexts, so implement `Language`s // is currently discouraged. This needs to be fully debugged and open // an issue in the `leptos` repository if necessary. - let current_lang = expect_i18n().language.get(); + let current_lang = expect_i18n().language.read(); let key = format!( "{}{}", self.id, @@ -387,31 +416,70 @@ impl FromStr for Language { macro_rules! impl_into_attr_for_language { () => { - /// Convert a language to an HTML attribute passing the language identifier. - /// - /// ```rust,ignore - /// // The following code: - /// <input id={lang} ... > - /// // is the same as - /// <input id={lang.id.to_string()} ... > - /// ``` - #[inline(always)] - fn into_attribute(self) -> Attribute { - Attribute::String(Oco::Owned(self.id.to_string())) + type State = <String as AttributeValue>::State; + type AsyncOutput = String; + type Cloneable = String; + type CloneableOwned = String; + + fn html_len(&self) -> usize { + self.id.to_string().len() } - #[inline(always)] - fn into_attribute_boxed(self: Box<Self>) -> Attribute { - self.into_attribute() + fn to_html(self, key: &str, buf: &mut String) { + <&str as AttributeValue>::to_html( + self.id.to_string().as_str(), + key, + buf, + ); + } + + fn to_template(_key: &str, _buf: &mut String) {} + + fn hydrate<const FROM_SERVER: bool>( + self, + key: &str, + el: &leptos::tachys::renderer::types::Element, + ) -> Self::State { + <String as AttributeValue>::hydrate::<FROM_SERVER>( + self.id.to_string(), + key, + el, + ) + } + + fn build( + self, + el: &leptos::tachys::renderer::types::Element, + key: &str, + ) -> Self::State { + <String as AttributeValue>::build(self.id.to_string(), el, key) + } + + fn rebuild(self, key: &str, state: &mut Self::State) { + <String as AttributeValue>::rebuild(self.id.to_string(), key, state) + } + + fn into_cloneable(self) -> Self::Cloneable { + self.id.to_string() + } + + fn into_cloneable_owned(self) -> Self::CloneableOwned { + self.id.to_string() + } + + fn dry_resolve(&mut self) {} + + async fn resolve(self) -> Self::AsyncOutput { + self.id.to_string() } }; } -impl IntoAttribute for &'static Language { +impl<'a> AttributeValue for &'a Language { impl_into_attr_for_language!(); } -impl IntoAttribute for &&'static Language { +impl<'a> AttributeValue for &&'a Language { impl_into_attr_for_language!(); } @@ -427,7 +495,7 @@ pub struct I18n { /// Available languages for the application. pub languages: &'static [&'static Language], /// Signal with a vector of fluent-templates static loaders. - pub translations: Signal<Rc<Vec<&'static Lazy<StaticLoader>>>>, + pub translations: Signal<Vec<&'static Lazy<StaticLoader>>>, } impl I18n { @@ -453,7 +521,7 @@ impl I18n { tracing::instrument(level = "trace", err(Debug)) )] pub fn meta(&self) -> Result<LeptosFluentMeta, String> { - leptos::use_context::<LeptosFluentMeta>().ok_or( + leptos::prelude::use_context::<LeptosFluentMeta>().ok_or( concat!( "You need to call `leptos_fluent!` with the parameter", " 'provide_meta_context' enabled to provide the meta context", @@ -580,10 +648,12 @@ pub fn tr_impl(i18n: I18n, text_id: &str) -> String { translations, .. } = i18n; - let found = with!(|translations, language| { - translations - .iter() - .find_map(|tr| tr.try_lookup(&language.id, text_id)) + let found = translations.with(|translations| { + language.with(|language| { + translations + .iter() + .find_map(|tr| tr.try_lookup(language.id, text_id)) + }) }); #[cfg(feature = "tracing")] @@ -622,10 +692,12 @@ pub fn tr_with_args_impl( translations, .. } = i18n; - let found = with!(|translations, language| { - translations - .iter() - .find_map(|tr| tr.try_lookup_with_args(&language.id, text_id, args)) + let found = translations.with(|translations| { + language.with(|language| { + translations.iter().find_map(|tr| { + tr.try_lookup_with_args(language.id, text_id, args) + }) + }) }); #[cfg(feature = "tracing")] @@ -709,10 +781,10 @@ macro_rules! tr { #[macro_export] macro_rules! move_tr { ($text_id:literal$(,)?) => { - ::leptos::Signal::derive(move || $crate::tr!($text_id)) + ::leptos::prelude::Signal::derive(move || $crate::tr!($text_id)) }; ($text_id:literal, {$($key:literal => $value:expr),*$(,)?}$(,)?) => { - ::leptos::Signal::derive(move || $crate::tr!($text_id, { + ::leptos::prelude::Signal::derive(move || $crate::tr!($text_id, { $( $key => $value, )* diff --git a/leptos-fluent/src/localstorage.rs b/leptos-fluent/src/localstorage.rs index 252d52af..720d7b86 100644 --- a/leptos-fluent/src/localstorage.rs +++ b/leptos-fluent/src/localstorage.rs @@ -5,7 +5,7 @@ pub fn get(key: &str) -> Option<String> { #[cfg(not(feature = "ssr"))] { - let result = leptos::window() + let result = leptos::prelude::window() .local_storage() .unwrap() .unwrap() @@ -40,7 +40,7 @@ pub fn get(key: &str) -> Option<String> { pub fn set(key: &str, value: &str) { #[cfg(not(feature = "ssr"))] { - _ = ::leptos::window() + _ = ::leptos::prelude::window() .local_storage() .unwrap() .unwrap() @@ -65,7 +65,7 @@ pub fn set(key: &str, value: &str) { pub fn delete(key: &str) { #[cfg(not(feature = "ssr"))] { - _ = ::leptos::window() + _ = ::leptos::prelude::window() .local_storage() .unwrap() .unwrap() diff --git a/leptos-fluent/src/url.rs b/leptos-fluent/src/url.rs index 16a83bf8..ef8d63ac 100644 --- a/leptos-fluent/src/url.rs +++ b/leptos-fluent/src/url.rs @@ -5,7 +5,7 @@ pub mod param { )] pub fn get(k: &str) -> Option<String> { #[cfg(not(feature = "ssr"))] - if let Ok(search) = leptos::window().location().search() { + if let Ok(search) = leptos::prelude::window().location().search() { if let Ok(search_params) = web_sys::UrlSearchParams::new_with_str(&search) { @@ -45,14 +45,14 @@ pub mod param { #[cfg(not(feature = "ssr"))] { let url = web_sys::Url::new( - &leptos::window() + &leptos::prelude::window() .location() .href() .expect("Failed to get location.href from the browser"), ) .expect("Failed to parse location.href from the browser"); url.search_params().set(k, v); - leptos::window() + leptos::prelude::window() .history() .expect("Failed to get the history from the browser") .replace_state_with_url( @@ -85,14 +85,14 @@ pub mod param { #[cfg(not(feature = "ssr"))] { let url = web_sys::Url::new( - &leptos::window() + &leptos::prelude::window() .location() .href() .expect("Failed to get location.href from the browser"), ) .expect("Failed to parse location.href from the browser"); url.search_params().delete(k); - leptos::window() + leptos::prelude::window() .history() .expect("Failed to get the history from the browser") .replace_state_with_url( @@ -123,7 +123,7 @@ pub mod path { )] pub fn get() -> Option<String> { #[cfg(not(feature = "ssr"))] - if let Ok(pathname) = leptos::window().location().pathname() { + if let Ok(pathname) = leptos::prelude::window().location().pathname() { return Some(pathname); }