diff --git a/crates/plugins/src/manifest.rs b/crates/plugins/src/manifest.rs index a16bd8a4f..b6e17e3ad 100644 --- a/crates/plugins/src/manifest.rs +++ b/crates/plugins/src/manifest.rs @@ -736,10 +736,41 @@ fn input_names<'de, D: serde::Deserializer<'de>>(d: D) -> std::result::Result>(d: D) -> std::result::Result, D::Error> { use serde::de::{Error as _, IgnoredAny, MapAccess, SeqAccess, Visitor}; + /// A visitor's methods for a boolean, a number and a string: each is the error its type's + /// `wrong()` gives. + macro_rules! refuse_scalars { + () => { + fn visit_bool(self, _: bool) -> std::result::Result { + Err(E::custom(self.wrong())) + } + fn visit_i64(self, _: i64) -> std::result::Result { + Err(E::custom(self.wrong())) + } + fn visit_u64(self, _: u64) -> std::result::Result { + Err(E::custom(self.wrong())) + } + fn visit_f64(self, _: f64) -> std::result::Result { + Err(E::custom(self.wrong())) + } + fn visit_str(self, _: &str) -> std::result::Result { + Err(E::custom(self.wrong())) + } + }; + } + + /// A string field of an entry: anything else is the error "`{key}` must be a string". + fn string_field<'de, A: MapAccess<'de>>(map: &mut A, key: &str) -> std::result::Result, A::Error> { + Ok(match map.next_value::()? { + Value::String(s) => Ok(s), + _ => Err(format!("`{key}` must be a string")), + }) + } + /// A command's `params`, read in declaration order. struct Params(Vec<(String, Param)>); impl<'de> Deserialize<'de> for Params { @@ -750,6 +781,11 @@ fn ordered_commands<'de, D: serde::Deserializer<'de>>(d: D) -> std::result::Resu /// The entry at place `.0` in the list. struct Entry(usize); + impl Entry { + fn wrong(&self) -> String { + format!("command {} must be an object with an `id` and a `label`", command_name(self.0, "")) + } + } impl<'de> serde::de::DeserializeSeed<'de> for Entry { type Value = Command; fn deserialize>(self, d: D) -> std::result::Result { @@ -759,21 +795,29 @@ fn ordered_commands<'de, D: serde::Deserializer<'de>>(d: D) -> std::result::Resu impl<'de> Visitor<'de> for Entry { type Value = Command; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "command [{}] as {{id, label, params?}}", self.0) + f.write_str(&self.wrong()) + } + refuse_scalars!(); + fn visit_unit(self) -> std::result::Result { + Err(E::custom(self.wrong())) + } + fn visit_seq>(self, _: A) -> std::result::Result { + Err(A::Error::custom(self.wrong())) } fn visit_map>(self, mut map: A) -> std::result::Result { let (mut id, mut label, mut params) = (None::, None::, None::); let named = |id: &Option, e: &dyn std::fmt::Display| { A::Error::custom(format!("command {}: {e}", command_name(self.0, id.as_deref().unwrap_or_default()))) }; - while let Some(key) = map.next_key::().map_err(|e| named(&id, &e))? { + // A key and an ignored value can only fail as JSON syntax, which keeps serde's own error. + while let Some(key) = map.next_key::()? { let repeated = match key.as_str() { "id" if id.is_none() => { - id = Some(map.next_value().map_err(|e| named(&id, &e))?); + id = Some(string_field(&mut map, "id")?.map_err(|e| named(&id, &e))?); false } "label" if label.is_none() => { - label = Some(map.next_value().map_err(|e| named(&id, &e))?); + label = Some(string_field(&mut map, "label")?.map_err(|e| named(&id, &e))?); false } "params" if params.is_none() => { @@ -782,7 +826,7 @@ fn ordered_commands<'de, D: serde::Deserializer<'de>>(d: D) -> std::result::Resu } "id" | "label" | "params" => true, _ => { - map.next_value::().map_err(|e| named(&id, &e))?; + map.next_value::()?; false } }; @@ -801,16 +845,22 @@ fn ordered_commands<'de, D: serde::Deserializer<'de>>(d: D) -> std::result::Resu } struct List; + impl List { + fn wrong(&self) -> &'static str { + "`commands` must be a list of commands, each with an `id` and a `label`" + } + } impl<'de> Visitor<'de> for List { type Value = Vec; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("`commands` as a list of {id, label, params?}") + f.write_str(self.wrong()) } + refuse_scalars!(); fn visit_unit(self) -> std::result::Result { Ok(Vec::new()) } fn visit_map>(self, _: A) -> std::result::Result { - Err(A::Error::custom("`commands` must be a list of {id, label, params?}")) + Err(A::Error::custom(self.wrong())) } fn visit_seq>(self, mut seq: A) -> std::result::Result { let mut out = Vec::new(); @@ -1215,14 +1265,27 @@ mod tests { r#"{"id":"a","name":"x","kind":"filter","commands":[{"id":"x","label":"A","params":{"r":{"type":"bool"},"r":{"type":"int"}}}]}"#, "command `x`: parameter `r` is declared twice", ), - (r#"{"id":"a","name":"x","kind":"filter","commands":[1]}"#, "command [0]"), - (r#"{"id":"a","name":"x","kind":"filter","commands":{"id":"x"}}"#, "must be a list"), + (r#"{"id":"a","name":"x","kind":"filter","commands":[1]}"#, "command [0] must be an object with an `id` and a `label`"), + (r#"{"id":"a","name":"x","kind":"filter","commands":[{"id":"x","label":"A"},null]}"#, "command [1] must be an object"), + (r#"{"id":"a","name":"x","kind":"filter","commands":[["x"]]}"#, "command [0] must be an object"), + (r#"{"id":"a","name":"x","kind":"filter","commands":[{"id":1,"label":"A"}]}"#, "command [0]: `id` must be a string"), + (r#"{"id":"a","name":"x","kind":"filter","commands":[{"id":"x","label":true}]}"#, "command `x`: `label` must be a string"), + (r#"{"id":"a","name":"x","kind":"filter","commands":[{"id":"x","id":"y","label":"A"}]}"#, "command `x`: duplicate field `id`"), + ( + r#"{"id":"a","name":"x","kind":"filter","commands":{"id":"x"}}"#, + "`commands` must be a list of commands, each with an `id` and a `label`", + ), + (r#"{"id":"a","name":"x","kind":"filter","commands":"x"}"#, "`commands` must be a list of commands"), + (r#"{"id":"a","name":"x","kind":"filter","commands":7}"#, "`commands` must be a list of commands"), + (r#"{"id":"a","name":"x","kind":"filter","commands":true}"#, "`commands` must be a list of commands"), (r#"{"id":"a","name":"x","kind":"exporter","extensions":["plt"],"commands":[{"id":"x","label":"A"}]}"#, "only a filter or a live effect"), (r#"{"id":"a","name":"x","kind":"filter","budget":"heavy","commands":[{"id":"x","label":"A"}]}"#, "heavy filter"), (too_many.as_str(), "at most 32 `commands`"), ] { let e = Manifest::parse(bad.as_bytes()).unwrap_err().to_string(); assert!(e.contains(says), "{bad}: {e}"); + // The message is the manifest reader's own, with serde's place in the manifest once. + assert!(!e.contains("invalid type") && !e.contains("expected") && e.matches(" at line ").count() <= 1, "{bad}: {e}"); } let long_id = format!(r#"{{"id":"a","name":"x","kind":"filter","commands":[{{"id":"{}","label":"A"}}]}}"#, "c".repeat(MAX_COMMAND_ID + 1)); assert!(Manifest::parse(long_id.as_bytes()).is_err()); diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index c9d7bd3b8..0fcef01ea 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -6188,6 +6188,12 @@ digits Malayalam Malaiàlam @msg command {name}: `label` must be 1-64 printable characters ordre {name}: `label` ha de tenir 1-64 caràcters imprimibles @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter ordre {name}: fes servir un id d’1-{MAX_COMMAND_ID} caràcters d’a-z 0-9 _ que comenci per una lletra @msg command {name}: {e} ordre {name}: {e} +@msg manifest: {e} manifest: {e} +@msg manifest: {e} at line {line} column {column} manifest: {e} (línia {line}, columna {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` ha de ser una llista d’ordres, cadascuna amb `id` i `label` +@msg command {name} must be an object with an `id` and a `label` l’ordre {name} ha de ser un objecte amb `id` i `label` +@msg missing field `{key}` falta el camp `{key}` +@msg duplicate field `{key}` el camp `{key}` està repetit @msg only a filter or a live effect declares `commands` només un filtre o un efecte dinàmic declara `commands` @msg “{name}” › {label}: {e} «{name}» › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed el mòdul no té el SHA-256 que indica `hash`: no s’ha instal·lat res diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 6abdbe4f4..da1f040e4 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -6141,6 +6141,12 @@ axis Y Axis osa Y @msg command {name}: `label` must be 1-64 printable characters příkaz {name}: `label` musí mít 1-64 tisknutelných znaků @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter příkaz {name}: použijte id o 1-{MAX_COMMAND_ID} znacích z a-z 0-9 _, které začíná písmenem @msg command {name}: {e} příkaz {name}: {e} +@msg manifest: {e} manifest: {e} +@msg manifest: {e} at line {line} column {column} manifest: {e} (řádek {line}, sloupec {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` musí být seznam příkazů, každý s `id` a `label` +@msg command {name} must be an object with an `id` and a `label` příkaz {name} musí být objekt s `id` a `label` +@msg missing field `{key}` chybí pole `{key}` +@msg duplicate field `{key}` pole `{key}` je uvedeno dvakrát @msg only a filter or a live effect declares `commands` `commands` deklaruje jen filtr nebo živý efekt @msg “{name}” › {label}: {e} „{name}“ › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed modul nemá SHA-256 uvedený v `hash`: nic nebylo nainstalováno diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index cf60d6e87..0561b7469 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -5732,6 +5732,12 @@ axis Y Axis Y-Achse @msg command {name}: `label` must be 1-64 printable characters Befehl {name}: `label` muss 1-64 druckbare Zeichen haben @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter Befehl {name}: Verwenden Sie eine ID aus 1-{MAX_COMMAND_ID} Zeichen aus a-z 0-9 _, die mit einem Buchstaben beginnt @msg command {name}: {e} Befehl {name}: {e} +@msg manifest: {e} Manifest: {e} +@msg manifest: {e} at line {line} column {column} Manifest: {e} (Zeile {line}, Spalte {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` muss eine Liste von Befehlen sein, jeder mit `id` und `label` +@msg command {name} must be an object with an `id` and a `label` der Befehl {name} muss ein Objekt mit `id` und `label` sein +@msg missing field `{key}` fehlendes Feld `{key}` +@msg duplicate field `{key}` doppeltes Feld `{key}` @msg only a filter or a live effect declares `commands` nur ein Filter oder ein Live-Effekt deklariert `commands` @msg “{name}” › {label}: {e} „{name}“ › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed das Modul hat nicht den SHA-256-Wert aus `hash`: Es wurde nichts installiert diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index b0d06c50b..d68afdb54 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -6092,6 +6092,12 @@ axis Y Axis Άξονας Y @msg command {name}: `label` must be 1-64 printable characters εντολή {name}: το `label` πρέπει να έχει 1-64 εκτυπώσιμους χαρακτήρες @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter εντολή {name}: χρησιμοποιήστε αναγνωριστικό 1-{MAX_COMMAND_ID} χαρακτήρων από a-z 0-9 _ που αρχίζει με γράμμα @msg command {name}: {e} εντολή {name}: {e} +@msg manifest: {e} αρχείο δηλώσεων: {e} +@msg manifest: {e} at line {line} column {column} αρχείο δηλώσεων: {e} (γραμμή {line}, στήλη {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` το `commands` πρέπει να είναι λίστα εντολών, καθεμία με `id` και `label` +@msg command {name} must be an object with an `id` and a `label` η εντολή {name} πρέπει να είναι αντικείμενο με `id` και `label` +@msg missing field `{key}` λείπει το πεδίο `{key}` +@msg duplicate field `{key}` το πεδίο `{key}` εμφανίζεται δύο φορές @msg only a filter or a live effect declares `commands` μόνο ένα φίλτρο ή ένα δυναμικό εφέ δηλώνει `commands` @msg “{name}” › {label}: {e} «{name}» › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed η λειτουργική μονάδα δεν έχει το SHA-256 που δίνει το `hash`: δεν εγκαταστάθηκε τίποτα diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 273ece122..543e4a466 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -6083,6 +6083,12 @@ axis Y Axis Eje Y @msg command {name}: `label` must be 1-64 printable characters comando {name}: `label` debe tener 1-64 caracteres imprimibles @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter comando {name}: usa un id de 1-{MAX_COMMAND_ID} caracteres de a-z 0-9 _ que empiece por una letra @msg command {name}: {e} comando {name}: {e} +@msg manifest: {e} manifiesto: {e} +@msg manifest: {e} at line {line} column {column} manifiesto: {e} (línea {line}, columna {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` debe ser una lista de comandos, cada uno con `id` y `label` +@msg command {name} must be an object with an `id` and a `label` el comando {name} debe ser un objeto con `id` y `label` +@msg missing field `{key}` falta el campo `{key}` +@msg duplicate field `{key}` el campo `{key}` está repetido @msg only a filter or a live effect declares `commands` solo un filtro o un efecto interactivo declara `commands` @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed el módulo no tiene el SHA-256 que indica `hash`: no se instaló nada diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 877669158..dd2a4e4ab 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6171,6 +6171,12 @@ axis Y Axis Y-akseli @msg command {name}: `label` must be 1-64 printable characters komento {name}: `label`-kentässä on oltava 1-64 tulostettavaa merkkiä @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter komento {name}: käytä 1-{MAX_COMMAND_ID} merkin tunnusta merkeistä a-z 0-9 _, joka alkaa kirjaimella @msg command {name}: {e} komento {name}: {e} +@msg manifest: {e} manifesti: {e} +@msg manifest: {e} at line {line} column {column} manifesti: {e} (rivi {line}, sarake {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands`-kohdan on oltava luettelo komennoista, joilla kullakin on `id` ja `label` +@msg command {name} must be an object with an `id` and a `label` komennon {name} on oltava objekti, jossa on `id` ja `label` +@msg missing field `{key}` kenttä `{key}` puuttuu +@msg duplicate field `{key}` kenttä `{key}` on kahdesti @msg only a filter or a live effect declares `commands` vain suodin tai live-tehoste määrittelee `commands`-kohdan @msg “{name}” › {label}: {e} ”{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed moduulilla ei ole `hash`-kentän SHA-256-arvoa: mitään ei asennettu diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 90bbecff6..c056b5c43 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6136,6 +6136,12 @@ axis Y Axis Axe Y @msg command {name}: `label` must be 1-64 printable characters commande {name} : `label` doit compter 1-64 caractères imprimables @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter commande {name} : utilisez un id de 1-{MAX_COMMAND_ID} caractères parmi a-z 0-9 _ commençant par une lettre @msg command {name}: {e} commande {name} : {e} +@msg manifest: {e} manifeste : {e} +@msg manifest: {e} at line {line} column {column} manifeste : {e} (ligne {line}, colonne {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` doit être une liste de commandes, chacune avec `id` et `label` +@msg command {name} must be an object with an `id` and a `label` la commande {name} doit être un objet avec `id` et `label` +@msg missing field `{key}` champ `{key}` manquant +@msg duplicate field `{key}` champ `{key}` en double @msg only a filter or a live effect declares `commands` seul un filtre ou un effet dynamique déclare `commands` @msg “{name}” › {label}: {e} « {name} » › {label} : {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed le module n’a pas le SHA-256 indiqué par `hash` : rien n’a été installé diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index 9a3c13c21..7867a06c3 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -5437,6 +5437,11 @@ antiAlias Sharp शार्प @msg command {name}: `label` must be 1-64 printable characters कमांड {name}: `label` में 1-64 प्रिंट करने योग्य वर्ण होने चाहिए @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter कमांड {name}: a-z 0-9 _ के 1-{MAX_COMMAND_ID} वर्णों वाली ऐसी id इस्तेमाल करें जो अक्षर से शुरू हो @msg command {name}: {e} कमांड {name}: {e} +@msg manifest: {e} at line {line} column {column} प्रकटन: {e} (लाइन {line}, कॉलम {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` कमांड की एक सूची होनी चाहिए, हर एक में `id` और `label` हो +@msg command {name} must be an object with an `id` and a `label` कमांड {name} एक ऑब्जेक्ट होना चाहिए जिसमें `id` और `label` हों +@msg missing field `{key}` फ़ील्ड `{key}` नहीं है +@msg duplicate field `{key}` फ़ील्ड `{key}` दो बार है @msg only a filter or a live effect declares `commands` केवल फ़िल्टर या लाइव इफ़ेक्ट ही `commands` घोषित करता है @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed मॉड्यूल का SHA-256 वह नहीं है जो `hash` बताता है: कुछ भी इंस्टॉल नहीं हुआ diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 5ffef4e33..a7f46b9b0 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -6124,6 +6124,12 @@ axis Y Axis Y tengely @msg command {name}: `label` must be 1-64 printable characters {name} parancs: a `label` 1-64 nyomtatható karakter legyen @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter {name} parancs: használj 1-{MAX_COMMAND_ID} karakteres, a-z 0-9 _ karakterekből álló, betűvel kezdődő azonosítót @msg command {name}: {e} {name} parancs: {e} +@msg manifest: {e} leíró: {e} +@msg manifest: {e} at line {line} column {column} leíró: {e} ({line}. sor, {column}. oszlop) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands`: parancsok listája kell, mindegyikben `id` és `label` értékkel +@msg command {name} must be an object with an `id` and a `label` a(z) {name} parancs csak `id` és `label` mezőt tartalmazó objektum lehet +@msg missing field `{key}` hiányzó mező: `{key}` +@msg duplicate field `{key}` ismétlődő mező: `{key}` @msg only a filter or a live effect declares `commands` `commands` értéket csak szűrő vagy élő effektus deklarálhat @msg “{name}” › {label}: {e} „{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed a modul SHA-256 értéke nem az, amit a `hash` megad: semmi sem lett telepítve diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index aa19103f8..eac166a2b 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -5766,6 +5766,12 @@ axis Y Axis Asse Y @msg command {name}: `label` must be 1-64 printable characters comando {name}: `label` deve avere 1-64 caratteri stampabili @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter comando {name}: usa un id di 1-{MAX_COMMAND_ID} caratteri tra a-z 0-9 _ che inizi con una lettera @msg command {name}: {e} comando {name}: {e} +@msg manifest: {e} manifest: {e} +@msg manifest: {e} at line {line} column {column} manifest: {e} (riga {line}, colonna {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` deve essere un elenco di comandi, ciascuno con `id` e `label` +@msg command {name} must be an object with an `id` and a `label` il comando {name} deve essere un oggetto con `id` e `label` +@msg missing field `{key}` campo `{key}` mancante +@msg duplicate field `{key}` campo `{key}` duplicato @msg only a filter or a live effect declares `commands` solo un filtro o un effetto dinamico dichiara `commands` @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed il modulo non ha lo SHA-256 indicato da `hash`: non è stato installato nulla diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 04fceb4d5..b93c27c02 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -5831,6 +5831,12 @@ axis Y Axis Y 軸 @msg command {name}: `label` must be 1-64 printable characters コマンド {name}: `label` は印刷可能な 1-64 文字にしてください @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter コマンド {name}: a-z 0-9 _ からなり英字で始まる 1-{MAX_COMMAND_ID} 文字の ID を使用してください @msg command {name}: {e} コマンド {name}: {e} +@msg manifest: {e} マニフェスト: {e} +@msg manifest: {e} at line {line} column {column} マニフェスト: {e} ({line} 行目、{column} 列目) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` は、それぞれ `id` と `label` を持つコマンドのリストにしてください +@msg command {name} must be an object with an `id` and a `label` コマンド {name} は `id` と `label` を持つオブジェクトにしてください +@msg missing field `{key}` フィールド `{key}` がありません +@msg duplicate field `{key}` フィールド `{key}` が重複しています @msg only a filter or a live effect declares `commands` `commands` を宣言できるのはフィルターかライブ効果だけです @msg “{name}” › {label}: {e} 「{name}」 › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed モジュールの SHA-256 が `hash` の値と一致しません。何もインストールされませんでした diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 85ba47d64..b73fdf838 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -6092,6 +6092,12 @@ axis Y Axis Y ღერძი @msg command {name}: `label` must be 1-64 printable characters ბრძანება {name}: `label` უნდა შედგებოდეს 1-64 დასაბეჭდი სიმბოლოსგან @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter ბრძანება {name}: გამოიყენეთ 1-{MAX_COMMAND_ID} სიმბოლოიანი id a-z 0-9 _ სიმბოლოებიდან, რომელიც ასოთი იწყება @msg command {name}: {e} ბრძანება {name}: {e} +@msg manifest: {e} მანიფესტი: {e} +@msg manifest: {e} at line {line} column {column} მანიფესტი: {e} (სტრიქონი {line}, სვეტი {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` უნდა იყოს ბრძანებების სია, თითოეული `id`-ით და `label`-ით +@msg command {name} must be an object with an `id` and a `label` ბრძანება {name} უნდა იყოს ობიექტი `id`-ით და `label`-ით +@msg missing field `{key}` აკლია ველი `{key}` +@msg duplicate field `{key}` ველი `{key}` ორჯერაა @msg only a filter or a live effect declares `commands` `commands`-ს მხოლოდ ფილტრი ან ცოცხალი ეფექტი აცხადებს @msg “{name}” › {label}: {e} „{name}“ › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed მოდულს არ აქვს `hash`-ში მითითებული SHA-256: არაფერი დაყენებულა diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 6c5e5c3bc..06f46657e 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -5727,6 +5727,12 @@ axis Y Axis Y축 @msg command {name}: `label` must be 1-64 printable characters 명령 {name}: `label`은 인쇄 가능한 문자 1-64자여야 합니다 @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter 명령 {name}: a-z 0-9 _로 이루어지고 문자로 시작하는 1-{MAX_COMMAND_ID}자 ID를 사용하세요 @msg command {name}: {e} 명령 {name}: {e} +@msg manifest: {e} 매니페스트: {e} +@msg manifest: {e} at line {line} column {column} 매니페스트: {e} ({line}행 {column}열) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands`는 각각 `id`와 `label`이 있는 명령 목록이어야 합니다 +@msg command {name} must be an object with an `id` and a `label` 명령 {name}은(는) `id`와 `label`이 있는 객체여야 합니다 +@msg missing field `{key}` `{key}` 필드가 없습니다 +@msg duplicate field `{key}` `{key}` 필드가 중복되었습니다 @msg only a filter or a live effect declares `commands` 필터나 라이브 효과만 `commands`를 선언합니다 @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed 모듈의 SHA-256이 `hash`에 지정된 값과 다릅니다. 아무것도 설치되지 않았습니다 diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 9cd545f98..1c99c3857 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -5995,6 +5995,12 @@ axis Y Axis Oś Y @msg command {name}: `label` must be 1-64 printable characters polecenie {name}: `label` musi mieć 1-64 drukowalnych znaków @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter polecenie {name}: użyj id z 1-{MAX_COMMAND_ID} znaków spośród a-z 0-9 _, zaczynającego się od litery @msg command {name}: {e} polecenie {name}: {e} +@msg manifest: {e} manifest: {e} +@msg manifest: {e} at line {line} column {column} manifest: {e} (wiersz {line}, kolumna {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` musi być listą poleceń, każde z `id` i `label` +@msg command {name} must be an object with an `id` and a `label` polecenie {name} musi być obiektem z `id` i `label` +@msg missing field `{key}` brak pola `{key}` +@msg duplicate field `{key}` zduplikowane pole `{key}` @msg only a filter or a live effect declares `commands` `commands` deklaruje tylko filtr lub efekt na żywo @msg “{name}” › {label}: {e} „{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed moduł nie ma skrótu SHA-256 podanego w `hash`: nic nie zainstalowano diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 8ec808166..fb2b42e73 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -6056,6 +6056,12 @@ axis Y Axis Eixo Y @msg command {name}: `label` must be 1-64 printable characters comando {name}: `label` deve ter 1-64 caracteres imprimíveis @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter comando {name}: use um id de 1-{MAX_COMMAND_ID} caracteres de a-z 0-9 _ que comece com uma letra @msg command {name}: {e} comando {name}: {e} +@msg manifest: {e} manifesto: {e} +@msg manifest: {e} at line {line} column {column} manifesto: {e} (linha {line}, coluna {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` deve ser uma lista de comandos, cada um com `id` e `label` +@msg command {name} must be an object with an `id` and a `label` o comando {name} deve ser um objeto com `id` e `label` +@msg missing field `{key}` falta o campo `{key}` +@msg duplicate field `{key}` campo `{key}` duplicado @msg only a filter or a live effect declares `commands` só um filtro ou um efeito dinâmico declara `commands` @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed o módulo não tem o SHA-256 indicado em `hash`: nada foi instalado diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 4070aad8d..162d1bb6b 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -5752,6 +5752,12 @@ axis Y Axis Ось Y @msg command {name}: `label` must be 1-64 printable characters команда {name}: `label` должен содержать 1-64 печатаемых символа @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter команда {name}: используйте id из 1-{MAX_COMMAND_ID} символов a-z 0-9 _, начинающийся с буквы @msg command {name}: {e} команда {name}: {e} +@msg manifest: {e} манифест: {e} +@msg manifest: {e} at line {line} column {column} манифест: {e} (строка {line}, столбец {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` должно быть списком команд, у каждой из которых есть `id` и `label` +@msg command {name} must be an object with an `id` and a `label` команда {name} должна быть объектом с `id` и `label` +@msg missing field `{key}` нет поля `{key}` +@msg duplicate field `{key}` поле `{key}` указано дважды @msg only a filter or a live effect declares `commands` `commands` объявляет только фильтр или динамический эффект @msg “{name}” › {label}: {e} «{name}» › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed у модуля не тот SHA-256, что указан в `hash`: ничего не установлено diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 483ae3282..8b60afddd 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -6159,6 +6159,11 @@ axis Y Axis Y-axel @msg command {name}: `label` must be 1-64 printable characters kommando {name}: `label` måste ha 1-64 utskrivbara tecken @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter kommando {name}: använd ett id med 1-{MAX_COMMAND_ID} tecken av a-z 0-9 _ som börjar med en bokstav @msg command {name}: {e} kommando {name}: {e} +@msg manifest: {e} at line {line} column {column} manifest: {e} (rad {line}, kolumn {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` måste vara en lista med kommandon, vart och ett med `id` och `label` +@msg command {name} must be an object with an `id` and a `label` kommandot {name} måste vara ett objekt med `id` och `label` +@msg missing field `{key}` fältet `{key}` saknas +@msg duplicate field `{key}` fältet `{key}` förekommer två gånger @msg only a filter or a live effect declares `commands` bara ett filter eller en live-effekt deklarerar `commands` @msg “{name}” › {label}: {e} ”{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed modulen har inte den SHA-256 som `hash` anger: ingenting installerades diff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs index 4d0b3a9eb..be5c132db 100644 --- a/crates/ui-egui/src/i18n/tests.rs +++ b/crates/ui-egui/src/i18n/tests.rs @@ -2027,6 +2027,38 @@ fn plugin_limit_errors_are_translated() { } } +/// A manifest whose `commands` value has the wrong shape is refused with an error that every +/// language of [`COMPLETE_MESSAGES`] translates whole, the command's name and the place in the +/// manifest included. +#[test] +fn wrongly_shaped_plugin_commands_errors_are_translated() { + let many: Vec = (0..=32).map(|i| format!(r#"{{"id":"c{i}","label":"C"}}"#)).collect(); + let commands = [ + r#"{"id":"x"}"#.to_string(), + r#""x""#.to_string(), + "[1]".to_string(), + r#"[{"id":1,"label":"A"}]"#.to_string(), + r#"[{"id":"x","label":true}]"#.to_string(), + r#"[{"label":"B"}]"#.to_string(), + r#"[{"id":"x"}]"#.to_string(), + r#"[{"id":"x","id":"y","label":"A"}]"#.to_string(), + format!("[{}]", many.join(",")), + ]; + let english = ["must", "list", "missing", "field", "duplicate", "object", "line", "column", "each", "with", "invalid", "expected"]; + for value in &commands { + let manifest = format!(r#"{{"id":"a","name":"x","kind":"filter","commands":{value}}}"#); + let e = vectorcraft_plugins::manifest::Manifest::parse(manifest.as_bytes()).unwrap_err().to_string(); + let numbers: Vec<&str> = e.split(|c: char| !c.is_ascii_digit()).filter(|n| !n.is_empty()).collect(); + for code in COMPLETE_MESSAGES { + let shown = message(Lang::from_code(code).expect("registered"), &e); + // Backticked names stay in English; the words around them are translated. + let words: String = shown.split('`').step_by(2).collect(); + assert!(words.split(|c: char| !c.is_alphabetic()).all(|w| !english.contains(&w)), "{code}: {e} -> {shown}"); + assert!(numbers.iter().all(|n| shown.contains(n)), "{code}: {e} -> {shown}"); + } + } +} + /// The warnings of an Image Trace with keepColors, which the status bar shows and the scan above /// doesn't read, are translated in each language of [`COMPLETE_MESSAGES`], with the colors kept. #[test] diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index e2cf7eb73..e57d1eeef 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -6097,6 +6097,12 @@ axis Y Axis Y ekseni @msg command {name}: `label` must be 1-64 printable characters {name} komutu: `label` 1-64 yazdırılabilir karakter olmalıdır @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter {name} komutu: a-z 0-9 _ karakterlerinden oluşan ve harfle başlayan 1-{MAX_COMMAND_ID} karakterlik bir kimlik kullanın @msg command {name}: {e} {name} komutu: {e} +@msg manifest: {e} bildirim: {e} +@msg manifest: {e} at line {line} column {column} bildirim: {e} (satır {line}, sütun {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands`, her biri `id` ve `label` içeren bir komut listesi olmalıdır +@msg command {name} must be an object with an `id` and a `label` {name} komutu `id` ve `label` içeren bir nesne olmalıdır +@msg missing field `{key}` `{key}` alanı eksik +@msg duplicate field `{key}` `{key}` alanı yinelenmiş @msg only a filter or a live effect declares `commands` `commands` yalnızca bir filtre veya canlı efekt tarafından bildirilir @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed modül `hash` içinde verilen SHA-256 değerine sahip değil: hiçbir şey yüklenmedi diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index cc87a1e3d..6f416569c 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -5746,6 +5746,12 @@ axis Y Axis Вісь Y @msg command {name}: `label` must be 1-64 printable characters команда {name}: `label` має містити 1-64 друковані символи @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter команда {name}: використайте id з 1-{MAX_COMMAND_ID} символів a-z 0-9 _, що починається з літери @msg command {name}: {e} команда {name}: {e} +@msg manifest: {e} маніфест: {e} +@msg manifest: {e} at line {line} column {column} маніфест: {e} (рядок {line}, стовпець {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` має бути списком команд, кожна з `id` і `label` +@msg command {name} must be an object with an `id` and a `label` команда {name} має бути об'єктом з `id` і `label` +@msg missing field `{key}` немає поля `{key}` +@msg duplicate field `{key}` поле `{key}` вказано двічі @msg only a filter or a live effect declares `commands` `commands` оголошує лише фільтр або динамічний ефект @msg “{name}” › {label}: {e} «{name}» › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed модуль має не той SHA-256, що вказаний у `hash`: нічого не встановлено diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 0db3daf46..55c849ad0 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -5747,6 +5747,12 @@ axis Y Axis Trục Y @msg command {name}: `label` must be 1-64 printable characters lệnh {name}: `label` phải có 1-64 ký tự in được @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter lệnh {name}: hãy dùng id gồm 1-{MAX_COMMAND_ID} ký tự từ a-z 0-9 _ và bắt đầu bằng một chữ cái @msg command {name}: {e} lệnh {name}: {e} +@msg manifest: {e} manifest: {e} +@msg manifest: {e} at line {line} column {column} manifest: {e} (dòng {line}, cột {column}) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` phải là một danh sách lệnh, mỗi lệnh có `id` và `label` +@msg command {name} must be an object with an `id` and a `label` lệnh {name} phải là một đối tượng có `id` và `label` +@msg missing field `{key}` thiếu trường `{key}` +@msg duplicate field `{key}` trường `{key}` bị lặp @msg only a filter or a live effect declares `commands` chỉ bộ lọc hoặc hiệu ứng trực tiếp mới khai báo `commands` @msg “{name}” › {label}: {e} “{name}” › {label}: {e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed mô-đun không có SHA-256 mà `hash` cho biết: không có gì được cài đặt diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 651d3c063..890036261 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -5979,6 +5979,12 @@ axis Y Axis Y 轴 @msg command {name}: `label` must be 1-64 printable characters 命令 {name}:`label` 必须是 1-64 个可打印字符 @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter 命令 {name}:请使用由 a-z 0-9 _ 组成、以字母开头的 1-{MAX_COMMAND_ID} 个字符的 ID @msg command {name}: {e} 命令 {name}:{e} +@msg manifest: {e} 清单:{e} +@msg manifest: {e} at line {line} column {column} 清单:{e}(第 {line} 行,第 {column} 列) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` 必须是命令列表,每个命令都有 `id` 和 `label` +@msg command {name} must be an object with an `id` and a `label` 命令 {name} 必须是包含 `id` 和 `label` 的对象 +@msg missing field `{key}` 缺少字段 `{key}` +@msg duplicate field `{key}` 字段 `{key}` 重复 @msg only a filter or a live effect declares `commands` 只有滤镜或实时效果才能声明 `commands` @msg “{name}” › {label}: {e} “{name}” › {label}:{e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed 模块的 SHA-256 与 `hash` 给出的不符:未安装任何内容 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 5091f1b7e..fdeb2ad38 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -5784,6 +5784,12 @@ axis Y Axis Y 軸 @msg command {name}: `label` must be 1-64 printable characters 指令 {name}:`label` 必須是 1-64 個可列印字元 @msg command {name}: use an id of 1-{MAX_COMMAND_ID} characters from a-z 0-9 _ that starts with a letter 指令 {name}:請使用由 a-z 0-9 _ 組成、以字母開頭的 1-{MAX_COMMAND_ID} 個字元的 ID @msg command {name}: {e} 指令 {name}:{e} +@msg manifest: {e} 資訊清單:{e} +@msg manifest: {e} at line {line} column {column} 資訊清單:{e}(第 {line} 行,第 {column} 欄) +@msg `commands` must be a list of commands, each with an `id` and a `label` `commands` 必須是指令清單,每個指令都有 `id` 和 `label` +@msg command {name} must be an object with an `id` and a `label` 指令 {name} 必須是包含 `id` 和 `label` 的物件 +@msg missing field `{key}` 找不到欄位 `{key}` +@msg duplicate field `{key}` 欄位 `{key}` 重複 @msg only a filter or a live effect declares `commands` 只有濾鏡或即時效果才能宣告 `commands` @msg “{name}” › {label}: {e} 「{name}」 › {label}:{e} @msg the module doesn't have the SHA-256 `hash` gives: nothing was installed 模組的 SHA-256 與 `hash` 提供的不符:未安裝任何內容