Why the need for a leptos-specific i18n library? How does this library differ from rust-i18n
?
#47
-
I'm having trouble figuring out why a leptos-specific i18n library is necessary. I'd originally thought this was just a wrapper of the library below for leptos, but it seems to be a ground-up building of i18n. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 8 replies
-
Multiple reasons:
Also Basically it expands to struct I18nKeys {
pub hello_world: &'static str,
}
const KEYS_FR: I18nKeys = I18nKeys {
hello_world: "Hello world",
};
const KEYS_EN: I18nKeys = I18nKeys {
hello_world: "Bonjour le monde",
}; and {move || match i18n.get_locale() {
Locale::en => KEYS_EN.hello_world,
Locale::fr => KEYS_FR.hello_world
}} I wanted to do the most runtime performant solution I could find. Locales are statics once the application run, so why not do as much work as possible in compilation? I hope this makes sense, but yes I could have used another crate as a backend and call it a day, but I wanted to do things differently, see what I could bring to the table, and full compile time locales loading was a really nice challenge. |
Beta Was this translation helpful? Give feedback.
-
Just for the exemple, this is what the pub mod i18n {
#[derive(Clone, Copy)]
pub struct Locales;
impl leptos_i18n::Locales for Locales {
type Variants = LocaleEnum;
type LocaleKeys = I18nKeys;
}
#[derive(Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum LocaleEnum {
en,
fr,
}
impl Default for LocaleEnum {
fn default() -> Self {
LocaleEnum::en
}
}
impl leptos_i18n::LocaleVariant for LocaleEnum {
fn as_str(&self) -> &'static str {
match *self {
LocaleEnum::en => "en",
LocaleEnum::fr => "fr",
}
}
fn from_str(s: &str) -> Option<Self> {
match s {
"en" => Some(LocaleEnum::en),
"fr" => Some(LocaleEnum::fr),
_ => None,
}
}
}
#[derive(Clone, Copy)]
#[allow(non_camel_case_types)]
pub struct I18nKeys {
pub click_to_change_lang: &'static str,
pub click_to_inc: &'static str,
pub click_count: builders::click_count_builder<builders::EmptyInterpolateValue>,
}
impl I18nKeys {
#[allow(non_upper_case_globals)]
pub const en: Self = Self::new(LocaleEnum::en);
#[allow(non_upper_case_globals)]
pub const fr: Self = Self::new(LocaleEnum::fr);
pub const fn new(_variant: LocaleEnum) -> Self {
match _variant {
LocaleEnum::en => I18nKeys {
click_to_change_lang: "Click to change language",
click_to_inc: "Click to increment the counter",
click_count: builders::click_count_builder::new(_variant),
},
LocaleEnum::fr => I18nKeys {
click_to_inc: "Cliquez pour incrémenter le compteur",
click_to_change_lang: "Cliquez pour changez de langue",
click_count: builders::click_count_builder::new(_variant),
},
}
}
}
impl leptos_i18n::LocaleKeys for I18nKeys {
type Locales = Locales;
fn from_variant(_variant: LocaleEnum) -> &'static Self {
match _variant {
LocaleEnum::en => &Self::en,
LocaleEnum::fr => &Self::fr,
}
}
}
#[doc(hidden)]
pub mod builders {
use super::LocaleEnum;
#[derive(Clone, Copy)]
pub struct EmptyInterpolateValue;
#[allow(non_camel_case_types)]
pub struct click_count_builder<__var_count> {
__locale: LocaleEnum,
var_count: __var_count,
}
impl click_count_builder<EmptyInterpolateValue> {
pub const fn new(__locale: LocaleEnum) -> Self {
Self {
var_count: EmptyInterpolateValue,
__locale,
}
}
}
#[allow(non_camel_case_types)]
impl<__var_count: Fn() -> i64 + core::clone::Clone + 'static> leptos::IntoView
for click_count_builder<__var_count>
{
fn into_view(self) -> leptos::View {
let Self {
var_count,
__locale,
} = self;
match __locale {
LocaleEnum::en => leptos::IntoView::into_view({
let var_count = core::clone::Clone::clone(&var_count);
move || match var_count() {
0i64 => leptos::IntoView::into_view("You have not clicked yet"),
1i64 => leptos::IntoView::into_view("You clicked once"),
2i64..=19i64 => leptos::CollectView::collect_view([
leptos::IntoView::into_view("You clicked "),
leptos::IntoView::into_view(core::clone::Clone::clone(&var_count)),
leptos::IntoView::into_view(" times"),
]),
20i64.. => leptos::IntoView::into_view("You clicked a lot"),
..=-1i64 => {
leptos::IntoView::into_view("You clicked a negative amount ??")
}
}
}),
LocaleEnum::fr => leptos::IntoView::into_view({
let var_count = core::clone::Clone::clone(&var_count);
move || match var_count() {
0i64 => leptos::IntoView::into_view("Vous n'avez pas cliqué"),
1i64 => leptos::IntoView::into_view("Vous avez cliqué une fois"),
2i64..=19i64 => leptos::CollectView::collect_view([
leptos::IntoView::into_view("You clicked "),
leptos::IntoView::into_view(core::clone::Clone::clone(&var_count)),
leptos::IntoView::into_view(" times"),
]),
20i64.. => leptos::IntoView::into_view("You clicked a lot"),
_ => leptos::IntoView::into_view("You clicked a negative amount ??"),
}
}),
}
}
}
#[allow(non_camel_case_types)]
impl click_count_builder<EmptyInterpolateValue> {
#[inline]
pub fn var_count<__T, __N>(
self,
var_count: __T,
) -> click_count_builder<impl Fn() -> i64 + core::clone::Clone + 'static>
where
__T: Fn() -> __N + core::clone::Clone + 'static,
__N: core::convert::Into<i64>,
{
let Self { __locale, .. } = self;
let var_count = move || core::convert::Into::into(var_count());
click_count_builder {
__locale,
var_count,
}
}
}
#[allow(non_camel_case_types)]
impl<__var_count: Fn() -> i64 + core::clone::Clone + 'static> click_count_builder<__var_count> {
#[deprecated(note = "variable `count` is already set")]
#[inline]
pub fn var_count<__T, __N>(
self,
var_count: __T,
) -> click_count_builder<impl Fn() -> i64 + core::clone::Clone + 'static>
where
__T: Fn() -> __N + core::clone::Clone + 'static,
__N: core::convert::Into<i64>,
{
let Self { __locale, .. } = self;
let var_count = move || core::convert::Into::into(var_count());
click_count_builder {
__locale,
var_count,
}
}
}
impl click_count_builder<EmptyInterpolateValue> {
#[deprecated(note = "\nMissing interpolations keys: [\"count\"]")]
pub fn build(self) {
{
{
::core::panicking::panic_fmt(format_args!(
"\nMissing interpolations keys: [\"count\"]"
));
}
}
}
}
#[allow(non_camel_case_types)]
impl<__var_count: Fn() -> i64 + core::clone::Clone + 'static> click_count_builder<__var_count> {
pub fn build(self) -> Self {
self
}
}
}
#[inline]
pub fn use_i18n() -> leptos_i18n::I18nContext<Locales> {
leptos_i18n::use_i18n_context()
}
#[inline]
pub fn provide_i18n_context() -> leptos_i18n::I18nContext<Locales> {
leptos_i18n::provide_i18n_context()
}
pub use leptos_i18n::t;
} |
Beta Was this translation helpful? Give feedback.
Multiple reasons:
leptos::IntoView
typesAlso
rust-i18n
use a different philosophie, they do load locales at compile time but just to embbed them in the binary and avoid loading them at runtime, it is still some kind ofHashMap<Key, String>
(not exactly, but you get the point). Here the locale is completly reconstructed as the type level, if you try to access a key not existing it will not compile, when you access a key it's a direct access of the value (minus the match on the locale). Even the declared languages are turned into a Enum, you can't set the lang to an unsu…