Pluralize count-dependent messages with a CLDR one/other selector and gate catalog consistency with a test
All checks were successful
CI / check (push) Successful in 5m20s

This commit is contained in:
Jean Chevronnet 2026-07-20 02:03:05 +00:00
parent 74a58c5425
commit ecdead8278
No known key found for this signature in database
34 changed files with 572 additions and 186 deletions

View file

@ -520,6 +520,46 @@ macro_rules! t {
};
}
/// CLDR cardinal plural category. `one` vs `other` covers every language echo
/// ships: en/de/es (and es-ar)/pt use `one` only for n==1, while fr and pt-br
/// count 0 as singular too. A language with richer rules (Slavic `few`/`many`,
/// Arabic) would need a real rule table here — and, because the catalog is keyed
/// by the English text, English only offers one/other forms to key off, so such
/// a language can't gain extra categories without a different catalog shape.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Plural {
One,
Other,
}
/// Pick the plural category for `n` under `lang`'s rule.
pub fn plural_category(lang: &str, n: u64) -> Plural {
let is_one = match lang {
"fr" | "pt-br" => n == 0 || n == 1,
_ => n == 1,
};
if is_one {
Plural::One
} else {
Plural::Other
}
}
/// Localize a count-dependent reply. Selects the `one` or `other` English
/// template by the target language's plural rule, then renders it like [`t!`].
/// Both forms are message ids, so both need a catalog entry in each language.
/// `plural!(ctx, n, one = "…{n} entry…", other = "…{n} entries…", n = n, …)`.
#[macro_export]
macro_rules! plural {
($ctx:expr, $n:expr, one = $one:literal, other = $other:literal $(, $name:ident = $val:expr)* $(,)?) => {{
let __key = match $crate::plural_category($ctx.lang(), ($n) as u64) {
$crate::Plural::One => $one,
$crate::Plural::Other => $other,
};
$crate::render($ctx.lang(), __key, &[$((stringify!($name), format!("{}", $val))),*])
}};
}
/// The intent sink a service writes to. A service never mutates the network or
/// the store itself; it pushes normalized actions (via [`ServiceCtx::notice`]
/// and friends) that the engine drains and applies.
@ -2887,6 +2927,26 @@ mod help_tests {
assert_eq!(render("fr", "not translated", &[]), "not translated");
}
#[test]
fn plural_rules_match_cldr() {
use Plural::{One, Other};
// Most languages: singular only for exactly 1.
for lang in ["en", "de", "es", "es-ar", "pt"] {
assert_eq!(plural_category(lang, 1), One, "{lang} 1");
assert_eq!(plural_category(lang, 0), Other, "{lang} 0");
assert_eq!(plural_category(lang, 2), Other, "{lang} 2");
}
// French and Brazilian Portuguese count 0 as singular.
for lang in ["fr", "pt-br"] {
assert_eq!(plural_category(lang, 0), One, "{lang} 0");
assert_eq!(plural_category(lang, 1), One, "{lang} 1");
assert_eq!(plural_category(lang, 2), Other, "{lang} 2");
}
// Unknown language falls back to the n==1 rule.
assert_eq!(plural_category("xx", 1), One);
assert_eq!(plural_category("xx", 5), Other);
}
#[test]
fn valid_email_rejects_header_injection() {
assert!(valid_email("alice@example.com"));

View file

@ -61,7 +61,6 @@
"\u0002{chan}\u0002 isn't suspended.": "\u0002{chan}\u0002 ist nicht gesperrt.",
"\u0002{chan}\u0002 was already set that way.": "\u0002{chan}\u0002 war bereits so eingestellt.",
"\u0002{chan}\u0002 will no longer expire.": "\u0002{chan}\u0002 wird nicht mehr ablaufen.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line(s) seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 Zeile(n) gesehen.",
"\u0002{code}\u0002 isn't an available language. Available: {list}.": "\u0002{code}\u0002 ist keine verfügbare Sprache. Verfügbar: {list}.",
"\u0002{d}\u0002 isn't a valid expiry — try 30d, 12h, 45m, or 0.": "\u0002{d}\u0002 ist kein gültiges Ablaufdatum — versuche 30d, 12h, 45m oder 0.",
"\u0002{host}\u0002 is already in use. Please choose another.": "\u0002{host}\u0002 wird bereits verwendet. Bitte wähle einen anderen.",
@ -69,7 +68,6 @@
"\u0002{host}\u0002 isn't a valid host (letters, digits, hyphens and dots).": "\u0002{host}\u0002 ist kein gültiger Host (Buchstaben, Ziffern, Bindestriche und Punkte).",
"\u0002{host}\u0002 isn't a valid host.": "\u0002{host}\u0002 ist kein gültiger Host.",
"\u0002{host}\u0002 isn't allowed here. Please choose another.": "\u0002{host}\u0002 ist hier nicht erlaubt. Bitte wähle einen anderen.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session(s).": "\u0002{ip}\u0002 hat \u0002{count}\u0002 aktive Sitzung(en).",
"\u0002{label}\u0002 access on \u0002{chan}\u0002: \u0002{level}\u0002": "\u0002{label}\u0002-Zugriff auf \u0002{chan}\u0002: \u0002{level}\u0002",
"\u0002{mask}\u0002 isn't on \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 steht nicht auf der Auto-Kick-Liste von \u0002{chan}\u0002.",
"\u0002{mask}\u0002 isn't on the ignore list.": "\u0002{mask}\u0002 steht nicht auf der Ignore-Liste.",
@ -88,7 +86,6 @@
"\u0002{nick}\u0002 isn't grouped to your account.": "\u0002{nick}\u0002 ist nicht zu deinem Konto gruppiert.",
"\u0002{nick}\u0002 isn't here.": "\u0002{nick}\u0002 ist nicht hier.",
"\u0002{nick}\u0002 was last seen {when} ({what}).": "\u0002{nick}\u0002 wurde zuletzt {when} gesehen ({what}).",
"\u0002{n}\u0002 vote(s) will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 Stimme(n) lösen jetzt einen \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002 aus.",
"\u0002{pattern}\u0002 isn't a valid regular expression.": "\u0002{pattern}\u0002 ist kein gültiger regulärer Ausdruck.",
"\u0002{raw}\u0002 isn't a valid \u0002{target}\u0002 mask.": "\u0002{raw}\u0002 ist keine gültige \u0002{target}\u0002-Maske.",
"\u0002{target}\u0002 had no access to \u0002{chan}\u0002.": "\u0002{target}\u0002 hatte keinen Zugriff auf \u0002{chan}\u0002.",
@ -143,7 +140,6 @@
" (custom)": " (eigen)",
" (no activity counters yet)": " (noch keine Aktivitätszähler)",
" About : \u0002{target}\u0002": " Über : \u0002{target}\u0002",
" Auto-join : {count} channel(s) — see \u0002AJOIN LIST\u0002": " Auto-Join : {count} Kanal/Kanäle — siehe \u0002AJOIN LIST\u0002",
" By : \u0002{by}\u0002": " Von : \u0002{by}\u0002",
" Description: {desc}": " Beschreibung: {desc}",
" Email : (none set)": " E-Mail : (keine gesetzt)",
@ -165,7 +161,6 @@
" Real name: {gecos}": " Echter Name: {gecos}",
" Reason : {reason}": " Grund : {reason}",
" Registered : {when}": " Registriert : {when}",
" Serving {count} channel(s): {list}": " Bedient {count} Kanal/Kanäle: {list}",
" Staff note : {note}": " Team-Notiz : {note}",
" Suspended : by \u0002{by}\u0002 — {reason}": " Gesperrt : von \u0002{by}\u0002 — {reason}",
" URL : {url}": " URL : {url}",
@ -278,7 +273,6 @@
"Both channels must be registered.": "Beide Kanäle müssen registriert sein.",
"Bots ({count}):": "Bots ({count}):",
"CALC and show each die": "CALC und jeden Würfel anzeigen",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILL'd.": "CHANKILL auf \u0002{chan}\u0002: \u0002{banned}\u0002 Host(s) mit AKILL belegt.",
"Can't activate: \u0002{host}\u0002 is on the forbidden list.": "Kann nicht aktivieren: \u0002{host}\u0002 steht auf der Verbotsliste.",
"Can't activate: {msg}": "Kann nicht aktivieren: {msg}",
"Challenge \u0002#{id}\u0002 ({game}) sent to \u0002{target}\u0002.": "Herausforderung \u0002#{id}\u0002 ({game}) an \u0002{target}\u0002 gesendet.",
@ -291,10 +285,6 @@
"Channels released: {list}.": "Freigegebene Kanäle: {list}.",
"Channels you have access on ({count}):": "Kanäle, auf die du Zugriff hast ({count}):",
"Classement \u0002{game}\u0002 vide. Sois le premier à gagner !": "Rangliste \u0002{game}\u0002 leer. Sei der Erste, der gewinnt!",
"Cleared \u0002{count}\u0002 entr{suffix} from \u0002{chan}\u0002's auto-kick list.": "\u0002{count}\u0002 Eintr{suffix} aus der Auto-Kick-Liste von \u0002{chan}\u0002 gelöscht.",
"Cleared \u0002{n}\u0002 badword pattern(s) from \u0002{chan}\u0002.": "\u0002{n}\u0002 Badword-Muster aus \u0002{chan}\u0002 gelöscht.",
"Cleared \u0002{n}\u0002 notify watch(es).": "\u0002{n}\u0002 Notify-Überwachung(en) gelöscht.",
"Cleared \u0002{n}\u0002 trigger(s) from \u0002{chan}\u0002.": "\u0002{n}\u0002 Trigger aus \u0002{chan}\u0002 gelöscht.",
"Cleared \u0002{target}\u0002's access to \u0002{chan}\u0002.": "Zugriff von \u0002{target}\u0002 auf \u0002{chan}\u0002 gelöscht.",
"Cleared the *!*@{host} ban on \u0002{chan}\u0002.": "Den *!*@{host}-Ban auf \u0002{chan}\u0002 entfernt.",
"Contact email for \u0002{chan}\u0002 cleared.": "Kontakt-E-Mail für \u0002{chan}\u0002 gelöscht.",
@ -306,22 +296,17 @@
"Couldn't update \u0002{chan}\u0002 — please try again in a moment.": "\u0002{chan}\u0002 konnte nicht aktualisiert werden — bitte versuche es gleich noch einmal.",
"DEFCON set to \u0002{level}\u0002 — {desc}.": "DEFCON auf \u0002{level}\u0002 gesetzt — {desc}.",
"Declined.": "Abgelehnt.",
"Deleted all \u0002{count}\u0002 memo(s).": "Alle \u0002{count}\u0002 Memo(s) gelöscht.",
"Description for \u0002{chan}\u0002 updated.": "Beschreibung für \u0002{chan}\u0002 aktualisiert.",
"DiceServ rolls dice and evaluates maths for tabletop games. Dice: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, and \u00023~2d6\u0002 to repeat.": "DiceServ würfelt und wertet Mathe für Tabletop-Spiele aus. Würfel: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Auch + - * / ^ %, Klammern, Funktionen (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002 und \u00023~2d6\u0002 zum Wiederholen.",
"DictServ looks words up in the dict.org dictionaries. Try \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, and more — \u0002LOOKUP\u0002 lists them all.": "DictServ schlägt Wörter in den dict.org-Wörterbüchern nach. Versuche \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (Thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002 und mehr — \u0002LOOKUP\u0002 listet sie alle auf.",
"Email for \u0002{account}\u0002 cleared.": "E-Mail für \u0002{account}\u0002 gelöscht.",
"Email for \u0002{account}\u0002 updated.": "E-Mail für \u0002{account}\u0002 aktualisiert.",
"End of exception list ({count} shown).": "Ende der Ausnahmeliste ({count} angezeigt).",
"End of flags ({count} entr{suffix}).": "Ende der Flags ({count} Eintr{suffix}).",
"End of ignore list ({count} shown).": "Ende der Ignore-Liste ({count} angezeigt).",
"End of jupe list ({count} shown).": "Ende der Jupe-Liste ({count} angezeigt).",
"End of list ({count} group(s)).": "Ende der Liste ({count} Gruppe(n)).",
"End of list — {count} match(es){more}.": "Ende der Liste — {count} Treffer{more}.",
"End of notify list ({shown} shown).": "Ende der Notify-Liste ({shown} angezeigt).",
"End of results ({count} shown, newest first — refine the search to narrow).": "Ende der Ergebnisse ({count} angezeigt, neueste zuerst — verfeinere die Suche zum Eingrenzen).",
"End of runtime operator list ({count} shown).": "Ende der Laufzeit-Operator-Liste ({count} angezeigt).",
"End of session list ({count} IP(s)).": "Ende der Sitzungsliste ({count} IP(s)).",
"End of spam-filter list ({shown} shown).": "Ende der Spam-Filter-Liste ({shown} angezeigt).",
"End of {name} list ({shown} shown).": "Ende der {name}-Liste ({shown} angezeigt).",
"End of {which} bulletins ({count} shown).": "Ende der {which}-Bulletins ({count} angezeigt).",
@ -387,8 +372,6 @@
"Mask must be a \u0002#channel\u0002, a \u0002nick!user@host\u0002 pattern, or a bare nick glob — and no spaces.": "Maske muss ein \u0002#channel\u0002, ein \u0002nick!user@host\u0002-Muster oder ein reiner Nick-Glob sein — und keine Leerzeichen.",
"Memo #\u0002{num}\u0002 from \u0002{from}\u0002 ({when}):": "Memo #\u0002{num}\u0002 von \u0002{from}\u0002 ({when}):",
"Memo #\u0002{n}\u0002 deleted.": "Memo #\u0002{n}\u0002 gelöscht.",
"Memo sent to \u0002{sent}\u0002 account(s).": "Memo an \u0002{sent}\u0002 Konto/Konten gesendet.",
"Memo sent to \u0002{sent}\u0002 operator(s).": "Memo an \u0002{sent}\u0002 Operator(en) gesendet.",
"Memo sent to \u0002{target}\u0002.": "Memo an \u0002{target}\u0002 gesendet.",
"MemoServ delivers messages to registered users, online or not. You must be identified to use it.": "MemoServ stellt Nachrichten an registrierte Nutzer zu, ob online oder nicht. Du musst identifiziert sein, um es zu nutzen.",
"Mode lock for \u0002{chan}\u0002 updated.": "Mode-Lock für \u0002{chan}\u0002 aktualisiert.",
@ -485,12 +468,10 @@
"Removed \u0002{mask}\u0002 from \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 wurde von der Auto-Kick-Liste von \u0002{chan}\u0002 entfernt.",
"Removed \u0002{target}\u0002 from \u0002{name}\u0002.": "\u0002{target}\u0002 wurde aus \u0002{name}\u0002 entfernt.",
"Removed \u0002{which}\u0002 bulletin \u0002{n}\u0002.": "\u0002{which}\u0002-Bulletin \u0002{n}\u0002 wurde entfernt.",
"Removed all \u0002{n}\u0002 bot(s).": "Alle \u0002{n}\u0002 Bot(s) wurden entfernt.",
"Removed badword pattern from \u0002{chan}\u0002.": "Schimpfwort-Muster wurde aus \u0002{chan}\u0002 entfernt.",
"Removed fingerprint \u0002{fp}\u0002.": "Fingerprint \u0002{fp}\u0002 wurde entfernt.",
"Removed forbidden pattern: {pattern}": "Verbotenes Muster entfernt: {pattern}",
"Removed the forbid on {label} \u0002{mask}\u0002.": "Das Verbot für {label} \u0002{mask}\u0002 wurde entfernt.",
"Reopped \u0002{opped}\u0002 trusted regular(s) in \u0002{chan}\u0002.": "\u0002{opped}\u0002 vertraute(r) Stammgast/Stammgäste in \u0002{chan}\u0002 wurde(n) wieder geoppt.",
"Report \u0002#{id}\u0002 ({state}):": "Meldung \u0002#{id}\u0002 ({state}):",
"Report \u0002#{n}\u0002 closed.": "Meldung \u0002#{n}\u0002 geschlossen.",
"Report \u0002#{n}\u0002 deleted.": "Meldung \u0002#{n}\u0002 gelöscht.",
@ -881,7 +862,6 @@
"The bot has left \u0002{chan}\u0002.": "Der Bot hat \u0002{chan}\u0002 verlassen.",
"The bot may again kick channel operators in \u0002{chan}\u0002.": "Der Bot darf in \u0002{chan}\u0002 wieder Channel-Operatoren kicken.",
"The bot may again kick voiced users in \u0002{chan}\u0002.": "Der Bot darf in \u0002{chan}\u0002 wieder Nutzer mit Voice kicken.",
"The bot will ban a user after \u0002{n}\u0002 kick(s) in \u0002{chan}\u0002.": "Der Bot bannt einen Nutzer nach \u0002{n}\u0002 Kick(s) in \u0002{chan}\u0002.",
"The bot will kick without warning in \u0002{chan}\u0002.": "Der Bot kickt in \u0002{chan}\u0002 ohne Warnung.",
"The bot will no longer kick channel operators in \u0002{chan}\u0002.": "Der Bot kickt in \u0002{chan}\u0002 keine Channel-Operatoren mehr.",
"The bot will no longer kick voiced users in \u0002{chan}\u0002.": "Der Bot kickt in \u0002{chan}\u0002 keine Nutzer mit Voice mehr.",
@ -927,7 +907,6 @@
"Ticket \u0002#{id}\u0002 isn't open (or doesn't exist).": "Ticket \u0002#{id}\u0002 ist nicht offen (oder existiert nicht).",
"Too many failed attempts. Please wait {secs}s and try again.": "Zu viele fehlgeschlagene Versuche. Bitte warte {secs}s und versuche es erneut.",
"Top talkers:": "Aktivste Sprecher:",
"Top {shown} of {total} scored identit{suffix} for \u0002{chan}\u0002.": "Top {shown} von {total} bewerteten Identit{suffix} für \u0002{chan}\u0002.",
"Topic for \u0002{chan}\u0002 updated.": "Thema für \u0002{chan}\u0002 aktualisiert.",
"Trigger #\u0002{n}\u0002 removed from \u0002{chan}\u0002.": "Trigger #\u0002{n}\u0002 aus \u0002{chan}\u0002 entfernt.",
"Triggers for \u0002{chan}\u0002 ({count}):": "Trigger für \u0002{chan}\u0002 ({count}):",
@ -958,8 +937,6 @@
"You can't ungroup your main account name.": "Du kannst deinen Hauptkontonamen nicht aus der Gruppe lösen.",
"You cannot challenge yourself.": "Du kannst dich nicht selbst herausfordern.",
"You don't have an account to confirm.": "Du hast kein Konto zum Bestätigen.",
"You have \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Du hast \u0002{total}\u0002 Memo(s), \u0002{unread}\u0002 ungelesen, von maximal \u0002{max}\u0002.",
"You have \u0002{unread}\u0002 new memo(s). Read them with \u0002/msg MemoServ READ NEW\u0002.": "Du hast \u0002{unread}\u0002 neue Memo(s). Lies sie mit \u0002/msg MemoServ READ NEW\u0002.",
"You have access on no channels.": "Du hast auf keinen Channels Zugriff.",
"You have no games. Use \u0002CHALLENGE <nick> <game>\u0002.": "Du hast keine Spiele. Verwende \u0002CHALLENGE <nick> <game>\u0002.",
"You have no memo #\u0002{n}\u0002.": "Du hast kein Memo #\u0002{n}\u0002.",
@ -1258,7 +1235,6 @@
"your mailbox summary": "deine Postfach-Übersicht",
"your memo preferences": "deine Memo-Einstellungen",
"{challenger} challenges you to {game} (game #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002": "{challenger} fordert dich zu {game} heraus (Spiel #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002",
"{count} ticket(s). \u0002VIEW\u0002 <id> for detail.": "{count} Ticket(s). \u0002VIEW\u0002 <id> für Details.",
"{name} added for \u0002{mask}\u0002 (temporary).": "{name} für \u0002{mask}\u0002 hinzugefügt (temporär).",
"{name} added for \u0002{mask}\u0002.": "{name} für \u0002{mask}\u0002 hinzugefügt.",
"{name} for \u0002{mask}\u0002 removed.": "{name} für \u0002{mask}\u0002 entfernt.",
@ -1266,7 +1242,6 @@
"{name} updated for \u0002{mask}\u0002.": "{name} für \u0002{mask}\u0002 aktualisiert.",
"{nick} declined your challenge #{id}.": "{nick} hat deine Herausforderung #{id} abgelehnt.",
"{num}. {text} — by {by}": "{num}. {text} — von {by}",
"{n} report(s). \u0002VIEW\u0002 <id> for detail.": "{n} Meldung(en). \u0002VIEW\u0002 <id> für Details.",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}) — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] von {setter} ({when}) — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}), expires in {ttl} — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] von {setter} ({when}), läuft ab in {ttl} — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] — {reason}",
@ -1283,5 +1258,55 @@
"{who}: I have no record of \u0002{nick}\u0002 talking in \u0002{chan}\u0002.": "{who}: Ich habe keine Aufzeichnung, dass \u0002{nick}\u0002 in \u0002{chan}\u0002 gesprochen hat.",
"{word} list for \u0002{name}\u0002:": "{word}-Liste für \u0002{name}\u0002:",
"Type \u0002HELP <command>\u0002 for detail on one command.": "Tippe \u0002HELP <command>\u0002 für Details zu einem Befehl.",
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Keine Hilfe für \u0002{t}\u0002. Tippe \u0002HELP\u0002 für die Befehlsliste."
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Keine Hilfe für \u0002{t}\u0002. Tippe \u0002HELP\u0002 für die Befehlsliste.",
"Reopped \u0002{opped}\u0002 trusted regular in \u0002{chan}\u0002.": "\u0002{opped}\u0002 als vertrauten Stammgast in \u0002{chan}\u0002 wieder geoppt.",
"Reopped \u0002{opped}\u0002 trusted regulars in \u0002{chan}\u0002.": "\u0002{opped}\u0002 vertraute Stammgäste in \u0002{chan}\u0002 wieder geoppt.",
"Cleared \u0002{n}\u0002 trigger from \u0002{chan}\u0002.": "\u0002{n}\u0002 Trigger aus \u0002{chan}\u0002 entfernt.",
"Cleared \u0002{n}\u0002 triggers from \u0002{chan}\u0002.": "\u0002{n}\u0002 Trigger aus \u0002{chan}\u0002 entfernt.",
" Serving {count} channel: {list}": " Bediene {count} Channel: {list}",
" Serving {count} channels: {list}": " Bediene {count} Channels: {list}",
"Removed all \u0002{n}\u0002 bot.": "Alle \u0002{n}\u0002 Bot entfernt.",
"Removed all \u0002{n}\u0002 bots.": "Alle \u0002{n}\u0002 Bots entfernt.",
"Cleared \u0002{n}\u0002 badword pattern from \u0002{chan}\u0002.": "\u0002{n}\u0002 Badword-Muster aus \u0002{chan}\u0002 entfernt.",
"Cleared \u0002{n}\u0002 badword patterns from \u0002{chan}\u0002.": "\u0002{n}\u0002 Badword-Muster aus \u0002{chan}\u0002 entfernt.",
"The bot will ban a user after \u0002{n}\u0002 kick in \u0002{chan}\u0002.": "Der Bot bannt einen Benutzer nach \u0002{n}\u0002 Kick in \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kicks in \u0002{chan}\u0002.": "Der Bot bannt einen Benutzer nach \u0002{n}\u0002 Kicks in \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entry from \u0002{chan}\u0002's auto-kick list.": "\u0002{count}\u0002 Eintrag aus der Auto-Kick-Liste von \u0002{chan}\u0002 entfernt.",
"Cleared \u0002{count}\u0002 entries from \u0002{chan}\u0002's auto-kick list.": "\u0002{count}\u0002 Einträge aus der Auto-Kick-Liste von \u0002{chan}\u0002 entfernt.",
"Top {shown} of {total} scored identity for \u0002{chan}\u0002.": "Top {shown} von {total} bewerteter Identität für \u0002{chan}\u0002.",
"Top {shown} of {total} scored identities for \u0002{chan}\u0002.": "Top {shown} von {total} bewerteten Identitäten für \u0002{chan}\u0002.",
"\u0002{n}\u0002 vote will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 Stimme trägt in \u0002{chan}\u0002 künftig einen \u0002!votekick\u0002/\u0002!voteban\u0002.",
"\u0002{n}\u0002 votes will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 Stimmen tragen in \u0002{chan}\u0002 künftig einen \u0002!votekick\u0002/\u0002!voteban\u0002.",
"End of flags ({count} entry).": "Ende der Flags ({count} Eintrag).",
"End of flags ({count} entries).": "Ende der Flags ({count} Einträge).",
"Deleted all \u0002{count}\u0002 memo.": "Alle \u0002{count}\u0002 Memo gelöscht.",
"Deleted all \u0002{count}\u0002 memos.": "Alle \u0002{count}\u0002 Memos gelöscht.",
"Memo sent to \u0002{sent}\u0002 account.": "Memo an \u0002{sent}\u0002 Account gesendet.",
"Memo sent to \u0002{sent}\u0002 accounts.": "Memo an \u0002{sent}\u0002 Accounts gesendet.",
"End of session list ({count} IP).": "Ende der Sitzungsliste ({count} IP).",
"End of session list ({count} IPs).": "Ende der Sitzungsliste ({count} IPs).",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session.": "\u0002{ip}\u0002 hat \u0002{count}\u0002 aktive Sitzung.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live sessions.": "\u0002{ip}\u0002 hat \u0002{count}\u0002 aktive Sitzungen.",
"You have \u0002{total}\u0002 memo, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Du hast \u0002{total}\u0002 Memo, \u0002{unread}\u0002 ungelesen, von maximal \u0002{max}\u0002.",
"You have \u0002{total}\u0002 memos, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Du hast \u0002{total}\u0002 Memos, \u0002{unread}\u0002 ungelesen, von maximal \u0002{max}\u0002.",
"End of list — {count} match{more}.": "Ende der Liste — {count} Treffer{more}.",
"End of list — {count} matches{more}.": "Ende der Liste — {count} Treffer{more}.",
"Memo sent to \u0002{sent}\u0002 operator.": "Memo an \u0002{sent}\u0002 Operator gesendet.",
"Memo sent to \u0002{sent}\u0002 operators.": "Memo an \u0002{sent}\u0002 Operatoren gesendet.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host AKILL'd.": "CHANKILL auf \u0002{chan}\u0002: \u0002{banned}\u0002 Host per AKILL gesperrt.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 hosts AKILL'd.": "CHANKILL auf \u0002{chan}\u0002: \u0002{banned}\u0002 Hosts per AKILL gesperrt.",
" Auto-join : {count} channel — see \u0002AJOIN LIST\u0002": " Auto-Join : {count} Channel — siehe \u0002AJOIN LIST\u0002",
" Auto-join : {count} channels — see \u0002AJOIN LIST\u0002": " Auto-Join : {count} Channels — siehe \u0002AJOIN LIST\u0002",
"{count} ticket. \u0002VIEW\u0002 <id> for detail.": "{count} Ticket. \u0002VIEW\u0002 <id> für Details.",
"{count} tickets. \u0002VIEW\u0002 <id> for detail.": "{count} Tickets. \u0002VIEW\u0002 <id> für Details.",
"You have \u0002{unread}\u0002 new memo. Read it with \u0002/msg MemoServ READ NEW\u0002.": "Du hast \u0002{unread}\u0002 neues Memo. Lies es mit \u0002/msg MemoServ READ NEW\u0002.",
"You have \u0002{unread}\u0002 new memos. Read them with \u0002/msg MemoServ READ NEW\u0002.": "Du hast \u0002{unread}\u0002 neue Memos. Lies sie mit \u0002/msg MemoServ READ NEW\u0002.",
"Cleared \u0002{n}\u0002 notify watch.": "\u0002{n}\u0002 Notify-Beobachtung entfernt.",
"Cleared \u0002{n}\u0002 notify watches.": "\u0002{n}\u0002 Notify-Beobachtungen entfernt.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 Zeile gesehen.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 lines seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 Zeilen gesehen.",
"{n} report. \u0002VIEW\u0002 <id> for detail.": "{n} Meldung. \u0002VIEW\u0002 <id> für Details.",
"{n} reports. \u0002VIEW\u0002 <id> for detail.": "{n} Meldungen. \u0002VIEW\u0002 <id> für Details.",
"End of list ({count} group).": "Ende der Liste ({count} Gruppe).",
"End of list ({count} groups).": "Ende der Liste ({count} Gruppen)."
}

