i18n: localize the snotice/announce path — translate at deliver_server_notice chokepoint; rehash, connect/exit, oper-up, login, channel & ojoin notices via trf (fr, es)

This commit is contained in:
Jean Chevronnet 2026-08-25 13:04:31 +00:00
parent 6f8ff39f99
commit ef96bcbd06
No known key found for this signature in database
GPG key ID: 439666D63A9477E4
9 changed files with 93 additions and 31 deletions

View file

@ -10,6 +10,27 @@
"This server was created at unix {0}" = "Este servidor fue creado el (unix) {0}"
"There are {0} users on 1 server" = "Hay {0} usuarios en 1 servidor"
# --- rehash / configuración (avisos del servidor) ---
"Server configuration reloaded." = "Configuración del servidor recargada."
"admin {0} has changed the configuration of the server." = "el administrador {0} ha cambiado la configuración del servidor."
"{0} is rehashing the server config file." = "{0} está recargando el archivo de configuración del servidor."
"{0} tried to reload the server configuration, but the config file could not be read — no changes were made." = "{0} intentó recargar la configuración del servidor, pero no se pudo leer el archivo de configuración — no se hicieron cambios."
"Could not read {0} — the running configuration was kept." = "No se pudo leer {0} — se mantuvo la configuración en curso."
# --- avisos de operador: conexión / oper / canal (prosa dinámica) ---
"The server is rehashing its configuration." = "El servidor está recargando su configuración."
"Server configuration reloaded via RPC." = "Configuración del servidor recargada vía RPC."
"Client connecting: {0} ({1}@{2})" = "Conexión de cliente: {0} ({1}@{2})"
", port: {0}" = ", puerto: {0}"
", sni: {0}" = ", sni: {0}"
", account: {0}" = ", cuenta: {0}"
"Client exiting: {0} ({1})" = "Desconexión de cliente: {0} ({1})"
"{0} is now an IRC operator" = "{0} ahora es operador IRC"
"Client {0} is now logged in as {1}" = "El cliente {0} ahora ha iniciado sesión como {1}"
"{0} used oper override to join {1}" = "{0} usó anulación de oper para entrar a {1}"
"{0} created channel {1}" = "{0} creó el canal {1}"
"{0} used OJOIN to enter {1}" = "{0} usó OJOIN para entrar a {1}"
# --- avisos / desafíos ---
"*** Cloudflare Challenge: verification successful — you may continue." = "*** Desafío de Cloudflare: verificación exitosa — puedes continuar."
"*** Correct — you may now message freely; please resend your message." = "*** Correcto — ya puedes enviar mensajes libremente; por favor reenvía tu mensaje."

View file

@ -10,6 +10,27 @@
"This server was created at unix {0}" = "Ce serveur a été créé le (unix) {0}"
"There are {0} users on 1 server" = "Il y a {0} utilisateurs sur 1 serveur"
# --- rehash / configuration (notices serveur) ---
"Server configuration reloaded." = "Configuration du serveur rechargée."
"admin {0} has changed the configuration of the server." = "l'administrateur {0} a modifié la configuration du serveur."
"{0} is rehashing the server config file." = "{0} recharge le fichier de configuration du serveur."
"{0} tried to reload the server configuration, but the config file could not be read — no changes were made." = "{0} a tenté de recharger la configuration du serveur, mais le fichier de configuration n'a pas pu être lu — aucune modification n'a été effectuée."
"Could not read {0} — the running configuration was kept." = "Impossible de lire {0} — la configuration en cours a été conservée."
# --- notices opérateur : connexion / oper / salon (prose dynamique) ---
"The server is rehashing its configuration." = "Le serveur recharge sa configuration."
"Server configuration reloaded via RPC." = "Configuration du serveur rechargée via RPC."
"Client connecting: {0} ({1}@{2})" = "Connexion du client : {0} ({1}@{2})"
", port: {0}" = ", port : {0}"
", sni: {0}" = ", sni : {0}"
", account: {0}" = ", compte : {0}"
"Client exiting: {0} ({1})" = "Déconnexion du client : {0} ({1})"
"{0} is now an IRC operator" = "{0} est maintenant opérateur IRC"
"Client {0} is now logged in as {1}" = "Le client {0} est maintenant connecté en tant que {1}"
"{0} used oper override to join {1}" = "{0} a utilisé le contournement oper pour rejoindre {1}"
"{0} created channel {1}" = "{0} a créé le salon {1}"
"{0} used OJOIN to enter {1}" = "{0} a utilisé OJOIN pour entrer dans {1}"
# --- notices / défis ---
"*** Cloudflare Challenge: verification successful — you may continue." = "*** Défi Cloudflare : vérification réussie — vous pouvez continuer."
"*** Correct — you may now message freely; please resend your message." = "*** Correct — vous pouvez maintenant envoyer des messages librement ; veuillez renvoyer votre message."

View file

@ -43,7 +43,8 @@ impl Server {
// connected. A SASL-at-connect login runs before registration completes, so
// it's already reflected in the "Client connecting: … account: …" notice.
if registered {
self.snotice_c('c', &format!("Client {nick} is now logged in as {account}"));
let m = self.trf("Client {0} is now logged in as {1}", &[nick.as_str(), account]);
self.snotice_c('c', &m);
}
}

View file

@ -941,7 +941,8 @@ impl Server {
.get(&uid)
.map(|u| u.nick.clone())
.unwrap_or_default();
self.snotice_c('v', &format!("{nick} used oper override to join {name}"));
let m = self.trf("{0} used oper override to join {1}", &[nick.as_str(), name]);
self.snotice_c('v', &m);
}
let is_new = !self.channels.contains_key(&key);
let ch = self
@ -971,7 +972,8 @@ impl Server {
.get(&uid)
.map(|u| u.nick.clone())
.unwrap_or_default();
self.snotice_c('j', &format!("{who} created channel {name}"));
let m = self.trf("{0} created channel {1}", &[who.as_str(), name]);
self.snotice_c('j', &m);
}
// JOIN broadcast — extended-join clients also get the account + realname

