i18n on the web - deepseek translations
This commit is contained in:
@@ -55,6 +55,33 @@ impl Nav {
|
||||
self.locale.lookup(key)
|
||||
}
|
||||
|
||||
/// Like [`Self::tr`], but interpolates named `{ $name }` placeholders.
|
||||
/// Values are strings; a template needing a *number* (for Fluent plural
|
||||
/// selection) should have the label built in Rust instead, where the
|
||||
/// `tr!` macro accepts `i64` arguments.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn tr_args(&self, key: &str, args: &[(&str, String)]) -> String {
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
let map: HashMap<Cow<'static, str>, fluent_templates::fluent_bundle::FluentValue<'_>> =
|
||||
args.iter()
|
||||
.map(|(name, value)| (Cow::Owned(name.to_string()), value.clone().into()))
|
||||
.collect();
|
||||
self.locale.lookup_args(key, &map)
|
||||
}
|
||||
|
||||
/// Translates a key with one numeric argument, for Fluent plural
|
||||
/// selection (`{ $count -> [one] … *[other] … }`).
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn tr_count(&self, key: &str, name: &str, count: &i64) -> String {
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
let mut map: HashMap<
|
||||
Cow<'static, str>,
|
||||
fluent_templates::fluent_bundle::FluentValue<'_>,
|
||||
> = HashMap::new();
|
||||
map.insert(Cow::Owned(name.to_string()), (*count).into());
|
||||
self.locale.lookup_args(key, &map)
|
||||
}
|
||||
|
||||
pub(crate) fn with_authorization(
|
||||
mut self,
|
||||
authorization: &crate::auth::AuthorizationSnapshot,
|
||||
@@ -97,22 +124,27 @@ impl Default for Nav {
|
||||
#[derive(Template)]
|
||||
#[template(path = "ui/alert_fragment.html")]
|
||||
pub(crate) struct Alert<'a> {
|
||||
/// The request's language, which the shared alert/dialog markup needs for
|
||||
/// its own chrome (the dismiss aria-label, the "Back to the form" button).
|
||||
locale: crate::i18n::Locale,
|
||||
success: bool,
|
||||
title: &'a str,
|
||||
message: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Alert<'a> {
|
||||
pub(crate) fn error(title: &'a str, message: &'a str) -> Self {
|
||||
pub(crate) fn error(locale: crate::i18n::Locale, title: &'a str, message: &'a str) -> Self {
|
||||
Self {
|
||||
locale,
|
||||
success: false,
|
||||
title,
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn success(title: &'a str, message: &'a str) -> Self {
|
||||
pub(crate) fn success(locale: crate::i18n::Locale, title: &'a str, message: &'a str) -> Self {
|
||||
Self {
|
||||
locale,
|
||||
success: true,
|
||||
title,
|
||||
message,
|
||||
@@ -124,22 +156,25 @@ impl<'a> Alert<'a> {
|
||||
#[derive(Template)]
|
||||
#[template(path = "ui/notice.html")]
|
||||
pub(crate) struct Notice<'a> {
|
||||
locale: crate::i18n::Locale,
|
||||
error: bool,
|
||||
message: &'a str,
|
||||
login_link: bool,
|
||||
}
|
||||
|
||||
impl<'a> Notice<'a> {
|
||||
pub(crate) fn error(message: &'a str) -> Self {
|
||||
pub(crate) fn error(locale: crate::i18n::Locale, message: &'a str) -> Self {
|
||||
Self {
|
||||
locale,
|
||||
error: true,
|
||||
message,
|
||||
login_link: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn login_required(message: &'a str) -> Self {
|
||||
pub(crate) fn login_required(locale: crate::i18n::Locale, message: &'a str) -> Self {
|
||||
Self {
|
||||
locale,
|
||||
error: true,
|
||||
message,
|
||||
login_link: true,
|
||||
@@ -172,7 +207,11 @@ mod tests {
|
||||
/// place that decides a failure cannot go unnoticed.
|
||||
#[test]
|
||||
fn a_failed_form_gets_a_dialog_and_a_successful_one_does_not() {
|
||||
let failure = render(&Alert::error("Could not save", "A name is required."));
|
||||
let failure = render(&Alert::error(
|
||||
crate::i18n::Locale::default(),
|
||||
"Could not save",
|
||||
"A name is required.",
|
||||
));
|
||||
assert!(!failure.contains("Template error"), "{failure}");
|
||||
assert!(failure.contains(r#"role="alert""#));
|
||||
assert!(failure.contains(r#"role="dialog""#));
|
||||
@@ -182,7 +221,11 @@ mod tests {
|
||||
// A success only asks the toast stack in `ui/base.html` to show it: it
|
||||
// dismisses itself, so it neither blocks the page nor stays behind in
|
||||
// the layout, and it renders nothing of its own here.
|
||||
let success = render(&Alert::success("Saved", "Two rows written."));
|
||||
let success = render(&Alert::success(
|
||||
crate::i18n::Locale::default(),
|
||||
"Saved",
|
||||
"Two rows written.",
|
||||
));
|
||||
assert!(!success.contains("Template error"), "{success}");
|
||||
assert!(success.contains("$dispatch('notify'"));
|
||||
assert!(success.contains(r#"data-message="Two rows written.""#));
|
||||
|
||||
Reference in New Issue
Block a user