Skip to content

Commit 61aa406

Browse files
committed
feat(i18n): made locale redirection much faster
Closes #61.
1 parent 4d6f904 commit 61aa406

File tree

5 files changed

+33
-7
lines changed

5 files changed

+33
-7
lines changed

packages/perseus-actix-web/src/initial_load.rs

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ pub async fn initial_load<M: MutableStore, T: TranslationsManager>(
127127
opts.locales.default,
128128
path
129129
),
130+
&opts.root_id,
130131
),
131132
)
132133
}

packages/perseus-warp/src/initial_load.rs

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pub async fn initial_load_handler<M: MutableStore, T: TranslationsManager>(
117117
opts.locales.default,
118118
path
119119
),
120+
&opts.root_id,
120121
))
121122
.unwrap()
122123
}

packages/perseus/src/export.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub async fn export_app(
9999
&html_shell,
100100
// If we don't include the path prefix, fallback redirection will fail for relative paths
101101
&format!("{}/{}/{}", path_prefix, locales.default, &path),
102+
root_id,
102103
),
103104
)
104105
.await?;

packages/perseus/src/html_shell.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,13 @@ pub fn interpolate_page_data(html_shell: &str, page_data: &PageData, root_id: &s
104104
/// From there, Perseus' inbuilt progressive enhancement can occur, but without this a user directed to an unlocalized page with JS disabled would see a
105105
/// blank screen, which is terrible UX. Note that this also includes a fallback for if JS is enabled but Wasm is disabled. Note that the redirect URL
106106
/// is expected to be generated with a path prefix inbuilt.
107-
pub fn interpolate_locale_redirection_fallback(html_shell: &str, redirect_url: &str) -> String {
107+
///
108+
/// This also adds a `__perseus_initial_state` `<div>` in case it's needed (for Wasm redirections).
109+
pub fn interpolate_locale_redirection_fallback(
110+
html_shell: &str,
111+
redirect_url: &str,
112+
root_id: &str,
113+
) -> String {
108114
// This will be used if JavaScript is completely disabled (it's then the site's responsibility to show a further message)
109115
let dumb_redirector = format!(
110116
r#"<noscript>
@@ -141,5 +147,16 @@ pub fn interpolate_locale_redirection_fallback(html_shell: &str, redirect_url: &
141147
&format!("{}\n{}\n</head>", js_redirector, dumb_redirector),
142148
);
143149

144-
html
150+
// The user MUST place have a `<div>` of this exact form (documented explicitly)
151+
// We permit either double or single quotes
152+
let html_to_replace_double = format!("<div id=\"{}\">", root_id);
153+
let html_to_replace_single = format!("<div id='{}'>", root_id);
154+
let html_replacement = format!(
155+
// We give the content a specific ID so that it can be deleted if an error page needs to be rendered on the client-side
156+
"{}<div id=\"__perseus_content_initial\" class=\"__perseus_content\"></div>",
157+
&html_to_replace_double,
158+
);
159+
// Now interpolate that HTML into the HTML shell
160+
html.replace(&html_to_replace_double, &html_replacement)
161+
.replace(&html_to_replace_single, &html_replacement)
145162
}

packages/perseus/src/locale_detector.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::locales::Locales;
22
use crate::path_prefix::get_path_prefix_client;
3+
use sycamore::rt::Reflect;
4+
use wasm_bindgen::JsValue;
35

46
/// Detects which locale the user should be served and redirects appropriately. This should only be used when the user navigates to a
57
/// page like `/about`, without a locale. This will only work on the client-side (needs access to browser i18n settings). Any pages
@@ -50,13 +52,17 @@ pub fn detect_locale(url: String, locales: &Locales) {
5052
let new_loc = format!("{}/{}/{}", base_path, locale, loc);
5153
let new_loc = new_loc.strip_suffix('/').unwrap_or(&new_loc);
5254

55+
// Unset the initial state variable so we perform subsequent renders correctly
56+
// This monstrosity is needed until `web-sys` adds a `.set()` method on `Window`
57+
Reflect::set(
58+
&JsValue::from(web_sys::window().unwrap()),
59+
&JsValue::from("__PERSEUS_INITIAL_STATE"),
60+
&JsValue::undefined(),
61+
)
62+
.unwrap();
5363
// Imperatively navigate to the localized route
5464
// This certainly shouldn't fail...
55-
web_sys::window()
56-
.unwrap()
57-
.location()
58-
.replace(new_loc)
59-
.unwrap();
65+
sycamore_router::navigate_replace(new_loc);
6066
}
6167

6268
/// The possible outcomes of trying to match a locale.

0 commit comments

Comments
 (0)