Setup leptop_i18n

This commit is contained in:
Tanguy Gérôme 2024-10-22 17:46:53 +03:00
parent 09d1e72ac5
commit 2af602d8b1
11 changed files with 1056 additions and 77 deletions

871
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -20,9 +20,15 @@ wasm-bindgen = "=0.2.93"
thiserror = "1" thiserror = "1"
tracing = { version = "0.1", optional = true } tracing = { version = "0.1", optional = true }
http = "1" http = "1"
leptos_i18n = { version = "0.4.1", default-features = false, features = ["yaml_files"] }
[features] [features]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"] hydrate = [
"leptos/hydrate",
"leptos_meta/hydrate",
"leptos_router/hydrate",
"leptos_i18n/hydrate",
]
ssr = [ ssr = [
"dep:axum", "dep:axum",
"dep:tokio", "dep:tokio",
@ -33,8 +39,13 @@ ssr = [
"leptos_meta/ssr", "leptos_meta/ssr",
"leptos_router/ssr", "leptos_router/ssr",
"dep:tracing", "dep:tracing",
"leptos_i18n/axum",
] ]
[package.metadata.leptos-i18n]
default = "en"
locales = ["en", "fr", "fi", "et", "sv", "eo", "jbo"]
# Defines a size-optimized profile for the WASM bundle in release mode # Defines a size-optimized profile for the WASM bundle in release mode
[profile.wasm-release] [profile.wasm-release]
inherits = "release" inherits = "release"

6
locales/en.yaml Normal file
View file

@ -0,0 +1,6 @@
home: Home
available_in: "Available in:"
partial_translations: (partial translations)
tanguy_gerome: Tanguy Gérôme

6
locales/eo.yaml Normal file
View file

@ -0,0 +1,6 @@
home: Hejmo
available_in: "Havebla en:"
partial_translations:
tanguy_gerome:

6
locales/et.yaml Normal file
View file

@ -0,0 +1,6 @@
home: Kodu
available_in: "Saadaval keeles:"
partial_translations:
tanguy_gerome:

6
locales/fi.yaml Normal file
View file

@ -0,0 +1,6 @@
home: Koti
available_in: "Saatavilla kielillä:"
partial_translations: (keskeneräisiä käännöksiä)
tanguy_gerome:

6
locales/fr.yaml Normal file
View file

@ -0,0 +1,6 @@
home: Accueil
available_in: "Disponible en:"
partial_translations: (traductions partielles)
tanguy_gerome:

6
locales/jbo.yaml Normal file
View file

@ -0,0 +1,6 @@
home: zdani
available_in: "fanva fi "
partial_translations: (nalmu'o puvyfanva)
tanguy_gerome: .tangis.jerom.

6
locales/sv.yaml Normal file
View file

@ -0,0 +1,6 @@
home: Hem
available_in: "Finns på:"
partial_translations:
tanguy_gerome:

View file

@ -1,65 +1,99 @@
use crate::error_template::{AppError, ErrorTemplate}; leptos_i18n::load_locales!();
use i18n::*;
use leptos::*; use leptos::*;
use leptos_meta::*; use leptos_meta::*;
use leptos_router::*; use leptos_router::*;
use crate::error_template::{AppError, ErrorTemplate};
#[component] #[component]
pub fn App() -> impl IntoView { pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc. // Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context(); provide_meta_context();
view! { view! {
<I18nContextProvider>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<Stylesheet href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@100..900&family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"/>
<link rel="preconnect" href="https://fonts.googleapis.com"/> // id=leptos means cargo-leptos will hot-reload this stylesheet
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <Stylesheet id="leptos" href="/pkg/tanguy-gerome-fi.css"/>
<Stylesheet href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@100..900&family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"/>
// id=leptos means cargo-leptos will hot-reload this stylesheet <Title text="tanguy.gerome.fi"/>
<Stylesheet id="leptos" href="/pkg/tanguy-gerome-fi.css"/>
<Title text="tanguy.gerome.fi"/> <Router fallback=|| {
let mut outside_errors = Errors::default();
outside_errors.insert_with_default_key(AppError::NotFound);
view! {
<ErrorTemplate outside_errors/>
}
.into_view()
}>
<Header/>
<Routes>
<I18nRoute view=|| view! { <Outlet /> }>
<Route path="" view=HomePage/>
</I18nRoute>
</Routes>
<Footer/>
</Router>
</I18nContextProvider>
}
}
<Router fallback=|| { #[component]
let mut outside_errors = Errors::default(); pub fn LanguageSwitcher() -> impl IntoView {
outside_errors.insert_with_default_key(AppError::NotFound); let i18n = use_i18n();
view! {
<ErrorTemplate outside_errors/> view! {
} <div class="language-switcher main-width">
.into_view() <p>{t!(i18n, available_in)}</p>
}> <button class="link" on:click=move |_| i18n.set_locale(Locale::en)>english</button>
<Header/> <button class="link" on:click=move |_| i18n.set_locale(Locale::fr)>français</button>
<Routes> <button class="link" on:click=move |_| i18n.set_locale(Locale::fi)>suomi</button>
<Route path="" view=HomePage/> <button class="link" on:click=move |_| i18n.set_locale(Locale::et)>eesti</button>
</Routes> <button class="link" on:click=move |_| i18n.set_locale(Locale::sv)>svenska</button>
<Footer/> <button class="link" on:click=move |_| i18n.set_locale(Locale::eo)>esperanto</button>
</Router> <button class="link" on:click=move |_| i18n.set_locale(Locale::jbo)>lojban</button>
<p>{t!(i18n, partial_translations)}</p>
</div>
} }
} }
#[component] #[component]
fn Header() -> impl IntoView { fn Header() -> impl IntoView {
let i18n = use_i18n();
view! { view! {
<header> <header>
<div class="text"> <div class="title-links-and-banner">
<h1><span>tanguy</span><wbr/><span>.gerome</span><span>.fi</span></h1> <div class="text">
<div class="links"> <h1><span>tanguy</span><wbr/><span>.gerome</span><span>.fi</span></h1>
<div class="links">
<A href="/">{t!(i18n, home)}</A>
</div>
</div> </div>
<img
class="image"
src="https://images.ctfassets.net/e3magj9g6dp1/14q5L7K0BCol1gx0aCSCck/d1f69bfa404efed6a2dcc71401bbc16d/P5310039-1-2.jpg?w=2000&q=90&fm=avif"
alt=""
/>
</div> </div>
<img
class="image" <LanguageSwitcher/>
src="https://images.ctfassets.net/e3magj9g6dp1/14q5L7K0BCol1gx0aCSCck/d1f69bfa404efed6a2dcc71401bbc16d/P5310039-1-2.jpg?w=2000&q=90&fm=avif"
alt=""
/>
</header> </header>
} }
} }
#[component] #[component]
fn Footer() -> impl IntoView { fn Footer() -> impl IntoView {
let i18n = use_i18n();
view! { view! {
<footer> <footer>
<div class="name-and-links main-width"> <div class="name-and-links main-width">
<span class="name">Tanguy Gérôme</span> <span class="name">{t!(i18n, tanguy_gerome)}</span>
<div class="links"> <div class="links">
<a href="https://www.instagram.com/kapno.cc/" target="_blank" rel="noopener noreferrer">instagram @kapno.cc</a> <a href="https://www.instagram.com/kapno.cc/" target="_blank" rel="noopener noreferrer">instagram @kapno.cc</a>
<a href="https://github.com/kapnoc" target="_blank" rel="noopener noreferrer">github @kapnoc</a> <a href="https://github.com/kapnoc" target="_blank" rel="noopener noreferrer">github @kapnoc</a>

View file

@ -1,4 +1,4 @@
$mainGreen: #2E7D32; $mainGreen: darken(#2E7D32, 10);
$mainGrey: #0F0F0F; $mainGrey: #0F0F0F;
@mixin top-level-padding { @mixin top-level-padding {
@ -12,6 +12,19 @@ $mainGrey: #0F0F0F;
box-sizing: border-box; box-sizing: border-box;
} }
button {
&.link {
all: unset;
text-decoration: underline;
color: $mainGreen!important;
cursor: pointer;
}
}
a {
color: $mainGreen!important;
}
body { body {
font-family: 'Ubuntu', sans-serif; font-family: 'Ubuntu', sans-serif;
text-align: left; text-align: left;
@ -44,62 +57,91 @@ body {
h4 { font-size: 18px; } h4 { font-size: 18px; }
header { header {
background: $mainGrey;
color: white;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@media all and (max-width: 2000px) { .title-links-and-banner {
justify-content: flex-end; background: $mainGrey;
} color: white;
width: 100%;
@media all and (max-width: 800px) {
flex-direction: column;
align-items: stretch;
}
.text {
@include top-level-padding;
flex-basis: auto;
flex-shrink: 0;
flex-grow: 1;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 16px;
h1 { @media all and (max-width: 2000px) {
display: flex; justify-content: flex-end;
flex-direction: column;
align-items: flex-start;
} }
.links { @media all and (max-width: 800px) {
display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: stretch;
}
.text {
@include top-level-padding;
flex-basis: auto;
flex-shrink: 0;
flex-grow: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 16px;
h1 {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.links {
display: flex;
flex-direction: column;
align-items: flex-end;
a {
color: white!important;
}
}
}
.image {
max-width: 800px;
width: 100%;
max-height: 300px;
height: 100%;
object-fit: cover;
object-position: top;
flex-shrink: 1;
} }
} }
.image { .language-switcher {
max-width: 800px; @include top-level-padding;
width: 100%; margin: 16px 0;
max-height: 300px;
height: 100%; gap: 8px;
object-fit: cover; display: flex;
object-position: top; flex-direction: row;
flex-shrink: 1; align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
p {
margin: 0;
}
} }
} }
main { main {
@include top-level-padding; @include top-level-padding;
margin-bottom: 32px;
} }
footer { footer {
@ -145,7 +187,6 @@ body {
a { a {
color: white!important; color: white!important;
text-decoration: unset;
} }
} }
} }