From c2a605ce8e25f37b25cfcae6c194bfd188d3a1ad Mon Sep 17 00:00:00 2001 From: Higgs32584 Date: Sun, 18 Oct 2026 18:51:55 -0400 Subject: [PATCH 1/7] Save: warn when SVG keeps only one of several artboards A document with more than one artboard saved as SVG/SVGZ without Preserve Editing Capabilities is written as one artboard and reopens with one, so the others were lost without a word. The save now says so (first, since the status bar shows only the first warning) and names the two ways to keep them all. Refs storytold/vectorcraft#2091 Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/fileio/save.rs | 17 ++++++++++++++++- crates/engine/src/cmd/fileio/tests_svg.rs | 17 +++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/fileio/save.rs b/crates/engine/src/cmd/fileio/save.rs index 2e884a739..ad1011f63 100644 --- a/crates/engine/src/cmd/fileio/save.rs +++ b/crates/engine/src/cmd/fileio/save.rs @@ -322,6 +322,19 @@ fn fidelity_warning(f: &Format) -> Option { }) } +/// What an SVG save loses of a document with several artboards: the file is one artboard and +/// reopens as one, unless it carries the native document (Preserve Editing Capabilities). +fn artboards_warning(f: &Format, doc: &Document, params: &Value) -> Option { + let n = doc.artboards.len(); + let preserved = super::svg::options_map(params).ok().and_then(|m| m.get("preserveEditing").and_then(Value::as_bool)).unwrap_or(false); + (is_svg(f) && n > 1 && !preserved).then(|| { + format!( + "{} keeps 1 of the document's {n} artboards (the first, unless one is chosen) and reopens with only that one: turn on Preserve Editing Capabilities or save as VectorCraft to keep them all", + f.label + ) + }) +} + /// A save of the active document, snapshotted and ready to encode and write anywhere (Background /// Save does both on a worker thread): [`save_job`], then [`SaveJob::write`], then /// [`SaveJob::finish`]. Cheap to clone (the documents are shared). @@ -549,7 +562,9 @@ impl SaveJob { let one = self.encode_one(&artboard_doc(&self.doc, b))?; enc.files.extend(one.files.into_iter().map(|(_, bytes)| (Some(b), bytes))); } - enc.warnings.splice(0..0, fidelity_warning(self.plan.format)); + // Lost artboards first: the status bar shows only the first warning. + let f = self.plan.format; + enc.warnings.splice(0..0, artboards_warning(f, &self.doc, &self.params).into_iter().chain(fidelity_warning(f))); Ok(enc) } diff --git a/crates/engine/src/cmd/fileio/tests_svg.rs b/crates/engine/src/cmd/fileio/tests_svg.rs index d52ab20eb..05cafeb6a 100644 --- a/crates/engine/src/cmd/fileio/tests_svg.rs +++ b/crates/engine/src/cmd/fileio/tests_svg.rs @@ -145,6 +145,23 @@ fn preserve_editing_reopens_the_native_document() { assert_eq!(s.doc().unwrap().doc.artboards.len(), 1); } +#[test] +fn saving_several_artboards_as_plain_svg_warns_they_are_lost() { + let artboards = |r: &Value| r["warnings"].as_array().unwrap().iter().filter(|w| w.as_str().unwrap().contains("artboards")).count(); + let mut s = session(3); + let r = s.execute("document.save", &json!({"format": "svg"})).unwrap(); + assert_eq!(artboards(&r), 1, "{r}"); + // First: the status bar shows only the first warning. + assert!(r["warnings"][0].as_str().unwrap().contains("1 of the document's 3 artboards"), "{r}"); + assert_eq!(artboards(&s.execute("file.saveAs", &json!({"format": "svgz"})).unwrap()), 1); + // Preserve Editing keeps them all (they reopen); a single artboard loses none. + for p in [json!({"format": "svg", "preserveEditing": true}), json!({"format": "svg", "svg": {"preserveEditing": true}})] { + let r = s.execute("document.save", &p).unwrap(); + assert_eq!(artboards(&r), 0, "{p}: {r}"); + } + assert_eq!(artboards(&session(1).execute("document.save", &json!({"format": "svg"})).unwrap()), 0); +} + #[test] fn save_writes_svg_and_remembers_its_options() { let mut s = session(1); From f9e559156f1ffd7e2bd62c8da89e72b0de391d17 Mon Sep 17 00:00:00 2001 From: Higgs32584 Date: Sun, 18 Oct 2026 20:11:13 -0400 Subject: [PATCH 2/7] Save: decide the lost-artboards warning in the SVG handler Move the Preserve Editing check out of save.rs into svg.rs, where it reads the options through `plan` as the encoder does; SaveJob::encode still puts the warning first. Review follow-up on #2994. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/fileio/save.rs | 16 ++-------------- crates/engine/src/cmd/fileio/svg.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/engine/src/cmd/fileio/save.rs b/crates/engine/src/cmd/fileio/save.rs index ad1011f63..166eda8b9 100644 --- a/crates/engine/src/cmd/fileio/save.rs +++ b/crates/engine/src/cmd/fileio/save.rs @@ -322,19 +322,6 @@ fn fidelity_warning(f: &Format) -> Option { }) } -/// What an SVG save loses of a document with several artboards: the file is one artboard and -/// reopens as one, unless it carries the native document (Preserve Editing Capabilities). -fn artboards_warning(f: &Format, doc: &Document, params: &Value) -> Option { - let n = doc.artboards.len(); - let preserved = super::svg::options_map(params).ok().and_then(|m| m.get("preserveEditing").and_then(Value::as_bool)).unwrap_or(false); - (is_svg(f) && n > 1 && !preserved).then(|| { - format!( - "{} keeps 1 of the document's {n} artboards (the first, unless one is chosen) and reopens with only that one: turn on Preserve Editing Capabilities or save as VectorCraft to keep them all", - f.label - ) - }) -} - /// A save of the active document, snapshotted and ready to encode and write anywhere (Background /// Save does both on a worker thread): [`save_job`], then [`SaveJob::write`], then /// [`SaveJob::finish`]. Cheap to clone (the documents are shared). @@ -564,7 +551,8 @@ impl SaveJob { } // Lost artboards first: the status bar shows only the first warning. let f = self.plan.format; - enc.warnings.splice(0..0, artboards_warning(f, &self.doc, &self.params).into_iter().chain(fidelity_warning(f))); + let lost = if is_svg(f) { super::svg::lost_artboards_warning(&self.doc, &self.params, f.label) } else { None }; + enc.warnings.splice(0..0, lost.into_iter().chain(fidelity_warning(f))); Ok(enc) } diff --git a/crates/engine/src/cmd/fileio/svg.rs b/crates/engine/src/cmd/fileio/svg.rs index 62c2d1a3a..e2883a773 100644 --- a/crates/engine/src/cmd/fileio/svg.rs +++ b/crates/engine/src/cmd/fileio/svg.rs @@ -147,6 +147,19 @@ fn plan(doc: &Document, p: &Value) -> Result<(ExportOptions, Vec>, Ok((opts, named.unwrap_or_else(|| vec![0]).into_iter().map(Some).collect(), chosen)) } +/// What a save of `doc` as SVG (format `label`) with options `p` loses of several artboards: the +/// file is one artboard and reopens as one, unless it carries the native document (Preserve +/// Editing Capabilities). +pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> Option { + let n = doc.artboards.len(); + let preserved = plan(doc, p).is_ok_and(|(opts, ..)| opts.preserve_editing); + (n > 1 && !preserved).then(|| { + format!( + "{label} keeps 1 of the document's {n} artboards (the first, unless one is chosen) and reopens with only that one: turn on Preserve Editing Capabilities or save as VectorCraft to keep them all" + ) + }) +} + /// Encode `doc` as SVG (or gzipped, SVGZ): one file per chosen artboard, with the images they /// link to and the writer's warnings. pub(super) fn encode(doc: &Document, p: &Value, compressed: bool) -> Result { From acd8ca097d23873ce1ffd62d65566ab8f13ef38a Mon Sep 17 00:00:00 2001 From: Michael Higgins <55243596+Higgs32584@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:20:39 -0400 Subject: [PATCH 3/7] Update crates/engine/src/cmd/fileio/svg.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- crates/engine/src/cmd/fileio/svg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/fileio/svg.rs b/crates/engine/src/cmd/fileio/svg.rs index e2883a773..bda2fb43a 100644 --- a/crates/engine/src/cmd/fileio/svg.rs +++ b/crates/engine/src/cmd/fileio/svg.rs @@ -155,7 +155,7 @@ pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> let preserved = plan(doc, p).is_ok_and(|(opts, ..)| opts.preserve_editing); (n > 1 && !preserved).then(|| { format!( - "{label} keeps 1 of the document's {n} artboards (the first, unless one is chosen) and reopens with only that one: turn on Preserve Editing Capabilities or save as VectorCraft to keep them all" + "{label} does not preserve the document's {n} artboards and reopens with only one: turn on Preserve Editing Capabilities or save as VectorCraft to keep them all" ) }) } From d8c20c8eb40f5acf8eada925586dfcc5da5b9f15 Mon Sep 17 00:00:00 2001 From: Michael Higgins <55243596+Higgs32584@users.noreply.github.com> Date: Mon, 19 Oct 2026 11:43:00 -0400 Subject: [PATCH 4/7] Update error message for artboard preservation --- crates/engine/src/cmd/fileio/svg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/fileio/svg.rs b/crates/engine/src/cmd/fileio/svg.rs index bda2fb43a..920998a51 100644 --- a/crates/engine/src/cmd/fileio/svg.rs +++ b/crates/engine/src/cmd/fileio/svg.rs @@ -155,7 +155,7 @@ pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> let preserved = plan(doc, p).is_ok_and(|(opts, ..)| opts.preserve_editing); (n > 1 && !preserved).then(|| { format!( - "{label} does not preserve the document's {n} artboards and reopens with only one: turn on Preserve Editing Capabilities or save as VectorCraft to keep them all" + "1 of the document's {n} artboards" ) }) } From 81cf399bfa79acb71879d3869a7d9a58b3d10ca0 Mon Sep 17 00:00:00 2001 From: Michael Higgins <55243596+Higgs32584@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:06:53 -0400 Subject: [PATCH 5/7] Refactor SVG options and error handling --- crates/engine/src/cmd/fileio/svg.rs | 95 +++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/crates/engine/src/cmd/fileio/svg.rs b/crates/engine/src/cmd/fileio/svg.rs index 920998a51..be0ee2487 100644 --- a/crates/engine/src/cmd/fileio/svg.rs +++ b/crates/engine/src/cmd/fileio/svg.rs @@ -45,9 +45,24 @@ pub const OPTIONS: &[FormatOption] = &[ default: "\"layerNames\"", description: "layerNames (readable ids from names) | minimal (only referenced ids) | unique (content-hashed prefix on every id and class)", }, - FormatOption { name: "decimals", ty: "integer", default: "3", description: "coordinate precision, 1–7 decimal places" }, - FormatOption { name: "minify", ty: "boolean", default: "false", description: "no XML declaration, indentation or line breaks" }, - FormatOption { name: "responsive", ty: "boolean", default: "false", description: "no width/height: the SVG scales to its container" }, + FormatOption { + name: "decimals", + ty: "integer", + default: "3", + description: "coordinate precision, 1–7 decimal places", + }, + FormatOption { + name: "minify", + ty: "boolean", + default: "false", + description: "no XML declaration, indentation or line breaks", + }, + FormatOption { + name: "responsive", + ty: "boolean", + default: "false", + description: "no width/height: the SVG scales to its container", + }, FormatOption { name: "preserveEditing", ty: "boolean", @@ -120,7 +135,9 @@ pub fn options_map(p: &Value) -> Result, String> { match o.get("svg") { None | Some(Value::Null) => {} Some(Value::Object(svg)) => m.extend(svg.clone()), - Some(_) => return Err("`svg` must be an object of SVG options (see document.formats)".into()), + Some(_) => { + return Err("`svg` must be an object of SVG options (see document.formats)".into()); + } } Ok(m) } @@ -131,12 +148,20 @@ pub fn options_map(p: &Value) -> Result, String> { fn plan(doc: &Document, p: &Value) -> Result<(ExportOptions, Vec>, bool), String> { let mut m = options_map(p)?; // Fonts: unless chosen, Document Setup → Type → Export decides (appearance = outlines). - if !m.contains_key("outlineText") && doc.setup.export_text == vectorcraft_doc::ExportText::Appearance { + if !m.contains_key("outlineText") + && doc.setup.export_text == vectorcraft_doc::ExportText::Appearance + { m.insert("outlineText".into(), Value::Bool(true)); } - let picks: Map = ARTBOARD_PARAMS.iter().chain(["useArtboards"].iter()).filter_map(|k| m.remove_entry(*k)).collect(); - let boards = Boards::deserialize(Value::Object(picks)).map_err(|e| format!("SVG options: {e}"))?; - let opts = ExportOptions::deserialize(Value::Object(m)).map_err(|e| format!("SVG options: {e}"))?; + let picks: Map = ARTBOARD_PARAMS + .iter() + .chain(["useArtboards"].iter()) + .filter_map(|k| m.remove_entry(*k)) + .collect(); + let boards = + Boards::deserialize(Value::Object(picks)).map_err(|e| format!("SVG options: {e}"))?; + let opts = + ExportOptions::deserialize(Value::Object(m)).map_err(|e| format!("SVG options: {e}"))?; opts.check().map_err(|e| format!("SVG options: {e}"))?; let n = doc.artboards.len(); if n == 0 || boards.use_artboards == Some(false) { @@ -144,7 +169,15 @@ fn plan(doc: &Document, p: &Value) -> Result<(ExportOptions, Vec>, } let named = boards.pick.resolve(n)?; let chosen = named.is_some(); - Ok((opts, named.unwrap_or_else(|| vec![0]).into_iter().map(Some).collect(), chosen)) + Ok(( + opts, + named + .unwrap_or_else(|| vec![0]) + .into_iter() + .map(Some) + .collect(), + chosen, + )) } /// What a save of `doc` as SVG (format `label`) with options `p` loses of several artboards: the @@ -155,7 +188,7 @@ pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> let preserved = plan(doc, p).is_ok_and(|(opts, ..)| opts.preserve_editing); (n > 1 && !preserved).then(|| { format!( - "1 of the document's {n} artboards" + "{label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all." ) }) } @@ -165,23 +198,44 @@ pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> pub(super) fn encode(doc: &Document, p: &Value, compressed: bool) -> Result { let (opts, boards, chosen) = plan(doc, p)?; // Preserve editing embeds the native document (once, shared by every file). - let native = opts.preserve_editing.then(|| vectorcraft_format::save(doc, false)); + let native = opts + .preserve_editing + .then(|| vectorcraft_format::save(doc, false)); // Draw linked files as vectors when available, or their previews with a warning. Keep // that preparation out of the native attachment so missing links remain relinkable. let (full, warnings) = crate::cmd::place::document::full_documents(doc); let doc = &*full; // A chosen artboard's file holds the art over it; otherwise the file holds all of it. - let regions: Option> = - chosen.then(|| boards.iter().flatten().filter_map(|b| doc.artboards.get(*b)).map(|a| a.rect).collect()); + let regions: Option> = chosen.then(|| { + boards + .iter() + .flatten() + .filter_map(|b| doc.artboards.get(*b)) + .map(|a| a.rect) + .collect() + }); let overflow = crate::cmd::fonts::export_overflow_warning(doc, &doc.layers, regions.as_deref()); // SVG has no filters for the Photoshop-style effects: their objects go in as images. let flat = crate::cmd::rasterfx::flatten_pixel_effects(doc); let doc = flat.as_ref().unwrap_or(doc); - let mut enc = Encoded { warnings, ..Encoded::default() }; + let mut enc = Encoded { + warnings, + ..Encoded::default() + }; for artboard in boards { // A chosen artboard's file holds the art over it (#550). - let over = artboard.filter(|_| chosen).and_then(|b| doc.artboards.get(b)).map(|a| super::export::art_over(doc, a.rect)); - let mut out = vectorcraft_svg::export_full(over.as_ref().unwrap_or(doc), &ExportOptions { artboard, ..opts.clone() }, native.as_deref()); + let over = artboard + .filter(|_| chosen) + .and_then(|b| doc.artboards.get(b)) + .map(|a| super::export::art_over(doc, a.rect)); + let mut out = vectorcraft_svg::export_full( + over.as_ref().unwrap_or(doc), + &ExportOptions { + artboard, + ..opts.clone() + }, + native.as_deref(), + ); let bytes = out.take_bytes(); for l in out.linked { if !enc.linked.iter().any(|e| e.name == l.name) { @@ -193,7 +247,14 @@ pub(super) fn encode(doc: &Document, p: &Value, compressed: bool) -> Result Date: Mon, 19 Oct 2026 14:02:29 -0400 Subject: [PATCH 6/7] fix changes --- crates/engine/src/cmd/fileio/svg.rs | 93 +++++------------------------ 1 file changed, 16 insertions(+), 77 deletions(-) diff --git a/crates/engine/src/cmd/fileio/svg.rs b/crates/engine/src/cmd/fileio/svg.rs index be0ee2487..8f028934a 100644 --- a/crates/engine/src/cmd/fileio/svg.rs +++ b/crates/engine/src/cmd/fileio/svg.rs @@ -45,24 +45,9 @@ pub const OPTIONS: &[FormatOption] = &[ default: "\"layerNames\"", description: "layerNames (readable ids from names) | minimal (only referenced ids) | unique (content-hashed prefix on every id and class)", }, - FormatOption { - name: "decimals", - ty: "integer", - default: "3", - description: "coordinate precision, 1–7 decimal places", - }, - FormatOption { - name: "minify", - ty: "boolean", - default: "false", - description: "no XML declaration, indentation or line breaks", - }, - FormatOption { - name: "responsive", - ty: "boolean", - default: "false", - description: "no width/height: the SVG scales to its container", - }, + FormatOption { name: "decimals", ty: "integer", default: "3", description: "coordinate precision, 1–7 decimal places" }, + FormatOption { name: "minify", ty: "boolean", default: "false", description: "no XML declaration, indentation or line breaks" }, + FormatOption { name: "responsive", ty: "boolean", default: "false", description: "no width/height: the SVG scales to its container" }, FormatOption { name: "preserveEditing", ty: "boolean", @@ -148,20 +133,12 @@ pub fn options_map(p: &Value) -> Result, String> { fn plan(doc: &Document, p: &Value) -> Result<(ExportOptions, Vec>, bool), String> { let mut m = options_map(p)?; // Fonts: unless chosen, Document Setup → Type → Export decides (appearance = outlines). - if !m.contains_key("outlineText") - && doc.setup.export_text == vectorcraft_doc::ExportText::Appearance - { + if !m.contains_key("outlineText") && doc.setup.export_text == vectorcraft_doc::ExportText::Appearance { m.insert("outlineText".into(), Value::Bool(true)); } - let picks: Map = ARTBOARD_PARAMS - .iter() - .chain(["useArtboards"].iter()) - .filter_map(|k| m.remove_entry(*k)) - .collect(); - let boards = - Boards::deserialize(Value::Object(picks)).map_err(|e| format!("SVG options: {e}"))?; - let opts = - ExportOptions::deserialize(Value::Object(m)).map_err(|e| format!("SVG options: {e}"))?; + let picks: Map = ARTBOARD_PARAMS.iter().chain(["useArtboards"].iter()).filter_map(|k| m.remove_entry(*k)).collect(); + let boards = Boards::deserialize(Value::Object(picks)).map_err(|e| format!("SVG options: {e}"))?; + let opts = ExportOptions::deserialize(Value::Object(m)).map_err(|e| format!("SVG options: {e}"))?; opts.check().map_err(|e| format!("SVG options: {e}"))?; let n = doc.artboards.len(); if n == 0 || boards.use_artboards == Some(false) { @@ -169,15 +146,7 @@ fn plan(doc: &Document, p: &Value) -> Result<(ExportOptions, Vec>, } let named = boards.pick.resolve(n)?; let chosen = named.is_some(); - Ok(( - opts, - named - .unwrap_or_else(|| vec![0]) - .into_iter() - .map(Some) - .collect(), - chosen, - )) + Ok((opts, named.unwrap_or_else(|| vec![0]).into_iter().map(Some).collect(), chosen)) } /// What a save of `doc` as SVG (format `label`) with options `p` loses of several artboards: the @@ -187,9 +156,7 @@ pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> let n = doc.artboards.len(); let preserved = plan(doc, p).is_ok_and(|(opts, ..)| opts.preserve_editing); (n > 1 && !preserved).then(|| { - format!( - "{label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all." - ) + format!("{label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all.") }) } @@ -198,44 +165,23 @@ pub(super) fn lost_artboards_warning(doc: &Document, p: &Value, label: &str) -> pub(super) fn encode(doc: &Document, p: &Value, compressed: bool) -> Result { let (opts, boards, chosen) = plan(doc, p)?; // Preserve editing embeds the native document (once, shared by every file). - let native = opts - .preserve_editing - .then(|| vectorcraft_format::save(doc, false)); + let native = opts.preserve_editing.then(|| vectorcraft_format::save(doc, false)); // Draw linked files as vectors when available, or their previews with a warning. Keep // that preparation out of the native attachment so missing links remain relinkable. let (full, warnings) = crate::cmd::place::document::full_documents(doc); let doc = &*full; // A chosen artboard's file holds the art over it; otherwise the file holds all of it. - let regions: Option> = chosen.then(|| { - boards - .iter() - .flatten() - .filter_map(|b| doc.artboards.get(*b)) - .map(|a| a.rect) - .collect() - }); + let regions: Option> = + chosen.then(|| boards.iter().flatten().filter_map(|b| doc.artboards.get(*b)).map(|a| a.rect).collect()); let overflow = crate::cmd::fonts::export_overflow_warning(doc, &doc.layers, regions.as_deref()); // SVG has no filters for the Photoshop-style effects: their objects go in as images. let flat = crate::cmd::rasterfx::flatten_pixel_effects(doc); let doc = flat.as_ref().unwrap_or(doc); - let mut enc = Encoded { - warnings, - ..Encoded::default() - }; + let mut enc = Encoded { warnings, ..Encoded::default() }; for artboard in boards { // A chosen artboard's file holds the art over it (#550). - let over = artboard - .filter(|_| chosen) - .and_then(|b| doc.artboards.get(b)) - .map(|a| super::export::art_over(doc, a.rect)); - let mut out = vectorcraft_svg::export_full( - over.as_ref().unwrap_or(doc), - &ExportOptions { - artboard, - ..opts.clone() - }, - native.as_deref(), - ); + let over = artboard.filter(|_| chosen).and_then(|b| doc.artboards.get(b)).map(|a| super::export::art_over(doc, a.rect)); + let mut out = vectorcraft_svg::export_full(over.as_ref().unwrap_or(doc), &ExportOptions { artboard, ..opts.clone() }, native.as_deref()); let bytes = out.take_bytes(); for l in out.linked { if !enc.linked.iter().any(|e| e.name == l.name) { @@ -247,14 +193,7 @@ pub(super) fn encode(doc: &Document, p: &Value, compressed: bool) -> Result Date: Tue, 20 Oct 2026 02:06:51 +0700 Subject: [PATCH 7/7] i18n: the SVG one-artboard warning in every complete catalog and Bulgarian (#2994) --- crates/ui-egui/src/i18n/bg.tsv | 1 + crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 1 + crates/ui-egui/src/i18n/el.tsv | 1 + crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fi.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/hu.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ja.tsv | 1 + crates/ui-egui/src/i18n/ka.tsv | 1 + crates/ui-egui/src/i18n/ko.tsv | 1 + crates/ui-egui/src/i18n/pl.tsv | 1 + crates/ui-egui/src/i18n/pt-br.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/sv.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/vi.tsv | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + 20 files changed, 20 insertions(+) diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 98f1a3e67..6a806e588 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -5190,3 +5190,4 @@ theme Appearance Външен вид # Select by Color (select.color) Select by Color Избиране по цвят Move Anchor Point Преместване на опорна точка +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} запазва 1 от {n} работни области на документа: файлът се отваря отново с един. Включете „Запазване на възможностите за редактиране“, за да запазите всички. diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 8f7b9ce79..d1bc56c97 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -5228,3 +5228,4 @@ mark-style Japanese Japonské # Select by Color (select.color) Select by Color Vybrat podle barvy Move Anchor Point Přesunout kotevní bod +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} zachová 1 z {n} pracovních ploch dokumentu: soubor se znovu otevře s jedním. Zapněte Zachovat možnosti úprav, aby zůstala všechna. diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index db7ea1dd4..c3e70abf6 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4808,3 +4808,4 @@ effect Soft Weich # Select by Color (select.color) Select by Color Nach Farbe auswählen Move Anchor Point Ankerpunkt verschieben +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} behält 1 der {n} Zeichenflächen des Dokuments: Die Datei wird mit einer wieder geöffnet. Aktivieren Sie „Bearbeitungsfunktionen beibehalten“, um alle zu behalten. diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index caa2c90df..9de4765c7 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -5180,3 +5180,4 @@ effect Points Σημεία # Select by Color (select.color) Select by Color Επιλογή βάσει χρώματος Move Anchor Point Μετακίνηση σημείου αγκύρωσης +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. Το {label} διατηρεί 1 από τους {n} πίνακες σχεδίασης του εγγράφου: το αρχείο ανοίγει ξανά με μία. Ενεργοποιήστε τη Διατήρηση δυνατοτήτων επεξεργασίας για να τους κρατήσετε όλους. diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index e3dc401b4..388d9c836 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -5170,3 +5170,4 @@ mark-style Japanese Japonesas # Select by Color (select.color) Select by Color Seleccionar por color Move Anchor Point Mover punto de ancla +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} conserva 1 de las {n} mesas de trabajo del documento: el archivo se vuelve a abrir con una. Active Conservar capacidades de edición para conservarlas todas. diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 669df6575..261995f62 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -5259,3 +5259,4 @@ swatch Bright Violet Kirkas violetti Save and Close Tallenna ja sulje Play: Toista: Move Anchor Point Siirrä ankkuripistettä +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} säilyttää asiakirjan {n} piirtoalustasta 1: tiedosto avautuu uudelleen yhdellä. Ota Säilytä muokkausominaisuudet käyttöön, jotta kaikki säilyvät. diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 68e5699a7..52e6fd3f2 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -5227,3 +5227,4 @@ theme Appearance Apparence # Select by Color (select.color) Select by Color Sélectionner par couleur Move Anchor Point Déplacer le point d’ancrage +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} conserve 1 des {n} plans de travail du document : le fichier se rouvre avec un seul. Activez Conserver les fonctions d’édition pour les conserver tous. diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index ff455c9ce..0d0a1e642 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -5214,3 +5214,4 @@ imageTrace Outline Körvonal # Select by Color (select.color) Select by Color Kijelölés szín szerint Move Anchor Point Horgonypont áthelyezése +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. A(z) {label} a dokumentum {n} rajztáblájából 1-et tart meg: a fájl eggyel nyílik meg újra. Kapcsolja be a Szerkeszthetőség megtartása beállítást, hogy mind megmaradjon. diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index fe0de9ba3..6e99dcab4 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4842,3 +4842,4 @@ lighting Light Luce # Select by Color (select.color) Select by Color Seleziona per colore Move Anchor Point Sposta punto di ancoraggio +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} mantiene 1 delle {n} tavole da disegno del documento: il file si riapre con una sola. Attiva Mantieni possibilità di modifica per mantenerle tutte. diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 56ad5ab9a..f980b2373 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4882,3 +4882,4 @@ lighting Light ライト # Select by Color (select.color) Select by Color カラーで選択 Move Anchor Point アンカーポイントを移動 +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} ではドキュメントの {n} 個のアートボードのうち 1 個だけが保持され、ファイルは 1 個で開き直されます。すべて保持するには「編集機能を保持」をオンにしてください。 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index edd9d2257..0538b0fd2 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5135,3 +5135,4 @@ imageTrace Outline კონტური @msg thumbnail: no page {n} (the file has 1) thumbnail: გვერდი {n} არ არსებობს (ფაილს 1 გვერდი აქვს) Move Anchor Point საყრდენი წერტილის გადაადგილება Alt key toggles to Smooth Tool Alt კლავიში ჩართავს გაგლუვების ხელსაწყოს +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} ინახავს დოკუმენტის {n} სამუშაო დაფიდან 1-ს: ფაილი ხელახლა ერთით გაიხსნება. ყველას შესანარჩუნებლად ჩართეთ „რედაქტირების შესაძლებლობების შენარჩუნება“. diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index d75734a88..144b1821f 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4805,3 +4805,4 @@ lighting Light 광원 # Select by Color (select.color) Select by Color 색상별 선택 Move Anchor Point 앵커 포인트 이동 +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label}은(는) 문서의 아트보드 {n}개 중 1개만 유지하며 파일은 아트보드 하나로 다시 열립니다. 모두 유지하려면 편집 기능 보존을 켜십시오. diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index ed914e79f..c66142993 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -5080,3 +5080,4 @@ mark-style Japanese Japońskie # Select by Color (select.color) Select by Color Zaznacz według koloru Move Anchor Point Przesuń punkt kontrolny +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} zachowuje 1 z {n} obszarów kompozycji dokumentu: plik otworzy się ponownie z jednym. Włącz Zachowaj możliwości edycji, aby zachować wszystkie. diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 0677e101a..e33d25c37 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -5145,3 +5145,4 @@ mark-style Japanese Japonesas # Select by Color (select.color) Select by Color Selecionar por Cor Move Anchor Point Mover Ponto de Ancoragem +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} mantém 1 das {n} mesas de trabalho do documento: o arquivo reabre com uma. Ative Preservar Capacidades de Edição para manter todas. diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 6e78153c2..c03d830ba 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4838,3 +4838,4 @@ lighting Light Свет # Select by Color (select.color) Select by Color Выделить по цвету Move Anchor Point Переместить опорную точку +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} сохраняет 1 из {n} монтажных областей документа: файл откроется снова с одной. Включите «Сохранять возможности редактирования», чтобы сохранить все. diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index a402532ac..05144a79f 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -5184,3 +5184,4 @@ theme Appearance Utseende # Select by Color (select.color) Select by Color Markera efter färg Move Anchor Point Flytta ankarpunkt +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} behåller 1 av dokumentets {n} ritytor: filen öppnas igen med en. Slå på Bevara redigeringsmöjligheter för att behålla alla. diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 6fa711d05..5474578d5 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4822,3 +4822,4 @@ lighting Light Світло # Select by Color (select.color) Select by Color Виділити за кольором Move Anchor Point Перемістити опорну точку +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} зберігає 1 з {n} монтажних областей документа: файл відкриється знову з однією. Увімкніть «Зберігати можливості редагування», щоб зберегти всі. diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 7affdb91b..7249d1899 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4822,3 +4822,4 @@ theme Appearance Giao diện # Select by Color (select.color) Select by Color Chọn theo màu Move Anchor Point Di chuyển điểm neo +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} chỉ giữ 1 trong {n} bảng vẽ của tài liệu: tệp sẽ mở lại với một bảng vẽ. Bật Bảo lưu khả năng chỉnh sửa để giữ tất cả. diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index ee31597b6..bb2698ecd 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -5065,3 +5065,4 @@ lighting Light 光源 # Select by Color (select.color) Select by Color 按颜色选择 Move Anchor Point 移动锚点 +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} 只保留文档 {n} 个画板中的 1 个:文件重新打开时只有一个。打开“保留编辑功能”可全部保留。 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 2faf73da7..a3c1948b2 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4860,3 +4860,4 @@ lighting Light 光源 @msg invalid object id {value}: expected a non-negative integer 無效的物件 id {value}:應為非負整數 @msg no such object id {value} 沒有 id 為 {value} 的物件 Move Anchor Point 移動錨點 +@msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} 只保留文件 {n} 個工作區域中的 1 個:檔案重新開啟時只有一個。開啟「保留編輯功能」可全部保留。