diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f515b5ae..46ecddd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,9 +88,9 @@ jobs: fail-fast: false matrix: include: - - example: minimal + - example: csr-minimal feature: csr - - example: complete + - example: csr-complete feature: csr - example: ssr-hydrate-actix feature: ssr diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f8473b5a..788ab19a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,6 +56,11 @@ repos: alias: clippy-ssr name: clippy-ssr args: [--features=ssr, --, -A, clippy::comparison-chain, -Dwarnings] + - id: clippy + alias: clippy-ssr-actix + name: clippy-ssr-actix + args: + ["--features=ssr,actix", --, -A, clippy::comparison-chain, -Dwarnings] - id: clippy alias: clippy-hydrate name: clippy-hydrate diff --git a/CHANGELOG.md b/CHANGELOG.md index c718f5fa..1ad11786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # CHANGELOG -## Unreleased +## 2024-03-24 - [0.0.21] - Minimum Leptos version set to `0.6`. +- Fix hydration mode. +- Allow to get the initial language on SSR from the `Accept-Language` header. +- Added `actix` feature to integrate with Actix Web framework. ## 2024-03-10 - [0.0.20] @@ -33,6 +36,7 @@ - Added all ISO-639-1 and ISO-639-2 languages. +[0.0.21]: https://github.com/mondeja/leptos-fluent/compare/v0.0.20...v0.0.21 [0.0.20]: https://github.com/mondeja/leptos-fluent/compare/v0.0.17...v0.0.20 [0.0.17]: https://github.com/mondeja/leptos-fluent/compare/v0.0.15...v0.0.17 [0.0.15]: https://github.com/mondeja/leptos-fluent/compare/v0.0.1...v0.0.15 diff --git a/Cargo.lock b/Cargo.lock index 02527037..709a0f86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "futures-core", "futures-sink", @@ -29,7 +29,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web", - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "derive_more", "futures-core", @@ -54,7 +54,7 @@ dependencies = [ "actix-utils", "ahash", "base64", - "bitflags 2.4.2", + "bitflags 2.5.0", "brotli", "bytes", "bytestring", @@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -201,7 +201,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -264,9 +264,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arc-swap" @@ -276,13 +276,13 @@ checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" [[package]] name = "async-recursion" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -294,7 +294,7 @@ dependencies = [ "attribute-derive-macro", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -310,7 +310,7 @@ dependencies = [ "proc-macro2", "quote", "quote-use", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -321,9 +321,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -348,9 +348,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -363,9 +363,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -400,9 +400,9 @@ checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytestring" @@ -693,7 +693,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -727,7 +727,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -819,24 +819,24 @@ dependencies = [ [[package]] name = "fluent-template-macros" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c58fd7421bad2b89506827409317a3088b74d0d637202003f2e87efdc43ae8e" +checksum = "5659bd41653516a2e46d76a58e67aa4885024c78fb5d00303f0673bbd53ad781" dependencies = [ "flume", "ignore", "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "unic-langid", ] [[package]] name = "fluent-templates" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc023356542b155925aa5e433806ddd33acb46f0218541f869b342676332cd79" +checksum = "8f755e319f6f8f836b94b28c6094c414d29a17cee76e24374c7cd61f7696b3f6" dependencies = [ "arc-swap", "fluent", @@ -936,7 +936,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1080,9 +1080,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -1327,8 +1327,9 @@ dependencies = [ [[package]] name = "leptos-fluent" -version = "0.0.20" +version = "0.0.21" dependencies = [ + "actix-web", "cfg-if", "fluent-templates", "leptos", @@ -1339,7 +1340,7 @@ dependencies = [ ] [[package]] -name = "leptos-fluent-complete-example" +name = "leptos-fluent-csr-complete-example" version = "0.1.0" dependencies = [ "console_error_panic_hook", @@ -1349,28 +1350,28 @@ dependencies = [ "web-sys", ] +[[package]] +name = "leptos-fluent-csr-minimal-example" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "fluent-templates", + "leptos", + "leptos-fluent", +] + [[package]] name = "leptos-fluent-macros" -version = "0.0.20" +version = "0.0.21" dependencies = [ "cfg-if", "proc-macro2", "quote", "serde_json", - "syn 2.0.52", + "syn 2.0.53", "web-sys", ] -[[package]] -name = "leptos-fluent-minimal-example" -version = "0.1.0" -dependencies = [ - "console_error_panic_hook", - "fluent-templates", - "leptos", - "leptos-fluent", -] - [[package]] name = "leptos-fluent-ssr-hydrate-actix-example" version = "0.1.0" @@ -1394,8 +1395,8 @@ version = "0.1.0" dependencies = [ "js-sys", "leptos", - "leptos-fluent-complete-example", - "leptos-fluent-minimal-example", + "leptos-fluent-csr-complete-example", + "leptos-fluent-csr-minimal-example", "wasm-bindgen-futures", "wasm-bindgen-test", "web-sys", @@ -1480,7 +1481,7 @@ dependencies = [ "quote", "rstml", "serde", - "syn 2.0.52", + "syn 2.0.53", "walkdir", ] @@ -1516,7 +1517,7 @@ dependencies = [ "quote", "rstml", "server_fn_macro", - "syn 2.0.52", + "syn 2.0.53", "tracing", "uuid", ] @@ -1677,7 +1678,7 @@ dependencies = [ "manyhow-macros", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1835,7 +1836,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1875,7 +1876,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1920,9 +1921,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1935,7 +1936,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "version_check", "yansi", ] @@ -1957,7 +1958,7 @@ checksum = "a7b5abe3fe82fdeeb93f44d66a7b444dedf2e4827defb0a8e69c437b2de2ef94" dependencies = [ "quote", "quote-use-macros", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1969,7 +1970,7 @@ dependencies = [ "derive-where", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2049,7 +2050,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.52", + "syn 2.0.53", "syn_derive", "thiserror", ] @@ -2160,7 +2161,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2256,7 +2257,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "xxhash-rust", ] @@ -2267,7 +2268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "060af1def72353a779fcc184c53e1965d3055a38b9e827f2259b2bff2d9c371e" dependencies = [ "server_fn_macro", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2311,9 +2312,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" @@ -2375,9 +2376,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -2393,27 +2394,27 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2504,9 +2505,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.10" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", @@ -2525,9 +2526,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.6" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" dependencies = [ "indexmap", "serde", @@ -2556,7 +2557,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2594,7 +2595,7 @@ checksum = "563b3b88238ec95680aef36bdece66896eaa7ce3c0f1b4f39d38fb2435261352" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2642,7 +2643,7 @@ checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.52", + "syn 2.0.53", "unic-langid-impl", ] @@ -2707,9 +2708,9 @@ checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -2763,7 +2764,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "wasm-bindgen-shared", ] @@ -2797,7 +2798,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2830,7 +2831,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3036,9 +3037,9 @@ checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" [[package]] name = "yansi" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2861d76f58ec8fc95708b9b1e417f7b12fd72ad33c01fa6886707092dea0d3" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" @@ -3057,7 +3058,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0695d436..16e2b46f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,8 @@ members = [ "leptos-fluent", "leptos-fluent-macros", "tests", - "examples/complete", - "examples/minimal", + "examples/csr-complete", + "examples/csr-minimal", "examples/ssr-hydrate-actix", ] resolver = "2" diff --git a/README.md b/README.md index ff1e1c91..b46fad81 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,16 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -leptos-fluent = "0.0.20" +leptos-fluent = "0.0.21" fluent-templates = "0.9" [features] csr = ["leptos-fluent/csr"] hydrate = ["leptos-fluent/hydrate"] -ssr = ["leptos-fluent/ssr"] +ssr = [ + "leptos-fluent/ssr", + "leptos-fluent/actix", # Currently only actix is supported +] ``` ## Usage @@ -99,6 +102,12 @@ pub fn App() -> impl IntoView { // Name of the field in local storage to get and set the // current language of the user. By default, it is `"lang"`. localstorage_key: "language", + + // Server side options (for `ssr`) + // ------------------------------- + // Set the initial language from the Accept-Language header of the + // request. By default, it is `false`. + initial_language_from_accept_language_header: true, }}; view! { @@ -121,6 +130,13 @@ fn ChildComponent() -> impl IntoView { } ``` +### Features + +- **Client side rendering (CSR)**: Use `leptos-fluent/csr` feature. +- **Server side rendering (SSR)**: Use `leptos-fluent/ssr` feature. +- **Hydration**: Use `leptos-fluent/hydrate` feature. +- **Actix web integration**: Use `leptos-fluent/actix` feature. + ## Resources - [Quickstart] diff --git a/examples/complete/Cargo.toml b/examples/csr-complete/Cargo.toml similarity index 78% rename from examples/complete/Cargo.toml rename to examples/csr-complete/Cargo.toml index 0ffe5f63..3da9cba9 100644 --- a/examples/complete/Cargo.toml +++ b/examples/csr-complete/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "leptos-fluent-complete-example" +name = "leptos-fluent-csr-complete-example" edition = "2021" version = "0.1.0" [lib] -name = "leptos_fluent_complete_example" +name = "leptos_fluent_csr_complete_example" path = "src/lib.rs" [dependencies] diff --git a/examples/complete/README.md b/examples/csr-complete/README.md similarity index 100% rename from examples/complete/README.md rename to examples/csr-complete/README.md diff --git a/examples/complete/index.html b/examples/csr-complete/index.html similarity index 100% rename from examples/complete/index.html rename to examples/csr-complete/index.html diff --git a/examples/complete/locales/en/main.ftl b/examples/csr-complete/locales/en/main.ftl similarity index 100% rename from examples/complete/locales/en/main.ftl rename to examples/csr-complete/locales/en/main.ftl diff --git a/examples/complete/locales/es/main.ftl b/examples/csr-complete/locales/es/main.ftl similarity index 100% rename from examples/complete/locales/es/main.ftl rename to examples/csr-complete/locales/es/main.ftl diff --git a/examples/complete/locales/languages.json b/examples/csr-complete/locales/languages.json similarity index 100% rename from examples/complete/locales/languages.json rename to examples/csr-complete/locales/languages.json diff --git a/examples/complete/src/lib.rs b/examples/csr-complete/src/lib.rs similarity index 100% rename from examples/complete/src/lib.rs rename to examples/csr-complete/src/lib.rs diff --git a/examples/minimal/src/main.rs b/examples/csr-complete/src/main.rs similarity index 74% rename from examples/minimal/src/main.rs rename to examples/csr-complete/src/main.rs index 61304ecd..5e894a67 100644 --- a/examples/minimal/src/main.rs +++ b/examples/csr-complete/src/main.rs @@ -1,5 +1,5 @@ use leptos::*; -use leptos_fluent_minimal_example::App; +use leptos_fluent_csr_complete_example::App; pub fn main() { console_error_panic_hook::set_once(); diff --git a/examples/minimal/Cargo.toml b/examples/csr-minimal/Cargo.toml similarity index 78% rename from examples/minimal/Cargo.toml rename to examples/csr-minimal/Cargo.toml index 10565644..9c1f26c7 100644 --- a/examples/minimal/Cargo.toml +++ b/examples/csr-minimal/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "leptos-fluent-minimal-example" +name = "leptos-fluent-csr-minimal-example" edition = "2021" version = "0.1.0" [lib] -name = "leptos_fluent_minimal_example" +name = "leptos_fluent_csr_minimal_example" path = "src/lib.rs" [dependencies] diff --git a/examples/minimal/README.md b/examples/csr-minimal/README.md similarity index 100% rename from examples/minimal/README.md rename to examples/csr-minimal/README.md diff --git a/examples/minimal/index.html b/examples/csr-minimal/index.html similarity index 100% rename from examples/minimal/index.html rename to examples/csr-minimal/index.html diff --git a/examples/minimal/locales/en/main.ftl b/examples/csr-minimal/locales/en/main.ftl similarity index 100% rename from examples/minimal/locales/en/main.ftl rename to examples/csr-minimal/locales/en/main.ftl diff --git a/examples/minimal/locales/es/main.ftl b/examples/csr-minimal/locales/es/main.ftl similarity index 100% rename from examples/minimal/locales/es/main.ftl rename to examples/csr-minimal/locales/es/main.ftl diff --git a/examples/minimal/src/lib.rs b/examples/csr-minimal/src/lib.rs similarity index 100% rename from examples/minimal/src/lib.rs rename to examples/csr-minimal/src/lib.rs diff --git a/examples/complete/src/main.rs b/examples/csr-minimal/src/main.rs similarity index 74% rename from examples/complete/src/main.rs rename to examples/csr-minimal/src/main.rs index 206fda9f..167a680f 100644 --- a/examples/complete/src/main.rs +++ b/examples/csr-minimal/src/main.rs @@ -1,5 +1,5 @@ use leptos::*; -use leptos_fluent_complete_example::App; +use leptos_fluent_csr_minimal_example::App; pub fn main() { console_error_panic_hook::set_once(); diff --git a/examples/ssr-hydrate-actix/Cargo.toml b/examples/ssr-hydrate-actix/Cargo.toml index 4270e5a7..b11eb8c6 100644 --- a/examples/ssr-hydrate-actix/Cargo.toml +++ b/examples/ssr-hydrate-actix/Cargo.toml @@ -24,13 +24,13 @@ csr = [ "leptos/csr", "leptos_meta/csr", "leptos_router/csr", - "leptos-fluent/csr" + "leptos-fluent/csr", ] hydrate = [ "leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate", - "leptos-fluent/hydrate" + "leptos-fluent/hydrate", ] ssr = [ "dep:actix-files", @@ -39,7 +39,8 @@ ssr = [ "leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr", - "leptos-fluent/ssr" + "leptos-fluent/ssr", + "leptos-fluent/actix" ] [package.metadata.leptos] diff --git a/examples/ssr-hydrate-actix/src/app.rs b/examples/ssr-hydrate-actix/src/app.rs index 990df79d..6dac0382 100644 --- a/examples/ssr-hydrate-actix/src/app.rs +++ b/examples/ssr-hydrate-actix/src/app.rs @@ -1,6 +1,6 @@ use fluent_templates::static_loader; use leptos::*; -use leptos_fluent::{i18n, leptos_fluent, move_tr, Language}; +use leptos_fluent::{i18n, leptos_fluent, move_tr, tr, Language}; use leptos_meta::*; use leptos_router::*; @@ -17,16 +17,18 @@ pub fn App() -> impl IntoView { leptos_fluent! {{ translations: TRANSLATIONS, locales: "./locales", - sync_html_tag_lang: true, initial_language_from_url: true, + initial_language_from_url_param: "lang", initial_language_from_url_to_localstorage: true, initial_language_from_localstorage: true, initial_language_from_navigator: true, + localstorage_key: "language", + initial_language_from_accept_language_header: true, }}; view! { // sets the document title - + <Title text=move || tr!("welcome-to-leptos")/> // content for this welcome page <Router> diff --git a/leptos-fluent-macros/Cargo.toml b/leptos-fluent-macros/Cargo.toml index 31f8932e..62a8d067 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 = "2021" -version = "0.0.20" +version = "0.0.21" license = "MIT" documentation = "https://docs.rs/leptos-fluent" repository = "https://github.com/mondeja/leptos-fluent" @@ -24,3 +24,4 @@ web-sys = { version = ">=0.1", optional = true } csr = ["web-sys/Storage", "web-sys/Navigator"] hydrate = ["web-sys/Storage", "web-sys/Navigator"] ssr = [] +actix = [] diff --git a/leptos-fluent-macros/src/lib.rs b/leptos-fluent-macros/src/lib.rs index b98ba333..ca47d526 100644 --- a/leptos-fluent-macros/src/lib.rs +++ b/leptos-fluent-macros/src/lib.rs @@ -100,6 +100,8 @@ struct I18nLoader { initial_language_from_navigator_expr: Option<syn::Expr>, localstorage_key_str: Option<syn::LitStr>, localstorage_key_expr: Option<syn::Expr>, + initial_language_from_accept_language_header_bool: Option<syn::LitBool>, + initial_language_from_accept_language_header_expr: Option<syn::Expr>, } impl Parse for I18nLoader { @@ -134,6 +136,12 @@ impl Parse for I18nLoader { let mut initial_language_from_navigator_expr: Option<syn::Expr> = None; let mut localstorage_key_str: Option<syn::LitStr> = None; let mut localstorage_key_expr: Option<syn::Expr> = None; + let mut initial_language_from_accept_language_header_bool: Option< + syn::LitBool, + > = None; + let mut initial_language_from_accept_language_header_expr: Option< + syn::Expr, + > = None; while !fields.is_empty() { let k = fields.parse::<Ident>()?; @@ -208,6 +216,15 @@ impl Parse for I18nLoader { ) { return Err(err); } + } else if k == "initial_language_from_accept_language_header" { + if let Some(err) = parse_litbool_or_expr_param( + &fields, + &mut initial_language_from_accept_language_header_bool, + &mut initial_language_from_accept_language_header_expr, + "initial_language_from_accept_language_header", + ) { + return Err(err); + } } else { return Err(syn::Error::new( k.span(), @@ -298,6 +315,8 @@ impl Parse for I18nLoader { initial_language_from_navigator_expr, localstorage_key_str, localstorage_key_expr, + initial_language_from_accept_language_header_bool, + initial_language_from_accept_language_header_expr, }) } } @@ -363,21 +382,25 @@ impl Parse for I18nLoader { /// expression that will be evaluated at runtime. /// - **`initial_language_from_url`** (_`false`_): Load the initial language of the user /// from a URL parameter. Can be a literal boolean or an expression that will be evaluated at -/// runtime. +/// runtime. It will only take effect on client-side. /// - **`initial_language_from_url_param`** (_`"lang"`_): The parameter name to look for the initial /// language in the URL. Can be a literal string or an expression that will be evaluated at -/// runtime. +/// runtime. It will only take effect on client-side. /// - **`initial_language_from_url_to_localstorage`** (_`false`_): Save the initial language /// of the user from the URL to [local storage]. Can be a literal boolean or an expression that will -/// be evaluated at runtime. +/// be evaluated at runtime. It will only take effect on client-side. /// - **`initial_language_from_localstorage`** (_`false`_): Load the initial language of the /// user from [local storage] if not found in the URL param. Can be a literal boolean or an expression -/// that will be evaluated at runtime. +/// that will be evaluated at runtime. It will only take effect on client-side. /// - **`initial_language_from_navigator`** (_`false`_): Load the initial language of the user /// from [`navigator.languages`] if not found in [local storage]. Can be a literal boolean or an -/// expression that will be evaluated at runtime. +/// expression that will be evaluated at runtime. It will only take effect on client-side. /// - **`localstorage_key`** (_`"lang"`_): The [local storage] field to get and save the current language /// of the user. Can be a literal string or an expression that will be evaluated at runtime. +/// It will only take effect on client-side. +/// - **`initial_language_from_accept_language_header`** (_`false`_): Load the initial language of the user +/// from the `Accept-Language` header. Can be a literal boolean or an expression that will be evaluated at +/// runtime. It will only take effect on server-side. /// /// [`fluent_templates::static_loader!`]: https://docs.rs/fluent-templates/0.8.0/fluent_templates/macro.static_loader.html /// [`once_cell:sync::Lazy`]: https://docs.rs/once_cell/latest/once_cell/sync/struct.Lazy.html @@ -390,7 +413,7 @@ impl Parse for I18nLoader { pub fn leptos_fluent( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - #[cfg_attr(feature = "ssr", allow(unused_variables))] + #[allow(unused_variables)] let I18nLoader { translations_ident, languages, @@ -408,6 +431,8 @@ pub fn leptos_fluent( initial_language_from_navigator_expr, localstorage_key_str, localstorage_key_expr, + initial_language_from_accept_language_header_bool, + initial_language_from_accept_language_header_expr, } = parse_macro_input!(input as I18nLoader); let n_languages = languages.len(); @@ -462,61 +487,63 @@ pub fn leptos_fluent( let sync_html_tag_lang_quote = quote! {}; }}; - let initial_language_from_url_bool_value = initial_language_from_url_bool - .as_ref() - .map(|lit| lit.clone().value); - - let initial_language_from_url = match initial_language_from_url_bool { - Some(lit) => quote! { #lit }, - None => match initial_language_from_url_expr { - Some(expr) => quote! { #expr }, - None => quote! { false }, - }, - }; - - let initial_language_from_localstorage_bool_value = - initial_language_from_localstorage_bool + cfg_if! { if #[cfg(not(feature = "ssr"))] { + let initial_language_from_url_bool_value = initial_language_from_url_bool .as_ref() .map(|lit| lit.clone().value); - let initial_language_from_url_to_localstorage = - match initial_language_from_url_to_localstorage_bool { - Some(lit) => quote! { #lit }, - None => match initial_language_from_url_to_localstorage_expr { - Some(expr) => quote! { #expr }, - None => quote! { false }, - }, - }; - let initial_language_from_localstorage = - match initial_language_from_localstorage_bool { + let initial_language_from_url = match initial_language_from_url_bool { Some(lit) => quote! { #lit }, - None => match initial_language_from_localstorage_expr { + None => match initial_language_from_url_expr { Some(expr) => quote! { #expr }, None => quote! { false }, }, }; - let initial_language_from_navigator_bool_value = - initial_language_from_navigator_bool - .as_ref() - .map(|lit| lit.clone().value); - let initial_language_from_navigator = - match initial_language_from_navigator_bool { - Some(lit) => quote! { #lit }, - None => match initial_language_from_navigator_expr { - Some(expr) => quote! { #expr }, - None => quote! { false }, - }, - }; + let initial_language_from_localstorage_bool_value = + initial_language_from_localstorage_bool + .as_ref() + .map(|lit| lit.clone().value); + let initial_language_from_url_to_localstorage = + match initial_language_from_url_to_localstorage_bool { + Some(lit) => quote! { #lit }, + None => match initial_language_from_url_to_localstorage_expr { + Some(expr) => quote! { #expr }, + None => quote! { false }, + }, + }; - let initial_language_from_url_param = - match initial_language_from_url_param_str { - Some(lit) => quote! { #lit }, - None => match initial_language_from_url_param_expr { - Some(expr) => quote! { #expr }, - None => quote! { "lang" }, - }, - }; + let initial_language_from_localstorage = + match initial_language_from_localstorage_bool { + Some(lit) => quote! { #lit }, + None => match initial_language_from_localstorage_expr { + Some(expr) => quote! { #expr }, + None => quote! { false }, + }, + }; + + let initial_language_from_navigator_bool_value = + initial_language_from_navigator_bool + .as_ref() + .map(|lit| lit.clone().value); + let initial_language_from_navigator = + match initial_language_from_navigator_bool { + Some(lit) => quote! { #lit }, + None => match initial_language_from_navigator_expr { + Some(expr) => quote! { #expr }, + None => quote! { false }, + }, + }; + + let initial_language_from_url_param = + match initial_language_from_url_param_str { + Some(lit) => quote! { #lit }, + None => match initial_language_from_url_param_expr { + Some(expr) => quote! { #expr }, + None => quote! { "lang" }, + }, + }; + }}; let localstorage_key = match localstorage_key_str { Some(lit) => quote! { #lit }, @@ -526,65 +553,83 @@ pub fn leptos_fluent( }, }; - let initial_language_from_url_quote = - match initial_language_from_url_bool_value { - Some(value) => match value { - true => quote! { - if let Some(l) = ::leptos_fluent::url::get(#initial_language_from_url_param) - { - lang = i18n.language_from_str(&l); - if let Some(l) = lang { - if #initial_language_from_url_to_localstorage { - ::leptos_fluent::localstorage::set( - #localstorage_key, - &l.id.to_string(), - ); + cfg_if! { if #[cfg(not(feature = "ssr"))] { + let initial_language_from_url_quote = + match initial_language_from_url_bool_value { + Some(value) => match value { + true => quote! { + if let Some(l) = ::leptos_fluent::url::get( + #initial_language_from_url_param + ) { + lang = ::leptos_fluent::language_from_str_between_languages( + &l, + &LANGUAGES + ); + if let Some(l) = lang { + if #initial_language_from_url_to_localstorage { + ::leptos_fluent::localstorage::set( + #localstorage_key, + &l.id.to_string(), + ); + } } } - } + }, + false => quote! {}, }, - false => quote! {}, - }, - None => quote! { - if #initial_language_from_url { - if let Some(l) = ::leptos_fluent::url::get(#initial_language_from_url_param) - { - lang = i18n.language_from_str(&l); - if let Some(l) = lang { - if #initial_language_from_url_to_localstorage { - ::leptos_fluent::localstorage::set( - #localstorage_key, - &l.id.to_string(), - ); + None => quote! { + if #initial_language_from_url { + if let Some(l) = ::leptos_fluent::url::get( + #initial_language_from_url_param + ) { + lang = ::leptos_fluent::language_from_str_between_languages( + &l, + &LANGUAGES + ); + if let Some(l) = lang { + if #initial_language_from_url_to_localstorage { + ::leptos_fluent::localstorage::set( + #localstorage_key, + &l.id.to_string(), + ); + } } } } - } - }, - }; + }, + }; + }}; - let initial_language_from_localstorage_quote = - match initial_language_from_localstorage_bool_value { - Some(value) => match value { - true => quote! { - if lang.is_none() { + cfg_if! { if #[cfg(not(feature = "ssr"))] { + let initial_language_from_localstorage_quote = + match initial_language_from_localstorage_bool_value { + Some(value) => match value { + true => quote! { + if lang.is_none() { + if let Some(l) = ::leptos_fluent::localstorage::get(#localstorage_key) + { + lang = ::leptos_fluent::language_from_str_between_languages( + &l, + &LANGUAGES + ); + } + } + }, + false => quote! {}, + }, + None => quote! { + if #initial_language_from_localstorage && lang.is_none() { if let Some(l) = ::leptos_fluent::localstorage::get(#localstorage_key) { - lang = i18n.language_from_str(&l); + lang = ::leptos_fluent::language_from_str_between_languages( + &l, + &LANGUAGES + ); } } }, - false => quote! {}, - }, - None => quote! { - if #initial_language_from_localstorage && lang.is_none() { - if let Some(l) = ::leptos_fluent::localstorage::get(#localstorage_key) - { - lang = i18n.language_from_str(&l); - } - } - }, - }; + }; + }}; cfg_if! { if #[cfg(not(feature = "ssr"))] { let window_navigator_languages_quote = quote! { @@ -594,64 +639,117 @@ pub fn leptos_fluent( if language.is_none() { continue; } - if let Some(l) = i18n.language_from_str(&language.unwrap()) - { + if let Some(l) = ::leptos_fluent::language_from_str_between_languages( + &language.unwrap(), + &LANGUAGES + ) { lang = Some(l); break; } } }; - } else { - let window_navigator_languages_quote = quote! {}; - }}; - let initial_language_from_navigator_quote = - match initial_language_from_navigator_bool_value { - Some(value) => match value { - true => quote! { - if lang.is_none() { + let initial_language_from_navigator_quote = + match initial_language_from_navigator_bool_value { + Some(value) => match value { + true => quote! { + if lang.is_none() { + #window_navigator_languages_quote; + } + }, + false => quote! {}, + }, + None => quote! { + if #initial_language_from_navigator && lang.is_none() { #window_navigator_languages_quote; } }, - false => quote! {}, - }, - None => quote! { - if #initial_language_from_navigator && lang.is_none() { - #window_navigator_languages_quote; + }; + }}; + + // Accept-Language header + cfg_if! { if #[cfg(not(feature = "ssr"))] { + } else if #[cfg(feature = "actix")] { + // Actix + let parse_actix_header_quote = quote! { + if let Some(req) = leptos::use_context::<actix_web::HttpRequest>() { + let maybe_header = req + .headers() + .get(actix_web::http::header::ACCEPT_LANGUAGE) + .and_then(|header| header.to_str().ok()); + + if let Some(header) = maybe_header { + let langs = ::leptos_fluent::http_header::parse(header); + for l in langs { + if let Some(l) = ::leptos_fluent::language_from_str_between_languages(&l, &LANGUAGES) { + lang = Some(l); + + break; + } + } } - }, + } }; - // create_effect only runs on the client - let initial_language_quote = quote! { - create_effect(move |prev| { - let i18n = expect_context::<::leptos_fluent::I18n>(); - let mut lang: Option<&'static ::leptos_fluent::Language> = None; - #initial_language_from_url_quote; - #initial_language_from_localstorage_quote; - #initial_language_from_navigator_quote; - if let Some(l) = lang { - i18n.language.set(l); - } - }); - }; + let initial_language_from_accept_language_header_quote = + match initial_language_from_accept_language_header_bool { + Some(lit) => match lit.value { + true => parse_actix_header_quote, + false => quote! {}, + }, + None => match initial_language_from_accept_language_header_expr { + Some(expr) => quote! { + if #expr { + #parse_actix_header_quote; + } + }, + None => quote! {}, + }, + }; + } else { + // Other SSR frameworks + // + // TODO: compilation error because is not implemented for this framework + let initial_language_from_accept_language_header_quote = quote! {}; + }}; + + cfg_if! { if #[cfg(not(feature = "ssr"))] { + let initial_language_quote = quote! { + #initial_language_from_url_quote + #initial_language_from_localstorage_quote + #initial_language_from_navigator_quote + }; + } else { + let initial_language_quote = quote! { + #initial_language_from_accept_language_header_quote + }; + }}; let quote = quote! { { const LANGUAGES: [&::leptos_fluent::Language; #n_languages] = #languages_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 i18n = ::leptos_fluent::I18n { - language: ::leptos::create_rw_signal(LANGUAGES[0]), + language: ::leptos::create_rw_signal(initial_lang), languages: &LANGUAGES, translations: &#translations_ident, localstorage_key: #localstorage_key, }; - provide_context::<::leptos_fluent::I18n>(i18n); - #initial_language_quote; - #sync_html_tag_lang_quote; - expect_context::<::leptos_fluent::I18n>() + let ctx = provide_context::<::leptos_fluent::I18n>(i18n); + #sync_html_tag_lang_quote + ctx } }; - // println!("{}", quote); + //println!("{}", quote); proc_macro::TokenStream::from(quote) } diff --git a/leptos-fluent/Cargo.toml b/leptos-fluent/Cargo.toml index 352559d8..9dcffa2f 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 = "2021" -version = "0.0.20" +version = "0.0.21" license = "MIT" documentation = "https://docs.rs/leptos-fluent" repository = "https://github.com/mondeja/leptos-fluent" @@ -16,6 +16,7 @@ leptos_router = { version = ">=0.1", optional = true } once_cell = "1" cfg-if = "1" web-sys = { version = ">=0.1", optional = true } +actix-web = { version = "*", optional = true, features = ["cookies"] } [features] csr = [ @@ -34,3 +35,4 @@ hydrate = [ "leptos_router/hydrate" ] ssr = ["leptos_router/ssr", "leptos/ssr", "leptos-fluent-macros/ssr"] +actix = ["dep:actix-web", "leptos-fluent-macros/actix"] diff --git a/leptos-fluent/README.md b/leptos-fluent/README.md index ff1e1c91..b46fad81 100644 --- a/leptos-fluent/README.md +++ b/leptos-fluent/README.md @@ -18,13 +18,16 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -leptos-fluent = "0.0.20" +leptos-fluent = "0.0.21" fluent-templates = "0.9" [features] csr = ["leptos-fluent/csr"] hydrate = ["leptos-fluent/hydrate"] -ssr = ["leptos-fluent/ssr"] +ssr = [ + "leptos-fluent/ssr", + "leptos-fluent/actix", # Currently only actix is supported +] ``` ## Usage @@ -99,6 +102,12 @@ pub fn App() -> impl IntoView { // Name of the field in local storage to get and set the // current language of the user. By default, it is `"lang"`. localstorage_key: "language", + + // Server side options (for `ssr`) + // ------------------------------- + // Set the initial language from the Accept-Language header of the + // request. By default, it is `false`. + initial_language_from_accept_language_header: true, }}; view! { @@ -121,6 +130,13 @@ fn ChildComponent() -> impl IntoView { } ``` +### Features + +- **Client side rendering (CSR)**: Use `leptos-fluent/csr` feature. +- **Server side rendering (SSR)**: Use `leptos-fluent/ssr` feature. +- **Hydration**: Use `leptos-fluent/hydrate` feature. +- **Actix web integration**: Use `leptos-fluent/actix` feature. + ## Resources - [Quickstart] diff --git a/leptos-fluent/src/http_header.rs b/leptos-fluent/src/http_header.rs new file mode 100644 index 00000000..13ccf2c0 --- /dev/null +++ b/leptos-fluent/src/http_header.rs @@ -0,0 +1,26 @@ +pub fn parse(header: &str) -> Vec<String> { + let mut parsed_lang: Vec<_> = header + .split(';') + .map(|lang| { + let mut langs = lang.split(',').peekable(); + let q = if let Some(a) = langs + .peek() + .and_then(|maybe_q| maybe_q.trim().strip_prefix("q=")) + { + let q = a.parse::<f32>().unwrap_or(1.0); + langs.next(); + q + } else { + 1.0 + }; + (q, langs) + }) + .collect(); + + parsed_lang.sort_unstable_by(|a, b| b.0.total_cmp(&a.0)); + + parsed_lang + .into_iter() + .flat_map(|(_q, langs)| langs.map(str::trim).map(String::from)) + .collect() +} diff --git a/leptos-fluent/src/lib.rs b/leptos-fluent/src/lib.rs index 4cb653b1..d76ec44e 100644 --- a/leptos-fluent/src/lib.rs +++ b/leptos-fluent/src/lib.rs @@ -11,13 +11,16 @@ //! //! ```toml //! [dependencies] -//! leptos-fluent = "0.0.20" +//! leptos-fluent = "0.0.21" //! fluent-templates = "0.9" //! //! [features] //! csr = ["leptos-fluent/csr"] //! hydrate = ["leptos-fluent/hydrate"] -//! ssr = ["leptos-fluent/ssr"] +//! ssr = [ +//! "leptos-fluent/ssr", +//! "leptos-fluent/actix", # Currently only actix is supported +//! ] //! ``` //! //! # Usage @@ -92,6 +95,12 @@ //! // Name of the field in local storage to get and set the //! // current language of the user. By default, it is `"lang"`. //! localstorage_key: "language", +//! +//! // Server side options (for `ssr`) +//! // ------------------------------- +//! // Set the initial language from the Accept-Language header of the +//! // request. By default, it is `false`. +//! initial_language_from_accept_language_header: true, //! }}; //! //! view! { @@ -114,6 +123,13 @@ //! } //! ``` //! +//! ## Features +//! +//! - **Client side rendering (CSR)**: Use `leptos-fluent/csr` feature. +//! - **Server side rendering (SSR)**: Use `leptos-fluent/ssr` feature. +//! - **Hydration**: Use `leptos-fluent/hydrate` feature. +//! - **Actix web integration**: Use `leptos-fluent/actix` feature. +//! //! # Resources //! //! - [Quickstart] @@ -132,6 +148,8 @@ //! [examples]: https://github.com/mondeja/leptos-fluent/tree/master/examples //! [documentation]: https://docs.rs/leptos-fluent +#[doc(hidden)] +pub mod http_header; #[doc(hidden)] pub mod localstorage; #[doc(hidden)] @@ -234,26 +252,7 @@ impl I18n { /// language identifier without the region. If it doesn't find a match, it will /// return `None`. pub fn language_from_str(&self, code: &str) -> Option<&'static Language> { - match LanguageIdentifier::from_str(code) { - Ok(target_lang) => match self - .languages - .iter() - .find(|lang| lang.id.matches(&target_lang, false, false)) - { - Some(lang) => Some(lang), - None => { - let mut lazy_target_lang = target_lang.clone(); - lazy_target_lang.region = None; - match self.languages.iter().find(|lang| { - lang.id.matches(&lazy_target_lang, true, true) - }) { - Some(lang) => Some(lang), - None => None, - } - } - }, - Err(_) => None, - } + language_from_str_between_languages(code, self.languages) } /// Set the current language in the signal of the context and in local storage. @@ -314,3 +313,29 @@ macro_rules! move_tr { })) }; } + +pub fn language_from_str_between_languages( + code: &str, + languages: &'static [&Language], +) -> Option<&'static Language> { + match LanguageIdentifier::from_str(code) { + Ok(target_lang) => match languages + .iter() + .find(|lang| lang.id.matches(&target_lang, false, false)) + { + Some(lang) => Some(lang), + None => { + let mut lazy_target_lang = target_lang.clone(); + lazy_target_lang.region = None; + match languages + .iter() + .find(|lang| lang.id.matches(&lazy_target_lang, true, true)) + { + Some(lang) => Some(lang), + None => None, + } + } + }, + Err(_) => None, + } +} diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 7049a280..a008df49 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -7,8 +7,8 @@ version = "0.1.0" crate-type = ["cdylib"] [dependencies] -leptos-fluent-minimal-example = { path = "../examples/minimal" } -leptos-fluent-complete-example = { path = "../examples/complete" } +leptos-fluent-csr-minimal-example = { path = "../examples/csr-minimal" } +leptos-fluent-csr-complete-example = { path = "../examples/csr-complete" } wasm-bindgen-test = "0.3" leptos = "0.6" js-sys = "0.3" diff --git a/tests/src/web.rs b/tests/src/web.rs index a235f633..72170b3a 100644 --- a/tests/src/web.rs +++ b/tests/src/web.rs @@ -67,7 +67,7 @@ fn html_lang() -> String { #[wasm_bindgen_test] async fn minimal_example() { - use leptos_fluent_minimal_example::App as MinimalExampleApp; + use leptos_fluent_csr_minimal_example::App as MinimalExampleApp; mount!(MinimalExampleApp); let es = input_by_id("es"); let en = input_by_id("en"); @@ -95,7 +95,7 @@ async fn minimal_example() { #[wasm_bindgen_test] async fn complete_example() { - use leptos_fluent_complete_example::App as CompleteExampleApp; + use leptos_fluent_csr_complete_example::App as CompleteExampleApp; mount!(CompleteExampleApp); let es = input_by_id("es"); let en = input_by_id("en");