From f024f5a5f258b9028a79269bddb63876b513d048 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Mon, 2 Nov 2026 11:10:05 +0700 Subject: [PATCH] Variables: Export Data Sets marks visibility and image columns with # and @ Squashed from #5141 onto main. --- crates/engine/src/cmd/variablecmds.rs | 5 +- crates/engine/src/cmd/variablecmds/csv.rs | 85 ++++++++++++++++++--- crates/engine/src/tests/variables.rs | 91 +++++++++++++++++++++-- crates/ui-egui/src/i18n/bg.tsv | 3 + crates/ui-egui/src/i18n/bs.tsv | 3 + crates/ui-egui/src/i18n/ca.tsv | 3 + crates/ui-egui/src/i18n/cs.tsv | 3 + crates/ui-egui/src/i18n/da.tsv | 3 + crates/ui-egui/src/i18n/de.tsv | 3 + crates/ui-egui/src/i18n/el.tsv | 3 + crates/ui-egui/src/i18n/es.tsv | 3 + crates/ui-egui/src/i18n/fi.tsv | 3 + crates/ui-egui/src/i18n/fr.tsv | 3 + crates/ui-egui/src/i18n/hu.tsv | 3 + crates/ui-egui/src/i18n/id.tsv | 3 + crates/ui-egui/src/i18n/it.tsv | 3 + crates/ui-egui/src/i18n/ja.tsv | 3 + crates/ui-egui/src/i18n/ka.tsv | 3 + crates/ui-egui/src/i18n/ko.tsv | 3 + crates/ui-egui/src/i18n/nl.tsv | 3 + crates/ui-egui/src/i18n/pl.tsv | 3 + crates/ui-egui/src/i18n/pt-br.tsv | 3 + crates/ui-egui/src/i18n/ru.tsv | 3 + crates/ui-egui/src/i18n/sv.tsv | 3 + crates/ui-egui/src/i18n/tr.tsv | 3 + crates/ui-egui/src/i18n/uk.tsv | 3 + crates/ui-egui/src/i18n/vi.tsv | 3 + crates/ui-egui/src/i18n/zh-hans.tsv | 3 + crates/ui-egui/src/i18n/zh-hant.tsv | 3 + crates/ui-egui/src/panels/variables.rs | 37 +++++++++ docs/mcp.md | 8 +- 31 files changed, 287 insertions(+), 17 deletions(-) diff --git a/crates/engine/src/cmd/variablecmds.rs b/crates/engine/src/cmd/variablecmds.rs index 66948e692..96b3c2a7a 100644 --- a/crates/engine/src/cmd/variablecmds.rs +++ b/crates/engine/src/cmd/variablecmds.rs @@ -5,7 +5,8 @@ //! variable, or a graph root to a `graph` variable (CSV data), put a row of values in //! each dataset, and `dataset.select` swaps the whole document to that row in one undo //! step. `dataset.import` / `dataset.export` move those rows as CSV (header: `name` -//! then variable names); import also reads tab-separated files, files without the +//! then variable names, which export writes with `#` before a visibility variable and `@` +//! before an image variable); import also reads tab-separated files, files without the //! `name` column, and header cells that define new variables (`#` for visibility, `@` for //! image, no prefix for text). `variable.loadLibrary` replaces the variables and data sets with the //! text variables and data sets of a variable library, the XML file of the reference app's Save @@ -807,7 +808,7 @@ pub fn specs() -> Vec { "Export Data Sets…", ["Window", "Variables"], None, - "{path?} write every dataset as CSV (header: name, then variables); without path → {csv, datasets}. Refused when the document has more than 1000 data sets or 256 variables, the most dataset.import reads", + "{path?} write every dataset as CSV (header: name, then one column per variable: `#Name` for a visibility variable, `@Name` for an image variable, and the name alone for a text or graph variable, as dataset.import reads them). Refused when the document has more than 1000 data sets or 256 variables, the most dataset.import reads, or when a variable's header is another variable's name (a visibility variable `Show` next to a text variable `#Show`) → {path, datasets, warning?}; without path → {csv, datasets, warning?}. `warning` names the variables whose header or values make a document without them refuse the file (a % header, a # header whose values aren't true or false); otherwise it names the variables such a document doesn't read back with their kind (text variables whose names start with # or @, graph variables)", has_doc, dataset_export ), diff --git a/crates/engine/src/cmd/variablecmds/csv.rs b/crates/engine/src/cmd/variablecmds/csv.rs index 47376d78f..507c153f8 100644 --- a/crates/engine/src/cmd/variablecmds/csv.rs +++ b/crates/engine/src/cmd/variablecmds/csv.rs @@ -187,12 +187,66 @@ fn value_to_cell(v: &DataValue) -> String { } } -/// Build the CSV of every dataset (header `name` then variables in definition order). -fn datasets_to_csv(vars: &Variables) -> String { +/// The header cell that [`datasets_to_csv`] writes for `v`, as [`header_variable`] reads it: `#` +/// before a visibility variable's name, `@` before an image variable's name, and the name alone +/// for a text or graph variable. +fn export_header(v: &Variable) -> String { + match v.kind { + VariableKind::Visibility => format!("#{}", v.name), + VariableKind::Image => format!("@{}", v.name), + VariableKind::Text | VariableKind::Graph => v.name.clone(), + } +} + +/// What [`dataset_import`] does with each variable's column of the CSV that [`datasets_to_csv`] +/// writes, in a document without the variables: the first list names the variables whose header +/// or values it refuses, so it doesn't import the file (a `%` header, a `#` header whose values +/// aren't true or false, a header that names a variable an earlier column named), and the second +/// the variables it reads as another variable (a text variable whose name starts with `#` or `@`, +/// and a graph variable, which no header cell defines). +fn kinds_a_new_document_loses(vars: &Variables) -> (Vec<&str>, Vec<&str>) { + const C: &str = "dataset.import"; + let none = BTreeMap::new(); + let mut defined = Vec::new(); + let (mut refused, mut other) = (Vec::new(), Vec::new()); + let mut seen = BTreeSet::new(); + for (i, v) in vars.variables.iter().enumerate() { + let header = export_header(v); + let cell = header.trim(); + // Column 1 holds the dataset names. + let read = if cell.is_empty() { None } else { header_variable(cell, i + 2, &none, &mut defined, C).ok() }; + // The import refuses a header that names a variable an earlier column named. + let Some((name, kind)) = read.filter(|(name, _)| seen.insert(name.clone())) else { + refused.push(v.name.as_str()); + continue; + }; + let cells_read = vars.datasets.iter().filter_map(|d| d.values.get(&v.name)).all(|val| { + let cell = value_to_cell(val); + cell_to_value(kind, &cell, cell.is_empty(), &name, 2, C).is_ok() + }); + if !cells_read { + refused.push(v.name.as_str()); + } else if name != v.name || kind != v.kind { + other.push(v.name.as_str()); + } + } + (refused, other) +} + +/// Build the CSV of every dataset (header `name` then each variable's [`export_header`] in +/// definition order). Refused when a variable's header is another variable's name, which the +/// import reads as that variable (a visibility variable `Show` next to a text variable `#Show`). +fn datasets_to_csv(vars: &Variables, cmd: &str) -> Result { + let names: BTreeSet<&str> = vars.variables.iter().map(|v| v.name.as_str()).collect(); let mut out = String::from("name"); for v in &vars.variables { + let header = export_header(v); + if header != v.name && names.contains(header.as_str()) { + let (name, other) = (&v.name, &header); + return Err(bad(cmd, format!("the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them"))); + } out.push(','); - out.push_str(&csv_escape(&v.name)); + out.push_str(&csv_escape(&header)); } out.push('\n'); for ds in &vars.datasets { @@ -205,7 +259,7 @@ fn datasets_to_csv(vars: &Variables) -> String { } out.push('\n'); } - out + Ok(out) } /// The variable that a datasets CSV header cell (trimmed, not empty) in 1-based `column` names, @@ -343,7 +397,10 @@ pub(super) fn dataset_import(s: &mut Session, p: &Value) -> Result { Ok(json!({"imported": imported, "updated": updated, "names": names, "defined": new_variables})) } -/// Export every dataset as CSV (`name` then variables). With `path`, write the file; else return `{csv}`. +/// Export every dataset as CSV ([`datasets_to_csv`]). With `path`, write the file; else return +/// `{csv}`. The reply's `warning` names the variables whose column makes a document without them +/// refuse the file, or else the variables it doesn't read back with their kind +/// ([`kinds_a_new_document_loses`]); the app shows it in its status bar. /// A document with more data sets or variables than [`dataset_import`] reads is refused. pub(super) fn dataset_export(s: &mut Session, p: &Value) -> Result { const C: &str = "dataset.export"; @@ -358,16 +415,26 @@ pub(super) fn dataset_export(s: &mut Session, p: &Value) -> Result { if st.doc.variables.variables.len() > MAX_CSV_COLS { return Err(bad(C, format!("more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS}"))); } - let csv = datasets_to_csv(&st.doc.variables); + let csv = datasets_to_csv(&st.doc.variables, C)?; if csv.len() > MAX_CSV_BYTES { return Err(bad(C, format!("CSV would be larger than {MAX_CSV_BYTES} bytes"))); } - match str_param(p, "path") { + let mut out = match str_param(p, "path") { Some(path) => { let path = absolute_path(path); write_file(&path, csv.as_bytes())?; - Ok(json!({"path": path, "datasets": st.doc.variables.datasets.len()})) + json!({"path": path, "datasets": st.doc.variables.datasets.len()}) } - None => Ok(json!({"csv": csv, "datasets": st.doc.variables.datasets.len()})), + None => json!({"csv": csv, "datasets": st.doc.variables.datasets.len()}), + }; + let (refused, lost) = kinds_a_new_document_loses(&st.doc.variables); + let list = |vars: &[&str]| vars.iter().map(|n| format!("`{n}`")).collect::>().join(", "); + if !refused.is_empty() { + let names = list(&refused); + out["warning"] = json!(format!("a new document refuses this file because of these variables: {names}")); + } else if !lost.is_empty() { + let names = list(&lost); + out["warning"] = json!(format!("a new document won't read these variables back with their kind: {names}")); } + Ok(out) } diff --git a/crates/engine/src/tests/variables.rs b/crates/engine/src/tests/variables.rs index 1844d9f20..c54350cc9 100644 --- a/crates/engine/src/tests/variables.rs +++ b/crates/engine/src/tests/variables.rs @@ -1521,13 +1521,13 @@ fn datasets_csv_header_prefixes_define_variables() { #[test] fn datasets_csv_exact_names_win_over_prefixes() { let mut s = session(); - for (name, kind) in [("#Shown", "text"), ("@Photo", "visibility"), ("%Chart", "graph"), ("Shown", "visibility")] { + for (name, kind) in [("#Shown", "text"), ("@Photo", "visibility"), ("%Chart", "graph"), ("Shown", "image")] { s.execute("variable.define", &json!({"name": name, "kind": kind})).unwrap(); } - let values = json!({"#Shown": "hello", "@Photo": true, "%Chart": ",Q\nX,3", "Shown": false}); + let values = json!({"#Shown": "hello", "@Photo": true, "%Chart": ",Q\nX,3", "Shown": "s.png"}); s.execute("dataset.new", &json!({"name": "A", "values": values})).unwrap(); let csv = s.execute("dataset.export", &json!({})).unwrap()["csv"].as_str().unwrap().to_string(); - assert!(csv.starts_with("name,#Shown,@Photo,%Chart,Shown\n"), "{csv}"); + assert!(csv.starts_with("name,#Shown,#@Photo,%Chart,@Shown\n"), "{csv}"); s.execute("dataset.delete", &json!({"names": ["A"]})).unwrap(); let imp = s.execute("dataset.import", &json!({"csv": csv})).unwrap(); assert_eq!((imp["imported"].as_u64(), imp["defined"].clone()), (Some(1), json!([]))); @@ -1535,10 +1535,91 @@ fn datasets_csv_exact_names_win_over_prefixes() { assert_eq!(value("#Shown"), Some(vectorcraft_doc::DataValue::Text("hello".into()))); assert_eq!(value("@Photo"), Some(vectorcraft_doc::DataValue::Visible(true))); assert_eq!(value("%Chart"), Some(vectorcraft_doc::DataValue::Graph(",Q\nX,3".into()))); - assert_eq!(value("Shown"), Some(vectorcraft_doc::DataValue::Visible(false))); + assert_eq!(value("Shown"), Some(vectorcraft_doc::DataValue::Image("s.png".into()))); assert_eq!(s.doc().unwrap().doc.variables.variables.len(), 4); } +/// `dataset.export` writes `#` before a visibility variable's header and `@` before an image +/// variable's, so a document without the variables reads the file back with their kinds. The +/// reply's `warning` names the variables it doesn't: a text variable whose name starts with `#`, +/// `@` or `%`, and a graph variable. +#[test] +fn datasets_csv_export_marks_visibility_and_image_columns() { + let mut s = session(); + for (name, kind) in [("Name", "text"), ("Show", "visibility"), ("Photo", "image")] { + s.execute("variable.define", &json!({"name": name, "kind": kind})).unwrap(); + } + s.execute("dataset.new", &json!({"name": "A", "values": {"Name": "Ann", "Show": false, "Photo": "a.png"}})).unwrap(); + let out = s.execute("dataset.export", &json!({})).unwrap(); + assert_eq!(out["csv"], "name,Name,#Show,@Photo\nA,Ann,false,a.png\n"); + assert!(out.get("warning").is_none(), "{out}"); + + let mut fresh = session(); + let imp = fresh.execute("dataset.import", &json!({"csv": out["csv"]})).unwrap(); + assert_eq!(imp["defined"], json!(["Name", "Show", "Photo"])); + let listed = fresh.execute("variable.list", &json!({})).unwrap(); + let kinds: Vec<_> = listed["variables"].as_array().unwrap().iter().map(|v| v["kind"].clone()).collect(); + assert_eq!(kinds, [json!("text"), json!("visibility"), json!("image")]); + let value = |var: &str| fresh.doc().unwrap().doc.variables.dataset("A").and_then(|d| d.values.get(var)).cloned(); + assert_eq!(value("Show"), Some(vectorcraft_doc::DataValue::Visible(false))); + assert_eq!(value("Photo"), Some(vectorcraft_doc::DataValue::Image("a.png".into()))); + + for (name, kind) in [("#Tag", "text"), ("Chart", "graph"), ("@Note", "text")] { + s.execute("variable.define", &json!({"name": name, "kind": kind})).unwrap(); + } + let out = s.execute("dataset.export", &json!({})).unwrap(); + assert_eq!(out["warning"], "a new document won't read these variables back with their kind: `#Tag`, `Chart`, `@Note`"); + assert!(out["csv"].as_str().unwrap().starts_with("name,Name,#Show,@Photo,#Tag,Chart,@Note\n"), "{out}"); +} + +/// The export's `warning` names the variables whose column a document without the variables +/// refuses, so it doesn't import the file: a `%` header, a `#` header whose values aren't true or +/// false, and a header that names a variable an earlier column defined with another kind. A +/// header that names such a variable with its kind is read with that kind, and is listed as one +/// read back with another kind. +#[test] +fn datasets_csv_export_warns_of_headers_a_new_document_refuses() { + let export = |vars: &[(&str, &str)], values: Value| { + let mut s = session(); + for (name, kind) in vars { + s.execute("variable.define", &json!({"name": name, "kind": kind})).unwrap(); + } + s.execute("dataset.new", &json!({"name": "A", "values": values})).unwrap(); + let out = s.execute("dataset.export", &json!({})).unwrap(); + let refused = session().execute("dataset.import", &json!({"csv": out["csv"]})).is_err(); + (out["warning"].as_str().unwrap_or("").to_string(), refused) + }; + let refuses = |names: &str| format!("a new document refuses this file because of these variables: {names}"); + let loses = |names: &str| format!("a new document won't read these variables back with their kind: {names}"); + + assert_eq!(export(&[("%Rate", "text"), ("Chart", "graph")], json!({})), (refuses("`%Rate`"), true)); + assert_eq!(export(&[("#Tag", "text")], json!({"#Tag": "hello"})), (refuses("`#Tag`"), true)); + assert_eq!(export(&[("#Tag", "text")], json!({"#Tag": "yes"})), (loses("`#Tag`"), false)); + assert_eq!(export(&[("#Seen", "text"), ("Seen", "image")], json!({})), (refuses("`Seen`"), true)); + assert_eq!(export(&[("#Seen", "text"), ("Seen", "text")], json!({})), (refuses("`Seen`"), true)); +} + +/// `dataset.export` is refused, naming both variables, when a variable's header is another +/// variable's name, which an import reads as that variable; with `path`, no file is written. +#[test] +fn datasets_csv_export_refuses_a_header_that_names_another_variable() { + let dir = Folder::new("vars-csv-header"); + for (first, second) in + [(("Show", "visibility"), ("#Show", "text")), (("Photo", "image"), ("@Photo", "graph")), (("X", "visibility"), ("#X", "image"))] + { + let mut s = session(); + for (name, kind) in [first, second] { + s.execute("variable.define", &json!({"name": name, "kind": kind})).unwrap(); + } + let e = s.execute("dataset.export", &json!({})).unwrap_err().to_string(); + let (name, other) = (first.0, second.0); + assert!(e.contains(&format!("for `{name}` would read back as the variable `{other}`")), "{e}"); + let out = dir.file("sets.csv"); + assert!(s.execute("dataset.export", &json!({"path": out})).is_err()); + assert!(!std::path::Path::new(&out).exists(), "{out}"); + } +} + /// A `%` header cell that isn't a variable's name (graph data files) is refused with its column, /// and the import defines nothing. #[test] @@ -1621,7 +1702,7 @@ fn datasets_csv_round_trips_and_rejects_bad_input() { let exported = s.execute("dataset.export", &json!({})).unwrap(); let csv = exported["csv"].as_str().unwrap().to_string(); - assert!(csv.starts_with("name,Name,Show,Photo\n"), "{csv}"); + assert!(csv.starts_with("name,Name,#Show,@Photo\n"), "{csv}"); assert!(csv.contains("Alice") && csv.contains("Bob") && csv.contains("false"), "{csv}"); // Clear rows, import again, apply B. diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index f3f6cbfbb..367da9cb3 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -4348,6 +4348,9 @@ axis Both И двете @msg unsupported: {0} не се поддържа: {0} @msg variables are locked променливите са заключени @msg variables that aren't text were left out: {kinds} променливите, които не са текстови, бяха пропуснати: {kinds} +@msg a new document won't read these variables back with their kind: {names} нов документ няма да прочете тези променливи обратно с техния вид: {names} +@msg a new document refuses this file because of these variables: {names} нов документ отказва този файл заради тези променливи: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them заглавието `{header}` за `{name}` ще бъде прочетено като променливата `{other}`: преименувайте едната от тях @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files файловете от версия {0} не могат да бъдат компресирани: само версия {COMPRESSED_SINCE} и по-нови отварят компресирани файлове @msg width and height are at least 1 pixel ширината и височината са най-малко 1 пиксел @msg workspace name can't be empty името на работното пространство не може да бъде празно diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index d7efa9c0e..035a87d75 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -4747,6 +4747,9 @@ imageTrace Outline Obris @msg unsupported: {0} nepodržano: {0} @msg variables are locked varijable su zaključane @msg variables that aren't text were left out: {kinds} izostavljene su varijable koje nisu tekst: {kinds} +@msg a new document won't read these variables back with their kind: {names} novi dokument neće ponovo učitati ove varijable s njihovom vrstom: {names} +@msg a new document refuses this file because of these variables: {names} novi dokument odbija ovu datoteku zbog ovih varijabli: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them zaglavlje `{header}` za `{name}` učitalo bi se kao varijabla `{other}`: preimenujte jednu od njih @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` i `options.{key}: {inner}` se ne slažu: navedite opciju jednom @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files datoteke verzije {0} ne mogu se komprimirati: komprimirane datoteke otvaraju samo verzija {COMPRESSED_SINCE} i novije @msg width and height are at least 1 pixel širina i visina su najmanje 1 piksel diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 205991cbc..dee5c3138 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -5604,6 +5604,9 @@ digits Malayalam Malaiàlam @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} més de {MAX_CSV_ROWS} conjunts de dades: Importa conjunts de dades en llegeix com a màxim {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} més de {MAX_CSV_COLS} variables: Importa conjunts de dades en llegeix com a màxim {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} les variables que no són text s’han omès: {kinds} +@msg a new document won't read these variables back with their kind: {names} un document nou no tornarà a llegir aquestes variables amb el seu tipus: {names} +@msg a new document refuses this file because of these variables: {names} un document nou rebutja aquest fitxer a causa d'aquestes variables: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them la capçalera `{header}` de `{name}` es tornaria a llegir com la variable `{other}`: canvieu el nom d’una de les dues @msg VectorCraft doesn't search other apps' or the system's folders: {path} VectorCraft no cerca a les carpetes d’altres aplicacions ni del sistema: {path} @msg VectorCraft doesn't search the Shared or Public folder in Users: {path} VectorCraft no cerca a la carpeta Shared o Public d’Usuaris: {path} @msg VectorCraft failed to start: {e} VectorCraft no s’ha pogut iniciar: {e} diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index a6d23ba3c..9b0218d5c 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -4791,6 +4791,9 @@ imageTrace Outline Obrys @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} více než {MAX_CSV_ROWS} sad dat: Importovat sady dat načte nejvýše {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} více než {MAX_CSV_COLS} proměnných: Importovat sady dat načte nejvýše {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} proměnné, které nejsou textové, byly vynechány: {kinds} +@msg a new document won't read these variables back with their kind: {names} nový dokument tyto proměnné nenačte zpět s jejich druhem: {names} +@msg a new document refuses this file because of these variables: {names} nový dokument tento soubor kvůli těmto proměnným odmítne: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them záhlaví `{header}` pro `{name}` by se načetlo jako proměnná `{other}`: jednu z nich přejmenujte @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` a `options.{key}: {inner}` si odporují: zadejte volbu jen jednou @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files soubory verze {0} nelze komprimovat: komprimované soubory otevírá až verze {COMPRESSED_SINCE} a novější @msg width and height are at least 1 pixel šířka i výška jsou alespoň 1 obrazový bod diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 5a2391342..5cfe139d8 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -5138,6 +5138,9 @@ mark-style Japanese Japansk Export Data Sets… Eksportér datasæt… Load Variable Library… Indlæs variabelbibliotek… @msg variables that aren't text were left out: {kinds} variabler, der ikke er tekst, blev udeladt: {kinds} +@msg a new document won't read these variables back with their kind: {names} et nyt dokument læser ikke disse variabler tilbage med deres type: {names} +@msg a new document refuses this file because of these variables: {names} et nyt dokument afviser denne fil på grund af disse variabler: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them overskriften `{header}` for `{name}` ville blive læst som variablen `{other}`: omdøb en af dem Make Graph Dynamic Gør diagram dynamisk Batch… Batch… Source Folder: Kildemappe: diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 1433e9d1c..d23d59d4e 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4400,6 +4400,9 @@ theme Appearance Erscheinungsbild @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} mehr als {MAX_CSV_ROWS} Datensätze: „Datensätze importieren“ liest höchstens {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} mehr als {MAX_CSV_COLS} Variablen: „Datensätze importieren“ liest höchstens {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} die Variablen, die kein Text sind, wurden ausgelassen: {kinds} +@msg a new document won't read these variables back with their kind: {names} ein neues Dokument liest diese Variablen nicht mit ihrer Art zurück: {names} +@msg a new document refuses this file because of these variables: {names} ein neues Dokument lehnt diese Datei wegen dieser Variablen ab: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them die Kopfzeile `{header}` für `{name}` würde als die Variable `{other}` gelesen: Benennen Sie eine der beiden um @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` und `options.{key}: {inner}` widersprechen sich: Option nur einmal angeben @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files Dateien der Version {0} können nicht komprimiert werden: Erst Version {COMPRESSED_SINCE} und neuer öffnen komprimierte Dateien @msg width and height are at least 1 pixel Breite und Höhe betragen mindestens 1 Pixel diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index f28611c54..e2a111848 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -4433,6 +4433,9 @@ digits Malayalam Μαλαγιάλαμ @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} περισσότερα από {MAX_CSV_ROWS} σύνολα δεδομένων: η Εισαγωγή συνόλων δεδομένων διαβάζει έως {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} περισσότερες από {MAX_CSV_COLS} μεταβλητές: η Εισαγωγή συνόλων δεδομένων διαβάζει έως {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} οι μεταβλητές που δεν είναι κειμένου παραλείφθηκαν: {kinds} +@msg a new document won't read these variables back with their kind: {names} ένα νέο έγγραφο δεν θα διαβάσει ξανά αυτές τις μεταβλητές με το είδος τους: {names} +@msg a new document refuses this file because of these variables: {names} ένα νέο έγγραφο απορρίπτει αυτό το αρχείο λόγω αυτών των μεταβλητών: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them η κεφαλίδα `{header}` για το `{name}` θα διαβαζόταν ως η μεταβλητή `{other}`: μετονομάστε μία από τις δύο @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once τα `{key}: {top}` και `options.{key}: {inner}` διαφέρουν: δώστε την επιλογή μόνο μία φορά @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files τα αρχεία έκδοσης {0} δεν μπορούν να συμπιεστούν: μόνο η έκδοση {COMPRESSED_SINCE} και νεότερες ανοίγουν συμπιεσμένα αρχεία @msg width and height are at least 1 pixel το πλάτος και το ύψος πρέπει να είναι τουλάχιστον 1 εικονοστοιχείο diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index dbd5dfb23..9e63d5266 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4485,6 +4485,9 @@ axis Both Ambos @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} más de {MAX_CSV_ROWS} conjuntos de datos: Importar conjuntos de datos lee como máximo {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} más de {MAX_CSV_COLS} variables: Importar conjuntos de datos lee como máximo {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} se omitieron las variables que no son de texto: {kinds} +@msg a new document won't read these variables back with their kind: {names} un documento nuevo no volverá a leer estas variables con su tipo: {names} +@msg a new document refuses this file because of these variables: {names} un documento nuevo rechaza este archivo por estas variables: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them el encabezado `{header}` de `{name}` se leería como la variable `{other}`: cambie el nombre de una de las dos @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` y `options.{key}: {inner}` no coinciden: indique la opción una sola vez @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files los archivos de la versión {0} no se pueden comprimir: solo la versión {COMPRESSED_SINCE} y posteriores abren archivos comprimidos @msg width and height are at least 1 pixel el ancho y el alto son de al menos 1 píxel diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index e232c972a..13f2d85be 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4693,6 +4693,9 @@ imageTrace Outline Ääriviiva @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} yli {MAX_CSV_ROWS} tietojoukkoa: Tuo tietojoukot lukee enintään {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} yli {MAX_CSV_COLS} muuttujaa: Tuo tietojoukot lukee enintään {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} muut kuin tekstimuuttujat jätettiin pois: {kinds} +@msg a new document won't read these variables back with their kind: {names} uusi asiakirja ei lue näitä muuttujia takaisin niiden lajin mukaisina: {names} +@msg a new document refuses this file because of these variables: {names} uusi asiakirja hylkää tämän tiedoston näiden muuttujien vuoksi: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them muuttujan `{name}` otsikko `{header}` luettaisiin muuttujaksi `{other}`: nimeä toinen niistä uudelleen @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` ja `options.{key}: {inner}` ovat ristiriidassa: anna asetus vain kerran @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files version {0} tiedostoja ei voi pakata: pakattuja tiedostoja voi avata vain versiosta {COMPRESSED_SINCE} alkaen @msg width and height are at least 1 pixel leveys ja korkeus ovat vähintään 1 pikseli diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 789e40c81..213bdb3d3 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4475,6 +4475,9 @@ axis Both Les deux @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} plus de {MAX_CSV_ROWS} jeux de données : Importer des jeux de données en lit au plus {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} plus de {MAX_CSV_COLS} variables : Importer des jeux de données en lit au plus {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} les variables qui ne sont pas du texte ({kinds}) ont été ignorées +@msg a new document won't read these variables back with their kind: {names} un nouveau document ne relira pas ces variables avec leur type : {names} +@msg a new document refuses this file because of these variables: {names} un nouveau document refuse ce fichier à cause de ces variables : {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them l’en-tête `{header}` de `{name}` serait relu comme la variable `{other}` : renommez l’une des deux @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` et `options.{key}: {inner}` ne concordent pas. Indiquez l’option une seule fois @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files les fichiers de version {0} ne peuvent pas être compressés : seules les versions {COMPRESSED_SINCE} et ultérieures ouvrent les fichiers compressés @msg width and height are at least 1 pixel la largeur et la hauteur valent au moins 1 pixel diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 76dc225e8..5396a6455 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -5255,6 +5255,9 @@ imageTrace Outline Körvonal @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} több mint {MAX_CSV_ROWS} adatkészlet: az Adatkészletek importálása legfeljebb {MAX_CSV_ROWS} adatkészletet olvas be @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} több mint {MAX_CSV_COLS} változó: az Adatkészletek importálása legfeljebb {MAX_CSV_COLS} változót olvas be @msg variables that aren't text were left out: {kinds} a nem szöveges változók kimaradtak: {kinds} +@msg a new document won't read these variables back with their kind: {names} egy új dokumentum nem a fajtájukkal olvassa vissza ezeket a változókat: {names} +@msg a new document refuses this file because of these variables: {names} egy új dokumentum ezen változók miatt elutasítja ezt a fájlt: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them a(z) `{name}` változó `{header}` fejléce a(z) `{other}` változóként olvasódna vissza: nevezze át az egyiket @msg VectorCraft doesn't search other apps' or the system's folders: {path} a VectorCraft nem keres más alkalmazások és a rendszer mappáiban: {path} @msg VectorCraft doesn't search the Shared or Public folder in Users: {path} a VectorCraft nem keres a Users alatti Shared és Public mappában: {path} @msg VectorCraft failed to start: {e} A VectorCraft nem tudott elindulni: {e} diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 89633ae99..1ae04500b 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -5138,6 +5138,9 @@ mark-style Japanese Jepang Export Data Sets… Ekspor himpunan data… Load Variable Library… Muat pustaka variabel… @msg variables that aren't text were left out: {kinds} variabel yang bukan teks dihilangkan: {kinds} +@msg a new document won't read these variables back with their kind: {names} dokumen baru tidak akan membaca kembali variabel ini dengan jenisnya: {names} +@msg a new document refuses this file because of these variables: {names} dokumen baru menolak file ini karena variabel berikut: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them header `{header}` untuk `{name}` akan terbaca sebagai variabel `{other}`: ganti nama salah satunya Make Graph Dynamic Jadikan grafik dinamis Batch… Batch… Source Folder: Folder sumber: diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index ad25ad87c..b34a730a7 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4526,6 +4526,9 @@ axis Both Entrambi @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} più di {MAX_CSV_ROWS} set di dati: Importa set di dati ne legge al massimo {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} più di {MAX_CSV_COLS} variabili: Importa set di dati ne legge al massimo {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} le variabili che non sono di testo sono state escluse: {kinds} +@msg a new document won't read these variables back with their kind: {names} un nuovo documento non rileggerà queste variabili con il loro tipo: {names} +@msg a new document refuses this file because of these variables: {names} un nuovo documento rifiuta questo file a causa di queste variabili: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them l’intestazione `{header}` di `{name}` verrebbe riletta come la variabile `{other}`: rinomina una delle due @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` e `options.{key}: {inner}` non coincidono: indicare l'opzione una sola volta @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files i file della versione {0} non possono essere compressi: solo la versione {COMPRESSED_SINCE} e successive aprono file compressi @msg width and height are at least 1 pixel larghezza e altezza sono di almeno 1 pixel diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 804186dd6..e7b1a1bf3 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4079,6 +4079,9 @@ swatch Bright Violet ビビッドバイオレット @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} データセットが {MAX_CSV_ROWS} 個を超えています: 「データセットを読み込み」が読み込めるのは {MAX_CSV_ROWS} 個までです @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} 変数が {MAX_CSV_COLS} 個を超えています: 「データセットを読み込み」が読み込めるのは {MAX_CSV_COLS} 個までです @msg variables that aren't text were left out: {kinds} テキスト以外の変数は除外されました: {kinds} +@msg a new document won't read these variables back with their kind: {names} 新しいドキュメントでは、これらの変数は元の種類で読み込まれません: {names} +@msg a new document refuses this file because of these variables: {names} 新しいドキュメントは、これらの変数のためにこのファイルを拒否します: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}` の見出し `{header}` は変数 `{other}` として読み込まれます: どちらかの名前を変更してください @msg guides are locked ガイドがロックされています @msg handle must be in or out handle には in または out を指定してください @msg no saved selection recalled 保存した選択範囲を呼び出していません diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 250e0f384..2dafb7ceb 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5424,6 +5424,9 @@ imageTrace Outline კონტური @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} {MAX_CSV_ROWS}-ზე მეტი მონაცემთა ნაკრები: მონაცემთა ნაკრებების იმპორტი კითხულობს მაქსიმუმ {MAX_CSV_ROWS}-ს @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} {MAX_CSV_COLS}-ზე მეტი ცვლადი: მონაცემთა ნაკრებების იმპორტი კითხულობს მაქსიმუმ {MAX_CSV_COLS}-ს @msg variables that aren't text were left out: {kinds} ცვლადები, რომლებიც ტექსტი არ არის, გამოტოვებულია: {kinds} +@msg a new document won't read these variables back with their kind: {names} ახალი დოკუმენტი ამ ცვლადებს მათი ტიპით ვერ წაიკითხავს: {names} +@msg a new document refuses this file because of these variables: {names} ახალი დოკუმენტი ამ ფაილს ამ ცვლადების გამო უარყოფს: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}`-ის სათაური `{header}` წაიკითხება როგორც ცვლადი `{other}`: გადაარქვით სახელი ერთ-ერთს @msg x and y must be finite x და y სასრული უნდა იყოს @msg {id} opens another app: only the person at the keyboard can run it {id} სხვა აპს ხსნის: მისი გაშვება მხოლოდ კლავიატურასთან მყოფ ადამიანს შეუძლია @msg “{name}” is not a file „{name}“ ფაილი არ არის diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 3ee9cb9d4..2cb947582 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4006,6 +4006,9 @@ theme Appearance 외관 @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} 데이터 세트가 {MAX_CSV_ROWS}개보다 많습니다: 데이터 세트 가져오기는 최대 {MAX_CSV_ROWS}개를 읽습니다 @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} 변수가 {MAX_CSV_COLS}개보다 많습니다: 데이터 세트 가져오기는 최대 {MAX_CSV_COLS}개를 읽습니다 @msg variables that aren't text were left out: {kinds} 텍스트가 아닌 변수는 제외되었습니다: {kinds} +@msg a new document won't read these variables back with their kind: {names} 새 문서는 이 변수들을 원래 종류로 다시 읽지 않습니다: {names} +@msg a new document refuses this file because of these variables: {names} 새 문서는 이 변수들 때문에 이 파일을 거부합니다: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}`의 머리글 `{header}`은(는) 변수 `{other}`(으)로 다시 읽힙니다: 둘 중 하나의 이름을 바꾸십시오 @msg guides are locked 안내선이 잠겨 있습니다 @msg handle must be in or out handle은 in 또는 out이어야 합니다 @msg no saved selection recalled 불러온 저장된 선택 영역이 없습니다 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 344853683..11e489e56 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -5493,6 +5493,9 @@ swatch Bright Violet Felviolet @msg the spine has no segments de as heeft geen segmenten @msg variables are locked variabelen zijn vergrendeld @msg variables that aren't text were left out: {kinds} variabelen die geen tekst zijn, zijn weggelaten: {kinds} +@msg a new document won't read these variables back with their kind: {names} een nieuw document leest deze variabelen niet terug met hun soort: {names} +@msg a new document refuses this file because of these variables: {names} een nieuw document weigert dit bestand vanwege deze variabelen: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them de kop `{header}` voor `{name}` zou worden gelezen als de variabele `{other}`: wijzig de naam van een van beide @msg x and y must be finite x en y moeten eindig zijn @msg Persistent libraries not found: {files} Permanente bibliotheken niet gevonden: {files} @msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` is geen bibliotheekpaneel (zie window.swatchLibrary) diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 5830a1b6a..c042bc487 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4617,6 +4617,9 @@ imageTrace Outline Kontur @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} więcej niż {MAX_CSV_ROWS} zestawów danych: Importuj zestawy danych odczytuje najwyżej {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} więcej niż {MAX_CSV_COLS} zmiennych: Importuj zestawy danych odczytuje najwyżej {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} pominięto zmienne, które nie są tekstowe: {kinds} +@msg a new document won't read these variables back with their kind: {names} nowy dokument nie odczyta tych zmiennych z ich rodzajem: {names} +@msg a new document refuses this file because of these variables: {names} nowy dokument odrzuca ten plik z powodu tych zmiennych: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them nagłówek `{header}` dla `{name}` zostałby odczytany jako zmienna `{other}`: zmień nazwę jednej z nich @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` i `options.{key}: {inner}` są sprzeczne: podaj opcję tylko raz @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files plików w wersji {0} nie można kompresować: skompresowane pliki otwierają tylko wersje {COMPRESSED_SINCE} i nowsze @msg width and height are at least 1 pixel szerokość i wysokość muszą wynosić co najmniej 1 piksel diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 00c619222..8f86b811c 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -4057,6 +4057,9 @@ axis Both Ambos @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} mais de {MAX_CSV_ROWS} conjuntos de dados: Importar Conjuntos de Dados lê no máximo {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} mais de {MAX_CSV_COLS} variáveis: Importar Conjuntos de Dados lê no máximo {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} as variáveis que não são de texto foram omitidas: {kinds} +@msg a new document won't read these variables back with their kind: {names} um novo documento não lerá essas variáveis de volta com o tipo delas: {names} +@msg a new document refuses this file because of these variables: {names} um novo documento recusa este arquivo por causa destas variáveis: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them o cabeçalho `{header}` de `{name}` seria lido como a variável `{other}`: renomeie uma delas @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` e `options.{key}: {inner}` não coincidem: informe a opção uma só vez @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files arquivos da versão {0} não podem ser compactados: somente a versão {COMPRESSED_SINCE} e posteriores abrem arquivos compactados @msg width and height are at least 1 pixel largura e altura têm pelo menos 1 pixel diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 50d1ca1bd..c28d4e979 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4521,6 +4521,9 @@ axis Both Оба @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} больше {MAX_CSV_ROWS} наборов данных: «Импортировать наборы данных» читает не более {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} больше {MAX_CSV_COLS} переменных: «Импортировать наборы данных» читает не более {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} переменные, которые не являются текстовыми, пропущены: {kinds} +@msg a new document won't read these variables back with their kind: {names} новый документ не прочитает эти переменные обратно с их типом: {names} +@msg a new document refuses this file because of these variables: {names} новый документ отклоняет этот файл из-за этих переменных: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them заголовок `{header}` для `{name}` будет прочитан как переменная `{other}`: переименуйте одну из них @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` и `options.{key}: {inner}` противоречат друг другу: укажите параметр только один раз @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files файлы версии {0} не могут быть сжаты: только версия {COMPRESSED_SINCE} и новее открывают сжатые файлы @msg width and height are at least 1 pixel ширина и высота должны быть не менее 1 пикселя diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 8ca7a3927..a42ba37e2 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4384,6 +4384,9 @@ axis Both Båda @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} fler än {MAX_CSV_ROWS} datauppsättningar: Importera datauppsättningar läser högst {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} fler än {MAX_CSV_COLS} variabler: Importera datauppsättningar läser högst {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} variabler som inte är text utelämnades: {kinds} +@msg a new document won't read these variables back with their kind: {names} ett nytt dokument läser inte tillbaka dessa variabler med deras typ: {names} +@msg a new document refuses this file because of these variables: {names} ett nytt dokument avvisar den här filen på grund av dessa variabler: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them rubriken `{header}` för `{name}` skulle läsas som variabeln `{other}`: byt namn på en av dem @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` och `options.{key}: {inner}` stämmer inte överens: ange alternativet bara en gång @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files filer i version {0} kan inte komprimeras: endast version {COMPRESSED_SINCE} och senare kan öppna komprimerade filer @msg width and height are at least 1 pixel bredd och höjd är minst 1 pixel diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index c893d81f3..f6f841f6c 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -5523,6 +5523,9 @@ theme Appearance Görünüm @msg an image has no pixels and was left out piksel içermeyen bir görüntü dışarıda bırakıldı @msg thumbnail: no page {n} (the file has 1) thumbnail: {n}. sayfa yok (dosyada 1 sayfa var) @msg variables that aren't text were left out: {kinds} metin olmayan değişkenler dışarıda bırakıldı: {kinds} +@msg a new document won't read these variables back with their kind: {names} yeni bir belge bu değişkenleri türleriyle geri okumaz: {names} +@msg a new document refuses this file because of these variables: {names} yeni bir belge bu değişkenler nedeniyle bu dosyayı reddeder: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}` için `{header}` başlığı `{other}` değişkeni olarak okunur: birini yeniden adlandırın Collapse Panel Group Panel Grubunu Daralt @msg panel is not in a dock group panel bir yuva grubunda değil @msg only a dock group above or below others collapses, not one beside another yalnızca diğerlerinin üstünde veya altındaki bir yuva grubu daraltılabilir, yanındaki değil diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 2676d107e..0685758bf 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4510,6 +4510,9 @@ axis Both Обидві @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} більше ніж {MAX_CSV_ROWS} наборів даних: «Імпортувати набори даних» читає не більше {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} більше ніж {MAX_CSV_COLS} змінних: «Імпортувати набори даних» читає не більше {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} змінні, що не є текстовими, пропущено: {kinds} +@msg a new document won't read these variables back with their kind: {names} новий документ не прочитає ці змінні назад з їхнім видом: {names} +@msg a new document refuses this file because of these variables: {names} новий документ відхиляє цей файл через ці змінні: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them заголовок `{header}` для `{name}` буде прочитано як змінну `{other}`: перейменуйте одну з них @msg `{key}: {top}` and `options.{key}: {inner}` disagree: give the option once `{key}: {top}` і `options.{key}: {inner}` суперечать одне одному: вкажіть параметр лише один раз @msg version {0} files can't be compressed: only version {COMPRESSED_SINCE} and later open compressed files файли версії {0} не можуть бути стиснуті: тільки версія {COMPRESSED_SINCE} і новіші відкривають стислі файли @msg width and height are at least 1 pixel ширина та висота повинні бути не менше 1 пікселя diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 42de855e0..75e0f7af4 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4917,6 +4917,9 @@ theme Appearance Giao diện @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} hơn {MAX_CSV_ROWS} tập dữ liệu: Nhập tập dữ liệu chỉ đọc tối đa {MAX_CSV_ROWS} @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} hơn {MAX_CSV_COLS} biến số: Nhập tập dữ liệu chỉ đọc tối đa {MAX_CSV_COLS} @msg variables that aren't text were left out: {kinds} các biến số không phải văn bản đã bị bỏ qua: {kinds} +@msg a new document won't read these variables back with their kind: {names} tài liệu mới sẽ không đọc lại các biến số này đúng loại: {names} +@msg a new document refuses this file because of these variables: {names} tài liệu mới sẽ từ chối tệp này vì các biến số sau: {names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them tiêu đề `{header}` của `{name}` sẽ được đọc thành biến số `{other}`: hãy đổi tên một trong hai @msg VectorCraft doesn't search other apps' or the system's folders: {path} VectorCraft không tìm kiếm trong thư mục của ứng dụng khác hoặc hệ thống: {path} @msg VectorCraft doesn't search the Shared or Public folder in Users: {path} VectorCraft không tìm kiếm thư mục Shared hoặc Public trong Users: {path} @msg VectorCraft failed to start: {e} VectorCraft khởi động thất bại: {e} diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 53a2e2847..815667fb9 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -3474,6 +3474,9 @@ digits Malayalam 马拉雅拉姆数字 @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} 数据集超过 {MAX_CSV_ROWS} 个:“导入数据集”最多读取 {MAX_CSV_ROWS} 个 @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} 变量超过 {MAX_CSV_COLS} 个:“导入数据集”最多读取 {MAX_CSV_COLS} 个 @msg variables that aren't text were left out: {kinds} 已省略非文本变量:{kinds} +@msg a new document won't read these variables back with their kind: {names} 新文档不会按原类型读回这些变量:{names} +@msg a new document refuses this file because of these variables: {names} 新文档会因这些变量而拒绝此文件:{names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}` 的标题 `{header}` 会被读作变量 `{other}`:请重命名其中一个 List Variables 列出变量 Bind Variable 绑定变量 Unbind Variable 解除变量绑定 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 0e9c6b5f2..27ae8fed5 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4466,6 +4466,9 @@ digits Malayalam 馬來亞拉姆數字 @msg more than {MAX_CSV_ROWS} data sets: Import Data Sets reads at most {MAX_CSV_ROWS} 資料集超過 {MAX_CSV_ROWS} 個:「匯入資料集」最多讀取 {MAX_CSV_ROWS} 個 @msg more than {MAX_CSV_COLS} variables: Import Data Sets reads at most {MAX_CSV_COLS} 變數超過 {MAX_CSV_COLS} 個:「匯入資料集」最多讀取 {MAX_CSV_COLS} 個 @msg variables that aren't text were left out: {kinds} 已略過非文字變數:{kinds} +@msg a new document won't read these variables back with their kind: {names} 新文件不會以原類型讀回這些變數:{names} +@msg a new document refuses this file because of these variables: {names} 新文件會因這些變數而拒絕此檔案:{names} +@msg the header `{header}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}` 的標題 `{header}` 會被讀作變數 `{other}`:請重新命名其中一個 List Variables 列出變數 Bind Variable 綁定變數 Unbind Variable 解除變數綁定 diff --git a/crates/ui-egui/src/panels/variables.rs b/crates/ui-egui/src/panels/variables.rs index 1f7a90598..e45e618ac 100644 --- a/crates/ui-egui/src/panels/variables.rs +++ b/crates/ui-egui/src/panels/variables.rs @@ -489,6 +489,43 @@ mod tests { } } + /// Export Data Sets…'s warnings about variables a new document doesn't read back with their + /// kind and about variables that make it refuse the file show in the status bar, and so does + /// its refusal of a header that is another variable's name; all three are translated in every + /// language but English. + #[test] + fn the_export_data_sets_warning_shows_in_the_status_bar() { + use crate::i18n::{Lang, message}; + let mut app = app_with_data(); + let dir = std::env::temp_dir().join(format!("vc-export-warning-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let path = dir.join("sets.csv"); + app.run("variable.define", json!({"name": "#Tag", "kind": "text"})).unwrap(); + app.run("dataset.export", json!({"path": path})).unwrap(); + assert_eq!(app.ui.status, "a new document won't read these variables back with their kind: `#Tag`"); + let warning = app.ui.status.clone(); + app.run("variable.define", json!({"name": "%Rate", "kind": "text"})).unwrap(); + app.run("dataset.export", json!({"path": path})).unwrap(); + assert_eq!(app.ui.status, "a new document refuses this file because of these variables: `%Rate`"); + let refuses = app.ui.status.clone(); + app.run("variable.delete", json!({"names": ["%Rate"]})).unwrap(); + app.run("variable.define", json!({"name": "Tag", "kind": "visibility"})).unwrap(); + assert!(app.run("dataset.export", json!({"path": path})).is_err()); + let refused = app.ui.status.clone(); + assert!(refused.contains("would read back as the variable `#Tag`"), "{refused}"); + let _ = std::fs::remove_dir_all(&dir); + let langs: Vec = Lang::all().filter(|l| l.code() != "en").collect(); + assert!(langs.len() >= 23, "{} languages", langs.len()); + for l in langs { + let shown = message(l, &warning); + assert!(!shown.contains("won't read") && shown.contains("`#Tag`"), "{}: {shown}", l.code()); + let shown = message(l, &refuses); + assert!(!shown.contains("refuses") && shown.contains("`%Rate`"), "{}: {shown}", l.code()); + let shown = message(l, &refused); + assert!(!shown.contains("would read back") && shown.contains("`#Tag`") && shown.contains("`Tag`"), "{}: {shown}", l.code()); + } + } + /// What the panel acts on is the highlight, and only while it names a variable: a stale one /// (deleted elsewhere, undone) highlights nothing, so Delete and Options… stay disabled. #[test] diff --git a/docs/mcp.md b/docs/mcp.md index f98195ed3..55d6d44d7 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1646,7 +1646,13 @@ already walks Image Trace. Short agent entry points: first free names `Data Set 1`, `Data Set 2` and so on. An import error about a row's values or name gives the file line the row starts on. A header cell that names no variable defines one, unbound, in the same undo step as the rows. `#Shown` defines a visibility variable `Shown`, `@Photo` defines an image variable `Photo`, and a cell without - a prefix defines a text variable. A prefixed cell whose name is already a variable of the prefix's kind names it; + a prefix defines a text variable. `dataset.export` writes a visibility variable's header as `#Shown` and an image + variable's as `@Photo`, and a text or graph variable's as its name alone. Its reply's `warning` names the variables + whose header or values make an import into a document without them refuse the file (a `%` header, a `#` header + whose values aren't true or false). Otherwise it names the variables that such an import does not read back with + their kind: text variables whose names start with `#` or `@`, and graph variables. Export is refused, naming both variables, when a variable's header is + another variable's name (a visibility variable `Show` next to a text variable `#Show`). A prefixed cell whose name + is already a variable of the prefix's kind names it; one whose name is a variable of another kind fails the import. A `%` cell that isn't a variable's exact name (graph data files) is refused, and so are two cells that name one variable (`City` twice, or `Shown` and `#Shown`). The reply's `defined` lists the variables the import defined. While the variables are