Translation args in templates

This commit is contained in:
Pascal Engélibert 2022-12-04 18:06:29 +01:00
parent e710e6678f
commit 800036ce49
Signed by: tuxmain
GPG key ID: 3504BC6D362F7DCA
7 changed files with 76 additions and 26 deletions

View file

@ -5,7 +5,14 @@ admin_login-password_prompt = Password:
admin_login-submit_button = Login admin_login-submit_button = Login
admin_login-title = Admin login | Comments admin_login-title = Admin login | Comments
error-antispam = The edition quota from your IP is reached. You will be unblocked in { $antispam_timeout }s. error-antispam = The edition quota from your IP is reached. You will be unblocked in { $antispam_timeout }s.
error-list = Whoops, the following error occurred: error-comment-author_name_too_long = Author name length is { $len } but maximum is { $max_len }.
error-comment-email_too_long = E-mail length is { $len } but maximum is { $max_len }.
error-comment-text_too_long = Comment length is { $len } but maximum is { $max_len }.
error-list =
{ $nb_errors ->
[one] Whoops, the following error occurred:
*[other] Whoops, the following { $nb_errors } errors occurred:
}
comment_form-author = Your name: comment_form-author = Your name:
comment_form-email = Your email: comment_form-email = Your email:
comment_form-edit_button = Edit comment comment_form-edit_button = Edit comment

View file

@ -5,7 +5,11 @@ admin_login-password_prompt = Mot de passe :
admin_login-submit_button = S'authentifier admin_login-submit_button = S'authentifier
admin_login-title = Authentification admin | Commentaires admin_login-title = Authentification admin | Commentaires
error-antispam = Le quota d'édition de votre adresse IP est atteint, elle sera débloquée dans { $antispam_timeout }s. error-antispam = Le quota d'édition de votre adresse IP est atteint, elle sera débloquée dans { $antispam_timeout }s.
error-list = Oups, l'erreur suivante est survenue : error-list =
{ $nb_errors ->
[one] Oups, l'erreur suivante est survenue :
*[other] Oups, les { $nb_errors } erreurs suivantes sont survenues :
}
comment_form-author = Votre nom : comment_form-author = Votre nom :
comment_form-email = Votre e-mail : comment_form-email = Votre e-mail :
comment_form-edit_button = Modifier comment_form-edit_button = Modifier

View file

@ -1,7 +1,9 @@
use crate::{config::Config, db::*, queries::*}; use crate::{config::Config, db::*, locales::Locales, queries::*};
use fluent_bundle::FluentArgs;
use log::error; use log::error;
use std::{net::IpAddr, str::FromStr}; use std::{net::IpAddr, str::FromStr};
use unic_langid::LanguageIdentifier;
pub fn new_pending_comment( pub fn new_pending_comment(
comment: &Comment, comment: &Comment,
@ -173,27 +175,45 @@ pub fn get_client_addr<State>(
)) ))
} }
pub fn check_comment(config: &Config, comment: &CommentForm, errors: &mut Vec<String>) { pub fn check_comment(
config: &Config,
locales: &Locales,
langs: &[LanguageIdentifier],
comment: &CommentForm,
errors: &mut Vec<String>,
) {
if comment.author.len() > config.comment_author_max_len { if comment.author.len() > config.comment_author_max_len {
errors.push(format!( let mut args = FluentArgs::new();
"Author name length is {} but maximum is {}.", args.set("len", comment.author.len());
comment.author.len(), args.set("max_len", config.comment_author_max_len);
config.comment_author_max_len errors.push(
)); locales
.tr(langs, "error-comment-author_name_too_long", Some(&args))
.unwrap()
.to_string(),
);
} }
if comment.email.len() > config.comment_email_max_len { if comment.email.len() > config.comment_email_max_len {
errors.push(format!( let mut args = FluentArgs::new();
"E-mail length is {} but maximum is {}.", args.set("len", comment.email.len());
comment.email.len(), args.set("max_len", config.comment_email_max_len);
config.comment_email_max_len errors.push(
)); locales
.tr(langs, "error-comment-email_too_long", Some(&args))
.unwrap()
.to_string(),
);
} }
if comment.text.len() > config.comment_text_max_len { if comment.text.len() > config.comment_text_max_len {
errors.push(format!( let mut args = FluentArgs::new();
"Comment length is {} but maximum is {}.", args.set("len", comment.text.len());
comment.text.len(), args.set("max_len", config.comment_text_max_len);
config.comment_text_max_len errors.push(
)); locales
.tr(langs, "error-comment-text_too_long", Some(&args))
.unwrap()
.to_string(),
);
} }
} }

View file