View file

@ -48,27 +48,23 @@ impl Command for Rehash {
match Config::try_load(&path) {
Some(fresh) => {
// announce to everyone connected, not just opers
s.announce(&format!(
"admin {who} has changed the configuration of the server."
));
s.announce(&format!("{who} is rehashing the server config file."));
let m = s.trf("admin {0} has changed the configuration of the server.", &[who.as_str()]);
s.announce(&m);
let m = s.trf("{0} is rehashing the server config file.", &[who.as_str()]);
s.announce(&m);
s.apply_config(fresh);
s.announce("Server configuration reloaded.");
s.numeric(uid, RPL_REHASHING, &format!("{path} :Rehashing"));
}
None => {
// Unreadable config — keep what's running (do NOT reset to defaults).
s.announce(&format!(
"{who} tried to reload the server configuration, but the config file \
could not be read no changes were made."
));
s.send(
uid,
format!(
":{} NOTICE {who} :*** Could not read {path} — the running configuration was kept.",
s.name
),
let m = s.trf(
"{0} tried to reload the server configuration, but the config file could not be read — no changes were made.",
&[who.as_str()],
);
s.announce(&m);
let m = s.trf("Could not read {0} — the running configuration was kept.", &[path.as_str()]);
s.send(uid, format!(":{} NOTICE {who} :*** {m}", s.name));
}
}
CmdResult::Ok

View file

@ -49,7 +49,8 @@ impl Command for OjoinCmd {
if s.conf_bool("ojoin_op", true) {
crate::coremods::core_mode::svs_set_chan_modes(s, &chan, "+o", &[nick.clone()]);
}
s.snotice_c('v', &format!("{nick} used OJOIN to enter {chan}"));
let m = s.trf("{0} used OJOIN to enter {1}", &[nick.as_str(), chan.as_str()]);
s.snotice_c('v', &m);
CmdResult::Ok
}
}

View file

@ -14,22 +14,36 @@ impl Module for Snoop {
fn on_user_connect(&mut self, srv: &mut Server, uid: Uid) {
// `conf_bool`/`snotice_c` are `&self`, so we can hold the `&User` borrow and
// reference its fields directly instead of cloning them out.
let Some(u) = srv.users.get(&uid) else {
return;
let (nick, ident, host, port, sni, account) = {
let Some(u) = srv.users.get(&uid) else {
return;
};
(
u.nick.clone(),
u.ident.clone(),
u.host.clone(),
u.port,
u.sni.clone(),
u.account.clone(),
)
};
if srv.conf_bool("snoop_stderr", false) {
eprintln!("[snoop] connect {} ({}@{})", u.nick, u.ident, u.host);
eprintln!("[snoop] connect {nick} ({ident}@{host})");
}
// port is always shown; sni/account only when present, so plaintext or
// anonymous connects don't carry empty fields.
let mut extra = format!(", port: {}", u.port);
if let Some(sni) = &u.sni {
extra.push_str(&format!(", sni: {sni}"));
// port is always shown; sni/account only when present. Prose + field labels come
// from the locale catalog so a translated build reads naturally.
let mut msg = srv.trf(
"Client connecting: {0} ({1}@{2})",
&[nick.as_str(), ident.as_str(), host.as_str()],
);
let port_s = port.to_string();
msg.push_str(&srv.trf(", port: {0}", &[port_s.as_str()]));
if let Some(sni) = &sni {
msg.push_str(&srv.trf(", sni: {0}", &[sni.as_str()]));
}
if let Some(acct) = &u.account {
extra.push_str(&format!(", account: {acct}"));
if let Some(acct) = &account {
msg.push_str(&srv.trf(", account: {0}", &[acct.as_str()]));
}
let msg = format!("Client connecting: {} ({}@{}){extra}", u.nick, u.ident, u.host);
srv.snotice_c('c', &msg);
}
fn on_join(&mut self, srv: &mut Server, uid: Uid, chan: &str) {
@ -56,6 +70,7 @@ impl Module for Snoop {
if srv.conf_bool("snoop_stderr", false) {
eprintln!("[snoop] quit uid={uid} ({reason})");
}
srv.snotice_c('q', &format!("Client exiting: {nick} ({reason})"));
let m = srv.trf("Client exiting: {0} ({1})", &[nick.as_str(), reason]);
srv.snotice_c('q', &m);
}
}

View file

@ -1070,6 +1070,10 @@ impl Server {
return;
};
let nick = u.nick.clone();
// Localize the prose for the recipient; the log/chanlog/syslog tees keep the
// English source. Static snotice/announce text auto-translates here (like the
// numeric chokepoint); already-templated dynamic text passes through unchanged.
let msg = self.catalog.tr(msg);
let mut tags: Vec<String> = Vec::new();
if u.caps.server_time {
tags.push(format!("time={}", iso_time(now())));

View file

@ -331,7 +331,8 @@ impl Server {
.unwrap_or_default();
self.numeric(uid, RPL_YOUREOPER, ":You are now an IRC operator");
self.send(uid, format!(":{} MODE {nick} :+os", self.name));
self.snotice_c('o', &format!("{nick} is now an IRC operator"));
let m = self.trf("{0} is now an IRC operator", &[nick.as_str()]);
self.snotice_c('o', &m);
// operprefix: give this oper the ! prefix in every channel they're already in
crate::modules::operprefix::grant_all(self, uid);
// opermodes: extra umodes on oper-up