View file

@ -61,7 +61,6 @@
"\u0002{chan}\u0002 isn't suspended.": "\u0002{chan}\u0002 no está suspendido.",
"\u0002{chan}\u0002 was already set that way.": "\u0002{chan}\u0002 ya estaba configurado así.",
"\u0002{chan}\u0002 will no longer expire.": "\u0002{chan}\u0002 ya no va a expirar.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line(s) seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 línea(s) vistas.",
"\u0002{code}\u0002 isn't an available language. Available: {list}.": "\u0002{code}\u0002 no es un idioma disponible. Disponibles: {list}.",
"\u0002{d}\u0002 isn't a valid expiry — try 30d, 12h, 45m, or 0.": "\u0002{d}\u0002 no es un vencimiento válido — probá 30d, 12h, 45m, o 0.",
"\u0002{host}\u0002 is already in use. Please choose another.": "\u0002{host}\u0002 ya está en uso. Elegí otro.",
@ -69,7 +68,6 @@
"\u0002{host}\u0002 isn't a valid host (letters, digits, hyphens and dots).": "\u0002{host}\u0002 no es un host válido (letras, dígitos, guiones y puntos).",
"\u0002{host}\u0002 isn't a valid host.": "\u0002{host}\u0002 no es un host válido.",
"\u0002{host}\u0002 isn't allowed here. Please choose another.": "\u0002{host}\u0002 no está permitido acá. Elegí otro.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session(s).": "\u0002{ip}\u0002 tiene \u0002{count}\u0002 sesión(es) activas.",
"\u0002{label}\u0002 access on \u0002{chan}\u0002: \u0002{level}\u0002": "Acceso de \u0002{label}\u0002 en \u0002{chan}\u0002: \u0002{level}\u0002",
"\u0002{mask}\u0002 isn't on \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 no está en la lista de auto-kick de \u0002{chan}\u0002.",
"\u0002{mask}\u0002 isn't on the ignore list.": "\u0002{mask}\u0002 no está en la lista de ignorados.",
@ -88,7 +86,6 @@
"\u0002{nick}\u0002 isn't grouped to your account.": "\u0002{nick}\u0002 no está agrupado a tu cuenta.",
"\u0002{nick}\u0002 isn't here.": "\u0002{nick}\u0002 no está acá.",
"\u0002{nick}\u0002 was last seen {when} ({what}).": "\u0002{nick}\u0002 se vio por última vez {when} ({what}).",
"\u0002{n}\u0002 vote(s) will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto(s) ahora van a concretar un \u0002!votekick\u0002/\u0002!voteban\u0002 en \u0002{chan}\u0002.",
"\u0002{pattern}\u0002 isn't a valid regular expression.": "\u0002{pattern}\u0002 no es una expresión regular válida.",
"\u0002{raw}\u0002 isn't a valid \u0002{target}\u0002 mask.": "\u0002{raw}\u0002 no es una máscara \u0002{target}\u0002 válida.",
"\u0002{target}\u0002 had no access to \u0002{chan}\u0002.": "\u0002{target}\u0002 no tenía acceso a \u0002{chan}\u0002.",
@ -143,7 +140,6 @@
" (custom)": " (personalizado)",
" (no activity counters yet)": " (todavía no hay contadores de actividad)",
" About : \u0002{target}\u0002": " Sobre : \u0002{target}\u0002",
" Auto-join : {count} channel(s) — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canal(es) — mirá \u0002AJOIN LIST\u0002",
" By : \u0002{by}\u0002": " Por : \u0002{by}\u0002",
" Description: {desc}": " Descripción: {desc}",
" Email : (none set)": " Email : (ninguno)",
@ -165,7 +161,6 @@
" Real name: {gecos}": " Nombre real: {gecos}",
" Reason : {reason}": " Motivo : {reason}",
" Registered : {when}": " Registrado : {when}",
" Serving {count} channel(s): {list}": " Atendiendo {count} canal(es): {list}",
" Staff note : {note}": " Nota del staff: {note}",
" Suspended : by \u0002{by}\u0002 — {reason}": " Suspendido : por \u0002{by}\u0002 — {reason}",
" URL : {url}": " URL : {url}",
@ -278,7 +273,6 @@
"Both channels must be registered.": "Los dos canales tienen que estar registrados.",
"Bots ({count}):": "Bots ({count}):",
"CALC and show each die": "CALC y mostrar cada dado",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILL'd.": "CHANKILL en \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILLeados.",
"Can't activate: \u0002{host}\u0002 is on the forbidden list.": "No se puede activar: \u0002{host}\u0002 está en la lista de prohibidos.",
"Can't activate: {msg}": "No se puede activar: {msg}",
"Challenge \u0002#{id}\u0002 ({game}) sent to \u0002{target}\u0002.": "Desafío \u0002#{id}\u0002 ({game}) enviado a \u0002{target}\u0002.",
@ -291,10 +285,6 @@
"Channels released: {list}.": "Canales liberados: {list}.",
"Channels you have access on ({count}):": "Canales en los que tenés acceso ({count}):",
"Classement \u0002{game}\u0002 vide. Sois le premier à gagner !": "Ranking de \u0002{game}\u0002 vacío. ¡Sé el primero en ganar!",
"Cleared \u0002{count}\u0002 entr{suffix} from \u0002{chan}\u0002's auto-kick list.": "Se borraron \u0002{count}\u0002 entrada{suffix} de la lista de auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword pattern(s) from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 patrón(es) de badword de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 notify watch(es).": "Se borraron \u0002{n}\u0002 vigilancia(s) de notify.",
"Cleared \u0002{n}\u0002 trigger(s) from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 trigger(s) de \u0002{chan}\u0002.",
"Cleared \u0002{target}\u0002's access to \u0002{chan}\u0002.": "Se borró el acceso de \u0002{target}\u0002 a \u0002{chan}\u0002.",
"Cleared the *!*@{host} ban on \u0002{chan}\u0002.": "Se sacó el ban *!*@{host} en \u0002{chan}\u0002.",
"Contact email for \u0002{chan}\u0002 cleared.": "Se borró el email de contacto de \u0002{chan}\u0002.",
@ -306,22 +296,17 @@
"Couldn't update \u0002{chan}\u0002 — please try again in a moment.": "No se pudo actualizar \u0002{chan}\u0002 — probá de nuevo en un momento.",
"DEFCON set to \u0002{level}\u0002 — {desc}.": "DEFCON configurado en \u0002{level}\u0002 — {desc}.",
"Declined.": "Rechazado.",
"Deleted all \u0002{count}\u0002 memo(s).": "Se borraron todos los \u0002{count}\u0002 memo(s).",
"Description for \u0002{chan}\u0002 updated.": "Se actualizó la descripción de \u0002{chan}\u0002.",
"DiceServ rolls dice and evaluates maths for tabletop games. Dice: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, and \u00023~2d6\u0002 to repeat.": "DiceServ tira dados y evalúa cuentas matemáticas para juegos de mesa. Dados: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. También + - * / ^ %, paréntesis, funciones (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, y \u00023~2d6\u0002 para repetir.",
"DictServ looks words up in the dict.org dictionaries. Try \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, and more — \u0002LOOKUP\u0002 lists them all.": "DictServ busca palabras en los diccionarios de dict.org. Probá \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (tesauro), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, y más — \u0002LOOKUP\u0002 los lista todos.",
"Email for \u0002{account}\u0002 cleared.": "Se borró el email de \u0002{account}\u0002.",
"Email for \u0002{account}\u0002 updated.": "Se actualizó el email de \u0002{account}\u0002.",
"End of exception list ({count} shown).": "Fin de la lista de excepciones ({count} mostradas).",
"End of flags ({count} entr{suffix}).": "Fin de los flags ({count} entrada{suffix}).",
"End of ignore list ({count} shown).": "Fin de la lista de ignorados ({count} mostrados).",
"End of jupe list ({count} shown).": "Fin de la lista de jupes ({count} mostrados).",
"End of list ({count} group(s)).": "Fin de la lista ({count} grupo(s)).",
"End of list — {count} match(es){more}.": "Fin de la lista — {count} coincidencia(s){more}.",
"End of notify list ({shown} shown).": "Fin de la lista de notify ({shown} mostrados).",
"End of results ({count} shown, newest first — refine the search to narrow).": "Fin de los resultados ({count} mostrados, más nuevos primero — refiná la búsqueda para acotar).",
"End of runtime operator list ({count} shown).": "Fin de la lista de operadores de runtime ({count} mostrados).",
"End of session list ({count} IP(s)).": "Fin de la lista de sesiones ({count} IP(s)).",
"End of spam-filter list ({shown} shown).": "Fin de la lista de spam-filter ({shown} mostrados).",
"End of {name} list ({shown} shown).": "Fin de la lista de {name} ({shown} mostrados).",
"End of {which} bulletins ({count} shown).": "Fin de los boletines {which} ({count} mostrados).",
@ -387,8 +372,6 @@
"Mask must be a \u0002#channel\u0002, a \u0002nick!user@host\u0002 pattern, or a bare nick glob — and no spaces.": "La máscara tiene que ser un \u0002#channel\u0002, un patrón \u0002nick!user@host\u0002, o un glob de nick pelado — y sin espacios.",
"Memo #\u0002{num}\u0002 from \u0002{from}\u0002 ({when}):": "Memo #\u0002{num}\u0002 de \u0002{from}\u0002 ({when}):",
"Memo #\u0002{n}\u0002 deleted.": "Memo #\u0002{n}\u0002 eliminado.",
"Memo sent to \u0002{sent}\u0002 account(s).": "Memo enviado a \u0002{sent}\u0002 cuenta(s).",
"Memo sent to \u0002{sent}\u0002 operator(s).": "Memo enviado a \u0002{sent}\u0002 operador(es).",
"Memo sent to \u0002{target}\u0002.": "Memo enviado a \u0002{target}\u0002.",
"MemoServ delivers messages to registered users, online or not. You must be identified to use it.": "MemoServ entrega mensajes a usuarios registrados, estén conectados o no. Tenés que estar identificado para usarlo.",
"Mode lock for \u0002{chan}\u0002 updated.": "Se actualizó el mode lock de \u0002{chan}\u0002.",
@ -485,12 +468,10 @@
"Removed \u0002{mask}\u0002 from \u0002{chan}\u0002's auto-kick list.": "Se quitó \u0002{mask}\u0002 de la lista de auto-kick de \u0002{chan}\u0002.",
"Removed \u0002{target}\u0002 from \u0002{name}\u0002.": "Se quitó \u0002{target}\u0002 de \u0002{name}\u0002.",
"Removed \u0002{which}\u0002 bulletin \u0002{n}\u0002.": "Se eliminó el boletín \u0002{which}\u0002 \u0002{n}\u0002.",
"Removed all \u0002{n}\u0002 bot(s).": "Se quitaron los \u0002{n}\u0002 bot(s).",
"Removed badword pattern from \u0002{chan}\u0002.": "Se quitó el patrón de palabra prohibida de \u0002{chan}\u0002.",
"Removed fingerprint \u0002{fp}\u0002.": "Se quitó la huella \u0002{fp}\u0002.",
"Removed forbidden pattern: {pattern}": "Se quitó el patrón prohibido: {pattern}",
"Removed the forbid on {label} \u0002{mask}\u0002.": "Se quitó la prohibición sobre {label} \u0002{mask}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regular(s) in \u0002{chan}\u0002.": "Se volvió a dar op a \u0002{opped}\u0002 habitué(s) de confianza en \u0002{chan}\u0002.",
"Report \u0002#{id}\u0002 ({state}):": "Reporte \u0002#{id}\u0002 ({state}):",
"Report \u0002#{n}\u0002 closed.": "Reporte \u0002#{n}\u0002 cerrado.",
"Report \u0002#{n}\u0002 deleted.": "Reporte \u0002#{n}\u0002 eliminado.",
@ -881,7 +862,6 @@
"The bot has left \u0002{chan}\u0002.": "El bot salió de \u0002{chan}\u0002.",
"The bot may again kick channel operators in \u0002{chan}\u0002.": "El bot puede volver a expulsar a los operadores del canal en \u0002{chan}\u0002.",
"The bot may again kick voiced users in \u0002{chan}\u0002.": "El bot puede volver a expulsar a los usuarios con voz en \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick(s) in \u0002{chan}\u0002.": "El bot va a banear a un usuario después de \u0002{n}\u0002 expulsión(es) en \u0002{chan}\u0002.",
"The bot will kick without warning in \u0002{chan}\u0002.": "El bot va a expulsar sin aviso en \u0002{chan}\u0002.",
"The bot will no longer kick channel operators in \u0002{chan}\u0002.": "El bot ya no va a expulsar a los operadores del canal en \u0002{chan}\u0002.",
"The bot will no longer kick voiced users in \u0002{chan}\u0002.": "El bot ya no va a expulsar a los usuarios con voz en \u0002{chan}\u0002.",
@ -927,7 +907,6 @@
"Ticket \u0002#{id}\u0002 isn't open (or doesn't exist).": "El ticket \u0002#{id}\u0002 no está abierto (o no existe).",
"Too many failed attempts. Please wait {secs}s and try again.": "Demasiados intentos fallidos. Esperá {secs}s y probá de nuevo.",
"Top talkers:": "Los que más hablan:",
"Top {shown} of {total} scored identit{suffix} for \u0002{chan}\u0002.": "Top {shown} de {total} identidad{suffix} con puntaje para \u0002{chan}\u0002.",
"Topic for \u0002{chan}\u0002 updated.": "Tema de \u0002{chan}\u0002 actualizado.",
"Trigger #\u0002{n}\u0002 removed from \u0002{chan}\u0002.": "Trigger #\u0002{n}\u0002 eliminado de \u0002{chan}\u0002.",
"Triggers for \u0002{chan}\u0002 ({count}):": "Triggers de \u0002{chan}\u0002 ({count}):",
@ -958,8 +937,6 @@
"You can't ungroup your main account name.": "No podés desagrupar el nombre principal de tu cuenta.",
"You cannot challenge yourself.": "No podés desafiarte a vos mismo.",
"You don't have an account to confirm.": "No tenés una cuenta para confirmar.",
"You have \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tenés \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 sin leer, de un máximo de \u0002{max}\u0002.",
"You have \u0002{unread}\u0002 new memo(s). Read them with \u0002/msg MemoServ READ NEW\u0002.": "Tenés \u0002{unread}\u0002 memo(s) nuevo(s). Leelos con \u0002/msg MemoServ READ NEW\u0002.",
"You have access on no channels.": "No tenés acceso en ningún canal.",
"You have no games. Use \u0002CHALLENGE <nick> <game>\u0002.": "No tenés juegos. Usá \u0002CHALLENGE <nick> <game>\u0002.",
"You have no memo #\u0002{n}\u0002.": "No tenés el memo #\u0002{n}\u0002.",
@ -1258,7 +1235,6 @@
"your mailbox summary": "el resumen de tu buzón",
"your memo preferences": "tus preferencias de memos",
"{challenger} challenges you to {game} (game #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002": "{challenger} te desafía a {game} (juego #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002",
"{count} ticket(s). \u0002VIEW\u0002 <id> for detail.": "{count} ticket(s). \u0002VIEW\u0002 <id> para el detalle.",
"{name} added for \u0002{mask}\u0002 (temporary).": "{name} agregado para \u0002{mask}\u0002 (temporal).",
"{name} added for \u0002{mask}\u0002.": "{name} agregado para \u0002{mask}\u0002.",
"{name} for \u0002{mask}\u0002 removed.": "{name} para \u0002{mask}\u0002 eliminado.",
@ -1266,7 +1242,6 @@
"{name} updated for \u0002{mask}\u0002.": "{name} actualizado para \u0002{mask}\u0002.",
"{nick} declined your challenge #{id}.": "{nick} rechazó tu desafío #{id}.",
"{num}. {text} — by {by}": "{num}. {text} — por {by}",
"{n} report(s). \u0002VIEW\u0002 <id> for detail.": "{n} reporte(s). \u0002VIEW\u0002 <id> para el detalle.",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}) — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}) — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}), expires in {ttl} — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}), vence en {ttl} — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] — {reason}",
@ -1283,5 +1258,55 @@
"{who}: I have no record of \u0002{nick}\u0002 talking in \u0002{chan}\u0002.": "{who}: No tengo registro de que \u0002{nick}\u0002 haya hablado en \u0002{chan}\u0002.",
"{word} list for \u0002{name}\u0002:": "Lista de {word} para \u0002{name}\u0002:",
"Type \u0002HELP <command>\u0002 for detail on one command.": "Escribí \u0002HELP <command>\u0002 para ver el detalle de un comando.",
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "No hay ayuda para \u0002{t}\u0002. Escribí \u0002HELP\u0002 para ver la lista de comandos."
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "No hay ayuda para \u0002{t}\u0002. Escribí \u0002HELP\u0002 para ver la lista de comandos.",
"Reopped \u0002{opped}\u0002 trusted regular in \u0002{chan}\u0002.": "Se reopeó \u0002{opped}\u0002 habitual de confianza en \u0002{chan}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regulars in \u0002{chan}\u0002.": "Se reopearon \u0002{opped}\u0002 habituales de confianza en \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 trigger from \u0002{chan}\u0002.": "Se borró \u0002{n}\u0002 disparador de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 triggers from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 disparadores de \u0002{chan}\u0002.",
" Serving {count} channel: {list}": " Atendiendo {count} canal: {list}",
" Serving {count} channels: {list}": " Atendiendo {count} canales: {list}",
"Removed all \u0002{n}\u0002 bot.": "Se eliminó \u0002{n}\u0002 bot en total.",
"Removed all \u0002{n}\u0002 bots.": "Se eliminaron los \u0002{n}\u0002 bots.",
"Cleared \u0002{n}\u0002 badword pattern from \u0002{chan}\u0002.": "Se borró \u0002{n}\u0002 patrón de palabra prohibida de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword patterns from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 patrones de palabras prohibidas de \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick in \u0002{chan}\u0002.": "El bot va a banear a un usuario después de \u0002{n}\u0002 kick en \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kicks in \u0002{chan}\u0002.": "El bot va a banear a un usuario después de \u0002{n}\u0002 kicks en \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entry from \u0002{chan}\u0002's auto-kick list.": "Se borró \u0002{count}\u0002 entrada de la lista de auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entries from \u0002{chan}\u0002's auto-kick list.": "Se borraron \u0002{count}\u0002 entradas de la lista de auto-kick de \u0002{chan}\u0002.",
"Top {shown} of {total} scored identity for \u0002{chan}\u0002.": "Top {shown} de {total} identidad puntuada para \u0002{chan}\u0002.",
"Top {shown} of {total} scored identities for \u0002{chan}\u0002.": "Top {shown} de {total} identidades puntuadas para \u0002{chan}\u0002.",
"\u0002{n}\u0002 vote will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto va a alcanzar ahora para un \u0002!votekick\u0002/\u0002!voteban\u0002 en \u0002{chan}\u0002.",
"\u0002{n}\u0002 votes will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 votos van a alcanzar ahora para un \u0002!votekick\u0002/\u0002!voteban\u0002 en \u0002{chan}\u0002.",
"End of flags ({count} entry).": "Fin de los flags ({count} entrada).",
"End of flags ({count} entries).": "Fin de los flags ({count} entradas).",
"Deleted all \u0002{count}\u0002 memo.": "Se eliminaron \u0002{count}\u0002 memo en total.",
"Deleted all \u0002{count}\u0002 memos.": "Se eliminaron los \u0002{count}\u0002 memos.",
"Memo sent to \u0002{sent}\u0002 account.": "Memo enviado a \u0002{sent}\u0002 cuenta.",
"Memo sent to \u0002{sent}\u0002 accounts.": "Memo enviado a \u0002{sent}\u0002 cuentas.",
"End of session list ({count} IP).": "Fin de la lista de sesiones ({count} IP).",
"End of session list ({count} IPs).": "Fin de la lista de sesiones ({count} IPs).",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session.": "\u0002{ip}\u0002 tiene \u0002{count}\u0002 sesión activa.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live sessions.": "\u0002{ip}\u0002 tiene \u0002{count}\u0002 sesiones activas.",
"You have \u0002{total}\u0002 memo, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tenés \u0002{total}\u0002 memo, \u0002{unread}\u0002 sin leer, de un máximo de \u0002{max}\u0002.",
"You have \u0002{total}\u0002 memos, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tenés \u0002{total}\u0002 memos, \u0002{unread}\u0002 sin leer, de un máximo de \u0002{max}\u0002.",
"End of list — {count} match{more}.": "Fin de la lista — {count} coincidencia{more}.",
"End of list — {count} matches{more}.": "Fin de la lista — {count} coincidencias{more}.",
"Memo sent to \u0002{sent}\u0002 operator.": "Memo enviado a \u0002{sent}\u0002 operador.",
"Memo sent to \u0002{sent}\u0002 operators.": "Memo enviado a \u0002{sent}\u0002 operadores.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host AKILL'd.": "CHANKILL en \u0002{chan}\u0002: se aplicó AKILL a \u0002{banned}\u0002 host.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 hosts AKILL'd.": "CHANKILL en \u0002{chan}\u0002: se aplicó AKILL a \u0002{banned}\u0002 hosts.",
" Auto-join : {count} channel — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canal — mirá \u0002AJOIN LIST\u0002",
" Auto-join : {count} channels — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canales — mirá \u0002AJOIN LIST\u0002",
"{count} ticket. \u0002VIEW\u0002 <id> for detail.": "{count} ticket. \u0002VIEW\u0002 <id> para el detalle.",
"{count} tickets. \u0002VIEW\u0002 <id> for detail.": "{count} tickets. \u0002VIEW\u0002 <id> para el detalle.",
"You have \u0002{unread}\u0002 new memo. Read it with \u0002/msg MemoServ READ NEW\u0002.": "Tenés \u0002{unread}\u0002 memo nuevo. Leelo con \u0002/msg MemoServ READ NEW\u0002.",
"You have \u0002{unread}\u0002 new memos. Read them with \u0002/msg MemoServ READ NEW\u0002.": "Tenés \u0002{unread}\u0002 memos nuevos. Leelos con \u0002/msg MemoServ READ NEW\u0002.",
"Cleared \u0002{n}\u0002 notify watch.": "Se borró \u0002{n}\u0002 seguimiento de notificación.",
"Cleared \u0002{n}\u0002 notify watches.": "Se borraron \u0002{n}\u0002 seguimientos de notificación.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 línea vista.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 lines seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 líneas vistas.",
"{n} report. \u0002VIEW\u0002 <id> for detail.": "{n} reporte. \u0002VIEW\u0002 <id> para el detalle.",
"{n} reports. \u0002VIEW\u0002 <id> for detail.": "{n} reportes. \u0002VIEW\u0002 <id> para el detalle.",
"End of list ({count} group).": "Fin de la lista ({count} grupo).",
"End of list ({count} groups).": "Fin de la lista ({count} grupos)."
}

