use super::Locales;
use crate::{path::PathWithoutLocale, utils::get_path_prefix_client};
use sycamore::rt::Reflect;
use wasm_bindgen::JsValue;
pub(crate) fn detect_locale(url: PathWithoutLocale, locales: &Locales) -> String {
let mut locale = locales.default.clone();
let navigator = web_sys::window().unwrap().navigator();
let langs = navigator.languages().to_vec();
if langs.is_empty() {
if let Some(lang) = navigator.language() {
locale = match compare_locale(&lang, &locales.get_all()) {
LocaleMatch::Exact(matched) | LocaleMatch::Language(matched) => matched,
LocaleMatch::None => locales.default.to_string(),
}
}
} else {
for cmp in langs {
let cmp_str = cmp.as_string().unwrap();
if let LocaleMatch::Exact(matched) | LocaleMatch::Language(matched) =
compare_locale(&cmp_str, &locales.get_all())
{
locale = matched;
break;
}
}
}
let url = url.strip_suffix('/').unwrap_or(&url);
let url = url.strip_prefix('/').unwrap_or(url);
let url = format!("/{}", url);
let base_path = get_path_prefix_client(); let loc = url.strip_prefix(&base_path).unwrap_or(&url);
let loc = loc.strip_prefix('/').unwrap_or(loc);
let new_loc = format!("{}/{}/{}", base_path, locale, loc);
let new_loc = new_loc.strip_suffix('/').unwrap_or(&new_loc);
Reflect::set(
&JsValue::from(web_sys::window().unwrap()),
&JsValue::from("__PERSEUS_INITIAL_STATE"),
&JsValue::undefined(),
)
.unwrap();
new_loc.to_string()
}
#[derive(Debug, PartialEq, Eq)]
enum LocaleMatch {
Exact(String),
Language(String),
None,
}
fn compare_locale<S: Into<String> + std::fmt::Display>(cmp: &str, locales: &[S]) -> LocaleMatch {
let mut outcome = LocaleMatch::None;
let cmp_parts: Vec<&str> = cmp.split('-').collect();
for locale in locales {
let locale = locale.to_string();
let parts: Vec<&str> = locale.split('-').collect();
if locale == cmp {
outcome = LocaleMatch::Exact(locale.to_string());
break;
} else if cmp_parts.first() == parts.first() {
if !matches!(outcome, LocaleMatch::Language(_)) {
outcome = LocaleMatch::Language(locale.to_string())
}
}
}
outcome
}
mod tests {
#[allow(unused_imports)] use super::*;
#[test]
fn matches_exact() {
let verdict = compare_locale("en-US", &["en-US"]);
assert_eq!(verdict, LocaleMatch::Exact("en-US".to_string()))
}
#[test]
fn matches_lang() {
let verdict = compare_locale("en-US", &["en-GB"]);
assert_eq!(verdict, LocaleMatch::Language("en-GB".to_string()))
}
#[test]
fn fails_on_no_match() {
let verdict = compare_locale("en-US", &["zh-CN"]);
assert_eq!(verdict, LocaleMatch::None)
}
#[test]
fn uses_later_exact_match() {
let verdict = compare_locale("en-US", &["en-GB", "en-US"]);
assert_eq!(verdict, LocaleMatch::Exact("en-US".to_string()))
}
}