leptos-fluent

Internationalization framework for Leptos using fluent-templates.
Installation
Add the following to your Cargo.toml file:
[dependencies]
leptos-fluent = "0.1"
fluent-templates = "0.9"
[features]
hydrate = [
"leptos-fluent/hydrate"
]
ssr = [
"leptos-fluent/ssr",
"leptos-fluent/actix",
]
If you're using cargo-leptos to build your project, watch the
locales/ folder with:
[package.metadata.leptos]
watch-additional-files = ["locales"]
Usage
Giving the following directory structure:
.
βββ π Cargo.toml
βββ π locales
β βββ π en
β β βββ π main.ftl
β βββ π es
β βββ π main.ftl
βββ π src
βββ π main.rs
βββ π lib.rs
With Fluent files en.ftl and es.ftl:
hello-world = Hello, world!
hello-args = Hello, { $arg1 } and { $arg2 }!
hello-world = Β‘Hola, mundo!
hello-args = Β‘Hola, { $arg1 } y { $arg2 }!
You can use leptos-fluent as follows:
use fluent_templates::static_loader;
use leptos::*;
use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, tr};
static_loader! {
static TRANSLATIONS = {
locales: "./locales",
fallback_language: "en",
};
}
#[component]
fn App() -> impl IntoView {
leptos_fluent! {{
locales: "./locales",
translations: [TRANSLATIONS],
check_translations: "./src/**/*.rs",
sync_html_tag_lang: true,
sync_html_tag_dir: true,
set_language_to_url_param: true,
initial_language_from_url_param_to_localstorage: true,
localstorage_key: "language",
initial_language_from_localstorage: true,
set_language_to_localstorage: true,
initial_language_from_navigator: true,
cookie_attrs: "SameSite=Strict; Secure; path=/; max-age=600",
set_language_to_cookie: true,
initial_language_from_accept_language_header: true,
cookie_name: "lang",
initial_language_from_cookie: true,
url_param: "lang",
initial_language_from_url_param: true,
}};
view! {
<ChildComponent />
<LanguageSelector />
}
}
#[component]
fn ChildComponent() -> impl IntoView {
view! {
<p>
<span>{move || tr!("hello-world")}</span>
<span>{move_tr!("hello-args", {
"arg1" => "foo",
"arg2" => "bar",
})}</span>
</p>
}
}
#[component]
fn LanguageSelector() -> impl IntoView {
let i18n = expect_i18n();
view! {
<fieldset>
{
move || i18n.languages.iter().map(|lang| {
view! {
<div>
<input
type="radio"
id=lang
name="language"
value=lang
checked=lang.is_active()
on:click=move |_| i18n.language.set(lang)
/>
<label for=lang>{lang.name}</label>
</div>
}
}).collect::<Vec<_>>()
}
</fieldset>
}
}
Features
- Server Side Rendering:
ssr
- Hydration:
hydrate
- Actix Web integration:
actix
- Axum integration:
axum
- JSON languages file:
json (enabled by default)
- YAML languages file:
yaml
- JSON5 languages file:
json5
Resources