diff --git a/examples/core/i18n/src/templates/about.rs b/examples/core/i18n/src/templates/about.rs index 5518341559..e832234630 100644 --- a/examples/core/i18n/src/templates/about.rs +++ b/examples/core/i18n/src/templates/about.rs @@ -4,15 +4,10 @@ use sycamore::prelude::*; fn about_page(cx: Scope) -> View { view! { cx, p { (t!(cx, "about")) } - p { - ( - if !G::IS_BROWSER { - "This is running on the server." - } else { - "This is running on the client." - } - ) - } + button(on:click = move |_| { + #[cfg(client)] + Reactor::::from_cx(cx).switch_locale("fr-FR"); + }) { "Switch to French" } } } diff --git a/packages/perseus-macro/src/entrypoint.rs b/packages/perseus-macro/src/entrypoint.rs index 3065d549e4..bdac403474 100644 --- a/packages/perseus-macro/src/entrypoint.rs +++ b/packages/perseus-macro/src/entrypoint.rs @@ -181,8 +181,8 @@ pub fn main_impl(input: MainFn, server_fn: Path) -> TokenStream { // The browser-specific `main` function #[cfg(client)] - pub fn main() -> ::perseus::ClientReturn { - ::perseus::run_client(__perseus_simple_main); + pub fn main() -> ::perseus::client::ClientReturn { + ::perseus::client::run_client(__perseus_simple_main); Ok(()) } diff --git a/packages/perseus/src/client.rs b/packages/perseus/src/client.rs index 1fd51ce7cf..c060c4e5ab 100644 --- a/packages/perseus/src/client.rs +++ b/packages/perseus/src/client.rs @@ -1,6 +1,6 @@ use crate::reactor::Reactor; -use crate::{checkpoint, plugins::PluginAction, template::BrowserNodeType}; use crate::{i18n::TranslationsManager, init::PerseusAppBase, stores::MutableStore}; +use crate::{plugins::PluginAction, template::BrowserNodeType, utils::checkpoint}; use sycamore::prelude::create_scope; #[cfg(feature = "hydrate")] use sycamore::utils::hydrate::with_hydration_context; diff --git a/packages/perseus/src/lib.rs b/packages/perseus/src/lib.rs index 6c0089f952..022e625c20 100644 --- a/packages/perseus/src/lib.rs +++ b/packages/perseus/src/lib.rs @@ -52,8 +52,9 @@ pub mod template; /// General utilities that may be useful while building Perseus apps. pub mod utils; +/// Utilities for initializing the Perseus client. #[cfg(all(feature = "client-helpers", any(client, doc)))] -mod client; +pub mod client; mod init; mod page_data; /// Utilities for working with typed paths. diff --git a/packages/perseus/src/reactor/initial_load.rs b/packages/perseus/src/reactor/initial_load.rs index f7fa535e58..61ee421340 100644 --- a/packages/perseus/src/reactor/initial_load.rs +++ b/packages/perseus/src/reactor/initial_load.rs @@ -1,14 +1,13 @@ use std::collections::HashMap; use crate::{ - checkpoint, error_views::ServerErrorData, errors::*, i18n::detect_locale, path::PathMaybeWithLocale, router::{match_route, FullRouteInfo, FullRouteVerdict, RouterLoadState}, state::TemplateState, - utils::get_path_prefix_client, + utils::{checkpoint, get_path_prefix_client}, }; use serde_json::Value; use sycamore::{ diff --git a/packages/perseus/src/reactor/mod.rs b/packages/perseus/src/reactor/mod.rs index 565b0901d4..4f7e99dee8 100644 --- a/packages/perseus/src/reactor/mod.rs +++ b/packages/perseus/src/reactor/mod.rs @@ -253,6 +253,27 @@ impl Reactor { pub fn get_translator(&self) -> Translator { self.try_get_translator().expect("translator not available") } + /// Switches the current locale to the given locale. This will navigate to + /// the current page in the given locale. + /// + /// If a new page is being loaded, or if an error view is loaded, this will + /// simply have no effect whatsoever (to avoid users trying to switch + /// locales during a navigation and inadvertently causing a panic). + /// + /// # Panics + /// + /// This will panic if the given locale is not supported: use this only with + /// hardcoded locale values! This will also panic if used in an error + /// view without a translator. + #[cfg(client)] + pub fn switch_locale(&self, new_locale: &str) { + let path = self.router_state.get_path(); + if let Some(path) = path { + let curr_locale = self.get_translator().get_locale(); + let new_path = path.replace(&curr_locale, new_locale); + sycamore_router::navigate(&new_path); + } + } } #[cfg(engine)] diff --git a/packages/perseus/src/reactor/start.rs b/packages/perseus/src/reactor/start.rs index a6c6daca57..e78fb1aaab 100644 --- a/packages/perseus/src/reactor/start.rs +++ b/packages/perseus/src/reactor/start.rs @@ -1,12 +1,11 @@ use super::Reactor; use crate::{ - checkpoint, error_views::ErrorPosition, errors::ClientError, reactor::InitialView, router::{PageDisposer, PerseusRoute, RouteVerdict, RouterLoadState}, template::BrowserNodeType, - utils::{render_or_hydrate, replace_head}, + utils::{checkpoint, render_or_hydrate, replace_head}, }; use sycamore::prelude::{create_effect, create_signal, on_mount, view, ReadSignal, Scope, View}; use sycamore_futures::spawn_local_scoped; diff --git a/packages/perseus/src/reactor/subsequent_load.rs b/packages/perseus/src/reactor/subsequent_load.rs index e519ef9b98..32529c5879 100644 --- a/packages/perseus/src/reactor/subsequent_load.rs +++ b/packages/perseus/src/reactor/subsequent_load.rs @@ -6,14 +6,13 @@ use sycamore::{ }; use crate::{ - checkpoint, errors::{AssetType, ClientError, ClientInvariantError}, i18n::detect_locale, page_data::PageDataPartial, path::PathMaybeWithLocale, router::{FullRouteInfo, FullRouteVerdict, RouteVerdict, RouterLoadState}, state::{PssContains, TemplateState}, - utils::{fetch, get_path_prefix_client, replace_head}, + utils::{checkpoint, fetch, get_path_prefix_client, replace_head}, }; use super::Reactor;