feat: localization support

This commit is contained in:
Felipe 2025-03-14 22:46:50 -03:00
parent e3e92a158a
commit f48d78d03b
Signed by: pitbuster
SSH key fingerprint: SHA256:HDYu2Pm4/TmSX8GBwV49UvFWr1Ljg8XlHxKeCpjJpOk
9 changed files with 106 additions and 26 deletions

View file

@ -1 +1,6 @@
not-found = We couldn't find that page.
title = Hypergeometric Distribution Calculator
population = Population Size
successes = Successes in Population
sample = Sample Size
sample_successes = Successes in Sample

View file

@ -1 +1,6 @@
not-found = No pudimos encontrar esta página.
title = Calculadora Distribución Hipergeométrica
population = Tamaño población
successes = Éxitos en la población
sample = Tamaño de la muestra
sample_successes = Éxitos en la muestra

View file

@ -32,6 +32,11 @@ h6 {
padding: 2rem;
}
h1.title {
width: 80vw;
max-inline-size: 80vw;
}
p {
margin: var(--size-6);
}
@ -59,7 +64,7 @@ form input {
form > div.results {
display: grid;
grid-template-columns: 1fr 6em 6em 1fr;
grid-template-columns: 1fr 8em 5em 1fr;
min-width: 20em;
max-width: 30em;
width: 30vw;

View file

@ -1,9 +1,10 @@
//! Hypergeometric Distribution Calculator
use leptos::html::ElementChild;
use leptos::prelude::{
signal, ClassAttribute, Get, GlobalAttributes, OnTargetAttribute, PropAttribute, Set,
ClassAttribute, Get, GlobalAttributes, OnTargetAttribute, PropAttribute, Set, signal,
};
use leptos::{component, view, IntoView};
use leptos::{IntoView, component, view};
use leptos_fluent::move_tr;
use crate::calc::hyper_geometric;
@ -26,7 +27,7 @@ pub fn Calculator() -> impl IntoView {
view! {
<form>
<p>
<label for="population">Population Size</label>
<label for="population">{move_tr!("population")}</label>
<input
id="population"
type="number"
@ -38,7 +39,7 @@ pub fn Calculator() -> impl IntoView {
/>
</p>
<p>
<label for="successes">Successes in Population</label>
<label for="successes">{move_tr!("successes")}</label>
<input
id="successes"
type="number"
@ -51,7 +52,7 @@ pub fn Calculator() -> impl IntoView {
/>
</p>
<p>
<label for="sample">Sample Size</label>
<label for="sample">{move_tr!("sample")}</label>
<input
id="sample"
type="number"
@ -64,7 +65,7 @@ pub fn Calculator() -> impl IntoView {
/>
</p>
<p>
<label for="sample_successes">Successes in Sample</label>
<label for="sample_successes">{move_tr!("sample_successes")}</label>
<input
id="sample_successes"
type="number"

View file

@ -0,0 +1,55 @@
//! Localization selector
use fluent_templates::static_loader;
use leptos::html::ElementChild;
use leptos::prelude::{Children, GlobalAttributes, OnAttribute, PropAttribute, Set};
use leptos::{IntoView, component, view};
use leptos_fluent::{Language, expect_i18n, leptos_fluent};
static_loader! {
pub static TRANSLATIONS = {
locales: "./locales",
fallback_language: "en",
};
}
/// This component provide localization context to every children component.
#[component]
pub fn I18n(children: Children) -> impl IntoView {
leptos_fluent! {
children: children(),
translations: [TRANSLATIONS],
locales: "./locales",
check_translations: "./src/**/*.rs",
}
}
#[component]
pub fn LanguageSelector() -> impl IntoView {
// Use `expect_i18n()` to get the current i18n context:
let i18n = expect_i18n();
view! {
<label for="language">"A/文:"</label>
<select id="language">
{move || {
i18n.languages.iter().map(|lang| render_language(lang)).collect::<Vec<_>>()
}}
</select>
}
}
fn render_language(lang: &'static Language) -> impl IntoView {
// Passed as atrribute, `Language` is converted to their code,
// so `<input id=lang` becomes `<input id=lang.id.to_string()`
let i18n = expect_i18n();
view! {
<option
id=lang
value=lang
prop:selected=lang.is_active()
on:click=move |_| i18n.language.set(lang)
>
{lang.name}
</option>
}
}

View file

@ -1 +1,2 @@
pub mod calculator;
pub mod localization;

View file

@ -1,6 +1,5 @@
use fluent_templates::static_loader;
use leptos::prelude::{AddAnyAttr, IntoAttribute};
use leptos::{component, view, IntoView};
use leptos::{IntoView, component, view};
use leptos_meta::*;
use leptos_router::{components::*, path};
@ -12,14 +11,6 @@ mod pages;
// Top-Level pages
use crate::pages::home::Home;
// Localization
static_loader! {
pub static TRANSLATIONS = {
locales: "./locales",
fallback_language: "en",
};
}
/// An app router which renders the homepage and handles 404's
#[component]
pub fn App() -> impl IntoView {
@ -30,7 +21,7 @@ pub fn App() -> impl IntoView {
<Html attr:lang="en" attr:dir="ltr" attr:data-theme="light" />
// sets the document title
<Title text="Welcome to Leptos CSR" />
<Title text="Hypergeometric Calculator" />
// injects metadata in the <head> of the page
<Meta charset="UTF-8" />

View file

@ -2,9 +2,11 @@ use leptos::attr::global::ClassAttribute;
use leptos::error::ErrorBoundary;
use leptos::html::ElementChild;
use leptos::prelude::{CollectView, Get};
use leptos::{component, view, IntoView};
use leptos::{IntoView, component, view};
use leptos_fluent::move_tr;
use crate::components::calculator::Calculator;
use crate::components::localization::{I18n, LanguageSelector};
/// Default Home Page
#[component]
@ -28,13 +30,21 @@ pub fn Home() -> impl IntoView {
</ul>
}
}>
<I18n>
<header>
<LanguageSelector />
</header>
<div class="container">
<h1>"Hypergeometric Distribution Calculator"</h1>
<div class="calculator">
<Title />
<Calculator />
</div>
</div>
</I18n>
</ErrorBoundary>
}
}
/// Title
#[component]
pub fn Title() -> impl IntoView {
view! {<h1 class="title">{move_tr!("title")}</h1>}
}

View file

@ -1,8 +1,15 @@
use leptos::html::ElementChild;
use leptos::{component, view, IntoView};
use leptos::{IntoView, component, view};
use leptos_fluent::move_tr;
use crate::components::localization::I18n;
/// 404 Not Found Page
#[component]
pub fn NotFound() -> impl IntoView {
view! { <h1>"We couldn't find that page."</h1> }
view! {
<I18n>
<h1>{move_tr!("not-found")}</h1>
</I18n>
}
}