Skip to main content

Crate hypersig_i18n

Crate hypersig_i18n 

Source
Expand description

Typed translations for hypersig, where a missing translation is a compile error.

An application lists its locales in an enum and implements Locale for it. The text of each locale sits in one value of Locale::Text, a struct with a field per locale, so a text without its translation into one of the locales fails to compile, and a locale added to the enum fails to compile until every text has it. The locale itself is a Segment, so it is the first segment of a page’s Route, and a link to the same page in another language is a link with another locale.

use hypersig::html::{a, p};
use hypersig::{Page, Route, Segment, Signals};
use hypersig_i18n::Locale;
use serde::{Deserialize, Serialize};

#[derive(Segment, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
#[serde(rename_all = "lowercase")]
enum Lang {
    En,
    Ja,
}

/// One value per language.
struct ByLang<T> {
    en: T,
    ja: T,
}

impl Locale for Lang {
    const ALL: &'static [Self] = &[Self::En, Self::Ja];
    type Text<T> = ByLang<T>;

    fn pick<T>(self, text: ByLang<T>) -> T {
        match self {
            Self::En => text.en,
            Self::Ja => text.ja,
        }
    }
}

#[derive(Signals, Serialize, Deserialize)]
struct Home {}

hypersig::routes! {
    fn pages(Router<()>);
    const HOME: Route<Lang> = "/{lang}" => home;
}

async fn home((): (), lang: Lang) -> Page<Home> {
    let other = if lang == Lang::En { Lang::Ja } else { Lang::En };
    Page::new(lang.pick(ByLang { en: "Welcome", ja: "ようこそ" }), Home {})
        .lang(lang.tag())
        .child(p().text(lang.pick(ByLang { en: "Hello.", ja: "こんにちは。" })))
        .child(a().href(HOME.link_with(&other)).text(other.pick(ByLang { en: "English", ja: "日本語" })))
}

assert_eq!(HOME.url(Lang::Ja).as_str(), "/ja");

A message that takes values is a function per locale, as in ByLang<fn(u32) -> String>, so its arguments are typed in every translation alike.

With the axum feature (on by default), LocaleRouterExt sends a visitor who opens / to the page in the language their browser asks for.

Traits§

Locale
The locales of an application: an enum with #[derive(Segment)] whose segments are BCP 47 tags.
LocalePage
Adds the alternate of each locale to a Page.
LocaleRouterExt
Adds the redirect from / to the page in the visitor’s language to an axum [Router].

Functions§

negotiate
The locale of L that best matches an Accept-Language header value, or the default.