i18n: per-network locale (en/es/fr) for karma replies and the web board
All checks were successful
ci / check (push) Successful in 45s

This commit is contained in:
Jean Chevronnet 2026-07-30 00:31:17 +00:00
parent f290554325
commit 739fc8ad94
No known key found for this signature in database
GPG key ID: 439666D63A9477E4
11 changed files with 406 additions and 115 deletions

View file

@ -1,3 +1,4 @@
use rustbot::i18n::Locale;
use rustbot::karma_web::{parse_board, parse_events, render};
fn board_with_events(net: &str, store: &str, log: &str) -> rustbot::karma_web::Board {
@ -51,11 +52,8 @@ fn renders_hero_podium_and_scores() {
"libera",
r#"{"rust":{"n":5,"why":"clean PR","by":"alice"}}"#,
);
let html = render(&[b], 0);
assert!(
html.contains(">karma<"),
"wordmark missing: has no karma mark"
);
let html = render(&[b], 0, Locale::En);
assert!(html.contains(">karma<"), "wordmark missing");
assert!(html.contains("podium"), "no podium");
assert!(html.contains(">rust<"), "champion nick missing");
assert!(html.contains(">+5<"), "score missing");
@ -67,34 +65,42 @@ fn renders_activity_and_givers_from_events() {
let log = "{\"t\":100,\"o\":\"rust\",\"d\":1,\"by\":\"alice\",\"why\":\"clean PR\"}\n\
{\"t\":200,\"o\":\"docs\",\"d\":1,\"by\":\"alice\"}\n";
let b = board_with_events("libera", r#"{"rust":1,"docs":1}"#, log);
let html = render(&[b], 0);
let html = render(&[b], 0, Locale::En);
assert!(html.contains("recent activity"), "no activity section");
assert!(html.contains("top givers"), "no givers section");
assert!(html.contains("gave"), "no feed verb");
// alice made two gifts -> shown in givers panel
assert!(
html.contains("2 gifts"),
"giver count wrong: {}",
html.contains("gift")
);
assert!(
html.contains("data-t=\"200\""),
"feed sorted/newest-first missing"
);
assert!(html.contains("2 gifts"), "giver count wrong");
assert!(html.contains("data-t=\"200\""), "feed newest-first missing");
}
#[test]
fn empty_states_are_friendly() {
// no karma at all
let html = render(&[], 0);
let html = render(&[], 0, Locale::En);
assert!(html.contains("No karma yet"), "{html}");
// karma but no event history yet
let b = parse_board("libera", r#"{"romaka":2}"#);
let html = render(&[b], 0);
let html = render(&[b], 0, Locale::En);
assert!(html.contains("Nothing yet"), "empty activity state missing");
assert!(html.contains("Be the first"), "empty givers state missing");
}
#[test]
fn renders_spanish_chrome() {
let log = "{\"t\":100,\"o\":\"rust\",\"d\":1,\"by\":\"nadia\",\"why\":\"buen PR\"}\n";
let b = board_with_events("libera", r#"{"rust":1}"#, log);
let html = render(&[b], 0, Locale::Es);
assert!(html.contains("karma neto"), "es stat label missing");
assert!(
html.contains("actividad reciente"),
"es activity heading missing"
);
assert!(html.contains("top donantes"), "es givers heading missing");
assert!(html.contains("le dio a"), "es feed verb missing");
// relative-time config for the client is Spanish
assert!(html.contains("\"pre\":\"hace \""), "es time config missing");
// user content is never translated
assert!(html.contains("buen PR") && html.contains(">rust<"));
}
#[test]
fn escapes_untrusted_irc_input_everywhere() {
let log = "{\"t\":1,\"o\":\"<script>\",\"d\":1,\"by\":\"a&b\",\"why\":\"\\\"><img src=x>\"}\n";
@ -103,7 +109,7 @@ fn escapes_untrusted_irc_input_everywhere() {
r#"{"<script>":{"n":1,"why":"\"><img src=x>","by":"a&b"}}"#,
log,
);
let html = render(&[b], 0);
let html = render(&[b], 0, Locale::En);
assert!(!html.contains("<img"), "raw img tag leaked");
assert!(html.contains("&lt;script&gt;"), "nick not escaped");
assert!(html.contains("a&amp;b"), "giver not escaped");