@ -1,6 +1,6 @@
use crate::config::Config; use crate::config::Config;
use fluent_bundle::{bundle::FluentBundle, FluentArgs, FluentResource}; use fluent_bundle::{bundle::FluentBundle, FluentArgs, FluentResource, FluentValue};
use fluent_langneg::{ use fluent_langneg::{
accepted_languages, negotiate::filter_matches, negotiate_languages, NegotiationStrategy, accepted_languages, negotiate::filter_matches, negotiate_languages, NegotiationStrategy,
}; };
@ -101,3 +101,20 @@ pub fn get_time_lang(langs: &[LanguageIdentifier]) -> Option<String> {
} }
None None
} }
pub fn tera_to_fluent(val: &tera::Value) -> FluentValue {
match val {
tera::Value::Null => FluentValue::None,
tera::Value::Number(v) => {
if v.is_i64() {
FluentValue::Number(v.as_i64().unwrap().into())
} else if v.is_u64() {
FluentValue::Number(v.as_u64().unwrap().into())
} else {
FluentValue::Number(v.as_f64().unwrap().into())
}
}
tera::Value::String(v) => FluentValue::String(v.into()),
_ => FluentValue::Error,
}
}

View file

@ -34,7 +34,6 @@ async fn main() {
let config = Box::leak(Box::new(config)); let config = Box::leak(Box::new(config));
let locales = Box::leak(Box::new(locales::Locales::new(config))); let locales = Box::leak(Box::new(locales::Locales::new(config)));
// TODO args
templates.tera.register_function( templates.tera.register_function(
"tr", "tr",
Box::new( Box::new(
@ -53,7 +52,10 @@ async fn main() {
.ok_or_else(|| tera::Error::from("Missing argument `k`"))? .ok_or_else(|| tera::Error::from("Missing argument `k`"))?
.as_str() .as_str()
.ok_or_else(|| tera::Error::from("Argument `k` must be string"))?; .ok_or_else(|| tera::Error::from("Argument `k` must be string"))?;
let res = locales.tr(&langs, key, None); let args_iter = fluent_bundle::FluentArgs::from_iter(
args.iter().map(|(k, v)| (k, locales::tera_to_fluent(v))),
);
let res = locales.tr(&langs, key, Some(&args_iter));
if res.is_none() { if res.is_none() {
warn!("(calling `tr` in template) translation key `{key}` not found"); warn!("(calling `tr` in template) translation key `{key}` not found");
} }

View file

@ -286,7 +286,7 @@ async fn handle_post_comments(
return Err(tide::Error::from_str(404, "No topic")) return Err(tide::Error::from_str(404, "No topic"))
}; };
helpers::check_comment(config, &query.comment, &mut errors); helpers::check_comment(config, locales, &client_langs, &query.comment, &mut errors);
if let Some(client_addr) = &client_addr { if let Some(client_addr) = &client_addr {
if antispam_enabled { if antispam_enabled {
@ -360,7 +360,7 @@ async fn handle_post_comments(
return Err(tide::Error::from_str(403, "Forbidden")); return Err(tide::Error::from_str(403, "Forbidden"));
} }
helpers::check_comment(config, &query.comment, &mut errors); helpers::check_comment(config, locales, &client_langs, &query.comment, &mut errors);
let comment_id = if let Ok(comment_id) = CommentId::from_base64(&query.id) { let comment_id = if let Ok(comment_id) = CommentId::from_base64(&query.id) {
comment_id comment_id

View file

@ -48,7 +48,7 @@
</div> </div>
<form id="new_comment-form" action="#new_comment-form" method="post"> <form id="new_comment-form" action="#new_comment-form" method="post">
{% if new_comment_errors %} {% if new_comment_errors %}
<p>{{ tr(l=l,k="error-list")|safe }}</p> <p>{{ tr(l=l,k="error-list",nb_errors=new_comment_errors|length)|safe }}</p>
<ul id="new_comment-errors" class="errors"> <ul id="new_comment-errors" class="errors">
{% for error in new_comment_errors %} {% for error in new_comment_errors %}
<li class="error">{{ error | safe }}</li> <li class="error">{{ error | safe }}</li>
@ -66,7 +66,7 @@
{% if edit_comment %} {% if edit_comment %}
<form id="edit_comment-form" action="#edit_comment-form" method="post"> <form id="edit_comment-form" action="#edit_comment-form" method="post">
{% if edit_comment_errors %} {% if edit_comment_errors %}
<p>{{ tr(l=l,k="error-list")|safe }}</p> <p>{{ tr(l=l,k="error-list",nb_errors=edit_comment_errors|length)|safe }}</p>
<ul id="edit_comment-errors" class="errors"> <ul id="edit_comment-errors" class="errors">
{% for error in edit_comment_errors %} {% for error in edit_comment_errors %}
<li class="error">{{ error | safe }}</li> <li class="error">{{ error | safe }}</li>