View file

@ -61,7 +61,6 @@
"\u0002{chan}\u0002 isn't suspended.": "\u0002{chan}\u0002 no está suspendido.",
"\u0002{chan}\u0002 was already set that way.": "\u0002{chan}\u0002 ya estaba configurado así.",
"\u0002{chan}\u0002 will no longer expire.": "\u0002{chan}\u0002 ya no caducará.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line(s) seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 línea(s) vistas.",
"\u0002{code}\u0002 isn't an available language. Available: {list}.": "\u0002{code}\u0002 no es un idioma disponible. Disponibles: {list}.",
"\u0002{d}\u0002 isn't a valid expiry — try 30d, 12h, 45m, or 0.": "\u0002{d}\u0002 no es una caducidad válida — prueba 30d, 12h, 45m o 0.",
"\u0002{host}\u0002 is already in use. Please choose another.": "\u0002{host}\u0002 ya está en uso. Por favor, elige otro.",
@ -69,7 +68,6 @@
"\u0002{host}\u0002 isn't a valid host (letters, digits, hyphens and dots).": "\u0002{host}\u0002 no es un host válido (letras, dígitos, guiones y puntos).",
"\u0002{host}\u0002 isn't a valid host.": "\u0002{host}\u0002 no es un host válido.",
"\u0002{host}\u0002 isn't allowed here. Please choose another.": "\u0002{host}\u0002 no está permitido aquí. Por favor, elige otro.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session(s).": "\u0002{ip}\u0002 tiene \u0002{count}\u0002 sesión(es) activa(s).",
"\u0002{label}\u0002 access on \u0002{chan}\u0002: \u0002{level}\u0002": "\u0002{label}\u0002 acceso en \u0002{chan}\u0002: \u0002{level}\u0002",
"\u0002{mask}\u0002 isn't on \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 no está en la lista de auto-kick de \u0002{chan}\u0002.",
"\u0002{mask}\u0002 isn't on the ignore list.": "\u0002{mask}\u0002 no está en la lista de ignorados.",
@ -88,7 +86,6 @@
"\u0002{nick}\u0002 isn't grouped to your account.": "\u0002{nick}\u0002 no está agrupado a tu cuenta.",
"\u0002{nick}\u0002 isn't here.": "\u0002{nick}\u0002 no está aquí.",
"\u0002{nick}\u0002 was last seen {when} ({what}).": "\u0002{nick}\u0002 se vio por última vez {when} ({what}).",
"\u0002{n}\u0002 vote(s) will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto(s) ahora activarán un \u0002!votekick\u0002/\u0002!voteban\u0002 en \u0002{chan}\u0002.",
"\u0002{pattern}\u0002 isn't a valid regular expression.": "\u0002{pattern}\u0002 no es una expresión regular válida.",
"\u0002{raw}\u0002 isn't a valid \u0002{target}\u0002 mask.": "\u0002{raw}\u0002 no es una máscara \u0002{target}\u0002 válida.",
"\u0002{target}\u0002 had no access to \u0002{chan}\u0002.": "\u0002{target}\u0002 no tenía acceso a \u0002{chan}\u0002.",
@ -143,7 +140,6 @@
" (custom)": " (personalizado)",
" (no activity counters yet)": " (aún no hay contadores de actividad)",
" About : \u0002{target}\u0002": " Acerca de : \u0002{target}\u0002",
" Auto-join : {count} channel(s) — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canal(es) — ver \u0002AJOIN LIST\u0002",
" By : \u0002{by}\u0002": " Por : \u0002{by}\u0002",
" Description: {desc}": " Descripción: {desc}",
" Email : (none set)": " Email : (no establecido)",
@ -165,7 +161,6 @@
" Real name: {gecos}": " Nombre real: {gecos}",
" Reason : {reason}": " Motivo : {reason}",
" Registered : {when}": " Registrado : {when}",
" Serving {count} channel(s): {list}": " Atendiendo {count} canal(es): {list}",
" Staff note : {note}": " Nota del staff: {note}",
" Suspended : by \u0002{by}\u0002 — {reason}": " Suspendido : por \u0002{by}\u0002 — {reason}",
" URL : {url}": " URL : {url}",
@ -278,7 +273,6 @@
"Both channels must be registered.": "Ambos canales deben estar registrados.",
"Bots ({count}):": "Bots ({count}):",
"CALC and show each die": "CALC y mostrar cada dado",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILL'd.": "CHANKILL en \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) con AKILL aplicado.",
"Can't activate: \u0002{host}\u0002 is on the forbidden list.": "No se puede activar: \u0002{host}\u0002 está en la lista de prohibidos.",
"Can't activate: {msg}": "No se puede activar: {msg}",
"Challenge \u0002#{id}\u0002 ({game}) sent to \u0002{target}\u0002.": "Desafío \u0002#{id}\u0002 ({game}) enviado a \u0002{target}\u0002.",
@ -291,10 +285,6 @@
"Channels released: {list}.": "Canales liberados: {list}.",
"Channels you have access on ({count}):": "Canales a los que tienes acceso ({count}):",
"Classement \u0002{game}\u0002 vide. Sois le premier à gagner !": "Clasificación \u0002{game}\u0002 vacía. ¡Sé el primero en ganar!",
"Cleared \u0002{count}\u0002 entr{suffix} from \u0002{chan}\u0002's auto-kick list.": "Se borraron \u0002{count}\u0002 entr{suffix} de la lista de auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword pattern(s) from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 patrón(es) de palabras prohibidas de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 notify watch(es).": "Se borraron \u0002{n}\u0002 vigilancia(s) de notificación.",
"Cleared \u0002{n}\u0002 trigger(s) from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 disparador(es) de \u0002{chan}\u0002.",
"Cleared \u0002{target}\u0002's access to \u0002{chan}\u0002.": "Se borró el acceso de \u0002{target}\u0002 a \u0002{chan}\u0002.",
"Cleared the *!*@{host} ban on \u0002{chan}\u0002.": "Se borró el ban *!*@{host} en \u0002{chan}\u0002.",
"Contact email for \u0002{chan}\u0002 cleared.": "Email de contacto de \u0002{chan}\u0002 borrado.",
@ -306,22 +296,17 @@
"Couldn't update \u0002{chan}\u0002 — please try again in a moment.": "No se pudo actualizar \u0002{chan}\u0002 — por favor inténtalo de nuevo en un momento.",
"DEFCON set to \u0002{level}\u0002 — {desc}.": "DEFCON establecido en \u0002{level}\u0002 — {desc}.",
"Declined.": "Rechazado.",
"Deleted all \u0002{count}\u0002 memo(s).": "Se eliminaron todos los \u0002{count}\u0002 memo(s).",
"Description for \u0002{chan}\u0002 updated.": "Descripción de \u0002{chan}\u0002 actualizada.",
"DiceServ rolls dice and evaluates maths for tabletop games. Dice: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, and \u00023~2d6\u0002 to repeat.": "DiceServ tira dados y evalúa operaciones matemáticas para juegos de mesa. Dados: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. También + - * / ^ %, paréntesis, funciones (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, y \u00023~2d6\u0002 para repetir.",
"DictServ looks words up in the dict.org dictionaries. Try \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, and more — \u0002LOOKUP\u0002 lists them all.": "DictServ busca palabras en los diccionarios de dict.org. Prueba \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (tesauro), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, y más — \u0002LOOKUP\u0002 los lista todos.",
"Email for \u0002{account}\u0002 cleared.": "Email de \u0002{account}\u0002 borrado.",
"Email for \u0002{account}\u0002 updated.": "Email de \u0002{account}\u0002 actualizado.",
"End of exception list ({count} shown).": "Fin de la lista de excepciones ({count} mostradas).",
"End of flags ({count} entr{suffix}).": "Fin de los flags ({count} entr{suffix}).",
"End of ignore list ({count} shown).": "Fin de la lista de ignorados ({count} mostrados).",
"End of jupe list ({count} shown).": "Fin de la lista de jupes ({count} mostrados).",
"End of list ({count} group(s)).": "Fin de la lista ({count} grupo(s)).",
"End of list — {count} match(es){more}.": "Fin de la lista — {count} coincidencia(s){more}.",
"End of notify list ({shown} shown).": "Fin de la lista de notificaciones ({shown} mostradas).",
"End of results ({count} shown, newest first — refine the search to narrow).": "Fin de los resultados ({count} mostrados, más recientes primero — afina la búsqueda para acotar).",
"End of runtime operator list ({count} shown).": "Fin de la lista de operadores en tiempo de ejecución ({count} mostrados).",
"End of session list ({count} IP(s)).": "Fin de la lista de sesiones ({count} IP(s)).",
"End of spam-filter list ({shown} shown).": "Fin de la lista de filtros de spam ({shown} mostrados).",
"End of {name} list ({shown} shown).": "Fin de la lista {name} ({shown} mostrados).",
"End of {which} bulletins ({count} shown).": "Fin de los boletines {which} ({count} mostrados).",
@ -387,8 +372,6 @@
"Mask must be a \u0002#channel\u0002, a \u0002nick!user@host\u0002 pattern, or a bare nick glob — and no spaces.": "La máscara debe ser un \u0002#channel\u0002, un patrón \u0002nick!user@host\u0002, o un glob de nick simple — y sin espacios.",
"Memo #\u0002{num}\u0002 from \u0002{from}\u0002 ({when}):": "Memo #\u0002{num}\u0002 de \u0002{from}\u0002 ({when}):",
"Memo #\u0002{n}\u0002 deleted.": "Memo #\u0002{n}\u0002 eliminado.",
"Memo sent to \u0002{sent}\u0002 account(s).": "Memo enviado a \u0002{sent}\u0002 cuenta(s).",
"Memo sent to \u0002{sent}\u0002 operator(s).": "Memo enviado a \u0002{sent}\u0002 operador(es).",
"Memo sent to \u0002{target}\u0002.": "Memo enviado a \u0002{target}\u0002.",
"MemoServ delivers messages to registered users, online or not. You must be identified to use it.": "MemoServ entrega mensajes a usuarios registrados, estén conectados o no. Debes estar identificado para usarlo.",
"Mode lock for \u0002{chan}\u0002 updated.": "Bloqueo de modos de \u0002{chan}\u0002 actualizado.",
@ -485,12 +468,10 @@
"Removed \u0002{mask}\u0002 from \u0002{chan}\u0002's auto-kick list.": "Se quitó \u0002{mask}\u0002 de la lista de auto-kick de \u0002{chan}\u0002.",
"Removed \u0002{target}\u0002 from \u0002{name}\u0002.": "Se quitó \u0002{target}\u0002 de \u0002{name}\u0002.",
"Removed \u0002{which}\u0002 bulletin \u0002{n}\u0002.": "Se eliminó el boletín \u0002{which}\u0002 \u0002{n}\u0002.",
"Removed all \u0002{n}\u0002 bot(s).": "Se quitaron los \u0002{n}\u0002 bot(s).",
"Removed badword pattern from \u0002{chan}\u0002.": "Se quitó el patrón de palabra prohibida de \u0002{chan}\u0002.",
"Removed fingerprint \u0002{fp}\u0002.": "Se quitó la huella \u0002{fp}\u0002.",
"Removed forbidden pattern: {pattern}": "Se quitó el patrón prohibido: {pattern}",
"Removed the forbid on {label} \u0002{mask}\u0002.": "Se quitó la prohibición sobre {label} \u0002{mask}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regular(s) in \u0002{chan}\u0002.": "Se volvió a dar op a \u0002{opped}\u0002 regular(es) de confianza en \u0002{chan}\u0002.",
"Report \u0002#{id}\u0002 ({state}):": "Reporte \u0002#{id}\u0002 ({state}):",
"Report \u0002#{n}\u0002 closed.": "Reporte \u0002#{n}\u0002 cerrado.",
"Report \u0002#{n}\u0002 deleted.": "Reporte \u0002#{n}\u0002 eliminado.",
@ -881,7 +862,6 @@
"The bot has left \u0002{chan}\u0002.": "El bot ha salido de \u0002{chan}\u0002.",
"The bot may again kick channel operators in \u0002{chan}\u0002.": "El bot puede volver a expulsar a los operadores del canal en \u0002{chan}\u0002.",
"The bot may again kick voiced users in \u0002{chan}\u0002.": "El bot puede volver a expulsar a los usuarios con voz en \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick(s) in \u0002{chan}\u0002.": "El bot vetará a un usuario tras \u0002{n}\u0002 expulsión(es) en \u0002{chan}\u0002.",
"The bot will kick without warning in \u0002{chan}\u0002.": "El bot expulsará sin avisar en \u0002{chan}\u0002.",
"The bot will no longer kick channel operators in \u0002{chan}\u0002.": "El bot ya no expulsará a los operadores del canal en \u0002{chan}\u0002.",
"The bot will no longer kick voiced users in \u0002{chan}\u0002.": "El bot ya no expulsará a los usuarios con voz en \u0002{chan}\u0002.",
@ -927,7 +907,6 @@
"Ticket \u0002#{id}\u0002 isn't open (or doesn't exist).": "El ticket \u0002#{id}\u0002 no está abierto (o no existe).",
"Too many failed attempts. Please wait {secs}s and try again.": "Demasiados intentos fallidos. Espera {secs}s e inténtalo de nuevo.",
"Top talkers:": "Los que más hablan:",
"Top {shown} of {total} scored identit{suffix} for \u0002{chan}\u0002.": "Top {shown} de {total} identidad{suffix} puntuadas para \u0002{chan}\u0002.",
"Topic for \u0002{chan}\u0002 updated.": "Tema de \u0002{chan}\u0002 actualizado.",
"Trigger #\u0002{n}\u0002 removed from \u0002{chan}\u0002.": "Disparador #\u0002{n}\u0002 eliminado de \u0002{chan}\u0002.",
"Triggers for \u0002{chan}\u0002 ({count}):": "Disparadores de \u0002{chan}\u0002 ({count}):",
@ -958,8 +937,6 @@
"You can't ungroup your main account name.": "No puedes desagrupar el nombre de tu cuenta principal.",
"You cannot challenge yourself.": "No puedes desafiarte a ti mismo.",
"You don't have an account to confirm.": "No tienes ninguna cuenta que confirmar.",
"You have \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tienes \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 sin leer, de un máximo de \u0002{max}\u0002.",
"You have \u0002{unread}\u0002 new memo(s). Read them with \u0002/msg MemoServ READ NEW\u0002.": "Tienes \u0002{unread}\u0002 memo(s) nuevo(s). Léelos con \u0002/msg MemoServ READ NEW\u0002.",
"You have access on no channels.": "No tienes acceso en ningún canal.",
"You have no games. Use \u0002CHALLENGE <nick> <game>\u0002.": "No tienes partidas. Usa \u0002CHALLENGE <nick> <game>\u0002.",
"You have no memo #\u0002{n}\u0002.": "No tienes el memo #\u0002{n}\u0002.",
@ -1258,7 +1235,6 @@
"your mailbox summary": "el resumen de tu buzón",
"your memo preferences": "tus preferencias de memos",
"{challenger} challenges you to {game} (game #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002": "{challenger} te desafía a {game} (partida #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002",
"{count} ticket(s). \u0002VIEW\u0002 <id> for detail.": "{count} ticket(s). \u0002VIEW\u0002 <id> para el detalle.",
"{name} added for \u0002{mask}\u0002 (temporary).": "{name} añadido para \u0002{mask}\u0002 (temporal).",
"{name} added for \u0002{mask}\u0002.": "{name} añadido para \u0002{mask}\u0002.",
"{name} for \u0002{mask}\u0002 removed.": "{name} para \u0002{mask}\u0002 eliminado.",
@ -1266,7 +1242,6 @@
"{name} updated for \u0002{mask}\u0002.": "{name} actualizado para \u0002{mask}\u0002.",
"{nick} declined your challenge #{id}.": "{nick} rechazó tu desafío #{id}.",
"{num}. {text} — by {by}": "{num}. {text} — por {by}",
"{n} report(s). \u0002VIEW\u0002 <id> for detail.": "{n} informe(s). \u0002VIEW\u0002 <id> para el detalle.",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}) — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}) — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}), expires in {ttl} — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}), expira en {ttl} — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] — {reason}",
@ -1283,5 +1258,55 @@
"{who}: I have no record of \u0002{nick}\u0002 talking in \u0002{chan}\u0002.": "{who}: No tengo registro de que \u0002{nick}\u0002 haya hablado en \u0002{chan}\u0002.",
"{word} list for \u0002{name}\u0002:": "lista de {word} para \u0002{name}\u0002:",
"Type \u0002HELP <command>\u0002 for detail on one command.": "Escribe \u0002HELP <command>\u0002 para más detalle sobre un comando.",
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "No hay ayuda para \u0002{t}\u0002. Escribe \u0002HELP\u0002 para la lista de comandos."
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "No hay ayuda para \u0002{t}\u0002. Escribe \u0002HELP\u0002 para la lista de comandos.",
"Reopped \u0002{opped}\u0002 trusted regular in \u0002{chan}\u0002.": "Se volvió a dar op a \u0002{opped}\u0002 habitual de confianza en \u0002{chan}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regulars in \u0002{chan}\u0002.": "Se volvió a dar op a \u0002{opped}\u0002 habituales de confianza en \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 trigger from \u0002{chan}\u0002.": "Se borró \u0002{n}\u0002 disparador de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 triggers from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 disparadores de \u0002{chan}\u0002.",
" Serving {count} channel: {list}": " Atendiendo {count} canal: {list}",
" Serving {count} channels: {list}": " Atendiendo {count} canales: {list}",
"Removed all \u0002{n}\u0002 bot.": "Se eliminó \u0002{n}\u0002 bot en total.",
"Removed all \u0002{n}\u0002 bots.": "Se eliminaron los \u0002{n}\u0002 bots.",
"Cleared \u0002{n}\u0002 badword pattern from \u0002{chan}\u0002.": "Se borró \u0002{n}\u0002 patrón de palabra prohibida de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword patterns from \u0002{chan}\u0002.": "Se borraron \u0002{n}\u0002 patrones de palabra prohibida de \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick in \u0002{chan}\u0002.": "El bot vetará a un usuario después de \u0002{n}\u0002 expulsión en \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kicks in \u0002{chan}\u0002.": "El bot vetará a un usuario después de \u0002{n}\u0002 expulsiones en \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entry from \u0002{chan}\u0002's auto-kick list.": "Se borró \u0002{count}\u0002 entrada de la lista de auto-expulsión de \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entries from \u0002{chan}\u0002's auto-kick list.": "Se borraron \u0002{count}\u0002 entradas de la lista de auto-expulsión de \u0002{chan}\u0002.",
"Top {shown} of {total} scored identity for \u0002{chan}\u0002.": "Top {shown} de {total} identidad puntuada para \u0002{chan}\u0002.",
"Top {shown} of {total} scored identities for \u0002{chan}\u0002.": "Top {shown} de {total} identidades puntuadas para \u0002{chan}\u0002.",
"\u0002{n}\u0002 vote will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto llevará ahora un \u0002!votekick\u0002/\u0002!voteban\u0002 en \u0002{chan}\u0002.",
"\u0002{n}\u0002 votes will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 votos llevarán ahora un \u0002!votekick\u0002/\u0002!voteban\u0002 en \u0002{chan}\u0002.",
"End of flags ({count} entry).": "Fin de los flags ({count} entrada).",
"End of flags ({count} entries).": "Fin de los flags ({count} entradas).",
"Deleted all \u0002{count}\u0002 memo.": "Se eliminó \u0002{count}\u0002 memo en total.",
"Deleted all \u0002{count}\u0002 memos.": "Se eliminaron los \u0002{count}\u0002 memos.",
"Memo sent to \u0002{sent}\u0002 account.": "Memo enviado a \u0002{sent}\u0002 cuenta.",
"Memo sent to \u0002{sent}\u0002 accounts.": "Memo enviado a \u0002{sent}\u0002 cuentas.",
"End of session list ({count} IP).": "Fin de la lista de sesiones ({count} IP).",
"End of session list ({count} IPs).": "Fin de la lista de sesiones ({count} IPs).",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session.": "\u0002{ip}\u0002 tiene \u0002{count}\u0002 sesión activa.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live sessions.": "\u0002{ip}\u0002 tiene \u0002{count}\u0002 sesiones activas.",
"You have \u0002{total}\u0002 memo, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tienes \u0002{total}\u0002 memo, \u0002{unread}\u0002 sin leer, de un máximo de \u0002{max}\u0002.",
"You have \u0002{total}\u0002 memos, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tienes \u0002{total}\u0002 memos, \u0002{unread}\u0002 sin leer, de un máximo de \u0002{max}\u0002.",
"End of list — {count} match{more}.": "Fin de la lista — {count} coincidencia{more}.",
"End of list — {count} matches{more}.": "Fin de la lista — {count} coincidencias{more}.",
"Memo sent to \u0002{sent}\u0002 operator.": "Memo enviado a \u0002{sent}\u0002 operador.",
"Memo sent to \u0002{sent}\u0002 operators.": "Memo enviado a \u0002{sent}\u0002 operadores.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host AKILL'd.": "CHANKILL en \u0002{chan}\u0002: \u0002{banned}\u0002 host con AKILL.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 hosts AKILL'd.": "CHANKILL en \u0002{chan}\u0002: \u0002{banned}\u0002 hosts con AKILL.",
" Auto-join : {count} channel — see \u0002AJOIN LIST\u0002": " Auto-unión : {count} canal — mira \u0002AJOIN LIST\u0002",
" Auto-join : {count} channels — see \u0002AJOIN LIST\u0002": " Auto-unión : {count} canales — mira \u0002AJOIN LIST\u0002",
"{count} ticket. \u0002VIEW\u0002 <id> for detail.": "{count} ticket. \u0002VIEW\u0002 <id> para ver el detalle.",
"{count} tickets. \u0002VIEW\u0002 <id> for detail.": "{count} tickets. \u0002VIEW\u0002 <id> para ver el detalle.",
"You have \u0002{unread}\u0002 new memo. Read it with \u0002/msg MemoServ READ NEW\u0002.": "Tienes \u0002{unread}\u0002 memo nuevo. Léelo con \u0002/msg MemoServ READ NEW\u0002.",
"You have \u0002{unread}\u0002 new memos. Read them with \u0002/msg MemoServ READ NEW\u0002.": "Tienes \u0002{unread}\u0002 memos nuevos. Léelos con \u0002/msg MemoServ READ NEW\u0002.",
"Cleared \u0002{n}\u0002 notify watch.": "Se borró \u0002{n}\u0002 seguimiento de notificación.",
"Cleared \u0002{n}\u0002 notify watches.": "Se borraron \u0002{n}\u0002 seguimientos de notificación.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 línea vista.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 lines seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 líneas vistas.",
"{n} report. \u0002VIEW\u0002 <id> for detail.": "{n} reporte. \u0002VIEW\u0002 <id> para ver el detalle.",
"{n} reports. \u0002VIEW\u0002 <id> for detail.": "{n} reportes. \u0002VIEW\u0002 <id> para ver el detalle.",
"End of list ({count} group).": "Fin de la lista ({count} grupo).",
"End of list ({count} groups).": "Fin de la lista ({count} grupos)."
}

