From a713c485bd7a4c11efadef0c8ab65fdf4c842625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar=20Rubio?= Date: Sat, 15 Jun 2024 13:04:57 +0200 Subject: [PATCH] Get the initial language from URL parameter on SSR (#112) --- .pre-commit-config.yaml | 4 ++ CHANGELOG.md | 7 +++ Cargo.lock | 4 +- README.md | 20 ++++---- leptos-fluent-macros/Cargo.toml | 2 +- leptos-fluent-macros/src/lib.rs | 83 +++++++++++++++++++++++++++++---- leptos-fluent/Cargo.toml | 2 +- leptos-fluent/README.md | 20 ++++---- leptos-fluent/src/lib.rs | 20 ++++---- 9 files changed, 118 insertions(+), 44 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c0c6546a..0a4ddd64 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -68,6 +68,8 @@ repos: "--features=ssr,actix", --exclude=leptos-fluent-ssr-hydrate-axum-example, --exclude=leptos-fluent-ssr-hydrate-actix-example, + --exclude=leptos-fluent-csr-complete-example, + --exclude=leptos-fluent-csr-minimal-example, --workspace, --, -D, @@ -83,6 +85,8 @@ repos: "--features=ssr,axum,yaml", --exclude=leptos-fluent-ssr-hydrate-axum-example, --exclude=leptos-fluent-ssr-hydrate-actix-example, + --exclude=leptos-fluent-csr-complete-example, + --exclude=leptos-fluent-csr-minimal-example, --workspace, --, -D, diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c286c61..c2e02d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2024-06-15 - [0.0.35] + +### Bug fixes + +- Get the initial language from URL parameter on server side rendering. + ## 2024-06-09 - [0.0.34] ### New features @@ -186,6 +192,7 @@ - Added all ISO-639-1 and ISO-639-2 languages. +[0.0.35]: https://github.com/mondeja/leptos-fluent/compare/v0.0.34...v0.0.35 [0.0.34]: https://github.com/mondeja/leptos-fluent/compare/v0.0.33...v0.0.34 [0.0.33]: https://github.com/mondeja/leptos-fluent/compare/v0.0.32...v0.0.33 [0.0.32]: https://github.com/mondeja/leptos-fluent/compare/v0.0.31...v0.0.32 diff --git a/Cargo.lock b/Cargo.lock index 56ca541e..8dfe4158 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1446,7 +1446,7 @@ dependencies = [ [[package]] name = "leptos-fluent" -version = "0.0.34" +version = "0.0.35" dependencies = [ "fluent-templates", "leptos", @@ -1478,7 +1478,7 @@ dependencies = [ [[package]] name = "leptos-fluent-macros" -version = "0.0.34" +version = "0.0.35" dependencies = [ "fluent-syntax", "fluent-templates", diff --git a/README.md b/README.md index 8067bbac..e79b27d9 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -leptos-fluent = "0.0.34" +leptos-fluent = "0.0.35" fluent-templates = "0.9" [features] @@ -90,18 +90,12 @@ fn App() -> impl IntoView { // Synchronize `` attribute with the current // language using `leptos::create_effect`. By default, it is `false`. sync_html_tag_lang: true, - // URL parameter name to use discovering the initial language - // of the user. By default is `"lang"`. - url_param: "lang", - // Discover the initial language of the user from the URL. - // By default, it is `false`. - initial_language_from_url_param: true, - // Set the discovered initial language of the user from - // the URL in local storage. By default, it is `false`. - initial_language_from_url_param_to_localstorage: true, // Update the language on URL parameter when using the method // `I18n.set_language`. By default, it is `false`. set_language_to_url_param: true, + // Set the discovered initial language of the user from + // the URL in local storage. By default, it is `false`. + initial_language_from_url_param_to_localstorage: true, // 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", @@ -131,6 +125,12 @@ fn App() -> impl IntoView { // Update the language on cookie when using the method `I18n.set_language`. // By default, it is `false`. set_language_to_cookie: true, + // URL parameter name to use discovering the initial language + // of the user. By default is `"lang"`. + url_param: "lang", + // Discover the initial language of the user from the URL. + // By default, it is `false`. + initial_language_from_url_param: true, }}; view! { diff --git a/leptos-fluent-macros/Cargo.toml b/leptos-fluent-macros/Cargo.toml index a126d57b..8c2ba2f8 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.0.34" +version = "0.0.35" license = "MIT" documentation.workspace = true repository.workspace = true diff --git a/leptos-fluent-macros/src/lib.rs b/leptos-fluent-macros/src/lib.rs index 0bb52933..18c3cbbb 100644 --- a/leptos-fluent-macros/src/lib.rs +++ b/leptos-fluent-macros/src/lib.rs @@ -117,11 +117,11 @@ use quote::quote; /// with current language using [`leptos::create_effect`]. Can be a literal boolean or an /// expression that will be evaluated at runtime. /// - **`url_param`** (_`"lang"`_): The parameter name to manage the language in a URL parameter. -/// Can be a literal string or an expression that will be evaluated at runtime. It will only take -/// effect on client-side. +/// Can be a literal string or an expression that will be evaluated at runtime. It will take effect +/// on client-side and server side. /// - **`initial_language_from_url_param`** (_`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. It will only take effect on client-side. +/// runtime. It will take effect on client-side and server side. /// - **`set_language_to_url_param`** (_`false`_): Save the language of the user to an URL parameter /// when setting the language. Can be a literal boolean or an expression that will be evaluated at /// runtime. It will only take effect on client-side. @@ -283,7 +283,6 @@ pub fn leptos_fluent( } }; - #[cfg(not(feature = "ssr"))] let initial_language_from_url_param_quote = { #[cfg(feature = "hydrate")] let hydrate_rerender_quote = quote! { @@ -294,9 +293,10 @@ pub fn leptos_fluent( }); }; - #[cfg(not(feature = "hydrate"))] + #[cfg(all(not(feature = "hydrate"), not(feature = "ssr")))] let hydrate_rerender_quote = quote! {}; + #[cfg(not(feature = "ssr"))] let set_to_localstorage_quote = match initial_language_from_url_param_to_localstorage_bool { Some(lit) => match lit.value { @@ -323,6 +323,7 @@ pub fn leptos_fluent( } }; + #[cfg(not(feature = "ssr"))] let parse_language_from_url_quote = quote! { if let Some(l) = ::leptos_fluent::url::get( #url_param @@ -338,6 +339,62 @@ pub fn leptos_fluent( } }; + #[cfg(all(feature = "ssr", feature = "actix"))] + let parse_language_from_url_quote = quote! { + if let Some(req) = leptos::use_context::() { + let uri_query = req.uri().query().unwrap_or(""); + let mut maybe_lang = None; + for (key, value) in uri_query.split('&').map(|pair| { + let mut split = pair.splitn(2, '='); + (split.next().unwrap_or(""), split.next().unwrap_or("")) + }) { + if key == #url_param { + maybe_lang = Some(value); + break; + } + } + + if let Some(l) = maybe_lang { + lang = ::leptos_fluent::language_from_str_between_languages( + &l, + &LANGUAGES + ); + } + } + }; + + #[cfg(all(feature = "ssr", feature = "axum"))] + let parse_language_from_url_quote = quote! { + if let Some(req) = leptos::use_context::() { + let uri_query = req.uri.query().unwrap_or(""); + let mut maybe_lang = None; + for (key, value) in uri_query.split('&').map(|pair| { + let mut split = pair.splitn(2, '='); + (split.next().unwrap_or(""), split.next().unwrap_or("")) + }) { + if key == #url_param { + maybe_lang = Some(value); + break; + } + } + + if let Some(l) = maybe_lang { + lang = ::leptos_fluent::language_from_str_between_languages( + &l, + &LANGUAGES + ); + } + } + }; + + // Other SSR framework or the user is not using any + #[cfg(all( + not(feature = "actix"), + not(feature = "axum"), + feature = "ssr" + ))] + let parse_language_from_url_quote = quote! {}; + match initial_language_from_url_param_bool { Some(lit) => match lit.value { true => parse_language_from_url_quote, @@ -520,7 +577,7 @@ pub fn leptos_fluent( }; match initial_language_from_accept_language_header_bool { - Some(lit) => match lit.value { + Some(ref lit) => match lit.value { true => quote! { if lang.is_none() { #parse_axum_header_quote @@ -529,7 +586,7 @@ pub fn leptos_fluent( false => quote! {}, }, None => match initial_language_from_accept_language_header_expr { - Some(expr) => quote! { + Some(ref expr) => quote! { if #expr && lang.is_none() { #parse_axum_header_quote; } @@ -539,11 +596,16 @@ pub fn leptos_fluent( } }; - // Other SSR frameworks or the user is not using any + // Other SSR framework or the user is not using any #[cfg(all(not(feature = "actix"), not(feature = "axum"), feature = "ssr"))] let initial_language_from_accept_language_header_quote = quote! {}; // Cookie + #[cfg(any( + not(feature = "ssr"), + all(feature = "ssr", feature = "actix"), + all(feature = "ssr", feature = "axum") + ))] let cookie_name = match cookie_name_str { Some(lit) => quote! { #lit }, None => match cookie_name_expr { @@ -673,7 +735,7 @@ pub fn leptos_fluent( }; match initial_language_from_cookie_bool { - Some(lit) => match lit.value { + Some(ref lit) => match lit.value { true => quote! { if lang.is_none() { #parse_axum_cookie_quote; @@ -682,7 +744,7 @@ pub fn leptos_fluent( false => quote! {}, }, None => match initial_language_from_cookie_expr { - Some(expr) => quote! { + Some(ref expr) => quote! { if #expr && lang.is_none() { #parse_axum_cookie_quote; } @@ -713,6 +775,7 @@ pub fn leptos_fluent( #[cfg(feature = "ssr")] quote! { + #initial_language_from_url_param_quote #initial_language_from_cookie_quote #initial_language_from_accept_language_header_quote } diff --git a/leptos-fluent/Cargo.toml b/leptos-fluent/Cargo.toml index 715798a2..6584402b 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.0.34" +version = "0.0.35" license = "MIT" documentation.workspace = true repository.workspace = true diff --git a/leptos-fluent/README.md b/leptos-fluent/README.md index 8067bbac..e79b27d9 100644 --- a/leptos-fluent/README.md +++ b/leptos-fluent/README.md @@ -19,7 +19,7 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -leptos-fluent = "0.0.34" +leptos-fluent = "0.0.35" fluent-templates = "0.9" [features] @@ -90,18 +90,12 @@ fn App() -> impl IntoView { // Synchronize `` attribute with the current // language using `leptos::create_effect`. By default, it is `false`. sync_html_tag_lang: true, - // URL parameter name to use discovering the initial language - // of the user. By default is `"lang"`. - url_param: "lang", - // Discover the initial language of the user from the URL. - // By default, it is `false`. - initial_language_from_url_param: true, - // Set the discovered initial language of the user from - // the URL in local storage. By default, it is `false`. - initial_language_from_url_param_to_localstorage: true, // Update the language on URL parameter when using the method // `I18n.set_language`. By default, it is `false`. set_language_to_url_param: true, + // Set the discovered initial language of the user from + // the URL in local storage. By default, it is `false`. + initial_language_from_url_param_to_localstorage: true, // 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", @@ -131,6 +125,12 @@ fn App() -> impl IntoView { // Update the language on cookie when using the method `I18n.set_language`. // By default, it is `false`. set_language_to_cookie: true, + // URL parameter name to use discovering the initial language + // of the user. By default is `"lang"`. + url_param: "lang", + // Discover the initial language of the user from the URL. + // By default, it is `false`. + initial_language_from_url_param: true, }}; view! { diff --git a/leptos-fluent/src/lib.rs b/leptos-fluent/src/lib.rs index 172c61d9..b4d13763 100644 --- a/leptos-fluent/src/lib.rs +++ b/leptos-fluent/src/lib.rs @@ -14,7 +14,7 @@ //! //! ```toml //! [dependencies] -//! leptos-fluent = "0.0.34" +//! leptos-fluent = "0.0.35" //! fluent-templates = "0.9" //! //! [features] @@ -85,18 +85,12 @@ //! // Synchronize `` attribute with the current //! // language using `leptos::create_effect`. By default, it is `false`. //! sync_html_tag_lang: true, -//! // URL parameter name to use discovering the initial language -//! // of the user. By default is `"lang"`. -//! url_param: "lang", -//! // Discover the initial language of the user from the URL. -//! // By default, it is `false`. -//! initial_language_from_url_param: true, -//! // Set the discovered initial language of the user from -//! // the URL in local storage. By default, it is `false`. -//! initial_language_from_url_param_to_localstorage: true, //! // Update the language on URL parameter when using the method //! // `I18n.set_language`. By default, it is `false`. //! set_language_to_url_param: true, +//! // Set the discovered initial language of the user from +//! // the URL in local storage. By default, it is `false`. +//! initial_language_from_url_param_to_localstorage: true, //! // 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", @@ -126,6 +120,12 @@ //! // Update the language on cookie when using the method `I18n.set_language`. //! // By default, it is `false`. //! set_language_to_cookie: true, +//! // URL parameter name to use discovering the initial language +//! // of the user. By default is `"lang"`. +//! url_param: "lang", +//! // Discover the initial language of the user from the URL. +//! // By default, it is `false`. +//! initial_language_from_url_param: true, //! }}; //! //! view! {