言語ごとのページ
言語は各ページのルートの最初のセグメントに置きます。そのため、別の言語のページは言語だけを変えた同じルートになります。
ルートに言語を入れる
Locale は Segment なので、"/{lang}/members/{id}" に対する Route<(Lang, i32)> のように、ルートの最初のパラメータにできます。ハンドラはほかのパラメータと一緒に言語を受け取ります。enum にない言語へのリクエストには、ハンドラを呼ぶ前に 404 を返します。
use hypersig::html::a;
use hypersig::{Page, Route};
#[derive(Signals, Serialize, Deserialize)]
struct Profile {
name: String,
}
hypersig::routes! {
fn pages(Router<()>);
// The language is the first segment of every page.
const MEMBER: Route<(Lang, i32)> = "/{lang}/members/{id}" => member;
}
async fn member((): (), (lang, id): (Lang, i32)) -> Page<Profile> {
let other = if lang == Lang::En { Lang::Ja } else { Lang::En };
Page::new(lang.pick(ByLang { en: "Member", ja: "メンバー" }), Profile { name: "Ada".to_owned() })
.lang(lang.tag())
// The same page in the other language is the same route with another locale.
.child(a().href(MEMBER.link_with((&other, id))).text(other.pick(ByLang { en: "English", ja: "日本語" })))
}
assert_eq!(MEMBER.url((Lang::Ja, 7)).as_str(), "/ja/members/7");ほかの言語へのリンク
同じページの別の言語へのリンクは、link_with に別の言語とそのほかの同じパラメータを渡して作ります。そのため、ほかのリンクと同じくルートがこのリンクを検査します。言語を切り替える UI は Locale::ALL を並べ、言語ごとに読者が今いるページへリンクします。
ページの言語
Page::lang はタグを <html lang> に書きます。ブラウザはこの属性を見て、ハイフネーション、スクリーンリーダーの読み上げの声、使うフォントを決めます。そのため、lang="ja" の付いた日本語の文は日本語の字形で表示されます。
LocalePage::alternates は Origin と、|lang| POST.url((lang, id)) のように言語からページの Url を返す関数を受け取ります。Locale::ALL の言語ごとに <link rel="alternate" hreflang> を 1 つ書き、最初の言語には x-default も書きます。検索エンジンはこれを見て、読者の言語のページを結果に出します。