Sub Context

You may want to have sections of you application to use the translations but be isolated from the "main" locale, this is what sub-context are for.

Why not just use I18nContextProvider ?

I18nContextProvider does not shadow any context if one already exist, this is because it should only be one "main" context, or they will battle for the cookie, the "lang" attribute, the routing, ect..

init_i18n_subcontext_* functions create a context that does not battle with the main context and makes it more obvious that a sub context is created, improving code clarity.

Initialize a sub-context

leptos_i18n::context::init_i18n_subcontext takes an initial_locale: Option<Signal<L>> argument, this is so you can control the sub-context locale outside of it, you can for example makes it so the locale of the sub-context is always the opposite of the "main" one:

#![allow(unused)]
fn main() {
fn neg_locale(locale: Locale) -> Locale {
    match locale {
        Locale::en => Locale::fr,
        Locale::fr => Locale::en
    }
}

fn neg_i18n_signal(i18n: I18nContext<Locale>) -> Signal<Locale> {
    Signal::derive(move || neg_locale(i18n.get()))
}

fn opposite_context() {
    let i18n = use_i18n();
    let ctx = init_i18n_subcontext(Some(neg_i18n_signal(i18n)));
    // ..
}
}

If it is not supplied, it takes the parent context locale as a default, and if no parent context exist (yes you can use sub-context as a "main" context if you want) it uses the same locale resolution as the normal context.

Providing a sub-context

There is no provide_i18n_subcontext. It does exist but is marked as deprecated, it is not actually deprecated, it is only there as a information point, although is does what you thing.

Shadowing correctly

Shadowing a context is not as easy as it sounds:

#![allow(unused)]
fn main() {
use crate::i18n::*;
use leptos::prelude::*;
use leptos_i18n::context::provide_i18n_subcontext;

#[component]
fn Foo() -> impl IntoView {
    view! {
        <I18nContextProvider>
            <Sub />
            <Home />
        </I18nContextProvider>
    }
}

#[component]
fn Sub() -> impl IntoView {
    let i18n = provide_i18n_subcontext();
    view! {
        <p>{t!(i18n, sub)}</p>
    }
}

#[component]
fn Home() -> impl IntoView {
    let i18n = use_i18n();
    view! {
        <p>{t!(i18n, home)}</p>
    }
}
}

This will actually make the sub-context provided in the <Sub /> component replace the parent context and leak into the <Home /> component.

leptos::provide_context has a section about shadowing in there docs, the best approach is to use a provider:

#![allow(unused)]
fn main() {
#[component]
fn Sub() -> impl IntoView {
    let i18n = init_i18n_subcontext();
    view! {
        <Provider value=i18n>
            <p>{t!(i18n, sub)}</p>
        </Provider>
    }
}
}

So this crate has a I18nSubContextProvider generated in the i18n module:

#![allow(unused)]
fn main() {
use crate::i18n::*;
use leptos::prelude::*;

#[component]
fn Foo() -> impl IntoView {
    view! {
        <I18nContextProvider>
            <I18nSubContextProvider>
                <Sub />
            </I18nSubContextProvider>
            <Home />
        </I18nContextProvider>
    }
}

#[component]
fn Sub() -> impl IntoView {
    let i18n = use_i18n();
    view! {
        <p>{t!(i18n, sub)}</p>
    }
}
}

Options

Same has with the normal context, sub-contexts have behavior control options, they all take the initial_locale: Option<Signal<L>> as their first argument.

init_i18n_subcontext_with_options takes options a cookie, that function is useless without the cookie feature.

  • cookie_name is an option to a name for a cookie to be set to keep state of the chosen locale
  • cookie_options is an option to some options for a cookie.