View file

@ -61,7 +61,6 @@
"\u0002{chan}\u0002 isn't suspended.": "\u0002{chan}\u0002 n'est pas suspendu.",
"\u0002{chan}\u0002 was already set that way.": "\u0002{chan}\u0002 était déjà réglé ainsi.",
"\u0002{chan}\u0002 will no longer expire.": "\u0002{chan}\u0002 n'expirera plus.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line(s) seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 ligne(s) vue(s).",
"\u0002{code}\u0002 isn't an available language. Available: {list}.": "\u0002{code}\u0002 n'est pas une langue disponible. Disponibles : {list}.",
"\u0002{d}\u0002 isn't a valid expiry — try 30d, 12h, 45m, or 0.": "\u0002{d}\u0002 n'est pas une expiration valide — essayez 30d, 12h, 45m ou 0.",
"\u0002{host}\u0002 is already in use. Please choose another.": "\u0002{host}\u0002 est déjà utilisé. Veuillez en choisir un autre.",
@ -69,7 +68,6 @@
"\u0002{host}\u0002 isn't a valid host (letters, digits, hyphens and dots).": "\u0002{host}\u0002 n'est pas un hôte valide (lettres, chiffres, tirets et points).",
"\u0002{host}\u0002 isn't a valid host.": "\u0002{host}\u0002 n'est pas un hôte valide.",
"\u0002{host}\u0002 isn't allowed here. Please choose another.": "\u0002{host}\u0002 n'est pas autorisé ici. Veuillez en choisir un autre.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session(s).": "\u0002{ip}\u0002 a \u0002{count}\u0002 session(s) active(s).",
"\u0002{label}\u0002 access on \u0002{chan}\u0002: \u0002{level}\u0002": "Accès de \u0002{label}\u0002 sur \u0002{chan}\u0002 : \u0002{level}\u0002",
"\u0002{mask}\u0002 isn't on \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 n'est pas dans la liste d'auto-kick de \u0002{chan}\u0002.",
"\u0002{mask}\u0002 isn't on the ignore list.": "\u0002{mask}\u0002 n'est pas dans la liste d'ignore.",
@ -88,7 +86,6 @@
"\u0002{nick}\u0002 isn't grouped to your account.": "\u0002{nick}\u0002 n'est pas groupé à votre compte.",
"\u0002{nick}\u0002 isn't here.": "\u0002{nick}\u0002 n'est pas ici.",
"\u0002{nick}\u0002 was last seen {when} ({what}).": "\u0002{nick}\u0002 a été vu pour la dernière fois {when} ({what}).",
"\u0002{n}\u0002 vote(s) will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 vote(s) suffiront désormais pour un \u0002!votekick\u0002/\u0002!voteban\u0002 dans \u0002{chan}\u0002.",
"\u0002{pattern}\u0002 isn't a valid regular expression.": "\u0002{pattern}\u0002 n'est pas une expression régulière valide.",
"\u0002{raw}\u0002 isn't a valid \u0002{target}\u0002 mask.": "\u0002{raw}\u0002 n'est pas un masque \u0002{target}\u0002 valide.",
"\u0002{target}\u0002 had no access to \u0002{chan}\u0002.": "\u0002{target}\u0002 n'avait aucun accès à \u0002{chan}\u0002.",
@ -143,7 +140,6 @@
" (custom)": " (personnalisé)",
" (no activity counters yet)": " (aucun compteur d'activité pour l'instant)",
" About : \u0002{target}\u0002": " Sujet : \u0002{target}\u0002",
" Auto-join : {count} channel(s) — see \u0002AJOIN LIST\u0002": " Auto-join : {count} salon(s) — voir \u0002AJOIN LIST\u0002",
" By : \u0002{by}\u0002": " Par : \u0002{by}\u0002",
" Description: {desc}": " Description: {desc}",
" Email : (none set)": " Email : (aucun défini)",
@ -165,7 +161,6 @@
" Real name: {gecos}": " Nom réel : {gecos}",
" Reason : {reason}": " Raison : {reason}",
" Registered : {when}": " Enregistré : {when}",
" Serving {count} channel(s): {list}": " Sert {count} salon(s) : {list}",
" Staff note : {note}": " Note du staff : {note}",
" Suspended : by \u0002{by}\u0002 — {reason}": " Suspendu : par \u0002{by}\u0002 — {reason}",
" URL : {url}": " URL : {url}",
@ -278,7 +273,6 @@
"Both channels must be registered.": "Les deux salons doivent être enregistrés.",
"Bots ({count}):": "Bots ({count}) :",
"CALC and show each die": "CALC en affichant chaque dé",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILL'd.": "CHANKILL sur \u0002{chan}\u0002 : \u0002{banned}\u0002 hôte(s) AKILL.",
"Can't activate: \u0002{host}\u0002 is on the forbidden list.": "Impossible d'activer : \u0002{host}\u0002 figure sur la liste des interdits.",
"Can't activate: {msg}": "Impossible d'activer : {msg}",
"Challenge \u0002#{id}\u0002 ({game}) sent to \u0002{target}\u0002.": "Défi \u0002#{id}\u0002 ({game}) envoyé à \u0002{target}\u0002.",
@ -291,10 +285,6 @@
"Channels released: {list}.": "Salons libérés : {list}.",
"Channels you have access on ({count}):": "Salons sur lesquels vous avez un accès ({count}) :",
"Classement \u0002{game}\u0002 vide. Sois le premier à gagner !": "Classement \u0002{game}\u0002 vide. Soyez le premier à gagner !",
"Cleared \u0002{count}\u0002 entr{suffix} from \u0002{chan}\u0002's auto-kick list.": "Suppression de \u0002{count}\u0002 entré{suffix} de la liste d'auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword pattern(s) from \u0002{chan}\u0002.": "\u0002{n}\u0002 motif(s) de gros mots effacé(s) de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 notify watch(es).": "\u0002{n}\u0002 surveillance(s) effacée(s).",
"Cleared \u0002{n}\u0002 trigger(s) from \u0002{chan}\u0002.": "\u0002{n}\u0002 déclencheur(s) effacé(s) de \u0002{chan}\u0002.",
"Cleared \u0002{target}\u0002's access to \u0002{chan}\u0002.": "Accès de \u0002{target}\u0002 à \u0002{chan}\u0002 effacé.",
"Cleared the *!*@{host} ban on \u0002{chan}\u0002.": "Ban *!*@{host} retiré sur \u0002{chan}\u0002.",
"Contact email for \u0002{chan}\u0002 cleared.": "E-mail de contact de \u0002{chan}\u0002 effacé.",
@ -306,22 +296,17 @@
"Couldn't update \u0002{chan}\u0002 — please try again in a moment.": "Impossible de mettre à jour \u0002{chan}\u0002 — veuillez réessayer dans un instant.",
"DEFCON set to \u0002{level}\u0002 — {desc}.": "DEFCON réglé sur \u0002{level}\u0002 — {desc}.",
"Declined.": "Refusé.",
"Deleted all \u0002{count}\u0002 memo(s).": "Tous les \u0002{count}\u0002 mémo(s) ont été supprimés.",
"Description for \u0002{chan}\u0002 updated.": "Description de \u0002{chan}\u0002 mise à jour.",
"DiceServ rolls dice and evaluates maths for tabletop games. Dice: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, and \u00023~2d6\u0002 to repeat.": "DiceServ lance des dés et évalue des calculs pour les jeux de rôle sur table. Dés : \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Aussi + - * / ^ %, parenthèses, fonctions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, et \u00023~2d6\u0002 pour répéter.",
"DictServ looks words up in the dict.org dictionaries. Try \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, and more — \u0002LOOKUP\u0002 lists them all.": "DictServ recherche des mots dans les dictionnaires de dict.org. Essayez \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thésaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, et plus — \u0002LOOKUP\u0002 les liste tous.",
"Email for \u0002{account}\u0002 cleared.": "Email de \u0002{account}\u0002 effacé.",
"Email for \u0002{account}\u0002 updated.": "Email de \u0002{account}\u0002 mis à jour.",
"End of exception list ({count} shown).": "Fin de la liste des exceptions ({count} affiché(s)).",
"End of flags ({count} entr{suffix}).": "Fin des flags ({count} entré{suffix}).",
"End of ignore list ({count} shown).": "Fin de la liste d'ignore ({count} affiché(s)).",
"End of jupe list ({count} shown).": "Fin de la liste des jupes ({count} affiché(s)).",
"End of list ({count} group(s)).": "Fin de la liste ({count} groupe(s)).",
"End of list — {count} match(es){more}.": "Fin de la liste — {count} correspondance(s){more}.",
"End of notify list ({shown} shown).": "Fin de la liste de surveillance ({shown} affiché(s)).",
"End of results ({count} shown, newest first — refine the search to narrow).": "Fin des résultats ({count} affiché(s), du plus récent au plus ancien — affinez la recherche pour restreindre).",
"End of runtime operator list ({count} shown).": "Fin de la liste des opérateurs d'exécution ({count} affiché(s)).",
"End of session list ({count} IP(s)).": "Fin de la liste des sessions ({count} IP).",
"End of spam-filter list ({shown} shown).": "Fin de la liste des filtres anti-spam ({shown} affiché(s)).",
"End of {name} list ({shown} shown).": "Fin de la liste {name} ({shown} affiché(s)).",
"End of {which} bulletins ({count} shown).": "Fin des bulletins {which} ({count} affiché(s)).",
@ -387,8 +372,6 @@
"Mask must be a \u0002#channel\u0002, a \u0002nick!user@host\u0002 pattern, or a bare nick glob — and no spaces.": "Le masque doit être un \u0002#canal\u0002, un motif \u0002nick!user@host\u0002, ou un simple glob de pseudo — et sans espaces.",
"Memo #\u0002{num}\u0002 from \u0002{from}\u0002 ({when}):": "Mémo n°\u0002{num}\u0002 de \u0002{from}\u0002 ({when}) :",
"Memo #\u0002{n}\u0002 deleted.": "Mémo n°\u0002{n}\u0002 supprimé.",
"Memo sent to \u0002{sent}\u0002 account(s).": "Mémo envoyé à \u0002{sent}\u0002 compte(s).",
"Memo sent to \u0002{sent}\u0002 operator(s).": "Mémo envoyé à \u0002{sent}\u0002 opérateur(s).",
"Memo sent to \u0002{target}\u0002.": "Mémo envoyé à \u0002{target}\u0002.",
"MemoServ delivers messages to registered users, online or not. You must be identified to use it.": "MemoServ délivre des messages aux utilisateurs enregistrés, connectés ou non. Vous devez être identifié pour l'utiliser.",
"Mode lock for \u0002{chan}\u0002 updated.": "Verrou de modes de \u0002{chan}\u0002 mis à jour.",
@ -485,12 +468,10 @@
"Removed \u0002{mask}\u0002 from \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 a été retiré de la liste d'auto-kick de \u0002{chan}\u0002.",
"Removed \u0002{target}\u0002 from \u0002{name}\u0002.": "\u0002{target}\u0002 a été retiré de \u0002{name}\u0002.",
"Removed \u0002{which}\u0002 bulletin \u0002{n}\u0002.": "Bulletin \u0002{which}\u0002 \u0002{n}\u0002 supprimé.",
"Removed all \u0002{n}\u0002 bot(s).": "Tous les \u0002{n}\u0002 bot(s) supprimé(s).",
"Removed badword pattern from \u0002{chan}\u0002.": "Motif de gros mot retiré de \u0002{chan}\u0002.",
"Removed fingerprint \u0002{fp}\u0002.": "Empreinte \u0002{fp}\u0002 retirée.",
"Removed forbidden pattern: {pattern}": "Motif interdit retiré : {pattern}",
"Removed the forbid on {label} \u0002{mask}\u0002.": "Interdiction retirée pour {label} \u0002{mask}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regular(s) in \u0002{chan}\u0002.": "\u0002{opped}\u0002 habitué(s) de confiance réoppé(s) dans \u0002{chan}\u0002.",
"Report \u0002#{id}\u0002 ({state}):": "Signalement \u0002#{id}\u0002 ({state}) :",
"Report \u0002#{n}\u0002 closed.": "Signalement \u0002#{n}\u0002 fermé.",
"Report \u0002#{n}\u0002 deleted.": "Signalement \u0002#{n}\u0002 supprimé.",
@ -881,7 +862,6 @@
"The bot has left \u0002{chan}\u0002.": "Le bot a quitté \u0002{chan}\u0002.",
"The bot may again kick channel operators in \u0002{chan}\u0002.": "Le bot peut à nouveau expulser les opérateurs du salon dans \u0002{chan}\u0002.",
"The bot may again kick voiced users in \u0002{chan}\u0002.": "Le bot peut à nouveau expulser les utilisateurs voicés dans \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick(s) in \u0002{chan}\u0002.": "Le bot bannira un utilisateur après \u0002{n}\u0002 expulsion(s) dans \u0002{chan}\u0002.",
"The bot will kick without warning in \u0002{chan}\u0002.": "Le bot expulsera sans avertissement dans \u0002{chan}\u0002.",
"The bot will no longer kick channel operators in \u0002{chan}\u0002.": "Le bot n'expulsera plus les opérateurs du salon dans \u0002{chan}\u0002.",
"The bot will no longer kick voiced users in \u0002{chan}\u0002.": "Le bot n'expulsera plus les utilisateurs voicés dans \u0002{chan}\u0002.",
@ -927,7 +907,6 @@
"Ticket \u0002#{id}\u0002 isn't open (or doesn't exist).": "Le ticket \u0002#{id}\u0002 n'est pas ouvert (ou n'existe pas).",
"Too many failed attempts. Please wait {secs}s and try again.": "Trop de tentatives échouées. Veuillez patienter {secs}s et réessayer.",
"Top talkers:": "Plus bavards :",
"Top {shown} of {total} scored identit{suffix} for \u0002{chan}\u0002.": "Top {shown} sur {total} identités classées pour \u0002{chan}\u0002.",
"Topic for \u0002{chan}\u0002 updated.": "Sujet de \u0002{chan}\u0002 mis à jour.",
"Trigger #\u0002{n}\u0002 removed from \u0002{chan}\u0002.": "Déclencheur #\u0002{n}\u0002 retiré de \u0002{chan}\u0002.",
"Triggers for \u0002{chan}\u0002 ({count}):": "Déclencheurs pour \u0002{chan}\u0002 ({count}) :",
@ -958,8 +937,6 @@
"You can't ungroup your main account name.": "Vous ne pouvez pas dégrouper le nom principal de votre compte.",
"You cannot challenge yourself.": "Vous ne pouvez pas vous défier vous-même.",
"You don't have an account to confirm.": "Vous n'avez pas de compte à confirmer.",
"You have \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Vous avez \u0002{total}\u0002 mémo(s), \u0002{unread}\u0002 non lu(s), sur un maximum de \u0002{max}\u0002.",
"You have \u0002{unread}\u0002 new memo(s). Read them with \u0002/msg MemoServ READ NEW\u0002.": "Vous avez \u0002{unread}\u0002 nouveau(x) mémo(s). Lisez-les avec \u0002/msg MemoServ READ NEW\u0002.",
"You have access on no channels.": "Vous n'avez d'accès sur aucun salon.",
"You have no games. Use \u0002CHALLENGE <nick> <game>\u0002.": "Vous n'avez aucune partie. Utilisez \u0002CHALLENGE <nick> <game>\u0002.",
"You have no memo #\u0002{n}\u0002.": "Vous n'avez aucun mémo n°\u0002{n}\u0002.",
@ -1258,7 +1235,6 @@
"your mailbox summary": "résumé de votre boîte",
"your memo preferences": "vos préférences de mémos",
"{challenger} challenges you to {game} (game #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002": "{challenger} vous défie au {game} (partie #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002",
"{count} ticket(s). \u0002VIEW\u0002 <id> for detail.": "{count} ticket(s). \u0002VIEW\u0002 <id> pour le détail.",
"{name} added for \u0002{mask}\u0002 (temporary).": "{name} ajouté pour \u0002{mask}\u0002 (temporaire).",
"{name} added for \u0002{mask}\u0002.": "{name} ajouté pour \u0002{mask}\u0002.",
"{name} for \u0002{mask}\u0002 removed.": "{name} pour \u0002{mask}\u0002 supprimé.",
@ -1266,7 +1242,6 @@
"{name} updated for \u0002{mask}\u0002.": "{name} mis à jour pour \u0002{mask}\u0002.",
"{nick} declined your challenge #{id}.": "{nick} a refusé votre défi #{id}.",
"{num}. {text} — by {by}": "{num}. {text} — par {by}",
"{n} report(s). \u0002VIEW\u0002 <id> for detail.": "{n} signalement(s). \u0002VIEW\u0002 <id> pour le détail.",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}) — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] par {setter} ({when}) — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}), expires in {ttl} — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] par {setter} ({when}), expire dans {ttl} — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] — {reason}",
@ -1283,5 +1258,55 @@
"{who}: I have no record of \u0002{nick}\u0002 talking in \u0002{chan}\u0002.": "{who} : je n'ai aucune trace de \u0002{nick}\u0002 ayant parlé dans \u0002{chan}\u0002.",
"{word} list for \u0002{name}\u0002:": "Liste {word} pour \u0002{name}\u0002 :",
"Type \u0002HELP <command>\u0002 for detail on one command.": "Tapez \u0002HELP <commande>\u0002 pour le détail d'une commande.",
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Aucune aide pour \u0002{t}\u0002. Tapez \u0002HELP\u0002 pour la liste des commandes."
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Aucune aide pour \u0002{t}\u0002. Tapez \u0002HELP\u0002 pour la liste des commandes.",
"Reopped \u0002{opped}\u0002 trusted regular in \u0002{chan}\u0002.": "\u0002{opped}\u0002 habitué de confiance réoppé dans \u0002{chan}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regulars in \u0002{chan}\u0002.": "\u0002{opped}\u0002 habitués de confiance réoppés dans \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 trigger from \u0002{chan}\u0002.": "\u0002{n}\u0002 déclencheur supprimé de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 triggers from \u0002{chan}\u0002.": "\u0002{n}\u0002 déclencheurs supprimés de \u0002{chan}\u0002.",
" Serving {count} channel: {list}": " Dessert {count} salon : {list}",
" Serving {count} channels: {list}": " Dessert {count} salons : {list}",
"Removed all \u0002{n}\u0002 bot.": "\u0002{n}\u0002 bot supprimé (tous).",
"Removed all \u0002{n}\u0002 bots.": "Tous les \u0002{n}\u0002 bots supprimés.",
"Cleared \u0002{n}\u0002 badword pattern from \u0002{chan}\u0002.": "\u0002{n}\u0002 motif d'insulte supprimé de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword patterns from \u0002{chan}\u0002.": "\u0002{n}\u0002 motifs d'insulte supprimés de \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick in \u0002{chan}\u0002.": "Le bot bannira un utilisateur après \u0002{n}\u0002 kick dans \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kicks in \u0002{chan}\u0002.": "Le bot bannira un utilisateur après \u0002{n}\u0002 kicks dans \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entry from \u0002{chan}\u0002's auto-kick list.": "\u0002{count}\u0002 entrée supprimée de la liste d'auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entries from \u0002{chan}\u0002's auto-kick list.": "\u0002{count}\u0002 entrées supprimées de la liste d'auto-kick de \u0002{chan}\u0002.",
"Top {shown} of {total} scored identity for \u0002{chan}\u0002.": "Top {shown} sur {total} identité notée pour \u0002{chan}\u0002.",
"Top {shown} of {total} scored identities for \u0002{chan}\u0002.": "Top {shown} sur {total} identités notées pour \u0002{chan}\u0002.",
"\u0002{n}\u0002 vote will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 vote fera désormais aboutir un \u0002!votekick\u0002/\u0002!voteban\u0002 dans \u0002{chan}\u0002.",
"\u0002{n}\u0002 votes will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 votes feront désormais aboutir un \u0002!votekick\u0002/\u0002!voteban\u0002 dans \u0002{chan}\u0002.",
"End of flags ({count} entry).": "Fin des flags ({count} entrée).",
"End of flags ({count} entries).": "Fin des flags ({count} entrées).",
"Deleted all \u0002{count}\u0002 memo.": "\u0002{count}\u0002 mémo supprimé (tous).",
"Deleted all \u0002{count}\u0002 memos.": "Tous les \u0002{count}\u0002 mémos supprimés.",
"Memo sent to \u0002{sent}\u0002 account.": "Mémo envoyé à \u0002{sent}\u0002 compte.",
"Memo sent to \u0002{sent}\u0002 accounts.": "Mémo envoyé à \u0002{sent}\u0002 comptes.",
"End of session list ({count} IP).": "Fin de la liste des sessions ({count} IP).",
"End of session list ({count} IPs).": "Fin de la liste des sessions ({count} IP).",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session.": "\u0002{ip}\u0002 a \u0002{count}\u0002 session active.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live sessions.": "\u0002{ip}\u0002 a \u0002{count}\u0002 sessions actives.",
"You have \u0002{total}\u0002 memo, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Vous avez \u0002{total}\u0002 mémo, \u0002{unread}\u0002 non lu, sur un maximum de \u0002{max}\u0002.",
"You have \u0002{total}\u0002 memos, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Vous avez \u0002{total}\u0002 mémos, \u0002{unread}\u0002 non lus, sur un maximum de \u0002{max}\u0002.",
"End of list — {count} match{more}.": "Fin de la liste — {count} correspondance{more}.",
"End of list — {count} matches{more}.": "Fin de la liste — {count} correspondances{more}.",
"Memo sent to \u0002{sent}\u0002 operator.": "Mémo envoyé à \u0002{sent}\u0002 opérateur.",
"Memo sent to \u0002{sent}\u0002 operators.": "Mémo envoyé à \u0002{sent}\u0002 opérateurs.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host AKILL'd.": "CHANKILL sur \u0002{chan}\u0002 : \u0002{banned}\u0002 hôte AKILL'd.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 hosts AKILL'd.": "CHANKILL sur \u0002{chan}\u0002 : \u0002{banned}\u0002 hôtes AKILL'd.",
" Auto-join : {count} channel — see \u0002AJOIN LIST\u0002": " Auto-join : {count} salon — voir \u0002AJOIN LIST\u0002",
" Auto-join : {count} channels — see \u0002AJOIN LIST\u0002": " Auto-join : {count} salons — voir \u0002AJOIN LIST\u0002",
"{count} ticket. \u0002VIEW\u0002 <id> for detail.": "{count} ticket. \u0002VIEW\u0002 <id> pour le détail.",
"{count} tickets. \u0002VIEW\u0002 <id> for detail.": "{count} tickets. \u0002VIEW\u0002 <id> pour le détail.",
"You have \u0002{unread}\u0002 new memo. Read it with \u0002/msg MemoServ READ NEW\u0002.": "Vous avez \u0002{unread}\u0002 nouveau mémo. Lisez-le avec \u0002/msg MemoServ READ NEW\u0002.",
"You have \u0002{unread}\u0002 new memos. Read them with \u0002/msg MemoServ READ NEW\u0002.": "Vous avez \u0002{unread}\u0002 nouveaux mémos. Lisez-les avec \u0002/msg MemoServ READ NEW\u0002.",
"Cleared \u0002{n}\u0002 notify watch.": "\u0002{n}\u0002 surveillance notify supprimée.",
"Cleared \u0002{n}\u0002 notify watches.": "\u0002{n}\u0002 surveillances notify supprimées.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 ligne vue.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 lines seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 lignes vues.",
"{n} report. \u0002VIEW\u0002 <id> for detail.": "{n} signalement. \u0002VIEW\u0002 <id> pour le détail.",
"{n} reports. \u0002VIEW\u0002 <id> for detail.": "{n} signalements. \u0002VIEW\u0002 <id> pour le détail.",
"End of list ({count} group).": "Fin de la liste ({count} groupe).",
"End of list ({count} groups).": "Fin de la liste ({count} groupes)."
}

