From 94e2a8e24b177cabb16dafb191e96fbb71aa843b Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Fri, 13 Nov 2026 06:34:40 -0800 Subject: [PATCH] i18n: messages with literal braces match only their own catalog row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The message scan read every message as a format string, so a plain literal such as `expected {"dataBase64": "…"}` became the catalog key `expected {"dataBase64"}`, a template whose placeholder took the rest of any message starting with "expected". The plug-in output error `expected value at line 1 column 1` was then shown in German as "erwartet: value at line 1 column 1". - The scan doubles every brace of a message that is not a format string (a plain literal or a `&str` constant); `format!` strings and `#[error(...)]` strings keep their `{{`, `}}` and placeholders. - 150 `@msg` rows in 23 catalogs are keyed by the full message with its braces doubled, and their translations write those braces doubled and carry the full JSON example of the English. - An `@msg` row with no placeholder is an exact message under its text with `{{` and `}}` read as braces, so it is found at any length, and a nested JSON part translated by such a row shows single braces. - The Hindi row for `give {key, value} or {values}` translates the whole message; it kept the English "or" and left out "give". Docs: docs/development.md, the zh-hant.tsv header, docs/target-app-parity.md. --- crates/ui-egui/src/i18n.rs | 8 ++- crates/ui-egui/src/i18n/bs.tsv | 2 +- crates/ui-egui/src/i18n/ca.tsv | 12 ++--- crates/ui-egui/src/i18n/catalog.rs | 26 ++++++---- crates/ui-egui/src/i18n/cs.tsv | 10 ++-- crates/ui-egui/src/i18n/de.tsv | 10 ++-- crates/ui-egui/src/i18n/el.tsv | 10 ++-- crates/ui-egui/src/i18n/es.tsv | 10 ++-- crates/ui-egui/src/i18n/fi.tsv | 10 ++-- crates/ui-egui/src/i18n/fr.tsv | 10 ++-- crates/ui-egui/src/i18n/hi.tsv | 44 ++++++++-------- crates/ui-egui/src/i18n/hu.tsv | 10 ++-- crates/ui-egui/src/i18n/it.tsv | 10 ++-- crates/ui-egui/src/i18n/ja.tsv | 10 ++-- crates/ui-egui/src/i18n/ka.tsv | 12 ++--- crates/ui-egui/src/i18n/ko.tsv | 10 ++-- crates/ui-egui/src/i18n/pl.tsv | 10 ++-- crates/ui-egui/src/i18n/pt-br.tsv | 12 ++--- crates/ui-egui/src/i18n/ru.tsv | 12 ++--- crates/ui-egui/src/i18n/sv.tsv | 44 ++++++++-------- crates/ui-egui/src/i18n/tests.rs | 80 ++++++++++++++++++++++++++--- crates/ui-egui/src/i18n/tr.tsv | 12 ++--- crates/ui-egui/src/i18n/uk.tsv | 10 ++-- crates/ui-egui/src/i18n/vi.tsv | 10 ++-- crates/ui-egui/src/i18n/zh-hans.tsv | 10 ++-- crates/ui-egui/src/i18n/zh-hant.tsv | 11 ++-- docs/development.md | 5 +- docs/target-app-parity.md | 1 + 28 files changed, 252 insertions(+), 169 deletions(-) diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 4ec89b8e32..ef2c48407e 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -676,7 +676,7 @@ fn message_at(lang: Lang, s: &str, depth: usize) -> String { if depth <= 1 || quoted(v) { v.to_string() } else if v.starts_with(['{', '[']) { - lang.catalog().exact_message(v).unwrap_or(v).to_string() + exact_translation(lang.catalog(), v).unwrap_or_else(|| v.to_string()) } else { message_at(lang, v, depth - 1) } @@ -686,6 +686,12 @@ fn message_at(lang: Lang, s: &str, depth: usize) -> String { fill_once(template, &args) } +/// The translation of a message with an exact `@msg` row in `catalog`, its `{{` and `}}` shown as +/// `{` and `}`. +fn exact_translation(catalog: &Catalog, s: &str) -> Option { + catalog.exact_message(s).map(|tr| fill_once(tr, &[])) +} + /// Fill `{name}` placeholders in one pass: a value that holds `{name}` text stays as it is. /// Unknown placeholders are left as written. `{{` and `}}` are a literal `{` and `}`. fn fill_once(template: &str, args: &[(&str, &str)]) -> String { diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 81fee3a079..c7aed47cdf 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -6384,7 +6384,7 @@ anchor Points: Tačke: Stop on Errors Zaustavi pri greškama Yonroku-ban Yonroku-ban @msg image '{key}' has no pixels and was left out slika '{key}' nema piksela i izostavljena je -@msg not an RTF file: it doesn't start with {\\rtf nije RTF datoteka: ne počinje s {\\rtf +@msg not an RTF file: it doesn't start with {{\\rtf nije RTF datoteka: ne počinje s {{\\rtf @msg this is a PostScript file (an .ai saved in an older format or without PDF compatibility, or an EPS file), which can't be opened yet: save it as PDF, PDF-compatible .ai or SVG ovo je PostScript datoteka (.ai sačuvan u starijem formatu ili bez PDF kompatibilnosti, ili EPS datoteka), koja se još ne može otvoriti: sačuvajte je kao PDF, .ai kompatibilan s PDF-om ili SVG font-script Japanese Japansko swatch [None] [Nijedna] diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 02ae0f4a09..d0d8277211 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -5831,7 +5831,7 @@ digits Malayalam Malaiàlam @msg not an HP-GL file no és un fitxer HP-GL @msg not a PICT file no és un fitxer PICT @msg `pens` must be an array of 1 to 255 #rrggbb colors `pens` ha de ser una matriu d’1 a 255 colors #rrggbb -@msg not an RTF file: it doesn't start with {\\rtf no és un fitxer RTF: no comença amb {\\rtf +@msg not an RTF file: it doesn't start with {{\\rtf no és un fitxer RTF: no comença amb {{\\rtf @msg not found no s’ha trobat @msg not in pattern editing mode no esteu en mode d’edició de motius @msg finish editing the pattern first acabeu primer l’edició del motiu @@ -6391,8 +6391,8 @@ digits Malayalam Malaiàlam @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` un exportador declara d’1 a {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` com a màxim {MAX_UNGROUPED} paràmetres fora de grups: doneu un `group` als altres @msg can't encode the input no es pot codificar l’entrada -@msg expected {"dataBase64"} s’esperava {"dataBase64"} -@msg expected {"objects"} s’esperava {"objects"} +@msg expected {{"dataBase64": "…"}} s’esperava {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} s’esperava {{"objects": [...]}} @msg export `{name}`: {e} exportació del mòdul `{name}`: {e} @msg extension {e} is listed twice l’extensió {e} apareix dues vegades @msg extension {e}: use 1-16 lower-case letters and digits, without the dot extensió {e}: feu servir 1-16 lletres minúscules i dígits, sense el punt @@ -6456,11 +6456,11 @@ digits Malayalam Malaiàlam @msg a painted live effect returns only `objects` un efecte dinàmic de pintura només retorna `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` una peça d’un efecte dinàmic de pintura només té `path`, `fillRule`, `fills` i `strokes` @msg a read-only object was left out s’ha omès un objecte de només lectura -@msg a read-only object was left out: return it, as {"id"} alone or as it was given s’ha omès un objecte de només lectura: retorneu-lo com a {"id"} sol o tal com s’ha rebut +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given s’ha omès un objecte de només lectura: retorneu-lo com a {{"id": …}} sol o tal com s’ha rebut @msg a string una cadena @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` un traç només té `paint`, `width`, `join`, `cap` i `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} un traç ha de ser {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} un efecte ha de ser {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} un traç ha de ser {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} un efecte ha de ser {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` un efecte en un farciment només retorna `fills` @msg an effect on a stroke returns only `strokes` un efecte en un traç només retorna `strokes` @msg an object must be a JSON object un objecte ha de ser un objecte JSON diff --git a/crates/ui-egui/src/i18n/catalog.rs b/crates/ui-egui/src/i18n/catalog.rs index ab3abff6f5..f2fab1fcfa 100644 --- a/crates/ui-egui/src/i18n/catalog.rs +++ b/crates/ui-egui/src/i18n/catalog.rs @@ -13,7 +13,8 @@ pub struct Catalog { ids: HashMap, /// plural messages: `one|other` → forms plurals: HashMap>, - /// status and error messages without placeholders (`@msg`): English → translation + /// status and error messages without placeholders (`@msg`): English, its `{{` and `}}` read as + /// `{` and `}` → translation, as written messages: HashMap, /// status and error messages with `{name}` placeholders (`@msg`, and each English form of a /// `@msgplural` row), most specific first @@ -193,13 +194,20 @@ impl Catalog { "@plural" => { c.plurals.insert(src, tr.split('|').map(str::to_string).collect()); } - "@msg" => { - if src.contains('{') || src.contains("}}") { - c.templates.extend(Template::parse(&src, vec![tr], false)); - } else { - c.messages.insert(src, tr); - } + "@msg" if !src.contains(['{', '}']) => { + c.messages.insert(src, tr); } + "@msg" => match Template::parse(&src, vec![tr], false) { + // A row without placeholders is an exact message, under its text with `{{` and + // `}}` read as literal braces. + Some(Template { pieces, mut forms, .. }) if matches!(pieces.as_slice(), [Piece::Text(_)]) => { + if let (Some(Piece::Text(text)), Some(tr)) = (pieces.into_iter().next(), forms.pop()) { + c.messages.insert(text, tr); + } + } + Some(template) => c.templates.push(template), + None => {} + }, "@msgplural" => { let forms: Vec = tr.split('|').map(str::to_string).collect(); c.templates.extend(src.split('|').filter_map(|english| Template::parse(english, forms.clone(), true))); @@ -249,8 +257,8 @@ impl Catalog { self.templates.iter().find_map(|t| t.captures(s).map(|caps| (t.forms.as_slice(), caps))) } - /// The translation of a status or error message that has an exact `@msg` entry; templates are - /// not tried. + /// The translation of a status or error message that has an exact `@msg` entry, as written in + /// the catalog (`{{` and `}}` for literal braces); templates are not tried. pub fn exact_message(&self, s: &str) -> Option<&str> { self.messages.get(s).map(String::as_str) } diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 7e3794e8a1..672a9ae170 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -6306,8 +6306,8 @@ axis Y Axis osa Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` exportní zásuvný modul deklaruje 1 až {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` mimo skupiny smí být nejvýše {MAX_UNGROUPED} parametrů: ostatním přiřaďte `group` @msg can't encode the input vstup nelze zakódovat -@msg expected {"dataBase64"} očekáváno {"dataBase64"} -@msg expected {"objects"} očekáváno {"objects"} +@msg expected {{"dataBase64": "…"}} očekáváno {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} očekáváno {{"objects": [...]}} @msg export `{name}`: {e} export `{name}`: {e} @msg extension {e} is listed twice přípona {e} je uvedena dvakrát @msg extension {e}: use 1-16 lower-case letters and digits, without the dot přípona {e}: použijte 1-16 malých písmen a číslic, bez tečky @@ -6371,11 +6371,11 @@ axis Y Axis osa Y @msg a painted live effect returns only `objects` malující živý efekt vrací jen `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` část malujícího živého efektu má jen `path`, `fillRule`, `fills` a `strokes` @msg a read-only object was left out objekt jen pro čtení byl vynechán -@msg a read-only object was left out: return it, as {"id"} alone or as it was given objekt jen pro čtení byl vynechán: vraťte ho jako samotné {"id"} nebo tak, jak byl předán +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given objekt jen pro čtení byl vynechán: vraťte ho jako samotné {{"id": …}} nebo tak, jak byl předán @msg a string řetězec @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` tah má jen `paint`, `width`, `join`, `cap` a `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} tah musí být {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} efekt musí být {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} tah musí být {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} efekt musí být {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` efekt na výplni vrací jen `fills` @msg an effect on a stroke returns only `strokes` efekt na tahu vrací jen `strokes` @msg an object must be a JSON object objekt musí být objekt JSON diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 4174537f87..97c18987a2 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -5897,8 +5897,8 @@ axis Y Axis Y-Achse @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` ein Export-Plug-in gibt 1 bis {MAX_EXTENSIONS} `extensions` an @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` höchstens {MAX_UNGROUPED} Parameter außerhalb von Gruppen: Geben Sie den anderen eine `group` @msg can't encode the input die Eingabe kann nicht codiert werden -@msg expected {"dataBase64"} erwartet: {"dataBase64"} -@msg expected {"objects"} erwartet: {"objects"} +@msg expected {{"dataBase64": "…"}} erwartet: {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} erwartet: {{"objects": [...]}} @msg export `{name}`: {e} Modulexport `{name}`: {e} @msg extension {e} is listed twice die Dateiendung {e} ist doppelt aufgeführt @msg extension {e}: use 1-16 lower-case letters and digits, without the dot Dateiendung {e}: Verwenden Sie 1-16 Kleinbuchstaben und Ziffern, ohne Punkt @@ -5962,11 +5962,11 @@ axis Y Axis Y-Achse @msg a painted live effect returns only `objects` ein malender Live-Effekt gibt nur `objects` zurück @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` ein Teil eines malenden Live-Effekts hat nur `path`, `fillRule`, `fills` und `strokes` @msg a read-only object was left out ein schreibgeschütztes Objekt wurde weggelassen -@msg a read-only object was left out: return it, as {"id"} alone or as it was given ein schreibgeschütztes Objekt wurde weggelassen: Geben Sie es zurück, als {"id"} allein oder so, wie es übergeben wurde +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given ein schreibgeschütztes Objekt wurde weggelassen: Geben Sie es zurück, als {{"id": …}} allein oder so, wie es übergeben wurde @msg a string eine Zeichenkette @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` eine Kontur hat nur `paint`, `width`, `join`, `cap` und `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} eine Kontur muss {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} sein -@msg an effect must be {"id", "params"?, "visible"?} ein Effekt muss {"id", "params"?, "visible"?} sein +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} eine Kontur muss {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} sein +@msg an effect must be {{"id", "params"?, "visible"?}} ein Effekt muss {{"id", "params"?, "visible"?}} sein @msg an effect on a fill returns only `fills` ein Effekt auf einer Fläche gibt nur `fills` zurück @msg an effect on a stroke returns only `strokes` ein Effekt auf einer Kontur gibt nur `strokes` zurück @msg an object must be a JSON object ein Objekt muss ein JSON-Objekt sein diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index bde2fbee78..f485282ca4 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -6257,8 +6257,8 @@ axis Y Axis Άξονας Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` ένα πρόσθετο εξαγωγής δηλώνει 1 έως {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` το πολύ {MAX_UNGROUPED} παράμετροι εκτός ομάδων: δώστε στις υπόλοιπες ένα `group` @msg can't encode the input η είσοδος δεν μπορεί να κωδικοποιηθεί -@msg expected {"dataBase64"} αναμενόταν {"dataBase64"} -@msg expected {"objects"} αναμενόταν {"objects"} +@msg expected {{"dataBase64": "…"}} αναμενόταν {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} αναμενόταν {{"objects": [...]}} @msg export `{name}`: {e} εξαγωγή `{name}`: {e} @msg extension {e} is listed twice η επέκταση {e} αναφέρεται δύο φορές @msg extension {e}: use 1-16 lower-case letters and digits, without the dot επέκταση {e}: χρησιμοποιήστε 1-16 πεζά γράμματα και ψηφία, χωρίς την τελεία @@ -6322,11 +6322,11 @@ axis Y Axis Άξονας Y @msg a painted live effect returns only `objects` ένα ζωντανό εφέ βαφής επιστρέφει μόνο `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` ένα κομμάτι ζωντανού εφέ βαφής έχει μόνο `path`, `fillRule`, `fills` και `strokes` @msg a read-only object was left out παραλείφθηκε ένα αντικείμενο μόνο για ανάγνωση -@msg a read-only object was left out: return it, as {"id"} alone or as it was given παραλείφθηκε ένα αντικείμενο μόνο για ανάγνωση: επιστρέψτε το ως {"id"} μόνο ή όπως δόθηκε +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given παραλείφθηκε ένα αντικείμενο μόνο για ανάγνωση: επιστρέψτε το ως {{"id": …}} μόνο ή όπως δόθηκε @msg a string συμβολοσειρά @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` ένα περίγραμμα έχει μόνο `paint`, `width`, `join`, `cap` και `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} ένα περίγραμμα πρέπει να είναι {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} ένα εφέ πρέπει να είναι {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} ένα περίγραμμα πρέπει να είναι {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} ένα εφέ πρέπει να είναι {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` ένα εφέ σε γέμισμα επιστρέφει μόνο `fills` @msg an effect on a stroke returns only `strokes` ένα εφέ σε περίγραμμα επιστρέφει μόνο `strokes` @msg an object must be a JSON object ένα αντικείμενο πρέπει να είναι αντικείμενο JSON diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index ff28d9dfc5..0f48fc6280 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -6248,8 +6248,8 @@ axis Y Axis Eje Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` un plugin de exportación declara de 1 a {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` como máximo {MAX_UNGROUPED} parámetros fuera de grupos: asigna un `group` a los demás @msg can't encode the input no se puede codificar la entrada -@msg expected {"dataBase64"} se esperaba {"dataBase64"} -@msg expected {"objects"} se esperaba {"objects"} +@msg expected {{"dataBase64": "…"}} se esperaba {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} se esperaba {{"objects": [...]}} @msg export `{name}`: {e} exportación del módulo `{name}`: {e} @msg extension {e} is listed twice la extensión {e} aparece dos veces @msg extension {e}: use 1-16 lower-case letters and digits, without the dot extensión {e}: usa 1-16 letras minúsculas y dígitos, sin el punto @@ -6313,11 +6313,11 @@ axis Y Axis Eje Y @msg a painted live effect returns only `objects` un efecto dinámico de pintura solo devuelve `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` una pieza de un efecto dinámico de pintura solo tiene `path`, `fillRule`, `fills` y `strokes` @msg a read-only object was left out se omitió un objeto de solo lectura -@msg a read-only object was left out: return it, as {"id"} alone or as it was given se omitió un objeto de solo lectura: devuélvalo como {"id"} solo o tal como se recibió +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given se omitió un objeto de solo lectura: devuélvalo como {{"id": …}} solo o tal como se recibió @msg a string una cadena @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` un trazo solo tiene `paint`, `width`, `join`, `cap` y `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} un trazo debe ser {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} un efecto debe ser {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} un trazo debe ser {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} un efecto debe ser {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` un efecto en un relleno solo devuelve `fills` @msg an effect on a stroke returns only `strokes` un efecto en un trazo solo devuelve `strokes` @msg an object must be a JSON object un objeto debe ser un objeto JSON diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index bb74188ed8..81e4f1c49e 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6336,8 +6336,8 @@ axis Y Axis Y-akseli @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` vientilaajennus ilmoittaa 1–{MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` ryhmien ulkopuolella saa olla enintään {MAX_UNGROUPED} parametria: anna muille `group` @msg can't encode the input syötettä ei voi koodata -@msg expected {"dataBase64"} odotettiin {"dataBase64"} -@msg expected {"objects"} odotettiin {"objects"} +@msg expected {{"dataBase64": "…"}} odotettiin {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} odotettiin {{"objects": [...]}} @msg export `{name}`: {e} moduulin vienti `{name}`: {e} @msg extension {e} is listed twice tunniste {e} on luettelossa kahdesti @msg extension {e}: use 1-16 lower-case letters and digits, without the dot tunniste {e}: käytä 1-16 pientä kirjainta ja numeroa ilman pistettä @@ -6401,11 +6401,11 @@ axis Y Axis Y-akseli @msg a painted live effect returns only `objects` maalaava live-tehoste palauttaa vain kentän `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` maalaavan live-tehosteen osalla on vain `path`, `fillRule`, `fills` ja `strokes` @msg a read-only object was left out vain luku -objekti jätettiin pois -@msg a read-only object was left out: return it, as {"id"} alone or as it was given vain luku -objekti jätettiin pois: palauta se pelkkänä {"id"}-muotona tai sellaisena kuin se annettiin +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given vain luku -objekti jätettiin pois: palauta se pelkkänä {{"id": …}}-muotona tai sellaisena kuin se annettiin @msg a string merkkijono @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` viivalla on vain `paint`, `width`, `join`, `cap` ja `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} viivan on oltava muotoa {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} tehosteen on oltava muotoa {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} viivan on oltava muotoa {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} tehosteen on oltava muotoa {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` täytön tehoste palauttaa vain kentän `fills` @msg an effect on a stroke returns only `strokes` viivan tehoste palauttaa vain kentän `strokes` @msg an object must be a JSON object objektin on oltava JSON-objekti diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 09c9c35b0d..041c7f40eb 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6301,8 +6301,8 @@ axis Y Axis Axe Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` un module externe d’exportation déclare de 1 à {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` {MAX_UNGROUPED} paramètres au plus hors des groupes : donnez un `group` aux autres @msg can't encode the input impossible d’encoder l’entrée -@msg expected {"dataBase64"} attendu : {"dataBase64"} -@msg expected {"objects"} attendu : {"objects"} +@msg expected {{"dataBase64": "…"}} attendu : {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} attendu : {{"objects": [...]}} @msg export `{name}`: {e} export du module `{name}` : {e} @msg extension {e} is listed twice l’extension {e} figure deux fois @msg extension {e}: use 1-16 lower-case letters and digits, without the dot extension {e} : utilisez 1-16 lettres minuscules et chiffres, sans le point @@ -6366,11 +6366,11 @@ axis Y Axis Axe Y @msg a painted live effect returns only `objects` un effet dynamique de peinture renvoie seulement `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` une pièce d’un effet dynamique de peinture a seulement `path`, `fillRule`, `fills` et `strokes` @msg a read-only object was left out un objet en lecture seule a été omis -@msg a read-only object was left out: return it, as {"id"} alone or as it was given un objet en lecture seule a été omis : renvoyez-le, sous la forme {"id"} seul ou tel qu’il a été fourni +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given un objet en lecture seule a été omis : renvoyez-le, sous la forme {{"id": …}} seul ou tel qu’il a été fourni @msg a string une chaîne @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` un contour a seulement `paint`, `width`, `join`, `cap` et `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} un contour doit être {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} un effet doit être {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} un contour doit être {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} un effet doit être {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` un effet sur un fond renvoie seulement `fills` @msg an effect on a stroke returns only `strokes` un effet sur un contour renvoie seulement `strokes` @msg an object must be a JSON object un objet doit être un objet JSON diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index 9aa4bd7b99..7d692604ee 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -5524,11 +5524,11 @@ antiAlias Sharp शार्प @msg a painted live effect returns only `objects` पेंट करने वाला लाइव इफ़ेक्ट केवल `objects` लौटाता है @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` पेंट करने वाले लाइव इफ़ेक्ट के हिस्से में केवल `path`, `fillRule`, `fills` और `strokes` होते हैं @msg a read-only object was left out एक केवल-पढ़ने योग्य ऑब्जेक्ट छोड़ दिया गया -@msg a read-only object was left out: return it, as {"id"} alone or as it was given एक केवल-पढ़ने योग्य ऑब्जेक्ट छोड़ दिया गया: इसे केवल {"id"} के रूप में या जैसा दिया गया था वैसा लौटाएँ +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given एक केवल-पढ़ने योग्य ऑब्जेक्ट छोड़ दिया गया: इसे केवल {{"id": …}} के रूप में या जैसा दिया गया था वैसा लौटाएँ @msg a string एक स्ट्रिंग @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` स्ट्रोक में केवल `paint`, `width`, `join`, `cap` और `miterLimit` होते हैं -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} स्ट्रोक {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} होना चाहिए -@msg an effect must be {"id", "params"?, "visible"?} इफ़ेक्ट {"id", "params"?, "visible"?} होना चाहिए +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} स्ट्रोक {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} होना चाहिए +@msg an effect must be {{"id", "params"?, "visible"?}} इफ़ेक्ट {{"id", "params"?, "visible"?}} होना चाहिए @msg an effect on a fill returns only `fills` फ़िल पर इफ़ेक्ट केवल `fills` लौटाता है @msg an effect on a stroke returns only `strokes` स्ट्रोक पर इफ़ेक्ट केवल `strokes` लौटाता है @msg an object must be a JSON object ऑब्जेक्ट एक JSON ऑब्जेक्ट होना चाहिए @@ -5988,7 +5988,7 @@ antiAlias Sharp शार्प @msg `files` must be 1 to 1000 paths of font files the last text.findFontFiles search found `files` में पिछली text.findFontFiles सर्च में मिली फ़ॉन्ट फ़ाइलों के 1 से 1000 पाथ होने चाहिए @msg `folder` must be an absolute folder path `folder` एक पूर्ण फ़ोल्डर पाथ होना चाहिए @msg `follow` must be "average", "a" or "b" `follow` को "average", "a" या "b" होना चाहिए। -@msg `fontAxes` must be an object of axis tags and values, such as {"wght"} `fontAxes` को अक्ष टैग और मानों का एक ऑब्जेक्ट होना चाहिए, जैसे कि {"wght"} +@msg `fontAxes` must be an object of axis tags and values, such as {{"wght": 650}} `fontAxes` को अक्ष टैग और मानों का एक ऑब्जेक्ट होना चाहिए, जैसे कि {{"wght": 650}} @msg `fontHeightReference` must be "emBox", "capHeight", "xHeight" or "icfBox" `fontHeightReference` को "emBox", "capHeight", "xHeight" या "icfBox" होना चाहिए @msg `format` must be a string `format` एक स्ट्रिंग होना चाहिए @msg `format` must be one of {_1} `format` को {_1} में से एक होना चाहिए @@ -6022,12 +6022,12 @@ antiAlias Sharp शार्प @msg `index` must be a point index `index` एक बिंदु सूचकांक होना चाहिए @msg `index` must be a whole number or null `index` होना चाहिए पूरी संख्या या null होना चाहिए @msg `indices` must be a non-empty array of item indices `indices` आइटम सूचकांकों की एक गैर-खाली सरणी होना चाहिए -@msg `items` is a list of {kind, item} `items` {kind, item} की सूची है +@msg `items` is a list of {{kind, item}} `items` {{kind, item}} की सूची है @msg `items` is empty `items` खाली है @msg `items` must be a list of {{id, anchors?}}, not {v} `items` को {{id, anchors?}} की सूची होना चाहिए, {v} नहीं -@msg `items` must be a list of {id, points} `items` को {id, points} की सूची होना चाहिए +@msg `items` must be a list of {{id, points}} `items` को {{id, points}} की सूची होना चाहिए @msg `items` must be an array of {{id, corners?}}, not {v} `items` को {{id, corners?}} की ऐरे होना चाहिए, {v} नहीं -@msg `items` must be an array of {id, anchors} `items` को {id, anchors} की ऐरे होना चाहिए +@msg `items` must be an array of {{id, anchors}} `items` को {{id, anchors}} की ऐरे होना चाहिए @msg `kashida` must be "none", "short", "medium", "long" or "stylistic" `kashida` होना चाहिए "none", "short", "medium", "long" या "stylistic"। @msg `kind` is one of {_1} `kind` {_1} में से एक है @msg `kind` must be "line" or "paragraph", not {other} `kind` होना चाहिए "line" या "paragraph", नहीं {other} @@ -6312,7 +6312,7 @@ antiAlias Sharp शार्प @msg artboard {i} doesn't print आर्टबोर्ड {i} प्रिंट नहीं करता है @msg artboard is a 0-based index artboard: आर्टबोर्ड एक 0-आधारित इंडेक्स है @msg artboard must be a 0-based index artboard: आर्टबोर्ड एक 0-आधारित इंडेक्स होना चाहिए -@msg artboardLayout must be {layout?, columns?, spacing?, rightToLeft?} artboardLayout को {layout?, columns?, spacing?, rightToLeft?} होना चाहिए +@msg artboardLayout must be {{layout?, columns?, spacing?, rightToLeft?}} artboardLayout को {{layout?, columns?, spacing?, rightToLeft?}} होना चाहिए @msg artboardLayout.columns must be 1 or more artboardLayout.columns को 1 या अधिक होना चाहिए @msg artboardLayout.layout must be gridByRow, gridByColumn, row or column artboardLayout.layout को gridByRow, gridByColumn, row या column होना चाहिए @msg artboardLayout.rightToLeft must be true or false artboardLayout.rightToLeft को true या false होना चाहिए @@ -6674,13 +6674,13 @@ antiAlias Sharp शार्प @msg DXF scale must be a positive number up to {_1}, not {scale} DXF स्केल को {_1} तक सकारात्मक संख्या होना चाहिए, न कि {scale} @msg dxf unit `{u}`: a unit such as mm, cm, in or pt dxf इकाई `{u}`: एक इकाई जैसे mm, cm, in या pt @msg dxf: {e} Dxf: {e} -@msg each format is an object {format, scale?, suffix?} हर फ़ॉर्मैट एक ऑब्जेक्ट {format, scale?, suffix?} है +@msg each format is an object {{format, scale?, suffix?}} हर फ़ॉर्मैट एक ऑब्जेक्ट {{format, scale?, suffix?}} है @msg each item needs an id प्रत्येक आइटम को एक आईडी की आवश्यकता होती है @msg each match needs `kind` प्रत्येक मैच की जरूरत है `kind` @msg each match needs a `name` प्रत्येक मैच को `name` की आवश्यकता होती है -@msg each of `fonts` is {family, style?}; 1 to 1000 of them `fonts` का हर आइटम {family, style?} है; 1 से 1000 आइटम +@msg each of `fonts` is {{family, style?}}; 1 to 1000 of them `fonts` का हर आइटम {{family, style?}} है; 1 से 1000 आइटम @msg each of `items` is {{id, corners?}} with an object id, not {it} `items` का हर आइटम ऑब्जेक्ट आईडी वाला {{id, corners?}} है, {it} नहीं -@msg each of `items` is {kind, item} `items` का हर आइटम {kind, item} है +@msg each of `items` is {{kind, item}} `items` का हर आइटम {{kind, item}} है @msg each row needs `from` हर पंक्ति के लिए `from` चाहिए @msg each stop needs a position प्रत्येक स्टॉप को स्थिति की आवश्यकता होती है @msg each subpath needs an anchors array प्रत्येक उपपाथ को एक एंकर सरणी की आवश्यकता होती है @@ -6712,8 +6712,8 @@ antiAlias Sharp शार्प @msg Expand: no gradient fills विस्तार: कोई ग्रेडिएंट भरता नहीं @msg Expand: nothing to expand विस्तार: विस्तार करने के लिए कुछ नहीं @msg expanded SVG styles exceed the import size limit विस्तारित SVG स्टाइल्स आयात आकार सीमा से अधिक है -@msg expected {"dataBase64"} अपेक्षित: {"dataBase64"} -@msg expected {"objects"} अपेक्षित: {"objects"} +@msg expected {{"dataBase64": "…"}} अपेक्षित: {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} अपेक्षित: {{"objects": [...]}} @msg export `{name}`: {e} निर्यात `{name}`: {e} @msg Export cancelled निर्यात रद्द @msg Export for Screens writes png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai or vectorcraft स्क्रीन के लिए एक्सपोर्ट png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai या vectorcraft लिखता है @@ -6733,7 +6733,7 @@ antiAlias Sharp शार्प @msg features must be a list of tags features: विशेषताएं टैग की एक सूची होना चाहिए @msg fidelity must be 0..100 fidelity: निष्ठा 0..100 होना चाहिए @msg file version {0} is newer than this VectorCraft supports ({VERSION}) फ़ाइल संस्करण {0} इस वेक्टर क्रेफ्ट समर्थन ({VERSION}) की तुलना में नया है। -@msg files must be {name, dataBase64} files: फ़ाइलों को {name, dataBase64} होना चाहिए +@msg files must be {{name, dataBase64}} files: फ़ाइलों को {{name, dataBase64}} होना चाहिए @msg finish editing the pattern first पहले पैटर्न को संपादित करना @msg First measured segment no longer exists पहले मापा खंड अब मौजूद नहीं है @msg fit must be none|autoHeight|shrinkText|block, got {id} fit को none|autoHeight|shrinkText|block होना चाहिए, {id} मिला @@ -6759,7 +6759,7 @@ antiAlias Sharp शार्प @msg frequency must be between 1 and 300 lines per inch frequency: आवृत्ति प्रति इंच 1 और 300 लाइनों के बीच होना चाहिए @msg from and to must be finite से और होना चाहिए करने के लिए @msg from must be [x0, y0, x1, y1] from: से होना चाहिए [x0, y0, x1, y1] -@msg give {key, value} or {values} {key, value} or {values} +@msg give {{key, value}} or {{values}} {{key, value}} या {{values}} दें @msg give `{a}` and `{b}` देना `{a}` and `{b}` @msg give `anchor`, the index of the anchor to slide खिसकाने वाले एंकर का इंडेक्स `anchor` दें @msg give `before` or `after`, not both `before` या `after` दें, दोनों नहीं @@ -6777,7 +6777,7 @@ antiAlias Sharp शार्प @msg give `id` or `guide`, not both देना `id` or `guide`, दोनों नहीं @msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` देना `inkLimit`, `removeWhiteOverprint` or `overprintBlack` @msg give `length` or `to` `length` या `to` देना -@msg give `matches`: [{kind, name, target}] `matches`: [{kind, name, target}] +@msg give `matches`: [{{kind, name, target}}] `matches`: [{{kind, name, target}}] @msg give `name` (or edit a pattern) `name` (या एक पैटर्न संपादित करें) @msg give `name` or `names` `name` या `names` दें @msg give `path` (a .wasm file) or `dataBase64` (the module) `path` (a .wasm file) या `dataBase64` (module) @@ -6834,7 +6834,7 @@ antiAlias Sharp शार्प @msg give the preset a `name` प्रीसेट देना `name` @msg give the preset a name प्रीसेट को एक नाम देना @msg give the preset a name (1–64 characters) प्रीसेट का नाम दें (1–64 अक्षर) -@msg give the settings to change, e.g. {"formats"}]} सेटिंग्स को बदलने के लिए, उदाहरण के लिए {"formats"}]} +@msg give the settings to change, e.g. {{"formats": [{{"format": "png", "scale": "2x"}}]}} सेटिंग्स को बदलने के लिए, उदाहरण के लिए {{"formats": [{{"format": "png", "scale": "2x"}}]}} @msg give the style a name स्टाइल को एक नाम दें @msg give two or more style `names` दो या अधिक स्टाइल `names` @msg give two or more swatches दो या अधिक swatch @@ -7053,7 +7053,7 @@ antiAlias Sharp शार्प @msg missing `library` (see graphicStyle.libraries) लापता `library` (graphicStyle.libraries देखें) @msg missing `library` (see swatch.library.list) लापता `library` (swatch.library.list देखें) @msg missing `library` (see symbol.libraries) `library` अनुपस्थित है (symbol.libraries देखें) -@msg missing `map` (rows [{from, to}] or {current}) लापता `map` (rows [{from, to}] या {current}) +@msg missing `map` (rows [{{from, to}}] or {{current: new}}) लापता `map` (rows [{{from, to}}] या {{current: new}}) @msg missing `matrix` [a,b,c,d,e,f] लापता `matrix` [a,b,c,d,e,f] @msg missing `name` लापता `name` @msg missing `name` (see gradient.presets.list) लापता `name` (view gradient.presets.list) @@ -7420,7 +7420,7 @@ antiAlias Sharp शार्प @msg not an export presets file (format `{_1}`) नहीं निर्यात presets फ़ाइल (format `{_1}`) @msg not an export presets file: {e} एक निर्यात प्रीसेट फ़ाइल नहीं: {e} @msg not an image VectorCraft reads (see document.formats) यह ऐसी इमेज नहीं है जिसे VectorCraft पढ़ सके (document.formats देखें) -@msg not an RTF file: it doesn't start with {\\rtf RTF फ़ाइल नहीं: यह {\rtf के साथ शुरू नहीं होता है +@msg not an RTF file: it doesn't start with {{\\rtf RTF फ़ाइल नहीं: यह {{\rtf के साथ शुरू नहीं होता है @msg not area type (text in a frame) outside perspective नहीं क्षेत्र के प्रकार (एक फ्रेम में टेक्स्ट) बाहर पर्सपेक्टिव @msg not editing an opacity mask एक opacity मास्क संपादित न करें @msg not found नहीं मिला @@ -7617,7 +7617,7 @@ antiAlias Sharp शार्प @msg printing isn't available here मुद्रण यहाँ उपलब्ध नहीं है @msg procedures nest too deeply प्रक्रियाओं घोंसला बहुत गहराई से @msg procedures nested too deeply प्रक्रियाओं ने बहुत गहराई से घोंसले -@msg quotes must be {double?, single?} quotes को {double?, single?} होना चाहिए +@msg quotes must be {{double?, single?}} quotes को {{double?, single?}} होना चाहिए @msg quotes.{k} must be an opening and a closing quote, e.g. "“”" उद्धरण.{k} एक उद्घाटन और एक समापन उद्धरण होना चाहिए, उदाहरण के लिए "“”" @msg range `{s}` is empty श्रेणी `{s}` खाली है @msg range `{s}`: `{part}` names no number सीमा `{s}`: `{part}` कोई संख्या नहीं बताता @@ -7856,14 +7856,14 @@ antiAlias Sharp शार्प @msg Switch x/y is for scatter graphs स्विच x/y स्कैटर ग्राफ़ के लिए है @msg t, dx and dy must be finite टी, डीएक्स और डीआई को परिमित होना चाहिए @msg Targa files are RGB: colorModel rgb Targa फ़ाइलें RGB हैं: colorModel rgb -@msg text must be {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} text को {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} होना चाहिए +@msg text must be {{characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?}} text को {{characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?}} होना चाहिए @msg Text options: {e} टेक्स्ट ऑप्शन्स: {e} @msg text transform is collapsed or unrepresentable टेक्स्ट रूपांतरण पतन या प्रतिनिधित्व करने योग्य है @msg Text Wrap: select a wrap object टेक्स्ट लपेटें: एक रैप ऑब्जेक्ट चुनें @msg text.{key} `{v}`: use "{_1}" or "{_2}" Text.{key} `{v}`: "{_1}" या "{_2}" का उपयोग करें। @msg text.replaceSpaces must be a whole number from 2 to 100 text.replaceSpaces को 2 से 100 के बीच पूर्णांक होना चाहिए @msg textureImage: {e} textureImage: {e} -@msg textureImage: give {path} or {name, dataBase64} of an image file, or a texture as effect.list gives it textureImage: किसी इमेज फ़ाइल का {path} या {name, dataBase64} दें, या effect.list द्वारा दिया गया टेक्सचर दें +@msg textureImage: give {{path}} or {{name, dataBase64}} of an image file, or a texture as effect.list gives it textureImage: किसी इमेज फ़ाइल का {{path}} या {{name, dataBase64}} दें, या effect.list द्वारा दिया गया टेक्सचर दें @msg that anchor can't slide: an end of an open path has nowhere to go कि एंकर स्लाइड नहीं कर सकते: एक खुले रास्ते का अंत कहीं नहीं जाना है @msg the active document changed while the question was open; nothing was deleted प्रश्न खुला रहते हुए सक्रिय डॉक्यूमेंट बदल गया; कुछ भी नहीं हटाया गया @msg that document is no longer open यह डॉक्यूमेंट अब खुला नहीं है diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index af6f586880..bfc95b271e 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -6289,8 +6289,8 @@ axis Y Axis Y tengely @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` az exportáló bővítmény 1–{MAX_EXTENSIONS} `extensions` értéket ad meg @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` csoporton kívül legfeljebb {MAX_UNGROUPED} paraméter lehet: a többinek adj meg `group` értéket @msg can't encode the input a bemenet nem kódolható -@msg expected {"dataBase64"} várt formátum: {"dataBase64"} -@msg expected {"objects"} várt formátum: {"objects"} +@msg expected {{"dataBase64": "…"}} várt formátum: {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} várt formátum: {{"objects": [...]}} @msg export `{name}`: {e} `{name}` modulexport: {e} @msg extension {e} is listed twice a(z) {e} kiterjesztés kétszer szerepel @msg extension {e}: use 1-16 lower-case letters and digits, without the dot {e} kiterjesztés: 1-16 kisbetűt és számjegyet használj, pont nélkül @@ -6354,11 +6354,11 @@ axis Y Axis Y tengely @msg a painted live effect returns only `objects` a festő élő effektus csak `objects` értéket ad vissza @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` a festő élő effektus darabjának csak `path`, `fillRule`, `fills` és `strokes` kulcsa van @msg a read-only object was left out kimaradt egy írásvédett objektum -@msg a read-only object was left out: return it, as {"id"} alone or as it was given kimaradt egy írásvédett objektum: adja vissza önmagában {"id"} formában vagy úgy, ahogy megkapta +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given kimaradt egy írásvédett objektum: adja vissza önmagában {{"id": …}} formában vagy úgy, ahogy megkapta @msg a string karakterlánc @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` a körvonalnak csak `paint`, `width`, `join`, `cap` és `miterLimit` kulcsa van -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} a körvonal formája {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} legyen -@msg an effect must be {"id", "params"?, "visible"?} az effektus formája {"id", "params"?, "visible"?} legyen +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} a körvonal formája {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} legyen +@msg an effect must be {{"id", "params"?, "visible"?}} az effektus formája {{"id", "params"?, "visible"?}} legyen @msg an effect on a fill returns only `fills` a kitöltésen lévő effektus csak `fills` értéket ad vissza @msg an effect on a stroke returns only `strokes` a körvonalon lévő effektus csak `strokes` értéket ad vissza @msg an object must be a JSON object az objektum JSON-objektum legyen diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index ce0bc58ce5..99e23af43c 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -5931,8 +5931,8 @@ axis Y Axis Asse Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` un plug-in di esportazione dichiara da 1 a {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` al massimo {MAX_UNGROUPED} parametri fuori dai gruppi: assegna agli altri un `group` @msg can't encode the input impossibile codificare l’input -@msg expected {"dataBase64"} previsto {"dataBase64"} -@msg expected {"objects"} previsto {"objects"} +@msg expected {{"dataBase64": "…"}} previsto {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} previsto {{"objects": [...]}} @msg export `{name}`: {e} esportazione del modulo `{name}`: {e} @msg extension {e} is listed twice l’estensione {e} è elencata due volte @msg extension {e}: use 1-16 lower-case letters and digits, without the dot estensione {e}: usa 1-16 lettere minuscole e cifre, senza il punto @@ -5996,11 +5996,11 @@ axis Y Axis Asse Y @msg a painted live effect returns only `objects` un effetto dinamico di pittura restituisce solo `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` un pezzo di un effetto dinamico di pittura ha solo `path`, `fillRule`, `fills` e `strokes` @msg a read-only object was left out è stato omesso un oggetto di sola lettura -@msg a read-only object was left out: return it, as {"id"} alone or as it was given è stato omesso un oggetto di sola lettura: restituiscilo come {"id"} da solo o così come è stato fornito +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given è stato omesso un oggetto di sola lettura: restituiscilo come {{"id": …}} da solo o così come è stato fornito @msg a string una stringa @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` una traccia ha solo `paint`, `width`, `join`, `cap` e `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} una traccia deve essere {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} un effetto deve essere {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} una traccia deve essere {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} un effetto deve essere {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` un effetto su un riempimento restituisce solo `fills` @msg an effect on a stroke returns only `strokes` un effetto su una traccia restituisce solo `strokes` @msg an object must be a JSON object un oggetto deve essere un oggetto JSON diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 1ecce4618a..959ee010d2 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -5996,8 +5996,8 @@ axis Y Axis Y 軸 @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` 書き出しプラグインは `extensions` を 1~{MAX_EXTENSIONS} 個宣言します @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` グループ外のパラメーターは {MAX_UNGROUPED} 個までです。ほかのパラメーターには `group` を指定してください @msg can't encode the input 入力をエンコードできません -@msg expected {"dataBase64"} {"dataBase64"} が必要です -@msg expected {"objects"} {"objects"} が必要です +@msg expected {{"dataBase64": "…"}} {{"dataBase64": "…"}} が必要です +@msg expected {{"objects": [...]}} {{"objects": [...]}} が必要です @msg export `{name}`: {e} モジュールのエクスポート `{name}`: {e} @msg extension {e} is listed twice 拡張子 {e} が 2 回指定されています @msg extension {e}: use 1-16 lower-case letters and digits, without the dot 拡張子 {e}: ドットを付けずに小文字と数字で 1-16 文字にしてください @@ -6061,11 +6061,11 @@ axis Y Axis Y 軸 @msg a painted live effect returns only `objects` ペイント型のライブ効果が返すのは `objects` だけです @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` ペイント型のライブ効果のピースに使えるのは `path`、`fillRule`、`fills`、`strokes` だけです @msg a read-only object was left out 読み取り専用のオブジェクトが省かれています -@msg a read-only object was left out: return it, as {"id"} alone or as it was given 読み取り専用のオブジェクトが省かれています: {"id"} だけの形か、渡されたとおりの形で返してください +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given 読み取り専用のオブジェクトが省かれています: {{"id": …}} だけの形か、渡されたとおりの形で返してください @msg a string 文字列 @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` 線に使えるのは `paint`、`width`、`join`、`cap`、`miterLimit` だけです -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 線は {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} の形にしてください -@msg an effect must be {"id", "params"?, "visible"?} 効果は {"id", "params"?, "visible"?} の形にしてください +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 線は {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} の形にしてください +@msg an effect must be {{"id", "params"?, "visible"?}} 効果は {{"id", "params"?, "visible"?}} の形にしてください @msg an effect on a fill returns only `fills` 塗りの効果が返すのは `fills` だけです @msg an effect on a stroke returns only `strokes` 線の効果が返すのは `strokes` だけです @msg an object must be a JSON object オブジェクトは JSON オブジェクトにしてください diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 3d6425c373..4f16368cd0 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -6257,8 +6257,8 @@ axis Y Axis Y ღერძი @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` ექსპორტის პლაგინი აცხადებს 1-დან {MAX_EXTENSIONS}-მდე `extensions`-ს @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` ჯგუფების გარეთ მაქსიმუმ {MAX_UNGROUPED} პარამეტრია დასაშვები: დანარჩენებს მიეცით `group` @msg can't encode the input შეყვანის კოდირება ვერ ხერხდება -@msg expected {"dataBase64"} მოსალოდნელი იყო {"dataBase64"} -@msg expected {"objects"} მოსალოდნელი იყო {"objects"} +@msg expected {{"dataBase64": "…"}} მოსალოდნელი იყო {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} მოსალოდნელი იყო {{"objects": [...]}} @msg export `{name}`: {e} მოდულის ექსპორტი `{name}`: {e} @msg extension {e} is listed twice გაფართოება {e} ორჯერაა მითითებული @msg extension {e}: use 1-16 lower-case letters and digits, without the dot გაფართოება {e}: გამოიყენეთ 1-16 პატარა ასო და ციფრი, წერტილის გარეშე @@ -6322,11 +6322,11 @@ axis Y Axis Y ღერძი @msg a painted live effect returns only `objects` მხატვრული ცოცხალი ეფექტი აბრუნებს მხოლოდ `objects`-ს @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` მხატვრული ცოცხალი ეფექტის ნაწილს აქვს მხოლოდ `path`, `fillRule`, `fills` და `strokes` @msg a read-only object was left out გამოტოვებულია მხოლოდ წასაკითხი ობიექტი -@msg a read-only object was left out: return it, as {"id"} alone or as it was given გამოტოვებულია მხოლოდ წასაკითხი ობიექტი: დააბრუნეთ ის მხოლოდ {"id"}-ის სახით ან ისე, როგორც მიიღეთ +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given გამოტოვებულია მხოლოდ წასაკითხი ობიექტი: დააბრუნეთ ის მხოლოდ {{"id": …}}-ის სახით ან ისე, როგორც მიიღეთ @msg a string სტრიქონი @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` კონტურს აქვს მხოლოდ `paint`, `width`, `join`, `cap` და `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} კონტური უნდა იყოს {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} ეფექტი უნდა იყოს {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} კონტური უნდა იყოს {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} ეფექტი უნდა იყოს {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` შევსების ეფექტი აბრუნებს მხოლოდ `fills`-ს @msg an effect on a stroke returns only `strokes` კონტურის ეფექტი აბრუნებს მხოლოდ `strokes`-ს @msg an object must be a JSON object ობიექტი უნდა იყოს JSON ობიექტი @@ -7243,7 +7243,7 @@ font-script Japanese იაპონური Japanese Envelope #3 იაპონური კონვერტი #3 Japanese Envelope #4 იაპონური კონვერტი #4 @msg image '{key}' has no pixels and was left out გამოსახულებას '{key}' პიქსელები არ აქვს და გამოტოვდა -@msg not an RTF file: it doesn't start with {\\rtf RTF ფაილი არ არის: არ იწყება {\\rtf-ით +@msg not an RTF file: it doesn't start with {{\\rtf RTF ფაილი არ არის: არ იწყება {{\\rtf-ით # Type Tools add-on (Object › Plug-ins › Type Tools). Type Tools ტექსტის ხელსაწყოები Text Tweaker… ტექსტის მორგება… diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index fb87488d64..b6d20ca4b4 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -5892,8 +5892,8 @@ axis Y Axis Y축 @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` 내보내기 플러그인은 `extensions`를 1~{MAX_EXTENSIONS}개 선언합니다 @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` 그룹 밖의 매개변수는 최대 {MAX_UNGROUPED}개입니다. 나머지에는 `group`을 지정하세요 @msg can't encode the input 입력을 인코딩할 수 없습니다 -@msg expected {"dataBase64"} {"dataBase64"} 형식이어야 합니다 -@msg expected {"objects"} {"objects"} 형식이어야 합니다 +@msg expected {{"dataBase64": "…"}} {{"dataBase64": "…"}} 형식이어야 합니다 +@msg expected {{"objects": [...]}} {{"objects": [...]}} 형식이어야 합니다 @msg export `{name}`: {e} 모듈 내보내기 `{name}`: {e} @msg extension {e} is listed twice 확장자 {e}이(가) 두 번 나열되었습니다 @msg extension {e}: use 1-16 lower-case letters and digits, without the dot 확장자 {e}: 점 없이 소문자와 숫자 1-16자를 사용하세요 @@ -5957,11 +5957,11 @@ axis Y Axis Y축 @msg a painted live effect returns only `objects` 페인트형 라이브 효과는 `objects`만 반환합니다 @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` 페인트형 라이브 효과의 조각에는 `path`, `fillRule`, `fills`, `strokes`만 있습니다 @msg a read-only object was left out 읽기 전용 개체가 빠졌습니다 -@msg a read-only object was left out: return it, as {"id"} alone or as it was given 읽기 전용 개체가 빠졌습니다: {"id"}만 있는 형태나 받은 그대로 반환하십시오 +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given 읽기 전용 개체가 빠졌습니다: {{"id": …}}만 있는 형태나 받은 그대로 반환하십시오 @msg a string 문자열 @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` 선에는 `paint`, `width`, `join`, `cap`, `miterLimit`만 있습니다 -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 선은 {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 형태여야 합니다 -@msg an effect must be {"id", "params"?, "visible"?} 효과는 {"id", "params"?, "visible"?} 형태여야 합니다 +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 선은 {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 형태여야 합니다 +@msg an effect must be {{"id", "params"?, "visible"?}} 효과는 {{"id", "params"?, "visible"?}} 형태여야 합니다 @msg an effect on a fill returns only `fills` 칠에 적용된 효과는 `fills`만 반환합니다 @msg an effect on a stroke returns only `strokes` 선에 적용된 효과는 `strokes`만 반환합니다 @msg an object must be a JSON object 개체는 JSON 개체여야 합니다 diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 0729e35c79..2cd431a593 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -6160,8 +6160,8 @@ axis Y Axis Oś Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` wtyczka eksportu deklaruje od 1 do {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` najwyżej {MAX_UNGROUPED} parametrów poza grupami: pozostałym nadaj `group` @msg can't encode the input nie można zakodować danych wejściowych -@msg expected {"dataBase64"} oczekiwano {"dataBase64"} -@msg expected {"objects"} oczekiwano {"objects"} +@msg expected {{"dataBase64": "…"}} oczekiwano {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} oczekiwano {{"objects": [...]}} @msg export `{name}`: {e} eksport modułu `{name}`: {e} @msg extension {e} is listed twice rozszerzenie {e} występuje dwa razy @msg extension {e}: use 1-16 lower-case letters and digits, without the dot rozszerzenie {e}: użyj 1-16 małych liter i cyfr, bez kropki @@ -6225,11 +6225,11 @@ axis Y Axis Oś Y @msg a painted live effect returns only `objects` malujący efekt dynamiczny zwraca tylko `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` element malującego efektu dynamicznego ma tylko `path`, `fillRule`, `fills` i `strokes` @msg a read-only object was left out pominięto obiekt tylko do odczytu -@msg a read-only object was left out: return it, as {"id"} alone or as it was given pominięto obiekt tylko do odczytu: zwróć go jako samo {"id"} lub w postaci, w jakiej został przekazany +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given pominięto obiekt tylko do odczytu: zwróć go jako samo {{"id": …}} lub w postaci, w jakiej został przekazany @msg a string ciągiem znaków @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` obrys ma tylko `paint`, `width`, `join`, `cap` i `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} obrys musi mieć postać {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} efekt musi mieć postać {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} obrys musi mieć postać {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} efekt musi mieć postać {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` efekt wypełnienia zwraca tylko `fills` @msg an effect on a stroke returns only `strokes` efekt obrysu zwraca tylko `strokes` @msg an object must be a JSON object obiekt musi być obiektem JSON diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 36f778dbd5..0f0301aabf 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -6221,8 +6221,8 @@ axis Y Axis Eixo Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` um plug-in de exportação declara de 1 a {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` no máximo {MAX_UNGROUPED} parâmetros fora de grupos: dê um `group` aos outros @msg can't encode the input não é possível codificar a entrada -@msg expected {"dataBase64"} esperado {"dataBase64"} -@msg expected {"objects"} esperado {"objects"} +@msg expected {{"dataBase64": "…"}} esperado {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} esperado {{"objects": [...]}} @msg export `{name}`: {e} exportação do módulo `{name}`: {e} @msg extension {e} is listed twice a extensão {e} aparece duas vezes @msg extension {e}: use 1-16 lower-case letters and digits, without the dot extensão {e}: use 1-16 letras minúsculas e dígitos, sem o ponto @@ -6286,11 +6286,11 @@ axis Y Axis Eixo Y @msg a painted live effect returns only `objects` um efeito dinâmico de pintura retorna apenas `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` uma peça de um efeito dinâmico de pintura tem apenas `path`, `fillRule`, `fills` e `strokes` @msg a read-only object was left out um objeto somente leitura foi omitido -@msg a read-only object was left out: return it, as {"id"} alone or as it was given um objeto somente leitura foi omitido: retorne-o como {"id"} sozinho ou como foi recebido +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given um objeto somente leitura foi omitido: retorne-o como {{"id": …}} sozinho ou como foi recebido @msg a string uma string @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` um traçado tem apenas `paint`, `width`, `join`, `cap` e `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} um traçado deve ser {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} um efeito deve ser {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} um traçado deve ser {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} um efeito deve ser {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` um efeito em um preenchimento retorna apenas `fills` @msg an effect on a stroke returns only `strokes` um efeito em um traçado retorna apenas `strokes` @msg an object must be a JSON object um objeto deve ser um objeto JSON @@ -7160,7 +7160,7 @@ swatch Lime Lima Line Weight: Espessura da linha: Load Variable Library Carregar biblioteca de variáveis swatch Magenta Magenta -@msg not an RTF file: it doesn't start with {\\rtf não é um arquivo RTF: ele não começa com {\\rtf +@msg not an RTF file: it doesn't start with {{\\rtf não é um arquivo RTF: ele não começa com {{\\rtf swatch Ocean Oceano shape Open Aberta swatch Orange Laranja diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 442a9612d4..f86e17a2c9 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -5917,8 +5917,8 @@ axis Y Axis Ось Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` модуль экспорта объявляет от 1 до {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` вне групп может быть не более {MAX_UNGROUPED} параметров: задайте остальным `group` @msg can't encode the input не удаётся закодировать входные данные -@msg expected {"dataBase64"} ожидалось {"dataBase64"} -@msg expected {"objects"} ожидалось {"objects"} +@msg expected {{"dataBase64": "…"}} ожидалось {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} ожидалось {{"objects": [...]}} @msg export `{name}`: {e} экспорт модуля `{name}`: {e} @msg extension {e} is listed twice расширение {e} указано дважды @msg extension {e}: use 1-16 lower-case letters and digits, without the dot расширение {e}: используйте 1-16 строчных букв и цифр, без точки @@ -5982,11 +5982,11 @@ axis Y Axis Ось Y @msg a painted live effect returns only `objects` рисующий динамический эффект возвращает только `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` у части рисующего динамического эффекта есть только `path`, `fillRule`, `fills` и `strokes` @msg a read-only object was left out пропущен объект только для чтения -@msg a read-only object was left out: return it, as {"id"} alone or as it was given пропущен объект только для чтения: верните его как один {"id"} или в том виде, в каком он был передан +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given пропущен объект только для чтения: верните его как один {{"id": …}} или в том виде, в каком он был передан @msg a string строка @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` у обводки есть только `paint`, `width`, `join`, `cap` и `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} обводка должна иметь вид {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} эффект должен иметь вид {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} обводка должна иметь вид {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} эффект должен иметь вид {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` эффект на заливке возвращает только `fills` @msg an effect on a stroke returns only `strokes` эффект на обводке возвращает только `strokes` @msg an object must be a JSON object объект должен быть объектом JSON @@ -7265,7 +7265,7 @@ breakText Glyphs Глифы @id pathfinder.add Объединить @msg give corners of the path: anchors between two straight sides укажите углы контура: опорные точки между двумя прямыми сторонами @msg image '{key}' has no pixels and was left out изображение '{key}' не содержит пикселов и было пропущено -@msg not an RTF file: it doesn't start with {\\rtf это не файл RTF: он не начинается с {\\rtf +@msg not an RTF file: it doesn't start with {{\\rtf это не файл RTF: он не начинается с {{\\rtf @msg this is a PostScript file (an .ai saved in an older format or without PDF compatibility, or an EPS file), which can't be opened yet: save it as PDF, PDF-compatible .ai or SVG это файл PostScript (.ai, сохранённый в старом формате или без совместимости с PDF, либо EPS-файл), который пока нельзя открыть: сохраните его как PDF, .ai с совместимостью с PDF или SVG @msg this kind of brush has no options dialog yet у кистей этого типа пока нет диалога параметров digits Hindi Хинди diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 8a8f8453b6..2fb87bd7f1 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -6357,11 +6357,11 @@ axis Y Axis Y-axel @msg a painted live effect returns only `objects` en målande live-effekt returnerar bara `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` en del av en målande live-effekt har bara `path`, `fillRule`, `fills` och `strokes` @msg a read-only object was left out ett skrivskyddat objekt utelämnades -@msg a read-only object was left out: return it, as {"id"} alone or as it was given ett skrivskyddat objekt utelämnades: returnera det som enbart {"id"} eller som det gavs +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given ett skrivskyddat objekt utelämnades: returnera det som enbart {{"id": …}} eller som det gavs @msg a string en sträng @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` en kontur har bara `paint`, `width`, `join`, `cap` och `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} en kontur måste vara {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} en effekt måste vara {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} en kontur måste vara {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} en effekt måste vara {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` en effekt på en fyllning returnerar bara `fills` @msg an effect on a stroke returns only `strokes` en effekt på en kontur returnerar bara `strokes` @msg an object must be a JSON object ett objekt måste vara ett JSON-objekt @@ -6879,7 +6879,7 @@ anchor Points: Punkter: VectorCraft Updates Uppdateringar för VectorCraft Yonroku-ban Yonroku-ban @msg image '{key}' has no pixels and was left out bilden '{key}' har inga pixlar och utelämnades -@msg not an RTF file: it doesn't start with {\\rtf inte en RTF-fil: den börjar inte med {\\rtf +@msg not an RTF file: it doesn't start with {{\\rtf inte en RTF-fil: den börjar inte med {{\\rtf shape Open Öppen # Color Effects add-on: Select by Color Kind. @@ -7478,7 +7478,7 @@ digits Hindi Hindi @msg `expand` must be true or false `expand` måste vara true eller false @msg `files` must be 1 to 1000 paths of font files the last text.findFontFiles search found `files` måste vara 1 till 1000 sökvägar till typsnittsfiler som den senaste text.findFontFiles-sökningen hittade @msg `folder` must be an absolute folder path `folder` måste vara en absolut mappsökväg -@msg `fontAxes` must be an object of axis tags and values, such as {"wght"} `fontAxes` måste vara ett objekt med axeltaggar och värden, till exempel {"wght"} +@msg `fontAxes` must be an object of axis tags and values, such as {{"wght": 650}} `fontAxes` måste vara ett objekt med axeltaggar och värden, till exempel {{"wght": 650}} @msg `format` must be a string `format` måste vara en sträng @msg `format` must be one of {_1} `format` måste vara något av {_1} @msg `fractions` is chop or scale `fractions` är chop eller scale @@ -7501,12 +7501,12 @@ digits Hindi Hindi @msg `index` must be a point index `index` måste vara ett punktindex @msg `index` must be a whole number or null `index` måste vara ett heltal eller null @msg `indices` must be a non-empty array of item indices `indices` måste vara en icke-tom array av objektindex -@msg `items` is a list of {kind, item} `items` är en lista med {kind, item} +@msg `items` is a list of {{kind, item}} `items` är en lista med {{kind, item}} @msg `items` is empty `items` är tom @msg `items` must be a list of {{id, anchors?}}, not {v} `items` måste vara en lista med {{id, anchors?}}, inte {v} -@msg `items` must be a list of {id, points} `items` måste vara en lista med {id, points} +@msg `items` must be a list of {{id, points}} `items` måste vara en lista med {{id, points}} @msg `items` must be an array of {{id, corners?}}, not {v} `items` måste vara en array av {{id, corners?}}, inte {v} -@msg `items` must be an array of {id, anchors} `items` måste vara en array av {id, anchors} +@msg `items` must be an array of {{id, anchors}} `items` måste vara en array av {{id, anchors}} @msg `kashida` must be "none", "short", "medium", "long" or "stylistic" `kashida` måste vara "none", "short", "medium", "long" eller "stylistic" @msg `kind` is one of {_1} `kind` är något av {_1} @msg `kind` must be "round", "invertedRound" or "chamfer", not {v} `kind` måste vara "round", "invertedRound" eller "chamfer", inte {v} @@ -7672,7 +7672,7 @@ digits Hindi Hindi @msg artboard {i} doesn't print rityta {i} skrivs inte ut @msg artboard is a 0-based index artboard är ett 0-baserat index @msg artboard must be a 0-based index artboard måste vara ett 0-baserat index -@msg artboardLayout must be {layout?, columns?, spacing?, rightToLeft?} artboardLayout måste vara {layout?, columns?, spacing?, rightToLeft?} +@msg artboardLayout must be {{layout?, columns?, spacing?, rightToLeft?}} artboardLayout måste vara {{layout?, columns?, spacing?, rightToLeft?}} @msg artboardLayout.columns must be 1 or more artboardLayout.columns måste vara 1 eller mer @msg artboardLayout.layout must be gridByRow, gridByColumn, row or column artboardLayout.layout måste vara gridByRow, gridByColumn, row eller column @msg artboardLayout.rightToLeft must be true or false artboardLayout.rightToLeft måste vara true eller false @@ -7820,13 +7820,13 @@ digits Hindi Hindi @msg DXF scale must be a positive number up to {_1}, not {scale} DXF-skalan måste vara ett positivt tal upp till {_1}, inte {scale} @msg dxf unit `{u}`: a unit such as mm, cm, in or pt dxf-enhet `{u}`: en enhet som mm, cm, in eller pt @msg dxf: {e} dxf: {e} -@msg each format is an object {format, scale?, suffix?} varje format är ett objekt {format, scale?, suffix?} +@msg each format is an object {{format, scale?, suffix?}} varje format är ett objekt {{format, scale?, suffix?}} @msg each item needs an id varje objekt behöver ett id @msg each match needs `kind` varje matchning behöver `kind` @msg each match needs a `name` varje matchning behöver ett `name` -@msg each of `fonts` is {family, style?}; 1 to 1000 of them varje post i `fonts` är {family, style?}; 1 till 1000 stycken +@msg each of `fonts` is {{family, style?}}; 1 to 1000 of them varje post i `fonts` är {{family, style?}}; 1 till 1000 stycken @msg each of `items` is {{id, corners?}} with an object id, not {it} varje post i `items` är {{id, corners?}} med ett objekt-id, inte {it} -@msg each of `items` is {kind, item} varje post i `items` är {kind, item} +@msg each of `items` is {{kind, item}} varje post i `items` är {{kind, item}} @msg each row needs `from` varje rad behöver `from` @msg each stop needs a position varje stopp behöver en position @msg each subpath needs an anchors array varje delbana behöver en anchors-array @@ -7844,8 +7844,8 @@ digits Hindi Hindi @msg EPS Save writes all artwork: use document.export for selected-only EPS När du sparar som EPS skrivs allt bildmaterial: använd document.export för EPS med bara det markerade @msg every numbered name for the result is taken alla numrerade namn för resultatet är upptagna @msg expanded SVG styles exceed the import size limit de expanderade SVG-stilarna överskrider storleksgränsen för import -@msg expected {"dataBase64"} förväntade {"dataBase64"} -@msg expected {"objects"} förväntade {"objects"} +@msg expected {{"dataBase64": "…"}} förväntade {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} förväntade {{"objects": [...]}} @msg export `{name}`: {e} export av `{name}`: {e} @msg Export for Screens writes png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai or vectorcraft Exportera för skärmar skriver png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai eller vectorcraft @msg export presets file is larger than {MAX_PRESET_FILE_BYTES} bytes filen med exportförinställningar är större än {MAX_PRESET_FILE_BYTES} byte @@ -7858,7 +7858,7 @@ digits Hindi Hindi @msg featureChanges must be a list of tags featureChanges måste vara en lista med taggar @msg features must be a list of tags features måste vara en lista med taggar @msg fidelity must be 0..100 fidelity måste vara 0..100 -@msg files must be {name, dataBase64} files måste vara {name, dataBase64} +@msg files must be {{name, dataBase64}} files måste vara {{name, dataBase64}} @msg fit must be none|autoHeight|shrinkText|block, got {id} fit måste vara none|autoHeight|shrinkText|block, fick {id} @msg Flare click coordinates must be finite numbers Klickkoordinaterna för Ljusreflex måste vara ändliga tal @msg flattener: {e} utplattning: {e} @@ -7876,7 +7876,7 @@ digits Hindi Hindi @msg frequency must be between 1 and 300 lines per inch frequency måste vara mellan 1 och 300 linjer per tum @msg from and to must be finite from och to måste vara ändliga @msg from must be [x0, y0, x1, y1] from måste vara [x0, y0, x1, y1] -@msg give {key, value} or {values} ange {key, value} eller {values} +@msg give {{key, value}} or {{values}} ange {{key, value}} eller {{values}} @msg give `before` or `after`, not both ange `before` eller `after`, inte båda @msg give `char` or `text` ange `char` eller `text` @msg give `colors`, or `color` and `rule` ange `colors`, eller `color` och `rule` @@ -7891,7 +7891,7 @@ digits Hindi Hindi @msg give `id` and `anchors`, or `items`, not both ange `id` och `anchors`, eller `items`, inte båda @msg give `id` or `guide`, not both ange `id` eller `guide`, inte båda @msg give `length` or `to` ange `length` eller `to` -@msg give `matches`: [{kind, name, target}] ange `matches`: [{kind, name, target}] +@msg give `matches`: [{{kind, name, target}}] ange `matches`: [{{kind, name, target}}] @msg give `name` (or edit a pattern) ange `name` (eller redigera ett mönster) @msg give `name` or `names` ange `name` eller `names` @msg give `path` (a .wasm file) or `dataBase64` (the module) ange `path` (en .wasm-fil) eller `dataBase64` (modulen) @@ -7927,7 +7927,7 @@ digits Hindi Hindi @msg give the preset a `name` ge förinställningen ett `name` @msg give the preset a name ge förinställningen ett namn @msg give the preset a name (1–64 characters) ge förinställningen ett namn (1–64 tecken) -@msg give the settings to change, e.g. {"formats"}]} ange inställningarna som ska ändras, t.ex. {"formats"}]} +@msg give the settings to change, e.g. {{"formats": [{{"format": "png", "scale": "2x"}}]}} ange inställningarna som ska ändras, t.ex. {{"formats": [{{"format": "png", "scale": "2x"}}]}} @msg give the style a name ge stilen ett namn @msg give two or more style `names` ange två eller fler stilnamn i `names` @msg give two or more swatches ange två eller fler färgrutor @@ -8032,7 +8032,7 @@ digits Hindi Hindi @msg missing `library` `library` saknas @msg missing `library` (see graphicStyle.libraries) `library` saknas (se graphicStyle.libraries) @msg missing `library` (see swatch.library.list) `library` saknas (se swatch.library.list) -@msg missing `map` (rows [{from, to}] or {current}) `map` saknas (rader [{from, to}] eller {current}) +@msg missing `map` (rows [{{from, to}}] or {{current: new}}) `map` saknas (rader [{{from, to}}] eller {{current: new}}) @msg missing `matrix` [a,b,c,d,e,f] `matrix` [a,b,c,d,e,f] saknas @msg missing `name` (see gradient.presets.list) `name` saknas (se gradient.presets.list) @msg missing `offset` (a distance in points) `offset` saknas (ett avstånd i punkter) @@ -8324,7 +8324,7 @@ digits Hindi Hindi @msg print settings: {e} utskriftsinställningar: {e} @msg procedures nest too deeply procedurerna är nästlade för djupt @msg procedures nested too deeply procedurerna nästlades för djupt -@msg quotes must be {double?, single?} quotes måste vara {double?, single?} +@msg quotes must be {{double?, single?}} quotes måste vara {{double?, single?}} @msg quotes.{k} must be an opening and a closing quote, e.g. "“”" quotes.{k} måste vara ett inledande och ett avslutande citattecken, t.ex. "“”" @msg rasterEffectsPpi must be 1–2400 (72 screen, 150 medium, 300 high) rasterEffectsPpi måste vara 1–2400 (72 skärm, 150 medel, 300 hög) @msg rating must be a whole number from 0 to {MAX_RATING} rating måste vara ett heltal från 0 till {MAX_RATING} @@ -8436,13 +8436,13 @@ digits Hindi Hindi @msg SVG is not UTF-8, UTF-16 or ISO 8859-1 SVG-filen är inte i UTF-8, UTF-16 eller ISO 8859-1 @msg swatchConflict must be "merge" or "add", not {v} swatchConflict måste vara "merge" eller "add", inte {v} @msg Switch x/y is for scatter graphs Växla x/y gäller spridningsdiagram -@msg text must be {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} text måste vara {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} +@msg text must be {{characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?}} text måste vara {{characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?}} @msg Text options: {e} Textalternativ: {e} @msg text transform is collapsed or unrepresentable texttransformeringen är kollapsad eller kan inte återges @msg text.{key} `{v}`: use "{_1}" or "{_2}" text.{key} `{v}`: använd "{_1}" eller "{_2}" @msg text.replaceSpaces must be a whole number from 2 to 100 text.replaceSpaces måste vara ett heltal från 2 till 100 @msg textureImage: {e} textureImage: {e} -@msg textureImage: give {path} or {name, dataBase64} of an image file, or a texture as effect.list gives it textureImage: ange {path} eller {name, dataBase64} för en bildfil, eller en textur så som effect.list anger den +@msg textureImage: give {{path}} or {{name, dataBase64}} of an image file, or a texture as effect.list gives it textureImage: ange {{path}} eller {{name, dataBase64}} för en bildfil, eller en textur så som effect.list anger den @msg that makes more than {MAX_PIECES} slices det ger fler än {MAX_PIECES} skivor @msg that object is not in the overlap det objektet ingår inte i överlappningen @msg the action set ids are not a list åtgärdsuppsättningarnas id:n är inte en lista diff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs index 66caa1c3a4..01594beb5b 100644 --- a/crates/ui-egui/src/i18n/tests.rs +++ b/crates/ui-egui/src/i18n/tests.rs @@ -1821,6 +1821,55 @@ fn message_keys_keep_doubled_braces() { assert_eq!(as_template(r"it doesn't start with {\rtf"), r"it doesn't start with {\rtf"); } +/// The braces of a message that is not a format string (a plain literal or a `&str` constant) are +/// literal, so its catalog key doubles them; a `format!` string or an `#[error(…)]` string keeps +/// its `{{`, `}}` and placeholders. +#[test] +fn plain_message_keys_double_their_braces() { + let code = concat!( + "const SHAPE: &str = \"a shape is {\\\"kind\\\": …}\";\n", + "fn f() -> Result<()> { Err(Error::Output(\"expected {\\\"dataBase64\\\": \\\"…\\\"}\".into())) }\n", + "fn g() -> Result<()> { Err(SHAPE.into()) }\n", + "fn h() -> Result<()> { Err(bad(C, \"not an RTF file: it doesn't start with {\\\\rtf\")) }\n", + "fn i() -> Result<()> { Err(bad(C, format!(\"`{key}` must be {{min?, max?}}\"))) }\n", + "#[error(\"the file is {0} bytes, not {{size}}\")]\n", + ); + let consts: std::collections::BTreeMap> = str_consts(code).into_iter().map(|(name, value)| (name, vec![value])).collect(); + // The engine's `error(` helper also occurs in each `#[error(` attribute. + let found: std::collections::BTreeSet = source_messages(code, &[("bad(", 1), ("error(", 0)], &consts).into_iter().collect(); + let want = [ + r#"expected {{"dataBase64": "…"}}"#, + r#"a shape is {{"kind": …}}"#, + r"not an RTF file: it doesn't start with {{\rtf", + "`{key}` must be {{min?, max?}}", + "the file is {0} bytes, not {{size}}", + ]; + assert_eq!(found, want.iter().map(|s| s.to_string()).collect::>(), "{found:#?}"); + assert_eq!(as_literal_key("a {b} c}"), "a {{b}} c}}"); +} + +/// A catalog row for a message with literal braces translates that message and no other: it has no +/// placeholder to take the rest of a message with the same start. +#[test] +fn literal_brace_rows_match_only_their_message() { + let c = Catalog::parse("@msg\texpected {{\"dataBase64\": \"…\"}}\terwartet: {{\"dataBase64\": \"…\"}}\n"); + let (form, caps) = c.message(r#"expected {"dataBase64": "…"}"#).expect("matches"); + assert!(caps.is_empty(), "{caps:?}"); + assert_eq!(fill_once(form, &caps), r#"erwartet: {"dataBase64": "…"}"#); + assert!(c.message("expected value at line 1 column 1").is_none()); + assert!(c.message(r#"expected {"dataBase64"}"#).is_none()); + assert_eq!(exact_translation(&c, r#"expected {"dataBase64": "…"}"#).as_deref(), Some(r#"erwartet: {"dataBase64": "…"}"#)); + // An exact message is found at any length; a template is matched only up to its limit. + let long = format!("{{{{{}}}}}", "x".repeat(3000)); + let c = Catalog::parse(&format!("@msg\t{long}\tlong {{{{}}}}\n@msg\tshort {{x}}\tshort {{x}} (de)\n")); + let shown = format!("{{{}}}", "x".repeat(3000)); + assert_eq!(c.message(&shown).map(|(f, _)| f), Some("long {{}}")); + assert_eq!(exact_translation(&c, &shown).as_deref(), Some("long {}")); + assert_eq!(c.message("short y").map(|(f, _)| f), Some("short {x} (de)")); + // In the real catalog, a serde reason after the plug-in output error stays English. + assert_eq!(message(de(), "plug-in output: expected value at line 1 column 1"), "Plug-in-Ausgabe: expected value at line 1 column 1"); +} + /// `plugin.run` of an importer, an exporter or a live effect names the command that runs it with /// the JSON that picks it, and every complete-message catalog translates that error with the /// plug-in's id and the JSON kept. @@ -3670,7 +3719,8 @@ const LATER_MESSAGE_VARIANTS: &[(&str, usize)] = &[("Disabled", 1)]; const NOT_MESSAGES: &[&str] = &["quit", "cancelled", "vc_manifest"]; /// Every status and error message literal in [`MESSAGE_CRATES`] (test modules aside), as catalog -/// templates: `{}` becomes `{_1}`, `{_2}` … and format specs are dropped (`{n:?}` → `{n}`). +/// templates: `{}` becomes `{_1}`, `{_2}` … and format specs are dropped (`{n:?}` → `{n}`), and +/// the braces of a message that is not a format string are doubled. pub fn message_literals() -> std::collections::BTreeSet { message_literals_in(MESSAGE_CRATES) } @@ -3790,27 +3840,35 @@ fn named_const<'a>(rest: &str, consts: &'a std::collections::BTreeMap>) -> Vec { let code = &without_comments(code); - let after_markers = MESSAGE_MARKERS.iter().flat_map(|marker| code.match_indices(marker).map(|(at, _)| &code[at + marker.len()..])); + let after_markers = + MESSAGE_MARKERS.iter().flat_map(|marker| code.match_indices(marker).map(|(at, _)| (&code[at + marker.len()..], *marker == "#[error("))); let in_variants = code.match_indices("Error::").filter_map(|(at, m)| { let rest = &code[at + m.len()..]; let (variant, args) = rest.split_at(rest.find(|c: char| !c.is_ascii_alphanumeric() && c != '_').unwrap_or(rest.len())); let named = variant.starts_with(|c: char| c.is_ascii_uppercase()) && !NAME_VARIANTS.contains(&variant); let before = LATER_MESSAGE_VARIANTS.iter().find(|(v, _)| *v == variant).map_or(0, |&(_, n)| n); - if named { skip_args(args.strip_prefix('(')?, before) } else { None } + if named { skip_args(args.strip_prefix('(')?, before).map(|rest| (rest, false)) } else { None } }); let in_helpers = helpers.iter().flat_map(|&(call, before)| { code.match_indices(call) .filter(|&(at, _)| call.starts_with('.') || !code[..at].ends_with(|c: char| c.is_alphanumeric() || c == '_' || c == '.')) - .filter_map(move |(at, _)| skip_args(&code[at + call.len()..], before)) + // `format!(` given as a helper, and an `error(` helper that is an `#[error(…)]` attribute, take a format string. + .filter_map(move |(at, _)| { + skip_args(&code[at + call.len()..], before).map(|rest| (rest, call == "format!(" || code[..at].ends_with("#["))) + }) }); let mut out = vec![]; - for rest in after_markers.chain(in_variants).chain(in_helpers) { + for (rest, takes_format) in after_markers.chain(in_variants).chain(in_helpers) { let rest = rest.trim_start(); let rest = rest.strip_prefix('&').map_or(rest, str::trim_start); - let rest = rest.strip_prefix("format!(").map_or(rest, str::trim_start); + let formatted = rest.strip_prefix("format!(").map(str::trim_start); + let format = takes_format || formatted.is_some(); + let rest = formatted.unwrap_or(rest); let lits = match rest.strip_prefix('"') { Some(quoted) => string_literal(quoted).into_iter().collect(), None => named_const(rest, consts).to_vec(), @@ -3819,7 +3877,7 @@ fn source_messages(code: &str, helpers: &[(&str, usize)], consts: &std::collecti let has_word = lit.as_bytes().windows(3).any(|w| w.iter().all(u8::is_ascii_lowercase)); let key_name = lit.len() > 1 && lit.starts_with('`') && lit.ends_with('`') && !lit.contains(' '); if has_word && !key_name && !NOT_MESSAGES.contains(&lit.as_str()) { - out.push(as_template(&lit)); + out.push(if format { as_template(&lit) } else { as_literal_key(&lit) }); } } } @@ -3926,6 +3984,12 @@ fn as_template(s: &str) -> String { out } +/// A message that is not a format string as a catalog key: each of its braces is literal, so it is +/// written `{{` or `}}`. +fn as_literal_key(s: &str) -> String { + s.replace('{', "{{").replace('}', "}}") +} + /// Render-site labels looked up in a context fall back to the plain row and then to English, and /// their templates fill in English as in any language. #[test] diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index ef8773c31b..1a1b27ec4b 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -4472,7 +4472,7 @@ axis Both Her İkisi @msg not an HP-GL file HP-GL dosyası değil @msg not a PICT file PICT dosyası değil @msg `pens` must be an array of 1 to 255 #rrggbb colors `pens` 1 ile 255 arasında #rrggbb renginden oluşan bir dizi olmalıdır -@msg not an RTF file: it doesn't start with {\\rtf bir RTF dosyası değil: {\\rtf ile başlamıyor +@msg not an RTF file: it doesn't start with {{\\rtf bir RTF dosyası değil: {{\\rtf ile başlamıyor @msg not found bulunamadı @msg not in pattern editing mode desen düzenleme modunda değil @msg finish editing the pattern first önce deseni düzenlemeyi bitir @@ -6262,8 +6262,8 @@ axis Y Axis Y ekseni @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` dışa aktarma eklentisi 1 ile {MAX_EXTENSIONS} arasında `extensions` bildirir @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` gruplar dışında en fazla {MAX_UNGROUPED} parametre olabilir: diğerlerine bir `group` verin @msg can't encode the input girdi kodlanamıyor -@msg expected {"dataBase64"} beklenen: {"dataBase64"} -@msg expected {"objects"} beklenen: {"objects"} +@msg expected {{"dataBase64": "…"}} beklenen: {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} beklenen: {{"objects": [...]}} @msg export `{name}`: {e} modül dışa aktarımı `{name}`: {e} @msg extension {e} is listed twice {e} uzantısı iki kez listelenmiş @msg extension {e}: use 1-16 lower-case letters and digits, without the dot {e} uzantısı: nokta olmadan 1-16 küçük harf ve rakam kullanın @@ -6327,11 +6327,11 @@ axis Y Axis Y ekseni @msg a painted live effect returns only `objects` boyama türü canlı efekt yalnızca `objects` döndürür @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` boyama türü canlı efektin bir parçasında yalnızca `path`, `fillRule`, `fills` ve `strokes` bulunur @msg a read-only object was left out salt okunur bir nesne atlandı -@msg a read-only object was left out: return it, as {"id"} alone or as it was given salt okunur bir nesne atlandı: onu yalnızca {"id"} olarak veya verildiği gibi döndürün +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given salt okunur bir nesne atlandı: onu yalnızca {{"id": …}} olarak veya verildiği gibi döndürün @msg a string bir dize @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` bir konturda yalnızca `paint`, `width`, `join`, `cap` ve `miterLimit` bulunur -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} bir kontur {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} biçiminde olmalıdır -@msg an effect must be {"id", "params"?, "visible"?} bir efekt {"id", "params"?, "visible"?} biçiminde olmalıdır +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} bir kontur {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} biçiminde olmalıdır +@msg an effect must be {{"id", "params"?, "visible"?}} bir efekt {{"id", "params"?, "visible"?}} biçiminde olmalıdır @msg an effect on a fill returns only `fills` dolgudaki bir efekt yalnızca `fills` döndürür @msg an effect on a stroke returns only `strokes` konturdaki bir efekt yalnızca `strokes` döndürür @msg an object must be a JSON object bir nesne bir JSON nesnesi olmalıdır diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 0bccbd8cb6..92d06a892d 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -5911,8 +5911,8 @@ axis Y Axis Вісь Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` модуль експорту оголошує від 1 до {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` поза групами може бути не більше {MAX_UNGROUPED} параметрів: задайте решті `group` @msg can't encode the input не вдається закодувати вхідні дані -@msg expected {"dataBase64"} очікувалося {"dataBase64"} -@msg expected {"objects"} очікувалося {"objects"} +@msg expected {{"dataBase64": "…"}} очікувалося {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} очікувалося {{"objects": [...]}} @msg export `{name}`: {e} експорт модуля `{name}`: {e} @msg extension {e} is listed twice розширення {e} вказано двічі @msg extension {e}: use 1-16 lower-case letters and digits, without the dot розширення {e}: використовуйте 1-16 малих літер і цифр, без крапки @@ -5976,11 +5976,11 @@ axis Y Axis Вісь Y @msg a painted live effect returns only `objects` малювальний динамічний ефект повертає лише `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` частина малювального динамічного ефекту має лише `path`, `fillRule`, `fills` і `strokes` @msg a read-only object was left out пропущено об’єкт лише для читання -@msg a read-only object was left out: return it, as {"id"} alone or as it was given пропущено об’єкт лише для читання: поверніть його як один {"id"} або в тому вигляді, у якому його передано +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given пропущено об’єкт лише для читання: поверніть його як один {{"id": …}} або в тому вигляді, у якому його передано @msg a string рядок @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` обведення має лише `paint`, `width`, `join`, `cap` і `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} обведення має мати вигляд {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} ефект має мати вигляд {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} обведення має мати вигляд {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} ефект має мати вигляд {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` ефект на заливці повертає лише `fills` @msg an effect on a stroke returns only `strokes` ефект на обведенні повертає лише `strokes` @msg an object must be a JSON object об’єкт має бути об’єктом JSON diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 4f084029db..e31a09de53 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -5912,8 +5912,8 @@ axis Y Axis Trục Y @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` plug-in xuất khai báo từ 1 đến {MAX_EXTENSIONS} `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` tối đa {MAX_UNGROUPED} tham số nằm ngoài nhóm: hãy đặt `group` cho các tham số còn lại @msg can't encode the input không thể mã hóa dữ liệu đầu vào -@msg expected {"dataBase64"} cần có {"dataBase64"} -@msg expected {"objects"} cần có {"objects"} +@msg expected {{"dataBase64": "…"}} cần có {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} cần có {{"objects": [...]}} @msg export `{name}`: {e} export `{name}` của mô-đun: {e} @msg extension {e} is listed twice phần mở rộng {e} được liệt kê hai lần @msg extension {e}: use 1-16 lower-case letters and digits, without the dot phần mở rộng {e}: dùng 1-16 chữ thường và chữ số, không có dấu chấm @@ -5977,11 +5977,11 @@ axis Y Axis Trục Y @msg a painted live effect returns only `objects` hiệu ứng động kiểu tô chỉ trả về `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` một phần của hiệu ứng động kiểu tô chỉ có `path`, `fillRule`, `fills` và `strokes` @msg a read-only object was left out một đối tượng chỉ đọc đã bị bỏ sót -@msg a read-only object was left out: return it, as {"id"} alone or as it was given một đối tượng chỉ đọc đã bị bỏ sót: hãy trả lại nó dưới dạng chỉ {"id"} hoặc như khi được nhận +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given một đối tượng chỉ đọc đã bị bỏ sót: hãy trả lại nó dưới dạng chỉ {{"id": …}} hoặc như khi được nhận @msg a string một chuỗi @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` nét chỉ có `paint`, `width`, `join`, `cap` và `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} nét phải có dạng {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} -@msg an effect must be {"id", "params"?, "visible"?} hiệu ứng phải có dạng {"id", "params"?, "visible"?} +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} nét phải có dạng {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} +@msg an effect must be {{"id", "params"?, "visible"?}} hiệu ứng phải có dạng {{"id", "params"?, "visible"?}} @msg an effect on a fill returns only `fills` hiệu ứng trên phần tô chỉ trả về `fills` @msg an effect on a stroke returns only `strokes` hiệu ứng trên nét chỉ trả về `strokes` @msg an object must be a JSON object đối tượng phải là một đối tượng JSON diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index b04e65a65b..fa7f4998ac 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -6144,8 +6144,8 @@ axis Y Axis Y 轴 @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` 导出增效工具声明 1 到 {MAX_EXTENSIONS} 个 `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` 组外最多 {MAX_UNGROUPED} 个参数:请为其余参数指定 `group` @msg can't encode the input 无法编码输入 -@msg expected {"dataBase64"} 应为 {"dataBase64"} -@msg expected {"objects"} 应为 {"objects"} +@msg expected {{"dataBase64": "…"}} 应为 {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} 应为 {{"objects": [...]}} @msg export `{name}`: {e} 模块导出 `{name}`:{e} @msg extension {e} is listed twice 扩展名 {e} 列出了两次 @msg extension {e}: use 1-16 lower-case letters and digits, without the dot 扩展名 {e}:请使用 1-16 个小写字母和数字,不带点 @@ -6209,11 +6209,11 @@ axis Y Axis Y 轴 @msg a painted live effect returns only `objects` 绘制型实时效果只返回 `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` 绘制型实时效果的片段只有 `path`、`fillRule`、`fills` 和 `strokes` @msg a read-only object was left out 漏掉了一个只读对象 -@msg a read-only object was left out: return it, as {"id"} alone or as it was given 漏掉了一个只读对象:请以单独的 {"id"} 或原样返回它 +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given 漏掉了一个只读对象:请以单独的 {{"id": …}} 或原样返回它 @msg a string 字符串 @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` 描边只有 `paint`、`width`、`join`、`cap` 和 `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 描边必须是 {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 形式 -@msg an effect must be {"id", "params"?, "visible"?} 效果必须是 {"id", "params"?, "visible"?} 形式 +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 描边必须是 {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 形式 +@msg an effect must be {{"id", "params"?, "visible"?}} 效果必须是 {{"id", "params"?, "visible"?}} 形式 @msg an effect on a fill returns only `fills` 填色上的效果只返回 `fills` @msg an effect on a stroke returns only `strokes` 描边上的效果只返回 `strokes` @msg an object must be a JSON object 对象必须是 JSON 对象 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index be62fde8a7..eab4694fbe 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -7,6 +7,7 @@ # the translation is a single string (see `plural` in i18n.rs) # anything else a disambiguating context passed to `tr_ctx` # escapes \n \t \\ inside a column. `{name}` placeholders must appear in both columns. +# In @msg rows a literal brace is written {{ or }}, as in a Rust format string. # lines starting with # and blank lines are ignored. # # Clean-room: every entry was written from the plain meaning of the English label using the @@ -5949,8 +5950,8 @@ axis Y Axis Y 軸 @msg an exporter declares 1 to {MAX_EXTENSIONS} `extensions` 匯出增效模組宣告 1 到 {MAX_EXTENSIONS} 個 `extensions` @msg at most {MAX_UNGROUPED} parameters outside groups: give the others a `group` 群組外最多 {MAX_UNGROUPED} 個參數:請為其餘參數指定 `group` @msg can't encode the input 無法編碼輸入 -@msg expected {"dataBase64"} 應為 {"dataBase64"} -@msg expected {"objects"} 應為 {"objects"} +@msg expected {{"dataBase64": "…"}} 應為 {{"dataBase64": "…"}} +@msg expected {{"objects": [...]}} 應為 {{"objects": [...]}} @msg export `{name}`: {e} 模組匯出 `{name}`:{e} @msg extension {e} is listed twice 副檔名 {e} 列出了兩次 @msg extension {e}: use 1-16 lower-case letters and digits, without the dot 副檔名 {e}:請使用 1-16 個小寫字母和數字,不含點 @@ -6014,11 +6015,11 @@ axis Y Axis Y 軸 @msg a painted live effect returns only `objects` 繪製型即時效果只傳回 `objects` @msg a painted live effect's piece has only `path`, `fillRule`, `fills` and `strokes` 繪製型即時效果的片段只有 `path`、`fillRule`、`fills` 和 `strokes` @msg a read-only object was left out 漏掉了一個唯讀物件 -@msg a read-only object was left out: return it, as {"id"} alone or as it was given 漏掉了一個唯讀物件:請以單獨的 {"id"} 或原樣傳回它 +@msg a read-only object was left out: return it, as {{"id": …}} alone or as it was given 漏掉了一個唯讀物件:請以單獨的 {{"id": …}} 或原樣傳回它 @msg a string 字串 @msg a stroke has only `paint`, `width`, `join`, `cap` and `miterLimit` 筆畫只有 `paint`、`width`、`join`、`cap` 和 `miterLimit` -@msg a stroke must be {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 筆畫必須是 {"paint", "width"?, "join"?, "cap"?, "miterLimit"?} 形式 -@msg an effect must be {"id", "params"?, "visible"?} 效果必須是 {"id", "params"?, "visible"?} 形式 +@msg a stroke must be {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 筆畫必須是 {{"paint", "width"?, "join"?, "cap"?, "miterLimit"?}} 形式 +@msg an effect must be {{"id", "params"?, "visible"?}} 效果必須是 {{"id", "params"?, "visible"?}} 形式 @msg an effect on a fill returns only `fills` 填色上的效果只傳回 `fills` @msg an effect on a stroke returns only `strokes` 筆畫上的效果只傳回 `strokes` @msg an object must be a JSON object 物件必須是 JSON 物件 diff --git a/docs/development.md b/docs/development.md index 37f2b770ac..cbf3088faa 100644 --- a/docs/development.md +++ b/docs/development.md @@ -294,7 +294,10 @@ other `sv-*` locale resolve to it), Georgian (`ka`, complete; `ka-GE` and `ka_GE control channel, MCP and tests read them) and are translated only where the status bar draws them (`i18n::msg`). `@msg` catalog rows hold a whole message or a template such as `Couldn't open {name}: {e}`; `{_1}`, `{_2}` … stand for the format string's `{}`, and the values in the - placeholders are translated in turn (the reason after `: {e}` is often a message too). Czech, German, Greek, Spanish, French, Georgian, Hungarian, Italian, Japanese, Korean, Polish, Brazilian Portuguese, Russian, Simplified Chinese, Traditional Chinese, Swedish, Ukrainian, Vietnamese, Finnish, Turkish and Catalan + placeholders are translated in turn (the reason after `: {e}` is often a message too). A literal brace in a + row is written `{{` or `}}`, in the English and in the translation: a message made with `format!` keeps the + doubled braces of its format string, and a plain string literal has each of its braces doubled, so the row for + `"expected {\"objects\": [...]}"` is `expected {{"objects": [...]}}`. Czech, German, Greek, Spanish, French, Georgian, Hungarian, Italian, Japanese, Korean, Polish, Brazilian Portuguese, Russian, Simplified Chinese, Traditional Chinese, Swedish, Ukrainian, Vietnamese, Finnish, Turkish and Catalan translate status and error messages (`COMPLETE_MESSAGES` in `i18n::tests`); the untranslated report lists the message literals the scan finds that one of them has no row for. The scan reads `Err("…")`, `Other(…)`, `#[error(…)]` and `status(…)` messages, messages given to an error enum's variant (`PsError::Limit(…)`, the reason diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index f04ee3c910..9514a6a78e 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -847,6 +847,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - The History panel, Edit › Undo and Edit › Redo translate the names of the steps that apply or redefine a character or paragraph style and of the step that redefines a graphic style: each such step keeps its template (`Apply {name}`, `Redefine {name}`, `Redefine Graphic Style “{name}”`) and the style's name, every complete catalog has a row for each template, and the panel and the menu show the style's name as the document holds it, except the Normal styles' names, which they show in the interface language (`steps_named_after_a_style_list_the_template_around_the_name`, `undo_and_redo_name_a_style_step_around_the_style_name`). - The status bar translates the limits a plug-in run can exceed (its instruction, time and memory budgets and its output size) and the error of a plug-in removal that leaves the plug-in's grant in the plug-in store, in every language that translates every message. The untranslated-strings report also lists messages that an error or a status takes from a `&str` constant (`plugin_limit_errors_are_translated`, `message_scan_reads_messages_held_in_constants`). - The status bar translates the plug-in host's other errors (manifest, module and run checks, the output an importer, exporter or effect returns, and the approval a plug-in's permissions need) in every language that translates every message. A JSON object or array inside a message stays as written, and a message that wraps another one, such as `plug-in manifest: {0}`, is matched by its own row before a row that starts with a placeholder. The reasons inside these errors (what is wrong with a parameter's spec or dialog keys, the value a parameter needs, what is wrong with an object, stroke, paint or effect in a plug-in's output) are translated with them, and the untranslated-strings report lists the reasons the plug-in host's error helpers take (`plugin_messages_are_translated_in_every_complete_catalog`, `plugin_errors_translate_with_their_values`, `plugin_error_reasons_are_translated_with_the_error`, `message_scan_reads_plugin_helpers`, `templates_that_start_with_text_match_first`). + - A status or error message whose braces are literal, such as a plug-in's `expected {"objects": [...]}` or a command's `quotes must be {double?, single?}`, is translated only when the whole message matches its row: the row writes those braces doubled and has no placeholder, so it no longer replaces a different message that starts with the same words, such as a JSON reason `expected value at line 1 column 1`, which stays in English. A row without placeholders is found at any message length (`plain_message_keys_double_their_braces`, `literal_brace_rows_match_only_their_message`). - The status bar translates the errors a script's `File` and `Folder` objects, `vc.run`, `$.evalFile`, the `$` object's properties and functions, `alert`, `confirm` and `prompt`, `vc.document` and `vc.log` raise, the limits a run can pass, and the errors of Drop Script Engine, and the line for a run that fails (a syntax error, a thrown error, a limit, a stop or an internal error, with the script's name, the line and column, the included file it is in and the files left written), in every language that translates every message. The script's name, paths, numbers, command ids and the text a script throws itself are shown as they are. A failure with no line and column, such as an error in code `eval` compiled, is shown with one colon after the script's name (`an_error_without_a_place_names_the_script_and_kind`). A message template that names a value twice matches only when both places hold the same text, so the line for a failed run is not taken for the message inside it (`a_repeated_placeholder_matches_the_same_text`). The untranslated-strings report also lists the messages the script host's `fail`, `value` and `over` helpers take and the errors the script interpreter throws, and a constant's text comes from the file or crate that declares it, so the Scripts menu's headers are not listed as messages (`script_errors_are_translated`, `script_host_errors_are_translated`, `message_scan_reads_script_interpreter_errors`, `message_scan_reads_constants_of_the_file_and_its_crate`, `message_scan_skips_test_modules_with_any_test_cfg`). - Localised UI: menus (in-window and native), panels, dialogs, toolbar and Preferences read from per-language catalogs (`crates/ui-egui/src/i18n`, see `docs/development.md`); Traditional Chinese (Taiwan), Simplified Chinese (mainland), Japanese, Korean, Vietnamese, German, Spanish, French, Italian, Polish, Brazilian Portuguese, Russian, Ukrainian, Georgian and Catalan ship complete, and Czech covers every menu label (and more), with system-locale detection on macOS, Windows, Linux and the web (the browser's languages, or `?lang=`), a Language preference and, on macOS, a VectorCraft ▸ Language menu. Names are never translated (fonts and their styles, layers, artboards, saved presets, user libraries, custom workspaces, recent files, plug-ins). The counts that Package's status and question, the folder search of Missing Fonts and Find Linked Files, the modified and missing linked file prompts and the CSS Properties panel's notes show use the interface language's plural forms instead of a fixed "(s)" form. Evidence: `the_missing_links_note_uses_each_count_form` in `crates/ui-egui/src/dialogs/tests_package.rs`, `the_modified_links_question_uses_each_count_form` in `crates/ui-egui/src/dialogs/missing_links.rs`, `search_counts_use_each_count_form` in `crates/ui-egui/src/dialogs/missing_fonts/tests.rs` and `the_unnamed_objects_note_uses_each_count_form` in `crates/ui-egui/src/panels/tests_css_properties.rs`.