diff --git a/crates/engine/src/cmd/fileio/action_batch.rs b/crates/engine/src/cmd/fileio/action_batch.rs index d1db60302..f2310962e 100644 --- a/crates/engine/src/cmd/fileio/action_batch.rs +++ b/crates/engine/src/cmd/fileio/action_batch.rs @@ -93,7 +93,7 @@ pub(super) fn action_batch(s: &mut Session, p: &Value) -> Result { }; match source { "folder" => batch_folder(s, C, p, override_open, &run), - "datasets" => batch_datasets(s, C, &run), + "datasets" => batch_datasets(s, C, &run, p), _ => Err(bad(C, "`source` must be `folder` or `datasets`")), } } @@ -134,10 +134,7 @@ fn batch_folder(s: &mut Session, cmd: &str, p: &Value, override_open: bool, run: } #[cfg(not(target_arch = "wasm32"))] -fn batch_datasets(s: &mut Session, cmd: &str, run: &Run<'_>) -> Result { - use super::distinct_names; - use super::screens::file_part; - +fn batch_datasets(s: &mut Session, cmd: &str, run: &Run<'_>, p: &Value) -> Result { let st = s.doc()?; let names: Vec = st.doc.variables.datasets.iter().map(|d| d.name.clone()).collect(); if names.is_empty() { @@ -147,11 +144,8 @@ fn batch_datasets(s: &mut Session, cmd: &str, run: &Run<'_>) -> Result { return Err(bad(cmd, format!("more than {MAX_BATCH_FILES} data sets"))); } let doc_stem = st.path.as_deref().and_then(|p| std::path::Path::new(p).file_stem().and_then(|s| s.to_str())).unwrap_or("Untitled").to_string(); - // Data set files are named File + Data Set Name (helpx, for Override Save/Export; the folder - // destination uses the same name). `file_part` writes the characters Windows does not allow in a - // file name (`/`, `\`, `:`, `<`, `>`, `"`, `|`, `?`, `*` and control characters) in the data set's - // name as `-`, and `distinct_names` adds `-2`, `-3`… to a name an earlier data set used. - let stems = distinct_names(names.iter().map(|name| format!("{doc_stem}_{}", file_part(name)))); + let naming = p.get("datasetFileNaming").map_or("fileDataSetName", |v| v.as_str().unwrap_or("")); + let stems = dataset_stems(&names, &doc_stem, naming, run)?; let steps = filter_steps(run.steps, true, false); let run = Run { steps: &steps, ..*run }; let mut processed = Vec::new(); @@ -240,6 +234,68 @@ fn finish_destination(s: &mut Session, run: &Run<'_>, stem: &str, ext: &str, sou } } +/// Builds the three data set naming forms, replaces unsafe name characters, and adds `-2`, `-3` +/// suffixes when a stem was used earlier or its output already exists in the destination folder. +#[cfg(not(target_arch = "wasm32"))] +fn dataset_stems(names: &[String], doc_stem: &str, naming: &str, run: &Run<'_>) -> Result> { + use super::screens::{file_part, safe_file_name}; + + if !matches!(naming, "fileNumber" | "fileDataSetName" | "dataSetName") { + return Err(bad("action.batch", "`datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName`")); + } + let bases = names.iter().enumerate().map(|(i, name)| { + let safe = file_part(name); + let safe_data_set = safe_file_name(&safe); + match naming { + "fileNumber" => format!("{doc_stem}{:03}", i + 1), + "dataSetName" if !safe_data_set.is_empty() => safe_data_set, + "dataSetName" => format!("{doc_stem}{:03}", i + 1), + _ => format!("{doc_stem}_{safe}"), + } + }); + let extensions = dataset_output_extensions(run); + let mut taken = std::collections::HashSet::new(); + let mut stems = Vec::with_capacity(bases.len()); + for base in bases { + let mut candidate = base.clone(); + let mut suffix = 2; + while taken.contains(&candidate.to_lowercase()) || dataset_output_exists(run.dest_folder, &candidate, &extensions) { + if suffix > 10_000 { + return Err(bad("action.batch", "no free data set file name in destination folder")); + } + candidate = format!("{base}-{suffix}"); + suffix += 1; + } + taken.insert(candidate.to_lowercase()); + stems.push(candidate); + } + Ok(stems) +} + +#[cfg(not(target_arch = "wasm32"))] +fn dataset_output_extensions(run: &Run<'_>) -> Vec { + let mut extensions = Vec::new(); + if run.destination == "folder" { + extensions.push("vectorcraft".to_string()); + } + for step in run.steps { + let id = step.get("command").and_then(Value::as_str).unwrap_or(""); + let writes = (run.override_save && matches!(id, "document.save" | "file.save" | "file.saveAs")) + || (run.override_export && matches!(id, "document.export" | "document.exportForScreens" | "document.exportSelection")); + if writes { + let ext = step.get("params").and_then(|p| p.get("format")).and_then(Value::as_str).filter(|f| !f.is_empty()); + extensions.push(ext.map_or_else(|| "vectorcraft".to_string(), format_extension)); + } + } + extensions +} + +#[cfg(not(target_arch = "wasm32"))] +fn dataset_output_exists(folder: Option<&str>, stem: &str, extensions: &[String]) -> bool { + let Some(folder) = folder else { return false }; + extensions.iter().any(|ext| std::path::Path::new(folder).join(format!("{stem}.{ext}")).exists()) +} + /// Save when the extension is a Save format; otherwise export (PNG, JPEG…). /// `as_copy`: `file.saveCopy` so the open document keeps its path (data-set batches). #[cfg(not(target_arch = "wasm32"))] @@ -548,6 +604,142 @@ mod tests { s } + fn named_batch(s: &mut Session, dest: &std::path::Path, naming: Option<&str>) -> Value { + let mut p = json!({ + "source": "datasets", "destination": "folder", "destinationFolder": dest.to_string_lossy(), + "commands": [{"command": "object.unlockAll", "params": {}}] + }); + if let Some(naming) = naming { + p["datasetFileNaming"] = json!(naming); + } + s.execute("action.batch", &p).unwrap() + } + + #[test] + fn batch_data_set_naming_choices_and_omitted_default() { + for (i, (naming, want)) in [ + (Some("fileNumber"), ["source001.vectorcraft", "source002.vectorcraft"]), + (Some("fileDataSetName"), ["source_Alpha.vectorcraft", "source_Beta.vectorcraft"]), + (Some("dataSetName"), ["Alpha.vectorcraft", "Beta.vectorcraft"]), + (None, ["source_Alpha.vectorcraft", "source_Beta.vectorcraft"]), + ] + .into_iter() + .enumerate() + { + let dest = tmp(&format!("choice-{i}")); + let mut s = with_data_sets(&["Alpha", "Beta"]); + let saved = tmp(&format!("saved-{i}")).join("source.vectorcraft"); + s.execute("document.save", &json!({"path": saved.to_string_lossy()})).unwrap(); + let r = named_batch(&mut s, &dest, naming); + assert_eq!(r["failed"], 0, "{r}"); + assert_eq!(file_names(&dest), want, "{naming:?}: {r}"); + } + } + + #[test] + fn batch_file_number_uses_three_digits_through_500() { + let names: Vec = (1..=500).map(|n| format!("Set {n}")).collect(); + let run = Run { + label: "Test", + steps: &[], + stop_on_error: true, + override_save: true, + override_export: true, + destination: "none", + dest_folder: None, + }; + let stems = dataset_stems(&names, "source", "fileNumber", &run).unwrap(); + for n in [1, 2, 10, 100, 500] { + assert_eq!(stems[n - 1], format!("source{n:03}")); + } + } + + #[test] + fn batch_unsaved_data_set_names_and_empty_fallback() { + let dest = tmp("unsaved-number"); + let mut s = with_data_sets(&["Alpha"]); + assert_eq!(named_batch(&mut s, &dest, Some("fileNumber"))["failed"], 0); + assert_eq!(file_names(&dest), ["Untitled001.vectorcraft"]); + let dest = tmp("unsaved-name"); + assert_eq!(named_batch(&mut s, &dest, Some("fileDataSetName"))["failed"], 0); + assert_eq!(file_names(&dest), ["Untitled_Alpha.vectorcraft"]); + let run = Run { + label: "Test", + steps: &[], + stop_on_error: true, + override_save: true, + override_export: true, + destination: "none", + dest_folder: None, + }; + assert_eq!(dataset_stems(&[String::new()], "Untitled", "dataSetName", &run).unwrap(), ["Untitled001"]); + assert_eq!(dataset_stems(&[" ".to_string()], "Untitled", "dataSetName", &run).unwrap(), ["Untitled001"]); + } + + #[test] + fn batch_data_set_name_collisions_and_existing_files() { + let clear = tmp("choice-collision-clear"); + let mut s = with_data_sets(&["a:b", "a-b"]); + let r = named_batch(&mut s, &clear, Some("dataSetName")); + assert_eq!(r["failed"], 0, "{r}"); + assert_eq!(file_names(&clear), ["a-b-2.vectorcraft", "a-b.vectorcraft"]); + let dest = tmp("choice-collision"); + std::fs::write(dest.join("a-b.vectorcraft"), b"keep").unwrap(); + let mut s = with_data_sets(&["a:b", "a-b"]); + let r = named_batch(&mut s, &dest, Some("dataSetName")); + assert_eq!(r["failed"], 0, "{r}"); + assert_eq!(std::fs::read(dest.join("a-b.vectorcraft")).unwrap(), b"keep"); + assert_eq!(file_names(&dest), ["a-b-2.vectorcraft", "a-b-3.vectorcraft", "a-b.vectorcraft"]); + } + + #[test] + fn batch_data_set_name_avoids_windows_device_files() { + let dest = tmp("choice-device"); + let mut s = with_data_sets(&["CON"]); + let r = named_batch(&mut s, &dest, Some("dataSetName")); + assert_eq!(r["failed"], 0, "{r}"); + assert_eq!(file_names(&dest), ["CON-.vectorcraft"]); + } + + #[test] + fn batch_override_export_keeps_existing_output() { + let dest = tmp("choice-existing-export"); + std::fs::write(dest.join("Alpha.svg"), b"keep").unwrap(); + let mut s = with_data_sets(&["Alpha"]); + let r = s + .execute( + "action.batch", + &json!({ + "source": "datasets", "datasetFileNaming": "dataSetName", + "destinationFolder": dest.to_string_lossy(), + "commands": [{"command": "document.export", "params": {"format": "svg"}}] + }), + ) + .unwrap(); + assert_eq!(r["failed"], 0, "{r}"); + assert_eq!(std::fs::read(dest.join("Alpha.svg")).unwrap(), b"keep"); + assert_eq!(file_names(&dest), ["Alpha-2.svg", "Alpha.svg"]); + } + + #[test] + fn batch_rejects_unknown_data_set_naming_but_ignores_it_for_folders() { + let mut s = with_data_sets(&["Alpha"]); + let e = s + .execute("action.batch", &json!({"source": "datasets", "datasetFileNaming": "other", "commands": [{"command": "object.unlockAll"}]})) + .unwrap_err(); + let msg = e.to_string(); + for value in ["fileNumber", "fileDataSetName", "dataSetName"] { + assert!(msg.contains(value), "{msg}"); + } + assert!( + s.execute("action.batch", &json!({"source": "datasets", "datasetFileNaming": 7, "commands": [{"command": "object.unlockAll"}]})).is_err() + ); + let src = tmp("folder-ignore-src"); + write_svg(&src, "one.svg", "#f00"); + let r = s.execute("action.batch", &json!({"source": "folder", "folder": src.to_string_lossy(), "datasetFileNaming": "other", "commands": [{"command": "object.unlockAll"}]})).unwrap(); + assert_eq!(r["failed"], 0, "{r}"); + } + #[test] fn batch_keeps_data_set_files_inside_the_destination_folder() { let root = tmp("set-names-root"); diff --git a/crates/engine/src/cmd/fileio/commands.rs b/crates/engine/src/cmd/fileio/commands.rs index abd6857ad..ba39d0bdb 100644 --- a/crates/engine/src/cmd/fileio/commands.rs +++ b/crates/engine/src/cmd/fileio/commands.rs @@ -99,7 +99,7 @@ pub fn specs() -> Vec { "Batch…", [], None, - "{commands: [{command, params}] (the action's steps), source?: folder (default) | datasets, folder? (required for folder: the source folder), includeSubdirs?: false, destination?: none (default: leave each file open) | saveAndClose (save over the source and close) | folder (save or export into destinationFolder and close), destinationFolder? (required when destination is folder; also the folder Override Save/Export write into), overrideOpen?: true (skip document.open / file.open steps: the batch opens each source file), overrideSave?: true (point document.save / file.save / file.saveAs at destinationFolder/{stem}.{ext}), overrideExport?: true (point document.export / document.exportForScreens / document.exportSelection the same way), stopOnError?: true, label?} play the commands on every readable file in folder (and its subfolders when includeSubdirs), or on every data set of the open document (source: datasets; File + Data Set Name for the folder destination and Override Save/Export, with `/`, `\\`, `:`, `<`, `>`, `\"`, `|`, `?`, `*` and control characters in the data set's name as `-`, and `-2`, `-3`… added to a name already used). Caps: 500 files or data sets, 8 folder levels, 256 steps. Batches cannot nest. → {processed: [{path|dataset, result|error}…], count, failed, stopped}", + "{commands: [{command, params}] (the action's steps), source?: folder (default) | datasets, folder? (required for folder: the source folder), includeSubdirs?: false, destination?: none (default: leave each file open) | saveAndClose (save over the source and close) | folder (save or export into destinationFolder and close), destinationFolder? (required when destination is folder; also the folder Override Save/Export write into), datasetFileNaming?: fileNumber | fileDataSetName (default) | dataSetName (used only for source datasets; ignored for folder), overrideOpen?: true (skip document.open / file.open steps: the batch opens each source file), overrideSave?: true (point document.save / file.save / file.saveAs at destinationFolder/{stem}.{ext}), overrideExport?: true (point document.export / document.exportForScreens / document.exportSelection the same way), stopOnError?: true, label?} play the commands on every readable file in folder (and its subfolders when includeSubdirs), or on every data set of the open document. Data set names use the document stem plus a three-digit ordinal, the document stem and an underscore plus the data set name, or the data set name alone. Invalid file name characters become `-`; a name already used in the batch or present in the destination folder gets the next free `-2`, `-3` suffix before the format-derived extension. Caps: 500 files or data sets, 8 folder levels, 256 steps. Batches cannot nest. → {processed: [{path|dataset, result|error}…], count, failed, stopped}", always, action_batch::action_batch ), diff --git a/crates/ui-egui/src/dialogs/action_batch.rs b/crates/ui-egui/src/dialogs/action_batch.rs index 01c27b98a..3464fad75 100644 --- a/crates/ui-egui/src/dialogs/action_batch.rs +++ b/crates/ui-egui/src/dialogs/action_batch.rs @@ -21,26 +21,28 @@ pub fn open(app: &mut VectorcraftApp, set: usize, action: usize) -> Result Value { + json!({ + "set": set, + "action": action, + "actionName": name, + "source": "folder", + "datasetFileNaming": "fileNumber", + "folder": "", + "includeSubdirs": false, + "destination": "folder", + "destinationFolder": "", + "overrideOpen": true, + "overrideSave": true, + "overrideExport": true, + "stopOnError": true, + }) +} + fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { let t = Tokens::get(ui.ctx()); ui.label(egui::RichText::new(d.str("actionName")).color(t.text_strong)); @@ -58,6 +60,14 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { form::check(ui, d, "includeSubdirs", "Include All Subdirectories"); } else { ui.label(egui::RichText::new(tl!("Uses every data set of the open document.")).size(11.5).color(t.text_dim)); + form::choice( + ui, + d, + "datasetFileNaming", + "File Name:", + (LABEL, 200.0), + &[("fileNumber", "File + Number"), ("fileDataSetName", "File + Data Set Name"), ("dataSetName", "Data Set Name")], + ); } ui.add_space(8.0); @@ -95,23 +105,7 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result { if source == "datasets" && app.session.active().is_none() { return Err("open a document with data sets".into()); } - let mut params = json!({ - "commands": commands, - "label": a.name, - "source": source, - "destination": destination, - "overrideOpen": d.bool("overrideOpen"), - "overrideSave": d.bool("overrideSave"), - "overrideExport": d.bool("overrideExport"), - "stopOnError": d.bool("stopOnError"), - "includeSubdirs": d.bool("includeSubdirs"), - }); - if source == "folder" { - params["folder"] = json!(d.str("folder")); - } - if destination == "folder" { - params["destinationFolder"] = json!(d.str("destinationFolder")); - } + let params = params(d, &a.name, commands); let r = app.run("action.batch", params)?; app.ui.dialog = None; let count = r["count"].as_u64().unwrap_or(0); @@ -123,3 +117,76 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result { } Ok(r) } + +fn params(d: &Dialog, action_name: &str, commands: Vec) -> Value { + let source = d.str("source"); + let destination = d.str("destination"); + let mut params = json!({ + "commands": commands, + "label": action_name, + "source": source, + "destination": destination, + "overrideOpen": d.bool("overrideOpen"), + "overrideSave": d.bool("overrideSave"), + "overrideExport": d.bool("overrideExport"), + "stopOnError": d.bool("stopOnError"), + "includeSubdirs": d.bool("includeSubdirs"), + }); + if source == "folder" { + params["folder"] = json!(d.str("folder")); + } else if source == "datasets" { + params["datasetFileNaming"] = json!(d.str("datasetFileNaming")); + } + if destination == "folder" { + params["destinationFolder"] = json!(d.str("destinationFolder")); + } + params +} + +#[cfg(test)] +mod tests { + use super::*; + use vectorcraft_engine::Session; + + fn shown(source: &str) -> Vec { + fn collect(shape: &egui::Shape, out: &mut Vec) { + match shape { + egui::Shape::Text(t) => out.push(t.galley.text().to_string()), + egui::Shape::Vec(shapes) => shapes.iter().for_each(|shape| collect(shape, out)), + _ => {} + } + } + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + let mut d = Dialog::new(KIND, initial_fields(0, 0, "Test")); + d.fields["source"] = json!(source); + let ctx = egui::Context::default(); + crate::theme::install_fonts(&ctx); + let mut frame = ctx.run_ui(Default::default(), |ui| { + body(&mut app, ui, &mut d); + }); + frame.textures_delta.clear(); + let mut labels = vec![]; + frame.shapes.iter().for_each(|shape| collect(&shape.shape, &mut labels)); + labels + } + + #[test] + fn file_name_choice_shows_only_for_data_sets() { + assert!(shown("datasets").iter().any(|label| label == "File Name:")); + assert!(shown("datasets").iter().any(|label| label == "File + Number")); + assert!(!shown("folder").iter().any(|label| label == "File Name:")); + } + + #[test] + fn data_set_naming_params_follow_dialog_choice() { + let mut d = Dialog::new(KIND, initial_fields(0, 0, "Test")); + assert_eq!(d.str("datasetFileNaming"), "fileNumber"); + d.fields["source"] = json!("datasets"); + for choice in ["fileNumber", "fileDataSetName", "dataSetName"] { + d.fields["datasetFileNaming"] = json!(choice); + assert_eq!(params(&d, "Test", vec![])["datasetFileNaming"], choice); + } + d.fields["source"] = json!("folder"); + assert!(params(&d, "Test", vec![]).get("datasetFileNaming").is_none()); + } +} diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index fbb0019ec..0becb7e96 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -5860,6 +5860,11 @@ breakText Glyphs Глифи @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` трябва да е lines, paragraphs, words или glyphs, а не {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` трябва да е "line" или "paragraph", а не {other} @msg `align` must be "left", "center" or "right", not {other} `align` трябва да е "left", "center" или "right", а не {other} + File + Number Файл + номер + File + Data Set Name Файл + име на набора от данни + Data Set Name Име на набора от данни +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` трябва да е `fileNumber`, `fileDataSetName` или `dataSetName` +@msg no free data set file name in destination folder Няма свободно име за файл на набор от данни в целевата папка # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Mode Режим diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index d5f5e6dad..b1635dc7b 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -5869,6 +5869,11 @@ swatch Yellow Green Žuto-zelena Position: Položaj: Font Size: Veličina fonta: shape Open Otvoren + File + Number Datoteka + broj + File + Data Set Name Datoteka + naziv skupa podataka + Data Set Name Naziv skupa podataka +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` mora biti `fileNumber`, `fileDataSetName` ili `dataSetName` +@msg no free data set file name in destination folder Nema slobodnog naziva datoteke skupa podataka u odredišnoj mapi # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Retract Handles Uvuci ručke diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 4f2d7c616..b875d1067 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -5966,6 +5966,11 @@ breakText Glyphs Glifs @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` ha de ser lines, paragraphs, words o glyphs, no {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` ha de ser "line" o "paragraph", no {other} @msg `align` must be "left", "center" or "right", not {other} `align` ha de ser "left", "center" o "right", no {other} + File + Number Fitxer + número + File + Data Set Name Fitxer + nom del conjunt de dades + Data Set Name Nom del conjunt de dades +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` ha de ser `fileNumber`, `fileDataSetName` o `dataSetName` +@msg no free data set file name in destination folder No hi ha cap nom de fitxer de conjunt de dades lliure a la carpeta de destinació # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Efectes de traçat diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index ab09e818a..645281216 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -5977,6 +5977,11 @@ breakText Glyphs Glyfy @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` musí být lines, paragraphs, words nebo glyphs, ne {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` musí být "line" nebo "paragraph", ne {other} @msg `align` must be "left", "center" or "right", not {other} `align` musí být "left", "center" nebo "right", ne {other} + File + Number Soubor + číslo + File + Data Set Name Soubor + název sady dat + Data Set Name Název sady dat +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` musí být `fileNumber`, `fileDataSetName` nebo `dataSetName` +@msg no free data set file name in destination folder V cílové složce není volný název souboru sady dat # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Efekty cesty diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index b7c6e23fd..fb80dcc0c 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -5875,6 +5875,11 @@ breakText Glyphs Glyffer @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` skal være lines, paragraphs, words eller glyphs, ikke {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` skal være "line" eller "paragraph", ikke {other} @msg `align` must be "left", "center" or "right", not {other} `align` skal være "left", "center" eller "right", ikke {other} + File + Number Fil + nummer + File + Data Set Name Fil + datasætnavn + Data Set Name Datasætnavn +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` skal være `fileNumber`, `fileDataSetName` eller `dataSetName` +@msg no free data set file name in destination folder Intet ledigt filnavn til datasættet i destinationsmappen # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Kurveeffekter diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 80bd277fd..1ea0d5f0d 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -5562,6 +5562,11 @@ breakText Glyphs Glyphen @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` muss lines, paragraphs, words oder glyphs sein, nicht {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` muss "line" oder "paragraph" sein, nicht {other} @msg `align` must be "left", "center" or "right", not {other} `align` muss "left", "center" oder "right" sein, nicht {other} + File + Number Datei + Nummer + File + Data Set Name Datei + Datensatzname + Data Set Name Datensatzname +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` muss `fileNumber`, `fileDataSetName` oder `dataSetName` sein +@msg no free data set file name in destination folder Kein freier Dateiname für den Datensatz im Zielordner # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Pfadeffekte diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index bcea580dd..383e9b434 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -5929,6 +5929,11 @@ breakText Glyphs Γλύφοι @msg `by` must be lines, paragraphs, words or glyphs, not {other} το `by` πρέπει να είναι lines, paragraphs, words ή glyphs, όχι {other} @msg `kind` must be "line" or "paragraph", not {other} το `kind` πρέπει να είναι "line" ή "paragraph", όχι {other} @msg `align` must be "left", "center" or "right", not {other} το `align` πρέπει να είναι "left", "center" ή "right", όχι {other} + File + Number Αρχείο + αριθμός + File + Data Set Name Αρχείο + όνομα συνόλου δεδομένων + Data Set Name Όνομα συνόλου δεδομένων +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` Το `datasetFileNaming` πρέπει να είναι `fileNumber`, `fileDataSetName` ή `dataSetName` +@msg no free data set file name in destination folder Δεν υπάρχει διαθέσιμο όνομα αρχείου συνόλου δεδομένων στον φάκελο προορισμού # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Mode Λειτουργία diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index e9555f324..80d54c074 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -5920,6 +5920,11 @@ breakText Glyphs Glifos @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` debe ser lines, paragraphs, words o glyphs, no {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` debe ser "line" o "paragraph", no {other} @msg `align` must be "left", "center" or "right", not {other} `align` debe ser "left", "center" o "right", no {other} + File + Number Archivo + número + File + Data Set Name Archivo + nombre del conjunto de datos + Data Set Name Nombre del conjunto de datos +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` debe ser `fileNumber`, `fileDataSetName` o `dataSetName` +@msg no free data set file name in destination folder No hay un nombre de archivo libre para el conjunto de datos en la carpeta de destino # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Efectos de trazado diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 58f8157ba..ef924d173 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6008,6 +6008,11 @@ breakText Glyphs Merkit @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` on oltava lines, paragraphs, words tai glyphs, ei {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` on oltava "line" tai "paragraph", ei {other} @msg `align` must be "left", "center" or "right", not {other} `align` on oltava "left", "center" tai "right", ei {other} + File + Number Tiedosto + numero + File + Data Set Name Tiedosto + tietojoukon nimi + Data Set Name Tietojoukon nimi +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming`-arvon on oltava `fileNumber`, `fileDataSetName` tai `dataSetName` +@msg no free data set file name in destination folder Kohdekansiossa ei ole vapaata tietojoukon tiedostonimeä # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Polkutehosteet diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 818a363e6..7d5fe46b1 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -5975,6 +5975,11 @@ breakText Glyphs Glyphes @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` doit valoir lines, paragraphs, words ou glyphs, et non {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` doit valoir "line" ou "paragraph", et non {other} @msg `align` must be "left", "center" or "right", not {other} `align` doit valoir "left", "center" ou "right", et non {other} + File + Number Fichier + numéro + File + Data Set Name Fichier + nom du jeu de données + Data Set Name Nom du jeu de données +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` doit être `fileNumber`, `fileDataSetName` ou `dataSetName` +@msg no free data set file name in destination folder Aucun nom de fichier libre pour le jeu de données dans le dossier de destination # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Effets de tracé diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 6bb3bf986..0d71cbb8a 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -5964,6 +5964,11 @@ breakText Glyphs Glifák @msg `by` must be lines, paragraphs, words or glyphs, not {other} a `by` értéke lines, paragraphs, words vagy glyphs lehet, nem {other} @msg `kind` must be "line" or "paragraph", not {other} a `kind` értéke "line" vagy "paragraph" lehet, nem {other} @msg `align` must be "left", "center" or "right", not {other} az `align` értéke "left", "center" vagy "right" lehet, nem {other} + File + Number Fájl + szám + File + Data Set Name Fájl + adatkészlet neve + Data Set Name Adatkészlet neve +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` A `datasetFileNaming` értéke `fileNumber`, `fileDataSetName` vagy `dataSetName` lehet +@msg no free data set file name in destination folder Nincs szabad adatkészlet-fájlnév a célmappában # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Útvonaleffektusok diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 664551a1f..bfa066024 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -5875,6 +5875,11 @@ breakText Glyphs Glif @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` harus lines, paragraphs, words, atau glyphs, bukan {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` harus "line" atau "paragraph", bukan {other} @msg `align` must be "left", "center" or "right", not {other} `align` harus "left", "center", atau "right", bukan {other} + File + Number File + nomor + File + Data Set Name File + nama set data + Data Set Name Nama set data +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` harus `fileNumber`, `fileDataSetName`, atau `dataSetName` +@msg no free data set file name in destination folder Tidak ada nama file set data yang tersedia di folder tujuan # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Efek jalur diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index ce6b0d70a..2c587de48 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -5596,6 +5596,11 @@ breakText Glyphs Glifi @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` deve essere lines, paragraphs, words o glyphs, non {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` deve essere "line" o "paragraph", non {other} @msg `align` must be "left", "center" or "right", not {other} `align` deve essere "left", "center" o "right", non {other} + File + Number File + numero + File + Data Set Name File + nome set di dati + Data Set Name Nome set di dati +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` deve essere `fileNumber`, `fileDataSetName` o `dataSetName` +@msg no free data set file name in destination folder Nessun nome file libero per il set di dati nella cartella di destinazione # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Effetti tracciato diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 69caf7f3a..0326a5c84 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -5662,6 +5662,11 @@ breakText Glyphs 字形 @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` は lines、paragraphs、words、glyphs のいずれかにしてください({other} は使用できません) @msg `kind` must be "line" or "paragraph", not {other} `kind` は "line" または "paragraph" にしてください({other} は使用できません) @msg `align` must be "left", "center" or "right", not {other} `align` は "left"、"center"、"right" のいずれかにしてください({other} は使用できません) + File + Number ファイル名 + 番号 + File + Data Set Name ファイル名 + データセット名 + Data Set Name データセット名 +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` は `fileNumber`、`fileDataSetName`、`dataSetName` のいずれかである必要があります +@msg no free data set file name in destination folder 保存先フォルダーに使用可能なデータセットのファイル名がありません # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects パス効果 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 134cc1808..b34d09550 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5967,6 +5967,11 @@ breakText Glyphs გლიფები @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` უნდა იყოს lines, paragraphs, words ან glyphs და არა {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` უნდა იყოს "line" ან "paragraph" და არა {other} @msg `align` must be "left", "center" or "right", not {other} `align` უნდა იყოს "left", "center" ან "right" და არა {other} + File + Number ფაილი + ნომერი + File + Data Set Name ფაილი + მონაცემთა ნაკრების სახელი + Data Set Name მონაცემთა ნაკრების სახელი +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` უნდა იყოს `fileNumber`, `fileDataSetName` ან `dataSetName` +@msg no free data set file name in destination folder დანიშნულების საქაღალდეში მონაცემთა ნაკრებისთვის თავისუფალი ფაილის სახელი არ არის # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects ტრაექტორიის ეფექტები diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 6a12ca363..5e7e7db02 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -5559,6 +5559,11 @@ breakText Glyphs 글리프 @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by`는 lines, paragraphs, words 또는 glyphs여야 합니다({other}는 사용할 수 없음) @msg `kind` must be "line" or "paragraph", not {other} `kind`는 "line" 또는 "paragraph"여야 합니다({other}는 사용할 수 없음) @msg `align` must be "left", "center" or "right", not {other} `align`은 "left", "center" 또는 "right"여야 합니다({other}는 사용할 수 없음) + File + Number 파일 + 번호 + File + Data Set Name 파일 + 데이터 세트 이름 + Data Set Name 데이터 세트 이름 +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming`은 `fileNumber`, `fileDataSetName` 또는 `dataSetName`이어야 합니다 +@msg no free data set file name in destination folder 대상 폴더에 사용할 수 있는 데이터 세트 파일 이름이 없습니다 # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects 패스 효과 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 19fdc8663..504ecae13 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -5919,6 +5919,11 @@ breakText Glyphs Glyphs @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` moet lines, paragraphs, words of glyphs zijn, niet {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` moet "line" of "paragraph" zijn, niet {other} @msg `align` must be "left", "center" or "right", not {other} `align` moet "left", "center" of "right" zijn, niet {other} + File + Number Bestand + nummer + File + Data Set Name Bestand + naam gegevensset + Data Set Name Naam gegevensset +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` moet `fileNumber`, `fileDataSetName` of `dataSetName` zijn +@msg no free data set file name in destination folder Geen vrije bestandsnaam voor de gegevensset in de doelmap # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Padeffecten diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index c15322337..fffff07ae 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -5832,6 +5832,11 @@ breakText Glyphs Glify @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` musi mieć wartość lines, paragraphs, words lub glyphs, a nie {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` musi mieć wartość "line" lub "paragraph", a nie {other} @msg `align` must be "left", "center" or "right", not {other} `align` musi mieć wartość "left", "center" lub "right", a nie {other} + File + Number Plik + numer + File + Data Set Name Plik + nazwa zestawu danych + Data Set Name Nazwa zestawu danych +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` musi mieć wartość `fileNumber`, `fileDataSetName` lub `dataSetName` +@msg no free data set file name in destination folder Brak wolnej nazwy pliku zestawu danych w folderze docelowym # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Efekty ścieżki diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 4fd8e2bc5..aab46d191 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -5895,6 +5895,11 @@ breakText Glyphs Glifos @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` deve ser lines, paragraphs, words ou glyphs, não {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` deve ser "line" ou "paragraph", não {other} @msg `align` must be "left", "center" or "right", not {other} `align` deve ser "left", "center" ou "right", não {other} + File + Number Arquivo + número + File + Data Set Name Arquivo + nome do conjunto de dados + Data Set Name Nome do conjunto de dados +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` deve ser `fileNumber`, `fileDataSetName` ou `dataSetName` +@msg no free data set file name in destination folder Não há nome de arquivo livre para o conjunto de dados na pasta de destino # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Distance Distância diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 122bf5939..a516437a6 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -5955,6 +5955,11 @@ breakText Glyphs Глифы @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` должен быть lines, paragraphs, words или glyphs, а не {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` должен быть "line" или "paragraph", а не {other} @msg `align` must be "left", "center" or "right", not {other} `align` должен быть "left", "center" или "right", а не {other} + File + Number Файл + номер + File + Data Set Name Файл + имя набора данных + Data Set Name Имя набора данных +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` должно быть `fileNumber`, `fileDataSetName` или `dataSetName` +@msg no free data set file name in destination folder В папке назначения нет свободного имени файла для набора данных # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Эффекты контура diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 711f1eab4..a98780bcf 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -6030,6 +6030,11 @@ breakText Glyphs Glyfer @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` måste vara lines, paragraphs, words eller glyphs, inte {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` måste vara "line" eller "paragraph", inte {other} @msg `align` must be "left", "center" or "right", not {other} `align` måste vara "left", "center" eller "right", inte {other} + File + Number Fil + nummer + File + Data Set Name Fil + datauppsättningens namn + Data Set Name Datauppsättningens namn +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` måste vara `fileNumber`, `fileDataSetName` eller `dataSetName` +@msg no free data set file name in destination folder Inget ledigt filnamn för datauppsättningen i målmappen # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Baneffekter diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 5f69d1acb..4d543f027 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -5935,6 +5935,11 @@ breakText Glyphs Glifler @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by`, lines, paragraphs, words veya glyphs olmalı, {other} değil @msg `kind` must be "line" or "paragraph", not {other} `kind`, "line" veya "paragraph" olmalı, {other} değil @msg `align` must be "left", "center" or "right", not {other} `align`, "left", "center" veya "right" olmalı, {other} değil + File + Number Dosya + numara + File + Data Set Name Dosya + veri kümesi adı + Data Set Name Veri kümesi adı +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` değeri `fileNumber`, `fileDataSetName` veya `dataSetName` olmalıdır +@msg no free data set file name in destination folder Hedef klasörde veri kümesi için boş bir dosya adı yok # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Yol Efektleri diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index eb9d14016..694290799 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -5576,6 +5576,11 @@ breakText Glyphs Гліфи @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` має бути lines, paragraphs, words або glyphs, а не {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` має бути "line" або "paragraph", а не {other} @msg `align` must be "left", "center" or "right", not {other} `align` має бути "left", "center" або "right", а не {other} + File + Number Файл + номер + File + Data Set Name Файл + назва набору даних + Data Set Name Назва набору даних +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` має бути `fileNumber`, `fileDataSetName` або `dataSetName` +@msg no free data set file name in destination folder У папці призначення немає вільного імені файлу набору даних # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Ефекти контуру diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index f6b926e07..1c3c49387 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -5578,6 +5578,11 @@ breakText Glyphs Glyph @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` phải là lines, paragraphs, words hoặc glyphs, không phải {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` phải là "line" hoặc "paragraph", không phải {other} @msg `align` must be "left", "center" or "right", not {other} `align` phải là "left", "center" hoặc "right", không phải {other} + File + Number Tệp + số + File + Data Set Name Tệp + tên tập dữ liệu + Data Set Name Tên tập dữ liệu +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` phải là `fileNumber`, `fileDataSetName` hoặc `dataSetName` +@msg no free data set file name in destination folder Không có tên tệp tập dữ liệu còn trống trong thư mục đích # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects Hiệu ứng đường dẫn diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 96b5fbe0d..a85bc1a63 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -5819,6 +5819,11 @@ breakText Glyphs 字形 @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` 必须是 lines、paragraphs、words 或 glyphs,而不是 {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` 必须是 "line" 或 "paragraph",而不是 {other} @msg `align` must be "left", "center" or "right", not {other} `align` 必须是 "left"、"center" 或 "right",而不是 {other} + File + Number 文件 + 编号 + File + Data Set Name 文件 + 数据集名称 + Data Set Name 数据集名称 +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` 必须是 `fileNumber`、`fileDataSetName` 或 `dataSetName` +@msg no free data set file name in destination folder 目标文件夹中没有可用的数据集文件名 # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects 路径效果 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 147c3b043..7fe82d929 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -5615,6 +5615,11 @@ breakText Glyphs 字符 @msg `by` must be lines, paragraphs, words or glyphs, not {other} `by` 必須是 lines、paragraphs、words 或 glyphs,而不是 {other} @msg `kind` must be "line" or "paragraph", not {other} `kind` 必須是 "line" 或 "paragraph",而不是 {other} @msg `align` must be "left", "center" or "right", not {other} `align` 必須是 "left"、"center" 或 "right",而不是 {other} + File + Number 檔案 + 編號 + File + Data Set Name 檔案 + 資料集名稱 + Data Set Name 資料集名稱 +@msg `datasetFileNaming` must be `fileNumber`, `fileDataSetName` or `dataSetName` `datasetFileNaming` 必須是 `fileNumber`、`fileDataSetName` 或 `dataSetName` +@msg no free data set file name in destination folder 目的地資料夾中沒有可用的資料集檔案名稱 # Path Precision Tools add-on: Path Effects (Effect › Path Effects). Path Effects 路徑效果 diff --git a/docs/mcp.md b/docs/mcp.md index 719ac6d40..1b5c7e3c6 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1622,12 +1622,13 @@ already walks Image Trace. Short agent entry points: `%`). A declaration that holds anything else, and entity references that expand the library past 8 MiB, are refused. So are a variable or data set declared twice and a value for a variable the library doesn't declare. - Batch: `action.batch {commands, source?: folder|datasets, folder?, destination?: none|saveAndClose|folder, - destinationFolder?, overrideOpen?, overrideSave?, overrideExport?, includeSubdirs?, stopOnError?}` plays an - action on every file in a folder or every data set (the Actions panel menu's Batch…). Override Save and Override - Export end the file name of a step with `format` in that `format`, in lower case and without a leading dot, when it - is one of the format's extensions (`.svg` and `SVG` give `.svg`, `.JPEG` gives `.jpeg`), and otherwise in the - format's first extension (`png8` gives `.png`, `template` gives `.vctemplate`). A step without `format` keeps the - source file's extension (`.vectorcraft` over data sets). + destinationFolder?, datasetFileNaming?: fileNumber|fileDataSetName|dataSetName, overrideOpen?, + overrideSave?, overrideExport?, includeSubdirs?, stopOnError?}` plays an action on every file in a + folder or every data set (the Actions panel menu's Batch…). Override Save and Override Export end + the file name of a step with `format` in that `format`, in lower case and without a leading dot, + when it is one of the format's extensions (`.svg` and `SVG` give `.svg`, `.JPEG` gives `.jpeg`), + and otherwise in the format's first extension (`png8` gives `.png`, `template` gives `.vctemplate`). + A step without `format` keeps the source file's extension (`.vectorcraft` over data sets). - Image Trace: `imageTrace.presets`, `imageTrace.make {id?, preset?, params?, view?}` (or `imageTrace.makeAndExpand`), `imageTrace.setView`, `imageTrace.expand`, `imageTrace.release`. A key inside `params` that is not one of the trace settings, such as `colours`, is an error that names it and the nearest setting (`colors`), as for a command's own keys. @@ -2963,10 +2964,16 @@ earlier step deleted the active artboard when it was the last one), the step get remote mode, MCP's `run_command` calls and each step of the `command_batch` tool get the active artboard too. The Actions panel plays an action as a `command.batch`. The Actions panel menu's Batch… runs `action.batch`: the same steps on every readable file in a folder (or every data set of the open document), with -destination `none` | `saveAndClose` | `folder` and Override Open / Save / Export. Over data sets, the folder -destination and the overrides name each file after the document and the data set (`_.`). +destination `none` | `saveAndClose` | `folder` and Override Open / Save / Export. For a Data Sets source, +`datasetFileNaming` chooses File + Number (`source001`), File + Data Set Name (`source_Alpha`), or Data Set Name +(`Alpha`). An omitted parameter keeps File + Data Set Name for existing callers; the dialog starts with File + +Number. A folder source ignores this parameter. The folder destination and overridden Save/Export paths use the +chosen stem with the output format's extension. An empty data set name under Data Set Name falls back to the +document stem plus its three-digit ordinal. Batch writes `/`, `\`, `:`, `<`, `>`, `"`, `|`, `?`, `*` and control characters in the data set's name as `-`, and -adds `-2`, `-3`… to a name an earlier data set used (compared without case). Caps: 500 files or data sets, 8 +adds the next free `-2`, `-3` suffix to a stem already used in the batch or whose generated output path exists in +the destination folder before the batch starts. Under Data Set Name, VectorCraft also makes Windows device names +safe (`CON` becomes `CON-`). This is VectorCraft's naming behavior. Caps: 500 files or data sets, 8 folder levels, 256 steps. An action recorded in the Actions panel leaves the artboard out, and its steps of these commands get the artboard that is active when the action plays. A press with the Selection, Direct Selection or Group Selection tool inside an artboard makes that artboard the active one; with the Selection diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 6f0a426b2..bcc92a39b 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -548,6 +548,8 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - Batch…: Override Save and Override Export name each file with the extension of the format the step writes, however the step spells the format (`.svg` and `SVG` give `.svg`, `png8` gives `.png`), in `action.batch`. - Actions panel (record/playback, persisted), generic parameter dialogs for every "…" command. - Batch… over data sets names each file after the document and the data set (`action.batch`). It writes `/`, `\`, `:`, `<`, `>`, `"`, `|`, `?`, `*` and control characters in the data set's name as `-`, and adds `-2`, `-3`… to a name an earlier data set used. + - Batch… offers File + Number, File + Data Set Name, and Data Set Name for a Data Sets source. The dialog defaults to File + Number; `action.batch` without `datasetFileNaming` keeps File + Data Set Name. An output name already in the destination folder gets the next free `-2`, `-3` suffix. [Batch options](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/batch-options.html). + - Export for Screens: the dialog's Example line shows the path of the file the export writes first, sub-folder included, named as the export names it, for the first chosen artboard, asset, layer or object (`document.exportForScreens`). - Export for Screens is laid out as the reference app's dialog: on the left the Artboards and Assets tabs (thumbnails with their checkboxes, number and name, in a grid or a list), Clear Selection and Prefix; on the right Select (All, Range, Include Bleed, Full Document), Export to, Open Location after Export, Create Sub-folders by Scale or by Format (on by default), Export PDFs As (Single File writes the chosen artboards as the pages of one PDF named after the document, `pdfs: "single"`), and the format rows with the iOS and Android buttons, the format presets (☰) and Format Settings; under them, how many items are selected and how many files the export writes. File name patterns, the Layers and Selection sources and per-item folders stay available through `document.exportForScreens` (scripts and MCP). Tests: `dialogs::tests_screens` (layout, iOS/Android, Clear Selection, sub-folders, Single File) and `fileio::tests_screens::single_file_pdfs_hold_every_chosen_artboard`. - Save for Web: Preview in Browser writes each preview's page and images to a folder of its own inside `VectorCraft Save for Web` in the system's temporary folder. A later preview, from the same app or another one running, does not overwrite an earlier one. Each preview first removes the preview folders there that are an hour old or older and, on Linux, macOS and FreeBSD, belong to the current user; it leaves other files and folders alone. The folders a preview makes there are open to their owner only on those systems. When `VectorCraft Save for Web` is a link or is not a folder, or on those systems belongs to another user or can be written by other users, the preview goes to a new folder of its own in the temporary folder, which a later preview removes once it is an hour old (`file.saveForWeb.browser`). - Export for Screens, Save for Web (slice images, and files named after the document's title) and the Libraries panel name files with the characters Windows does not allow written as `-` and with a `-` after a Windows device name such as `CON`, on every platform (`document.exportForScreens`, `document.exportForWeb`, `library.create`).