View file

@ -61,7 +61,6 @@
"\u0002{chan}\u0002 isn't suspended.": "\u0002{chan}\u0002 não está suspenso.",
"\u0002{chan}\u0002 was already set that way.": "\u0002{chan}\u0002 já estava definido assim.",
"\u0002{chan}\u0002 will no longer expire.": "\u0002{chan}\u0002 não expirará mais.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line(s) seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 linha(s) vista(s).",
"\u0002{code}\u0002 isn't an available language. Available: {list}.": "\u0002{code}\u0002 não é um idioma disponível. Disponíveis: {list}.",
"\u0002{d}\u0002 isn't a valid expiry — try 30d, 12h, 45m, or 0.": "\u0002{d}\u0002 não é uma expiração válida — tente 30d, 12h, 45m ou 0.",
"\u0002{host}\u0002 is already in use. Please choose another.": "\u0002{host}\u0002 já está em uso. Por favor, escolha outro.",
@ -69,7 +68,6 @@
"\u0002{host}\u0002 isn't a valid host (letters, digits, hyphens and dots).": "\u0002{host}\u0002 não é um host válido (letras, dígitos, hifens e pontos).",
"\u0002{host}\u0002 isn't a valid host.": "\u0002{host}\u0002 não é um host válido.",
"\u0002{host}\u0002 isn't allowed here. Please choose another.": "\u0002{host}\u0002 não é permitido aqui. Por favor, escolha outro.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session(s).": "\u0002{ip}\u0002 tem \u0002{count}\u0002 sessão(ões) ativa(s).",
"\u0002{label}\u0002 access on \u0002{chan}\u0002: \u0002{level}\u0002": "\u0002{label}\u0002 acesso em \u0002{chan}\u0002: \u0002{level}\u0002",
"\u0002{mask}\u0002 isn't on \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 não está na lista de auto-kick de \u0002{chan}\u0002.",
"\u0002{mask}\u0002 isn't on the ignore list.": "\u0002{mask}\u0002 não está na lista de ignorados.",
@ -88,7 +86,6 @@
"\u0002{nick}\u0002 isn't grouped to your account.": "\u0002{nick}\u0002 não está agrupado à sua conta.",
"\u0002{nick}\u0002 isn't here.": "\u0002{nick}\u0002 não está aqui.",
"\u0002{nick}\u0002 was last seen {when} ({what}).": "\u0002{nick}\u0002 foi visto pela última vez {when} ({what}).",
"\u0002{n}\u0002 vote(s) will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto(s) agora acionarão um \u0002!votekick\u0002/\u0002!voteban\u0002 em \u0002{chan}\u0002.",
"\u0002{pattern}\u0002 isn't a valid regular expression.": "\u0002{pattern}\u0002 não é uma expressão regular válida.",
"\u0002{raw}\u0002 isn't a valid \u0002{target}\u0002 mask.": "\u0002{raw}\u0002 não é uma máscara \u0002{target}\u0002 válida.",
"\u0002{target}\u0002 had no access to \u0002{chan}\u0002.": "\u0002{target}\u0002 não tinha acesso a \u0002{chan}\u0002.",
@ -143,7 +140,6 @@
" (custom)": " (personalizado)",
" (no activity counters yet)": " (ainda sem contadores de atividade)",
" About : \u0002{target}\u0002": " Sobre : \u0002{target}\u0002",
" Auto-join : {count} channel(s) — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canal(is) — veja \u0002AJOIN LIST\u0002",
" By : \u0002{by}\u0002": " Por : \u0002{by}\u0002",
" Description: {desc}": " Descrição: {desc}",
" Email : (none set)": " Email : (nenhum definido)",
@ -165,7 +161,6 @@
" Real name: {gecos}": " Nome real: {gecos}",
" Reason : {reason}": " Motivo : {reason}",
" Registered : {when}": " Registrado : {when}",
" Serving {count} channel(s): {list}": " Atendendo {count} canal(is): {list}",
" Staff note : {note}": " Nota da equipe : {note}",
" Suspended : by \u0002{by}\u0002 — {reason}": " Suspenso : por \u0002{by}\u0002 — {reason}",
" URL : {url}": " URL : {url}",
@ -278,7 +273,6 @@
"Both channels must be registered.": "Ambos os canais precisam estar registrados.",
"Bots ({count}):": "Bots ({count}):",
"CALC and show each die": "CALC e mostrar cada dado",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILL'd.": "CHANKILL em \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) sob AKILL.",
"Can't activate: \u0002{host}\u0002 is on the forbidden list.": "Não é possível ativar: \u0002{host}\u0002 está na lista de proibidos.",
"Can't activate: {msg}": "Não é possível ativar: {msg}",
"Challenge \u0002#{id}\u0002 ({game}) sent to \u0002{target}\u0002.": "Desafio \u0002#{id}\u0002 ({game}) enviado a \u0002{target}\u0002.",
@ -291,10 +285,6 @@
"Channels released: {list}.": "Canais liberados: {list}.",
"Channels you have access on ({count}):": "Canais em que você tem acesso ({count}):",
"Classement \u0002{game}\u0002 vide. Sois le premier à gagner !": "Classificação de \u0002{game}\u0002 vazia. Seja o primeiro a vencer!",
"Cleared \u0002{count}\u0002 entr{suffix} from \u0002{chan}\u0002's auto-kick list.": "\u0002{count}\u0002 entrada{suffix} removida(s) da lista de auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword pattern(s) from \u0002{chan}\u0002.": "\u0002{n}\u0002 padrão(ões) de palavrão removido(s) de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 notify watch(es).": "\u0002{n}\u0002 observação(ões) de notify removida(s).",
"Cleared \u0002{n}\u0002 trigger(s) from \u0002{chan}\u0002.": "\u0002{n}\u0002 gatilho(s) removido(s) de \u0002{chan}\u0002.",
"Cleared \u0002{target}\u0002's access to \u0002{chan}\u0002.": "Acesso de \u0002{target}\u0002 a \u0002{chan}\u0002 removido.",
"Cleared the *!*@{host} ban on \u0002{chan}\u0002.": "Banimento *!*@{host} removido de \u0002{chan}\u0002.",
"Contact email for \u0002{chan}\u0002 cleared.": "Email de contato para \u0002{chan}\u0002 apagado.",
@ -306,22 +296,17 @@
"Couldn't update \u0002{chan}\u0002 — please try again in a moment.": "Não foi possível atualizar \u0002{chan}\u0002 — por favor tente novamente em um instante.",
"DEFCON set to \u0002{level}\u0002 — {desc}.": "DEFCON definido como \u0002{level}\u0002 — {desc}.",
"Declined.": "Recusado.",
"Deleted all \u0002{count}\u0002 memo(s).": "Todos os \u0002{count}\u0002 memorando(s) excluídos.",
"Description for \u0002{chan}\u0002 updated.": "Descrição para \u0002{chan}\u0002 atualizada.",
"DiceServ rolls dice and evaluates maths for tabletop games. Dice: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, and \u00023~2d6\u0002 to repeat.": "O DiceServ rola dados e avalia contas para jogos de mesa. Dados: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Também + - * / ^ %, parênteses, funções (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, e \u00023~2d6\u0002 para repetir.",
"DictServ looks words up in the dict.org dictionaries. Try \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, and more — \u0002LOOKUP\u0002 lists them all.": "O DictServ procura palavras nos dicionários do dict.org. Tente \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (dicionário de sinônimos), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, e mais — \u0002LOOKUP\u0002 lista todos.",
"Email for \u0002{account}\u0002 cleared.": "Email de \u0002{account}\u0002 apagado.",
"Email for \u0002{account}\u0002 updated.": "Email de \u0002{account}\u0002 atualizado.",
"End of exception list ({count} shown).": "Fim da lista de exceções ({count} mostrada(s)).",
"End of flags ({count} entr{suffix}).": "Fim das flags ({count} entrada{suffix}).",
"End of ignore list ({count} shown).": "Fim da lista de ignorados ({count} mostrada(s)).",
"End of jupe list ({count} shown).": "Fim da lista de jupes ({count} mostrada(s)).",
"End of list ({count} group(s)).": "Fim da lista ({count} grupo(s)).",
"End of list — {count} match(es){more}.": "Fim da lista — {count} correspondência(s){more}.",
"End of notify list ({shown} shown).": "Fim da lista de notify ({shown} mostrada(s)).",
"End of results ({count} shown, newest first — refine the search to narrow).": "Fim dos resultados ({count} mostrado(s), mais recentes primeiro — refine a busca para restringir).",
"End of runtime operator list ({count} shown).": "Fim da lista de operadores em tempo de execução ({count} mostrado(s)).",
"End of session list ({count} IP(s)).": "Fim da lista de sessões ({count} IP(s)).",
"End of spam-filter list ({shown} shown).": "Fim da lista de filtros de spam ({shown} mostrado(s)).",
"End of {name} list ({shown} shown).": "Fim da lista {name} ({shown} mostrado(s)).",
"End of {which} bulletins ({count} shown).": "Fim dos boletins {which} ({count} mostrado(s)).",
@ -387,8 +372,6 @@
"Mask must be a \u0002#channel\u0002, a \u0002nick!user@host\u0002 pattern, or a bare nick glob — and no spaces.": "A máscara deve ser um \u0002#channel\u0002, um padrão \u0002nick!user@host\u0002 ou um glob de apelido simples — e sem espaços.",
"Memo #\u0002{num}\u0002 from \u0002{from}\u0002 ({when}):": "Memorando #\u0002{num}\u0002 de \u0002{from}\u0002 ({when}):",
"Memo #\u0002{n}\u0002 deleted.": "Memorando #\u0002{n}\u0002 excluído.",
"Memo sent to \u0002{sent}\u0002 account(s).": "Memorando enviado a \u0002{sent}\u0002 conta(s).",
"Memo sent to \u0002{sent}\u0002 operator(s).": "Memorando enviado a \u0002{sent}\u0002 operador(es).",
"Memo sent to \u0002{target}\u0002.": "Memorando enviado a \u0002{target}\u0002.",
"MemoServ delivers messages to registered users, online or not. You must be identified to use it.": "O MemoServ entrega mensagens a usuários registrados, online ou não. Você precisa estar identificado para usá-lo.",
"Mode lock for \u0002{chan}\u0002 updated.": "Trava de modos para \u0002{chan}\u0002 atualizada.",
@ -485,12 +468,10 @@
"Removed \u0002{mask}\u0002 from \u0002{chan}\u0002's auto-kick list.": "Removido \u0002{mask}\u0002 da lista de expulsão automática de \u0002{chan}\u0002.",
"Removed \u0002{target}\u0002 from \u0002{name}\u0002.": "Removido \u0002{target}\u0002 de \u0002{name}\u0002.",
"Removed \u0002{which}\u0002 bulletin \u0002{n}\u0002.": "Removido o boletim \u0002{which}\u0002 \u0002{n}\u0002.",
"Removed all \u0002{n}\u0002 bot(s).": "Removidos todos os \u0002{n}\u0002 bot(s).",
"Removed badword pattern from \u0002{chan}\u0002.": "Removido o padrão de palavra proibida de \u0002{chan}\u0002.",
"Removed fingerprint \u0002{fp}\u0002.": "Removida a impressão digital \u0002{fp}\u0002.",
"Removed forbidden pattern: {pattern}": "Removido o padrão proibido: {pattern}",
"Removed the forbid on {label} \u0002{mask}\u0002.": "Removida a proibição sobre {label} \u0002{mask}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regular(s) in \u0002{chan}\u0002.": "Reopados \u0002{opped}\u0002 frequentador(es) confiável(is) em \u0002{chan}\u0002.",
"Report \u0002#{id}\u0002 ({state}):": "Denúncia \u0002#{id}\u0002 ({state}):",
"Report \u0002#{n}\u0002 closed.": "Denúncia \u0002#{n}\u0002 encerrada.",
"Report \u0002#{n}\u0002 deleted.": "Denúncia \u0002#{n}\u0002 excluída.",
@ -881,7 +862,6 @@
"The bot has left \u0002{chan}\u0002.": "O bot saiu de \u0002{chan}\u0002.",
"The bot may again kick channel operators in \u0002{chan}\u0002.": "O bot pode novamente expulsar operadores de canal em \u0002{chan}\u0002.",
"The bot may again kick voiced users in \u0002{chan}\u0002.": "O bot pode novamente expulsar usuários com voz em \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick(s) in \u0002{chan}\u0002.": "O bot vai banir um usuário após \u0002{n}\u0002 expulsão(ões) em \u0002{chan}\u0002.",
"The bot will kick without warning in \u0002{chan}\u0002.": "O bot vai expulsar sem aviso em \u0002{chan}\u0002.",
"The bot will no longer kick channel operators in \u0002{chan}\u0002.": "O bot não vai mais expulsar operadores de canal em \u0002{chan}\u0002.",
"The bot will no longer kick voiced users in \u0002{chan}\u0002.": "O bot não vai mais expulsar usuários com voz em \u0002{chan}\u0002.",
@ -927,7 +907,6 @@
"Ticket \u0002#{id}\u0002 isn't open (or doesn't exist).": "O ticket \u0002#{id}\u0002 não está aberto (ou não existe).",
"Too many failed attempts. Please wait {secs}s and try again.": "Muitas tentativas malsucedidas. Aguarde {secs}s e tente novamente.",
"Top talkers:": "Quem mais fala:",
"Top {shown} of {total} scored identit{suffix} for \u0002{chan}\u0002.": "Top {shown} de {total} identidade{suffix} pontuada(s) para \u0002{chan}\u0002.",
"Topic for \u0002{chan}\u0002 updated.": "Tópico de \u0002{chan}\u0002 atualizado.",
"Trigger #\u0002{n}\u0002 removed from \u0002{chan}\u0002.": "Gatilho #\u0002{n}\u0002 removido de \u0002{chan}\u0002.",
"Triggers for \u0002{chan}\u0002 ({count}):": "Gatilhos de \u0002{chan}\u0002 ({count}):",
@ -958,8 +937,6 @@
"You can't ungroup your main account name.": "Você não pode desagrupar o nome principal da sua conta.",
"You cannot challenge yourself.": "Você não pode desafiar a si mesmo.",
"You don't have an account to confirm.": "Você não tem uma conta para confirmar.",
"You have \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Você tem \u0002{total}\u0002 recado(s), \u0002{unread}\u0002 não lido(s), de um máximo de \u0002{max}\u0002.",
"You have \u0002{unread}\u0002 new memo(s). Read them with \u0002/msg MemoServ READ NEW\u0002.": "Você tem \u0002{unread}\u0002 recado(s) novo(s). Leia-os com \u0002/msg MemoServ READ NEW\u0002.",
"You have access on no channels.": "Você não tem acesso em nenhum canal.",
"You have no games. Use \u0002CHALLENGE <nick> <game>\u0002.": "Você não tem jogos. Use \u0002CHALLENGE <nick> <game>\u0002.",
"You have no memo #\u0002{n}\u0002.": "Você não tem o recado #\u0002{n}\u0002.",
@ -1258,7 +1235,6 @@
"your mailbox summary": "resumo da sua caixa de correio",
"your memo preferences": "suas preferências de recado",
"{challenger} challenges you to {game} (game #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002": "{challenger} desafia você para {game} (jogo #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002",
"{count} ticket(s). \u0002VIEW\u0002 <id> for detail.": "{count} ticket(s). \u0002VIEW\u0002 <id> para detalhes.",
"{name} added for \u0002{mask}\u0002 (temporary).": "{name} adicionado para \u0002{mask}\u0002 (temporário).",
"{name} added for \u0002{mask}\u0002.": "{name} adicionado para \u0002{mask}\u0002.",
"{name} for \u0002{mask}\u0002 removed.": "{name} para \u0002{mask}\u0002 removido.",
@ -1266,7 +1242,6 @@
"{name} updated for \u0002{mask}\u0002.": "{name} atualizado para \u0002{mask}\u0002.",
"{nick} declined your challenge #{id}.": "{nick} recusou seu desafio #{id}.",
"{num}. {text} — by {by}": "{num}. {text} — por {by}",
"{n} report(s). \u0002VIEW\u0002 <id> for detail.": "{n} denúncia(s). \u0002VIEW\u0002 <id> para detalhes.",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}) — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}) — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}), expires in {ttl} — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}), expira em {ttl} — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] — {reason}",
@ -1283,5 +1258,55 @@
"{who}: I have no record of \u0002{nick}\u0002 talking in \u0002{chan}\u0002.": "{who}: Não tenho registro de \u0002{nick}\u0002 falando em \u0002{chan}\u0002.",
"{word} list for \u0002{name}\u0002:": "lista de {word} para \u0002{name}\u0002:",
"Type \u0002HELP <command>\u0002 for detail on one command.": "Digite \u0002HELP <command>\u0002 para detalhes sobre um comando.",
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Sem ajuda para \u0002{t}\u0002. Digite \u0002HELP\u0002 para a lista de comandos."
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Sem ajuda para \u0002{t}\u0002. Digite \u0002HELP\u0002 para a lista de comandos.",
"Reopped \u0002{opped}\u0002 trusted regular in \u0002{chan}\u0002.": "Reopado \u0002{opped}\u0002 frequentador confiável em \u0002{chan}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regulars in \u0002{chan}\u0002.": "Reopados \u0002{opped}\u0002 frequentadores confiáveis em \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 trigger from \u0002{chan}\u0002.": "Removido \u0002{n}\u0002 gatilho de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 triggers from \u0002{chan}\u0002.": "Removidos \u0002{n}\u0002 gatilhos de \u0002{chan}\u0002.",
" Serving {count} channel: {list}": " Atendendo {count} canal: {list}",
" Serving {count} channels: {list}": " Atendendo {count} canais: {list}",
"Removed all \u0002{n}\u0002 bot.": "Removido todo o \u0002{n}\u0002 bot.",
"Removed all \u0002{n}\u0002 bots.": "Removidos todos os \u0002{n}\u0002 bots.",
"Cleared \u0002{n}\u0002 badword pattern from \u0002{chan}\u0002.": "Removido \u0002{n}\u0002 padrão de palavrão de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword patterns from \u0002{chan}\u0002.": "Removidos \u0002{n}\u0002 padrões de palavrão de \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick in \u0002{chan}\u0002.": "O bot vai banir um usuário após \u0002{n}\u0002 expulsão em \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kicks in \u0002{chan}\u0002.": "O bot vai banir um usuário após \u0002{n}\u0002 expulsões em \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entry from \u0002{chan}\u0002's auto-kick list.": "Removida \u0002{count}\u0002 entrada da lista de auto-expulsão de \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entries from \u0002{chan}\u0002's auto-kick list.": "Removidas \u0002{count}\u0002 entradas da lista de auto-expulsão de \u0002{chan}\u0002.",
"Top {shown} of {total} scored identity for \u0002{chan}\u0002.": "As {shown} melhores de {total} identidade pontuada para \u0002{chan}\u0002.",
"Top {shown} of {total} scored identities for \u0002{chan}\u0002.": "As {shown} melhores de {total} identidades pontuadas para \u0002{chan}\u0002.",
"\u0002{n}\u0002 vote will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto agora será necessário para um \u0002!votekick\u0002/\u0002!voteban\u0002 em \u0002{chan}\u0002.",
"\u0002{n}\u0002 votes will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 votos agora serão necessários para um \u0002!votekick\u0002/\u0002!voteban\u0002 em \u0002{chan}\u0002.",
"End of flags ({count} entry).": "Fim das permissões ({count} entrada).",
"End of flags ({count} entries).": "Fim das permissões ({count} entradas).",
"Deleted all \u0002{count}\u0002 memo.": "Apagado todo \u0002{count}\u0002 memorando.",
"Deleted all \u0002{count}\u0002 memos.": "Apagados todos os \u0002{count}\u0002 memorandos.",
"Memo sent to \u0002{sent}\u0002 account.": "Memorando enviado para \u0002{sent}\u0002 conta.",
"Memo sent to \u0002{sent}\u0002 accounts.": "Memorando enviado para \u0002{sent}\u0002 contas.",
"End of session list ({count} IP).": "Fim da lista de sessões ({count} IP).",
"End of session list ({count} IPs).": "Fim da lista de sessões ({count} IPs).",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session.": "\u0002{ip}\u0002 tem \u0002{count}\u0002 sessão ativa.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live sessions.": "\u0002{ip}\u0002 tem \u0002{count}\u0002 sessões ativas.",
"You have \u0002{total}\u0002 memo, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Você tem \u0002{total}\u0002 memorando, \u0002{unread}\u0002 não lido, de um máximo de \u0002{max}\u0002.",
"You have \u0002{total}\u0002 memos, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Você tem \u0002{total}\u0002 memorandos, \u0002{unread}\u0002 não lidos, de um máximo de \u0002{max}\u0002.",
"End of list — {count} match{more}.": "Fim da lista — {count} resultado{more}.",
"End of list — {count} matches{more}.": "Fim da lista — {count} resultados{more}.",
"Memo sent to \u0002{sent}\u0002 operator.": "Memorando enviado para \u0002{sent}\u0002 operador.",
"Memo sent to \u0002{sent}\u0002 operators.": "Memorando enviado para \u0002{sent}\u0002 operadores.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host AKILL'd.": "CHANKILL em \u0002{chan}\u0002: \u0002{banned}\u0002 host recebeu AKILL.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 hosts AKILL'd.": "CHANKILL em \u0002{chan}\u0002: \u0002{banned}\u0002 hosts receberam AKILL.",
" Auto-join : {count} channel — see \u0002AJOIN LIST\u0002": " Auto-entrada : {count} canal — veja \u0002AJOIN LIST\u0002",
" Auto-join : {count} channels — see \u0002AJOIN LIST\u0002": " Auto-entrada : {count} canais — veja \u0002AJOIN LIST\u0002",
"{count} ticket. \u0002VIEW\u0002 <id> for detail.": "{count} ticket. \u0002VIEW\u0002 <id> para detalhes.",
"{count} tickets. \u0002VIEW\u0002 <id> for detail.": "{count} tickets. \u0002VIEW\u0002 <id> para detalhes.",
"You have \u0002{unread}\u0002 new memo. Read it with \u0002/msg MemoServ READ NEW\u0002.": "Você tem \u0002{unread}\u0002 novo memorando. Leia com \u0002/msg MemoServ READ NEW\u0002.",
"You have \u0002{unread}\u0002 new memos. Read them with \u0002/msg MemoServ READ NEW\u0002.": "Você tem \u0002{unread}\u0002 novos memorandos. Leia com \u0002/msg MemoServ READ NEW\u0002.",
"Cleared \u0002{n}\u0002 notify watch.": "Removida \u0002{n}\u0002 observação de notificação.",
"Cleared \u0002{n}\u0002 notify watches.": "Removidas \u0002{n}\u0002 observações de notificação.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 linha vista.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 lines seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 linhas vistas.",
"{n} report. \u0002VIEW\u0002 <id> for detail.": "{n} denúncia. \u0002VIEW\u0002 <id> para detalhes.",
"{n} reports. \u0002VIEW\u0002 <id> for detail.": "{n} denúncias. \u0002VIEW\u0002 <id> para detalhes.",
"End of list ({count} group).": "Fim da lista ({count} grupo).",
"End of list ({count} groups).": "Fim da lista ({count} grupos)."
}

View file

@ -61,7 +61,6 @@
"\u0002{chan}\u0002 isn't suspended.": "\u0002{chan}\u0002 não está suspenso.",
"\u0002{chan}\u0002 was already set that way.": "\u0002{chan}\u0002 já estava definido dessa forma.",
"\u0002{chan}\u0002 will no longer expire.": "\u0002{chan}\u0002 já não vai expirar.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line(s) seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 linha(s) vista(s).",
"\u0002{code}\u0002 isn't an available language. Available: {list}.": "\u0002{code}\u0002 não é um idioma disponível. Disponíveis: {list}.",
"\u0002{d}\u0002 isn't a valid expiry — try 30d, 12h, 45m, or 0.": "\u0002{d}\u0002 não é uma expiração válida — tente 30d, 12h, 45m ou 0.",
"\u0002{host}\u0002 is already in use. Please choose another.": "\u0002{host}\u0002 já está em uso. Por favor escolha outro.",
@ -69,7 +68,6 @@
"\u0002{host}\u0002 isn't a valid host (letters, digits, hyphens and dots).": "\u0002{host}\u0002 não é um host válido (letras, dígitos, hífens e pontos).",
"\u0002{host}\u0002 isn't a valid host.": "\u0002{host}\u0002 não é um host válido.",
"\u0002{host}\u0002 isn't allowed here. Please choose another.": "\u0002{host}\u0002 não é permitido aqui. Por favor escolha outro.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session(s).": "\u0002{ip}\u0002 tem \u0002{count}\u0002 sessão(ões) ativa(s).",
"\u0002{label}\u0002 access on \u0002{chan}\u0002: \u0002{level}\u0002": "Acesso \u0002{label}\u0002 em \u0002{chan}\u0002: \u0002{level}\u0002",
"\u0002{mask}\u0002 isn't on \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 não está na lista de auto-kick de \u0002{chan}\u0002.",
"\u0002{mask}\u0002 isn't on the ignore list.": "\u0002{mask}\u0002 não está na lista de ignorados.",
@ -88,7 +86,6 @@
"\u0002{nick}\u0002 isn't grouped to your account.": "\u0002{nick}\u0002 não está agrupado à sua conta.",
"\u0002{nick}\u0002 isn't here.": "\u0002{nick}\u0002 não está aqui.",
"\u0002{nick}\u0002 was last seen {when} ({what}).": "\u0002{nick}\u0002 foi visto pela última vez {when} ({what}).",
"\u0002{n}\u0002 vote(s) will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto(s) irão agora accionar um \u0002!votekick\u0002/\u0002!voteban\u0002 em \u0002{chan}\u0002.",
"\u0002{pattern}\u0002 isn't a valid regular expression.": "\u0002{pattern}\u0002 não é uma expressão regular válida.",
"\u0002{raw}\u0002 isn't a valid \u0002{target}\u0002 mask.": "\u0002{raw}\u0002 não é uma máscara \u0002{target}\u0002 válida.",
"\u0002{target}\u0002 had no access to \u0002{chan}\u0002.": "\u0002{target}\u0002 não tinha acesso a \u0002{chan}\u0002.",
@ -143,7 +140,6 @@
" (custom)": " (personalizado)",
" (no activity counters yet)": " (ainda sem contadores de atividade)",
" About : \u0002{target}\u0002": " Sobre : \u0002{target}\u0002",
" Auto-join : {count} channel(s) — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canal(is) — ver \u0002AJOIN LIST\u0002",
" By : \u0002{by}\u0002": " Por : \u0002{by}\u0002",
" Description: {desc}": " Descrição : {desc}",
" Email : (none set)": " Email : (nenhum definido)",
@ -165,7 +161,6 @@
" Real name: {gecos}": " Nome real: {gecos}",
" Reason : {reason}": " Motivo : {reason}",
" Registered : {when}": " Registado : {when}",
" Serving {count} channel(s): {list}": " A servir {count} canal(is): {list}",
" Staff note : {note}": " Nota da equipa : {note}",
" Suspended : by \u0002{by}\u0002 — {reason}": " Suspenso : por \u0002{by}\u0002 — {reason}",
" URL : {url}": " URL : {url}",
@ -278,7 +273,6 @@
"Both channels must be registered.": "Ambos os canais têm de estar registados.",
"Bots ({count}):": "Bots ({count}):",
"CALC and show each die": "CALC e mostrar cada dado",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) AKILL'd.": "CHANKILL em \u0002{chan}\u0002: \u0002{banned}\u0002 host(s) com AKILL aplicado.",
"Can't activate: \u0002{host}\u0002 is on the forbidden list.": "Não é possível ativar: \u0002{host}\u0002 está na lista de proibidos.",
"Can't activate: {msg}": "Não é possível ativar: {msg}",
"Challenge \u0002#{id}\u0002 ({game}) sent to \u0002{target}\u0002.": "Desafio \u0002#{id}\u0002 ({game}) enviado a \u0002{target}\u0002.",
@ -291,10 +285,6 @@
"Channels released: {list}.": "Canais libertados: {list}.",
"Channels you have access on ({count}):": "Canais a que tem acesso ({count}):",
"Classement \u0002{game}\u0002 vide. Sois le premier à gagner !": "Classificação de \u0002{game}\u0002 vazia. Seja o primeiro a ganhar!",
"Cleared \u0002{count}\u0002 entr{suffix} from \u0002{chan}\u0002's auto-kick list.": "Removida(s) \u0002{count}\u0002 entrada{suffix} da lista de auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword pattern(s) from \u0002{chan}\u0002.": "Removido(s) \u0002{n}\u0002 padrão(ões) de palavras proibidas de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 notify watch(es).": "Removida(s) \u0002{n}\u0002 vigilância(s) de notificação.",
"Cleared \u0002{n}\u0002 trigger(s) from \u0002{chan}\u0002.": "Removido(s) \u0002{n}\u0002 trigger(s) de \u0002{chan}\u0002.",
"Cleared \u0002{target}\u0002's access to \u0002{chan}\u0002.": "Removido o acesso de \u0002{target}\u0002 a \u0002{chan}\u0002.",
"Cleared the *!*@{host} ban on \u0002{chan}\u0002.": "Removido o ban *!*@{host} em \u0002{chan}\u0002.",
"Contact email for \u0002{chan}\u0002 cleared.": "Email de contacto para \u0002{chan}\u0002 removido.",
@ -306,22 +296,17 @@
"Couldn't update \u0002{chan}\u0002 — please try again in a moment.": "Não foi possível atualizar \u0002{chan}\u0002 — por favor tente novamente daqui a instantes.",
"DEFCON set to \u0002{level}\u0002 — {desc}.": "DEFCON definido para \u0002{level}\u0002 — {desc}.",
"Declined.": "Recusado.",
"Deleted all \u0002{count}\u0002 memo(s).": "Eliminados todos os \u0002{count}\u0002 memo(s).",
"Description for \u0002{chan}\u0002 updated.": "Descrição de \u0002{chan}\u0002 atualizada.",
"DiceServ rolls dice and evaluates maths for tabletop games. Dice: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Also + - * / ^ %, parentheses, functions (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, and \u00023~2d6\u0002 to repeat.": "O DiceServ lança dados e avalia expressões matemáticas para jogos de tabuleiro. Dados: \u00022d6\u0002, \u0002d20\u0002, \u0002d%\u0002. Também + - * / ^ %, parênteses, funções (sqrt, floor, min, ...), \u0002pi\u0002/\u0002e\u0002, e \u00023~2d6\u0002 para repetir.",
"DictServ looks words up in the dict.org dictionaries. Try \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (thesaurus), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, and more — \u0002LOOKUP\u0002 lists them all.": "O DictServ procura palavras nos dicionários do dict.org. Tente \u0002dict\u0002 <word> (WordNet), \u0002define\u0002 (GCIDE), \u0002thes\u0002 (dicionário de sinónimos), \u0002acronym\u0002, \u0002element\u0002, \u0002law\u0002, \u0002bible\u0002, e mais — \u0002LOOKUP\u0002 lista todos.",
"Email for \u0002{account}\u0002 cleared.": "Email de \u0002{account}\u0002 removido.",
"Email for \u0002{account}\u0002 updated.": "Email de \u0002{account}\u0002 atualizado.",
"End of exception list ({count} shown).": "Fim da lista de exceções ({count} mostradas).",
"End of flags ({count} entr{suffix}).": "Fim das flags ({count} entrada{suffix}).",
"End of ignore list ({count} shown).": "Fim da lista de ignorados ({count} mostrados).",
"End of jupe list ({count} shown).": "Fim da lista de jupes ({count} mostrados).",
"End of list ({count} group(s)).": "Fim da lista ({count} grupo(s)).",
"End of list — {count} match(es){more}.": "Fim da lista — {count} correspondência(s){more}.",
"End of notify list ({shown} shown).": "Fim da lista de notificações ({shown} mostradas).",
"End of results ({count} shown, newest first — refine the search to narrow).": "Fim dos resultados ({count} mostrados, mais recentes primeiro — refine a pesquisa para restringir).",
"End of runtime operator list ({count} shown).": "Fim da lista de operadores de runtime ({count} mostrados).",
"End of session list ({count} IP(s)).": "Fim da lista de sessões ({count} IP(s)).",
"End of spam-filter list ({shown} shown).": "Fim da lista de spam-filter ({shown} mostrados).",
"End of {name} list ({shown} shown).": "Fim da lista {name} ({shown} mostrados).",
"End of {which} bulletins ({count} shown).": "Fim dos boletins {which} ({count} mostrados).",
@ -387,8 +372,6 @@
"Mask must be a \u0002#channel\u0002, a \u0002nick!user@host\u0002 pattern, or a bare nick glob — and no spaces.": "A máscara tem de ser um \u0002#channel\u0002, um padrão \u0002nick!user@host\u0002, ou um glob de alcunha simples — e sem espaços.",
"Memo #\u0002{num}\u0002 from \u0002{from}\u0002 ({when}):": "Memo #\u0002{num}\u0002 de \u0002{from}\u0002 ({when}):",
"Memo #\u0002{n}\u0002 deleted.": "Memo #\u0002{n}\u0002 eliminado.",
"Memo sent to \u0002{sent}\u0002 account(s).": "Memo enviado a \u0002{sent}\u0002 conta(s).",
"Memo sent to \u0002{sent}\u0002 operator(s).": "Memo enviado a \u0002{sent}\u0002 operador(es).",
"Memo sent to \u0002{target}\u0002.": "Memo enviado a \u0002{target}\u0002.",
"MemoServ delivers messages to registered users, online or not. You must be identified to use it.": "O MemoServ entrega mensagens a utilizadores registados, online ou não. Tem de estar identificado para o usar.",
"Mode lock for \u0002{chan}\u0002 updated.": "Bloqueio de modos de \u0002{chan}\u0002 atualizado.",
@ -485,12 +468,10 @@
"Removed \u0002{mask}\u0002 from \u0002{chan}\u0002's auto-kick list.": "\u0002{mask}\u0002 removido da lista de auto-expulsão de \u0002{chan}\u0002.",
"Removed \u0002{target}\u0002 from \u0002{name}\u0002.": "\u0002{target}\u0002 removido de \u0002{name}\u0002.",
"Removed \u0002{which}\u0002 bulletin \u0002{n}\u0002.": "Boletim \u0002{which}\u0002 \u0002{n}\u0002 removido.",
"Removed all \u0002{n}\u0002 bot(s).": "Removidos todos os \u0002{n}\u0002 bot(s).",
"Removed badword pattern from \u0002{chan}\u0002.": "Padrão de palavrão removido de \u0002{chan}\u0002.",
"Removed fingerprint \u0002{fp}\u0002.": "Impressão digital \u0002{fp}\u0002 removida.",
"Removed forbidden pattern: {pattern}": "Padrão proibido removido: {pattern}",
"Removed the forbid on {label} \u0002{mask}\u0002.": "Proibição de {label} \u0002{mask}\u0002 removida.",
"Reopped \u0002{opped}\u0002 trusted regular(s) in \u0002{chan}\u0002.": "Dei op novamente a \u0002{opped}\u0002 frequentador(es) de confiança em \u0002{chan}\u0002.",
"Report \u0002#{id}\u0002 ({state}):": "Denúncia \u0002#{id}\u0002 ({state}):",
"Report \u0002#{n}\u0002 closed.": "Denúncia \u0002#{n}\u0002 fechada.",
"Report \u0002#{n}\u0002 deleted.": "Denúncia \u0002#{n}\u0002 eliminada.",
@ -881,7 +862,6 @@
"The bot has left \u0002{chan}\u0002.": "O bot saiu de \u0002{chan}\u0002.",
"The bot may again kick channel operators in \u0002{chan}\u0002.": "O bot pode voltar a expulsar operadores de canal em \u0002{chan}\u0002.",
"The bot may again kick voiced users in \u0002{chan}\u0002.": "O bot pode voltar a expulsar utilizadores com voz em \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick(s) in \u0002{chan}\u0002.": "O bot irá banir um utilizador após \u0002{n}\u0002 expulsão(ões) em \u0002{chan}\u0002.",
"The bot will kick without warning in \u0002{chan}\u0002.": "O bot irá expulsar sem aviso em \u0002{chan}\u0002.",
"The bot will no longer kick channel operators in \u0002{chan}\u0002.": "O bot deixará de expulsar operadores de canal em \u0002{chan}\u0002.",
"The bot will no longer kick voiced users in \u0002{chan}\u0002.": "O bot deixará de expulsar utilizadores com voz em \u0002{chan}\u0002.",
@ -927,7 +907,6 @@
"Ticket \u0002#{id}\u0002 isn't open (or doesn't exist).": "O bilhete \u0002#{id}\u0002 não está aberto (ou não existe).",
"Too many failed attempts. Please wait {secs}s and try again.": "Demasiadas tentativas falhadas. Aguarde {secs}s e tente novamente.",
"Top talkers:": "Quem mais fala:",
"Top {shown} of {total} scored identit{suffix} for \u0002{chan}\u0002.": "Top {shown} de {total} identidad{suffix} pontuada(s) para \u0002{chan}\u0002.",
"Topic for \u0002{chan}\u0002 updated.": "Tópico de \u0002{chan}\u0002 atualizado.",
"Trigger #\u0002{n}\u0002 removed from \u0002{chan}\u0002.": "Acionador #\u0002{n}\u0002 removido de \u0002{chan}\u0002.",
"Triggers for \u0002{chan}\u0002 ({count}):": "Acionadores de \u0002{chan}\u0002 ({count}):",
@ -958,8 +937,6 @@
"You can't ungroup your main account name.": "Não pode desagrupar o nome da sua conta principal.",
"You cannot challenge yourself.": "Não pode desafiar-se a si próprio.",
"You don't have an account to confirm.": "Não tem nenhuma conta para confirmar.",
"You have \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tem \u0002{total}\u0002 memo(s), \u0002{unread}\u0002 por ler, de um máximo de \u0002{max}\u0002.",
"You have \u0002{unread}\u0002 new memo(s). Read them with \u0002/msg MemoServ READ NEW\u0002.": "Tem \u0002{unread}\u0002 memo(s) novo(s). Leia-os com \u0002/msg MemoServ READ NEW\u0002.",
"You have access on no channels.": "Não tem acesso a nenhum canal.",
"You have no games. Use \u0002CHALLENGE <nick> <game>\u0002.": "Não tem jogos. Use \u0002CHALLENGE <nick> <game>\u0002.",
"You have no memo #\u0002{n}\u0002.": "Não tem nenhum memo #\u0002{n}\u0002.",
@ -1258,7 +1235,6 @@
"your mailbox summary": "o resumo da sua caixa de correio",
"your memo preferences": "as suas preferências de memos",
"{challenger} challenges you to {game} (game #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002": "{challenger} desafia-o para {game} (jogo #{id}). \u0002/msg GamesServ ACCEPT {id}\u0002",
"{count} ticket(s). \u0002VIEW\u0002 <id> for detail.": "{count} bilhete(s). \u0002VIEW\u0002 <id> para detalhes.",
"{name} added for \u0002{mask}\u0002 (temporary).": "{name} adicionado para \u0002{mask}\u0002 (temporário).",
"{name} added for \u0002{mask}\u0002.": "{name} adicionado para \u0002{mask}\u0002.",
"{name} for \u0002{mask}\u0002 removed.": "{name} para \u0002{mask}\u0002 removido.",
@ -1266,7 +1242,6 @@
"{name} updated for \u0002{mask}\u0002.": "{name} atualizado para \u0002{mask}\u0002.",
"{nick} declined your challenge #{id}.": "{nick} recusou o seu desafio #{id}.",
"{num}. {text} — by {by}": "{num}. {text} — por {by}",
"{n} report(s). \u0002VIEW\u0002 <id> for detail.": "{n} relatório(s). \u0002VIEW\u0002 <id> para detalhes.",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}) — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}) — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] by {setter} ({when}), expires in {ttl} — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] por {setter} ({when}), expira em {ttl} — {reason}",
"{n}. \u0002{mask}\u0002 [{flags}] — {reason}": "{n}. \u0002{mask}\u0002 [{flags}] — {reason}",
@ -1283,5 +1258,55 @@
"{who}: I have no record of \u0002{nick}\u0002 talking in \u0002{chan}\u0002.": "{who}: não tenho registo de \u0002{nick}\u0002 a falar em \u0002{chan}\u0002.",
"{word} list for \u0002{name}\u0002:": "lista de {word} para \u0002{name}\u0002:",
"Type \u0002HELP <command>\u0002 for detail on one command.": "Escreva \u0002HELP <command>\u0002 para detalhes sobre um comando.",
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Sem ajuda para \u0002{t}\u0002. Escreva \u0002HELP\u0002 para a lista de comandos."
"No help for \u0002{t}\u0002. Type \u0002HELP\u0002 for the command list.": "Sem ajuda para \u0002{t}\u0002. Escreva \u0002HELP\u0002 para a lista de comandos.",
"Reopped \u0002{opped}\u0002 trusted regular in \u0002{chan}\u0002.": "Op devolvido a \u0002{opped}\u0002 habitual de confiança em \u0002{chan}\u0002.",
"Reopped \u0002{opped}\u0002 trusted regulars in \u0002{chan}\u0002.": "Op devolvido a \u0002{opped}\u0002 habituais de confiança em \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 trigger from \u0002{chan}\u0002.": "Removido \u0002{n}\u0002 gatilho de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 triggers from \u0002{chan}\u0002.": "Removidos \u0002{n}\u0002 gatilhos de \u0002{chan}\u0002.",
" Serving {count} channel: {list}": " A servir {count} canal: {list}",
" Serving {count} channels: {list}": " A servir {count} canais: {list}",
"Removed all \u0002{n}\u0002 bot.": "Removido \u0002{n}\u0002 bot.",
"Removed all \u0002{n}\u0002 bots.": "Removidos todos os \u0002{n}\u0002 bots.",
"Cleared \u0002{n}\u0002 badword pattern from \u0002{chan}\u0002.": "Removido \u0002{n}\u0002 padrão de palavrão de \u0002{chan}\u0002.",
"Cleared \u0002{n}\u0002 badword patterns from \u0002{chan}\u0002.": "Removidos \u0002{n}\u0002 padrões de palavrão de \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kick in \u0002{chan}\u0002.": "O bot irá banir um utilizador após \u0002{n}\u0002 expulsão em \u0002{chan}\u0002.",
"The bot will ban a user after \u0002{n}\u0002 kicks in \u0002{chan}\u0002.": "O bot irá banir um utilizador após \u0002{n}\u0002 expulsões em \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entry from \u0002{chan}\u0002's auto-kick list.": "Removida \u0002{count}\u0002 entrada da lista de auto-kick de \u0002{chan}\u0002.",
"Cleared \u0002{count}\u0002 entries from \u0002{chan}\u0002's auto-kick list.": "Removidas \u0002{count}\u0002 entradas da lista de auto-kick de \u0002{chan}\u0002.",
"Top {shown} of {total} scored identity for \u0002{chan}\u0002.": "Top {shown} de {total} identidade pontuada para \u0002{chan}\u0002.",
"Top {shown} of {total} scored identities for \u0002{chan}\u0002.": "Top {shown} de {total} identidades pontuadas para \u0002{chan}\u0002.",
"\u0002{n}\u0002 vote will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 voto passará a bastar para um \u0002!votekick\u0002/\u0002!voteban\u0002 em \u0002{chan}\u0002.",
"\u0002{n}\u0002 votes will now carry a \u0002!votekick\u0002/\u0002!voteban\u0002 in \u0002{chan}\u0002.": "\u0002{n}\u0002 votos passarão a bastar para um \u0002!votekick\u0002/\u0002!voteban\u0002 em \u0002{chan}\u0002.",
"End of flags ({count} entry).": "Fim das flags ({count} entrada).",
"End of flags ({count} entries).": "Fim das flags ({count} entradas).",
"Deleted all \u0002{count}\u0002 memo.": "Eliminado \u0002{count}\u0002 memo.",
"Deleted all \u0002{count}\u0002 memos.": "Eliminados todos os \u0002{count}\u0002 memos.",
"Memo sent to \u0002{sent}\u0002 account.": "Memo enviado para \u0002{sent}\u0002 conta.",
"Memo sent to \u0002{sent}\u0002 accounts.": "Memo enviado para \u0002{sent}\u0002 contas.",
"End of session list ({count} IP).": "Fim da lista de sessões ({count} IP).",
"End of session list ({count} IPs).": "Fim da lista de sessões ({count} IPs).",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live session.": "\u0002{ip}\u0002 tem \u0002{count}\u0002 sessão ativa.",
"\u0002{ip}\u0002 has \u0002{count}\u0002 live sessions.": "\u0002{ip}\u0002 tem \u0002{count}\u0002 sessões ativas.",
"You have \u0002{total}\u0002 memo, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tem \u0002{total}\u0002 memo, \u0002{unread}\u0002 por ler, de um máximo de \u0002{max}\u0002.",
"You have \u0002{total}\u0002 memos, \u0002{unread}\u0002 unread, of a maximum \u0002{max}\u0002.": "Tem \u0002{total}\u0002 memos, \u0002{unread}\u0002 por ler, de um máximo de \u0002{max}\u0002.",
"End of list — {count} match{more}.": "Fim da lista — {count} correspondência{more}.",
"End of list — {count} matches{more}.": "Fim da lista — {count} correspondências{more}.",
"Memo sent to \u0002{sent}\u0002 operator.": "Memo enviado para \u0002{sent}\u0002 operador.",
"Memo sent to \u0002{sent}\u0002 operators.": "Memo enviado para \u0002{sent}\u0002 operadores.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 host AKILL'd.": "CHANKILL em \u0002{chan}\u0002: \u0002{banned}\u0002 host recebeu AKILL.",
"CHANKILL on \u0002{chan}\u0002: \u0002{banned}\u0002 hosts AKILL'd.": "CHANKILL em \u0002{chan}\u0002: \u0002{banned}\u0002 hosts receberam AKILL.",
" Auto-join : {count} channel — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canal — ver \u0002AJOIN LIST\u0002",
" Auto-join : {count} channels — see \u0002AJOIN LIST\u0002": " Auto-join : {count} canais — ver \u0002AJOIN LIST\u0002",
"{count} ticket. \u0002VIEW\u0002 <id> for detail.": "{count} ticket. \u0002VIEW\u0002 <id> para detalhes.",
"{count} tickets. \u0002VIEW\u0002 <id> for detail.": "{count} tickets. \u0002VIEW\u0002 <id> para detalhes.",
"You have \u0002{unread}\u0002 new memo. Read it with \u0002/msg MemoServ READ NEW\u0002.": "Tem \u0002{unread}\u0002 memo novo. Leia-o com \u0002/msg MemoServ READ NEW\u0002.",
"You have \u0002{unread}\u0002 new memos. Read them with \u0002/msg MemoServ READ NEW\u0002.": "Tem \u0002{unread}\u0002 memos novos. Leia-os com \u0002/msg MemoServ READ NEW\u0002.",
"Cleared \u0002{n}\u0002 notify watch.": "Removido \u0002{n}\u0002 alerta de notificação.",
"Cleared \u0002{n}\u0002 notify watches.": "Removidos \u0002{n}\u0002 alertas de notificação.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 line seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 linha vista.",
"\u0002{chan}\u0002 — \u0002{lines}\u0002 lines seen.": "\u0002{chan}\u0002 — \u0002{lines}\u0002 linhas vistas.",
"{n} report. \u0002VIEW\u0002 <id> for detail.": "{n} denúncia. \u0002VIEW\u0002 <id> para detalhes.",
"{n} reports. \u0002VIEW\u0002 <id> for detail.": "{n} denúncias. \u0002VIEW\u0002 <id> para detalhes.",
"End of list ({count} group).": "Fim da lista ({count} grupo).",
"End of list ({count} groups).": "Fim da lista ({count} grupos)."
}

View file

@ -40,7 +40,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
}
}
Some("CLEAR") => match db.badword_clear(chan) {
Ok(n) => ctx.notice(me, from.uid, t!(ctx, "Cleared \x02{n}\x02 badword pattern(s) from \x02{chan}\x02.", n = n, chan = chan)),
Ok(n) => ctx.notice(me, from.uid, echo_api::plural!(ctx, n, one = "Cleared \x02{n}\x02 badword pattern from \x02{chan}\x02.", other = "Cleared \x02{n}\x02 badword patterns from \x02{chan}\x02.", n = n, chan = chan)),
Err(_) => reg_error(me, from, chan, ctx),
},
None | Some("LIST") => {

View file

@ -45,7 +45,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
};
if nick == "*" {
match db.bot_del_all() {
Ok(n) => ctx.notice(me, from.uid, t!(ctx, "Removed all \x02{n}\x02 bot(s).", n = n)),
Ok(n) => ctx.notice(me, from.uid, echo_api::plural!(ctx, n, one = "Removed all \x02{n}\x02 bot.", other = "Removed all \x02{n}\x02 bots.", n = n)),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
}
return;

View file

@ -50,6 +50,6 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
if channels.is_empty() {
ctx.notice(me, from.uid, " Not assigned to any channel.");
} else {
ctx.notice(me, from.uid, t!(ctx, " Serving {count} channel(s): {list}", count = channels.len(), list = channels.join(", ")));
ctx.notice(me, from.uid, echo_api::plural!(ctx, channels.len(), one = " Serving {count} channel: {list}", other = " Serving {count} channels: {list}", count = channels.len(), list = channels.join(", ")));
}
}

View file

@ -17,7 +17,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
match args.get(3).and_then(|s| s.parse::<u16>().ok()) {
Some(n) => match db.set_ttb(chan, n) {
Ok(()) if n == 0 => ctx.notice(me, from.uid, t!(ctx, "The bot will only kick (not ban) in \x02{chan}\x02.", chan = chan)),
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "The bot will ban a user after \x02{n}\x02 kick(s) in \x02{chan}\x02.", n = n, chan = chan)),
Ok(()) => ctx.notice(me, from.uid, echo_api::plural!(ctx, n, one = "The bot will ban a user after \x02{n}\x02 kick in \x02{chan}\x02.", other = "The bot will ban a user after \x02{n}\x02 kicks in \x02{chan}\x02.", n = n, chan = chan)),
Err(_) => reg_error(me, from, chan, ctx),
},
None => ctx.notice(me, from.uid, "Syntax: KICK <#channel> TTB <number>"),

View file

@ -47,7 +47,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
match args.get(3).and_then(|s| s.parse::<u16>().ok()) {
Some(n) => match db.set_votekick(chan, n) {
Ok(()) if n == 0 => ctx.notice(me, from.uid, t!(ctx, "\x02!votekick\x02 is now disabled in \x02{chan}\x02.", chan = chan)),
Ok(()) => ctx.notice(me, from.uid, t!(ctx, "\x02{n}\x02 vote(s) will now carry a \x02!votekick\x02/\x02!voteban\x02 in \x02{chan}\x02.", n = n, chan = chan)),
Ok(()) => ctx.notice(me, from.uid, echo_api::plural!(ctx, n, one = "\x02{n}\x02 vote will now carry a \x02!votekick\x02/\x02!voteban\x02 in \x02{chan}\x02.", other = "\x02{n}\x02 votes will now carry a \x02!votekick\x02/\x02!voteban\x02 in \x02{chan}\x02.", n = n, chan = chan)),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
},
None => ctx.notice(me, from.uid, "Syntax: SET <#channel> VOTEKICK <number> (0 to disable)"),

View file

@ -53,7 +53,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
}
}
Some("CLEAR") => match db.trigger_clear(chan) {
Ok(n) => ctx.notice(me, from.uid, t!(ctx, "Cleared \x02{n}\x02 trigger(s) from \x02{chan}\x02.", n = n, chan = chan)),
Ok(n) => ctx.notice(me, from.uid, echo_api::plural!(ctx, n, one = "Cleared \x02{n}\x02 trigger from \x02{chan}\x02.", other = "Cleared \x02{n}\x02 triggers from \x02{chan}\x02.", n = n, chan = chan)),
Err(_) => reg_error(me, from, chan, ctx),
},
None | Some("LIST") => {

View file

@ -49,6 +49,6 @@ pub fn handle(me: &str, from: &Sender, chan: Option<&str>, ctx: &mut ServiceCtx,
if opped == 0 {
ctx.notice(me, from.uid, t!(ctx, "None of \x02{chan}\x02's trusted regulars are here right now.", chan = chan));
} else {
ctx.notice(me, from.uid, t!(ctx, "Reopped \x02{opped}\x02 trusted regular(s) in \x02{chan}\x02.", opped = opped, chan = chan));
ctx.notice(me, from.uid, echo_api::plural!(ctx, opped, one = "Reopped \x02{opped}\x02 trusted regular in \x02{chan}\x02.", other = "Reopped \x02{opped}\x02 trusted regulars in \x02{chan}\x02.", opped = opped, chan = chan));
}
}

View file

@ -14,5 +14,5 @@ pub fn handle(me: &str, from: &Sender, chan: Option<&str>, ctx: &mut ServiceCtx,
for (id, score) in scores.iter().take(15) {
ctx.notice(me, from.uid, t!(ctx, " \x02{score}\x02 {id}", score = score, id = id));
}
ctx.notice(me, from.uid, t!(ctx, "Top {shown} of {total} scored identit{suffix} for \x02{chan}\x02.", shown = scores.len().min(15), total = scores.len(), suffix = if scores.len() == 1 { "y" } else { "ies" }, chan = chan));
ctx.notice(me, from.uid, echo_api::plural!(ctx, scores.len(), one = "Top {shown} of {total} scored identity for \x02{chan}\x02.", other = "Top {shown} of {total} scored identities for \x02{chan}\x02.", shown = scores.len().min(15), total = scores.len(), chan = chan));
}

View file

@ -111,7 +111,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
ctx.channel_mode(me, chan, &format!("-b {mask}"));
}
}
ctx.notice(me, from.uid, t!(ctx, "Cleared \x02{count}\x02 entr{suffix} from \x02{chan}\x02's auto-kick list.", count = masks.len(), suffix = if masks.len() == 1 { "y" } else { "ies" }, chan = chan));
ctx.notice(me, from.uid, echo_api::plural!(ctx, masks.len(), one = "Cleared \x02{count}\x02 entry from \x02{chan}\x02's auto-kick list.", other = "Cleared \x02{count}\x02 entries from \x02{chan}\x02's auto-kick list.", count = masks.len(), chan = chan));
}
_ => ctx.notice(me, from.uid, "Syntax: AKICK <#channel> ADD <mask> [reason] | DEL <mask> | LIST | CLEAR"),
}

View file

@ -26,7 +26,7 @@ pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut Serv
for a in &info.access {
ctx.notice(me, from.uid, t!(ctx, " \x02{account}\x02: \x02{flags}\x02", account = a.account, flags = Flags::from_level(&a.level).to_letters()));
}
ctx.notice(me, from.uid, t!(ctx, "End of flags ({count} entr{suffix}).", count = info.access.len() + 1, suffix = if info.access.is_empty() { "y" } else { "ies" }));
ctx.notice(me, from.uid, echo_api::plural!(ctx, info.access.len() + 1, one = "End of flags ({count} entry).", other = "End of flags ({count} entries).", count = info.access.len() + 1));
return;
};

View file

@ -16,5 +16,5 @@ pub fn handle(me: &str, from: &Sender, ctx: &mut ServiceCtx, db: &mut dyn Store)
for n in &names {
ctx.notice(me, from.uid, t!(ctx, " \x02{n}\x02", n = n));
}
ctx.notice(me, from.uid, t!(ctx, "End of list ({count} group(s)).", count = names.len()));
ctx.notice(me, from.uid, echo_api::plural!(ctx, names.len(), one = "End of list ({count} group).", other = "End of list ({count} groups).", count = names.len()));
}

View file

@ -20,5 +20,5 @@ pub fn handle(me: &str, from: &Sender, arg: Option<&str>, ctx: &mut ServiceCtx,
let short: String = t.message.chars().take(60).collect();
ctx.notice(me, from.uid, t!(ctx, "\x02#{id}\x02 {requester} — {short}{state}", id = t.id, requester = t.requester, short = short, state = state));
}
ctx.notice(me, from.uid, t!(ctx, "{count} ticket(s). \x02VIEW\x02 <id> for detail.", count = tickets.len()));
ctx.notice(me, from.uid, echo_api::plural!(ctx, tickets.len(), one = "{count} ticket. \x02VIEW\x02 <id> for detail.", other = "{count} tickets. \x02VIEW\x02 <id> for detail.", count = tickets.len()));
}

View file

@ -9,7 +9,7 @@ pub fn handle(me: &str, from: &Sender, account: &str, args: &[&str], ctx: &mut S
for i in (0..count).rev() {
db.memo_del(account, i);
}
ctx.notice(me, from.uid, t!(ctx, "Deleted all \x02{count}\x02 memo(s).", count = count));
ctx.notice(me, from.uid, echo_api::plural!(ctx, count, one = "Deleted all \x02{count}\x02 memo.", other = "Deleted all \x02{count}\x02 memos.", count = count));
}
Some(numstr) => {
let Some(n) = numstr.parse::<usize>().ok().filter(|n| *n >= 1) else {

View file

@ -1,4 +1,4 @@
use echo_api::{t, Sender, ServiceCtx, Store};
use echo_api::{Sender, ServiceCtx, Store};
// INFO: a summary of your mailbox (total, unread, capacity).
pub fn handle(me: &str, from: &Sender, account: &str, ctx: &mut ServiceCtx, db: &mut dyn Store) {
@ -7,6 +7,6 @@ pub fn handle(me: &str, from: &Sender, account: &str, ctx: &mut ServiceCtx, db:
ctx.notice(
me,
from.uid,
t!(ctx, "You have \x02{total}\x02 memo(s), \x02{unread}\x02 unread, of a maximum \x02{max}\x02.", total = total, unread = unread, max = super::MAX_MEMOS),
echo_api::plural!(ctx, total, one = "You have \x02{total}\x02 memo, \x02{unread}\x02 unread, of a maximum \x02{max}\x02.", other = "You have \x02{total}\x02 memos, \x02{unread}\x02 unread, of a maximum \x02{max}\x02.", total = total, unread = unread, max = super::MAX_MEMOS),
);
}

View file

@ -1,4 +1,4 @@
use echo_api::{t, Priv, Sender, ServiceCtx, Store};
use echo_api::{Priv, Sender, ServiceCtx, Store};
// SENDALL <text>: leave a memo on every registered account. Admin-only, for
// network-wide announcements that persist until read.
@ -20,5 +20,5 @@ pub fn handle(me: &str, from: &Sender, account: &str, args: &[&str], ctx: &mut S
sent += 1;
}
}
ctx.notice(me, from.uid, t!(ctx, "Memo sent to \x02{sent}\x02 account(s).", sent = sent));
ctx.notice(me, from.uid, echo_api::plural!(ctx, sent, one = "Memo sent to \x02{sent}\x02 account.", other = "Memo sent to \x02{sent}\x02 accounts.", sent = sent));
}

View file

@ -1,4 +1,4 @@
use echo_api::{t, NetView, Priv, Sender, ServiceCtx, Store};
use echo_api::{NetView, Priv, Sender, ServiceCtx, Store};
// STAFF <text>: leave a memo on every operator's account. Admin-only, for
// notes to the staff team that persist until read. Recipients are the union of
@ -29,5 +29,5 @@ pub fn handle(me: &str, from: &Sender, account: &str, args: &[&str], ctx: &mut S
sent += 1;
}
}
ctx.notice(me, from.uid, t!(ctx, "Memo sent to \x02{sent}\x02 operator(s).", sent = sent));
ctx.notice(me, from.uid, echo_api::plural!(ctx, sent, one = "Memo sent to \x02{sent}\x02 operator.", other = "Memo sent to \x02{sent}\x02 operators.", sent = sent));
}

View file

@ -39,7 +39,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
}
let ajoin = db.ajoin_list(&acct.name);
if !ajoin.is_empty() {
ctx.notice(me, from.uid, t!(ctx, " Auto-join : {count} channel(s) — see \x02AJOIN LIST\x02", count = ajoin.len()));
ctx.notice(me, from.uid, echo_api::plural!(ctx, ajoin.len(), one = " Auto-join : {count} channel — see \x02AJOIN LIST\x02", other = " Auto-join : {count} channels — see \x02AJOIN LIST\x02", count = ajoin.len()));
}
}
// A staff note is for operators' eyes only, never the account's owner.

View file

@ -20,5 +20,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
ctx.notice(me, from.uid, t!(ctx, " \x02{name}\x02 registered {when}{flag}", name = a.name, when = human_time(a.ts), flag = flag));
}
let more = if matches.len() > MAX_SHOWN { t!(ctx, ", showing the first {max}", max = MAX_SHOWN) } else { String::new() };
ctx.notice(me, from.uid, t!(ctx, "End of list — {count} match(es){more}.", count = matches.len(), more = more));
ctx.notice(me, from.uid, echo_api::plural!(ctx, matches.len(), one = "End of list — {count} match{more}.", other = "End of list — {count} matches{more}.", count = matches.len(), more = more));
}

View file

@ -1,5 +1,4 @@
use echo_api::{Sender, ServiceCtx, Store};
use echo_api::t;
// UPDATE: re-apply your account's auto-joins and vhost, and re-check for waiting
// memos, without having to re-identify.
@ -16,7 +15,7 @@ pub fn handle(me: &str, from: &Sender, ctx: &mut ServiceCtx, db: &dyn Store) {
}
let unread = db.unread_memos(account);
if unread > 0 {
ctx.notice(me, from.uid, t!(ctx, "You have \x02{unread}\x02 new memo(s). Read them with \x02/msg MemoServ READ NEW\x02.", unread = unread));
ctx.notice(me, from.uid, echo_api::plural!(ctx, unread, one = "You have \x02{unread}\x02 new memo. Read it with \x02/msg MemoServ READ NEW\x02.", other = "You have \x02{unread}\x02 new memos. Read them with \x02/msg MemoServ READ NEW\x02.", unread = unread));
}
ctx.notice(me, from.uid, "Your status has been refreshed.");
}

View file

@ -34,5 +34,5 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net:
banned += 1;
}
}
ctx.notice(me, from.uid, t!(ctx, "CHANKILL on \x02{chan}\x02: \x02{banned}\x02 host(s) AKILL'd.", chan = chan, banned = banned));
ctx.notice(me, from.uid, echo_api::plural!(ctx, banned, one = "CHANKILL on \x02{chan}\x02: \x02{banned}\x02 host AKILL'd.", other = "CHANKILL on \x02{chan}\x02: \x02{banned}\x02 hosts AKILL'd.", chan = chan, banned = banned));
}

View file

@ -20,7 +20,7 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
Some("VIEW") => list(me, from, true, args.get(2).copied(), ctx, db),
Some("CLEAR") => match db.notify_clear() {
Ok(0) => ctx.notice(me, from.uid, "The notify list is already empty."),
Ok(n) => ctx.notice(me, from.uid, t!(ctx, "Cleared \x02{n}\x02 notify watch(es).", n = n)),
Ok(n) => ctx.notice(me, from.uid, echo_api::plural!(ctx, n, one = "Cleared \x02{n}\x02 notify watch.", other = "Cleared \x02{n}\x02 notify watches.", n = n)),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
},
_ => ctx.notice(me, from.uid, SYNTAX),

View file

@ -19,14 +19,14 @@ pub fn handle_session(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceC
for (ip, n) in &over {
ctx.notice(me, from.uid, t!(ctx, " \x02{n}\x02 sessions from \x02{ip}\x02", n = n, ip = ip));
}
ctx.notice(me, from.uid, t!(ctx, "End of session list ({count} IP(s)).", count = over.len()));
ctx.notice(me, from.uid, echo_api::plural!(ctx, over.len(), one = "End of session list ({count} IP).", other = "End of session list ({count} IPs).", count = over.len()));
}
Some("VIEW") => {
let Some(&ip) = args.get(2) else {
ctx.notice(me, from.uid, "Syntax: SESSION VIEW <ip>");
return;
};
ctx.notice(me, from.uid, t!(ctx, "\x02{ip}\x02 has \x02{count}\x02 live session(s).", ip = ip, count = net.session_count(ip)));
ctx.notice(me, from.uid, echo_api::plural!(ctx, net.session_count(ip), one = "\x02{ip}\x02 has \x02{count}\x02 live session.", other = "\x02{ip}\x02 has \x02{count}\x02 live sessions.", ip = ip, count = net.session_count(ip)));
}
_ => ctx.notice(me, from.uid, "Syntax: SESSION LIST <min> | SESSION VIEW <ip>"),
}

View file

@ -16,5 +16,5 @@ pub fn handle(me: &str, from: &Sender, arg: Option<&str>, ctx: &mut ServiceCtx,
let short: String = r.reason.chars().take(60).collect();
ctx.notice(me, from.uid, t!(ctx, "\x02#{id}\x02 {reporter} → \x02{target}\x02: {short}{flag}", id = r.id, reporter = r.reporter, target = r.target, short = short, flag = flag));
}
ctx.notice(me, from.uid, t!(ctx, "{n} report(s). \x02VIEW\x02 <id> for detail.", n = reports.len()));
ctx.notice(me, from.uid, echo_api::plural!(ctx, reports.len(), one = "{n} report. \x02VIEW\x02 <id> for detail.", other = "{n} reports. \x02VIEW\x02 <id> for detail.", n = reports.len()));
}

View file

@ -10,7 +10,7 @@ pub fn handle(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, net: &d
ctx.notice(me, from.uid, t!(ctx, "No activity recorded for \x02{chan}\x02 yet.", chan = chan));
return;
};
ctx.notice(me, from.uid, t!(ctx, "\x02{chan}\x02\x02{lines}\x02 line(s) seen.", chan = chan, lines = lines));
ctx.notice(me, from.uid, echo_api::plural!(ctx, lines, one = "\x02{chan}\x02\x02{lines}\x02 line seen.", other = "\x02{chan}\x02\x02{lines}\x02 lines seen.", chan = chan, lines = lines));
if top.is_empty() {
return;
}

View file

@ -3308,7 +3308,7 @@
// Per-channel view.
let out = ss(&mut e, "#c");
assert!(out.iter().any(|a| matches!(a, NetAction::Notice { text, .. } if text.contains("line(s) seen"))), "channel lines: {out:?}");
assert!(out.iter().any(|a| matches!(a, NetAction::Notice { text, .. } if text.contains("lines seen"))), "channel lines: {out:?}");
assert!(out.iter().any(|a| matches!(a, NetAction::Notice { text, .. } if text.contains("spammer") && text.contains("3"))), "top talker: {out:?}");
// Global view (oper) shows the shared counters.
let out = ss(&mut e, "SERVER");

175
src/i18n_check.rs Normal file
View file

@ -0,0 +1,175 @@
//! Translation-catalog guards, run as `cargo test`. These keep the shipped
//! `lang/<code>.json` catalogs complete and consistent with the source, so a
//! stray English edit or a dropped placeholder fails the build instead of
//! silently degrading a language at runtime.
use regex::Regex;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::PathBuf;
const ROOT: &str = env!("CARGO_MANIFEST_DIR");
// Modules kept intentionally English-only (staff/dev tools), excluded from the
// source-coverage check.
const ENGLISH_ONLY: &[&str] = &["debugserv", "example"];
fn load_catalogs() -> HashMap<String, HashMap<String, String>> {
let dir = PathBuf::from(ROOT).join("lang");
let mut out = HashMap::new();
for entry in fs::read_dir(&dir).expect("read lang/") {
let path = entry.unwrap().path();
if path.extension().and_then(|s| s.to_str()) != Some("json") {
continue;
}
let code = path.file_stem().unwrap().to_str().unwrap().to_string();
let data = fs::read_to_string(&path).unwrap();
let map: HashMap<String, String> =
serde_json::from_str(&data).unwrap_or_else(|e| panic!("{}: {e}", path.display()));
out.insert(code, map);
}
assert!(!out.is_empty(), "no catalogs found in lang/");
out
}
/// The sorted multiset of `{...}` tokens in a string.
fn placeholders(s: &str) -> Vec<&str> {
let mut v = Vec::new();
let bytes = s.as_bytes();
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'{' {
if let Some(rel) = s[i..].find('}') {
v.push(&s[i..i + rel + 1]);
i += rel + 1;
continue;
}
}
i += 1;
}
v.sort_unstable();
v
}
/// Every translation must carry exactly the same `{placeholder}` tokens as its
/// English key — otherwise a substitution silently no-ops or leaks a raw token.
#[test]
fn placeholder_parity() {
let cats = load_catalogs();
let mut bad = Vec::new();
for (code, map) in &cats {
for (key, val) in map {
if placeholders(key) != placeholders(val) {
bad.push(format!("[{code}] {key:?}\n -> {val:?}"));
}
}
}
assert!(bad.is_empty(), "placeholder mismatches:\n{}", bad.join("\n"));
}
/// All catalogs must cover the exact same set of message ids, so no language
/// quietly lags behind another.
#[test]
fn catalogs_share_one_keyset() {
let cats = load_catalogs();
let reference: HashSet<&String> = cats.values().next().unwrap().keys().collect();
let mut problems = Vec::new();
for (code, map) in &cats {
let keys: HashSet<&String> = map.keys().collect();
let missing = reference.difference(&keys).count();
let extra = keys.difference(&reference).count();
if missing != 0 || extra != 0 {
problems.push(format!("[{code}] missing {missing}, extra {extra}"));
}
}
assert!(problems.is_empty(), "catalog keysets differ:\n{}", problems.join("\n"));
}
/// Turn a Rust string literal's escape sequences into the runtime message id, so
/// scraped templates match the catalog keys byte for byte.
fn unescape(s: &str) -> String {
let mut out = String::new();
let mut chars = s.char_indices().peekable();
while let Some((i, c)) = chars.next() {
if c != '\\' {
out.push(c);
continue;
}
match chars.next() {
Some((_, 'x')) => {
let hex = &s[i + 2..i + 4];
out.push(u8::from_str_radix(hex, 16).unwrap() as char);
chars.next(); // skip the two hex digits
chars.next();
}
Some((_, 'n')) => out.push('\n'),
Some((_, 't')) => out.push('\t'),
Some((_, 'r')) => out.push('\r'),
Some((_, '0')) => out.push('\0'),
Some((_, other)) => out.push(other),
None => {}
}
}
out
}
fn module_sources() -> Vec<PathBuf> {
let mut files = Vec::new();
let modules = PathBuf::from(ROOT).join("modules");
let mut stack = vec![modules];
while let Some(dir) = stack.pop() {
let Ok(rd) = fs::read_dir(&dir) else { continue };
for entry in rd.flatten() {
let path = entry.path();
if path.is_dir() {
let name = path.file_name().and_then(|s| s.to_str()).unwrap_or("");
if ENGLISH_ONLY.contains(&name) {
continue;
}
stack.push(path);
} else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
files.push(path);
}
}
}
files
}
/// Every `t!` and `plural!` template used in a translated module must exist in
/// the reference catalog, so a new user-facing string can't ship untranslated.
#[test]
fn every_template_is_translated() {
let cats = load_catalogs();
// Any catalog works as the reference — `catalogs_share_one_keyset` proves
// they agree; use French, the network default.
let reference = cats.get("fr").expect("fr catalog");
let str_lit = r#""((?:[^"\\]|\\.)*)""#;
let t_re = Regex::new(&format!(r"\bt!\s*\(\s*ctx\s*,\s*{str_lit}")).unwrap();
let plural_re =
Regex::new(&format!(r"(?s)plural!\s*\(\s*ctx\s*,.*?one\s*=\s*{str_lit}\s*,\s*other\s*=\s*{str_lit}")).unwrap();
let mut missing = Vec::new();
for path in module_sources() {
let src = fs::read_to_string(&path).unwrap();
let rel = path.strip_prefix(ROOT).unwrap_or(&path).display().to_string();
for cap in t_re.captures_iter(&src) {
let id = unescape(&cap[1]);
if !reference.contains_key(&id) {
missing.push(format!("{rel}: t! {id:?}"));
}
}
for cap in plural_re.captures_iter(&src) {
for g in [1usize, 2] {
let id = unescape(&cap[g]);
if !reference.contains_key(&id) {
missing.push(format!("{rel}: plural! {id:?}"));
}
}
}
}
assert!(
missing.is_empty(),
"these templates have no catalog entry:\n{}",
missing.join("\n")
);
}

View file

@ -12,6 +12,8 @@ mod keycard;
mod link;
mod migrate;
mod proto;
#[cfg(test)]
mod i18n_check;
use anyhow::Result;
use std::sync::Arc;