diff --git a/Cargo.lock b/Cargo.lock index dc08d4542e..00fe4ca454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -978,11 +978,33 @@ dependencies = [ "ruzstd", ] +[[package]] +name = "craft-codepage" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=6d620e971e820b517b11a99cad040ebac670e1e2#6d620e971e820b517b11a99cad040ebac670e1e2" + [[package]] name = "craft-docpath" version = "0.1.0" source = "git+https://github.com/storytold/craft-libs?rev=9be9a63782298ab59cd9b7a42ee9cba4f42a5ccb#9be9a63782298ab59cd9b7a42ee9cba4f42a5ccb" +[[package]] +name = "craft-dxf" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=6d620e971e820b517b11a99cad040ebac670e1e2#6d620e971e820b517b11a99cad040ebac670e1e2" +dependencies = [ + "craft-codepage", + "encoding_rs", + "kurbo 0.13.1", + "log", + "thiserror 2.0.21", +] + +[[package]] +name = "craft-eps" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=6d620e971e820b517b11a99cad040ebac670e1e2#6d620e971e820b517b11a99cad040ebac670e1e2" + [[package]] name = "craft-fonts-build" version = "0.1.0" @@ -1057,6 +1079,21 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "craft-svg" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=6d620e971e820b517b11a99cad040ebac670e1e2#6d620e971e820b517b11a99cad040ebac670e1e2" +dependencies = [ + "craft-xml", + "flate2", + "kurbo 0.13.1", + "roxmltree 0.21.2", + "thiserror 2.0.21", + "usvg 0.48.1", + "vectorcraft-geom 0.18.0", + "vectorcraft-pathops 0.18.0", +] + [[package]] name = "craft-ui" version = "0.1.0" @@ -1146,6 +1183,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "craft-xml" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=6d620e971e820b517b11a99cad040ebac670e1e2#6d620e971e820b517b11a99cad040ebac670e1e2" +dependencies = [ + "quick-xml 0.41.0", + "thiserror 2.0.21", +] + [[package]] name = "crc32fast" version = "1.5.3" @@ -6386,13 +6432,14 @@ dependencies = [ "serde_json", "vectorcraft-color", "vectorcraft-doc", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", ] [[package]] name = "vectorcraft-cad" version = "0.24.1" dependencies = [ + "craft-dxf", "image", "kurbo 0.13.1", "serde_json", @@ -6400,8 +6447,8 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", - "vectorcraft-pathops", + "vectorcraft-geom 0.24.1", + "vectorcraft-pathops 0.24.1", "vectorcraft-text", ] @@ -6418,7 +6465,7 @@ dependencies = [ "vectorcraft-doc", "vectorcraft-engine", "vectorcraft-format", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-mcp", "vectorcraft-render", "vectorcraft-svg", @@ -6455,7 +6502,7 @@ dependencies = [ "thiserror 2.0.21", "tiff", "vectorcraft-color", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "zune-jpeg 0.5.15", ] @@ -6470,8 +6517,8 @@ dependencies = [ "svgtypes 0.16.1", "vectorcraft-color", "vectorcraft-doc", - "vectorcraft-geom", - "vectorcraft-pathops", + "vectorcraft-geom 0.24.1", + "vectorcraft-pathops 0.24.1", "vectorcraft-plugins", "vectorcraft-text", "vectorcraft-three-d", @@ -6515,10 +6562,10 @@ dependencies = [ "vectorcraft-doc", "vectorcraft-eps", "vectorcraft-format", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-js", "vectorcraft-metafile", - "vectorcraft-pathops", + "vectorcraft-pathops 0.24.1", "vectorcraft-pdf", "vectorcraft-plugins", "vectorcraft-render", @@ -6537,6 +6584,7 @@ dependencies = [ name = "vectorcraft-eps" version = "0.24.1" dependencies = [ + "craft-eps", "craft-pdf", "encoding_rs", "fax", @@ -6552,9 +6600,9 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-metafile", - "vectorcraft-pathops", + "vectorcraft-pathops 0.24.1", "vectorcraft-pdf", "vectorcraft-render", "vectorcraft-testkit", @@ -6573,10 +6621,20 @@ dependencies = [ "serde_json", "thiserror 2.0.21", "vectorcraft-doc", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-testkit", ] +[[package]] +name = "vectorcraft-geom" +version = "0.18.0" +source = "git+https://github.com/storytold/vectorcraft.git?rev=6b3a6b8788ebcb420d69449199cbdf323888d27e#6b3a6b8788ebcb420d69449199cbdf323888d27e" +dependencies = [ + "kurbo 0.13.1", + "serde", + "thiserror 2.0.21", +] + [[package]] name = "vectorcraft-geom" version = "0.24.1" @@ -6611,7 +6669,7 @@ dependencies = [ "vectorcraft-doc", "vectorcraft-engine", "vectorcraft-format", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-render", "vectorcraft-svg", "vectorcraft-testkit", @@ -6628,10 +6686,21 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-text", ] +[[package]] +name = "vectorcraft-pathops" +version = "0.18.0" +source = "git+https://github.com/storytold/vectorcraft.git?rev=6b3a6b8788ebcb420d69449199cbdf323888d27e#6b3a6b8788ebcb420d69449199cbdf323888d27e" +dependencies = [ + "kurbo 0.13.1", + "linesweeper", + "thiserror 2.0.21", + "vectorcraft-geom 0.18.0", +] + [[package]] name = "vectorcraft-pathops" version = "0.24.1" @@ -6640,7 +6709,7 @@ dependencies = [ "linesweeper", "proptest", "thiserror 2.0.21", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-testkit", ] @@ -6673,7 +6742,7 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-testkit", "vectorcraft-text", "weezl 0.2.1", @@ -6692,7 +6761,7 @@ dependencies = [ "thiserror 2.0.21", "vectorcraft-color", "vectorcraft-doc", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "wasmi", "wat", "web-time", @@ -6717,7 +6786,7 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-plugins", "vectorcraft-testkit", "vectorcraft-text", @@ -6741,6 +6810,7 @@ name = "vectorcraft-svg" version = "0.24.1" dependencies = [ "craft-docpath", + "craft-svg", "flate2", "image", "kurbo 0.13.1", @@ -6757,8 +6827,8 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", - "vectorcraft-pathops", + "vectorcraft-geom 0.24.1", + "vectorcraft-pathops 0.24.1", "vectorcraft-testkit", "vectorcraft-text", ] @@ -6776,7 +6846,7 @@ dependencies = [ "vectorcraft-doc", "vectorcraft-engine", "vectorcraft-format", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-render", "vectorcraft-svg", ] @@ -6796,7 +6866,7 @@ dependencies = [ "unicode-script", "unicode-segmentation", "vectorcraft-doc", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vello_cpu", "windows-registry", "write-fonts", @@ -6806,8 +6876,8 @@ dependencies = [ name = "vectorcraft-three-d" version = "0.24.1" dependencies = [ - "vectorcraft-geom", - "vectorcraft-pathops", + "vectorcraft-geom 0.24.1", + "vectorcraft-pathops 0.24.1", ] [[package]] @@ -6822,8 +6892,8 @@ dependencies = [ "vectorcraft-color", "vectorcraft-doc", "vectorcraft-effects", - "vectorcraft-geom", - "vectorcraft-pathops", + "vectorcraft-geom 0.24.1", + "vectorcraft-pathops 0.24.1", "vectorcraft-text", ] @@ -6836,7 +6906,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.21", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", ] [[package]] @@ -6865,7 +6935,7 @@ dependencies = [ "vectorcraft-engine", "vectorcraft-eps", "vectorcraft-format", - "vectorcraft-geom", + "vectorcraft-geom 0.24.1", "vectorcraft-pdf", "vectorcraft-plugins", "vectorcraft-render", diff --git a/Cargo.toml b/Cargo.toml index 5bed166e17..c7856d589e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,12 @@ craft-vectorcraft-format = { git = "https://github.com/storytold/craft-libs", re # craft-update: app-specific pretend versions apply to startup and manual checks. # Native Affinity documents (craft-libs#914). craft-affinity = { git = "https://github.com/storytold/craft-libs", rev = "228f6d0c50f1fdee4c5124603602993fc79d4c9d" } +# SVG parsing, limits, SVGZ and writer (craft-libs#778). +craft-svg = { git = "https://github.com/storytold/craft-libs", rev = "6d620e971e820b517b11a99cad040ebac670e1e2", features = ["tree"] } +# EPS container, previews, ASCII85 and DSC comments (craft-libs#778). +craft-eps = { git = "https://github.com/storytold/craft-libs", rev = "6d620e971e820b517b11a99cad040ebac670e1e2" } +# DXF tags, reader and writer (craft-libs#778, #926, #927). +craft-dxf = { git = "https://github.com/storytold/craft-libs", rev = "6d620e971e820b517b11a99cad040ebac670e1e2" } craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "e98299546f5c5c3c22388d16507f8b5e61a5f280", features = ["egui"] } # internal vectorcraft-geom = { path = "crates/geom" } diff --git a/crates/cad/Cargo.toml b/crates/cad/Cargo.toml index 34f77ec929..e529e1d4e2 100644 --- a/crates/cad/Cargo.toml +++ b/crates/cad/Cargo.toml @@ -9,6 +9,7 @@ description = "VectorCraft CAD interchange: a hand-written ASCII DXF writer (R12 workspace = true [dependencies] +craft-dxf = { workspace = true } vectorcraft-geom = { workspace = true } vectorcraft-color = { workspace = true } vectorcraft-doc = { workspace = true } diff --git a/crates/cad/src/aci.rs b/crates/cad/src/aci.rs index 63fbb180f9..39818a78ef 100644 --- a/crates/cad/src/aci.rs +++ b/crates/cad/src/aci.rs @@ -1,50 +1,11 @@ -//! The 256-colour index palette CAD apps share, generated rather than tabulated: indices 1–9 are -//! the standard colours, 10–249 run through 24 hues at five brightnesses each in a full and a -//! half-saturated tone, and 250–255 are greys. +//! The colour index palette is `craft_dxf::model::aci`; here are the indices each colour depth +//! of the writer may use. use crate::ColorDepth; -/// The nine standard colours (index 7 shows white on a dark background and black on paper). -const STANDARD: [[u8; 3]; 9] = - [[255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255], [255, 255, 255], [128, 128, 128], [192, 192, 192]]; - -/// The brightness of the five shades of each hue. -const SHADES: [f64; 5] = [1.0, 0.65, 0.5, 0.3, 0.15]; - /// The RGB of colour index `i` (1–255; anything else is index 7's white). pub fn aci_rgb(i: u8) -> [u8; 3] { - match i { - 1..=9 => STANDARD[usize::from(i - 1)], - 10..=249 => { - let hue = f64::from(i / 10 - 1) * 15.0; - let k = i % 10; - let v = SHADES[usize::from(k / 2)]; - let pastel = k % 2 == 1; - hue_rgb(hue).map(|f| { - let f = if pastel { f + (1.0 - f) / 2.0 } else { f }; - (255.0 * v * f).floor() as u8 - }) - } - 250..=255 => { - let g = (51.0 + 204.0 * f64::from(i - 250) / 5.0).floor() as u8; - [g; 3] - } - _ => STANDARD[6], - } -} - -/// The fully saturated, full-brightness colour of `hue` degrees as 0–1 channels. -fn hue_rgb(hue: f64) -> [f64; 3] { - let h = hue.rem_euclid(360.0) / 60.0; - let x = 1.0 - (h % 2.0 - 1.0).abs(); - match h as u8 { - 0 => [1.0, x, 0.0], - 1 => [x, 1.0, 0.0], - 2 => [0.0, 1.0, x], - 3 => [0.0, x, 1.0], - 4 => [x, 0.0, 1.0], - _ => [1.0, 0.0, x], - } + craft_dxf::model::aci::rgb(i) } /// The indices a colour depth may use (true colour: all of them, for the fallback index). @@ -59,37 +20,13 @@ fn candidates(depth: ColorDepth) -> Box> { /// The index of `depth` nearest to `rgb` (squared RGB distance; ties go to the lower index). /// Index 7 stands for both white and black, as CAD apps draw it in the background's contrast. pub fn nearest_aci(rgb: [u8; 3], depth: ColorDepth) -> u8 { - let dist = |c: [u8; 3]| rgb.iter().zip(c).map(|(a, b)| (i32::from(*a) - i32::from(b)).pow(2)).sum::(); - candidates(depth).min_by_key(|i| if *i == 7 { dist([255; 3]).min(dist([0; 3])) } else { dist(aci_rgb(*i)) }).unwrap_or(7) + craft_dxf::model::aci::nearest(rgb, candidates(depth)) } #[cfg(test)] mod tests { use super::*; - #[test] - fn the_palette_matches_its_known_entries() { - let known: [(u8, [u8; 3]); 14] = [ - (1, [255, 0, 0]), - (10, [255, 0, 0]), - (11, [255, 127, 127]), - (12, [165, 0, 0]), - (13, [165, 82, 82]), - (17, [76, 38, 38]), - (19, [38, 19, 19]), - (20, [255, 63, 0]), - (21, [255, 159, 127]), - (30, [255, 127, 0]), - (140, [0, 191, 255]), - (250, [51, 51, 51]), - (252, [132, 132, 132]), - (255, [255, 255, 255]), - ]; - for (i, rgb) in known { - assert_eq!(aci_rgb(i), rgb, "index {i}"); - } - } - #[test] fn nearest_index_by_depth() { assert_eq!(nearest_aci([255, 0, 0], ColorDepth::Aci8), 1); diff --git a/crates/cad/src/import.rs b/crates/cad/src/import.rs index f1f4104863..9216c57c29 100644 --- a/crates/cad/src/import.rs +++ b/crates/cad/src/import.rs @@ -1,4 +1,4 @@ -//! DXF import: an ASCII DXF drawing of any version as a document. +//! DXF import: a DXF drawing (ASCII or binary) of any version as a document. //! //! The drawing's model space (or a paper layout) comes in at a ratio (1 unit of the art = N //! drawing units; by default the drawing's own unit at 1:1) or fitted to an artboard, centred @@ -10,7 +10,8 @@ //! lineweights, linetypes and transparency come through layers and blocks as CAD apps resolve //! them. What can't come in is listed in the warnings. //! -//! - `reader`: the file's text, group codes, sections, tables, blocks and layouts. +//! - `reader`: what the import uses of the drawing `craft_dxf::model` reads: header, tables, +//! blocks and layouts. //! - `entity`: entities to items (geometry and properties). //! - `curve`: bulges, arcs, ellipses and NURBS as Bézier paths. //! - `text`: text values to plain text. @@ -31,9 +32,6 @@ use crate::{DxfVersion, INSUNITS, SCALE_RANGE}; /// Letter, the box Fit to Artboard fills unless told otherwise (points). pub const FIT_TO: (f64, f64) = (612.0, 792.0); -/// Why a binary DXF can't be opened. -pub const BINARY: &str = "this is a binary DXF file, which can't be read: save it from the CAD app as an ASCII DXF and open that"; - /// How a drawing comes in. #[derive(Clone, Debug, PartialEq)] pub struct ImportOptions { @@ -104,15 +102,20 @@ pub fn is_dxf(bytes: &[u8]) -> bool { false } -/// The pairs of a DXF file and where it is damaged (binary and DWG files are refused). -fn text(bytes: &[u8]) -> Result, String> { - if bytes.starts_with(reader::BINARY_SENTINEL) { - return Err(BINARY.into()); - } +/// The tags of a DXF file and where it is damaged (DWG files are refused). +fn tags(bytes: &[u8]) -> Result<(Vec, Option), String> { if bytes.starts_with(b"AC10") || bytes.starts_with(b"AC1.") { - return Err("this is a DWG drawing, which can't be read: save it from the CAD app as an ASCII DXF and open that".into()); + return Err("this is a DWG drawing, which can't be read: save it from the CAD app as a DXF and open that".into()); } - Ok(reader::decode(bytes)) + let (tags, damaged) = craft_dxf::parse_recovering(bytes).map_err(|e| match e { + craft_dxf::DxfError::TooLarge { .. } => "the drawing is too large to open".to_string(), + _ if bytes.starts_with(reader::BINARY_SENTINEL) => "this binary DXF file is damaged or cut short".to_string(), + _ => "not a DXF drawing".to_string(), + })?; + if tags.is_empty() { + return Err("not a DXF drawing".into()); + } + Ok((tags, damaged.map(|line| format!("the file is damaged at line {line}: what follows is left out")))) } /// The unit of `$INSUNITS` code `code` and the scale that shows the drawing 1:1 in it. @@ -161,9 +164,8 @@ fn units_name(code: i64) -> &'static str { /// Read what `bytes` holds: its version, units, layouts and layers. pub fn info(bytes: &[u8]) -> Result { - let text = text(bytes)?; - let (pairs, _) = reader::pairs(&text)?; - let d = reader::Drawing::read(&pairs); + let (tags, _) = tags(bytes)?; + let d = reader::Drawing::read(craft_dxf::model::Document::read(&tags)); if d.sections == 0 { return Err("not a DXF drawing".into()); } @@ -180,7 +182,7 @@ pub fn info(bytes: &[u8]) -> Result { }) } -/// Import an ASCII DXF drawing with `o`. +/// Import a DXF drawing with `o`. pub fn import(bytes: &[u8], o: &ImportOptions) -> Result { let (w, h) = o.fit_to; if !(w > 0.0 && h > 0.0 && w.max(h) <= build::MAX_EXTENT) { @@ -191,9 +193,8 @@ pub fn import(bytes: &[u8], o: &ImportOptions) -> Result { { return Err(format!("scale must be a number from {} to {}, not {s}", SCALE_RANGE.start(), SCALE_RANGE.end())); } - let text = text(bytes)?; - let (pairs, damaged) = reader::pairs(&text)?; - let d = reader::Drawing::read(&pairs); + let (tags, damaged) = tags(bytes)?; + let d = reader::Drawing::read(craft_dxf::model::Document::read(&tags)); if d.sections == 0 { return Err("not a DXF drawing".into()); } diff --git a/crates/cad/src/import/entity.rs b/crates/cad/src/import/entity.rs index 59e1283cce..309a4ea228 100644 --- a/crates/cad/src/import/entity.rs +++ b/crates/cad/src/import/entity.rs @@ -7,9 +7,10 @@ use kurbo::{BezPath, PathEl}; use vectorcraft_doc::Justify; use vectorcraft_geom::{Affine, Point, Vec2}; +use craft_dxf::model::{self, EntityRecord, Groups, HatchEdge, HatchPath}; + use super::curve::{self, Vertex}; -use super::reader::{Groups, Pair, Record, groups, number}; -use crate::aci::aci_rgb; +use super::reader::{aci_paper, point}; /// How far below the baseline the lowest descender reaches, as a fraction of the cap height. const DESCENT: f64 = 0.3; @@ -25,21 +26,6 @@ const MAX_COORD: f64 = 1e12; /// factor 1, the 1 to 10,000% horizontal scale the Character panel allows. const SPAN_SCALE: (f64, f64) = (0.01, 100.0); -/// The colour of index `i` on paper: index 7 (white on a CAD screen) is black. -pub(crate) fn aci_paper(i: u64) -> [u8; 3] { - match u8::try_from(i) { - Ok(7) | Err(_) => [0; 3], - Ok(i) => aci_rgb(i), - } -} - -/// The true colour (group 420, `0xRRGGBB`) of an entity or layer. -pub(crate) fn true_color(g: &[Pair<'_>]) -> Option<[u8; 3]> { - let v = g.int(420)?; - let [_, r, gr, b] = u32::try_from(v & 0xFF_FFFF).ok()?.to_be_bytes(); - Some([r, gr, b]) -} - /// An entity's colour. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub(crate) enum Col { @@ -79,30 +65,30 @@ pub(crate) struct Props { } impl Props { - fn read(g: &[Pair<'_>]) -> Self { - let color = match (true_color(g), g.int(62)) { - (Some(rgb), _) => Col::Rgb(rgb), - (None, Some(0)) => Col::ByBlock, - (None, None | Some(256..)) => Col::ByLayer, - (None, Some(i)) => Col::Rgb(aci_paper(i.unsigned_abs())), + fn read(c: &model::Common) -> Self { + let color = match c.color { + model::Color::Rgb(rgb) => Col::Rgb(rgb), + model::Color::ByBlock => Col::ByBlock, + model::Color::ByLayer => Col::ByLayer, + model::Color::Index(i) => Col::Rgb(aci_paper(i)), }; - let lineweight = match g.int(370) { - Some(-2) => Lw::ByBlock, - Some(-3) => Lw::Default, - Some(v @ 0..=211) => Lw::Hundredths(v as i32), + let lineweight = match c.lineweight { + model::Lineweight::ByBlock => Lw::ByBlock, + model::Lineweight::Default => Lw::Default, + model::Lineweight::Hundredths(v @ 0..=211) => Lw::Hundredths(i32::from(v)), _ => Lw::ByLayer, }; - let alpha = match g.int(440) { - Some(v) if v & 0x0200_0000 != 0 => Alpha::Opacity((v & 0xFF) as f32 / 255.0), - Some(v) if v & 0x0100_0000 != 0 => Alpha::ByBlock, - _ => Alpha::ByLayer, + let alpha = match c.transparency { + model::Transparency::Alpha(a) => Alpha::Opacity(f32::from(a) / 255.0), + model::Transparency::ByBlock => Alpha::ByBlock, + model::Transparency::ByLayer => Alpha::ByLayer, }; Self { - layer: g.name(8).unwrap_or("0").to_string(), + layer: c.layer.clone(), color, lineweight, - linetype: g.name(6).unwrap_or("BYLAYER").to_uppercase(), - ltscale: g.num(48).filter(|v| *v > 0.0).unwrap_or(1.0), + linetype: c.linetype.as_deref().unwrap_or("BYLAYER").to_uppercase(), + ltscale: c.ltscale, alpha, } } @@ -209,90 +195,87 @@ impl Converter { } /// The items of `records` (an entity section or a block), in drawing order. - pub fn items(&mut self, records: &[Record<'_>]) -> Vec { + pub fn items(&mut self, records: &[EntityRecord<'_>]) -> Vec { let mut out = Vec::new(); - for group in groups(records) { - let Some(head) = group.first() else { continue }; + for e in records { + let m = model::Entity::read(e); // Invisible entities. - if head.g.int(60) == Some(1) { + if !m.common.visible { continue; } - match self.geom(head, group) { + match self.geom(e, &m) { Some(geom) if !in_range(&geom) => self.warn(FAR_AWAY), - Some(geom) => out.push(Item { props: Props::read(head.g), geom }), - None if is_known(head.kind) => {} - None => self.skip(head.kind), + Some(geom) => out.push(Item { props: Props::read(&m.common), geom }), + None if is_known(e.kind) => {} + None => self.skip(e.kind), } } out } - fn geom(&mut self, head: &Record<'_>, group: &[Record<'_>]) -> Option { - let g = head.g; + fn geom(&mut self, e: &EntityRecord<'_>, m: &model::Entity) -> Option { + let g = e.groups(); let path = |bp: BezPath| Some(Geom::Path { bp, fill: false, width: 0.0 }); - match head.kind { - "LINE" => { + let ocs = ocs(m.common.extrusion); + match &m.kind { + model::EntityKind::Line { start, end } => { let mut bp = BezPath::new(); - bp.move_to(g.point(10)); - bp.line_to(g.point(11)); + bp.move_to(point(*start)); + bp.line_to(point(*end)); path(bp) } - "CIRCLE" => path(transformed(curve::arc(g.point(10), g.num(40)?, 0.0, std::f64::consts::TAU)?, ocs(g))), - "ARC" => { - let (start, end) = (g.num_or(50, 0.0), g.num_or(51, 360.0)); - let sweep = ccw_sweep(start, end); - path(transformed(curve::arc(g.point(10), g.num(40)?, start.to_radians(), sweep.to_radians())?, ocs(g))) + model::EntityKind::Circle { center, radius } => path(transformed(curve::arc(point(*center), *radius, 0.0, std::f64::consts::TAU)?, ocs)), + model::EntityKind::Arc { center, radius, start_angle, end_angle } => { + let sweep = ccw_sweep(*start_angle, *end_angle); + path(transformed(curve::arc(point(*center), *radius, start_angle.to_radians(), sweep.to_radians())?, ocs)) } - "ELLIPSE" => path(ellipse(g)?), - "LWPOLYLINE" => lwpolyline(g), - "POLYLINE" => self.polyline(g, group.get(1..).unwrap_or(&[])), - "SPLINE" => path(spline(g)?), - "SOLID" | "TRACE" => { - let [a, b, c, d] = [g.point(10), g.point(11), g.point(12), g.point_opt(13).unwrap_or(g.point(12))]; + model::EntityKind::Ellipse { center, major, ratio, start, end } => { + path(ellipse(m.common.extrusion, *center, *major, *ratio, *start, *end)?) + } + model::EntityKind::LwPolyline(p) => lwpolyline(p, ocs), + model::EntityKind::Polyline(p) => self.polyline(p, ocs), + model::EntityKind::Spline(s) => path(spline(s)?), + model::EntityKind::Solid { corners } | model::EntityKind::Trace { corners } => { + let [a, b, c, d] = corners.map(point); // The corners zigzag: the outline runs 1, 2, 4, 3. - Some(Geom::Path { bp: transformed(polygon(&[a, b, d, c]), ocs(g)), fill: true, width: 0.0 }) + Some(Geom::Path { bp: transformed(polygon(&[a, b, d, c]), ocs), fill: true, width: 0.0 }) } - "3DFACE" => { - let [a, b, c, d] = [g.point(10), g.point(11), g.point(12), g.point_opt(13).unwrap_or(g.point(12))]; - path(polygon(&[a, b, c, d])) - } - "HATCH" => self.hatch(g), - "TEXT" | "ATTRIB" => text(g, head.kind == "ATTRIB").map(Geom::Text), - "MTEXT" => mtext(g).map(Geom::Text), - "INSERT" => self.insert(g, group.get(1..).unwrap_or(&[])), + model::EntityKind::Face3d { corners, .. } => path(polygon(&corners.map(point))), + model::EntityKind::Hatch(h) => self.hatch(h, ocs), + model::EntityKind::Text(t) => text(t, &g, false, ocs).map(Geom::Text), + model::EntityKind::MText(t) => mtext(t, e.tags).map(Geom::Text), + model::EntityKind::Insert(ins) => self.insert(ins, &e.followers, ocs), // A dimension draws the anonymous block of its lines, arrows and text. - "DIMENSION" => Some(Geom::Insert(InsertItem { block: g.name(2)?.to_uppercase(), cells: vec![Affine::IDENTITY], attribs: vec![] })), + model::EntityKind::Dimension(d) => { + Some(Geom::Insert(InsertItem { block: d.block.as_ref()?.to_uppercase(), cells: vec![Affine::IDENTITY], attribs: vec![] })) + } _ => None, } } - fn polyline(&mut self, g: &[Pair<'_>], rest: &[Record<'_>]) -> Option { - let flags = g.int_or(70, 0); - if flags & (16 | 64) != 0 { + fn polyline(&mut self, p: &model::Polyline, ocs: Affine) -> Option { + if p.is_mesh() || p.is_polyface() { self.warn(MESHES); return None; } // Spline frame control points and polyface faces aren't on the line. - let verts: Vec = rest - .iter() - .filter(|r| r.kind == "VERTEX" && r.g.int_or(70, 0) & (16 | 128) == 0) - .map(|r| Vertex { p: r.g.point(10), bulge: r.g.num_or(42, 0.0) }) - .collect(); - let bp = curve::polyline(&verts, flags & 1 != 0)?; + let verts: Vec = + p.vertices.iter().filter(|v| v.flags & (16 | 128) == 0).map(|v| Vertex { p: point(v.location), bulge: v.bulge }).collect(); + let bp = curve::polyline(&verts, p.closed())?; // 3D polylines are in world coordinates; 2D ones in their plane's. - let bp = if flags & 8 != 0 { bp } else { transformed(bp, ocs(g)) }; - Some(Geom::Path { bp, fill: false, width: g.num_or(40, 0.0).max(0.0) }) + let bp = if p.is_3d() { bp } else { transformed(bp, ocs) }; + Some(Geom::Path { bp, fill: false, width: p.start_width.max(0.0) }) } - fn insert(&mut self, g: &[Pair<'_>], rest: &[Record<'_>]) -> Option { - let block = g.name(2)?.to_uppercase(); - let (sx, sy) = (g.num_or(41, 1.0), g.num_or(42, 1.0)); + fn insert(&mut self, ins: &model::Insert, followers: &[model::Record<'_>], ocs: Affine) -> Option { + let block = Some(ins.block.trim()).filter(|b| !b.is_empty())?.to_uppercase(); + let [sx, sy, _] = ins.scale; if sx.abs() < 1e-12 || sy.abs() < 1e-12 { return None; } - let place = ocs(g) * Affine::translate(g.point(10).to_vec2()) * Affine::rotate(g.num_or(50, 0.0).to_radians()); - let (cols, rows) = (g.int_or(70, 1).max(1), g.int_or(71, 1).max(1)); - let (cs, rs) = (g.num_or(44, 0.0), g.num_or(45, 0.0)); + let place = ocs * Affine::translate(point(ins.insert).to_vec2()) * Affine::rotate(ins.rotation.to_radians()); + let (cols, rows) = (ins.columns, ins.rows); + let (cs, rs) = (ins.column_spacing, ins.row_spacing); let (cols, rows) = if cols.saturating_mul(rows) > MAX_CELLS { self.warn(BIG_ARRAY); (cols.min(MAX_CELLS), (MAX_CELLS / cols.min(MAX_CELLS)).max(1).min(rows)) @@ -312,27 +295,41 @@ impl Converter { .flat_map(|r| (0..cols).map(move |c| (r, c))) .map(|(r, c)| place * Affine::translate((c as f64 * cs, r as f64 * rs)) * Affine::scale_non_uniform(sx, sy)) .collect(); - let attribs = self.items(rest); + let attribs = self.attribs(followers); Some(Geom::Insert(InsertItem { block, cells, attribs })) } - fn hatch(&mut self, g: &[Pair<'_>]) -> Option { - let start = g.iter().position(|p| p.code == 91)?; - let count = g.get(start).and_then(|p| number(p.value)).filter(|n| *n >= 0.0)? as usize; - let mut c = Cursor { g, i: start + 1 }; + /// An insert's attributes as text. + fn attribs(&mut self, followers: &[model::Record<'_>]) -> Vec { + let mut out = Vec::new(); + for r in followers { + let c = model::Common::read(r.tags); + if !c.visible { + continue; + } + let a = model::Attrib::read("ATTRIB", r.tags); + match text(&a.text, &r.groups(), true, ocs(c.extrusion)) { + Some(t) if !in_range(&Geom::Text(t.clone())) => self.warn(FAR_AWAY), + Some(t) => out.push(Item { props: Props::read(&c), geom: Geom::Text(t) }), + None => {} + } + } + out + } + + fn hatch(&mut self, h: &model::Hatch, ocs: Affine) -> Option { let mut bp = BezPath::new(); - for _ in 0..count { - let Some(path) = boundary(&mut c) else { break }; + for l in &h.loops { + let Some(path) = boundary(&l.path) else { break }; bp.extend(path); } if bp.elements().is_empty() { return None; } - let bp = transformed(bp, ocs(g)); - let solid = g.int_or(70, 0) == 1; - if g.int_or(450, 0) == 1 { + let bp = transformed(bp, ocs); + if h.gradient.is_some() { self.warn(GRADIENT_HATCH); - } else if !solid { + } else if !h.solid { self.warn(PATTERN_HATCH); return Some(Geom::Path { bp, fill: false, width: 0.0 }); } @@ -401,217 +398,104 @@ fn polygon(pts: &[Point]) -> BezPath { bp } -/// The extrusion direction (210, 220, 230) of a planar entity, normalised. -fn extrusion(g: &[Pair<'_>]) -> [f64; 3] { - let n = [g.num_or(210, 0.0), g.num_or(220, 0.0), g.num_or(230, 1.0)]; - let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt(); - if len > 1e-12 && len.is_finite() { n.map(|v| v / len) } else { [0.0, 0.0, 1.0] } -} - fn cross(a: [f64; 3], b: [f64; 3]) -> [f64; 3] { [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]] } -fn unit(v: [f64; 3]) -> [f64; 3] { - let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt(); - if len > 1e-12 { v.map(|x| x / len) } else { v } -} - /// A planar entity's coordinate system seen from above: its x and y axes in world space by the /// arbitrary axis algorithm (identity for drawings in the world's plane; extruded along −z it /// mirrors x). -fn ocs(g: &[Pair<'_>]) -> Affine { - let n = extrusion(g); - if n[2] > 1.0 - 1e-12 { +fn ocs(extrusion: model::Point) -> Affine { + let [ax, ay, _] = model::ocs_axes(extrusion); + if ax == [1.0, 0.0, 0.0] && ay == [0.0, 1.0, 0.0] { return Affine::IDENTITY; } - let ax = unit(if n[0].abs() < 1.0 / 64.0 && n[1].abs() < 1.0 / 64.0 { cross([0.0, 1.0, 0.0], n) } else { cross([0.0, 0.0, 1.0], n) }); - let ay = unit(cross(n, ax)); Affine::new([ax[0], ax[1], ay[0], ay[1], 0.0, 0.0]) } -fn ellipse(g: &[Pair<'_>]) -> Option { - let centre = g.point(10); - let major = g.point(11).to_vec2(); - let ratio = g.num_or(40, 1.0); +fn ellipse(extrusion: model::Point, centre: model::Point, major: model::Point, ratio: f64, start: f64, end: f64) -> Option { + let centre = point(centre); + let major = point(major).to_vec2(); if ratio <= 0.0 || major.hypot() < 1e-12 { return None; } // The minor axis is the major one turned a quarter about the extrusion direction. - let n = extrusion(g); + let n = model::ocs_axes(extrusion)[2]; let m = cross(n, [major.x, major.y, 0.0]); let minor = Vec2::new(m[0], m[1]) * ratio; - let (start, end) = (g.num_or(41, 0.0), g.num_or(42, std::f64::consts::TAU)); let sweep = ccw_sweep(start.to_degrees(), end.to_degrees()).to_radians(); curve::ellipse(Affine::new([major.x, major.y, minor.x, minor.y, centre.x, centre.y]), start, sweep) } -fn lwpolyline(g: &[Pair<'_>]) -> Option { - let mut verts: Vec = Vec::new(); - let (mut widths, mut uniform) = (None, true); - for p in g { - match p.code { - 10 => verts.push(Vertex { p: Point::new(number(p.value)?, 0.0), bulge: 0.0 }), - 20 => verts.last_mut()?.p.y = number(p.value)?, - 42 => verts.last_mut()?.bulge = number(p.value).unwrap_or(0.0), - 40 | 41 => { - let w = number(p.value).unwrap_or(0.0); - uniform &= widths.is_none_or(|x: f64| (x - w).abs() < 1e-12); - widths = Some(w); - } - _ => {} - } - } - let bp = transformed(curve::polyline(&verts, g.int_or(70, 0) & 1 != 0)?, ocs(g)); - let width = g.num(43).filter(|w| *w > 0.0).or(widths.filter(|_| uniform)).unwrap_or(0.0).max(0.0); +fn lwpolyline(p: &model::LwPolyline, ocs: Affine) -> Option { + let verts: Vec = p.vertices.iter().map(|v| Vertex { p: Point::new(v.x, v.y), bulge: v.bulge }).collect(); + let bp = transformed(curve::polyline(&verts, p.closed)?, ocs); + // One width for every vertex is the line's width. + let widths: Vec = p.vertices.iter().flat_map(|v| [v.start_width, v.end_width]).collect(); + let uniform = widths.first().filter(|w| widths.iter().all(|x| (x - *w).abs() < 1e-12)).copied(); + let width = Some(p.const_width).filter(|w| *w > 0.0).or(uniform).unwrap_or(0.0).max(0.0); Some(Geom::Path { bp, fill: false, width }) } -/// The points at `code` (x) and `code + 10` (y), in order. -fn points(g: &[Pair<'_>], code: i32) -> Option> { - let mut out: Vec = Vec::new(); - for p in g { - if p.code == code { - out.push(Point::new(number(p.value)?, 0.0)); - } else if p.code == code + 10 { - out.last_mut()?.y = number(p.value)?; - } - } - Some(out) -} - -fn spline(g: &[Pair<'_>]) -> Option { - let flags = g.int_or(70, 0); - let ctrl = points(g, 10)?; - let degree = usize::try_from(g.int_or(71, 3)).ok()?; - let knots: Vec = g.iter().filter(|p| p.code == 40).map(|p| number(p.value)).collect::>()?; - let weights: Vec = g.iter().filter(|p| p.code == 41).filter_map(|p| number(p.value)).collect(); - let weights = (flags & 4 != 0 && weights.len() == ctrl.len()).then_some(weights.as_slice()); - curve::nurbs(degree, &knots, &ctrl, weights) +fn spline(s: &model::Spline) -> Option { + let ctrl: Vec = s.control.iter().map(|p| point(*p)).collect(); + let degree = usize::try_from(s.degree).ok()?; + let weights = (s.flags & 4 != 0 && s.weights.len() == ctrl.len()).then_some(s.weights.as_slice()); + curve::nurbs(degree, &s.knots, &ctrl, weights) .map(|mut path| { - if flags & 1 != 0 { + if s.flags & 1 != 0 { path.close_path(); } path }) - .or_else(|| curve::through(&points(g, 11)?, flags & 1 != 0)) -} - -/// Reads a hatch's boundary groups in order. -struct Cursor<'g, 'a> { - g: &'g [Pair<'a>], - i: usize, -} - -impl Cursor<'_, '_> { - /// The next group's value when it has `code` (consumed). - fn opt(&mut self, code: i32) -> Option<&str> { - let p = self.g.get(self.i).filter(|p| p.code == code)?; - self.i += 1; - Some(p.value) - } - fn num(&mut self, code: i32) -> Option { - self.opt(code).and_then(number) - } - fn count(&mut self, code: i32) -> Option { - self.num(code).filter(|n| *n >= 0.0 && *n <= 1e7).map(|n| n as usize) - } - fn point(&mut self, code: i32) -> Option { - Some(Point::new(self.num(code)?, self.num(code + 10)?)) - } + .or_else(|| curve::through(&s.fit.iter().map(|p| point(*p)).collect::>(), s.flags & 1 != 0)) } /// One hatch boundary loop, closed. -fn boundary(c: &mut Cursor<'_, '_>) -> Option { - let flags = c.num(92)? as i64; - let mut bp = BezPath::new(); - if flags & 2 != 0 { - let bulges = c.num(72).unwrap_or(0.0) != 0.0; - let _closed = c.opt(73); - let n = c.count(93)?; - let mut verts = Vec::with_capacity(n.min(4096)); - for _ in 0..n { - let p = c.point(10)?; - let bulge = if bulges { c.num(42).unwrap_or(0.0) } else { 0.0 }; - verts.push(Vertex { p, bulge }); +fn boundary(path: &HatchPath) -> Option { + let xy = |p: &[f64; 2]| Point::new(p[0], p[1]); + match path { + HatchPath::Polyline { vertices, .. } => { + let verts: Vec = vertices.iter().map(|[x, y, b]| Vertex { p: Point::new(*x, *y), bulge: *b }).collect(); + curve::polyline(&verts, true) } - bp = curve::polyline(&verts, true)?; - } else { - let n = c.count(93)?; - for _ in 0..n { - let edge = edge(c)?; - append(&mut bp, &edge); - } - if bp.elements().is_empty() { - return None; - } - bp.close_path(); - } - // The boundary objects it was made from. - if let Some(n) = c.count(97) { - for _ in 0..n { - if c.opt(330).is_none() { - break; - } - } - } - Some(bp) -} - -/// One edge of a hatch boundary. -fn edge(c: &mut Cursor<'_, '_>) -> Option { - match c.num(72)? as i64 { - 1 => { + HatchPath::Edges(edges) => { let mut bp = BezPath::new(); - bp.move_to(c.point(10)?); - bp.line_to(c.point(11)?); + for e in edges { + let seg = match e { + HatchEdge::Line { start, end } => { + let mut bp = BezPath::new(); + bp.move_to(xy(start)); + bp.line_to(xy(end)); + Some(bp) + } + HatchEdge::Arc { center, radius, start_angle, end_angle, ccw } => { + let sweep = ccw_sweep(*start_angle, *end_angle); + // Clockwise arcs have their angles measured clockwise. + let (start, sweep) = if *ccw { (*start_angle, sweep) } else { (-start_angle, -sweep) }; + curve::arc(xy(center), *radius, start.to_radians(), sweep.to_radians()) + } + HatchEdge::Ellipse { center, major, ratio, start_angle, end_angle, ccw } => { + let (centre, major) = (xy(center), xy(major).to_vec2()); + let minor = Vec2::new(-major.y, major.x) * *ratio * if *ccw { 1.0 } else { -1.0 }; + let sweep = ccw_sweep(*start_angle, *end_angle).to_radians(); + curve::ellipse(Affine::new([major.x, major.y, minor.x, minor.y, centre.x, centre.y]), start_angle.to_radians(), sweep) + } + HatchEdge::Spline { degree, rational, knots, control, weights, fit, .. } => { + let ctrl: Vec = control.iter().map(xy).collect(); + let degree = usize::try_from(*degree).ok()?; + let weights = (*rational && weights.len() == ctrl.len()).then_some(weights.as_slice()); + curve::nurbs(degree, knots, &ctrl, weights).or_else(|| curve::through(&fit.iter().map(xy).collect::>(), false)) + } + }; + append(&mut bp, &seg?); + } + if bp.elements().is_empty() { + return None; + } + bp.close_path(); Some(bp) } - 2 => { - let (centre, r, start, end) = (c.point(10)?, c.num(40)?, c.num(50)?, c.num(51)?); - let ccw = c.num(73).unwrap_or(1.0) != 0.0; - let sweep = ccw_sweep(start, end); - // Clockwise arcs have their angles measured clockwise. - let (start, sweep) = if ccw { (start, sweep) } else { (-start, -sweep) }; - curve::arc(centre, r, start.to_radians(), sweep.to_radians()) - } - 3 => { - let (centre, major, ratio, start, end) = (c.point(10)?, c.point(11)?.to_vec2(), c.num(40)?, c.num(50)?, c.num(51)?); - let ccw = c.num(73).unwrap_or(1.0) != 0.0; - let minor = Vec2::new(-major.y, major.x) * ratio * if ccw { 1.0 } else { -1.0 }; - let sweep = ccw_sweep(start, end).to_radians(); - curve::ellipse(Affine::new([major.x, major.y, minor.x, minor.y, centre.x, centre.y]), start.to_radians(), sweep) - } - 4 => { - let degree = c.count(94)?; - let rational = c.num(73).unwrap_or(0.0) != 0.0; - let _periodic = c.opt(74); - let (nk, nc) = (c.count(95)?, c.count(96)?); - let knots: Vec = (0..nk).map(|_| c.num(40)).collect::>()?; - let mut ctrl = Vec::with_capacity(nc.min(4096)); - let mut weights = Vec::with_capacity(nc.min(4096)); - for _ in 0..nc { - ctrl.push(c.point(10)?); - weights.push(c.num(42).unwrap_or(1.0)); - } - // Fit data (DXF 2010 and later): a count, then that many points. Older files have none, - // and the 97 that may follow is the boundary's count of source objects (then their - // handles), so it is only the fit count when it is 0 or points follow. - let fit_count = match (c.g.get(c.i), c.g.get(c.i + 1)) { - (Some(count), next) if count.code == 97 => number(count.value) == Some(0.0) || next.is_some_and(|p| p.code == 11), - _ => false, - }; - let fit: Vec = match fit_count.then(|| c.count(97)).flatten() { - Some(n) => (0..n).map(|_| c.point(11)).collect::>()?, - None => vec![], - }; - // Start and end tangents. - for code in [12, 13] { - c.point(code); - } - curve::nurbs(degree, &knots, &ctrl, rational.then_some(weights.as_slice())).or_else(|| curve::through(&fit, false)) - } - _ => None, } } @@ -643,18 +527,21 @@ fn baseline(v: i64, height: f64) -> f64 { } } -fn text(g: &[Pair<'_>], attrib: bool) -> Option { - if attrib && g.int_or(70, 0) & 1 != 0 { +/// TEXT, or an ATTRIB's text. The string is read from group 1 as written, so that the caret and +/// percent codes are turned into text once, by `super::text`. +fn text(t: &model::Text, g: &Groups<'_>, attrib: bool, ocs: Affine) -> Option { + if attrib && g.i_or(70, 0) & 1 != 0 { return None; } - let s = super::text::plain(g.raw(1)?); + let s = super::text::plain(&g.s(1)?); if s.trim().is_empty() { return None; } - let height = g.num(40).filter(|h| *h > 0.0)?; - let (h, v) = (g.int_or(72, 0), g.int_or(if attrib { 74 } else { 73 }, 0)); - let (p1, p2) = (g.point(10), g.point_opt(11)); - let mut angle = g.num_or(50, 0.0).to_radians(); + let height = Some(t.height).filter(|h| *h > 0.0)?; + // An ATTRIB's 73 is its field length: its vertical alignment is 74. + let (h, v) = (t.halign, if attrib { g.i_or(74, 0) } else { t.valign }); + let (p1, p2) = (point(t.insert), t.align.map(point)); + let mut angle = t.rotation.to_radians(); let mut span = None; // Aligned and fit text run from the first point to the second. let anchor = match (h, p2) { @@ -674,33 +561,36 @@ fn text(g: &[Pair<'_>], attrib: bool) -> Option { _ => Justify::Left, }; let v = if h == 4 { 2 } else { v }; - let flags = g.int_or(71, 0); + let flags = t.generation; let mirror = Affine::scale_non_uniform(if flags & 2 != 0 { -1.0 } else { 1.0 }, if flags & 4 != 0 { -1.0 } else { 1.0 }); - let xf = ocs(g) * Affine::translate(anchor.to_vec2()) * Affine::rotate(angle) * mirror * Affine::translate((0.0, baseline(v, height))); + let xf = ocs * Affine::translate(anchor.to_vec2()) * Affine::rotate(angle) * mirror * Affine::translate((0.0, baseline(v, height))); Some(TextItem { text: s, height, xf, - width: g.num(41).filter(|w| *w > 0.0).unwrap_or(1.0), + width: Some(t.width_factor).filter(|w| *w > 0.0).unwrap_or(1.0), justify, - style: g.name(7).unwrap_or("STANDARD").to_uppercase(), + style: t.style.to_uppercase(), family: None, leading: None, span, }) } -fn mtext(g: &[Pair<'_>]) -> Option { - // The text comes in 250-character chunks (3) before the last (1). - let raw: String = g.iter().filter(|p| p.code == 3).map(|p| p.value).chain(g.raw(1)).collect(); +/// MTEXT. The contents are read from groups 3 and 1 as written, as for [`text`]. +fn mtext(t: &model::MText, tags: &[craft_dxf::Tag]) -> Option { + // The text comes in 250-character chunks (3) before the last (1), up to an embedded object. + let (own, _) = model::text::split_embedded(tags); + let g = Groups(own); + let raw: String = own.iter().filter(|t| t.code == 3).map(craft_dxf::Tag::str).chain(g.s(1)).collect(); let (s, family) = super::text::mtext(&raw); if s.trim().is_empty() { return None; } - let height = g.num(40).filter(|h| *h > 0.0)?; - let leading = height * LINE_SPACING * g.num(44).filter(|f| *f > 0.0).unwrap_or(1.0); + let height = Some(t.height).filter(|h| *h > 0.0)?; + let leading = height * LINE_SPACING * Some(t.line_spacing).filter(|f| *f > 0.0).unwrap_or(1.0); let lines = s.lines().count().max(1) as f64; - let attach = g.int_or(71, 1).clamp(1, 9) - 1; + let attach = i64::from(t.attach) - 1; let justify = [Justify::Left, Justify::Center, Justify::Right].get((attach % 3) as usize).copied().unwrap_or_default(); // The first baseline below the attachment point: under the top, around the middle, above // the bottom of the lines. @@ -710,18 +600,6 @@ fn mtext(g: &[Pair<'_>]) -> Option { 1 => total / 2.0 - height, _ => (lines - 1.0) * leading, }; - let direction = g.point_opt(11).map(|p| p.to_vec2()).filter(|d| d.hypot() > 1e-12); - let angle = direction.map_or_else(|| g.num_or(50, 0.0), |d| d.atan2()); - let xf = Affine::translate(g.point(10).to_vec2()) * Affine::rotate(angle) * Affine::translate((0.0, first)); - Some(TextItem { - text: s, - height, - xf, - width: 1.0, - justify, - style: g.name(7).unwrap_or("STANDARD").to_uppercase(), - family, - leading: Some(leading), - span: None, - }) + let xf = Affine::translate(point(t.insert).to_vec2()) * Affine::rotate(t.angle()) * Affine::translate((0.0, first)); + Some(TextItem { text: s, height, xf, width: 1.0, justify, style: t.style.to_uppercase(), family, leading: Some(leading), span: None }) } diff --git a/crates/cad/src/import/reader.rs b/crates/cad/src/import/reader.rs index 0da950ead1..762cfdb721 100644 --- a/crates/cad/src/import/reader.rs +++ b/crates/cad/src/import/reader.rs @@ -1,156 +1,14 @@ -//! Reading an ASCII DXF file: its text, the group-code pairs, and what the import uses of its -//! sections (header variables; the layer, linetype, text style and block record tables; the -//! blocks; the entities; the layouts). +//! What the import uses of a drawing, from `craft_dxf::model`: header variables; the layer, +//! linetype and text style tables; the blocks; the entities; the layouts. -use std::borrow::Cow; use std::collections::HashMap; +use craft_dxf::model::{self, EntityRecord}; use vectorcraft_geom::Point; -/// The most group-code pairs a drawing may hold (about 300 MB of DXF). -const MAX_PAIRS: usize = 20_000_000; - /// The first bytes of a binary DXF file (its format's signature). pub const BINARY_SENTINEL: &[u8] = b"AutoCAD Binary DXF\r\n\x1a\x00"; -/// One group: its code and its value as written. -#[derive(Clone, Copy, Debug)] -pub(crate) struct Pair<'a> { - pub code: i32, - pub value: &'a str, -} - -/// Values of a run of pairs by group code. -pub(crate) trait Groups<'a> { - /// The value of the first `code`, as written. - fn raw(&self, code: i32) -> Option<&'a str>; - /// The first `code` as a name (trimmed, never empty). - fn name(&self, code: i32) -> Option<&'a str> { - self.raw(code).map(str::trim).filter(|s| !s.is_empty()) - } - /// The first `code` as a finite number. - fn num(&self, code: i32) -> Option { - self.raw(code).and_then(number) - } - fn num_or(&self, code: i32, default: f64) -> f64 { - self.num(code).unwrap_or(default) - } - /// The first `code` as a whole number. - fn int(&self, code: i32) -> Option { - self.raw(code).and_then(integer) - } - fn int_or(&self, code: i32, default: i64) -> i64 { - self.int(code).unwrap_or(default) - } - /// The point at `code` (x) and `code + 10` (y); 0 for what is missing. - fn point(&self, code: i32) -> Point { - Point::new(self.num_or(code, 0.0), self.num_or(code + 10, 0.0)) - } - /// [`Groups::point`] when its x is given. - fn point_opt(&self, code: i32) -> Option { - self.num(code).map(|x| Point::new(x, self.num_or(code + 10, 0.0))) - } -} - -impl<'a> Groups<'a> for [Pair<'a>] { - fn raw(&self, code: i32) -> Option<&'a str> { - self.iter().find(|p| p.code == code).map(|p| p.value) - } -} - -/// A finite number (`1e999`, `NaN` and junk are none). -pub(crate) fn number(s: &str) -> Option { - s.trim().parse::().ok().filter(|v| v.is_finite()) -} - -/// A whole number; some writers put integers as `1.0`. -pub(crate) fn integer(s: &str) -> Option { - let s = s.trim(); - s.parse::().ok().or_else(|| number(s).filter(|v| v.abs() < 9.0e15 && v.fract() == 0.0).map(|v| v as i64)) -} - -/// One object: its type (the value of its `0` group) and the groups up to the next object. -#[derive(Clone, Copy, Debug)] -pub(crate) struct Record<'a> { - pub kind: &'a str, - pub g: &'a [Pair<'a>], -} - -/// The text of a DXF file: UTF-8 (DXF 2007 and later), else the Windows code page older versions -/// write (a byte order mark is dropped). -pub(crate) fn decode(bytes: &[u8]) -> Cow<'_, str> { - let bytes = bytes.strip_prefix(b"\xEF\xBB\xBF").unwrap_or(bytes); - match std::str::from_utf8(bytes) { - Ok(s) => Cow::Borrowed(s), - Err(_) => Cow::Owned(bytes.iter().map(|b| windows_1252(*b)).collect()), - } -} - -/// A byte of the Windows Western code page. -fn windows_1252(b: u8) -> char { - const HIGH: [char; 32] = [ - '€', '\u{81}', '‚', 'ƒ', '„', '…', '†', '‡', 'ˆ', '‰', 'Š', '‹', 'Œ', '\u{8D}', 'Ž', '\u{8F}', '\u{90}', '‘', '’', '“', '”', '•', '–', '—', - '˜', '™', 'š', '›', 'œ', '\u{9D}', 'ž', 'Ÿ', - ]; - match b { - 0x80..=0x9F => HIGH.get(usize::from(b - 0x80)).copied().unwrap_or('?'), - _ => char::from(b), - } -} - -/// The group-code pairs of `text`, up to `0 EOF`. A line that isn't a group code ends the -/// reading: what came before is kept and the second value says where the file is damaged. -pub(crate) fn pairs(text: &str) -> Result<(Vec>, Option), String> { - let mut out = Vec::new(); - let mut lines = text.lines().enumerate(); - let mut damaged = None; - while let Some((n, code)) = lines.next() { - let c = code.trim(); - if c.is_empty() && out.is_empty() { - continue; - } - let Ok(code) = c.parse::() else { - damaged = Some(format!("the file is damaged at line {}: what follows is left out", n + 1)); - break; - }; - let value = lines.next().map_or("", |(_, v)| v); - if code == 0 && value.trim() == "EOF" { - break; - } - if out.len() >= MAX_PAIRS { - return Err("the drawing is too large to open".into()); - } - out.push(Pair { code, value }); - } - if out.is_empty() { - return Err("not a DXF drawing".into()); - } - Ok((out, damaged)) -} - -/// The objects in `pairs`: each from a `0` group up to the next. -fn records<'a>(pairs: &'a [Pair<'a>]) -> Vec> { - let mut out = Vec::new(); - let mut start: Option = None; - for (i, p) in pairs.iter().enumerate() { - if p.code == 0 { - if let Some(s) = start { - out.extend(record(pairs, s, i)); - } - start = Some(i); - } - } - if let Some(s) = start { - out.extend(record(pairs, s, pairs.len())); - } - out -} - -fn record<'a>(pairs: &'a [Pair<'a>], start: usize, end: usize) -> Option> { - let kind = pairs.get(start)?.value.trim(); - Some(Record { kind, g: pairs.get(start + 1..end)? }) -} - /// The header variables the import reads. #[derive(Clone, Debug, Default)] pub(crate) struct Header { @@ -186,7 +44,7 @@ pub(crate) struct LayerDef { pub(crate) struct BlockDef<'a> { pub name: String, pub base: Point, - pub records: Vec>, + pub records: Vec>, /// A reference to another drawing (its art isn't in this file). pub xref: bool, } @@ -218,97 +76,51 @@ pub(crate) struct Drawing<'a> { /// Blocks by upper-case name. pub blocks: HashMap>, /// The ENTITIES section. - pub entities: Vec>, + pub entities: Vec>, /// Model space first, then the paper layouts in tab order. pub layouts: Vec, /// How many sections the file has (none: not a drawing). pub sections: usize, } -impl<'a> Drawing<'a> { - /// Read the sections of `pairs`. - pub fn read(pairs: &'a [Pair<'a>]) -> Self { - let mut d = Drawing { header: Header { ltscale: 1.0, lwdefault: 25, ..Header::default() }, ..Drawing::default() }; - let all = records(pairs); - let mut section: Option<&str> = None; - let (mut tables, mut blocks, mut objects) = (vec![], vec![], vec![]); - for r in all { - match (r.kind, section) { - ("SECTION", _) => { - d.sections += 1; - section = r.g.name(2); - if section == Some("HEADER") { - d.header = header(r.g); - } - } - ("ENDSEC", _) => section = None, - (_, Some("TABLES")) => tables.push(r), - (_, Some("BLOCKS")) => blocks.push(r), - (_, Some("ENTITIES")) => d.entities.push(r), - (_, Some("OBJECTS")) => objects.push(r), - _ => {} - } - } - let mut block_records = HashMap::new(); - let mut table = ""; - for r in &tables { - match r.kind { - "TABLE" => table = r.g.name(2).unwrap_or(""), - "LAYER" if table == "LAYER" => { - if let Some(l) = layer(r.g) { - d.layer_index.entry(l.name.to_uppercase()).or_insert(d.layers.len()); - d.layers.push(l); - } - } - "LTYPE" if table == "LTYPE" => { - if let Some(name) = r.g.name(2) { - let pattern: Vec = r.g.iter().filter(|p| p.code == 49).filter_map(|p| number(p.value)).collect(); - d.linetypes.insert(name.to_uppercase(), pattern); - } - } - "STYLE" if table == "STYLE" => { - if let Some(name) = r.g.name(2) { - d.styles.insert(name.to_uppercase(), font_family(r.g)); - } - } - "BLOCK_RECORD" if table == "BLOCK_RECORD" => { - if let (Some(h), Some(name)) = (r.g.name(5), r.g.name(2)) { - block_records.insert(h.to_uppercase(), name.to_uppercase()); - } - } - _ => {} - } - } - d.read_blocks(&blocks, &mut block_records); - d.layouts = layouts(&objects, &block_records, &d.entities); - d - } +/// The colour of index `i` on paper: index 7 (white on a CAD screen) is black. +pub(crate) fn aci_paper(i: u8) -> [u8; 3] { + if i == 7 { [0; 3] } else { model::aci::rgb(i) } +} - fn read_blocks(&mut self, records: &[Record<'a>], block_records: &mut HashMap) { - let mut current: Option> = None; - for r in records { - match r.kind { - "BLOCK" => { - let name = r.g.name(2).or_else(|| r.g.name(3)).unwrap_or("").to_string(); - // R13+ blocks name their block record: layouts find their block through it. - if let Some(owner) = r.g.name(330) { - block_records.entry(owner.to_uppercase()).or_insert_with(|| name.to_uppercase()); - } - let xref = r.g.int_or(70, 0) & 4 != 0; - current = Some(BlockDef { name, base: r.g.point(10), records: vec![], xref }); - } - "ENDBLK" => { - if let Some(b) = current.take().filter(|b| !b.name.is_empty()) { - self.blocks.insert(b.name.to_uppercase(), b); - } - } - _ => { - if let Some(b) = &mut current { - b.records.push(*r); - } - } - } +impl<'a> Drawing<'a> { + /// What the import uses of `doc`. + pub fn read(doc: model::Document<'a>) -> Self { + let h = &doc.header; + let header = Header { + acadver: h.acadver().unwrap_or_default(), + insunits: h.insunits(), + measurement: h.measurement(), + ltscale: h.ltscale(), + lwdefault: i32::from(h.lwdefault()), + }; + let mut d = Drawing { header, sections: doc.sections, ..Drawing::default() }; + for l in doc.layers() { + d.layer_index.entry(l.name.to_uppercase()).or_insert(d.layers.len()); + d.layers.push(layer(l)); } + for lt in doc.linetypes() { + d.linetypes.insert(lt.name.to_uppercase(), lt.pattern.iter().map(|e| e.length).collect()); + } + for st in doc.text_styles().into_iter().filter(|s| !s.name.is_empty()) { + d.styles.insert(st.name.to_uppercase(), st.family().unwrap_or_default()); + } + let block_names = doc.block_names(); + d.layouts = layouts(&doc, &block_names); + for b in doc.blocks { + if b.name.is_empty() { + continue; + } + let def = BlockDef { name: b.name.to_string(), base: point(b.base()), xref: b.flags() & 4 != 0, records: b.entities }; + d.blocks.insert(b.name.to_uppercase(), def); + } + d.entities = doc.entities; + d } /// The layout named `name` (any case; `model` is model space). @@ -317,7 +129,7 @@ impl<'a> Drawing<'a> { } /// The entity records of `layout`. - pub fn layout_records(&self, layout: &LayoutDef) -> Vec> { + pub fn layout_records(&self, layout: &LayoutDef) -> Vec> { let block = |name: &str| self.blocks.get(name).map(|b| b.records.clone()).unwrap_or_default(); // The active paper layout keeps its art in the ENTITIES section, flagged paper space. let (block_name, paper) = match &layout.block { @@ -325,7 +137,7 @@ impl<'a> Drawing<'a> { Some(b) if b == PAPER_BLOCK => (PAPER_BLOCK, true), Some(b) => return block(b), }; - let mut out: Vec> = groups(&self.entities).filter(|g| in_paper_space(g) == paper).flatten().copied().collect(); + let mut out: Vec> = self.entities.iter().filter(|e| e.paper_space() == paper).cloned().collect(); out.extend(block(block_name)); out } @@ -336,111 +148,47 @@ impl<'a> Drawing<'a> { } } -/// Is an entity (its first record) in paper space? -fn in_paper_space(group: &[Record<'_>]) -> bool { - group.first().is_some_and(|r| r.g.int(67) == Some(1)) +pub(crate) fn point(p: model::Point) -> Point { + Point::new(p[0], p[1]) } -/// The entities of `records`, each with the records that belong to it (a polyline's vertices, -/// an insert's attributes, and the SEQEND closing them). -pub(crate) fn groups<'r, 'a>(records: &'r [Record<'a>]) -> impl Iterator]> { - let mut i = 0; - std::iter::from_fn(move || { - let start = i; - let head = records.get(start)?; - i += 1; - if matches!(head.kind, "POLYLINE" | "INSERT") { - while let Some(r) = records.get(i) { - match r.kind { - "VERTEX" | "ATTRIB" => i += 1, - "SEQEND" => { - i += 1; - break; - } - _ => break, - } - } - } - records.get(start..i) - }) -} - -fn header(g: &[Pair<'_>]) -> Header { - let mut h = Header { ltscale: 1.0, lwdefault: 25, ..Header::default() }; - let mut var = ""; - for p in g { - if p.code == 9 { - var = p.value.trim(); - continue; - } - match (var, p.code) { - ("$ACADVER", 1) => h.acadver = p.value.trim().to_string(), - ("$INSUNITS", 70) => h.insunits = integer(p.value).unwrap_or(0), - ("$MEASUREMENT", 70) => h.measurement = integer(p.value), - ("$LTSCALE", 40) => h.ltscale = number(p.value).filter(|v| *v > 0.0).unwrap_or(1.0), - ("$LWDEFAULT", 370) => h.lwdefault = integer(p.value).and_then(|v| i32::try_from(v).ok()).filter(|v| *v >= 0).unwrap_or(25), - _ => {} - } - } - h -} - -fn layer(g: &[Pair<'_>]) -> Option { - let name = g.name(2)?.to_string(); - let aci = g.int_or(62, 7); - let flags = g.int_or(70, 0); - let rgb = super::entity::true_color(g).unwrap_or_else(|| super::entity::aci_paper(aci.unsigned_abs())); - Some(LayerDef { +fn layer(l: model::Layer) -> LayerDef { + let rgb = match l.color { + model::Color::Rgb(rgb) => rgb, + model::Color::Index(i) => aci_paper(i), + model::Color::ByLayer | model::Color::ByBlock => aci_paper(7), + }; + LayerDef { // CAD apps never plot this layer of dimension points. - plot: g.int_or(290, 1) != 0 && !name.eq_ignore_ascii_case("Defpoints"), - name, + plot: l.plot && !l.name.eq_ignore_ascii_case("Defpoints"), rgb, - hidden: aci < 0 || flags & 1 != 0, - locked: flags & 4 != 0, - linetype: g.name(6).unwrap_or("CONTINUOUS").to_uppercase(), - lineweight: g.int(370).and_then(|v| i32::try_from(v).ok()).unwrap_or(-3), - }) -} - -/// A text style's font family: the one 2000-and-later files name, else the font file's name -/// (TrueType); CAD fonts (`.shx`) have none. -fn font_family(g: &[Pair<'_>]) -> String { - if let Some(i) = g.iter().position(|p| p.code == 1001 && p.value.trim() == "ACAD") - && let Some(f) = g.get(i + 1..).and_then(|rest| rest.name(1000)) - { - return f.to_string(); - } - let file = g.name(3).unwrap_or(""); - let path = std::path::Path::new(file); - let ext = path.extension().map(|e| e.to_string_lossy().to_ascii_lowercase()).unwrap_or_default(); - match ext.as_str() { - "ttf" | "otf" | "ttc" => path.file_stem().map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(), - _ => String::new(), + hidden: !l.on || l.frozen, + locked: l.locked, + linetype: l.linetype.to_uppercase(), + lineweight: i32::try_from(l.lineweight.to_dxf()).unwrap_or(-3), + name: l.name, } } -/// Model space, then each paper layout (its LAYOUT object, in tab order); a file without layout -/// objects but with paper-space art has one paper layout. /// The most bytes of layout and block names the layouts keep together. Each layout keeps its own /// copy of its block's name, so many layouts naming one long block name multiplied it; real /// drawings have a few dozen layouts with short names. const MAX_LAYOUT_NAME_BYTES: usize = 4 << 20; -fn layouts(objects: &[Record<'_>], block_records: &HashMap, entities: &[Record<'_>]) -> Vec { +/// Model space, then each paper layout (its LAYOUT object, in tab order); a file without layout +/// objects but with paper-space art has one paper layout. +fn layouts(doc: &model::Document<'_>, block_names: &HashMap) -> Vec { let mut paper: Vec<(i64, LayoutDef)> = vec![]; let mut seen = std::collections::HashSet::new(); let mut name_bytes = 0usize; - for r in objects.iter().filter(|r| r.kind == "LAYOUT") { - // The layout's own groups follow its subclass marker. - let own = r.g.iter().position(|p| p.code == 100 && p.value.trim() == "AcDbLayout").and_then(|i| r.g.get(i + 1..)).unwrap_or(&[]); - let Some(name) = own.name(1) else { continue }; - let block = own.name(330).and_then(|h| block_records.get(&h.to_uppercase())); - if name.eq_ignore_ascii_case(MODEL) || block.map(String::as_str) == Some(MODEL_BLOCK) { + for l in doc.layouts() { + let block = l.block_record.and_then(|h| block_names.get(&h)).map(|n| n.to_uppercase()); + if l.name.eq_ignore_ascii_case(MODEL) || block.as_deref() == Some(MODEL_BLOCK) { continue; } let Some(block) = block else { continue }; - let key = name.to_ascii_lowercase(); - let cost = name.len() + block.len(); + let key = l.name.to_ascii_lowercase(); + let cost = l.name.len() + block.len(); // A layout past the allowance is skipped alone: a later short one is still offered, and a // skipped one reserves neither its name nor its bytes. if seen.contains(&key) || name_bytes.saturating_add(cost) > MAX_LAYOUT_NAME_BYTES { @@ -448,22 +196,11 @@ fn layouts(objects: &[Record<'_>], block_records: &HashMap, enti } seen.insert(key); name_bytes += cost; - paper.push((own.int_or(71, i64::MAX), LayoutDef { name: name.to_string(), block: Some(block.clone()) })); + paper.push((l.tab_order, LayoutDef { name: l.name, block: Some(block) })); } paper.sort_by_key(|(order, _)| *order); - if paper.is_empty() && groups(entities).any(in_paper_space) { + if paper.is_empty() && doc.entities.iter().any(EntityRecord::paper_space) { paper.push((1, LayoutDef { name: "Layout1".into(), block: Some(PAPER_BLOCK.into()) })); } std::iter::once(LayoutDef { name: MODEL.into(), block: None }).chain(paper.into_iter().map(|(_, l)| l)).collect() } - -#[cfg(test)] -mod tests { - use super::integer; - - #[test] - fn integer_rejects_fractional_float_values() { - assert_eq!(integer("1.0"), Some(1)); - assert_eq!(integer("1.9"), None); - } -} diff --git a/crates/cad/src/import/tests.rs b/crates/cad/src/import/tests.rs index d28a48553d..67ceef03a0 100644 --- a/crates/cad/src/import/tests.rs +++ b/crates/cad/src/import/tests.rs @@ -997,7 +997,12 @@ fn binary_dwg_damaged_and_foreign_files() { binary.extend([0u8; 40]); assert!(is_dxf(&binary)); let e = import(&binary, &ImportOptions::default()).unwrap_err(); - assert!(e.contains("binary DXF") && e.contains("ASCII"), "{e}"); + assert!(e.contains("binary DXF") && e.contains("damaged"), "{e}"); + // A binary DXF opens as its ASCII form does. + let ascii = entities(LINE); + let tags = craft_dxf::parse(&ascii).unwrap(); + let r = open(&craft_dxf::write_binary(&tags, true), &points()); + assert_eq!(leaves(&r.document).len(), 1); let e = import(b"AC1032\x00\x00\x00", &ImportOptions::default()).unwrap_err(); assert!(e.contains("DWG"), "{e}"); for junk in [&b""[..], b"hello", b"", b"999\nnote\n"] { @@ -1166,9 +1171,8 @@ fn many_array_inserts_of_a_missing_block_stay_bounded() { let one = [(0, "INSERT"), (8, "0"), (2, "NOPE"), (10, "0"), (20, "0"), (70, "100"), (71, "100"), (44, "1"), (45, "1")]; let e: Vec<(i32, &str)> = (0..3000).flat_map(|_| one).collect(); let bytes = entities(&e); - let text = reader::decode(&bytes); - let (pairs, _) = reader::pairs(&text).unwrap(); - let d = reader::Drawing::read(&pairs); + let tags = craft_dxf::parse(&bytes).unwrap(); + let d = reader::Drawing::read(craft_dxf::model::Document::read(&tags)); let model = d.layout("Model").or(d.layouts.first()).unwrap(); let mut conv = entity::Converter::default(); let items = conv.items(&d.layout_records(model)); diff --git a/crates/cad/src/lib.rs b/crates/cad/src/lib.rs index 1443829806..66a6a36baa 100644 --- a/crates/cad/src/lib.rs +++ b/crates/cad/src/lib.rs @@ -1,5 +1,5 @@ -//! CAD interchange: a hand-written ASCII DXF writer (versions R12 to 2018) and reader, and an -//! HP-GL/2 plot file reader and writer. +//! CAD interchange: a hand-written ASCII DXF writer (versions R12 to 2018) and a reader on +//! `craft_dxf::model`, and an HP-GL/2 plot file reader and writer. //! //! [`export`] writes the visible art of a document into one DXF drawing: each layer becomes a DXF //! layer (hidden ones switched off, locked ones locked, non-printing ones not plotted), paths @@ -11,7 +11,7 @@ //! What DXF can't hold (blending modes, opacity masks, raster effects, gradients, patterns, //! clipping) is approximated or left out, and each such loss comes back as a warning. //! -//! [`import()`] reads an ASCII DXF drawing (any version) into a document: see [`import`]. +//! [`import()`] reads a DXF drawing (ASCII or binary, any version) into a document: see [`import`]. //! [`hpgl::import`] reads an HP-GL plotter file, and [`hpgl::export`] writes one: see [`hpgl`]. //! //! - `aci`: the 256-colour index palette and the nearest index of a colour. diff --git a/crates/engine/src/cmd/addons/pathtools/tests.rs b/crates/engine/src/cmd/addons/pathtools/tests.rs index f98880e204..a72075d233 100644 --- a/crates/engine/src/cmd/addons/pathtools/tests.rs +++ b/crates/engine/src/cmd/addons/pathtools/tests.rs @@ -713,6 +713,71 @@ fn corner_commands_refuse_bad_params() { } } +#[test] +fn corner_commands_refuse_an_unknown_item_key() { + let mut s = session(); + let id = square(&mut s); + let i = id.0; + let set = json!({"items": [{"id": i, "anchor": [0]}], "radius": 5}); + let e = s.execute("addon.pathtools.cornerSet", &set).unwrap_err().to_string(); + assert!(e.contains("unknown parameter `items[0].anchor`; did you mean `items[0].anchors`?"), "{e}"); + let set_late = json!({"items": [{"id": i, "anchors": [0]}, {"id": i, "radius": 3}], "radius": 5}); + let e = s.execute("addon.pathtools.cornerSet", &set_late).unwrap_err().to_string(); + assert!(e.contains("unknown parameter `items[1].radius`; the command takes: items[1].id, items[1].anchors"), "{e}"); + refuses(&mut s, "addon.pathtools.cornerSet", &[set, set_late]); + s.execute("addon.pathtools.cornerSet", &json!({"radius": 10})).unwrap(); + let remove = json!({"items": [{"id": i, "anchor": [0]}]}); + let e = s.execute("addon.pathtools.cornerRemove", &remove).unwrap_err().to_string(); + assert!(e.contains("unknown parameter `items[0].anchor`; did you mean `items[0].anchors`?"), "{e}"); + refuses(&mut s, "addon.pathtools.cornerRemove", &[remove]); + assert_eq!(drawn(&s, id, 0), 10.0); +} + +#[test] +fn corner_items_take_their_documented_keys() { + let mut s = session(); + let id = square(&mut s); + let i = id.0; + let r = s.execute("addon.pathtools.cornerSet", &json!({"items": [{"id": i, "anchors": [0]}], "radius": 5})).unwrap(); + assert_eq!((r["corners"].clone(), drawn(&s, id, 0), drawn(&s, id, 1)), (json!(1), 5.0, 0.0)); + // A member without `anchors` takes the request's. + s.execute("addon.pathtools.cornerSet", &json!({"items": [{"id": i}], "anchors": [2], "radius": 6})).unwrap(); + assert_eq!(drawn(&s, id, 2), 6.0); + let r = s.execute("addon.pathtools.cornerRemove", &json!({"items": [{"id": i, "anchors": [0]}]})).unwrap(); + assert_eq!((r["corners"].clone(), drawn(&s, id, 0), drawn(&s, id, 2)), (json!(1), 0.0, 6.0)); + // A null `ids` beside `items` counts as not given. + s.execute("addon.pathtools.cornerRemove", &json!({"items": [{"id": i}], "ids": null})).unwrap(); + assert_eq!(drawn(&s, id, 2), 0.0); +} + +#[test] +fn corner_commands_refuse_items_with_ids() { + let mut s = session(); + let id = square(&mut s); + let other = line(&mut s, &[(350.0, 10.0), (390.0, 10.0), (390.0, 50.0)], false); + let both = json!({"items": [{"id": id.0, "anchors": [0]}], "ids": [other.0], "radius": 5}); + let e = s.execute("addon.pathtools.cornerSet", &both).unwrap_err().to_string(); + assert!(e.contains("give `items` or `ids`, not both"), "{e}"); + refuses(&mut s, "addon.pathtools.cornerSet", &[both]); + s.execute("addon.pathtools.cornerSet", &json!({"ids": [id.0], "radius": 5})).unwrap(); + let both = json!({"items": [{"id": id.0}], "ids": [id.0]}); + let e = s.execute("addon.pathtools.cornerRemove", &both).unwrap_err().to_string(); + assert!(e.contains("give `items` or `ids`, not both"), "{e}"); + refuses(&mut s, "addon.pathtools.cornerRemove", &[both]); +} + +#[test] +fn saved_corner_steps_with_older_item_keys_still_play() { + let mut s = session(); + let id = square(&mut s); + let other = line(&mut s, &[(350.0, 10.0), (390.0, 10.0), (390.0, 50.0)], false); + let saved = json!({"items": [{"id": id.0, "anchors": [0], "old": 1}], "ids": [other.0], "radius": 5}); + s.replay("addon.pathtools.cornerSet", &saved).unwrap(); + assert_eq!((drawn(&s, id, 0), drawn(&s, id, 1)), (5.0, 0.0)); + s.replay("addon.pathtools.cornerRemove", &json!({"items": [{"id": id.0, "old": 1}]})).unwrap(); + assert_eq!(drawn(&s, id, 0), 0.0); +} + /// A closed five-pointed star about (200, 150): its points at the even indices 0, 2… (the odd /// numbers counting from 1), its inner corners at the odd ones. fn star_path(s: &mut Session) -> NodeId { diff --git a/crates/engine/src/cmd/fileio/dxfimport.rs b/crates/engine/src/cmd/fileio/dxfimport.rs index 96fb715106..eef7aca4cd 100644 --- a/crates/engine/src/cmd/fileio/dxfimport.rs +++ b/crates/engine/src/cmd/fileio/dxfimport.rs @@ -16,7 +16,7 @@ pub fn specs() -> Vec { "DXF Info", [], None, - "{path} or {name?, dataBase64} what a DXF drawing holds → {version (2018, R12…), units (its drawing unit: Millimeters, Inches, Unitless…), layouts: [\"Model\", paper layouts…], layers: [name…], unit, scale (the default ratio: 1 unit = scale drawing units, the drawing at 1:1)}; a binary DXF or a DWG answers an error saying to save it as ASCII DXF", + "{path} or {name?, dataBase64} what a DXF drawing holds → {version (2018, R12…), units (its drawing unit: Millimeters, Inches, Unitless…), layouts: [\"Model\", paper layouts…], layers: [name…], unit, scale (the default ratio: 1 unit = scale drawing units, the drawing at 1:1)}; a DWG answers an error saying to save it as DXF", always, dxf_info )] diff --git a/crates/engine/src/cmd/fileio/tests_dxfimport.rs b/crates/engine/src/cmd/fileio/tests_dxfimport.rs index ec7b295c23..d3dcdcb86c 100644 --- a/crates/engine/src/cmd/fileio/tests_dxfimport.rs +++ b/crates/engine/src/cmd/fileio/tests_dxfimport.rs @@ -163,12 +163,12 @@ fn dxf_info_lists_layouts_layers_and_units() { } #[test] -fn binary_dxf_says_to_save_it_as_ascii() { +fn damaged_binary_dxf_says_so() { let mut s = Session::new(); let mut bytes = vectorcraft_cad::import::BINARY_SENTINEL.to_vec(); bytes.extend([0u8; 64]); let e = open(&mut s, &bytes, json!({})).unwrap_err().to_string(); - assert!(e.contains("binary DXF") && e.contains("ASCII"), "{e}"); + assert!(e.contains("binary DXF") && e.contains("damaged"), "{e}"); let e = s.execute("document.dxfInfo", &json!({"dataBase64": b64(&bytes)})).unwrap_err().to_string(); assert!(e.contains("binary DXF"), "{e}"); } diff --git a/crates/engine/src/cmd/params.rs b/crates/engine/src/cmd/params.rs index 20e5054aeb..fe8431a6c6 100644 --- a/crates/engine/src/cmd/params.rs +++ b/crates/engine/src/cmd/params.rs @@ -10,7 +10,7 @@ //! save or Export for Screens: those are checked against the options of the formats the command //! can write, in `marks`, `bleed` and the other objects too ([`check_export_options`]); and in the //! objects of an array whose keys `MEMBER_KEYS` lists, such as the `items` of -//! `object.setLiveShape`. +//! `object.setLiveShape` and `addon.pathtools.cornerSet`. //! //! [`Session::execute`] answers a key the description doesn't name with a parameter error //! ([`check_params`]), for every caller (the app, the control channel, MCP, the CLI) and for the @@ -256,6 +256,22 @@ pub fn check_keys(id: &str, doc: &'static str, params: &Value) -> Result<()> { } } +/// Parameters a command takes instead of one another: (command, key, other key). Giving both, +/// neither null, is a parameter error ([`check_exclusive_keys`]). +const EXCLUSIVE_KEYS: &[(&str, &str, &str)] = &[("addon.pathtools.cornerSet", "items", "ids"), ("addon.pathtools.cornerRemove", "items", "ids")]; + +/// `params` of command `id` give at most one of each pair in [`EXCLUSIVE_KEYS`], or the parameter +/// error naming the pair. +fn check_exclusive_keys(id: &str, params: &Value) -> Result<()> { + let given = |key: &str| params.get(key).filter(|v| !v.is_null()); + for (_, key, other) in EXCLUSIVE_KEYS.iter().filter(|(c, ..)| *c == id) { + if given(key).is_some() && given(other).is_some() { + return Err(bad(id, format!("give `{key}` or `{other}`, not both"))); + } + } + Ok(()) +} + /// The parameter error of command `id` for `key`, which isn't one of `keys`: with the nearest of /// them, or all of them. pub(crate) fn unknown(id: &str, key: &str, keys: &[&str]) -> crate::EngineError { @@ -273,7 +289,11 @@ pub(crate) fn unknown(id: &str, key: &str, keys: &[&str]) -> crate::EngineError /// Commands whose params hold an array of objects with keys of their own: the command, the key of /// the array and the keys each of its objects takes. -const MEMBER_KEYS: &[(&str, &str, &[&str])] = &[("object.setLiveShape", "items", &["id", "corners"])]; +const MEMBER_KEYS: &[(&str, &str, &[&str])] = &[ + ("object.setLiveShape", "items", &["id", "corners"]), + ("addon.pathtools.cornerSet", "items", &["id", "anchors"]), + ("addon.pathtools.cornerRemove", "items", &["id", "anchors"]), +]; /// Each object in the arrays [`MEMBER_KEYS`] names for command `id` has only the keys it lists, or /// the parameter error naming the first other one with its place (`items[0].corner`), and the @@ -848,9 +868,9 @@ fn check_export_options(id: &str, params: &Value) -> Result<()> { check_option_keys(id, "", given, &keys, why_not, &trees) } -/// [`check_keys`] for an engine command, the steps of a `command.batch` or an `action.batch` included, -/// [`check_effect_params`] for the effect `effect.apply` adds and [`check_export_options`] for an -/// export. A command the engine doesn't have passes: running it reports that. +/// [`check_keys`], [`check_exclusive_keys`] and [`check_member_keys`] for an engine command, the steps of a `command.batch` or an +/// `action.batch` included, [`check_effect_params`] for the effect `effect.apply` adds and +/// [`check_export_options`] for an export. A command the engine doesn't have passes: running it reports that. pub fn check_params(id: &str, params: &Value) -> Result<()> { check_params_in(id, params, false) } @@ -869,6 +889,7 @@ fn check_params_in(id: &str, params: &Value, in_batch: bool) -> Result<()> { return Ok(()); } check_keys(id, spec.params, params)?; + check_exclusive_keys(id, params)?; check_member_keys(id, params)?; if in_batch { crate::schemas::check(spec, params, false)?; diff --git a/crates/engine/src/cmd/textwrap.rs b/crates/engine/src/cmd/textwrap.rs index c7c9adb261..d5eefe9d4d 100644 --- a/crates/engine/src/cmd/textwrap.rs +++ b/crates/engine/src/cmd/textwrap.rs @@ -34,8 +34,12 @@ pub fn specs() -> Vec { ] } +/// The Offset a wrap object takes, in points. +pub const TEXT_WRAP_OFFSET_RANGE: std::ops::RangeInclusive = -1000.0..=1000.0; + fn wrap_param(p: &Value, base: TextWrap) -> TextWrap { - TextWrap { offset: f64_or(p, "offset", base.offset).clamp(-1000.0, 1000.0), invert: bool_or(p, "invert", base.invert) } + let (lo, hi) = (*TEXT_WRAP_OFFSET_RANGE.start(), *TEXT_WRAP_OFFSET_RANGE.end()); + TextWrap { offset: f64_or(p, "offset", base.offset).clamp(lo, hi), invert: bool_or(p, "invert", base.invert) } } fn make(s: &mut Session, p: &Value) -> Result { diff --git a/crates/engine/src/cmd/variablecmds.rs b/crates/engine/src/cmd/variablecmds.rs index 74c89d1089..9acd31e664 100644 --- a/crates/engine/src/cmd/variablecmds.rs +++ b/crates/engine/src/cmd/variablecmds.rs @@ -867,7 +867,7 @@ pub fn specs() -> Vec { "Import Data Sets…", ["Window", "Variables"], None, - "{path? | data? | dataBase64? | csv?} replace every dataset with the rows of a CSV, comma- or tab-separated, in UTF-16 with a byte-order mark, UTF-8 or else Windows-1252 (header: one variable name per column, whatever its case; one row per dataset, named Data Set 1, 2… in file order). The document's variables and their bindings stay. A header that names no variable defines one, unbound: `#Name` defines a visibility variable, `@Name` defines an image variable, and a header without a prefix defines a text variable. A prefixed header whose name is a variable of another kind, and a `%` header that isn't a variable's exact name (graph data files), are refused, and so are two headers that name one variable and a header that would define a variable while the variables are locked. An import that leaves the variables and data sets as they were adds no undo step → {imported, names, defined, deletedDataSets}", + "{path? | data? | dataBase64? | csv?} replace every dataset with the rows of a CSV, comma- or tab-separated, in UTF-16 (with a byte-order mark, or without one when at least half of its two-byte units hold a NUL byte and only one byte order reads a line break; any other file with NUL bytes is refused), UTF-8 or else Windows-1252 (header: one variable name per column, whatever its case; one row per dataset, named Data Set 1, 2… in file order). The document's variables and their bindings stay. A header that names no variable defines one, unbound: `#Name` defines a visibility variable, `@Name` defines an image variable, and a header without a prefix defines a text variable. A prefixed header whose name is a variable of another kind, and a `%` header that isn't a variable's exact name (graph data files), are refused, and so are two headers that name one variable and a header that would define a variable while the variables are locked. An import that leaves the variables and data sets as they were adds no undo step → {imported, names, defined, deletedDataSets}", has_doc, dataset_import ), diff --git a/crates/engine/src/cmd/variablecmds/csv.rs b/crates/engine/src/cmd/variablecmds/csv.rs index 31e46787f2..38dd42d922 100644 --- a/crates/engine/src/cmd/variablecmds/csv.rs +++ b/crates/engine/src/cmd/variablecmds/csv.rs @@ -32,20 +32,17 @@ fn datasets_csv_bytes(p: &Value, cmd: &str) -> Result<(Vec, bool)> { } /// The text of a datasets CSV given as a file or as `dataBase64`: UTF-16 after a UTF-16 -/// byte-order mark, else UTF-8, with or without a byte-order mark, else Windows-1252. A file -/// that starts with a byte-order mark must be valid in its encoding, and a file without one must -/// not hold NUL bytes (UTF-16 without a byte-order mark). +/// byte-order mark, else UTF-16 without one when the file holds NUL bytes (see +/// [`utf16_without_mark`]), else UTF-8, with or without a byte-order mark, else Windows-1252. A +/// file that starts with a byte-order mark must be valid in its encoding, and a file with NUL +/// bytes and no byte-order mark must read as UTF-16 by [`utf16_without_mark`]'s rule. fn datasets_csv_text(bytes: &[u8], cmd: &str) -> Result { - let utf16 = |rest: &[u8], le: bool| { - let (units, odd) = rest.as_chunks::<2>(); - let units = units.iter().map(|&c| if le { u16::from_le_bytes(c) } else { u16::from_be_bytes(c) }); - let text = char::decode_utf16(units).collect::>(); - text.ok().filter(|_| odd.is_empty()).ok_or_else(|| bad(cmd, "CSV is not UTF-16")) - }; match bytes { - [0xFF, 0xFE, rest @ ..] => return utf16(rest, true), - [0xFE, 0xFF, rest @ ..] => return utf16(rest, false), - _ if bytes.contains(&0) => return Err(bad(cmd, "CSV holds NUL bytes: save it as UTF-8, or as UTF-16 with a byte-order mark")), + [0xFF, 0xFE, rest @ ..] => return utf16(rest, true).ok_or_else(|| bad(cmd, "CSV is not UTF-16")), + [0xFE, 0xFF, rest @ ..] => return utf16(rest, false).ok_or_else(|| bad(cmd, "CSV is not UTF-16")), + _ if bytes.contains(&0) => { + return utf16_without_mark(bytes).ok_or_else(|| bad(cmd, "CSV holds NUL bytes: save it as UTF-8, or as UTF-16 with a byte-order mark")); + } _ => {} } match std::str::from_utf8(bytes) { @@ -55,6 +52,34 @@ fn datasets_csv_text(bytes: &[u8], cmd: &str) -> Result { } } +/// `bytes` as UTF-16, little-endian when `le` is set, or `None` when they aren't valid UTF-16. +fn utf16(bytes: &[u8], le: bool) -> Option { + let (units, odd) = bytes.as_chunks::<2>(); + let units = units.iter().map(|&c| if le { u16::from_le_bytes(c) } else { u16::from_be_bytes(c) }); + char::decode_utf16(units).collect::>().ok().filter(|_| odd.is_empty()) +} + +/// `bytes`, which hold NUL bytes and no byte-order mark, as UTF-16, or `None`. At least half of +/// the two-byte units must hold a NUL byte, as characters from U+0001 to U+00FF do; a file with +/// fewer, such as UTF-8 or Windows-1252 text with stray NUL bytes, is refused. The byte order is +/// the one that reads a line break (`\n` or `\r`). The other order reads one only from U+0A00 or +/// U+0D00, so a file that reads one in both orders is refused. A file that reads none in either +/// order has no data rows, and is read little-endian so that the import reports that. The text +/// must be valid UTF-16 in that order and hold no NUL character. +fn utf16_without_mark(bytes: &[u8]) -> Option { + let (units, odd) = bytes.as_chunks::<2>(); + if !odd.is_empty() || units.iter().filter(|c| c.contains(&0)).count() * 2 < units.len() { + return None; + } + let is_line_break = |u: u16| matches!(u, 0x0A | 0x0D); + let lines_le = units.iter().any(|&c| is_line_break(u16::from_le_bytes(c))); + let lines_be = units.iter().any(|&c| is_line_break(u16::from_be_bytes(c))); + if lines_le && lines_be { + return None; + } + utf16(bytes, !lines_be).filter(|text| !text.contains('\0')) +} + /// A row of a datasets CSV: the file line it starts on, its cells, and for each cell whether it was quoted. type CsvRow = (usize, Vec, Vec); diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index e3f2b91ee7..4b47966463 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -33,6 +33,7 @@ pub use cmd::params::{check_keys, check_params}; pub use cmd::pathops::auto_simplify_level; pub use cmd::rasterfx::{export_pdf, flatten_raster_effects}; pub use cmd::select::{path_fingerprint, storable_selection, stored_path_params, stored_path_step}; +pub use cmd::textwrap::TEXT_WRAP_OFFSET_RANGE; pub use cmd::{CommandInfo, CommandSpec, command_specs, find_command}; pub use cmd::{EyedropperOptions, PathfinderOptions}; pub use journal::Journal; diff --git a/crates/engine/src/tests/build.rs b/crates/engine/src/tests/build.rs index cb908efafd..1c3ad5d8b4 100644 --- a/crates/engine/src/tests/build.rs +++ b/crates/engine/src/tests/build.rs @@ -1748,6 +1748,203 @@ fn shape_builder_arrow_keys_pass_swatches_of_the_same_color() { assert_eq!(s.paint.fill, after, "the swatch after Twin B"); } +/// The colors of the cursor swatch preview's chips, left to right, and which one is ringed. +fn swatch_chips(s: &mut Session, v: ViewInfo) -> Vec<([u8; 4], bool)> { + let mut chips: Vec<(f64, [u8; 4], bool)> = s + .overlays(v) + .into_iter() + .filter_map(|o| match o { + vectorcraft_tools::Overlay::Swatch { p, color, selected } => Some((p.x, color, selected)), + _ => None, + }) + .collect(); + chips.sort_by(|a, b| a.0.total_cmp(&b.0)); + chips.into_iter().map(|(_, c, sel)| (c, sel)).collect() +} + +/// A solid paint's color as the chips draw it. +fn chip_color(p: &Paint) -> [u8; 4] { + match p { + Paint::Solid { color, .. } => color.to_rgba8(1.0), + _ => panic!("not a solid color: {p:?}"), + } +} + +/// Live Paint Bucket: Left and Right step the active paint through the document's color swatches +/// (the selected art keeps its paint), the Cursor Swatch Preview (on at first) shows the active +/// paint ringed between the swatches before and after it, and with it off the arrows still step. +#[test] +fn live_paint_bucket_arrow_keys_step_the_active_paint_through_the_swatches() { + let mut s = session(); + let (a, _) = two(&mut s); + let v = ViewInfo::default(); + s.select_tool("livePaintBucket", v).unwrap(); + assert_eq!(s.tool_options_of("livePaintBucket")["cursorSwatchPreview"], json!(true)); + assert!(s.tool_claims_key(ToolKey::Right, v) && s.tool_claims_key(ToolKey::Left, v)); + assert!(!s.tool_claims_key(ToolKey::Up, v), "Up and Down keep their own use"); + let list: Vec<(String, Paint)> = + vectorcraft_tools::builder::color_swatches(&s.doc().unwrap().doc).iter().map(|sw| (sw.name.clone(), sw.paint.clone())).collect(); + assert!(list.len() >= 4); + let n = list.len(); + let stroke = s.paint.stroke.clone(); + s.execute("paint.setFill", &json!({"swatch": list[0].0, "ids": []})).unwrap(); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, list[2].1); + s.tool_key(ToolKey::Left, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, list[1].1); + assert_eq!(s.paint.stroke, stroke, "the stroke stays"); + assert_eq!(node(&s, a).appearance.fill_paint(), Paint::solid(Color::rgb(1.0, 0.0, 0.0)), "A keeps its fill"); + s.pointer(&PointerEvent::new(PointerKind::Move, 300.0, 300.0), v).unwrap(); + assert_eq!(swatch_chips(&mut s, v), vec![(chip_color(&list[0].1), false), (chip_color(&list[1].1), true), (chip_color(&list[2].1), false)]); + let alt = Mods { alt: true, ..Default::default() }; + s.pointer(&PointerEvent::new(PointerKind::Move, 300.0, 300.0).with_mods(alt), v).unwrap(); + assert!(swatch_chips(&mut s, v).is_empty(), "Alt samples with the eyedropper and shows no chips"); + s.pointer(&PointerEvent::new(PointerKind::Move, 300.0, 300.0), v).unwrap(); + // Past the first swatch, Left wraps around to the last. + s.tool_key(ToolKey::Left, Mods::default(), v).unwrap(); + s.tool_key(ToolKey::Left, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, list[n - 1].1); + assert_eq!(swatch_chips(&mut s, v).iter().map(|c| c.0).collect::>(), [&list[n - 2].1, &list[n - 1].1, &list[0].1].map(chip_color)); + // With the Stroke proxy in front, the arrows step the stroke and the chips show it. + s.execute("paint.toggleActive", &json!({"fill": false})).unwrap(); + let fill = s.paint.fill.clone(); + s.execute("paint.setStroke", &json!({"swatch": list[1].0, "ids": []})).unwrap(); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!((&s.paint.fill, &s.paint.stroke), (&fill, &list[2].1)); + assert!(!s.fill_active, "the Stroke proxy stays in front"); + assert_eq!(swatch_chips(&mut s, v)[1], (chip_color(&list[2].1), true)); + assert_eq!(node(&s, a).appearance.fill_paint(), Paint::solid(Color::rgb(1.0, 0.0, 0.0)), "A keeps its paint"); + // Cursor Swatch Preview off hides the chips; the arrows still step. + s.set_tool_option_cmd(&json!({"tool": "livePaintBucket", "values": {"cursorSwatchPreview": false}})).unwrap(); + assert!(swatch_chips(&mut s, v).is_empty()); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.stroke, list[3].1); +} + +/// The Live Paint Bucket and the Shape Builder take Left and Right for swatches only without +/// modifiers: Shift, Alt and Cmd/Ctrl arrows are left to their shortcuts and change no paint. +#[test] +fn swatch_arrow_keys_leave_modified_arrows_to_the_shortcuts() { + let mut s = session(); + two(&mut s); + let v = ViewInfo::default(); + let first = vectorcraft_tools::builder::color_swatches(&s.doc().unwrap().doc)[0].name.clone(); + s.execute("paint.setFill", &json!({"swatch": first, "ids": []})).unwrap(); + for tool in ["livePaintBucket", "shapeBuilder"] { + s.select_tool(tool, v).unwrap(); + if tool == "shapeBuilder" { + s.set_tool_option_cmd(&json!({"tool": tool, "values": {"pickColorFrom": "swatches"}})).unwrap(); + } + let fill = s.paint.fill.clone(); + assert!(s.tool_claims_key_with(ToolKey::Right, Mods::default(), v), "{tool}"); + for m in [Mods { shift: true, ..Default::default() }, Mods { alt: true, ..Default::default() }, Mods { cmd: true, ..Default::default() }] { + for key in [ToolKey::Left, ToolKey::Right] { + assert!(!s.tool_claims_key_with(key, m, v), "{tool} {key:?} {m:?}"); + s.tool_key(key, m, v).unwrap(); + assert_eq!(s.paint.fill, fill, "{tool} {key:?} {m:?}"); + } + } + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_ne!(s.paint.fill, fill, "{tool}: a plain Right steps"); + } +} + +/// Two swatches of the same color: the Bucket's arrows step through both, and the fill and the +/// stroke each step on from the swatch picked for them. +#[test] +fn live_paint_bucket_arrow_keys_pass_swatches_of_the_same_color_for_fill_and_stroke() { + let mut s = session(); + two(&mut s); + for name in ["Twin A", "Twin B"] { + s.execute("swatch.new", &json!({"name": name, "color": "#123456"})).unwrap(); + } + let v = ViewInfo::default(); + s.select_tool("livePaintBucket", v).unwrap(); + let names: Vec = vectorcraft_tools::builder::color_swatches(&s.doc().unwrap().doc).iter().map(|sw| sw.name.clone()).collect(); + let a = names.iter().position(|n| n == "Twin A").unwrap(); + assert_eq!(names[a + 1], "Twin B"); + let after = vectorcraft_tools::builder::color_swatches(&s.doc().unwrap().doc)[(a + 2) % names.len()].paint.clone(); + // The fill goes to Twin B. + s.execute("paint.setFill", &json!({"swatch": "Twin A", "ids": []})).unwrap(); + let twin = s.paint.fill.clone(); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, twin, "Twin B"); + // The stroke starts at Twin A: Right goes to Twin B, then past it. + s.execute("paint.setStroke", &json!({"swatch": "Twin A", "ids": []})).unwrap(); + assert!(!s.fill_active); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.stroke, twin, "Twin B for the stroke"); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.stroke, after, "the swatch after Twin B"); + // Back on the fill, which is still Twin B: Right goes past it. + s.execute("paint.toggleActive", &json!({"fill": true})).unwrap(); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, after, "the fill steps on from Twin B"); +} + +/// A color that is no swatch shows alone and Right picks the first swatch, Left the last; a paint +/// that is not a solid color shows no chip; one swatch steps to itself; with no color swatch the +/// tool leaves the arrows alone; during a fill drag the arrows change nothing. +#[test] +fn live_paint_bucket_arrow_keys_handle_unmatched_paint_few_swatches_and_drags() { + let mut s = session(); + live(&mut s); + let v = ViewInfo::default(); + s.select_tool("livePaintBucket", v).unwrap(); + s.pointer(&PointerEvent::new(PointerKind::Move, 300.0, 300.0), v).unwrap(); + let list: Vec = vectorcraft_tools::builder::color_swatches(&s.doc().unwrap().doc).iter().map(|sw| sw.paint.clone()).collect(); + let odd = Paint::solid(Color::rgb8(0x12, 0x34, 0x57)); + assert!(!list.contains(&odd)); + s.paint.fill = odd.clone(); + assert_eq!(swatch_chips(&mut s, v), vec![(chip_color(&odd), true)]); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, list[0]); + s.paint.fill = odd.clone(); + s.tool_key(ToolKey::Left, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, list[list.len() - 1]); + s.paint.fill = Paint::None; + assert!(swatch_chips(&mut s, v).is_empty()); + + // During a fill drag the arrows are not taken and change nothing. + s.paint.fill = list[0].clone(); + s.pointer(&PointerEvent::new(PointerKind::Down, 25.0, 50.0), v).unwrap(); + assert!(s.tool_busy()); + assert!(!s.tool_claims_key(ToolKey::Right, v)); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, list[0]); + assert!(swatch_chips(&mut s, v).is_empty(), "no chips during a drag"); + s.pointer(&PointerEvent::new(PointerKind::Up, 25.0, 50.0), v).unwrap(); + + // One color swatch: both arrows pick it, and it stands on both sides of itself. + let one = list[0].clone(); + s.edit("t", |d, _| { + d.swatch_groups.clear(); + d.swatches.retain(|sw| sw.paint == one); + d.swatches.truncate(1); + Ok(()) + }) + .unwrap(); + assert_eq!(vectorcraft_tools::builder::color_swatches(&s.doc().unwrap().doc).len(), 1); + s.paint.fill = odd; + s.tool_key(ToolKey::Left, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, one); + s.pointer(&PointerEvent::new(PointerKind::Move, 301.0, 300.0), v).unwrap(); + assert_eq!(swatch_chips(&mut s, v), vec![(chip_color(&one), false), (chip_color(&one), true), (chip_color(&one), false)]); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, one); + + // No color swatch: the arrows are left to the canvas and the paint stays. + s.edit("t", |d, _| { + d.swatches.clear(); + Ok(()) + }) + .unwrap(); + assert!(!s.tool_claims_key(ToolKey::Right, v) && !s.tool_claims_key(ToolKey::Left, v)); + s.tool_key(ToolKey::Right, Mods::default(), v).unwrap(); + assert_eq!(s.paint.fill, one); +} + #[test] fn shape_builder_tool_alt_deletes_line_pieces() { let mut s = session(); @@ -3284,9 +3481,10 @@ fn live_paint_tool_options_refuse_invalid_values_and_change_nothing() { let colors = [json!(3), json!("nope"), json!("#12345"), json!("#00ff0080"), json!("00ff0080"), json!("#0f08"), json!(null)]; let widths = [json!("wide"), json!(null), json!(true)]; let switches = [json!("true"), json!(null), json!(1)]; - for (tool, keys) in - [("livePaintBucket", &["paintFills", "paintStrokes", "highlight"][..]), ("livePaintSelection", &["selectFills", "selectStrokes"][..])] - { + for (tool, keys) in [ + ("livePaintBucket", &["paintFills", "paintStrokes", "cursorSwatchPreview", "highlight"][..]), + ("livePaintSelection", &["selectFills", "selectStrokes"][..]), + ] { let mut bad: Vec<(&str, Value)> = keys.iter().flat_map(|k| switches.iter().map(move |v| (*k, v.clone()))).collect(); bad.extend(colors.iter().map(|v| ("color", v.clone()))); bad.extend(widths.iter().map(|v| ("width", v.clone()))); diff --git a/crates/engine/src/tests/variables.rs b/crates/engine/src/tests/variables.rs index 08ba426ef1..eea8ae4986 100644 --- a/crates/engine/src/tests/variables.rs +++ b/crates/engine/src/tests/variables.rs @@ -2137,8 +2137,9 @@ fn datasets_csv_reads_windows_1252_files() { } /// A CSV that starts with a UTF-16 byte-order mark is read as UTF-16, and -/// one that isn't valid UTF-16 is refused. A file with NUL bytes and no byte-order mark is refused. -/// A text value holding NUL imports back from the `csv` that `dataset.export` returns. +/// one that isn't valid UTF-16 is refused. A file with NUL bytes and no byte-order mark that isn't +/// UTF-16 is refused. A text value holding NUL imports back from the `csv` that `dataset.export` +/// returns. #[test] fn datasets_csv_reads_utf16_files() { let mut s = session(); @@ -2160,7 +2161,7 @@ fn datasets_csv_reads_utf16_files() { assert!(e.contains("CSV is not UTF-16"), "{e}"); let e = import(&mut s, &[b"\xff\xfe".as_slice(), "City\nAB,".as_bytes(), b"\x00\xd8"].concat()).unwrap_err().to_string(); assert!(e.contains("CSV is not UTF-16"), "{e}"); - let e = import(&mut s, &utf16(b"", "City\nx\n", true)).unwrap_err().to_string(); + let e = import(&mut s, b"City\nx\0\n").unwrap_err().to_string(); assert!(e.contains("CSV holds NUL bytes"), "{e}"); assert_eq!(value(&s, "Data Set 1"), text_value("José"), "a refused file changes nothing"); s.execute("dataset.set", &json!({"name": "Data Set 1", "values": {"City": "a\u{0}b"}})).unwrap(); @@ -2170,6 +2171,63 @@ fn datasets_csv_reads_utf16_files() { assert_eq!(value(&s, "Data Set 1"), text_value("a\u{0}b")); } +/// A CSV in UTF-16 without a byte-order mark, with a NUL byte in at least half of its units, is +/// read in the byte order that reads a line break: in either order, with characters whose bytes +/// read as a line break, a quote or NUL, and when its bytes are also valid UTF-8. Files with fewer +/// NUL bytes, that read a line break in both orders, that aren't valid UTF-16 in it, that hold a +/// NUL character or that have an odd length are refused. +#[test] +fn datasets_csv_reads_utf16_files_without_a_byte_order_mark() { + let mut s = session(); + s.execute("variable.define", &json!({"name": "City", "kind": "text"})).unwrap(); + let import = |s: &mut Session, bytes: &[u8]| s.execute("dataset.import", &json!({"dataBase64": vectorcraft_format::base64_encode(bytes)})); + let value = |s: &Session, name: &str| s.doc().unwrap().doc.variables.dataset(name).and_then(|d| d.values.get("City")).cloned(); + let text_value = |v: &str| Some(vectorcraft_doc::DataValue::Text(v.into())); + let utf16 = |text: &str, le: bool| -> Vec { text.encode_utf16().flat_map(|u| if le { u.to_le_bytes() } else { u.to_be_bytes() }).collect() }; + import(&mut s, &utf16("City\r\nParis\r\n", true)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("Paris")); + import(&mut s, &utf16("City\nZoë 😀\n", false)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("Zoë 😀")); + // U+4E00's low byte is NUL, U+010A holds a `\n` byte and U+2200 a `"` byte; all three files + // are valid UTF-8 too. + import(&mut s, &utf16("City\n一\n", true)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("一")); + import(&mut s, &utf16("City\nĊ\n", true)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("Ċ")); + import(&mut s, &utf16("City\n∀∀∀\n", true)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("∀∀∀")); + // A file with no line break has no data rows in either byte order. + for bytes in [utf16("City", true), utf16("City", false), b"\0aa\0".to_vec()] { + let e = import(&mut s, &bytes).unwrap_err().to_string(); + assert!(e.contains("CSV has a header but no data rows"), "{e}"); + } + import(&mut s, &utf16("City\tName\n一二三丁目\tKai\n", true)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("一二三丁目")); + // Most units hold their NUL byte where a big-endian file would (U+4E00); the line breaks + // give the byte order. + import(&mut s, &utf16("City\n一一一一一一一一一一二\n", true)).unwrap(); + assert_eq!(value(&s, "Data Set 1"), text_value("一一一一一一一一一一二")); + // Windows-1252 and UTF-8 text with stray NUL bytes (the first with `\n\0` units), UTF-16 with + // fewer than half of its units holding a NUL byte, and, last, two files that read a line break + // in both byte orders (U+0D00 reads as `\r` and U+0A00 as `\n` big-endian). + let refused: [&[u8]; 9] = [ + b"Caf\xe9\n\0Lyon\n\0", + b"Cit\0\n", + b"City\nx\0\n", + &utf16("City\n丁丁丁丁丁丁丁丁丁丁\n", true), + &utf16("City\na\u{0}\n", true), + &[utf16("City\n", true), vec![0x00, 0xD8], utf16("\n", true)].concat(), + &[utf16("City\n", false), vec![0xDC, 0x00], utf16("\n", false)].concat(), + &utf16("City\n\u{0D00}\u{0D00}\u{0D00}\n", true), + &utf16("City\u{0A00}\nParis\n", true), + ]; + for bytes in refused { + let e = import(&mut s, bytes).unwrap_err().to_string(); + assert!(e.contains("CSV holds NUL bytes"), "{bytes:?}: {e}"); + } + assert_eq!(value(&s, "Data Set 1"), text_value("一一一一一一一一一一二"), "a refused file changes nothing"); +} + /// A data set of [`library`]: its name, and each variable's name with its paragraphs. type LibrarySet<'a> = (&'a str, &'a [(&'a str, &'a [&'a str])]); diff --git a/crates/engine/src/tooling.rs b/crates/engine/src/tooling.rs index 4dedfe7b28..bb29b06e75 100644 --- a/crates/engine/src/tooling.rs +++ b/crates/engine/src/tooling.rs @@ -1164,6 +1164,12 @@ impl Session { self.plane_key(key).is_some() || self.with_tool_cx(view, |t, cx| t.claims_key(cx, key)) } + /// Does the active tool take `key`, pressed with `mods` held, ahead of the shortcuts bound to it + /// (see `Tool::claims_key_with`)? + pub fn tool_claims_key_with(&mut self, key: ToolKey, mods: Mods, view: ViewInfo) -> bool { + self.plane_key(key).is_some() || self.with_tool_cx(view, |t, cx| t.claims_key_with(cx, key, mods)) + } + /// Has the active tool started something that Escape ends while no button is pressed (see /// `Tool::ends_on_escape`)? pub fn tool_ends_on_escape(&mut self, view: ViewInfo) -> bool { diff --git a/crates/eps/Cargo.toml b/crates/eps/Cargo.toml index 13c1c76ada..bd173588aa 100644 --- a/crates/eps/Cargo.toml +++ b/crates/eps/Cargo.toml @@ -9,6 +9,7 @@ description = "VectorCraft Encapsulated PostScript: a hand-written EPS writer (P workspace = true [dependencies] +craft-eps = { workspace = true } vectorcraft-geom = { workspace = true } vectorcraft-color = { workspace = true } vectorcraft-doc = { workspace = true } diff --git a/crates/eps/src/ai_editing/tests.rs b/crates/eps/src/ai_editing/tests.rs index 3af515181c..967c982ad4 100644 --- a/crates/eps/src/ai_editing/tests.rs +++ b/crates/eps/src/ai_editing/tests.rs @@ -7582,9 +7582,10 @@ fn a_linked_object_past_the_object_limit_warns_that_its_link_is_left_out() { } /// A link to a graphic style with Twist is kept where the reader reads Twist: on a curve, a curved -/// compound path or a group with nothing stroked up to a quarter turn, and on a path with straight -/// segments at any angle. A stroked curve, a group with a stroked member or a guide, or a curve, -/// compound path or group twisted further, is written without the link and warns. +/// compound path or a group with nothing stroked up to a quarter turn, and on a path or compound path +/// with straight segments up to half a turn. A stroked curve, a group with a stroked member or a +/// guide, a straight compound path with a guide member that reaches past its other members, or an +/// object twisted further, is written without the link and warns. #[test] fn a_link_to_a_twist_style_is_kept_where_the_reader_reads_it() { // A document with the object `make` builds from its appearance, `ap` with Twist at `angle`, @@ -7619,6 +7620,17 @@ fn a_link_to_a_twist_style_is_kept_where_the_reader_reads_it() { n.appearance = ap.into(); n }; + // A compound path of a square and a guide, a rectangle with corners `a` and `b`. + let guided = |a: (f64, f64), b: (f64, f64)| { + move |doc: &mut Document, ap: Appearance| { + let outer = Node::path(doc.alloc_id(), square(), Appearance::default()); + let path = shapes::rectangle(Rect::new(a.0, a.1, b.0, b.1)); + let guide = Node::new(doc.alloc_id(), NodeKind::Path { path, rule: FillRule::NonZero, live: None, clipping: false, guide: true }); + let mut n = Node::new(doc.alloc_id(), NodeKind::Compound { children: vec![Arc::new(outer), Arc::new(guide)], rule: FillRule::NonZero }); + n.appearance = ap.into(); + n + } + }; // A group of a filled square and `second`. let group = |second: fn(&mut Document) -> Node| { move |doc: &mut Document, ap: Appearance| { @@ -7649,6 +7661,8 @@ fn a_link_to_a_twist_style_is_kept_where_the_reader_reads_it() { ("a square twisted three quarters of a turn back", twisted(-270.0, filled(), path(square())), false), ("a straight compound path twisted half a turn", twisted(180.0, filled(), frame), true), ("a straight compound path twisted a full turn", twisted(360.0, filled(), frame), false), + ("a straight compound path with a guide inside it", twisted(45.0, filled(), guided((30.0, 20.0), (70.0, 50.0))), true), + ("a straight compound path with a guide reaching past it", twisted(45.0, filled(), guided((30.0, 20.0), (120.0, 50.0))), false), ("a curve twisted past a quarter turn", twisted(120.0, filled(), path(oval())), false), ("a stroked curve", twisted(45.0, Appearance::basic(black_fill(), red.clone(), 2.0), path(oval())), false), ("a curved compound path", twisted(-60.0, filled(), ring), true), diff --git a/crates/eps/src/import/ai/read/ops.rs b/crates/eps/src/import/ai/read/ops.rs index 1bc5d036b5..ef19456f54 100644 --- a/crates/eps/src/import/ai/read/ops.rs +++ b/crates/eps/src/import/ai/read/ops.rs @@ -1103,6 +1103,15 @@ fn no_guides(n: &Node, depth: usize) -> bool { depth <= MAX_DEPTH && !n.is_guide() && n.children().into_iter().flatten().all(|c| no_guides(c, depth + 1)) } +/// Is `n` a compound path with a guide member whose bounds reach past the bounds of its members that +/// aren't guides, or with guide members only? Any other object counts as no. +fn guides_reach_past(n: &Node) -> bool { + let NodeKind::Compound { children, .. } = &n.kind else { return false }; + let bounds = + |guides: bool| children.iter().filter(|c| c.is_guide() == guides).fold(None, |acc, c| vectorcraft_geom::union_opt(acc, c.geometric_bounds())); + bounds(true).is_some_and(|g| bounds(false).is_none_or(|o| o.union(g) != o)) +} + /// The largest Twist angle, in degrees either way, read as a live effect on an object that isn't a /// path or compound path with straight segments: VectorCraft's own limit. An object with a larger /// Twist keeps the file's drawn look. @@ -1116,7 +1125,8 @@ const MAX_STRAIGHT_TWIST: f64 = 180.0; /// Is `object` one that style `st`, whose effect moves the outline, is read on? It and everything /// in it [`moves_alike`], and the style paints no gradient. Twist is read only when nothing is /// stroked and its angle is a number: up to [`MAX_STRAIGHT_TWIST`] degrees either way on a path or -/// compound path with straight segments, or up to [`MAX_TWIST`] degrees either way on another object +/// compound path with straight segments (only at 0° when its guide members reach past its other +/// members, see [`guides_reach_past`]), or up to [`MAX_TWIST`] degrees either way on another object /// with no guide in it. Transform that scales, turns or reflects is read only when nothing is stroked /// (its reference point lies on the bounds without strokes). fn moves_with(object: &Node, st: &crate::import::ai::style::ArtStyle) -> bool { @@ -1129,7 +1139,12 @@ fn moves_with(object: &Node, st: &crate::import::ai::style::ArtStyle) -> bool { && st.effects.iter().all(|e| match e.id.as_str() { "distort.twist" => { let within = |limit: f64| e.params["angle"].as_f64().is_some_and(|a| a.abs() <= limit); - !stroked && if straight(object) { within(MAX_STRAIGHT_TWIST) } else { no_guides(object, 0) && within(MAX_TWIST) } + !stroked + && if straight(object) { + within(MAX_STRAIGHT_TWIST) && (e.params["angle"].as_f64() == Some(0.0) || !guides_reach_past(object)) + } else { + no_guides(object, 0) && within(MAX_TWIST) + } } "distort.transform" => { let p = &e.params; diff --git a/crates/eps/src/import/ai/tests.rs b/crates/eps/src/import/ai/tests.rs index 1b9cc54ea5..ad88ecbef8 100644 --- a/crates/eps/src/import/ai/tests.rs +++ b/crates/eps/src/import/ai/tests.rs @@ -7296,7 +7296,11 @@ fn twist_is_read_on_curves_compound_paths_and_groups_with_nothing_stroked_up_to_ ("a twisted group", read(&twist(90.0, None), &distort_group()), 2), ("a group with a hidden member", read(&twist(45.0, None), &hidden_member), 2), ("a curve twisted a quarter turn back", read(&twist(-90.0, BLUE_FILL), &curved), 0), - ("a straight compound path with a guide, as before", read(&twist(45.0, BLUE_FILL), &with_guide(&rect_path(20.0, 20.0, 60.0, 50.0))), 2), + ( + "a straight compound path with a guide inside it, as before", + read(&twist(45.0, BLUE_FILL), &with_guide(&rect_path(0.0, 0.0, 60.0, 50.0))), + 2, + ), ] { assert!(!r.warnings.iter().any(|w| w.contains("drawn look")), "{what}: {:?}", r.warnings); let a = art(&r.doc); @@ -7363,6 +7367,48 @@ fn twist_is_read_on_straight_paths_and_compound_paths_up_to_half_a_turn() { } } +#[test] +fn twist_on_a_straight_compound_path_keeps_the_drawn_look_where_a_guide_reaches_past_its_other_members() { + // GUARDS: a straight compound path whose guide members reach past its other members was read + // with a live Twist measured from bounds that take in those guides, which draws differently from + // the art saved with it. + // The object, `hidden` painted with its style, under its drawn look. + let object = |hidden: &str| { + format!("0 Ae\nu\n{RED}{}f\nU\n%_Bb\n%_{}0 BB\n1 (Bent) XW\n", rect_path(16.0, 16.0, 64.0, 54.0), hidden.replace('\n', "\n%_")) + }; + // A compound path of a square and the guide from `from` to `to`. + let with_guide = |from: (f64, f64), to: (f64, f64)| { + object(&format!("*u\n{}f\n{} {} m\n{} {} L\n(N) *\n*U\n", rect_path(20.0, 20.0, 60.0, 50.0), from.0, from.1, to.0, to.1)) + }; + let twist = |angle: f64| distort_styles("Adobe Twirl", &format!("{angle} /Real (angle) ,\n"), BLUE_FILL); + let read = |angle: f64, art_: &str| read_ok(&format!("{}{}", twist(angle), layer(art_))); + for (what, r) in [ + ("a guide inside the square", read(45.0, &with_guide((25.0, 25.0), (35.0, 35.0)))), + ("a guide on the square's corners", read(180.0, &with_guide((20.0, 20.0), (60.0, 50.0)))), + ("a guide inside the square, half a turn back", read(-180.0, &with_guide((30.0, 40.0), (50.0, 30.0)))), + ("a guide outside the square, not turned", read(0.0, &with_guide((5.0, 0.0), (15.0, 10.0)))), + ] { + assert!(!r.warnings.iter().any(|w| w.contains("drawn look")), "{what}: {:?}", r.warnings); + let a = art(&r.doc); + assert_eq!(a.len(), 1, "{what}: {a:#?}"); + assert_eq!(a[0].children().map_or(0, |c| c.len()), 2, "{what}: the object, not its look: {a:#?}"); + let [e] = a[0].appearance.effects.as_slice() else { panic!("{what}: {:?}", a[0].appearance) }; + assert_eq!(e.id, "distort.twist", "{what}"); + } + for (what, r) in [ + ("a guide outside the square", read(45.0, &with_guide((5.0, 0.0), (15.0, 10.0)))), + ("a guide reaching past the square's right side", read(45.0, &with_guide((30.0, 30.0), (70.0, 40.0)))), + ("a guide reaching past the square's top, half a turn", read(180.0, &with_guide((30.0, 30.0), (40.0, 51.0)))), + ("a guide around the square, a quarter turn back", read(-90.0, &with_guide((0.0, 0.0), (80.0, 70.0)))), + ("a compound path of guides only", read(45.0, &object("*u\n25 25 m\n35 35 L\n(N) *\n40 25 m\n50 35 L\n(N) *\n*U\n"))), + ] { + let a = art(&r.doc); + assert_eq!(a.len(), 1, "{what}: {a:#?}"); + assert!(a[0].appearance.effects.is_empty(), "{what}: the drawn look: {a:#?}"); + assert!(r.warnings.iter().any(|w| w.contains("drawn look")), "{what}: {:?}", r.warnings); + } +} + #[test] fn a_bare_comment_line_in_a_prolog_leaves_its_end_alone() { // GUARDS: a bare `%` line's empty marker matched the empty begin marker of a section that has none. diff --git a/crates/eps/src/lib.rs b/crates/eps/src/lib.rs index 44ec49c190..49b64f4bce 100644 --- a/crates/eps/src/lib.rs +++ b/crates/eps/src/lib.rs @@ -352,64 +352,23 @@ fn read_data(ps: &[u8], name: &str) -> Option> { None } -/// The magic number of an EPS file with a binary header (a preview). -const DOS_MAGIC: [u8; 4] = [0xC5, 0xD0, 0xD3, 0xC6]; -/// The binary header's size. -const DOS_HEADER: usize = 30; +pub use craft_eps::{DOS_HEADER, DOS_MAGIC, Sections, is_eps}; /// `ps` behind a binary header, followed by the TIFF preview `tiff`. fn dos_eps(ps: &[u8], tiff: &[u8]) -> Result, String> { - let big = || "the file is too large for an EPS preview header (4 GB): choose no preview".to_string(); - let ps_len = u32::try_from(ps.len()).map_err(|_| big())?; - let tiff_at = u32::try_from(DOS_HEADER + ps.len()).map_err(|_| big())?; - let tiff_len = u32::try_from(tiff.len()).map_err(|_| big())?; - tiff_at.checked_add(tiff_len).ok_or_else(big)?; - let mut out = Vec::with_capacity(DOS_HEADER + ps.len() + tiff.len()); - out.extend(DOS_MAGIC); - out.extend((DOS_HEADER as u32).to_le_bytes()); - out.extend(ps_len.to_le_bytes()); - // No metafile preview. - out.extend(0u32.to_le_bytes()); - out.extend(0u32.to_le_bytes()); - out.extend(tiff_at.to_le_bytes()); - out.extend(tiff_len.to_le_bytes()); - // No checksum. - out.extend(0xFFFFu16.to_le_bytes()); - out.extend(ps); - out.extend(tiff); - Ok(out) + craft_eps::wrap(ps, Some(tiff), None).map_err(|e| e.to_string()) } /// The sections of an EPS file: its PostScript and its TIFF preview (binary header), or the whole /// file as PostScript. `None` when a binary header points outside the file. pub fn sections(bytes: &[u8]) -> Option<(&[u8], Option<&[u8]>)> { - if !bytes.starts_with(&DOS_MAGIC) { - return Some((bytes, None)); - } - let word = |at: usize| bytes.get(at..at + 4).and_then(|b| <[u8; 4]>::try_from(b).ok()).map(|b| u32::from_le_bytes(b) as usize); - let part = |at: usize| { - let (start, len) = (word(at)?, word(at + 4)?); - bytes.get(start..start.checked_add(len)?) - }; - let ps = part(4)?; - let tiff = match word(24) { - Some(0) | None => None, - Some(_) => Some(part(20)?), - }; - Some((ps, tiff)) + let s = craft_eps::sections(bytes).ok()?; + Some((s.postscript, s.tiff)) } /// The Windows metafile preview behind an EPS file's binary header, if it has one. pub fn metafile_preview(bytes: &[u8]) -> Option<&[u8]> { - if !bytes.starts_with(&DOS_MAGIC) { - return None; - } - let word = |at: usize| bytes.get(at..at + 4).and_then(|b| <[u8; 4]>::try_from(b).ok()).map(|b| u32::from_le_bytes(b) as usize); - let (start, len) = (word(12)?, word(16)?); - if start == 0 || len == 0 { - return None; - } - bytes.get(start..start.checked_add(len)?) + craft_eps::sections(bytes).ok()?.metafile } /// The native document an EPS file written by [`export`] carries, if any. diff --git a/crates/eps/src/ps.rs b/crates/eps/src/ps.rs index 88da08551e..2a10b8a86c 100644 --- a/crates/eps/src/ps.rs +++ b/crates/eps/src/ps.rs @@ -21,9 +21,6 @@ VCdict begin end "; -/// Longest line of encoded data (DSC readers take up to 255 characters). -const LINE: usize = 76; - /// `v` as PostScript writes it: at most four decimals, no trailing zeros (0 when not finite). pub(crate) fn num(v: f64) -> String { let mut s = String::new(); @@ -180,54 +177,7 @@ pub(crate) fn clip_op(rule: FillRule) -> &'static str { /// `bytes` in ASCII85 with its `~>` end, in lines of about [`LINE`] characters, none starting /// with `%` (DSC readers would take it for a comment). -pub(crate) fn ascii85(bytes: &[u8]) -> String { - let mut raw = String::with_capacity(bytes.len() * 5 / 4 + 8); - let (chunks, rest) = bytes.as_chunks::<4>(); - for c in chunks { - let v = u32::from_be_bytes(*c); - if v == 0 { - raw.push('z'); - } else { - push85(&mut raw, v, 5); - } - } - if !rest.is_empty() { - let mut c = [0u8; 4]; - for (d, s) in c.iter_mut().zip(rest) { - *d = *s; - } - push85(&mut raw, u32::from_be_bytes(c), rest.len() + 1); - } - raw.push_str("~>"); - let mut out = String::with_capacity(raw.len() + raw.len() / LINE + 2); - if raw.starts_with('%') { - // Whitespace is ignored by readers, and keeps the first line from starting with `%`. - out.push(' '); - } - let mut col = 0; - for ch in raw.chars() { - if col >= LINE && ch != '%' { - out.push('\n'); - col = 0; - } - out.push(ch); - col += 1; - } - out.push('\n'); - out -} - -/// The first `n` base-85 digits of `v`. -fn push85(s: &mut String, mut v: u32, n: usize) { - let mut d = [0u8; 5]; - for slot in d.iter_mut().rev() { - *slot = (v % 85) as u8 + b'!'; - v /= 85; - } - for b in d.iter().take(n) { - s.push(char::from(*b)); - } -} +pub(crate) use craft_eps::ascii85::encode as ascii85; /// Most bytes [`ascii85_decode`] makes: what one filter or data section may hold. pub(crate) const MAX_ASCII85: usize = 1 << 28; @@ -241,47 +191,7 @@ pub(crate) fn ascii85_decode(text: &str) -> Option> { /// [`ascii85_decode`] of at most `max` bytes: `z` is four bytes for one, so the length of the /// text doesn't bound what it becomes (#1715). pub(crate) fn ascii85_decode_within(text: &str, max: usize) -> Option> { - let mut out = Vec::with_capacity((text.len() / 5 * 4).min(max)); - let mut group = [0u8; 5]; - let mut n = 0; - let mut chars = text.bytes().filter(|b| !b.is_ascii_whitespace()).peekable(); - while let Some(b) = chars.next() { - if out.len() > max { - return None; - } - match b { - b'~' => { - if chars.next() != Some(b'>') { - return None; - } - if n == 1 { - return None; - } - if n > 1 { - let padded: Vec = group.iter().take(n).copied().chain(std::iter::repeat(b'u')).take(5).collect(); - let v = value85(&padded)?; - out.extend(v.to_be_bytes().iter().take(n - 1)); - } - return (out.len() <= max).then_some(out); - } - b'z' if n == 0 => out.extend([0; 4]), - b'!'..=b'u' => { - *group.get_mut(n)? = b; - n += 1; - if n == 5 { - out.extend(value85(&group)?.to_be_bytes()); - n = 0; - } - } - _ => return None, - } - } - None -} - -/// The value of five base-85 digits; `None` past `u32::MAX`. -fn value85(digits: &[u8]) -> Option { - digits.iter().try_fold(0u32, |acc, d| acc.checked_mul(85)?.checked_add(u32::from(d.checked_sub(b'!')?))) + craft_eps::ascii85::decode(text.as_bytes(), max) } /// Run-length encoding (PackBits: what PostScript's `RunLengthDecode` reads), shared with TIFF. diff --git a/crates/mcp/src/ui_catalog.rs b/crates/mcp/src/ui_catalog.rs index 4e1e56619a..e3b57166b7 100644 --- a/crates/mcp/src/ui_catalog.rs +++ b/crates/mcp/src/ui_catalog.rs @@ -925,7 +925,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "tool.options", "Tool Options…", "", - "{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x, y and preview (on initially), previews one there and accepts it as one Undo step; Cancel rolls back the preview), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (px for pencil, paintbrush and smooth, the same at any zoom; pt for blobBrush), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), livePaintBucket → Live Paint Bucket Options (dialog `livePaintBucketOptions`, fields paintFills (on) and paintStrokes (off), highlight (on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the face highlight's width, 1–20 px; 4; an edge's highlight is half as wide); OK runs tool.setOption {tool: \"livePaintBucket\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values}; a highlightColor with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), objectsOnPath → Objects on Path Tool Options (dialog `objectsOnPathOptions`, fields pivot (0–8, row by row from the top left; 4, the center) and rotate (°, −360–360; 0); Reset puts 4 and 0 back; Save runs tool.setOption {tool: \"objectsOnPath\", values}: the objects attached next use them, groups attached before keep theirs)", + "{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x, y and preview (on initially), previews one there and accepts it as one Undo step; Cancel rolls back the preview), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (px for pencil, paintbrush and smooth, the same at any zoom; pt for blobBrush), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), livePaintBucket → Live Paint Bucket Options (dialog `livePaintBucketOptions`, fields paintFills (on) and paintStrokes (off), cursorSwatchPreview (on: the active fill or stroke shows above the pointer between the color swatches before and after it; Left and Right without modifiers step it through the color swatches whether it is on or off), highlight (on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the face highlight's width, 1–20 px; 4; an edge's highlight is half as wide); OK runs tool.setOption {tool: \"livePaintBucket\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values}; a highlightColor with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), objectsOnPath → Objects on Path Tool Options (dialog `objectsOnPathOptions`, fields pivot (0–8, row by row from the top left; 4, the center) and rotate (°, −360–360; 0); Reset puts 4 and 0 back; Save runs tool.setOption {tool: \"objectsOnPath\", values}: the objects attached next use them, groups attached before keep theirs)", ), ( "ui.colorGuideOptions", diff --git a/crates/pdf/src/import/builder.rs b/crates/pdf/src/import/builder.rs index c1be8fba84..4a979e8742 100644 --- a/crates/pdf/src/import/builder.rs +++ b/crates/pdf/src/import/builder.rs @@ -4,7 +4,7 @@ use super::entry::{ UNNAMED_CHARACTERS_NOTE, max_objects, }; use super::reshaped; -use super::state::{Builder, Frame, FrameKind, GlyphRun, Saved, bounds, grouped, line_width, mean_scale, paints, round3, stroke_layer}; +use super::state::{Builder, Frame, FrameKind, GlyphRun, Saved, bounds, grouped, line_width, mean_scale, paints, round3, same_stroke, stroke_layer}; use super::{ Affine, Appearance, AppearanceItem, Arc, BezPath, BfString, BlendMode, CacheKey, Color, Colors, Families, FillLayer, FillRule, FunctionBudget, FunctionPaint, HashMap, HashSet, ImageBlob, ImageObject, Knockout, Look, MaskSpec, MaskType, Native, Node, NodeId, NodeKind, OpacityMask, Paint, @@ -445,15 +445,23 @@ impl<'p> Builder<'p> { if let Some((t, opacity, facts)) = line.finish() { if checked && reshaped::reshapes(&t.plain_text()) && !reshaped::draws_as(&t, &facts.ink) { outlined = true; + if self.mask.is_some() { + self.flush_glyphs(); + self.flush_masked(); + } for g in glyphs { - let same = self.glyphs.as_ref().is_some_and(|r| { - r.paint == g.paint - && r.opacity == g.opacity - && r.overprint == g.overprint - && r.stroke.is_some() == g.stroke.is_some() - && r.stroke.as_ref().map(|s| s.line_width) == g.stroke.as_ref().map(|s| s.line_width) - && (r.scale - g.scale).abs() < 1e-9 - }); + // Glyphs the file fills one by one composite where they overlap: only opaque + // ones, drawn alike down to the stroke, and not under a soft mask (which + // would be applied once to all of them), share a path. + let same = g.opacity >= 0.999 + && self.mask.is_none() + && self.glyphs.as_ref().is_some_and(|r| { + r.paint == g.paint + && r.opacity == g.opacity + && r.overprint == g.overprint + && same_stroke(r.stroke.as_ref(), g.stroke.as_ref()) + && (r.scale - g.scale).abs() < 1e-9 + }); match &mut self.glyphs { Some(r) if same => r.path.extend(g.path.iter()), _ => { @@ -461,6 +469,12 @@ impl<'p> Builder<'p> { self.glyphs = Some(g); } } + // Under a soft mask each glyph is masked on its own: the art queued for the + // mask is drained at each glyph, or one group of them all takes it once. + if self.mask.is_some() { + self.flush_glyphs(); + self.flush_masked(); + } } self.warn(RESHAPED_TEXT_NOTE); } else { diff --git a/crates/pdf/src/import/state.rs b/crates/pdf/src/import/state.rs index 0470d641e2..12eb4498dc 100644 --- a/crates/pdf/src/import/state.rs +++ b/crates/pdf/src/import/state.rs @@ -235,6 +235,23 @@ pub(super) fn line_width(p: &StrokeProps, scale: f64) -> f64 { if p.line_width == 0.0 { HAIRLINE } else { p.line_width as f64 * scale } } +/// Do strokes `a` and `b` draw alike: both unstroked, or the same width, caps, joins, miter limit +/// and dashes ([`stroke_layer`] takes all of them)? +pub(super) fn same_stroke(a: Option<&StrokeProps>, b: Option<&StrokeProps>) -> bool { + match (a, b) { + (None, None) => true, + (Some(a), Some(b)) => { + a.line_width == b.line_width + && a.line_cap == b.line_cap + && a.line_join == b.line_join + && a.miter_limit == b.miter_limit + && a.dash_array == b.dash_array + && a.dash_offset == b.dash_offset + } + _ => false, + } +} + pub(super) fn stroke_layer(paint: Paint, opacity: f32, p: &StrokeProps, scale: f64) -> StrokeLayer { let mut st = StrokeLayer::new(paint, line_width(p, scale)); st.opacity = opacity; diff --git a/crates/pdf/src/tests/reshaped.rs b/crates/pdf/src/tests/reshaped.rs index 060eca40b7..af173fa55b 100644 --- a/crates/pdf/src/tests/reshaped.rs +++ b/crates/pdf/src/tests/reshaped.rs @@ -5,6 +5,7 @@ //! ([`vectorcraft_text::test_fonts::matra_font`]): Ka draws Source Sans 3's `a` and the vowel sign //! I, set before its consonant, draws its `i`. +use kurbo::{Rect, Shape}; use vectorcraft_doc::{Document, NodeKind}; use vectorcraft_testkit::pdf::{PdfPage, first_extra, pdf_with}; use vectorcraft_text::FontDb; @@ -29,6 +30,14 @@ fn glyph(c: char) -> (u32, f64) { /// and a ToUnicode map naming each glyph's character. `sign_width`: the advance the file gives /// the vowel sign, in thousandths of an em (`None`: the font's). fn page(drawn: &[char], sign_width: Option) -> Vec { + page_with(|id| format!("[{}] TJ", drawn.iter().map(|&c| id(c)).collect::()), "", &[], sign_width) +} + +/// [`page`] showing glyphs with the text operators `ops` makes (after the position of the first +/// glyph) from a function giving a character's glyph id in hex, and `extra` more resources: a +/// graphics state, to set between glyphs or before them, with `objects` it refers to (the first +/// is object `first_extra(1) + 4`). +fn page_with(ops: impl Fn(&dyn Fn(char) -> String) -> String, extra: &str, objects: &[String], sign_width: Option) -> Vec { FontDb::global().add_font(matra_font().expect("the test font builds")); let program = matra_font().unwrap(); let hex: String = program.iter().map(|b| format!("{b:02X}")).collect::() + ">"; @@ -55,14 +64,13 @@ fn page(drawn: &[char], sign_width: Option) -> Vec { ), ), ]; - let refs: Vec<&str> = objs.iter().map(String::as_str).collect(); + let refs: Vec<&str> = objs.iter().chain(objects).map(String::as_str).collect(); let resources = format!( - "/Font << /F1 << /Type /Font /Subtype /Type0 /BaseFont /MatratestSans-Regular /Encoding /Identity-H /DescendantFonts [{} 0 R] /ToUnicode {} 0 R >> >>", + "/Font << /F1 << /Type /Font /Subtype /Type0 /BaseFont /MatratestSans-Regular /Encoding /Identity-H /DescendantFonts [{} 0 R] /ToUnicode {} 0 R >> >> {extra}", n + 2, n + 3 ); - let shown: String = drawn.iter().map(|&c| format!("{:04X}", glyph(c).0)).collect(); - let content = format!("BT /F1 40 Tf 20 100 Td <{shown}> Tj ET"); + let content = format!("BT /F1 40 Tf 20 100 Td {} ET", ops(&|c| format!("<{:04X}>", glyph(c).0))); pdf_with(&[PdfPage { resources, ..PdfPage::new(300.0, 200.0, &content) }], &refs, None) } @@ -117,3 +125,96 @@ fn a_mark_without_an_advance_stays_with_its_line() { assert_eq!(texts(&report.document), [""; 0], "the mark is no type of its own"); assert_eq!(outlines(&report.document), 1, "both glyphs, as one path"); } + +/// The file's glyphs are outlines of one path when drawn alike, and a path each when a stroke +/// property other than the width (here the dash) differs between them: the first glyph's would +/// otherwise be drawn on all. +#[test] +fn outlined_glyphs_stroked_differently_stay_apart() { + // Stroked (`1 Tr`) at the same width, one glyph solid and the next dashed. + let alike = page_with(|id| format!("1 Tr 2 w {} Tj {} Tj {} Tj", id(KA), id(SIGN_I), id(KA)), "", &[], None); + let apart = page_with(|id| format!("1 Tr 2 w {} Tj [3 2] 0 d {} Tj [] 0 d {} Tj", id(KA), id(SIGN_I), id(KA)), "", &[], None); + assert_eq!(outlines(&open(&alike).document), 1, "drawn alike: one path"); + assert_eq!(outlines(&open(&apart).document), 3, "solid, dashed, solid: a path each"); +} + +/// Translucent glyphs the file fills one by one composite where they overlap, which one fill of +/// their joined outlines does not do: each keeps a path of its own. +#[test] +fn outlined_translucent_glyphs_stay_apart() { + let bytes = page_with(|id| format!("/G gs {} Tj {} Tj {} Tj", id(KA), id(SIGN_I), id(KA)), "/ExtGState << /G << /ca 0.5 >> >>", &[], None); + let report = open(&bytes); + assert_eq!(texts(&report.document), [""; 0]); + assert_eq!(outlines(&report.document), 3, "a path each"); +} + +/// Glyphs the file draws under a soft mask are not joined into one path: the mask would be applied +/// once to the whole, where the file applies it to each glyph. +#[test] +fn outlined_glyphs_under_a_soft_mask_stay_apart() { + // A luminosity mask (object `first_extra(1) + 4`) of mid gray over the page. + let group = stream("/Type /XObject /Subtype /Form /BBox [0 0 300 200] /Group << /S /Transparency /CS /DeviceGray >>", "0.5 g 0 0 300 200 re f"); + let mask = format!("/ExtGState << /M << /SMask << /S /Luminosity /G {} 0 R >> >> >>", first_extra(1) + 4); + let bytes = page_with(|id| format!("/M gs {} Tj {} Tj {} Tj", id(KA), id(SIGN_I), id(KA)), &mask, &[group], None); + let report = open(&bytes); + assert_eq!(texts(&report.document), [""; 0]); + assert_eq!(outlines(&report.document), 3, "a path each"); +} + +/// What the glyph outlines of `d` draw: how many path elements, and the box round them all. +fn outline_geometry(d: &Document) -> (usize, Rect) { + let (mut elements, mut bounds) = (0, None::); + d.walk(|n| { + if is_glyph_outlines(n) + && let Some(p) = n.path_data() + { + let path = p.to_bezpath(); + elements += path.elements().len(); + let b = path.bounding_box(); + bounds = Some(bounds.map_or(b, |u| u.union(b))); + } + }); + (elements, bounds.unwrap_or(Rect::ZERO)) +} + +/// A line kept as outlines draws the glyphs where they are drawn when the file is opened as +/// outlines: none dropped or moved. +#[test] +fn kept_glyphs_are_where_the_file_draws_them() { + for (drawn, sign_width) in [(vec![KA, SIGN_I, KA], None), (vec![KA, SIGN_I], Some(0.0))] { + let bytes = page(&drawn, sign_width); + let kept = open(&bytes); + let all = import_with_report(&bytes, &ImportOptions { text_as: TextAs::Outlines, ..Default::default() }).unwrap(); + assert_eq!(texts(&kept.document), [""; 0], "the line is kept as outlines"); + let (kept, all) = (outline_geometry(&kept.document), outline_geometry(&all.document)); + assert!(all.0 > 0, "the glyphs have outlines"); + assert_eq!(kept.0, all.0, "every outline element is kept"); + for (a, b) in [(kept.1.x0, all.1.x0), (kept.1.y0, all.1.y0), (kept.1.x1, all.1.x1), (kept.1.y1, all.1.y1)] { + assert!((a - b).abs() < 1e-6, "{:?} vs {:?}", kept.1, all.1); + } + } +} + +/// How many glyph outlines carry a soft mask of their own. +fn masked_outlines(d: &Document) -> usize { + let mut n = 0; + d.walk(|node| n += usize::from(is_glyph_outlines(node) && node.extras().mask.is_some())); + n +} + +/// A mask that isn't constant (dark on the left, light on the right) is a mask of its own on each +/// glyph, not one on a group of them: glyphs that overlap composite one by one, as the file draws +/// them. +#[test] +fn outlined_glyphs_under_a_varying_soft_mask_are_masked_one_by_one() { + let group = stream( + "/Type /XObject /Subtype /Form /BBox [0 0 300 200] /Group << /S /Transparency /CS /DeviceGray >>", + "0.2 g 0 0 150 200 re f 0.9 g 150 0 150 200 re f", + ); + let mask = format!("/ExtGState << /M << /SMask << /S /Luminosity /G {} 0 R >> >> >>", first_extra(1) + 4); + let bytes = page_with(|id| format!("/M gs {} Tj {} Tj {} Tj", id(KA), id(SIGN_I), id(KA)), &mask, &[group], None); + let report = open(&bytes); + assert_eq!(texts(&report.document), [""; 0]); + assert_eq!(outlines(&report.document), 3, "a path each"); + assert_eq!(masked_outlines(&report.document), 3, "each path has its own mask"); +} diff --git a/crates/svg/Cargo.toml b/crates/svg/Cargo.toml index 7c506d2bb3..7708d23c06 100644 --- a/crates/svg/Cargo.toml +++ b/crates/svg/Cargo.toml @@ -9,6 +9,7 @@ description = "VectorCraft SVG import and export" workspace = true [dependencies] +craft-svg = { workspace = true } # Which paths stored in documents may be opened. craft-docpath = { workspace = true } vectorcraft-geom = { workspace = true } diff --git a/crates/svg/src/entities.rs b/crates/svg/src/entities.rs index d1eb4cfef7..e80622ae42 100644 --- a/crates/svg/src/entities.rs +++ b/crates/svg/src/entities.rs @@ -2,90 +2,10 @@ //! replaces every `&name;` with the entity's text as it reads, with no total limit: a short file //! that repeats a large entity in an attribute allocates far more than it holds. -use std::collections::HashMap; - -/// The most text the references to entities may expand to in all (bytes). -const MAX_EXPANDED: usize = 16 << 20; - -/// How deep entities that refer to entities are followed (the reader's own limit is lower). -const MAX_NESTING: u32 = 16; - -/// The longest entity name a reference is looked for with ([`references`]). -const MAX_NAME: usize = 256; - -/// The internal general entities declared in `svg`: name → every value declared for it. Text that -/// only looks like a declaration (in a comment, or in another entity's value) is kept too: the -/// largest value counts, so it can only make the estimate larger. -fn declared(svg: &str) -> HashMap<&str, Vec<&str>> { - let mut map: HashMap<&str, Vec<&str>> = HashMap::new(); - for (at, _) in svg.match_indices(" impl Iterator { - text.match_indices('&').filter_map(|(at, _)| { - let rest = text.get(at + 1..)?; - // Look no further than the longest name: a file of `&`s without `;` would be read quadratically. - let end = rest.bytes().take(MAX_NAME + 1).position(|b| b == b';')?; - let name = rest.get(..end)?; - (!name.is_empty() && name.len() <= MAX_NAME && !name.starts_with('#') && !name.contains(char::is_whitespace)).then_some(name) - }) -} - -/// What entity `name` expands to (bytes), references in its value followed. -fn expanded<'a>(name: &'a str, entities: &HashMap<&'a str, Vec<&'a str>>, memo: &mut HashMap<&'a str, usize>, depth: u32) -> usize { - if let Some(n) = memo.get(name) { - return *n; - } - let Some(values) = entities.get(name) else { return 0 }; - if depth >= MAX_NESTING { - return usize::MAX; - } - let mut most = 0usize; - for value in values { - let mut total = value.len(); - for inner in references(value) { - total = total.saturating_add(expanded(inner, entities, memo, depth + 1)); - } - most = most.max(total); - } - memo.insert(name, most); - most -} - -/// Whether the references to the entities `svg` declares expand to more than [`MAX_EXPANDED`] +/// Whether the references to the entities `svg` declares expand to more than the limit /// bytes in all. False for a file that declares none. pub(crate) fn expansion_too_large(svg: &str) -> bool { - let entities = declared(svg); - if entities.is_empty() { - return false; - } - // A reference to a longer name isn't looked for: refuse such a declaration instead. - if entities.keys().any(|name| name.len() > MAX_NAME) { - return true; - } - let mut memo = HashMap::new(); - let mut total = 0usize; - for name in references(svg) { - total = total.saturating_add(expanded(name, &entities, &mut memo, 0)); - if total > MAX_EXPANDED { - return true; - } - } - false + craft_svg::guard::entities_expand_past(svg, craft_svg::guard::MAX_ENTITY_EXPANSION) } #[cfg(test)] @@ -118,7 +38,7 @@ mod tests { assert!(expansion_too_large(&commented)); let in_value = format!("\">]>"); assert!(expansion_too_large(&in_value)); - let long = "n".repeat(MAX_NAME + 1); + let long = "n".repeat(257); let long_name = format!("]>"); assert!(expansion_too_large(&long_name)); } diff --git a/crates/svg/src/lib.rs b/crates/svg/src/lib.rs index 0c698eebc7..23cc07d3c1 100644 --- a/crates/svg/src/lib.rs +++ b/crates/svg/src/lib.rs @@ -458,21 +458,17 @@ pub(crate) fn body_hash(parts: &[&str]) -> String { /// Does `bytes` start like gzip data (an SVGZ file)? pub fn is_svgz(bytes: &[u8]) -> bool { - bytes.starts_with(&[0x1f, 0x8b]) + craft_svg::sniff::is_svgz(bytes) } /// Compress SVG text as SVGZ (gzip). pub fn compress(svg: &str) -> Vec { - compress_bytes(svg.as_bytes()) + craft_svg::svgz::compress(svg.as_bytes()) } /// Compress an SVG file (in any encoding, see [`Output::bytes`]) as SVGZ (gzip). pub fn compress_bytes(svg: &[u8]) -> Vec { - use std::io::Write as _; - let mut gz = flate2::write::GzEncoder::new(Vec::with_capacity(svg.len() / 4), flate2::Compression::default()); - // Writing to a Vec cannot fail. - let _ = gz.write_all(svg); - gz.finish().unwrap_or_default() + craft_svg::svgz::compress(svg) } /// Most bytes an SVGZ file may unpack to (a guard against decompression bombs). @@ -487,29 +483,26 @@ pub fn text_of(bytes: &[u8]) -> Result, SvgError> { /// [`text_of`], SVGZ bytes unpacking within what `unpacked`, the bytes SVGZ data unpacked to so /// far, leaves of [`MAX_SVGZ`]. What they unpack to is added to it, whether or not it decodes. pub(crate) fn text_within<'a>(bytes: &'a [u8], unpacked: &std::sync::atomic::AtomicU64) -> Result, SvgError> { - use std::io::Read as _; use std::sync::atomic::Ordering; if !is_svgz(bytes) { - return match decode(bytes)? { - Decoded::Utf8(skip) => std::str::from_utf8(bytes.get(skip..).unwrap_or_default()).map(Into::into).map_err(|_| not_utf8()), - Decoded::Text(t) => Ok(t.into()), - }; + return craft_svg::svgz::decode(bytes).map_err(|_| not_utf8()); } - let most = MAX_SVGZ.saturating_sub(unpacked.load(Ordering::Relaxed)); - let mut raw = Vec::new(); - let read = flate2::read::GzDecoder::new(bytes).take(most.saturating_add(1)).read_to_end(&mut raw); - // Read before a failure is kept: it was unpacked too. - unpacked.fetch_add(raw.len() as u64, Ordering::Relaxed); - read.map_err(|e| SvgError::Parse(format!("not a valid SVGZ file: {e}")))?; - if raw.len() as u64 > most { - return Err(SvgError::TooBig(format!("the SVGZ file unpacks to more than {} MB", most >> 20))); - } - match decode(&raw)? { - Decoded::Utf8(skip) => { - raw.drain(..skip); - String::from_utf8(raw).map(Into::into).map_err(|_| not_utf8()) + let most = usize::try_from(MAX_SVGZ.saturating_sub(unpacked.load(Ordering::Relaxed))).unwrap_or(usize::MAX); + match craft_svg::svgz::inflate(bytes, most) { + Ok(raw) => { + unpacked.fetch_add(raw.len() as u64, Ordering::Relaxed); + craft_svg::svgz::decode(&raw) + .map(|t| std::borrow::Cow::Owned(t.into_owned())) + .map_err(|_| not_utf8()) } - Decoded::Text(t) => Ok(t.into()), + Err(craft_svg::svgz::Error::TooLarge(_)) => { + Err(SvgError::TooBig(format!("the SVGZ file unpacks to more than {} MB", most >> 20))) + } + Err(craft_svg::svgz::Error::Corrupt(e)) => { + Err(SvgError::Parse(format!("not a valid SVGZ file: {e}"))) + } + Err(craft_svg::svgz::Error::Encoding) => Err(not_utf8()), + Err(e) => Err(SvgError::Parse(e.to_string())), } } @@ -517,44 +510,6 @@ fn not_utf8() -> SvgError { SvgError::Parse("SVG is not UTF-8, UTF-16 or ISO 8859-1".into()) } -/// How SVG bytes are read. -enum Decoded { - /// UTF-8 after this many bytes (a byte order mark). - Utf8(usize), - /// Text decoded from another encoding. - Text(String), -} - -/// The encoding of SVG bytes: a byte order mark (UTF-8 or UTF-16), else the XML declaration's -/// (ISO 8859-1 by its names; anything else is read as UTF-8). -fn decode(bytes: &[u8]) -> Result { - let utf16 = |rest: &[u8], unit: fn([u8; 2]) -> u16| { - let (units, odd) = rest.as_chunks::<2>(); - if !odd.is_empty() { - return Err(not_utf8()); - } - char::decode_utf16(units.iter().map(|u| unit(*u))).collect::>().map(Decoded::Text).map_err(|_| not_utf8()) - }; - match bytes { - [0xef, 0xbb, 0xbf, ..] => Ok(Decoded::Utf8(3)), - [0xfe, 0xff, rest @ ..] => utf16(rest, u16::from_be_bytes), - [0xff, 0xfe, rest @ ..] => utf16(rest, u16::from_le_bytes), - _ if declared_latin1(bytes) => Ok(Decoded::Text(bytes.iter().map(|b| char::from(*b)).collect())), - _ => Ok(Decoded::Utf8(0)), - } -} - -/// Does the XML declaration at the start of `bytes` name ISO 8859-1? -fn declared_latin1(bytes: &[u8]) -> bool { - let head = bytes.get(..bytes.len().min(200)).unwrap_or_default(); - let Some(decl) = head.strip_prefix(b"').next()) else { return false }; - let decl = String::from_utf8_lossy(decl).to_ascii_lowercase(); - let Some(at) = decl.find("encoding") else { return false }; - let value = decl.get(at + "encoding".len()..).unwrap_or("").trim_start().trim_start_matches('=').trim_start(); - let name = value.trim_start_matches(['"', '\'']).split(['"', '\'', ' ', '?']).next().unwrap_or(""); - matches!(name, "iso-8859-1" | "iso8859-1" | "iso_8859-1" | "latin1" | "latin-1" | "l1") -} - /// Import an SVG document. pub fn import(svg: &str) -> Result { import_with_report(svg).map(|(d, _)| d) diff --git a/crates/tools/src/builder.rs b/crates/tools/src/builder.rs index 2190d34180..5a8d44d400 100644 --- a/crates/tools/src/builder.rs +++ b/crates/tools/src/builder.rs @@ -143,6 +143,38 @@ fn step_swatch(list: &[&Swatch], fill: &Paint, last: Option, forward: boo } } +/// Is no Shift, Alt, Cmd or Ctrl held? The arrows step swatches only then. +fn plain(mods: Mods) -> bool { + !(mods.shift || mods.alt || mods.cmd || mods.ctrl) +} + +/// The color swatch the Right (`forward`) or Left arrow key picks for the current `paint`, with its +/// index in [`color_swatches`] (see [`step_swatch`]); None when the document has no color swatch. +fn pick_swatch(doc: &Document, paint: &Paint, last: Option, forward: bool) -> Option<(usize, String)> { + let list = color_swatches(doc); + step_swatch(&list, paint, last, forward).and_then(|i| Some((i, list.get(i)?.name.clone()))) +} + +/// The cursor swatch preview for the current `paint` with the pointer at `at`: the swatch before +/// it, `paint` itself (ringed, while it is a solid color) and the swatch after it, side by side above +/// the pointer. With `matched_only`, the swatches beside it show only while `paint` is one of the +/// color swatches; otherwise the last and the first swatch stand beside a color that is none of them. +fn swatch_chips(cx: &ToolContext, at: Point, paint: &Paint, last: Option, matched_only: bool) -> Vec { + let list = color_swatches(cx.doc); + let rgba = |p: &Paint| match p { + Paint::Solid { color, .. } => Some(color.to_rgba8(1.0)), + _ => None, + }; + let beside = !matched_only || swatch_index(&list, paint, last).is_some(); + let chip = |forward| beside.then(|| step_swatch(&list, paint, last, forward)).flatten().and_then(|i| rgba(&list.get(i)?.paint)); + let (before, after) = (chip(false), chip(true)); + let y = at.y - cx.tol(22.0); + [(before, -16.0, false), (rgba(paint), 0.0, true), (after, 16.0, false)] + .into_iter() + .filter_map(|(color, dx, selected)| Some(Overlay::Swatch { p: Point::new(at.x + cx.tol(dx), y), color: color?, selected })) + .collect() +} + /// Shape Builder tool: drag across regions to merge them. Holding Alt (Option) switches to erase /// mode while it is held: the pointer shows a minus, what a click or drag would delete highlights in /// red, and the gesture deletes the regions it touches, the pieces of open paths and the edges @@ -425,20 +457,7 @@ impl ShapeBuilderTool { /// The cursor swatch preview: the swatch before the current fill, the current fill (ringed) /// and the swatch after it, side by side above the pointer. fn swatch_chips(&self, cx: &ToolContext) -> Vec { - let Some(at) = self.at else { return vec![] }; - let list = color_swatches(cx.doc); - let fill = &cx.paint.fill; - let rgba = |p: &Paint| match p { - Paint::Solid { color, .. } => Some(color.to_rgba8(1.0)), - _ => None, - }; - let chip = |forward| step_swatch(&list, fill, self.picked, forward).and_then(|i| rgba(&list.get(i)?.paint)); - let (before, after) = (chip(false), chip(true)); - let y = at.y - cx.tol(22.0); - [(before, -16.0, false), (rgba(fill), 0.0, true), (after, 16.0, false)] - .into_iter() - .filter_map(|(color, dx, selected)| Some(Overlay::Swatch { p: Point::new(at.x + cx.tol(dx), y), color: color?, selected })) - .collect() + self.at.map(|at| swatch_chips(cx, at, &cx.paint.fill, self.picked, false)).unwrap_or_default() } } @@ -712,9 +731,15 @@ impl Tool for ShapeBuilderTool { (self.opts.swatches && !self.dragging && matches!(key, ToolKey::Left | ToolKey::Right)) || (self.dragging && key == ToolKey::Escape) } - fn key(&mut self, cx: &ToolContext, key: ToolKey, _mods: Mods) -> Vec { + /// The arrows pick swatches only without modifiers; Shift, Alt and Cmd/Ctrl arrows keep their + /// shortcuts. + fn claims_key_with(&self, cx: &ToolContext, key: ToolKey, mods: Mods) -> bool { + self.claims_key(cx, key) && (key == ToolKey::Escape || plain(mods)) + } + + fn key(&mut self, cx: &ToolContext, key: ToolKey, mods: Mods) -> Vec { // While a merge is being computed, the arrows leave the current fill it takes as it was. - if !self.claims_key(cx, key) || self.editing() { + if !self.claims_key_with(cx, key, mods) || self.editing() { return vec![]; } if key == ToolKey::Escape { @@ -726,13 +751,12 @@ impl Tool for ShapeBuilderTool { (self.marquee, self.hover, self.far) = (None, None, false); return vec![]; } - let list = color_swatches(cx.doc); - let Some((i, s)) = step_swatch(&list, &cx.paint.fill, self.picked, key == ToolKey::Right).and_then(|i| Some((i, list.get(i)?))) else { + let Some((i, name)) = pick_swatch(cx.doc, &cx.paint.fill, self.picked, key == ToolKey::Right) else { return vec![]; }; self.picked = Some(i); // The current fill only (no `ids`): the selected art keeps its own. - vec![Action::Exec("paint.setFill".into(), json!({ "swatch": s.name, "ids": [] }))] + vec![Action::Exec("paint.setFill".into(), json!({ "swatch": name, "ids": [] }))] } fn options(&self) -> Value { diff --git a/crates/tools/src/builder/live_paint.rs b/crates/tools/src/builder/live_paint.rs index 6b744e4435..2ae2f082ee 100644 --- a/crates/tools/src/builder/live_paint.rs +++ b/crates/tools/src/builder/live_paint.rs @@ -3,7 +3,7 @@ use super::lookup::{is_live_paint, live_paint_at, live_paint_at_where, visible_e use super::map::{HIGHLIGHT_RED, sorted_roots}; use super::{ Action, Arc, BezPath, CLICK_TOL_PX, Cursor, Document, EDGE_NAME, FACE_NAME, FillRule, Mods, Node, NodeId, Overlay, Point, PointerEvent, - PointerKind, Rect, Tool, ToolContext, ToolKey, Value, json, json_ids, path_contains, + PointerKind, Rect, Tool, ToolContext, ToolKey, Value, color_swatches, json, json_ids, path_contains, pick_swatch, plain, swatch_chips, }; // ---------- Live Paint Bucket ---------- @@ -171,6 +171,14 @@ enum LpPaint { /// click paints nothing. With Highlight off, the face or edge under the pointer is not /// highlighted. The cursor is a filled bucket where a click fills a face, a brush where it paints /// an edge and an empty bucket where it paints nothing; with Alt it is the Eyedropper. +/// +/// The Left and Right arrow keys without Shift, Alt or Cmd/Ctrl set the active paint (the fill, +/// or the stroke when the Stroke proxy is in front) to the color swatch before or after it in the +/// Swatches panel, wrapping around; from a color that is no swatch, Right picks the first swatch +/// and Left the last. The selected art keeps its paint. With `cursorSwatchPreview` (on), the +/// active paint shows as a chip above the pointer between the swatches before and after it, +/// except during a fill drag or with Alt held; a solid color that is no swatch shows alone, and a +/// paint that is not a solid color shows no chip. pub struct LivePaintBucketTool { pub(super) cache: RegionCache, pub(super) hover: LpHover, @@ -183,6 +191,11 @@ pub struct LivePaintBucketTool { highlight: bool, color: [u8; 3], width: f64, + /// Cursor Swatch Preview. + preview: bool, + /// The index in [`color_swatches`] of the swatch the arrow keys picked last for the fill and for + /// the stroke. + picked: [Option; 2], } /// Maximum points in one Live Paint fill path chunk. @@ -200,11 +213,24 @@ impl Default for LivePaintBucketTool { highlight: true, color: HIGHLIGHT_RED, width: LP_BUCKET_WIDTH, + preview: true, + picked: [None; 2], } } } impl LivePaintBucketTool { + /// The active paint the arrow keys step and the preview shows: the fill, or the stroke when the + /// Stroke proxy is in front. + fn active_paint<'a>(cx: &'a ToolContext) -> &'a vectorcraft_color::Paint { + if cx.fill_active { &cx.paint.fill } else { &cx.paint.stroke } + } + + /// The slot of [`Self::picked`] for the active paint. + fn picked_slot(cx: &ToolContext) -> usize { + usize::from(!cx.fill_active) + } + fn begin_fill(&mut self, params: Value, p: Point) -> Vec { self.fill_drag = Some((params.clone(), vec![vec![p]])); vec![Action::Begin("Live Paint Bucket".into()), Action::Preview("livePaint.fill".into(), params)] @@ -377,6 +403,8 @@ impl Tool for LivePaintBucketTool { } PointerKind::Drag => self.drag_fill(p), PointerKind::Up => { + // The swatch preview shows again at the release point. + self.at = Some((p, ev.mods.shift, ev.mods.alt)); let mut acts = self.drag_fill(p); if self.fill_drag.take().is_some() { acts.push(Action::Commit); @@ -387,24 +415,63 @@ impl Tool for LivePaintBucketTool { } } - fn key(&mut self, _cx: &ToolContext, key: ToolKey, _mods: Mods) -> Vec { - if key == ToolKey::Escape && self.fill_drag.take().is_some() { vec![Action::Cancel] } else { vec![] } + /// Escape during a fill drag cancels it. Left and Right pick the color swatch before or after + /// the active paint, while no drag is on. + fn key(&mut self, cx: &ToolContext, key: ToolKey, mods: Mods) -> Vec { + if key == ToolKey::Escape { + return if self.fill_drag.take().is_some() { vec![Action::Cancel] } else { vec![] }; + } + if !self.claims_key_with(cx, key, mods) { + return vec![]; + } + let slot = Self::picked_slot(cx); + let Some((i, name)) = pick_swatch(cx.doc, Self::active_paint(cx), self.picked[slot], key == ToolKey::Right) else { + return vec![]; + }; + self.picked[slot] = Some(i); + // The active paint only (no `ids`): the selected art keeps its own. + let cmd = if cx.fill_active { "paint.setFill" } else { "paint.setStroke" }; + vec![Action::Exec(cmd.into(), json!({ "swatch": name, "ids": [] }))] } fn busy(&self) -> bool { self.fill_drag.is_some() } - fn claims_key(&self, _cx: &ToolContext, key: ToolKey) -> bool { - key == ToolKey::Escape && self.busy() + fn claims_key(&self, cx: &ToolContext, key: ToolKey) -> bool { + match key { + ToolKey::Escape => self.busy(), + ToolKey::Left | ToolKey::Right => !self.busy() && !color_swatches(cx.doc).is_empty(), + _ => false, + } + } + + /// The arrows pick swatches only without modifiers; Shift, Alt and Cmd/Ctrl arrows keep their + /// shortcuts. + fn claims_key_with(&self, cx: &ToolContext, key: ToolKey, mods: Mods) -> bool { + self.claims_key(cx, key) && (key == ToolKey::Escape || plain(mods)) } fn deactivate(&mut self, _cx: &ToolContext) -> Vec { if self.fill_drag.take().is_some() { vec![Action::Commit] } else { vec![] } } - fn overlays(&self, _cx: &ToolContext) -> Vec { - lp_overlays(&self.hover, &self.cache, self.color, self.width as f32, (self.width * LP_BUCKET_EDGE_FRACTION) as f32) + /// The pointer hovers nothing for the tool: its highlight and its swatch preview go. + fn hover_ended(&mut self, _cx: &ToolContext) { + self.hover = LpHover::None; + self.at = None; + } + + fn overlays(&self, cx: &ToolContext) -> Vec { + let mut out = lp_overlays(&self.hover, &self.cache, self.color, self.width as f32, (self.width * LP_BUCKET_EDGE_FRACTION) as f32); + // No chips during a fill drag, or while Alt makes the tool sample with the eyedropper. + if self.preview + && !self.busy() + && let Some((at, _, false)) = self.at + { + out.extend(swatch_chips(cx, at, Self::active_paint(cx), self.picked[Self::picked_slot(cx)], true)); + } + out } fn cursor(&self, cx: &ToolContext, p: Point, m: Mods) -> Cursor { @@ -416,6 +483,7 @@ impl Tool for LivePaintBucketTool { json!({ "paintFills": self.fills, "paintStrokes": self.strokes, + "cursorSwatchPreview": self.preview, "highlight": self.highlight, "color": format!("#{r:02x}{g:02x}{b:02x}"), "width": self.width, @@ -426,6 +494,7 @@ impl Tool for LivePaintBucketTool { match key { "paintFills" => self.fills = v.as_bool().unwrap_or(self.fills), "paintStrokes" => self.strokes = v.as_bool().unwrap_or(self.strokes), + "cursorSwatchPreview" => self.preview = v.as_bool().unwrap_or(self.preview), "highlight" => self.highlight = v.as_bool().unwrap_or(self.highlight), "color" => self.color = lp_color(v).unwrap_or(self.color), "width" => { @@ -612,7 +681,7 @@ pub(super) fn lp_rgb_color(v: &Value) -> bool { /// value it cannot read. pub fn check_live_paint_options(tool: &str, values: &serde_json::Map) -> Result<(), String> { let switches: &[&str] = match tool { - "livePaintBucket" => &["paintFills", "paintStrokes", "highlight"], + "livePaintBucket" => &["paintFills", "paintStrokes", "cursorSwatchPreview", "highlight"], "livePaintSelection" => &["selectFills", "selectStrokes"], _ => return Ok(()), }; diff --git a/crates/tools/src/builder/tests.rs b/crates/tools/src/builder/tests.rs index 298e6a1907..01b64ee8c3 100644 --- a/crates/tools/src/builder/tests.rs +++ b/crates/tools/src/builder/tests.rs @@ -1087,6 +1087,42 @@ fn bucket_click_fills_face_and_shift_click_strokes_edge() { assert_eq!(id, "livePaint.strokeEdge"); } +/// After a fill drag, the cursor swatch preview shows at the release point, not where the pointer +/// last moved before the press. +#[test] +fn bucket_swatch_preview_follows_the_release_point() { + let (d, ..) = live_group_doc(); + let s = Selection::default(); + let p = paint(); + let cx = cx(&d, &s, &p); + let mut t = LivePaintBucketTool::default(); + let chip_x = |t: &LivePaintBucketTool| { + t.overlays(&cx).iter().find_map(|o| if let Overlay::Swatch { p, selected: true, .. } = o { Some(p.x) } else { None }) + }; + t.pointer(&cx, &ev(PointerKind::Move, 25.0, 25.0)); + assert_eq!(chip_x(&t), Some(25.0)); + t.pointer(&cx, &ev(PointerKind::Down, 25.0, 25.0)); + t.pointer(&cx, &ev(PointerKind::Drag, 50.0, 25.0)); + assert_eq!(chip_x(&t), None, "no chips during the drag"); + t.pointer(&cx, &ev(PointerKind::Up, 75.0, 25.0)); + assert_eq!(chip_x(&t), Some(75.0)); +} + +/// When the pointer leaves the canvas, the Live Paint Bucket's swatch preview and highlight go. +#[test] +fn bucket_hover_ended_drops_the_swatch_preview_and_highlight() { + let (d, ..) = live_group_doc(); + let s = Selection::default(); + let p = paint(); + let cx = cx(&d, &s, &p); + let mut t = LivePaintBucketTool::default(); + t.pointer(&cx, &ev(PointerKind::Move, 75.0, 25.0)); + let ov = t.overlays(&cx); + assert!(ov.iter().any(|o| matches!(o, Overlay::Swatch { .. })) && ov.iter().any(|o| matches!(o, Overlay::Path { .. })), "{ov:?}"); + t.hover_ended(&cx); + assert!(t.overlays(&cx).is_empty()); +} + #[test] fn bucket_options_choose_what_a_click_paints() { let (d, gid, ..) = live_group_doc(); @@ -1113,7 +1149,12 @@ fn bucket_options_choose_what_a_click_paints() { }; let (face, edge) = (Some(Rect::new(50.0, 0.0, 100.0, 50.0)), Some(Rect::new(50.0, 0.0, 50.0, 50.0))); let mut t = LivePaintBucketTool::default(); - assert_eq!(t.options(), json!({"paintFills": true, "paintStrokes": false, "highlight": true, "color": "#ff2a2a", "width": 4.0})); + assert_eq!( + t.options(), + json!({"paintFills": true, "paintStrokes": false, "cursorSwatchPreview": true, "highlight": true, "color": "#ff2a2a", "width": 4.0}) + ); + // The highlight alone, without the swatch chips. + t.set_option("cursorSwatchPreview", &json!(false)); // Paint Fills alone: 1 pt from the edge, a click fills the face and Shift-click strokes the edge. assert_eq!((click(&mut t, 51.0, Mods::default()), hovered(&mut t, 51.0, Mods::default())), (fill(51.0), face)); assert_eq!((click(&mut t, 51.0, shift), hovered(&mut t, 51.0, shift)), (stroke(51.0), edge)); @@ -1231,6 +1272,7 @@ fn bucket_fills_a_region_of_a_selection_that_mixes_a_group_and_paths() { s.set([g]); let live = cx(&d, &s, &p); let mut t = LivePaintBucketTool::default(); + t.set_option("cursorSwatchPreview", &json!(false)); t.pointer(&live, &ev(PointerKind::Move, pos.x, pos.y)); t.poll(&live, true); assert!(t.overlays(&live).is_empty()); @@ -1245,6 +1287,7 @@ fn bucket_strokes_alone_paints_and_highlights_no_region_of_the_selection() { let p = paint(); let cx = cx(&d, &s, &p); let mut t = LivePaintBucketTool::default(); + t.set_option("cursorSwatchPreview", &json!(false)); t.pointer(&cx, &ev(PointerKind::Move, 75.0, 50.0)); t.poll(&cx, true); assert!(!t.overlays(&cx).is_empty(), "Paint Fills highlights the region"); @@ -1263,6 +1306,7 @@ fn bucket_options_set_the_highlight() { let p = paint(); let cx = cx(&d, &s, &p); let mut t = LivePaintBucketTool::default(); + t.set_option("cursorSwatchPreview", &json!(false)); let highlight = |t: &mut LivePaintBucketTool| { t.pointer(&cx, &ev(PointerKind::Move, 75.0, 25.0)); match t.overlays(&cx).as_slice() { @@ -1299,6 +1343,7 @@ fn bucket_highlights_an_edge_thinner_than_a_face() { let p = paint(); let cx = cx(&d, &s, &p); let mut t = LivePaintBucketTool::default(); + t.set_option("cursorSwatchPreview", &json!(false)); let width = |t: &mut LivePaintBucketTool, x: f64, shift: bool| { t.pointer(&cx, &ev(PointerKind::Move, x, 25.0).with_mods(Mods { shift, ..Default::default() })); match t.overlays(&cx).as_slice() { @@ -1517,7 +1562,7 @@ fn bucket_hover_builds_a_large_map_on_another_thread() { poll_until_ready(&mut t, &cx); assert!(matches!(t.hover, LpHover::Region(_)), "{:?}", t.hover); assert_eq!((t.cache.builds, t.cache.background), (1, 1)); - assert_eq!(t.overlays(&cx).len(), 1); + assert_eq!(t.overlays(&cx).iter().filter(|o| matches!(o, Overlay::Path { .. })).count(), 1); } #[test] @@ -1883,6 +1928,7 @@ fn live_paint_edges_outside_the_faces_come_from_the_nearest_visible_group() { }; assert_eq!(lp_click(&mut sel, &cx, ev(PointerKind::Down, x, y).with_mods(alt)), vec![picked]); let mut bucket = LivePaintBucketTool::default(); + bucket.set_option("cursorSwatchPreview", &json!(false)); bucket.pointer(&cx, &ev(PointerKind::Move, x, y).with_mods(shift)); assert_eq!(edge_x(&bucket.overlays(&cx)), want.map(|w| w.2)); let stroked = want.map(|(g, ..)| Action::Exec("livePaint.strokeEdge".into(), json!({ "group": g.0, "point": [x, y], "tolerance": 4.0 }))); @@ -1926,6 +1972,7 @@ fn live_paint_tools_skip_hidden_edges() { }; assert_eq!(lp_click(&mut sel, &cx, ev(PointerKind::Down, x, 50.0).with_mods(alt)), vec![picked], "x {x}"); let mut bucket = LivePaintBucketTool::default(); + bucket.set_option("cursorSwatchPreview", &json!(false)); bucket.pointer(&cx, &ev(PointerKind::Move, x, 50.0).with_mods(shift)); assert_eq!(edge_x(&bucket.overlays(&cx)), want.map(|w| w.2), "x {x}"); let stroked = want.map(|(g, ..)| Action::Exec("livePaint.strokeEdge".into(), json!({ "group": g.0, "point": [x, 50.0], "tolerance": 4.0 }))); @@ -1953,6 +2000,7 @@ fn live_paint_tools_skip_hidden_faces() { }; // Where the faces overlap, both tools take the back group's face under the hidden one. let mut bucket = LivePaintBucketTool::default(); + bucket.set_option("cursorSwatchPreview", &json!(false)); bucket.pointer(&cx, &ev(PointerKind::Move, 75.0, 50.0)); assert_eq!(part(&bucket.overlays(&cx)), Some(Rect::new(0.0, 0.0, 100.0, 100.0))); let fill = Action::Preview("livePaint.fill".into(), json!({ "group": back.0, "point": [75.0, 50.0] })); diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index d46a7fd972..3ee1d48256 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs @@ -182,6 +182,11 @@ pub trait Tool: Send { fn claims_key(&self, _cx: &ToolContext, _key: ToolKey) -> bool { false } + /// [`Self::claims_key`] for a press with `mods` held. By default the modifiers do not matter; + /// a tool that takes a key only without modifiers leaves the modified presses to the shortcuts. + fn claims_key_with(&self, cx: &ToolContext, key: ToolKey, _mods: Mods) -> bool { + self.claims_key(cx, key) + } /// Has the tool started something that Escape ends while no button is pressed (a path being /// drawn, the Blend tool's first pick)? That Escape ends nothing else, such as isolation mode or /// a rotated view. diff --git a/crates/tools/src/settings.rs b/crates/tools/src/settings.rs index e7b9f9a5c4..a4d1b1a64f 100644 --- a/crates/tools/src/settings.rs +++ b/crates/tools/src/settings.rs @@ -46,7 +46,7 @@ const ROWS: &[Row] = &[ // Live Paint Selection Tool Options (`builder::LivePaintSelectionTool`). (&["livePaintSelection"], None, &["selectFills", "selectStrokes", "color", "width"]), // Live Paint Bucket Options (`builder::LivePaintBucketTool`). - (&["livePaintBucket"], None, &["paintFills", "paintStrokes", "highlight", "color", "width"]), + (&["livePaintBucket"], None, &["paintFills", "paintStrokes", "cursorSwatchPreview", "highlight", "color", "width"]), (&["polygon"], None, &["sides"]), (&["star"], None, &["points"]), (&["freeTransform"], None, &["constrain"]), diff --git a/crates/ui-egui/src/canvas/tests.rs b/crates/ui-egui/src/canvas/tests.rs index 666a1c8a62..2a7162f9a1 100644 --- a/crates/ui-egui/src/canvas/tests.rs +++ b/crates/ui-egui/src/canvas/tests.rs @@ -680,9 +680,17 @@ fn bucket_modifier_only_hover_updates_the_visible_cursor() { frame(app, &ctx, events); app.canvas.hover_cursor.map(|(_, _, cursor)| cursor) }; + // The cursor swatch preview's chips go and come back with Alt too. + let chips = |app: &mut VectorcraftApp| { + let view = app.view_info(); + app.session.overlays(view).iter().filter(|o| matches!(o, vectorcraft_tools::Overlay::Swatch { .. })).count() + }; assert_eq!(shown(&mut app, vec![Event::PointerMoved(at)]), Some(Cursor::LivePaintBucket)); + assert!(chips(&mut app) > 0); assert_eq!(shown(&mut app, vec![Event::ModifiersChanged(Modifiers::ALT)]), Some(Cursor::Eyedropper)); + assert_eq!(chips(&mut app), 0); assert_eq!(shown(&mut app, vec![Event::ModifiersChanged(Modifiers::NONE)]), Some(Cursor::LivePaintBucket)); + assert!(chips(&mut app) > 0); } /// The Image Trace panel's eye-button hold ends when the pointer is released, even when the diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 552fbc0c06..1f3a01528c 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -783,6 +783,7 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { return window(app, ctx); } let mut ok = false; + let mut ok_clicked = false; let mut ok_enabled = true; let mut cancel = false; let mut reset = false; @@ -843,7 +844,7 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { if let Some(label) = spec.ok.map(|ok| spec.ok_label.map_or(ok, |f| f(app))) && widgets::primary_button_enabled(ui, label, ok_enabled).clicked() { - ok = true; + ok_clicked = true; } ui.add_space(8.0); // While Alt (Option) is held, Cancel reads Reset on a dialog that has one. @@ -878,6 +879,20 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { }); }); let rejected = ctx.data_mut(|d| d.remove_temp::(widgets::dialog_reject_commit_flag())).unwrap_or(false); + // A field that refused its text when the press on OK took its focus keeps the dialog open, as + // Enter does. Only a pointer click has such a press; the keyboard and screen readers press OK + // in one frame. + let press = egui::Id::unique("dialog-press-pass"); + let (pressed, released) = ctx.input(|i| (i.pointer.any_pressed(), i.pointer.any_released())); + if pressed { + let pass = ctx.cumulative_pass_nr(); + ctx.data_mut(|m| m.insert_temp(press, pass)); + } + let (pressed_at, refused_at) = ctx.data(|m| (m.get_temp::(press), m.get_temp::(widgets::dialog_reject_pass()))); + let refused_during_click = released && matches!((refused_at, pressed_at), (Some(r), Some(p)) if r >= p); + if ok_clicked && !rejected && !refused_during_click { + ok = true; + } if spec.ok.is_some() && ok_enabled && !after_panel && !rejected && crate::shortcuts::pressed_anew(ctx, egui::Key::Enter) { ok = true; } diff --git a/crates/ui-egui/src/dialogs/command.rs b/crates/ui-egui/src/dialogs/command.rs index cb23628a4c..6656b45bf5 100644 --- a/crates/ui-egui/src/dialogs/command.rs +++ b/crates/ui-egui/src/dialogs/command.rs @@ -128,10 +128,20 @@ fn lengths(command: &str) -> &'static [&'static str] { "type.pathOptions" => &["spacing"], "object.pathfinder.trap" => &["thickness"], crate::addons::cutting::BRIDGES => &["width"], + "object.textWrap.options" => &["offset"], _ => &[], } } +/// The range (points) of a distance parameter of the commands this dialog edits, where the +/// command has one: the field refuses a distance typed outside it. +pub(super) fn length_range(command: &str, key: &str) -> Option> { + match (command, key) { + ("object.textWrap.options", "offset") => Some(vectorcraft_engine::TEXT_WRAP_OFFSET_RANGE), + _ => None, + } +} + /// The order the fields of the commands this dialog edits come in, where the order of their /// names isn't it (the rest follow, by name). fn order(command: &str) -> &'static [&'static str] { @@ -505,4 +515,168 @@ mod tests { assert_eq!(crate::panels::pattern_options::repeat_fields(&app).unwrap()["instances"], 4); assert!(!app.session.in_interaction()); } + + /// Text Wrap Options › Offset is a distance, and its range is the one `object.textWrap.options` + /// keeps an Offset to. + #[test] + fn text_wrap_offset_is_a_distance_within_the_commands_range() { + assert!(lengths("object.textWrap.options").contains(&"offset")); + assert!(!lengths("object.textWrap.options").contains(&"invert")); + let range = length_range("object.textWrap.options", "offset").expect("a range"); + assert_eq!(range, vectorcraft_engine::TEXT_WRAP_OFFSET_RANGE); + assert_eq!(length_range("object.textWrap.options", "invert"), None); + assert_eq!(length_range("text.areaOptions", "inset"), None); + let mut s = Session::new(); + s.execute("file.new", &json!({"width": 400, "height": 400})).unwrap(); + s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap(); + s.execute("select.all", &json!({})).unwrap(); + s.execute("object.textWrap.make", &json!({})).unwrap(); + for (sent, end) in [(5000.0, *range.end()), (-5000.0, *range.start())] { + assert_eq!(s.execute("object.textWrap.options", &json!({ "offset": sent })).unwrap()["offset"], json!(end)); + } + } + + /// Replaces the text of the dialog's Offset field with `text`, leaving the field focused. + fn type_offset(h: &mut egui_kittest::Harness<'_, VectorcraftApp>, text: &str) { + use egui::accesskit::Role; + use egui_kittest::kittest::Queryable; + let all = egui::Modifiers { ctrl: true, command: true, ..Default::default() }; + h.get_by_role_and_label(Role::TextInput, "Offset:").focus(); + h.run_steps(2); + h.key_press_modifiers(all, egui::Key::A); + h.get_by_role_and_label(Role::TextInput, "Offset:").type_text(text); + h.run_steps(2); + } + + /// Replaces the text of the dialog's Offset field with `text` and presses Enter. + fn enter_offset(h: &mut egui_kittest::Harness<'_, VectorcraftApp>, text: &str) { + type_offset(h, text); + h.key_press(egui::Key::Enter); + h.run_steps(3); + } + + /// Text Wrap Options › Offset reads a bare number in the document's units and a typed unit as + /// typed, and OK sends points. A distance typed outside the command's range, or text that + /// doesn't read, is refused: the dialog stays open and the Offset isn't changed. + #[test] + fn text_wrap_offset_field_takes_document_units_and_refuses_values_outside_its_range() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 400, "height": 400})).unwrap(); + app.run("document.setUnits", json!({"units": "millimeters"})).unwrap(); + let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap()["id"].as_u64().unwrap(); + app.run("select.set", json!({"ids": [id]})).unwrap(); + app.run("object.textWrap.make", json!({})).unwrap(); + let mut fonts = false; + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1100.0, 900.0)).build_ui_state( + move |ui, app: &mut VectorcraftApp| { + if !std::mem::replace(&mut fonts, true) { + crate::theme::install_fonts(ui.ctx()); + return; + } + crate::dialogs::show(app, ui.ctx()); + }, + app, + ); + let offset = |h: &mut egui_kittest::Harness<'_, VectorcraftApp>| { + h.state_mut().session.execute("object.textWrap.options", &json!({})).unwrap()["offset"].as_f64().unwrap() + }; + // The ends as the field shows them in millimeters (352.7778 mm is 1000.00006 pt) read + // back as the ends. + let ends = [("-1000 pt", -1000.0), ("352.7778", 1000.0), ("-352.7778", -1000.0), ("1000 pt", 1000.0)]; + for (text, want) in [("10", 10.0 * 72.0 / 25.4), ("-12 pt", -12.0)].into_iter().chain(ends) { + crate::menus::invoke(h.state_mut(), "object.textWrap.options", json!({})); + h.run_steps(3); + enter_offset(&mut h, text); + assert!(h.state().ui.dialog.is_none(), "{text}: OK applied it"); + assert!((offset(&mut h) - want).abs() < 1e-9, "{text}: {} pt", offset(&mut h)); + } + for text in ["1000.5 pt", "-2000", "abc"] { + crate::menus::invoke(h.state_mut(), "object.textWrap.options", json!({})); + h.run_steps(3); + enter_offset(&mut h, text); + let d = h.state().ui.dialog.as_ref().unwrap_or_else(|| panic!("{text}: the dialog stays open")); + assert_eq!(d.fields.get("offset"), Some(&json!(1000.0)), "{text}: the field keeps its value"); + crate::dialogs::cancel(h.state_mut()); + assert_eq!(offset(&mut h), 1000.0, "{text}: the Offset is unchanged"); + } + // A click on OK with a value outside the range still in the field is refused too. + crate::menus::invoke(h.state_mut(), "object.textWrap.options", json!({})); + h.run_steps(3); + type_offset(&mut h, "2000 pt"); + click_ok(&mut h); + assert!(h.state().ui.dialog.is_some(), "OK leaves the dialog open"); + assert_eq!(offset(&mut h), 1000.0, "the Offset is unchanged"); + // After it, a value inside the range committed with Tab and OK pressed from the keyboard + // apply. + type_offset(&mut h, "-7 pt"); + h.key_press(egui::Key::Tab); + h.run_steps(2); + { + use egui_kittest::kittest::Queryable; + h.get_by_label("OK").focus(); + } + h.run_steps(2); + h.key_press(egui::Key::Space); + h.run_steps(3); + assert!(h.state().ui.dialog.is_none(), "OK from the keyboard applied it"); + assert_eq!(offset(&mut h), -7.0); + // One inside it applies. + crate::menus::invoke(h.state_mut(), "object.textWrap.options", json!({})); + h.run_steps(3); + type_offset(&mut h, "-5 pt"); + click_ok(&mut h); + assert!(h.state().ui.dialog.is_none(), "OK applied it"); + assert_eq!(offset(&mut h), -5.0); + } + + /// In a document in picas, Text Wrap Options › Offset reads a bare number as the other length + /// fields in picas do: in points with Preferences › Units › Numbers Without Units Are Points on + /// (the default), in picas with it off. A typed unit is read as typed either way. + #[test] + fn text_wrap_offset_in_picas_follows_numbers_without_units_are_points() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 400, "height": 400})).unwrap(); + app.run("document.setUnits", json!({"units": "picas"})).unwrap(); + let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap()["id"].as_u64().unwrap(); + app.run("select.set", json!({"ids": [id]})).unwrap(); + app.run("object.textWrap.make", json!({})).unwrap(); + let mut fonts = false; + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1100.0, 900.0)).build_ui_state( + move |ui, app: &mut VectorcraftApp| { + if !std::mem::replace(&mut fonts, true) { + crate::theme::install_fonts(ui.ctx()); + return; + } + crate::dialogs::show(app, ui.ctx()); + }, + app, + ); + let apply = |h: &mut egui_kittest::Harness<'_, VectorcraftApp>, text: &str| { + crate::menus::invoke(h.state_mut(), "object.textWrap.options", json!({})); + h.run_steps(3); + enter_offset(h, text); + assert!(h.state().ui.dialog.is_none(), "{text}: OK applied it"); + h.state_mut().session.execute("object.textWrap.options", &json!({})).unwrap()["offset"].as_f64().unwrap() + }; + assert_eq!(apply(&mut h, "10"), 10.0, "on by default: a bare number is in points"); + assert_eq!(apply(&mut h, "2p6"), 30.0, "picas and points as typed"); + assert_eq!(apply(&mut h, "-1in"), -72.0, "a typed unit wins"); + crate::widgets::set_bare_numbers_are_points(&h.ctx, false); + assert_eq!(apply(&mut h, "10"), 120.0, "off: a bare number is in picas"); + assert_eq!(apply(&mut h, "-12 pt"), -12.0, "a typed unit wins"); + } + + /// Clicks the dialog's OK button with the pointer, the press and the release in frames of + /// their own. + fn click_ok(h: &mut egui_kittest::Harness<'_, VectorcraftApp>) { + use egui_kittest::kittest::Queryable; + let ok = h.get_by_label("OK").rect().center(); + let (button, modifiers) = (egui::PointerButton::Primary, egui::Modifiers::default()); + h.event(egui::Event::PointerMoved(ok)); + h.run_steps(1); + h.event(egui::Event::PointerButton { pos: ok, button, pressed: true, modifiers }); + h.run_steps(1); + h.event(egui::Event::PointerButton { pos: ok, button, pressed: false, modifiers }); + h.run_steps(3); + } } diff --git a/crates/ui-egui/src/dialogs/form.rs b/crates/ui-egui/src/dialogs/form.rs index bbddd222f5..033e194e50 100644 --- a/crates/ui-egui/src/dialogs/form.rs +++ b/crates/ui-egui/src/dialogs/form.rs @@ -453,7 +453,14 @@ pub(super) fn param_fields( if is_length(&k) { // An effect's documented range keeps the field to the distance it applies. let range = vectorcraft_effects::length_range(&d.str("__effect"), &k); - if spinners { + // A command's own range refuses a distance typed outside it. + if let Some(bounds) = super::command::length_range(&d.str("__command"), &k) { + let value = d.fields.contains_key(&k).then(|| d.f64(&k, 0.0)); + if let Some(x) = crate::widgets::num_field_refusing(ui, ("dlg-len", k.as_str()), value, unit, 140.0, bounds) { + d.fields.insert(k.clone(), json!(x)); + changed = true; + } + } else if spinners { let bounds = range.unwrap_or(if k == "blur" { 0.0..=f64::INFINITY } else { crate::widgets::ANY }); let value = d.fields.contains_key(&k).then(|| d.f64(&k, 0.0)); if let Some(x) = crate::widgets::spin_length_within(ui, ("dlg-len", k.as_str()), value, unit, 140.0, bounds) { diff --git a/crates/ui-egui/src/dialogs/live_paint_bucket.rs b/crates/ui-egui/src/dialogs/live_paint_bucket.rs index c040cdcc31..f515c3d904 100644 --- a/crates/ui-egui/src/dialogs/live_paint_bucket.rs +++ b/crates/ui-egui/src/dialogs/live_paint_bucket.rs @@ -4,7 +4,8 @@ //! `tool.setOption {tool: "livePaintBucket", values}`. //! //! Fields: `paintFills` and `paintStrokes` (the faces and the edges of Live Paint groups), -//! `highlight` (whether the face or edge under the pointer is outlined), `color` (the highlight +//! `cursorSwatchPreview` (whether the active paint and the color swatches beside it show above the +//! pointer), `highlight` (whether the face or edge under the pointer is outlined), `color` (the highlight //! color: `#rrggbb`, or a layer color's name such as "Red") and `width` (the width of a face's //! highlight in screen pixels; an edge's highlight is half as wide). @@ -25,7 +26,7 @@ pub const KIND: &str = "livePaintBucketOptions"; const TOOL: &str = "livePaintBucket"; /// The options the dialog edits. -const KEYS: [&str; 5] = ["paintFills", "paintStrokes", "highlight", "color", "width"]; +const KEYS: [&str; 6] = ["paintFills", "paintStrokes", "cursorSwatchPreview", "highlight", "color", "width"]; /// Width of the label column. const LABEL_W: f32 = 60.0; @@ -48,6 +49,7 @@ pub fn open(app: &mut VectorcraftApp) -> Result { fn body(_app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { form::check(ui, d, "paintFills", tl!("Paint Fills")); form::check(ui, d, "paintStrokes", tl!("Paint Strokes")); + form::check(ui, d, "cursorSwatchPreview", tl!("Cursor Swatch Preview")); ui.add_space(6.0); form::check(ui, d, "highlight", tl!("Highlight")); let color = resolve(&d.str("color")).unwrap_or(Color::BLACK); @@ -120,17 +122,18 @@ mod tests { crate::toolbar::open_options(&mut app, TOOL).unwrap(); let text = painted(&mut app); - for label in ["Live Paint Bucket Options", "Paint Fills", "Paint Strokes", "Highlight", "Color:", "Width:"] { + for label in ["Live Paint Bucket Options", "Paint Fills", "Paint Strokes", "Cursor Swatch Preview", "Highlight", "Color:", "Width:"] { assert!(text.contains(label), "{label} in {text}"); } let d = app.ui.dialog.as_mut().unwrap(); assert_eq!(d.kind, KIND); assert_eq!( - (d.bool("paintFills"), d.bool("paintStrokes"), d.bool("highlight"), d.str("color"), d.f64("width", 0.0)), - (true, false, true, "#ff2a2a".to_string(), 4.0) + (d.bool("paintFills"), d.bool("paintStrokes"), d.bool("cursorSwatchPreview"), d.bool("highlight"), d.str("color"), d.f64("width", 0.0)), + (true, false, true, true, "#ff2a2a".to_string(), 4.0) ); d.fields.insert("paintFills".into(), json!(false)); d.fields.insert("paintStrokes".into(), json!(true)); + d.fields.insert("cursorSwatchPreview".into(), json!(false)); d.fields.insert("color".into(), json!("Green")); d.fields.insert("width".into(), json!(8)); super::super::confirm(&mut app).unwrap(); @@ -141,10 +144,13 @@ mod tests { // They last while another tool is chosen, and the dialog opens on them again. app.select_tool("selection"); let o = app.session.tool_options_of(TOOL); - assert_eq!((o["paintFills"].as_bool(), o["paintStrokes"].as_bool(), o["color"].as_str()), (Some(false), Some(true), Some("#4fff4f"))); + assert_eq!( + (o["paintFills"].as_bool(), o["paintStrokes"].as_bool(), o["cursorSwatchPreview"].as_bool(), o["color"].as_str()), + (Some(false), Some(true), Some(false), Some("#4fff4f")) + ); app.run("tool.options", json!({"tool": TOOL})).unwrap(); let d = app.ui.dialog.as_mut().unwrap(); - assert_eq!((d.bool("paintStrokes"), d.str("color")), (true, "#4fff4f".to_string())); + assert_eq!((d.bool("paintStrokes"), d.bool("cursorSwatchPreview"), d.str("color")), (true, false, "#4fff4f".to_string())); // Highlight off: the tool outlines nothing under the pointer. d.fields.insert("highlight".into(), json!(false)); super::super::confirm(&mut app).unwrap(); diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 5184985726..48f2671c2d 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -7349,3 +7349,1813 @@ breakText Glyphs Glify Grommets Oczka Grommet Inset Odległość oczek od krawędzi Diameter Średnica + +# Status and error messages of commands, scripts, file import and export, and plug-ins. +@msg 'caller', 'callee' and 'arguments' cannot be used on strict mode functions w funkcjach trybu ścisłego nie można używać 'caller', 'callee' ani 'arguments' +@msg Alignment must be one of the choices Wyrównanie musi być jedną z dostępnych opcji +@msg Boolean.prototype.{name} was called on a value that is not a Boolean Boolean.prototype.{name} wywołano na wartości, która nie jest wartością Boolean +@msg CMYK images whose samples couldn't be read in CMYK were imported in RGB Obrazy CMYK, których próbek nie udało się odczytać w CMYK, zaimportowano w RGB +@msg Cannot write to the location of “{name}”; choose where to save it Nie można zapisać w lokalizacji pliku „{name}”; wybierz miejsce zapisu +@msg DCS files can only be placed linked: use File › Place with Link on Pliki DCS można umieszczać tylko jako połączone: użyj polecenia Plik › Umieść z włączoną opcją Łącze +@msg Date.prototype method called on a value that is not a Date object Metodę Date.prototype wywołano na wartości, która nie jest obiektem Date +@msg Error.prototype.toString was called on a value that is not an object Error.prototype.toString wywołano na wartości, która nie jest obiektem +@msg Function.prototype.toString was called on a value that is not a function Function.prototype.toString wywołano na wartości, która nie jest funkcją +@msg Import SVG Filter reads SVG files, not SVGZ Importowanie filtra SVG odczytuje pliki SVG, a nie SVGZ +@msg JSON.parse: {why} (at offset {at}) JSON.parse: {why} (przesunięcie {at}) +@msg JSON.stringify cannot write a structure that contains itself JSON.stringify nie może zapisać struktury, która zawiera samą siebie +@msg Line Gap must be a number Odstęp między wierszami musi być liczbą +@msg Namespace.prototype.toString needs a Namespace Namespace.prototype.toString wymaga obiektu Namespace +@msg New Document profiles need the preferences folder, which this run doesn't have Profile nowego dokumentu wymagają folderu preferencji, którego to uruchomienie nie ma +@msg Number.prototype.{name} was called on a value that is not a number Number.prototype.{name} wywołano na wartości, która nie jest liczbą +@msg Object.create's prototype must be an object or null Object.create: prototyp musi być obiektem lub null +@msg Object.{function} was given a value that is not an object Object.{function} otrzymało wartość, która nie jest obiektem +@msg QName.prototype.toString needs a QName QName.prototype.toString wymaga obiektu QName +@msg RegExp.prototype.{name} was called on a value that is not a RegExp object RegExp.prototype.{name} wywołano na wartości, która nie jest obiektem RegExp +@msg Stencil Bridges: the selected art is too large or too detailed to bridge Mostki szablonu: zaznaczona grafika jest zbyt duża lub zbyt szczegółowa, aby utworzyć mostki +@msg String.prototype.toString was called on a value that is not a string String.prototype.toString wywołano na wartości, która nie jest ciągiem znaków +@msg The {name} profile could not be read, so the new document has the default settings: {reason} Nie udało się odczytać profilu {name}, więc nowy dokument ma ustawienia domyślne: {reason} +@msg Trap: more than {_1} pairs of objects lie close enough to trap, or too many objects share a horizontal range; trap fewer objects at a time Zalewka: ponad {_1} par obiektów leży na tyle blisko siebie, że wymaga zalewki, albo zbyt wiele obiektów ma wspólny zakres poziomy; stosuj zalewkę do mniejszej liczby obiektów naraz +@msg Weed Box and Lines: no weeding line fits outside the art, and the weed box is off Ramka i linie do wybierania: żadna linia do wybierania nie mieści się poza grafiką, a ramka do wybierania jest wyłączona +@msg \\ at end of pattern \\ na końcu wzorca +@msg `alignOn` cannot be empty `alignOn` nie może być puste +@msg `alignOn` must be a string `alignOn` musi być ciągiem znaków +@msg `align` must be a string `align` musi być ciągiem znaków +@msg `answer` for this {kind} dialog must be one of: {_1} `answer` dla tego okna dialogowego {kind} musi mieć jedną z wartości: {_1} +@msg `answers` has more than {MAX_ANSWERS} answers `answers` zawiera więcej niż {MAX_ANSWERS} odpowiedzi +@msg `answers` is larger than 1 MiB `answers` ma rozmiar większy niż 1 MiB +@msg `answers` must be a list of answers `answers` musi być listą odpowiedzi +@msg `artboard` must be the index of an artboard of the document `artboard` musi być indeksem obszaru kompozycji dokumentu +@msg `artboardsAt` must be [x, y] `artboardsAt` musi mieć postać [x, y] +@msg `artboards` names an artboard the document does not have `artboards` wskazuje obszar kompozycji, którego dokument nie ma +@msg `artboards` names an artboard twice `artboards` wskazuje ten sam obszar kompozycji dwa razy +@msg `at` must be [x, y] (got {at}) `at` musi mieć postać [x, y] (podano {at}) +@msg `at` must be a point [x, y] `at` musi być punktem [x, y] +@msg `beside` needs `side` `beside` wymaga `side` +@msg `code` must be a whole number `code` musi być liczbą całkowitą +@msg `colorMode` must be one of rgb, cmyk `colorMode` musi mieć jedną z wartości: rgb, cmyk +@msg `colors` does not apply to the {name} reduction `colors` nie ma zastosowania do redukcji {name} +@msg `colors` must be a whole number from 2 to 256 `colors` musi być liczbą całkowitą od 2 do 256 +@msg `colors` must be at least 9 for the uniform reduction `colors` musi wynosić co najmniej 9 dla redukcji uniform +@msg `colors` must be between 1 and {MAX_THEME_COLORS} (got {n}) `colors` musi mieścić się w zakresie od 1 do {MAX_THEME_COLORS} (podano {n}) +@msg `count` must be a whole number from 0 to {MAX_COUNT} `count` musi być liczbą całkowitą od 0 do {MAX_COUNT} +@msg `ditherAmount` must be a number from 0 to 100 `ditherAmount` musi być liczbą od 0 do 100 +@msg `fidelity` must be from {lo} to {hi} pt `fidelity` musi mieścić się w zakresie od {lo} do {hi} pt +@msg `focal` and `radius` cannot be used together `focal` i `radius` nie mogą być używane razem +@msg `focal` must be an array of [subpath, anchor] pairs `focal` musi być tablicą par [subpath, anchor] +@msg `focal` names [{si}, {ai}], which is not an anchor of the path `focal` wskazuje [{si}, {ai}], co nie jest punktem kontrolnym ścieżki +@msg `glyphAlternate` takes only null, which takes a glyph choice away (text.setGlyphAlternate makes one) `glyphAlternate` przyjmuje tylko null, co usuwa wybór glifu (wybór ustawia text.setGlyphAlternate) +@msg `group` must be one of {_1} `group` musi mieć jedną z wartości: {_1} +@msg `group` must be the Objects on Path group of `member` and `target` `group` musi być grupą Obiekty na ścieżce, do której należą `member` i `target` +@msg `id` is an object id, not {v} `id` to identyfikator obiektu, a nie {v} +@msg `item` needs `index` `item` wymaga `index` +@msg `kerningBefore` belongs to a line's first character, not to a character style (text.setRangeStyle sets it) `kerningBefore` należy do pierwszego znaku wiersza, a nie do stylu znakowego (ustawia go text.setRangeStyle) +@msg `kinsokuType` must be "pushInFirst", "pushOutFirst" or "pushOutOnly" `kinsokuType` musi mieć wartość "pushInFirst", "pushOutFirst" lub "pushOutOnly" +@msg `leader` must be a string `leader` musi być ciągiem znaków +@msg `max` must be 1 to {MAX_SUGGESTIONS} `max` musi wynosić od 1 do {MAX_SUGGESTIONS} +@msg `name` must be a name that is not empty `name` musi być niepustą nazwą +@msg `name` must not be empty `name` nie może być puste +@msg `origin` must be [x, y] in points `origin` musi mieć postać [x, y] w punktach +@msg `picks` must be an array (got {v}) `picks` musi być tablicą (podano {v}) +@msg `picks` must hold 1 to {MAX_PICKS} picks (got {_1}) `picks` musi zawierać od 1 do {MAX_PICKS} wskazań (podano {_1}) +@msg `points` must hold from 2 to 100000 points `points` musi zawierać od 2 do 100000 punktów +@msg `radius` must be 0 or more `radius` musi wynosić 0 lub więcej +@msg `rect` must be [x, y, width, height] `rect` musi mieć postać [x, y, width, height] +@msg `rect` must be [x0, y0, x1, y1] (got {r}) `rect` musi mieć postać [x0, y0, x1, y1] (podano {r}) +@msg `replace` must be a string `replace` musi być ciągiem znaków +@msg `rows` must be lists of numbers or nulls, not {r} `rows` musi zawierać listy liczb lub wartości null, a nie {r} +@msg `scale` must be a number from 0.001 to 1000 `scale` musi być liczbą od 0,001 do 1000 +@msg `scope.{key}` must be a non-empty array `scope.{key}` musi być niepustą tablicą +@msg `scope` must be "document", {artboards} or {layers} `scope` musi mieć wartość "document", {artboards} lub {layers} +@msg `side` must be "left", "right", "top" or "bottom" `side` musi mieć wartość "left", "right", "top" lub "bottom" +@msg `side` places the artboard: leave out x, y, width and height `side` wyznacza położenie obszaru kompozycji: pomiń x, y, width i height +@msg `source` is the only path in series group `target` `source` jest jedyną ścieżką w grupie serii `target` +@msg `spacing` makes more than {MAX_COUNT} lines across the box `spacing` daje więcej niż {MAX_COUNT} linii w poprzek ramki +@msg `spacing` must be more than 0 and at most {MAX_DISTANCE} pt `spacing` musi być większe od 0 i wynosić najwyżej {MAX_DISTANCE} pt +@msg `target` must be an object of the same Objects on Path group as `member` `target` musi być obiektem tej samej grupy Obiekty na ścieżce co `member` +@msg `tolerance` must be from 0 to 100 pt `tolerance` musi mieścić się w zakresie od 0 do 100 pt +@msg `version` must be 0 or {_1} `version` musi wynosić 0 lub {_1} +@msg `version` must be 0 or {newest} `version` musi wynosić 0 lub {newest} +@msg `warichuAlign` must be one of {_1} `warichuAlign` musi mieć jedną z wartości: {_1} +@msg `warichuLines` must be a whole number from {_1} to {_2} `warichuLines` musi być liczbą całkowitą od {_1} do {_2} +@msg `weight` must be from 0.01 to 1000 pt `weight` musi mieścić się w zakresie od 0,01 do 1000 pt +@msg `weights` must be a list of {_1} numbers, one per row (got {v}) `weights` musi być listą {_1} liczb, po jednej na wiersz (podano {v}) +@msg `xml` must be a string `xml` musi być ciągiem znaków +@msg `{KEY}` entry {n} gives the paragraph at byte {start} of {_1} other indents than an entry before it `{KEY}`: wpis {n} nadaje akapitowi od bajtu {start} obiektu {_1} inne wcięcia niż wcześniejszy wpis +@msg `{KEY}` entry {n} must be an object `{KEY}`: wpis {n} musi być obiektem +@msg `{KEY}` entry {n} sets neither `leftIndent` nor `firstLineIndent` `{KEY}`: wpis {n} nie ustawia ani `leftIndent`, ani `firstLineIndent` +@msg `{KEY}` entry {n}: `id` must be an object id `{KEY}`: wpis {n}: `id` musi być identyfikatorem obiektu +@msg `{KEY}` entry {n}: `start` must be a byte offset `{KEY}`: wpis {n}: `start` musi być przesunięciem w bajtach +@msg `{KEY}` entry {n}: `{k}` must be a number from -{MAX_PARA} to {MAX_PARA} pt `{KEY}`: wpis {n}: `{k}` musi być liczbą od -{MAX_PARA} do {MAX_PARA} pt +@msg `{KEY}` entry {n}: no paragraph of {_1} starts at byte {start} `{KEY}`: wpis {n}: żaden akapit obiektu {_1} nie zaczyna się od bajtu {start} +@msg `{KEY}` entry {n}: unknown key `{k}` `{KEY}`: wpis {n}: nieznany klucz `{k}` +@msg `{KEY}` entry {n}: {_1} is not a type object `{KEY}`: wpis {n}: {_1} nie jest obiektem tekstowym +@msg `{KEY}` is empty `{KEY}` jest puste +@msg `{KEY}` must be a list `{KEY}` musi być listą +@msg `{KEY}` takes at most {MAX_PARAGRAPH_INDENTS} entries (got {_1}) `{KEY}` przyjmuje najwyżej {MAX_PARAGRAPH_INDENTS} wpisów (podano {_1}) +@msg `{KEY}` takes no `{other}` beside it `{KEY}` nie przyjmuje obok siebie `{other}` +@msg `{base}` is larger than {_1} MB `{base}` ma rozmiar większy niż {_1} MB +@msg `{base}` is not in the DCS file's folder `{base}` nie znajduje się w folderze pliku DCS +@msg `{key}` holds more than {MAX_EDIT_WORDS} words `{key}` zawiera więcej niż {MAX_EDIT_WORDS} słów +@msg `{key}` must be 0 or more `{key}` musi wynosić 0 lub więcej +@msg `{key}` must be [x, y] numbers `{key}` musi zawierać liczby [x, y] +@msg `{key}` must be a list of words `{key}` musi być listą słów +@msg `{key}` must be a list, not {v} `{key}` musi być listą, a nie {v} +@msg `{key}` must be a number or null, not {v} `{key}` musi być liczbą lub null, a nie {v} +@msg `{key}` must be a whole number of 0 or more `{key}` musi być liczbą całkowitą równą 0 lub większą +@msg `{key}` must be from 0 to {MAX_DISTANCE} pt `{key}` musi mieścić się w zakresie od 0 do {MAX_DISTANCE} pt +@msg `{key}` must be from 0.01 to 1000 pt `{key}` musi mieścić się w zakresie od 0,01 do 1000 pt +@msg `{key}` must be from {lo} to {hi}, not {v} `{key}` musi mieścić się w zakresie od {lo} do {hi}, a nie {v} +@msg `{key}` must be one of auto, always, never `{key}` musi mieć jedną z wartości: auto, always, never +@msg `{key}` must be one of miter, round, bevel `{key}` musi mieć jedną z wartości: miter, round, bevel +@msg `{key}` must be one word of at most {_1} characters `{key}` musi być jednym słowem o długości najwyżej {_1} znaków +@msg `{key}` must hold single words of at most {_1} characters `{key}` musi zawierać pojedyncze słowa o długości najwyżej {_1} znaków +@msg `{key}` must name an object attached to the path of an Objects on Path group `{key}` musi wskazywać obiekt dołączony do ścieżki grupy Obiekty na ścieżce +@msg `{key}` names an object that is hidden or locked `{key}` wskazuje obiekt, który jest ukryty lub zablokowany +@msg `{name}` is a file of its own, which can only be found next to the DCS file's path `{name}` to osobny plik, który można znaleźć tylko obok ścieżki pliku DCS +@msg `{name}`: {_1}: {e} `{name}`: {_1}: {e} +@msg `{u}` is no Unicode character `{u}` nie jest znakiem Unicode +@msg `{word}` isn't in the custom dictionary słowa `{word}` nie ma w słowniku użytkownika +@msg a CMap has too many mappings mapa CMap ma zbyt wiele mapowań +@msg a \\u escape needs four hexadecimal digits sekwencja \\u wymaga czterech cyfr szesnastkowych +@msg a comma in an XPath expression must separate function arguments przecinek w wyrażeniu XPath musi rozdzielać argumenty funkcji +@msg a document holds at most {_1} SVG filters dokument może zawierać najwyżej {_1} filtrów SVG +@msg a document with unsaved changes has no recovery copy dokument z niezapisanymi zmianami nie ma kopii odzyskiwania +@msg a font's data is too large dane czcionki są zbyt duże +@msg a font's subroutines are too large podprogramy czcionki są zbyt duże +@msg a function declaration without a name deklaracja funkcji bez nazwy +@msg a host value has too many entries wartość hosta ma zbyt wiele wpisów +@msg a host value is nested too deep wartość hosta jest zbyt głęboko zagnieżdżona +@msg a namespace declaration uses a reserved prefix or URI deklaracja przestrzeni nazw używa zastrzeżonego prefiksu lub identyfikatora URI +@msg a namespace qualifier is undefined kwalifikator przestrzeni nazw jest niezdefiniowany +@msg a namespace with an empty URI cannot have a prefix przestrzeń nazw z pustym identyfikatorem URI nie może mieć prefiksu +@msg a number has no digits liczba nie ma cyfr +@msg a number's exponent has no digits wykładnik liczby nie ma cyfr +@msg a number's fraction has no digits część ułamkowa liczby nie ma cyfr +@msg a property descriptor cannot have both a value or writable and a get or set deskryptor właściwości nie może mieć jednocześnie value lub writable oraz get lub set +@msg a property descriptor must be an object deskryptor właściwości musi być obiektem +@msg a property's {name} must be a function or undefined {name} właściwości musi być funkcją lub undefined +@msg a stream in it would decode to more than 256 MB, or its decode parameters can't be applied zawarty w nim strumień po zdekodowaniu przekroczyłby 256 MB albo nie można zastosować jego parametrów dekodowania +@msg a string holds a control character ciąg znaków zawiera znak sterujący +@msg a string holds an escape sequence JSON does not have ciąg znaków zawiera sekwencję ucieczki, której nie ma w JSON +@msg a string is not closed ciąg znaków nie jest zamknięty +@msg an SVG filter is named by its id: give `xml` with `name` nazwą filtra SVG jest jego identyfikator: podaj `xml` razem z `name` +@msg an XML element has two attributes with the same name element XML ma dwa atrybuty o tej samej nazwie +@msg an XML value cannot be inserted into itself or its descendants wartości XML nie można wstawić do niej samej ani do jej elementów potomnych +@msg an XML value's children cannot be assigned by position elementów potomnych wartości XML nie można przypisywać według pozycji +@msg an XML value's children cannot be deleted by position elementów potomnych wartości XML nie można usuwać według pozycji +@msg an XMLList converts to XML only when it has one item XMLList można przekształcić w XML tylko wtedy, gdy ma jeden element +@msg an XPath node test is missing brak testu węzła XPath +@msg an XPath operand is missing brak operandu XPath +@msg an XPath operator is missing brak operatora XPath +@msg an XPath predicate or step cannot follow here w tym miejscu nie może wystąpić predykat ani krok XPath +@msg an XPath predicate or step follows a value that is not a node-set predykat lub krok XPath następuje po wartości, która nie jest zbiorem węzłów +@msg an XPath step is missing brak kroku XPath +@msg an image couldn't be decoded and is missing from the picture nie udało się zdekodować obrazu, więc brakuje go na ilustracji +@msg an image of {w} × {h} pixels is too large to convert (at most {_1} pixels) obraz o wymiarach {w} × {h} pikseli jest zbyt duży, aby go przekonwertować (najwyżej {_1} pikseli) +@msg apply was called on a value that is not a function apply wywołano na wartości, która nie jest funkcją +@msg area type in a thread cannot use Dynamic Text: {frames} tekst akapitowy w tekście wątkowym nie może używać tekstu dynamicznego: {frames} +@msg array literal too long literał tablicowy jest zbyt długi +@msg assignment to a constant binding przypisanie do stałego powiązania +@msg at least one row that isn't excluded needs a weight above 0 co najmniej jeden niewykluczony wiersz musi mieć wagę większą od 0 +@msg bad point {v}: expected [x, y] nieprawidłowy punkt {v}: oczekiwano [x, y] +@msg blend must be a mode name blend musi być nazwą trybu +@msg both sides of an XPath | must select nodes obie strony operatora | w XPath muszą wybierać węzły +@msg canceled anulowano +@msg cannot convert the object to a primitive value nie można przekonwertować obiektu na wartość prostą +@msg cannot convert undefined or null to an object nie można przekonwertować undefined ani null na obiekt +@msg character dimensions cannot be represented with the source text transform wymiarów znaków nie można przedstawić przy przekształceniu tekstu źródłowego +@msg character dimensions cannot be represented with the target text transform wymiarów znaków nie można przedstawić przy przekształceniu tekstu docelowego +@msg continuation must be an array of path chunks continuation musi być tablicą fragmentów ścieżki +@msg continuation requires points continuation wymaga points +@msg each path chunk must contain 1 to 4096 points każdy fragment ścieżki musi zawierać od 1 do 4096 punktów +@msg each pick is {{at: [x, y]}} or {{rect: [x0, y0, x1, y1]}} (got {v}) każde wskazanie ma postać {{at: [x, y]}} lub {{rect: [x0, y0, x1, y1]}} (podano {v}) +@msg each weight must be a number of 0 or more (got {v}) każda waga musi być liczbą równą 0 lub większą (podano {v}) +@msg finally table {t} out of range tabela finally {t} poza zakresem +@msg flags cannot be given with a RegExp object flag nie można podawać razem z obiektem RegExp +@msg function declaration index out of range indeks deklaracji funkcji poza zakresem +@msg give `char`, `text`, `code` or `unicode` podaj `char`, `text`, `code` lub `unicode` +@msg give `count` or `spacing`, not both podaj `count` albo `spacing`, nie oba naraz +@msg give `name`, an SVG filter's name podaj `name`, nazwę filtra SVG +@msg give `path`, an SVG file, or `svg`, SVG text podaj `path`, plik SVG, albo `svg`, tekst SVG +@msg give `xml`, one SVG element podaj `xml`, jeden element SVG +@msg give exactly one of `at`, `rect` and `points` podaj dokładnie jedno z: `at`, `rect` i `points` +@msg give exactly one of `path`, `data` and `dataBase64` podaj dokładnie jedno z: `path`, `data` i `dataBase64` +@msg give index or indexes, not both podaj index albo indexes, nie oba naraz +@msg give one element podaj jeden element +@msg give opacity or blend podaj opacity lub blend +@msg handler at {_1} expects {_2} values but its range starts with {d} procedura obsługi w {_1} oczekuje {_2} wartości, ale jej zakres zaczyna się od {d} +@msg handler depth too large zbyt duża głębokość procedur obsługi +@msg handler range {_1}..{_2} out of range zakres procedury obsługi {_1}..{_2} poza zakresem +@msg hiddenLayers must be true or false hiddenLayers musi mieć wartość true lub false +@msg hvcC hvcC +@msg images in a spot ink whose samples couldn't be read were imported in RGB obrazy w farbie dodatkowej, których próbek nie udało się odczytać, zaimportowano w RGB +@msg images past the most pixels one file may hold were left out pominięto obrazy przekraczające największą liczbę pikseli dozwoloną w jednym pliku +@msg images too large to read were left out pominięto obrazy zbyt duże do odczytania +@msg indexes may hold at most {MAX_GUIDE_INDEXES} entries indexes może zawierać najwyżej {MAX_GUIDE_INDEXES} wpisów +@msg indexes must be an array of guide indexes indexes musi być tablicą indeksów linii pomocniczych +@msg instruction out of range instrukcja poza zakresem +@msg instruction {pc} ({op}) pops below the stack instrukcja {pc} ({op}) zdejmuje ze stosu więcej, niż on zawiera +@msg instruction {pc} reached with stack depths {seen} and {d} instrukcja {pc} osiągnięta przy głębokościach stosu {seen} i {d} +@msg invalid array length nieprawidłowa długość tablicy +@msg invalid group nieprawidłowa grupa +@msg invalid object id {v}: expected a non-negative integer nieprawidłowy identyfikator obiektu {v}: oczekiwano nieujemnej liczby całkowitej +@msg invalid regular expression flag '{_1}' nieprawidłowa flaga wyrażenia regularnego '{_1}' +@msg invalid regular expression: {m} nieprawidłowe wyrażenie regularne: {m} +@msg invalid time value nieprawidłowa wartość czasu +@msg is a confirm's answer, whose `value` must be true or false to odpowiedź na okno confirm, której `value` musi mieć wartość true lub false +@msg is a prompt's answer, whose `value` must be a string or null to odpowiedź na okno prompt, której `value` musi być ciągiem znaków lub null +@msg is an alert's answer, whose `value` must be "ok" to odpowiedź na okno alert, której `value` musi mieć wartość "ok" +@msg is longer than 16 KiB ma długość większą niż 16 KiB +@msg it draws its image through a clipping path rysuje swój obraz przez ścieżkę przycinającą +@msg it draws no image nie rysuje żadnego obrazu +@msg it is larger than {MAX_DICTIONARY_FILE_BYTES} bytes ma rozmiar większy niż {MAX_DICTIONARY_FILE_BYTES} bajtów +@msg it isn't a file to nie jest plik +@msg it names {_1} plates, and at most {MAX_PLATES} are read wymienia {_1} płyt, a odczytywanych jest najwyżej {MAX_PLATES} +@msg its art is too long or too detailed for a head jego grafika jest zbyt długa lub zbyt szczegółowa na grot +@msg its art paints nothing jego grafika niczego nie maluje +@msg its image is too large to read jego obraz jest zbyt duży do odczytania +@msg its plates are too large: more than {MAX_SAMPLES} pixels together jego płyty są zbyt duże: łącznie ponad {MAX_SAMPLES} pikseli +@msg its plates are too large: {_1} plates of {w} × {h} pixels jego płyty są zbyt duże: {_1} płyt o wymiarach {w} × {h} pikseli +@msg its plates can't be kept together jego płyt nie można zachować razem +@msg its shapes could not be combined into one jego kształtów nie udało się połączyć w jeden +@msg jump to {pc}, past the end skok do {pc}, poza koniec +@msg legacyNameEncoding must be one of {_1} legacyNameEncoding musi mieć jedną z wartości: {_1} +@msg localize: the first argument must be a localization object or a string localize: pierwszy argument musi być obiektem lokalizacji lub ciągiem znaków +@msg missing `picks` brak `picks` +@msg missing `word` brak `word` +@msg must be an object with `kind` and `value` musi być obiektem z `kind` i `value` +@msg must have `kind` alert, confirm or prompt `kind` musi mieć wartość alert, confirm lub prompt +@msg must have exactly `kind` and `value` musi mieć dokładnie `kind` i `value` +@msg needs a closing quote after the name wymaga zamykającego cudzysłowu po nazwie +@msg needs a name wymaga nazwy +@msg needs a name of at most 64 bytes wymaga nazwy o długości najwyżej 64 bajtów +@msg needs a name of letters, digits and _, or a quoted name wymaga nazwy złożonej z liter, cyfr i znaku _ albo nazwy w cudzysłowie +@msg needs a name without control characters wymaga nazwy bez znaków sterujących +@msg nesting too deep zbyt głębokie zagnieżdżenie +@msg no HP-GL format brak formatu HP-GL +@msg no New Document profile called `{shown}` ({_1}) brak profilu nowego dokumentu o nazwie `{shown}` ({_1}) +@msg no SVG filter at index {k} brak filtra SVG o indeksie {k} +@msg no arrowheads file here tu nie ma pliku grotów strzałek +@msg no character has code {code} żaden znak nie ma kodu {code} +@msg no custom arrowhead {name} (see stroke.arrowheads.list) brak niestandardowego grotu strzałki {name} (patrz stroke.arrowheads.list) +@msg no file to open brak pliku do otwarcia +@msg no instructions brak instrukcji +@msg no layer to rename brak warstwy do zmiany nazwy +@msg no random numbers ({e}) brak liczb losowych ({e}) +@msg no selected or given object has a visible 3D effect żaden zaznaczony ani podany obiekt nie ma widocznego efektu 3D +@msg no such artboard {v} brak takiego obszaru kompozycji {v} +@msg no symbol named `{_1}` brak symbolu o nazwie `{_1}` +@msg node {_1} already has the text variable `{_2}` węzeł {_1} ma już zmienną tekstową `{_2}` +@msg not a DCS file to nie jest plik DCS +@msg not a RegExp object to nie jest obiekt RegExp +@msg not a regular expression to nie jest wyrażenie regularne +@msg not an action set: the text doesn't start with /version and a number to nie jest zestaw operacji: tekst nie zaczyna się od /version i liczby +@msg nothing to repeat brak elementu do powtórzenia +@msg numbers out of order in {_1} quantifier liczby w niewłaściwej kolejności w kwantyfikatorze {_1} +@msg object {_1} needs a 3D effect obiekt {_1} wymaga efektu 3D +@msg object {_1}: a hollow Extrude & Bevel has no caps: turn on Cap to map a graphic obiekt {_1}: puste w środku Wyciągnięcie i fazowanie nie ma zakończeń: włącz opcję Zakończenie, aby odwzorować grafikę +@msg object {_1}: with a depth of 0 the object has one face: map its graphics onto the front obiekt {_1}: przy głębokości 0 obiekt ma jedną ścianę: odwzoruj jego grafiki na przodzie +@msg object {_1}: {_2} obiekt {_1}: {_2} +@msg object {_1}: {e} obiekt {_1}: {e} +@msg object {_1}: {name} at index {index} has no lighting presets; set its lights with effect.setParams obiekt {_1}: {name} o indeksie {index} nie ma ustawień oświetlenia; ustaw jego światła poleceniem effect.setParams +@msg opacity must be a number opacity musi być liczbą +@msg operand too large operand jest zbyt duży +@msg order is a whole number from 0 to {others}, not `{v}` order to liczba całkowita od 0 do {others}, a nie `{v}` +@msg path chunks must share their boundary point fragmenty ścieżki muszą mieć wspólny punkt graniczny +@msg pdfCompatible: false needs the artboards to keep the editable artwork when useArtboards is false pdfCompatible: false wymaga obszarów kompozycji, aby zachować edytowalną grafikę, gdy useArtboards ma wartość false +@msg point x must be a number współrzędna x punktu musi być liczbą +@msg point y must be a number współrzędna y punktu musi być liczbą +@msg points must be [x,y] pairs points musi zawierać pary [x,y] +@msg points must be finite canvas points points musi zawierać skończone punkty płótna +@msg range out of order in character class zakres w niewłaściwej kolejności w klasie znaków +@msg reduce of an empty array with no initial value reduce na pustej tablicy bez wartości początkowej +@msg regular expression flag '{_1}' given twice flagę wyrażenia regularnego '{_1}' podano dwa razy +@msg sampled text would exceed the canvas (coordinates out of range) próbkowany tekst wykroczyłby poza płótno (współrzędne poza zakresem) +@msg select an SVG filter zaznacz filtr SVG +@msg select an object with a 3D effect zaznacz obiekt z efektem 3D +@msg select an object with a 3D effect, or give its id in ids zaznacz obiekt z efektem 3D albo podaj jego identyfikator w ids +@msg select one layer, group or object to rename zaznacz jedną warstwę, grupę lub obiekt, aby zmienić nazwę +@msg select the art to weed zaznacz grafikę do wybierania +@msg select the banner, or mark every artboard zaznacz baner albo oznacz każdy obszar kompozycji +@msg select type on a path or area type zaznacz tekst na ścieżce lub tekst akapitowy +@msg side is left or right, not `{v}` side ma wartość left lub right, a nie `{v}` +@msg source text transform is collapsed or unrepresentable przekształcenie tekstu źródłowego jest zdegenerowane lub nie da się go przedstawić +@msg table must be true or false table musi mieć wartość true lub false +@msg takes one name przyjmuje jedną nazwę +@msg target text transform is collapsed or unrepresentable przekształcenie tekstu docelowego jest zdegenerowane lub nie da się go przedstawić +@msg that makes too many pieces (at most 100000) or dash steps: simplify the dash pattern or make the dashes longer to daje za dużo części (najwyżej 100000) lub kroków kresek: uprość wzór kresek albo wydłuż kreski +@msg the Layers panel is not shown panel Warstwy nie jest wyświetlany +@msg the Layers panel's search, filter or Show Layers Only hides its row wyszukiwanie, filtr lub opcja Pokaż tylko warstwy w panelu Warstwy ukrywa jego wiersz +@msg the Objects on Path group is hidden or locked grupa Obiekty na ścieżce jest ukryta lub zablokowana +@msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes plik SVG jest większy niż {MAX_IMPORT_BYTES} bajtów +@msg the XML operation needs an XML or XMLList value operacja XML wymaga wartości XML lub XMLList +@msg the XPath expression does not evaluate to a node-set wyrażenie XPath nie daje w wyniku zbioru węzłów +@msg the XPath expression ends early wyrażenie XPath kończy się przedwcześnie +@msg the XPath expression has an unmatched ) wyrażenie XPath zawiera niesparowany znak ) +@msg the XPath expression has an unmatched ] wyrażenie XPath zawiera niesparowany znak ] +@msg the XPath expression has an unmatched closing bracket wyrażenie XPath zawiera niesparowany nawias zamykający +@msg the XPath expression selects a namespace node, which is not an XML value wyrażenie XPath wybiera węzeł przestrzeni nazw, który nie jest wartością XML +@msg the XPath expression selects the root node, which is not an XML value wyrażenie XPath wybiera węzeł główny, który nie jest wartością XML +@msg the XPath function {name} needs a node-set funkcja XPath {name} wymaga zbioru węzłów +@msg the XPath function {name} takes the wrong number of arguments funkcja XPath {name} przyjmuje inną liczbę argumentów +@msg the XPath name functions need a node-set funkcje nazw XPath wymagają zbioru węzłów +@msg the XPath prefix {shown} is not bound to a namespace prefiks XPath {shown} nie jest powiązany z przestrzenią nazw +@msg the XPath variable ${shown} is not bound zmienna XPath ${shown} nie jest powiązana +@msg the argument list is not an object lista argumentów nie jest obiektem +@msg the artwork is too large for EPS: what follows 256 MB of PostScript was left out grafika jest zbyt duża dla formatu EPS: pominięto wszystko po 256 MB kodu PostScript +@msg the banner has no width or height baner nie ma szerokości lub wysokości +@msg the bitmaps hold more pixels than one file may bitmapy zawierają więcej pikseli, niż może mieścić jeden plik +@msg the code runs past its last instruction kod wykracza poza swoją ostatnią instrukcję +@msg the curve tolerance must be from 0.01 to 10 points tolerancja krzywych musi mieścić się w zakresie od 0,01 do 10 punktów +@msg the custom dictionary couldn't be saved to {_1}: {e} nie udało się zapisać słownika użytkownika w {_1}: {e} +@msg the custom dictionary {_1} can't be read ({why}), so it is left as it is nie można odczytać słownika użytkownika {_1} ({why}), więc pozostaje on bez zmian +@msg the document already has an SVG filter named {name} dokument ma już filtr SVG o nazwie {name} +@msg the document has another SVG filter named {name}: use svgFilter.apply, or svgFilter.define with `replace` to edit it dokument ma inny filtr SVG o nazwie {name}: użyj svgFilter.apply albo svgFilter.define z `replace`, aby go edytować +@msg the document has no SVG filter named {name} dokument nie ma filtra SVG o nazwie {name} +@msg the document has no SVG filter named {r} dokument nie ma filtra SVG o nazwie {r} +@msg the document has no color swatches dokument nie ma próbek kolorów +@msg the document's swatches hold {_1} colors; the document reduction takes at most 255 próbki dokumentu zawierają {_1} kolorów; redukcja document przyjmuje najwyżej 255 +@msg the file isn't valid SVG: {e} plik nie jest prawidłowym plikiem SVG: {e} +@msg the file names no plate plik nie wymienia żadnej płyty +@msg the function's prototype is not an object prototyp funkcji nie jest obiektem +@msg the grommet inset is too large for the banner odległość oczek od krawędzi jest zbyt duża dla banera +@msg the guide is hidden or locked linia pomocnicza jest ukryta lub zablokowana +@msg the hem is too deep for the banner obszycie jest zbyt głębokie dla banera +@msg the library's file is outside the read roots plik biblioteki znajduje się poza katalogami głównymi odczytu +@msg the line is too long, or the paths it passes too many, to check linia jest zbyt długa albo mija zbyt wiele ścieżek, aby ją sprawdzić +@msg the method needs an XML value metoda wymaga wartości XML +@msg the paint is not a freeform gradient (apply one with paint.editGradient {kind}) malowanie obiektu nie jest gradientem dowolnym (zastosuj go poleceniem paint.editGradient {kind}) +@msg the parameters or body do not form one function parametry lub treść nie tworzą jednej funkcji +@msg the pasted SVG filter {name} draws differently from the document's filter of that name, and no free name fits it wklejony filtr SVG {name} rysuje inaczej niż filtr dokumentu o tej nazwie, a nie znaleziono dla niego wolnej nazwy +@msg the paths are too many or too tangled to find where they cross ścieżek jest zbyt wiele lub są zbyt splątane, aby znaleźć miejsca ich przecięć +@msg the pen table holds more than 255 pens tabela pisaków zawiera więcej niż 255 pisaków +@msg the plates can't be kept nie można zachować płyt +@msg the position table does not match the instructions tabela pozycji nie odpowiada instrukcjom +@msg the prompt's text is longer than {MAX_PROMPT_BYTES} bytes tekst okna prompt jest dłuższy niż {MAX_PROMPT_BYTES} bajtów +@msg the radix must be between 2 and 36 podstawa systemu liczbowego musi mieścić się w zakresie od 2 do 36 +@msg the rectangle or line reaches too many paths to check prostokąt lub linia sięga zbyt wielu ścieżek, aby je sprawdzić +@msg the right side of 'in' is not an object prawa strona operatora 'in' nie jest obiektem +@msg the right side of 'instanceof' is not a function prawa strona operatora 'instanceof' nie jest funkcją +@msg the selected art is nested more than {MAX_DEPTH} levels deep zaznaczona grafika jest zagnieżdżona głębiej niż na {MAX_DEPTH} poziomów +@msg the selected art is too large to measure zaznaczona grafika jest zbyt duża, aby ją zmierzyć +@msg the selection has no outlines to weed around zaznaczenie nie ma konturów, wokół których można wybierać +@msg the spacing makes more than {MAX_GROMMETS} grommets odstęp daje więcej niż {MAX_GROMMETS} oczek +@msg the value bind was called on is not a function wartość, na której wywołano bind, nie jest funkcją +@msg the value is not a constructor wartość nie jest konstruktorem +@msg the value is not a function wartość nie jest funkcją +@msg the value is not a valid XML name wartość nie jest prawidłową nazwą XML +@msg the value is not an XML attribute name wartość nie jest nazwą atrybutu XML +@msg the value is not an XML name wartość nie jest nazwą XML +@msg the weeding lines cross the art's outlines too many times to measure; use fewer lines linie do wybierania przecinają kontury grafiki zbyt wiele razy, aby to zmierzyć; użyj mniejszej liczby linii +@msg the weeding lines pass too close to too many outline segments to measure; use fewer lines or a smaller gap linie do wybierania przebiegają zbyt blisko zbyt wielu segmentów konturu, aby to zmierzyć; użyj mniejszej liczby linii lub mniejszego odstępu +@msg the weeding lines would be more than {max_pieces} pieces linie do wybierania składałyby się z więcej niż {max_pieces} części +@msg the {_1} plate lies outside the file płyta {_1} leży poza plikiem +@msg there is no banner to mark nie ma banera do oznaczenia +@msg this is a binary DXF file, which can't be read: save it from the CAD app as an ASCII DXF and open that to binarny plik DXF, którego nie można odczytać: zapisz go w programie CAD jako ASCII DXF i otwórz ten plik +@msg this warp's points can't be edited: use Reset with Mesh first punktów tego wypaczenia nie można edytować: najpierw użyj polecenia Resetuj z siatką +@msg toExponential() digits must be between 0 and 20 liczba cyfr w toExponential() musi mieścić się w zakresie od 0 do 20 +@msg toFixed() digits must be between 0 and 20 liczba cyfr w toFixed() musi mieścić się w zakresie od 0 do 20 +@msg toISOString is not a function toISOString nie jest funkcją +@msg toPrecision() argument must be between 1 and 21 argument toPrecision() musi mieścić się w zakresie od 1 do 21 +@msg toSource: a getter cannot be written as source toSource: gettera nie można zapisać jako kodu źródłowego +@msg toSource: an array with properties besides its elements, a property that is not enumerable or another prototype cannot be written as source toSource: tablicy z właściwościami innymi niż jej elementy, z właściwością niewyliczalną lub z innym prototypem nie można zapisać jako kodu źródłowego +@msg toSource: an object with a property that is not enumerable, or whose prototype is not Object.prototype, cannot be written as source toSource: obiektu z właściwością niewyliczalną lub z prototypem innym niż Object.prototype nie można zapisać jako kodu źródłowego +@msg toSource: the source is too long toSource: kod źródłowy jest zbyt długi +@msg toSource: the value contains itself toSource: wartość zawiera samą siebie +@msg toSource: the value has too many entries toSource: wartość ma zbyt wiele wpisów +@msg toSource: the value is nested too deep toSource: wartość jest zbyt głęboko zagnieżdżona +@msg toString is not a function toString nie jest funkcją +@msg too many arguments zbyt wiele argumentów +@msg too many quantifiers zbyt wiele kwantyfikatorów +@msg turn on at least one side włącz co najmniej jedną stronę +@msg unknown OpenType feature `{t}` (liga, calt, dlig, smcp, frac, onum, tnum, ordn, swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom, aalt; prefix - to turn off; swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom and aalt take an alternate's number as `tag=N` with N from 0 to {_1}, as `salt=2`) nieznana funkcja OpenType `{t}` (liga, calt, dlig, smcp, frac, onum, tnum, ordn, swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom, aalt; prefiks - wyłącza funkcję; swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom i aalt przyjmują numer wariantu w postaci `tag=N`, gdzie N to liczba od 0 do {_1}, na przykład `salt=2`) +@msg unknown dither `{d}` (diffusion, pattern, noise or none) nieznane rozpraszanie `{d}` (diffusion, pattern, noise lub none) +@msg unknown panel `{panel}` nieznany panel `{panel}` +@msg unknown parameter `{key}` nieznany parametr `{key}` +@msg unknown parameter `{within}settings.{format}`; {why} nieznany parametr `{within}settings.{format}`; {why} +@msg unknown parameter `{within}{key}`; {why} nieznany parametr `{within}{key}`; {why} +@msg unknown reduction `{reduction}` (selective, perceptual, adaptive, web, gray, blackWhite, uniform or document) nieznana redukcja `{reduction}` (selective, perceptual, adaptive, web, gray, blackWhite, uniform lub document) +@msg unmatched ')' niesparowany znak ')' +@msg unterminated character class niezakończona klasa znaków +@msg unterminated group niezakończona grupa +@msg with no hem and no grommets there is nothing to mark bez obszycia i bez oczek nie ma czego oznaczać +@msg wordGap and lineGap need area type in the selection wordGap i lineGap wymagają tekstu akapitowego w zaznaczeniu +@msg xpath needs its variables as an object xpath wymaga zmiennych w postaci obiektu +@msg xpath needs the expression as a string xpath wymaga wyrażenia w postaci ciągu znaków +@msg {GRANT_NOT_REMOVED}, and its settings and cache can't be moved back from {_1} to {_2}: {e} {GRANT_NOT_REMOVED}, a jej ustawień i pamięci podręcznej nie można przenieść z powrotem z {_1} do {_2}: {e} +@msg {_1} is not a folder: {e} {_1} nie jest folderem: {e} +@msg {_1}: {_2} and {_3} are in the way {_1}: przeszkadzają {_2} i {_3} +@msg {code}: {0} {code}: {0} +@msg {dir}: {e} {dir}: {e} +@msg {file} names more than one linked JavaScript file {file} wskazuje więcej niż jeden połączony plik JavaScript +@msg {k}: a custom arrowhead's path needs an area to fill and at most {most} anchors and {most} subpaths, each anchor within {far} head units of its tip {k}: ścieżka niestandardowego grotu strzałki wymaga obszaru do wypełnienia oraz najwyżej {most} punktów kontrolnych i {most} ścieżek podrzędnych, a każdy punkt kontrolny musi leżeć najwyżej {far} jednostek grotu od jego wierzchołka +@msg {k}: bad custom arrowhead path: {e} {k}: nieprawidłowa ścieżka niestandardowego grotu strzałki: {e} +@msg {k}: bad custom arrowhead: {e} {k}: nieprawidłowy niestandardowy grot strzałki: {e} +@msg {k}: custom must be a name {k}: custom musi być nazwą +@msg {name} must be a number {name} musi być liczbą +@msg {path}: copy takes a DCS file only when its plates are inside it; relink to it where its plate files are {path}: kopiowanie przyjmuje plik DCS tylko wtedy, gdy zawiera on swoje płyty; połącz go ponownie w miejscu, w którym znajdują się pliki jego płyt +@msg {path}: larger than {_1} MB {path}: rozmiar większy niż {_1} MB +@msg {saving} failed: {e} {saving}: niepowodzenie: {e} +@msg {shown} is not an XPath 1.0 function {shown} nie jest funkcją XPath 1.0 +@msg {v} names no layer or sublayer {v} nie wskazuje żadnej warstwy ani podwarstwy +@msg {what} is not a function {what} nie jest funkcją +@msg {what} would print more than {MAX_COPIES_PER_SHEET} copies on a sheet: scale it up {what}: na arkuszu zostałoby wydrukowanych ponad {MAX_COPIES_PER_SHEET} kopii: zwiększ skalę +@msg {what} {i} out of range {what} {i} poza zakresem +@msg A profile supports one Revolve effect. Edit the existing effect's options instead. Profil obsługuje jeden efekt Obrót. Zamiast tego edytuj opcje istniejącego efektu. +@msg Add Points at Crossings: a path went missing Dodaj punkty na skrzyżowaniach: brakuje ścieżki +@msg CSS options: {e} Opcje CSS: {e} +@msg CSV has a header but no data rows Plik CSV ma nagłówek, ale nie ma wierszy danych +@msg CSV holds NUL bytes: save it as UTF-8, or as UTF-16 with a byte-order mark Plik CSV zawiera bajty NUL: zapisz go jako UTF-8 albo jako UTF-16 ze znacznikiem kolejności bajtów +@msg CSV is empty Plik CSV jest pusty +@msg CSV is larger than {MAX_CSV_BYTES} bytes Plik CSV jest większy niż {MAX_CSV_BYTES} bajtów +@msg CSV is not UTF-16 Plik CSV nie jest w kodowaniu UTF-16 +@msg CSV is not UTF-8 Plik CSV nie jest w kodowaniu UTF-8 +@msg CSV would be larger than {MAX_CSV_BYTES} bytes Plik CSV byłby większy niż {MAX_CSV_BYTES} bajtów +@msg Contour: select paths or shapes Kontur: zaznacz ścieżki lub kształty +@msg Contour: the Offset Path effect is not available Kontur: efekt Odsuń ścieżkę nie jest dostępny +@msg Create needs fills, strokes or both Tworzenie wymaga wypełnień, obrysów lub obu +@msg DXF options: {e} Opcje DXF: {e} +@msg DXF scale must be a positive number up to {_1}, not {scale} Skala DXF musi być liczbą dodatnią nie większą niż {_1}, a nie {scale} +@msg DXF {field} `{s}`: {allowed} DXF {field} `{s}`: {allowed} +@msg Draw Inside needs exactly one selected path, compound path or text Rysuj wewnątrz wymaga dokładnie jednej zaznaczonej ścieżki, ścieżki złożonej lub tekstu +@msg EPS Save writes all artwork: use document.export for selected-only EPS Zapis EPS obejmuje całą grafikę: użyj document.export, aby zapisać w EPS tylko zaznaczenie +@msg EPS flattener: {e} Spłaszczanie EPS: {e} +@msg EPS options: {e} Opcje EPS: {e} +@msg EPS {field} `{s}`: {allowed} EPS {field} `{s}`: {allowed} +@msg Export for Screens writes png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai or vectorcraft Eksportuj na ekrany zapisuje formaty png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai lub vectorcraft +@msg Flare click coordinates must be finite numbers Współrzędne kliknięcia rozbłysku muszą być liczbami skończonymi +@msg HTML Text applies to object slices of type only Tekst HTML dotyczy tylko plasterków obiektów tekstowych +@msg Identify Objects By is XML ID: the name must be a valid XML ID (start with a letter, underscore or colon; no spaces) Opcja Identyfikuj obiekty według ma wartość ID XML: nazwa musi być prawidłowym ID XML (zaczynać się od litery, podkreślenia lub dwukropka; bez spacji) +@msg Image Trace failed: internal error: its thread stopped (please report this bug) Obrys obrazu nie powiódł się: błąd wewnętrzny: jego wątek został zatrzymany (zgłoś ten błąd) +@msg Image Trace failed: {e} Obrys obrazu nie powiódł się: {e} +@msg Image Trace finished, but its document was closed Obrys obrazu został ukończony, ale jego dokument został zamknięty +@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Obrys obrazu został ukończony, ale obraz lub jego ustawienia zmieniły się w międzyczasie: obrysuj go ponownie +@msg Join: a subpath went missing Połącz: brakuje ścieżki podrzędnej +@msg Lock Workspace is not available in VectorCraft Polecenie Zablokuj obszar roboczy nie jest dostępne w programie VectorCraft +@msg Move Panel to New Window is not available: floating panels stay in the main window Polecenie Przenieś panel do nowego okna nie jest dostępne: panele pływające pozostają w oknie głównym +@msg Offset Path: the path is too complex to offset Odsuń ścieżkę: ścieżka jest zbyt złożona, aby ją odsunąć +@msg Offset Path: {e} Odsuń ścieżkę: {e} +@msg PDF content is incomplete or exceeds the reader's limits; no document was imported Zawartość PDF jest niekompletna lub przekracza limity czytnika; nie zaimportowano żadnego dokumentu +@msg PDF flattener: {e} Spłaszczanie PDF: {e} +@msg PDF options: {e} Opcje PDF: {e} +@msg Recolor Artwork is no longer open Okno Zmień kolory kompozycji nie jest już otwarte +@msg SVG is not UTF-8, UTF-16 or ISO 8859-1 SVG nie jest w kodowaniu UTF-8, UTF-16 ani ISO 8859-1 +@msg Save writes one artboard: name one, or export several with document.export Zapis obejmuje jeden obszar kompozycji: wskaż jeden albo wyeksportuj kilka poleceniem document.export +@msg Select a dimension first Najpierw zaznacz wymiar +@msg Select dimensions to update Zaznacz wymiary do zaktualizowania +@msg Select only dimensions Zaznacz tylko wymiary +@msg Select two or more objects, or a group Zaznacz co najmniej dwa obiekty albo grupę +@msg Shaper needs 1–64 source paths Kształtowanie wymaga od 1 do 64 ścieżek źródłowych +@msg Switch x/y is for scatter graphs Zamień x/y dotyczy wykresów punktowych +@msg Text options: {e} Opcje tekstu: {e} +@msg `align` is start, center or end `align` ma wartość start, center lub end +@msg `anchors` must be an array of [subpath, anchor] pairs `anchors` musi być tablicą par [subpath, anchor] +@msg `anchors` must list anchor indices (0, 1, 2…), not {k} `anchors` musi zawierać indeksy punktów kontrolnych (0, 1, 2…), a nie {k} +@msg `anchors` must list anchor indices (0, 1, 2…), not {v} `anchors` musi zawierać indeksy punktów kontrolnych (0, 1, 2…), a nie {v} +@msg `artboards` must be a list of artboard indices `artboards` musi być listą indeksów obszarów kompozycji +@msg `asset` is the asset id (see assets.list) `asset` to identyfikator zasobu (patrz assets.list) +@msg `at` must be a byte offset `at` musi być przesunięciem w bajtach +@msg `autoLeading` must be a number `autoLeading` musi być liczbą +@msg `background` must be "", "matte" or #rrggbb `background` musi mieć wartość "", "matte" lub #rrggbb +@msg `burasagari` must be "none", "standard" or "forced" `burasagari` musi mieć wartość "none", "standard" lub "forced" +@msg `center` must be [x, y] `center` musi mieć postać [x, y] +@msg `charAlign` must be "romanBaseline", "emBoxTop", "emBoxCenter", "emBoxBottom", "icfTop" or "icfBottom" `charAlign` musi mieć wartość "romanBaseline", "emBoxTop", "emBoxCenter", "emBoxBottom", "icfTop" lub "icfBottom" +@msg `charDirection` must be "default", "leftToRight" or "rightToLeft" `charDirection` musi mieć wartość "default", "leftToRight" lub "rightToLeft" +@msg `clearStroke` requires `stroke: false`, `ids: []` and no `stop` `clearStroke` wymaga `stroke: false`, `ids: []` i braku `stop` +@msg `clear` must be a list of type object ids, not {v} `clear` musi być listą identyfikatorów obiektów tekstowych, a nie {v} +@msg `clear` must list type objects; {_1} is not one `clear` musi zawierać obiekty tekstowe; {_1} nim nie jest +@msg `clear` must not list `id` `clear` nie może zawierać `id` +@msg `color` needs a `rule` to make the theme from `color` wymaga `rule`, na podstawie której powstaje motyw +@msg `colors` is empty `colors` jest puste +@msg `columnType` is vertical, uniform, repeating or sliding `columnType` ma wartość vertical, uniform, repeating lub sliding +@msg `columns` must be a whole number 1..50 `columns` musi być liczbą całkowitą z zakresu 1..50 +@msg `commands` must not be empty `commands` nie może być puste +@msg `contents` goes with `to` `contents` występuje razem z `to` +@msg `corners` must be sharp, round or square, not `{other}` `corners` musi mieć wartość sharp, round lub square, a nie `{other}` +@msg `corners` must list anchor indices (0, 1, 2…), not {v} `corners` musi zawierać indeksy punktów kontrolnych (0, 1, 2…), a nie {v} +@msg `count` must be a whole number from 1 to 100 `count` musi być liczbą całkowitą od 1 do 100 +@msg `dataBase64` is larger than the module limit `dataBase64` przekracza limit rozmiaru modułu +@msg `dataBase64` is not valid base64 `dataBase64` nie jest prawidłowym kodem base64 +@msg `defaultsOnly` cannot be combined with `ids`, `reverse` or `append` `defaultsOnly` nie można łączyć z `ids`, `reverse` ani `append` +@msg `depth` and `childLimit` slice the summary: pass `summary: true` `depth` i `childLimit` ograniczają podsumowanie: przekaż `summary: true` +@msg `design` is a design name, or null for plain columns `design` to nazwa wzoru albo null dla zwykłych kolumn +@msg `design` is a design name, or null for the default marker `design` to nazwa wzoru albo null dla domyślnego znacznika +@msg `destinationFolder` is required when destination is `folder` `destinationFolder` jest wymagane, gdy destination ma wartość `folder` +@msg `destination` must be `none`, `saveAndClose` or `folder` `destination` musi mieć wartość `none`, `saveAndClose` lub `folder` +@msg `diameter` must be from 0.1 to 2500 pt `diameter` musi mieścić się w zakresie od 0,1 do 2500 pt +@msg `digits` must be one of {_1} `digits` musi mieć jedną z wartości: {_1} +@msg `dimImages` is a percentage or false `dimImages` to wartość procentowa albo false +@msg `direction` must be "auto", "leftToRight" or "rightToLeft" `direction` musi mieć wartość "auto", "leftToRight" lub "rightToLeft" +@msg `each` is the value one design stands for, more than 0 `each` to wartość, którą reprezentuje jeden wzór, większa od 0 +@msg `end` must be "start" or "end" `end` musi mieć wartość "start" lub "end" +@msg `ends` applies to joining exactly two paths `ends` dotyczy łączenia dokładnie dwóch ścieżek +@msg `event` must be one of {_1} `event` musi mieć jedną z wartości: {_1} +@msg `every` must be "all", "odd" or "even", not {v} `every` musi mieć wartość "all", "odd" lub "even", a nie {v} +@msg `expand` must be true or false `expand` musi mieć wartość true lub false +@msg `files` must be 1 to 1000 paths of font files the last text.findFontFiles search found `files` musi zawierać od 1 do 1000 ścieżek plików czcionek znalezionych przez ostatnie wyszukiwanie text.findFontFiles +@msg `folder` must be an absolute folder path `folder` musi być bezwzględną ścieżką folderu +@msg `fontAxes` must be an object of axis tags and values, such as {"wght"} `fontAxes` musi być obiektem ze znacznikami osi i wartościami, na przykład {"wght"} +@msg `format` must be a string `format` musi być ciągiem znaków +@msg `format` must be one of {_1} `format` musi mieć jedną z wartości: {_1} +@msg `fractions` is chop or scale `fractions` ma wartość chop lub scale +@msg `from` and `to` must differ `from` i `to` muszą się różnić +@msg `from` has an empty frame `from` ma pustą ramkę +@msg `from` must be a non-negative integer `from` musi być nieujemną liczbą całkowitą +@msg `from` must be area type or type on a path `from` musi być tekstem akapitowym lub tekstem na ścieżce +@msg `gid` must be a glyph id, not {v} `gid` musi być identyfikatorem glifu, a nie {v} +@msg `glyphAlternate` belongs to one character, not to a character style (text.setGlyphAlternate sets it) `glyphAlternate` należy do jednego znaku, a nie do stylu znakowego (ustawia go text.setGlyphAlternate) +@msg `guide` must be a guide index (guide.list) `guide` musi być indeksem linii pomocniczej (guide.list) +@msg `hAlign` must be default, left, center or right `hAlign` musi mieć wartość default, left, center lub right +@msg `id` must be a node id `id` musi być identyfikatorem węzła +@msg `id` must be an object id, not {v} `id` musi być identyfikatorem obiektu, a nie {v} +@msg `ids` must name Objects on Path groups or objects in them `ids` musi wskazywać grupy Obiekty na ścieżce lub należące do nich obiekty +@msg `ids` takes at most {MAX_INSPECT_IDS} ids `ids` przyjmuje najwyżej {MAX_INSPECT_IDS} identyfikatorów +@msg `imageMap` must be none, rectangle or polygon `imageMap` musi mieć wartość none, rectangle lub polygon +@msg `includeArtboardFill` must be true or false `includeArtboardFill` musi mieć wartość true lub false +@msg `includeSubdirs` must be true or false `includeSubdirs` musi mieć wartość true lub false +@msg `index` must be a point index `index` musi być indeksem punktu +@msg `index` must be a whole number or null `index` musi być liczbą całkowitą lub null +@msg `indices` must be a non-empty array of item indices `indices` musi być niepustą tablicą indeksów elementów +@msg `items` is a list of {kind, item} `items` to lista elementów {kind, item} +@msg `items` is empty `items` jest puste +@msg `items` must be a list of {id, points} `items` musi być listą elementów {id, points} +@msg `items` must be a list of {{id, anchors?}}, not {v} `items` musi być listą elementów {{id, anchors?}}, a nie {v} +@msg `items` must be an array of {id, anchors} `items` musi być tablicą elementów {id, anchors} +@msg `items` must be an array of {{id, corners?}}, not {v} `items` musi być tablicą elementów {{id, corners?}}, a nie {v} +@msg `kashida` must be "none", "short", "medium", "long" or "stylistic" `kashida` musi mieć wartość "none", "short", "medium", "long" lub "stylistic" +@msg `kind` is one of {_1} `kind` ma jedną z wartości: {_1} +@msg `kind` must be "round", "invertedRound" or "chamfer", not {v} `kind` musi mieć wartość "round", "invertedRound" lub "chamfer", a nie {v} +@msg `kind` must be `text`, `visibility`, `image` or `graph` `kind` musi mieć wartość `text`, `visibility`, `image` lub `graph` +@msg `kind` must be a string `kind` musi być ciągiem znaków +@msg `kind` must be image, noImage or htmlText `kind` musi mieć wartość image, noImage lub htmlText +@msg `kinsoku` must be "none", "hard" or "soft" `kinsoku` musi mieć wartość "none", "hard" lub "soft" +@msg `label` must be a non-empty name of at most 200 characters `label` musi być niepustą nazwą o długości najwyżej 200 znaków +@msg `language` must be a language name or tag, such as "Turkish" or "tr" `language` musi być nazwą lub znacznikiem języka, na przykład "Turkish" lub "tr" +@msg `leadingModel` must be "romanBaseline" or "emBoxTop" `leadingModel` musi mieć wartość "romanBaseline" lub "emBoxTop" +@msg `leading` must be from 0.1 to 5000, or null for Auto `leading` musi mieścić się w zakresie od 0,1 do 5000 albo mieć wartość null dla interlinii automatycznej +@msg `length` must be a number of at most 1000000 pt either way `length` musi być liczbą nie większą niż 1000000 pt w każdą stronę +@msg `line` must be true or false `line` musi mieć wartość true lub false +@msg `minAngle` ({min_angle}°) can't be more than `maxAngle` ({max_angle}°) `minAngle` ({min_angle}°) nie może być większe niż `maxAngle` ({max_angle}°) +@msg `mode` must be "handles", "straight" or "smooth" `mode` musi mieć wartość "handles", "straight" lub "smooth" +@msg `mode` must be "straight", "bezier" or "arc" `mode` musi mieć wartość "straight", "bezier" lub "arc" +@msg `mode` must be one of {_1} `mode` musi mieć jedną z wartości: {_1} +@msg `mojikumi` must be "none", "yakumonoHankaku", "gyomatsuYakumonoHankaku", "gyomatsuYakumonoZenkaku", "yakumonoZenkaku" or "lineEndHalf" `mojikumi` musi mieć wartość "none", "yakumonoHankaku", "gyomatsuYakumonoHankaku", "gyomatsuYakumonoZenkaku", "yakumonoZenkaku" lub "lineEndHalf" +@msg `names` is a list of preset names `names` to lista nazw ustawień +@msg `names` lists preset names `names` zawiera nazwy ustawień +@msg `names` must be a list of names `names` musi być listą nazw +@msg `names` must be a list of swatch names `names` musi być listą nazw próbek +@msg `names` must be an array of style names `names` musi być tablicą nazw stylów +@msg `new` is a design name, or true `new` to nazwa wzoru albo true +@msg `path` must be a folder `path` musi być folderem +@msg `path` must be a path object `path` musi być obiektem ścieżki +@msg `pivot` must be a whole number from 0 to 8 `pivot` musi być liczbą całkowitą od 0 do 8 +@msg `points` must be a list of [x, y] points `points` musi być listą punktów [x, y] +@msg `points` must be a list of point indexes `points` musi być listą indeksów punktów +@msg `points` must be an array of point indices `points` musi być tablicą indeksów punktów +@msg `points` must be point indexes `points` musi zawierać indeksy punktów +@msg `port` must be "in" or "out" `port` musi mieć wartość "in" lub "out" +@msg `position` is above or below `position` ma wartość above lub below +@msg `preset` must be a string `preset` musi być ciągiem znaków +@msg `ratio` must be from 0.1 to 0.5 `ratio` musi mieścić się w zakresie od 0,1 do 0,5 +@msg `rect` must be [x, y, width, height] with a positive size `rect` musi mieć postać [x, y, width, height] i dodatni rozmiar +@msg `relation` must be overlap, inside or outside `relation` musi mieć wartość overlap, inside lub outside +@msg `reversed` must be true or false `reversed` musi mieć wartość true lub false +@msg `rotate` must be a finite number `rotate` musi być liczbą skończoną +@msg `rule` must be nonZero or evenOdd `rule` musi mieć wartość nonZero lub evenOdd +@msg `scale` must be a number in (0, 100] `scale` musi być liczbą z przedziału (0, 100] +@msg `scope` must be "selection" or "document", not {other} `scope` musi mieć wartość "selection" lub "document", a nie {other} +@msg `script` must be a string `script` musi być ciągiem znaków +@msg `seriesIndexes` is a non-empty list of series indexes `seriesIndexes` to niepusta lista indeksów serii +@msg `seriesIndexes` needs a `type` or a `valueAxis` `seriesIndexes` wymaga `type` lub `valueAxis` +@msg `shift` must be a number of points `shift` musi być liczbą punktów +@msg `showCenter` must be true or false `showCenter` musi mieć wartość true lub false +@msg `singleWordJustification` must be "fullJustify", "alignLeft", "alignCenter" or "alignRight" `singleWordJustification` musi mieć wartość "fullJustify", "alignLeft", "alignCenter" lub "alignRight" +@msg `size` is a percentage of the base text's size, 1 to 100 `size` to wartość procentowa rozmiaru tekstu podstawowego, od 1 do 100 +@msg `source` and `target` are the same object `source` i `target` to ten sam obiekt +@msg `source` must be `folder` or `datasets` `source` musi mieć wartość `folder` lub `datasets` +@msg `spacing` must be a number `spacing` musi być liczbą +@msg `spacing` must be a number of points, 0 or more, or "auto" `spacing` musi być liczbą punktów równą 0 lub większą albo wartością "auto" +@msg `start` must be a finite number `start` musi być liczbą skończoną +@msg `starts` must be an array of anchor indices (or nulls) `starts` musi być tablicą indeksów punktów kontrolnych (lub wartości null) +@msg `status` must be linked, embedded, missing or modified, or a list of them `status` musi mieć wartość linked, embedded, missing lub modified albo być ich listą +@msg `stop` must be a stop index `stop` musi być indeksem punktu koloru +@msg `story` styles the whole story: give no `start` or `end` `story` nadaje styl całemu tekstowi wątkowemu: nie podawaj `start` ani `end` +@msg `story` takes the whole story: give no `start` or `end` `story` obejmuje cały tekst wątkowy: nie podawaj `start` ani `end` +@msg `strokeMode` applies to strokes (stroke: true) `strokeMode` dotyczy obrysów (stroke: true) +@msg `style` must be roman or japanese `style` musi mieć wartość roman lub japanese +@msg `subpaths` must be two integer indices `subpaths` musi zawierać dwa indeksy całkowite +@msg `symbol` must be a symbol name `symbol` musi być nazwą symbolu +@msg `target` must be "object" or "contents", not {v} `target` musi mieć wartość "object" lub "contents", a nie {v} +@msg `tint` applies to global and spot colours `tint` dotyczy kolorów globalnych i dodatkowych +@msg `tint` goes with a global or spot `swatch` `tint` występuje razem z globalną lub dodatkową próbką `swatch` +@msg `tint` must be a number (%) `tint` musi być liczbą (%) +@msg `tint` needs a global or spot colour `tint` wymaga koloru globalnego lub dodatkowego +@msg `to` is already threaded `to` jest już połączone w wątek +@msg `to` is the design's new name `to` to nowa nazwa wzoru +@msg `to` must be [x, y] `to` musi mieć postać [x, y] +@msg `to` must be a closed path, area type or type on a path other than `from` `to` musi być ścieżką zamkniętą, tekstem akapitowym lub tekstem na ścieżce innym niż `from` +@msg `to` must be a whole number `to` musi być liczbą całkowitą +@msg `to` takes the rows of one object's stack, not aligned rows `to` przyjmuje wiersze stosu jednego obiektu, a nie wiersze wyrównane +@msg `useLab` must be true or false `useLab` musi mieć wartość true lub false +@msg `vAlign` must be default, top, middle, baseline or bottom `vAlign` musi mieć wartość default, top, middle, baseline lub bottom +@msg `values` must be a list `values` musi być listą +@msg `values` must be an object `values` musi być obiektem +@msg `values` must name hex, rgb, cmyk, lab or gray `values` musi wskazywać hex, rgb, cmyk, lab lub gray +@msg `values` names a kind twice `values` wskazuje ten sam rodzaj dwa razy +@msg `{_1}` can't be edited or removed `{_1}` nie można edytować ani usunąć +@msg `{_1}` is built in and always listed `{_1}` jest wbudowane i zawsze widoczne na liście +@msg `{_1}` is not a font file the last text.findFontFiles search found `{_1}` nie jest plikiem czcionki znalezionym przez ostatnie wyszukiwanie text.findFontFiles +@msg `{_1}` would be overwritten by the package: choose a different folder or name `{_1}` zostałoby nadpisane przez pakiet: wybierz inny folder lub inną nazwę +@msg `{file}` has no art to place `{file}` nie zawiera grafiki do umieszczenia +@msg `{file}` is over {_1} MB `{file}` ma ponad {_1} MB +@msg `{f}` belongs to a VectorCraft that is running `{f}` należy do uruchomionego programu VectorCraft +@msg `{f}` is the copy of a document open now `{f}` to kopia otwartego teraz dokumentu +@msg `{id}` is no writable format (see document.formats) `{id}` nie jest formatem z możliwością zapisu (patrz document.formats) +@msg `{id}` isn't a loaded library `{id}` nie jest wczytaną biblioteką +@msg `{key}` has no colours `{key}` nie zawiera kolorów +@msg `{key}` is a design name `{key}` to nazwa wzoru +@msg `{key}` is a design name or a list of them `{key}` to nazwa wzoru lub lista takich nazw +@msg `{key}` is longer than {MAX_NAME} characters `{key}` ma więcej niż {MAX_NAME} znaków +@msg `{key}` is out of range `{key}` jest poza zakresem +@msg `{key}` must be [min, desired, max] or {{min?, desired?, max?}}, in percent `{key}` musi mieć postać [min, desired, max] lub {{min?, desired?, max?}}, w procentach +@msg `{key}` must be a non-negative integer `{key}` musi być nieujemną liczbą całkowitą +@msg `{key}` must be a number {_1}..{_2} `{key}` musi być liczbą z zakresu {_1}..{_2} +@msg `{key}` must be a whole number of at least 0, not {n} `{key}` musi być liczbą całkowitą równą co najmniej 0, a nie {n} +@msg `{key}` must be an appearance item index (paint order) or null `{key}` musi być indeksem elementu wyglądu (kolejność malowania) lub null +@msg `{key}` must be an array of asset ids (see assets.list) `{key}` musi być tablicą identyfikatorów zasobów (patrz assets.list) +@msg `{key}` must be from 0 to 180 degrees, not {a} `{key}` musi mieścić się w zakresie od 0 do 180 stopni, a nie {a} +@msg `{key}` must be from {_1} to {shift_max} `{key}` musi mieścić się w zakresie od {_1} do {shift_max} +@msg `{key}`: not a colour: {v} `{key}`: to nie jest kolor: {v} +@msg `{k}.family` is required `{k}.family` jest wymagane +@msg `{k}` is a number 0..1 `{k}` to liczba z zakresu 0..1 +@msg `{k}` is true or false `{k}` ma wartość true lub false +@msg `{k}` isn't an export setting: {_1} `{k}` nie jest ustawieniem eksportu: {_1} +@msg `{k}` must be a byte offset `{k}` musi być przesunięciem w bajtach +@msg `{k}` must be a number `{k}` musi być liczbą +@msg `{k}` must be a number of points `{k}` musi być liczbą punktów +@msg `{k}` must be a string `{k}` musi być ciągiem znaków +@msg `{k}` must be a whole number `{k}` musi być liczbą całkowitą +@msg `{k}` must be from {lo} to {hi} for {key} `{k}` musi mieścić się w zakresie od {lo} do {hi} dla {key} +@msg `{k}` must be {what}, not {v} `{k}` musi mieć wartość {what}, a nie {v} +@msg `{l}` isn't a global or spot colour `{l}` nie jest kolorem globalnym ani dodatkowym +@msg `{m}` isn't a bitmap: use clipboard.importSvg, importPdf or importText `{m}` nie jest bitmapą: użyj clipboard.importSvg, importPdf lub importText +@msg `{name}` can't be deleted `{name}` nie można usunąć +@msg `{name}` can't be duplicated `{name}` nie można powielić +@msg `{name}` can't be edited `{name}` nie można edytować +@msg `{name}` can't be edited this way `{name}` nie można edytować w ten sposób +@msg `{name}` can't be renamed nazwy `{name}` nie można zmienić +@msg `{name}` can't name a folder `{name}` nie może być nazwą folderu +@msg `{name}` has no art to place `{name}` nie zawiera grafiki do umieszczenia +@msg `{name}` has no text to place `{name}` nie zawiera tekstu do umieszczenia +@msg `{name}` in the Word document is not UTF-8 or UTF-16 text `{name}` w dokumencie Word nie jest tekstem UTF-8 ani UTF-16 +@msg `{name}` in the Word document is not well-formed XML: {e} `{name}` w dokumencie Word nie jest poprawnie sformułowanym kodem XML: {e} +@msg `{name}` in the Word document nests elements more than {MAX_NESTING} deep `{name}` w dokumencie Word zagnieżdża elementy głębiej niż na {MAX_NESTING} poziomów +@msg `{name}` is a built-in preset and is read-only: save it under another name `{name}` to wbudowane ustawienie tylko do odczytu: zapisz je pod inną nazwą +@msg `{name}` is a built-in preset: save under another name `{name}` to wbudowane ustawienie: zapisz pod inną nazwą +@msg `{name}` is a built-in profile and stays `{name}` to wbudowany profil i pozostaje +@msg `{name}` is a tint of `{base}`: edit `{base}` (a tint swatch only takes a new name) `{name}` to tinta koloru `{base}`: edytuj `{base}` (próbka tinty przyjmuje tylko nową nazwę) +@msg `{name}` is a working space: choose another with edit.colorSettings first `{name}` to przestrzeń robocza: najpierw wybierz inną poleceniem edit.colorSettings +@msg `{name}` is built in and stays `{name}` jest wbudowane i pozostaje +@msg `{name}` takes a paint of its own kind (colour, gradient or pattern) `{name}` przyjmuje malowanie własnego rodzaju (kolor, gradient lub wzorek) +@msg `{n}` can't be deleted `{n}` nie można usunąć +@msg `{n}` can't be merged `{n}` nie można scalić +@msg `{n}` can't be moved `{n}` nie można przenieść +@msg `{n}` is not a colour swatch `{n}` nie jest próbką koloru +@msg `{n}` isn't a solid colour `{n}` nie jest kolorem jednolitym +@msg `{n}`: colour groups hold solid colours only `{n}`: grupy kolorów zawierają tylko kolory jednolite +@msg `{other}` doesn't trace an image `{other}` nie obrysowuje obrazu +@msg `{s}`: the step's references copy in more than {_1} MB of values `{s}`: odwołania kroku kopiują ponad {_1} MB wartości +@msg `{tag}` is not an axis tag: a tag is four characters, such as "wght" `{tag}` nie jest znacznikiem osi: znacznik ma cztery znaki, na przykład "wght" +@msg `{to}` is empty or already used `{to}` jest puste lub już używane +@msg `{what}` is longer than {MAX_TEXT} bytes `{what}` ma więcej niż {MAX_TEXT} bajtów +@msg `{what}` must be text `{what}` musi być tekstem +@msg a DXF drawing has one origin: pass useArtboards: true for one drawing per artboard rysunek DXF ma jeden punkt początkowy: przekaż useArtboards: true, aby uzyskać jeden rysunek na obszar kompozycji +@msg a PDF presets file with over {_1} presets plik ustawień PDF zawierający ponad {_1} ustawień +@msg a batch preview cannot switch documents podgląd przetwarzania wsadowego nie może przełączać dokumentów +@msg a brush named `{nn}` exists istnieje już pędzel o nazwie `{nn}` +@msg a container of the listed objects is gone kontener wymienionych obiektów już nie istnieje +@msg a content stream can't be read nie można odczytać strumienia zawartości +@msg a content stream isn't a stream strumień zawartości nie jest strumieniem +@msg a design holds at most {_1} objects wzór zawiera najwyżej {_1} obiektów +@msg a design needs a name wzór wymaga nazwy +@msg a dictionary grew too large słownik stał się zbyt duży +@msg a document keeps at most {_1} graph designs dokument przechowuje najwyżej {_1} wzorów wykresów +@msg a document keeps at most {_1} saved selections dokument przechowuje najwyżej {_1} zapisanych zaznaczeń +@msg a document keeps at most {_1} views dokument przechowuje najwyżej {_1} widoków +@msg a document links at most {MAX_SVG_SCRIPTS} JavaScript files dokument łączy najwyżej {MAX_SVG_SCRIPTS} plików JavaScript +@msg a feConvolveMatrix filter's order is {x}×{y}, which overflows the kernel-size multiply usvg makes rząd filtra feConvolveMatrix wynosi {x}×{y}, co powoduje przepełnienie przy mnożeniu rozmiaru jądra wykonywanym przez usvg +@msg a gradient preset is already called {n} ustawienie gradientu o nazwie {n} już istnieje +@msg a graph has at most {_1} series, so it transposes with at most that many categories wykres ma najwyżej {_1} serii, więc można go transponować przy najwyżej tylu kategoriach +@msg a layer can't be merged into its own sublayer warstwy nie można scalić z jej własną podwarstwą +@msg a layer's form box isn't an array pole ograniczające formularza warstwy nie jest tablicą +@msg a layer's form can't be read nie można odczytać formularza warstwy +@msg a layer's form has no box formularz warstwy nie ma pola ograniczającego +@msg a layer's form has no dictionary formularz warstwy nie ma słownika +@msg a legend draws at most {MAX_CHIPS} swatches legenda rysuje najwyżej {MAX_CHIPS} próbek +@msg a name names one asset: give multiple: false, or one object nazwa wskazuje jeden zasób: podaj multiple: false albo jeden obiekt +@msg a page can't be read nie można odczytać strony +@msg a page object is used by something else obiekt strony jest używany przez coś innego +@msg a page thumbnail must be RGB pixels, 1 to {THUMBNAIL_SIZE} a side (got {w} × {h}) miniatura strony musi składać się z pikseli RGB, od 1 do {THUMBNAIL_SIZE} na bok (podano {w} × {h}) +@msg a pattern layer doesn't end what it starts warstwa wzorka nie kończy tego, co zaczyna +@msg a pattern layer's colors hold something else kolory warstwy wzorka zawierają coś innego +@msg a pattern named `{n}` exists istnieje już wzorek o nazwie `{n}` +@msg a plug-in with id {_1} is already installed wtyczka o ID {_1} jest już zainstalowana +@msg a preset named `{n}` exists istnieje już ustawienie o nazwie `{n}` +@msg a print presets file with over {_1} presets plik ustawień drukowania zawierający ponad {_1} ustawień +@msg a profile is already called {n} profil o nazwie {n} już istnieje +@msg a row can't go into itself wiersza nie można przenieść do niego samego +@msg a series goes on the left or the right value axis seria trafia na lewą lub prawą oś wartości +@msg a start must be an anchor index ≥ 0 or null początek musi być indeksem punktu kontrolnego ≥ 0 lub null +@msg a style named `{name}` already exists styl o nazwie `{name}` już istnieje +@msg a style named `{to}` already exists styl o nazwie `{to}` już istnieje +@msg a swatch needs a colour, gradient or pattern próbka wymaga koloru, gradientu lub wzorka +@msg a symbol named `{n}` already exists symbol o nazwie `{n}` już istnieje +@msg a theme has 1 to {THEME_SIZE} colours motyw ma od 1 do {THEME_SIZE} kolorów +@msg a theme is already called {name} (replace: "{name}" overwrites it) motyw o nazwie {name} już istnieje (replace: "{name}" go nadpisze) +@msg a toolbar name has at most {MAX_NAME} characters nazwa paska narzędzi ma najwyżej {MAX_NAME} znaków +@msg a view named `{_1}` exists istnieje już widok o nazwie `{_1}` +@msg a view named `{name}` exists istnieje już widok o nazwie `{name}` +@msg a workspace keeps at most {MAX} toolbars obszar roboczy przechowuje najwyżej {MAX} pasków narzędzi +@msg a {_1} series can't go in a {_2} graph serii {_1} nie można umieścić na wykresie {_2} +@msg aiVersion {v}: "pdf" (PDF-compatible, the default) or "7" (legacy .ai, version 7) aiVersion {v}: "pdf" (zgodny z PDF, domyślny) lub "7" (starszy format .ai, wersja 7) +@msg already editing an opacity mask trwa już edycja maski krycia +@msg already editing another object's opacity mask trwa już edycja maski krycia innego obiektu +@msg already in pattern editing mode tryb edycji wzorka jest już włączony +@msg an artboard is listed twice obszar kompozycji jest wymieniony dwa razy +@msg an empty artboard has no width or height to scale to pusty obszar kompozycji nie ma szerokości ani wysokości, do których można skalować +@msg an image is too large for DXF and was left out obraz jest zbyt duży dla formatu DXF i został pominięty +@msg an image of {_1} MB, at most {_2} MB obraz o rozmiarze {_1} MB, dozwolone najwyżej {_2} MB +@msg an image of {declared_w} × {declared_h} pixels is too large to draw obraz o wymiarach {declared_w} × {declared_h} pikseli jest zbyt duży, aby go narysować +@msg an image of {width} × {height} pixels is too large to draw obraz o wymiarach {width} × {height} pikseli jest zbyt duży, aby go narysować +@msg an index must be a whole number indeks musi być liczbą całkowitą +@msg an inline graphic has no glyphs grafika w wierszu nie ma glifów +@msg an invisible text form can't be read nie można odczytać formularza niewidocznego tekstu +@msg an object is missing brakuje obiektu +@msg an object's header is missing brakuje nagłówka obiektu +@msg an overprinting form can't be read nie można odczytać formularza z nadrukiem +@msg an unread object has no readable bounds nieodczytany obiekt nie ma odczytywalnych granic +@msg an unread object holds a frame of threaded type nieodczytany obiekt zawiera ramkę tekstu wątkowego +@msg an unread object is missing from its layer nieodczytanego obiektu brakuje w jego warstwie +@msg anchor `smooth` must be true or false `smooth` punktu kontrolnego musi mieć wartość true lub false +@msg anchor `{key}` must be [x, y] `{key}` punktu kontrolnego musi mieć postać [x, y] +@msg anchor `{key}` must be a number `{key}` punktu kontrolnego musi być liczbą +@msg angle and roundness must be finite kąt i okrągłość muszą być skończone +@msg angles must be a list as long as pins (degrees or null) angles musi być listą tej samej długości co pins (stopnie lub null) +@msg appearance must be flat|center|edge appearance musi mieć wartość flat|center|edge +@msg apply is "fill" or "stroke", not `{other}` apply ma wartość "fill" lub "stroke", a nie `{other}` +@msg area must be a closed polygon of 3 to 100000 [x, y] points area musi być zamkniętym wielokątem złożonym z 3 do 100000 punktów [x, y] +@msg area type needs a path that encloses an area tekst akapitowy wymaga ścieżki, która otacza obszar +@msg area type {_1} is named twice tekst akapitowy {_1} wymieniono dwa razy +@msg arrowAlign must be extend|tip, got {o} arrowAlign musi mieć wartość extend|tip, podano {o} +@msg arrowScale must be [start, end] arrowScale musi mieć postać [start, end] +@msg artboard is a 0-based index artboard to indeks liczony od 0 +@msg artboard must be a 0-based index artboard musi być indeksem liczonym od 0 +@msg artboard {i} doesn't print obszar kompozycji {i} nie jest drukowany +@msg artboardLayout must be {layout?, columns?, spacing?, rightToLeft?} artboardLayout musi mieć postać {layout?, columns?, spacing?, rightToLeft?} +@msg artboardLayout.columns must be 1 or more artboardLayout.columns musi wynosić 1 lub więcej +@msg artboardLayout.layout must be gridByRow, gridByColumn, row or column artboardLayout.layout musi mieć wartość gridByRow, gridByColumn, row lub column +@msg artboardLayout.rightToLeft must be true or false artboardLayout.rightToLeft musi mieć wartość true lub false +@msg artboardLayout.spacing must be 0–{MAX_SPACING} pt artboardLayout.spacing musi wynosić 0–{MAX_SPACING} pt +@msg artboards must be a non-empty list artboards musi być niepustą listą +@msg artboards must be a number artboards musi być liczbą +@msg asset `{_1}` has no art to export zasób `{_1}` nie zawiera grafiki do wyeksportowania +@msg at most {MAX_KEYWORDS} keywords najwyżej {MAX_KEYWORDS} słów kluczowych +@msg at most {MAX_MATCHES} matches are kept zachowywanych jest najwyżej {MAX_MATCHES} dopasowań +@msg at most {MAX_POINTS} points najwyżej {MAX_POINTS} punktów +@msg at most {MAX_QUEUE} files najwyżej {MAX_QUEUE} plików +@msg at must be [x, y] at musi mieć postać [x, y] +@msg at/rect lie outside the canvas at/rect leżą poza płótnem +@msg attribute must be size|leading|tracking|kerning|baselineShift attribute musi mieć wartość size|leading|tracking|kerning|baselineShift +@msg attrs must be an object attrs musi być obiektem +@msg automation path rejected: the folder's name isn't valid text odrzucono ścieżkę automatyzacji: nazwa folderu nie jest prawidłowym tekstem +@msg automation path rejected: {_1} isn't valid text odrzucono ścieżkę automatyzacji: {_1} nie jest prawidłowym tekstem +@msg automation path rejected: {why}: {path} odrzucono ścieżkę automatyzacji: {why}: {path} +@msg axis must be "vertical", "horizontal" or an angle in degrees, not `{given}` axis musi mieć wartość "vertical", "horizontal" lub być kątem w stopniach, a nie `{given}` +@msg backgroundContents must be transparent or white backgroundContents musi mieć wartość transparent lub white +@msg bad AES key nieprawidłowy klucz AES +@msg bad `runs`: {e} nieprawidłowe `runs`: {e} +@msg bad arrowScale nieprawidłowe arrowScale +@msg bad base64 nieprawidłowy kod base64 +@msg bad color {c} nieprawidłowy kolor {c} +@msg bad colour nieprawidłowy kolor +@msg bad colour in `colors` nieprawidłowy kolor w `colors` +@msg bad colour {v} nieprawidłowy kolor {v} +@msg bad colour {v} in groupColors nieprawidłowy kolor {v} w groupColors +@msg bad cross-reference entry nieprawidłowy wpis tabeli odsyłaczy +@msg bad cross-reference table nieprawidłowa tabela odsyłaczy +@msg bad current colour {v} nieprawidłowy bieżący kolor {v} +@msg bad dataBase64 nieprawidłowe dataBase64 +@msg bad edit nieprawidłowa edycja +@msg bad fill {v} nieprawidłowe wypełnienie {v} +@msg bad fit: {e} nieprawidłowe dopasowanie: {e} +@msg bad model {other} (keep, new or document) nieprawidłowy model {other} (keep, new lub document) +@msg bad new colour {v} nieprawidłowy nowy kolor {v} +@msg bad object nieprawidłowy obiekt +@msg bad object number nieprawidłowy numer obiektu +@msg bad offset nieprawidłowe przesunięcie +@msg bad path data: {e} nieprawidłowe dane ścieżki: {e} +@msg bad point {v}: expected [x, y] or [x, y, pressure] nieprawidłowy punkt {v}: oczekiwano [x, y] lub [x, y, pressure] +@msg bad reference nieprawidłowe odwołanie +@msg bad trailer size nieprawidłowy rozmiar w sekcji trailer +@msg bad {k} colour nieprawidłowy kolor {k} +@msg batches cannot nest przetwarzania wsadowego nie można zagnieżdżać +@msg bind something to a variable first najpierw powiąż coś ze zmienną +@msg bleed must be 0–{MAX_BLEED} pt: a number, [top, bottom, left, right] or {{top, bottom, left, right}} bleed musi wynosić 0–{MAX_BLEED} pt: liczba, [top, bottom, left, right] lub {{top, bottom, left, right}} +@msg brush must be a name or null brush musi być nazwą lub null +@msg by must be a number by musi być liczbą +@msg can't add page thumbnails: {why} nie można dodać miniatur stron: {why} +@msg can't add the editing data for other apps: {why} nie można dodać danych edycyjnych dla innych aplikacji: {why} +@msg can't edit the written PDF: {why} nie można edytować zapisanego pliku PDF: {why} +@msg can't encrypt the PDF: {why} nie można zaszyfrować pliku PDF: {why} +@msg can't linearise the PDF: {why} nie można zlinearyzować pliku PDF: {why} +@msg can't open `{_1}`: {_2} nie można otworzyć `{_1}`: {_2} +@msg can't open `{_1}`: {e} nie można otworzyć `{_1}`: {e} +@msg can't open `{name}`: not a format VectorCraft reads (see document.formats) nie można otworzyć `{name}`: to nie jest format odczytywany przez VectorCraft (patrz document.formats) +@msg can't place `{name}`: not a format VectorCraft reads (see document.formats) nie można umieścić `{name}`: to nie jest format odczytywany przez VectorCraft (patrz document.formats) +@msg can't read back the written PDF: {e} nie można ponownie odczytać zapisanego pliku PDF: {e} +@msg can't read this Word document: {why} nie można odczytać tego dokumentu Word: {why} +@msg can't write .{e} images: use .png, .jpg, .gif, .webp, .tif or .bmp nie można zapisać obrazów .{e}: użyj .png, .jpg, .gif, .webp, .tif lub .bmp +@msg can't write PDF layers, overprint or invisible text: {why} nie można zapisać warstw PDF, nadruku ani niewidocznego tekstu: {why} +@msg can't write the file's copyright: {why} nie można zapisać informacji o prawach autorskich pliku: {why} +@msg can't write the file's modification date: {why} nie można zapisać daty modyfikacji pliku: {why} +@msg can't write the pages' user units: {why} nie można zapisać jednostek użytkownika stron: {why} +@msg cannot distort a zero-size or non-finite bounding box nie można zniekształcić obwiedni o zerowym lub nieskończonym rozmiarze +@msg cannot move an object into itself nie można przenieść obiektu do niego samego +@msg case must be upper|lower|title|sentence case musi mieć wartość upper|lower|title|sentence +@msg category `{c}`: one of {_1} kategoria `{c}`: jedna z wartości: {_1} +@msg center must be [x, y] center musi mieć postać [x, y] +@msg choose at least one artboard wybierz co najmniej jeden obszar kompozycji +@msg choose at least one status wybierz co najmniej jeden stan +@msg clip must be true or false clip musi mieć wartość true lub false +@msg clippingMask must be true or false clippingMask musi mieć wartość true lub false +@msg closed must be a boolean closed musi być wartością logiczną +@msg collapsed must be true or false collapsed musi mieć wartość true lub false +@msg color.profile: no RGB or CMYK profile is called “{profile}” color.profile: żaden profil RGB ani CMYK nie nosi nazwy „{profile}” +@msg colorMode must be rgb or cmyk, not `{m}` colorMode musi mieć wartość rgb lub cmyk, a nie `{m}` +@msg colorModel must be {own} (the document's mode), grayscale or bitmap colorModel musi mieć wartość {own} (tryb dokumentu), grayscale lub bitmap +@msg colour groups can't go into colour groups grup kolorów nie można umieszczać w grupach kolorów +@msg colour, mode and spot apply to solid-colour swatches only color, mode i spot dotyczą tylko próbek kolorów jednolitych +@msg column {column}: `{cell}` is a `%` column of graph data files, which are not read kolumna {column}: `{cell}` to kolumna `%` plików danych wykresu, które nie są odczytywane +@msg column {column}: `{cell}` names `{name}`, which is a {_1} variable kolumna {column}: `{cell}` wskazuje `{name}`, czyli zmienną typu {_1} +@msg column {column}: `{cell}` names no variable kolumna {column}: `{cell}` nie wskazuje żadnej zmiennej +@msg column {column}: the variable name is longer than {MAX_NAME} characters kolumna {column}: nazwa zmiennej ma więcej niż {MAX_NAME} znaków +@msg column: true floats the whole column and takes no onto, above or below column: true odłącza całą kolumnę i nie przyjmuje onto, above ani below +@msg command must be a shape.* command command musi być poleceniem shape.* +@msg commands[{i}]: missing `command` commands[{i}]: brak `command` +@msg composer must be "singleLine" or "everyLine" composer musi mieć wartość "singleLine" lub "everyLine" +@msg compound shapes take paths, compound paths, groups, compound shapes, type, blends and envelopes kształty złożone przyjmują ścieżki, ścieżki złożone, grupy, kształty złożone, tekst, przejścia i koperty +@msg compound {_1} must contain exactly one open path to join obiekt złożony {_1} musi zawierać dokładnie jedną otwartą ścieżkę do połączenia +@msg connect needs a path other than the one extended connect wymaga ścieżki innej niż przedłużana +@msg connect needs id connect wymaga id +@msg connect path has no open end ścieżka w connect nie ma otwartego końca +@msg copy needs path: the file to copy into the document's folder copy wymaga path: pliku do skopiowania do folderu dokumentu +@msg copy takes images only: relink placed documents where their files are copy przyjmuje tylko obrazy: umieszczone dokumenty połącz ponownie w miejscu, w którym znajdują się ich pliki +@msg copying a file isn't available on the web kopiowanie pliku nie jest dostępne w wersji webowej +@msg copyrightStatus must be unknown, copyrighted or publicDomain copyrightStatus musi mieć wartość unknown, copyrighted lub publicDomain +@msg copyrightUrl must be a URL (no spaces, at most 2048 characters) copyrightUrl musi być adresem URL (bez spacji, najwyżej 2048 znaków) +@msg corners must be 4 [x, y] points (TL, TR, BR, BL) corners musi zawierać 4 punkty [x, y] (TL, TR, BR, BL) +@msg counterPer `{c}`: item or file counterPer `{c}`: item lub file +@msg crop `{_1}`: only PDF pages have art, trim, bleed and media boxes; use "crop" or "bounding" crop `{_1}`: tylko strony PDF mają pola art, trim, bleed i media; użyj "crop" lub "bounding" +@msg crop rectangle doesn't overlap the image prostokąt kadrowania nie pokrywa się z obrazem +@msg cross-reference and object streams aren't supported strumienie odsyłaczy i obiektów nie są obsługiwane +@msg damaged compressed data: {e} uszkodzone dane skompresowane: {e} +@msg dash lengths must be numbers, got {v} długości kresek muszą być liczbami, podano {v} +@msg dash must be a list of lengths or null, got {v} dash musi być listą długości lub null, podano {v} +@msg data key `{k}`: letters, digits, -, _ and . (not name or vc-…) klucz danych `{k}`: litery, cyfry, -, _ i . (nie name ani vc-…) +@msg data must be an object of key: value, not {v} data musi być obiektem w postaci key: value, a nie {v} +@msg data set `{name}` holds a value for `{var}`, which the library doesn't declare zestaw danych `{name}` zawiera wartość dla `{var}`, której biblioteka nie deklaruje +@msg data set `{name}` holds two values for `{var}` zestaw danych `{name}` zawiera dwie wartości dla `{var}` +@msg data set `{name}` is declared twice zestaw danych `{name}` zadeklarowano dwa razy +@msg data takes at most {MAX_DATA} keys at once data przyjmuje najwyżej {MAX_DATA} kluczy naraz +@msg dataset `{name}` already exists zestaw danych `{name}` już istnieje +@msg dataset `{to}` already exists zestaw danych `{to}` już istnieje +@msg date `{d}`: YYYY-MM-DD data `{d}`: YYYY-MM-DD +@msg decoded data is too large zdekodowane dane są zbyt duże +@msg define a variable first najpierw zdefiniuj zmienną +@msg detect must be true or false detect musi mieć wartość true lub false +@msg direct-select anchor points of a path zaznacz bezpośrednio punkty kontrolne ścieżki +@msg distance must be > 0 distance musi być > 0 +@msg dx and dy give the arrow's direction dx i dy określają kierunek strzałki +@msg dx and dy must be numbers dx i dy muszą być liczbami +@msg dxf fitTo must be [width, height], positive dxf fitTo musi mieć postać [width, height] i wartości dodatnie +@msg dxf must be an object of DXF import options dxf musi być obiektem z opcjami importu DXF +@msg dxf scale must be a positive number up to {_1}, not {s} dxf scale musi być liczbą dodatnią nie większą niż {_1}, a nie {s} +@msg dxf unit `{u}`: a unit such as mm, cm, in or pt dxf unit `{u}`: jednostka, na przykład mm, cm, in lub pt +@msg dxf: {e} dxf: {e} +@msg each format is an object {format, scale?, suffix?} każdy format to obiekt {format, scale?, suffix?} +@msg each item needs an id każdy element wymaga id +@msg each match needs `kind` każde dopasowanie wymaga `kind` +@msg each match needs a `name` każde dopasowanie wymaga `name` +@msg each of `fonts` is {family, style?}; 1 to 1000 of them każdy element `fonts` ma postać {family, style?}; od 1 do 1000 elementów +@msg each of `items` is {kind, item} każdy element `items` ma postać {kind, item} +@msg each of `items` is {{id, corners?}} with an object id, not {it} każdy element `items` ma postać {{id, corners?}} z identyfikatorem obiektu, a nie {it} +@msg each row needs `from` każdy wiersz wymaga `from` +@msg each stop needs a position każdy punkt koloru wymaga położenia +@msg each subpath needs an anchors array każda ścieżka podrzędna wymaga tablicy anchors +@msg easingType must be easeIn, easeOut, easeInOut or easeOutIn easingType musi mieć wartość easeIn, easeOut, easeInOut lub easeOutIn +@msg editingData must be true or false editingData musi mieć wartość true lub false +@msg editingData must be true, false or "always" editingData musi mieć wartość true, false lub "always" +@msg edits overlap edycje nakładają się na siebie +@msg effects of objects whose appearances differ can't be moved together efektów obiektów o różnym wyglądzie nie można przenosić razem +@msg empty header in column {_1} pusty nagłówek w kolumnie {_1} +@msg encoding `{_1}`: utf8 or utf16 encoding `{_1}`: utf8 lub utf16 +@msg ends must be two of "first" and "last" ends musi zawierać dwie wartości spośród "first" i "last" +@msg every numbered name for the result is taken każda numerowana nazwa wyniku jest już zajęta +@msg expanded SVG styles exceed the import size limit rozwinięte style SVG przekraczają limit rozmiaru importu +@msg export presets file is larger than {MAX_PRESET_FILE_BYTES} bytes plik ustawień eksportu jest większy niż {MAX_PRESET_FILE_BYTES} bajtów +@msg exportText must be editable or appearance exportText musi mieć wartość editable lub appearance +@msg exportType must be movieClip or graphic, not `{s}` exportType musi mieć wartość movieClip lub graphic, a nie `{s}` +@msg extend needs id extend wymaga id +@msg featureChanges lists at most {MAX_FEATURE_CHANGES} tags featureChanges zawiera najwyżej {MAX_FEATURE_CHANGES} znaczników +@msg featureChanges must be a list of tags featureChanges musi być listą znaczników +@msg features must be a list of tags features musi być listą znaczników +@msg fidelity must be 0..100 fidelity musi mieścić się w zakresie 0..100 +@msg files must be {name, dataBase64} files musi mieć postać {name, dataBase64} +@msg fit must be none|autoHeight|shrinkText|block, got {id} fit musi mieć wartość none|autoHeight|shrinkText|block, podano {id} +@msg flattener: {e} spłaszczanie: {e} +@msg flattenerPreset `{name}`: high, medium, low or a saved one (see flattener.presets.list) flattenerPreset `{name}`: high, medium, low lub zapisane ustawienie (patrz flattener.presets.list) +@msg flipProfile must be along|across, got {o} flipProfile musi mieć wartość along|across, podano {o} +@msg folders `{f}`: none, rows, format, item or itemFormat folders `{f}`: none, rows, format, item lub itemFormat +@msg folders deeper than {MAX_BATCH_DEPTH} levels foldery zagnieżdżone głębiej niż na {MAX_BATCH_DEPTH} poziomów +@msg folders deeper than {MAX_DEPTH} levels foldery zagnieżdżone głębiej niż na {MAX_DEPTH} poziomów +@msg font family `{family}` is not available rodzina czcionek `{family}` nie jest dostępna +@msg font family `{tf}` is not available rodzina czcionek `{tf}` nie jest dostępna +@msg format `{f}`: pdf or postscript format `{f}`: pdf lub postscript +@msg format `{f}`: text or json format `{f}`: text lub json +@msg format is `{format}` format to `{format}` +@msg formats must be an array of rows, not {v} formats musi być tablicą wierszy, a nie {v} +@msg frequency must be between 1 and 300 lines per inch frequency musi mieścić się w zakresie od 1 do 300 linii na cal +@msg from and to must be finite from i to muszą być skończone +@msg from must be [x0, y0, x1, y1] from musi mieć postać [x0, y0, x1, y1] +@msg give `before` or `after`, not both podaj `before` albo `after`, nie oba naraz +@msg give `colors`, or `color` and `rule` podaj `colors` albo `color` i `rule` +@msg give `event`, such as onclick podaj `event`, na przykład onclick +@msg give `file`, the JavaScript file's path or URL podaj `file`, ścieżkę lub adres URL pliku JavaScript +@msg give `fill` and/or `stroke` podaj `fill` i/lub `stroke` +@msg give `fill`, `stroke` or both podaj `fill`, `stroke` lub oba +@msg give `folder` podaj `folder` +@msg give `fonts`, or open a document podaj `fonts` albo otwórz dokument +@msg give `from` or `indices`, not both podaj `from` albo `indices`, nie oba naraz +@msg give `id` (no text is being edited) podaj `id` (żaden tekst nie jest edytowany) +@msg give `id` and `anchors`, or `items`, not both podaj `id` i `anchors` albo `items`, nie oba naraz +@msg give `id` or `guide`, not both podaj `id` albo `guide`, nie oba naraz +@msg give `length` or `to` podaj `length` lub `to` +@msg give `matches`: [{kind, name, target}] podaj `matches`: [{kind, name, target}] +@msg give `name` (or edit a pattern) podaj `name` (albo edytuj wzorek) +@msg give `name` or `names` podaj `name` lub `names` +@msg give `path` (a .wasm file) or `dataBase64` (the module) podaj `path` (plik .wasm) lub `dataBase64` (moduł) +@msg give `path`, `data` or `dataBase64` podaj `path`, `data` lub `dataBase64` +@msg give `path`, `data`, `dataBase64` or `csv` podaj `path`, `data`, `dataBase64` lub `csv` +@msg give `path`, `xml` or `dataBase64` podaj `path`, `xml` lub `dataBase64` +@msg give `script`, the JavaScript the event runs ("" removes the event) podaj `script`, kod JavaScript uruchamiany przez zdarzenie ("" usuwa zdarzenie) +@msg give `text` (the reading) or `remove` podaj `text` (czytanie) lub `remove` +@msg give `x` and `y` (and a `tolerance` of 0 or more) podaj `x` i `y` (oraz `tolerance` równe 0 lub więcej) +@msg give a mode or r/g/b, c/m/y/k, gray or tint adjustments podaj mode albo korekty r/g/b, c/m/y/k, gray lub tint +@msg give a name, or paint the active proxy with a saved preset podaj nazwę albo nadaj aktywnemu wskaźnikowi wypełnienia lub obrysu zapisane ustawienie +@msg give a name, or select a stroke with a saved profile podaj nazwę albo zaznacz obrys z zapisanym profilem +@msg give a pattern name or select an object painted with a pattern podaj nazwę wzorka albo zaznacz obiekt pomalowany wzorkiem +@msg give at least one of clip, invert, disabled, linked podaj co najmniej jedno z: clip, invert, disabled, linked +@msg give color, none, swatch or gradient podaj color, none, swatch lub gradient +@msg give dataBase64 podaj dataBase64 +@msg give either at (a click) or area (a path drawn around the overlaps) podaj at (kliknięcie) albo area (ścieżkę narysowaną wokół nakładających się obszarów) +@msg give formats or a preset, not both podaj formats albo ustawienie, nie oba naraz +@msg give newName or delete podaj newName lub delete +@msg give offset or by podaj offset lub by +@msg give one of `to`, `rect` or `at` podaj jedno z: `to`, `rect` lub `at` +@msg give one of assets, layers, selection or fullDocument podaj jedno z: assets, layers, selection lub fullDocument +@msg give only one of onto, above, below, icon and a column place podaj tylko jedno z: onto, above, below, icon i miejsce w kolumnie +@msg give origin: [x, y], or reset: true podaj origin: [x, y] albo reset: true +@msg give overprintFill, overprintStroke, showCenter, imageMap, url or note podaj overprintFill, overprintStroke, showCenter, imageMap, url lub note +@msg give path (a file) or folder podaj path (plik) lub folder +@msg give path, or name and dataBase64 podaj path albo name i dataBase64 +@msg give paths or files podaj paths lub files +@msg give rows, rowHeight, columns or columnWidth podaj rows, rowHeight, columns lub columnWidth +@msg give svg, or dataBase64 of an SVG or SVGZ file podaj svg albo dataBase64 pliku SVG lub SVGZ +@msg give text podaj text +@msg give the asset a name nadaj zasobowi nazwę +@msg give the preset a `name` nadaj ustawieniu `name` +@msg give the preset a name nadaj ustawieniu nazwę +@msg give the preset a name (1–64 characters) nadaj ustawieniu nazwę (1–64 znaki) +@msg give the settings to change, e.g. {"formats"}]} podaj ustawienia do zmiany, np. {"formats"}]} +@msg give the style a name nadaj stylowi nazwę +@msg give two or more style `names` podaj co najmniej dwie nazwy stylów w `names` +@msg give two or more swatches podaj co najmniej dwie próbki +@msg give x, y, or a handle's length or angle podaj x, y albo długość lub kąt uchwytu +@msg give {key, value} or {values} podaj {key, value} lub {values} +@msg global must be true or false global musi mieć wartość true lub false +@msg glyph {_1} is not drawn for {ch} with the character's style (such as All Caps, Small Caps or a numeral system) glif {_1} nie jest rysowany dla {ch} przy stylu tego znaku (takim jak Wersaliki, Kapitaliki lub system liczbowy) +@msg glyph {g} is not an alternate of {ch} in {_1} {_2} glif {g} nie jest wariantem {ch} w {_1} {_2} +@msg gradient must be "objects" or "mesh" gradient musi mieć wartość "objects" lub "mesh" +@msg grays must be "profile" or "black", not `{g}` grays musi mieć wartość "profile" lub "black", a nie `{g}` +@msg gridColors must be a preset name or two colours gridColors musi być nazwą ustawienia lub dwoma kolorami +@msg gridSize must be small, medium or large gridSize musi mieć wartość small, medium lub large +@msg guide {g} is not selected linia pomocnicza {g} nie jest zaznaczona +@msg handle must be 0..3 handle musi mieścić się w zakresie 0..3 +@msg hiddenObjects {v}: "layer" (the default), "omit" or "visible" hiddenObjects {v}: "layer" (domyślnie), "omit" lub "visible" +@msg highlight a layer to merge into wyróżnij warstwę, z którą ma nastąpić scalenie +@msg highlight two or more rows in one layer or group wyróżnij co najmniej dwa wiersze w jednej warstwie lub grupie +@msg highlight two or more rows to merge wyróżnij co najmniej dwa wiersze do scalenia +@msg icon docks a panel in the icon column: use window.panel.dock icon dokuje panel w kolumnie ikon: użyj window.panel.dock +@msg id must be a dimension id id musi być identyfikatorem wymiaru +@msg image has no bounds obraz nie ma granic +@msg image {_1} is linked already obraz {_1} jest już połączony +@msg imageMap `{m}`: none, client or server imageMap `{m}`: none, client lub server +@msg index out of range indeks poza zakresem +@msg instances must be 1..1000 instances musi mieścić się w zakresie 1..1000 +@msg invalid `color` nieprawidłowe `color` +@msg invalid anchor index {v}: expected a non-negative integer nieprawidłowy indeks punktu kontrolnego {v}: oczekiwano nieujemnej liczby całkowitej +@msg invalid anchor reference {v}: expected [subpath, anchor] nieprawidłowe odwołanie do punktu kontrolnego {v}: oczekiwano [subpath, anchor] +@msg invalid angle nieprawidłowy kąt +@msg invalid brush: {e} nieprawidłowy pędzel: {e} +@msg invalid color nieprawidłowy kolor +@msg invalid colour {c} nieprawidłowy kolor {c} +@msg invalid delta nieprawidłowa delta +@msg invalid point nieprawidłowy punkt +@msg invalid size nieprawidłowy rozmiar +@msg invalid t nieprawidłowe t +@msg invalid tolerance nieprawidłowa tolerancja +@msg its artboards all lie beyond the canvas (more than {_1} pt from the origin) wszystkie jego obszary kompozycji leżą poza płótnem (ponad {_1} pt od punktu początkowego) +@msg its clipping masks are nested too deeply jego maski przycinające są zbyt głęboko zagnieżdżone +@msg its metadata has no description jego metadane nie mają opisu +@msg its metadata has no direct length jego metadane nie mają bezpośredniej długości +@msg join two different paths połącz dwie różne ścieżki +@msg justify must be auto|left|center|right|justifyAll justify musi mieć wartość auto|left|center|right|justifyAll +@msg kbps must be a positive number, not {kbps} kbps musi być liczbą dodatnią, a nie {kbps} +@msg keywords must be a list of words or a comma-separated string keywords musi być listą słów lub ciągiem znaków rozdzielanym przecinkami +@msg keywords must be at most {MAX_KEYWORD} characters, without control characters keywords może mieć najwyżej {MAX_KEYWORD} znaków, bez znaków sterujących +@msg kind must be 1, 2 or 3, or give a preset `name` (see perspective.presets.list) kind musi wynosić 1, 2 lub 3, albo podaj `name` ustawienia (patrz perspective.presets.list) +@msg kind must be graphic, fillColor, strokeColor, fillGradient, strokeGradient, fillPattern, strokePattern, charStyle or paraStyle kind musi mieć wartość graphic, fillColor, strokeColor, fillGradient, strokeGradient, fillPattern, strokePattern, charStyle lub paraStyle +@msg knockout must be "on", "off", "neutral" or a bool, not {v} knockout musi mieć wartość "on", "off", "neutral" lub wartość logiczną, a nie {v} +@msg layer `{name}` has no art to export warstwa `{name}` nie zawiera grafiki do wyeksportowania +@msg layer must name a layer or sublayer layer musi wskazywać warstwę lub podwarstwę +@msg layers can't be intertwined: select the objects in them warstw nie można przeplatać: zaznacz znajdujące się w nich obiekty +@msg layers go only at the top level or in layers, objects in layers and groups warstwy mogą się znajdować tylko na najwyższym poziomie lub w warstwach, a obiekty w warstwach i grupach +@msg layers must be true or false layers musi mieć wartość true lub false +@msg layout must be gridByRow, gridByColumn, row or column layout musi mieć wartość gridByRow, gridByColumn, row lub column +@msg leading must be a number or "auto" leading musi być liczbą lub wartością "auto" +@msg left/right must be non-negative widths left/right muszą być nieujemnymi szerokościami +@msg level `{t}`: 2 or 3 level `{t}`: 2 lub 3 +@msg line {line}: more than {MAX_CSV_COLS} columns wiersz {line}: więcej niż {MAX_CSV_COLS} kolumn +@msg line {line}: unclosed quote wiersz {line}: niezamknięty cudzysłów +@msg line {line}: value for `{var}` must match its variable kind wiersz {line}: wartość dla `{var}` musi odpowiadać rodzajowi zmiennej +@msg lineEndings `{other}`: lf or crlf lineEndings `{other}`: lf lub crlf +@msg loading profiles from disk isn't available in the browser wczytywanie profili z dysku nie jest dostępne w przeglądarce +@msg margin: a {m} pt margin leaves no imageable area on the paper margin: margines {m} pt nie pozostawia na papierze obszaru zadruku +@msg matrix must be finite and invertible, depth finite matrix musi być skończona i odwracalna, a depth skończona +@msg matte: {e} matte: {e} +@msg member is for order front, forward, backward or back member dotyczy order o wartości front, forward, backward lub back +@msg missing `artboards` brak `artboards` +@msg missing `at` [x, y] brak `at` [x, y] +@msg missing `attrs` brak `attrs` +@msg missing `color` or `opacity` brak `color` lub `opacity` +@msg missing `colors` brak `colors` +@msg missing `commands` brak `commands` +@msg missing `destinationFolder` brak `destinationFolder` +@msg missing `effect` id brak identyfikatora `effect` +@msg missing `family` brak `family` +@msg missing `find` brak `find` +@msg missing `gid` (a glyph id, or null for the default glyph) brak `gid` (identyfikator glifu albo null dla glifu domyślnego) +@msg missing `group` brak `group` +@msg missing `id` brak `id` +@msg missing `id`: give one, or select one type object brak `id`: podaj je albo zaznacz jeden obiekt tekstowy +@msg missing `index` (a point index, or null to clear) brak `index` (indeks punktu albo null, aby wyczyścić) +@msg missing `index` (a stop index, or null to clear) brak `index` (indeks punktu koloru albo null, aby wyczyścić) +@msg missing `index` (an item index or null) brak `index` (indeks elementu lub null) +@msg missing `item` brak `item` +@msg missing `library` brak `library` +@msg missing `library` (see graphicStyle.libraries) brak `library` (patrz graphicStyle.libraries) +@msg missing `library` (see swatch.library.list) brak `library` (patrz swatch.library.list) +@msg missing `map` (rows [{from, to}] or {current}) brak `map` (wiersze [{from, to}] lub {current}) +@msg missing `matrix` [a,b,c,d,e,f] brak `matrix` [a,b,c,d,e,f] +@msg missing `name` (see gradient.presets.list) brak `name` (patrz gradient.presets.list) +@msg missing `offset` (a distance in points) brak `offset` (odległość w punktach) +@msg missing `path` brak `path` +@msg missing `path` (a path object id) brak `path` (identyfikator obiektu ścieżki) +@msg missing `rule` brak `rule` +@msg missing `source` id brak identyfikatora `source` +@msg missing `start` (the byte offset of a character) brak `start` (przesunięcie znaku w bajtach) +@msg missing `status`: linked, embedded, missing or modified brak `status`: linked, embedded, missing lub modified +@msg missing `target` id brak identyfikatora `target` +@msg missing `text` brak `text` +@msg missing `to` brak `to` +@msg missing `to` (an index) brak `to` (indeks) +@msg missing `to`: a non-negative integer brak `to`: nieujemna liczba całkowita +@msg missing `type` brak `type` +@msg missing `value` brak `value` +@msg missing `{key}` brak `{key}` +@msg missing `{k}` brak `{k}` +@msg missing anchor brak punktu kontrolnego +@msg missing anchors brak punktów kontrolnych +@msg missing anchors [[subpath, anchor]…] brak punktów kontrolnych [[subpath, anchor]…] +@msg missing array `{key}` brak tablicy `{key}` +@msg missing case brak case +@msg missing color brak koloru +@msg missing commands brak poleceń +@msg missing destination folder brak folderu docelowego +@msg missing from brak from +@msg missing group brak grupy +@msg missing id or ids brak id lub ids +@msg missing ids brak ids +@msg missing indexes brak indexes +@msg missing matrix [a,b,c,d,e,f] brak matrix [a,b,c,d,e,f] +@msg missing name brak nazwy +@msg missing op brak op +@msg missing or invalid `color` brak `color` lub jest ono nieprawidłowe +@msg missing or unknown `tool` brak `tool` lub jest ono nieznane +@msg missing point brak punktu +@msg missing point [x,y] brak punktu [x,y] +@msg missing point `{key}` ([x, y]) brak punktu `{key}` ([x, y]) +@msg missing points brak punktów +@msg missing points [[x,y]…] brak punktów [[x,y]…] +@msg missing segment brak segmentu +@msg missing stops brak punktów koloru +@msg missing subpaths brak ścieżek podrzędnych +@msg missing target brak celu +@msg missing to brak to +@msg missing x, y brak x, y +@msg mode is set, add or toggle, not `{other}` mode ma wartość set, add lub toggle, a nie `{other}` +@msg mode must be "cmyk" or "rgb" mode musi mieć wartość "cmyk" lub "rgb" +@msg mode must be area|onPath, got {o} mode musi mieć wartość area|onPath, podano {o} +@msg more than 10000 linked files: package dependencies in smaller parts ponad 10000 połączonych plików: pakuj zależności w mniejszych częściach +@msg more than 256 commands więcej niż 256 poleceń +@msg more than {MAX_BATCH_FILES} data sets więcej niż {MAX_BATCH_FILES} zestawów danych +@msg more than {MAX_BATCH_FILES} files więcej niż {MAX_BATCH_FILES} plików +@msg more than {MAX_CSV_ROWS} data rows więcej niż {MAX_CSV_ROWS} wierszy danych +@msg more than {MAX_FILES} images więcej niż {MAX_FILES} obrazów +@msg more than {MAX_IMPORT} presets więcej niż {MAX_IMPORT} ustawień +@msg moved must be [[x,y]…] moved musi mieć postać [[x,y]…] +@msg name (a toolbar's name) is required name (nazwa paska narzędzi) jest wymagane +@msg name (a toolbar's name) must be a string name (nazwa paska narzędzi) musi być ciągiem znaków +@msg name must be a toolbar's name name musi być nazwą paska narzędzi +@msg names is empty names jest puste +@msg names must be an array of symbol names names musi być tablicą nazw symboli +@msg need `anchor` or `segment` + `t` wymagane `anchor` albo `segment` + `t` +@msg need at least one anchor wymagany co najmniej jeden punkt kontrolny +@msg need at least one point wymagany co najmniej jeden punkt +@msg need at least two points wymagane co najmniej dwa punkty +@msg needs points wymaga punktów +@msg nineSlice must be true or false nineSlice musi mieć wartość true lub false +@msg nineSliceGuides must be [left, top, right, bottom], each -16..16, with left + right < 1 and top + bottom < 1 nineSliceGuides musi mieć postać [left, top, right, bottom], każda wartość z zakresu -16..16, przy czym left + right < 1 i top + bottom < 1 +@msg no PDF preset named `{n}` brak ustawienia PDF o nazwie `{n}` +@msg no action set is current żaden zestaw operacji nie jest bieżący +@msg no active data set brak aktywnego zestawu danych +@msg no appearance item {index} brak elementu wyglądu {index} +@msg no artboard {_1} brak obszaru kompozycji {_1} +@msg no artboard {artboard} (0-based; the document has {_1}) brak obszaru kompozycji {artboard} (liczone od 0; dokument ma {_1}) +@msg no asset {id} brak zasobu {id} +@msg no asset {id} (see assets.list) brak zasobu {id} (patrz assets.list) +@msg no assets to export brak zasobów do wyeksportowania +@msg no assets yet: collect art for export first (assets.add) nie ma jeszcze zasobów: najpierw zbierz grafikę do eksportu (assets.add) +@msg no brush named `{n}` brak pędzla o nazwie `{n}` +@msg no character at byte {start} brak znaku w bajcie {start} +@msg no colour brak koloru +@msg no colour group `{group}` brak grupy kolorów `{group}` +@msg no colour group `{name}` brak grupy kolorów `{name}` +@msg no data sets brak zestawów danych +@msg no dataset named `{from}` brak zestawu danych o nazwie `{from}` +@msg no dataset named `{name}` brak zestawu danych o nazwie `{name}` +@msg no datasets brak zestawów danych +@msg no design named `{name}` brak wzoru o nazwie `{name}` +@msg no design named `{n}` brak wzoru o nazwie `{n}` +@msg no design named `{old}` brak wzoru o nazwie `{old}` +@msg no encoder for {_1} yet nie ma jeszcze kodera dla {_1} +@msg no export preset `{name}` (see document.exportPresets.list) brak ustawienia eksportu `{name}` (patrz document.exportPresets.list) +@msg no folder: pass `path` or set Preferences › Plug-ins & Scratch Disks › Additional Plug-ins Folder brak folderu: przekaż `path` albo ustaw Preferencje › Wtyczki i dyski robocze › Dodatkowy folder wtyczek +@msg no fonts to look for: they are all available brak czcionek do wyszukania: wszystkie są dostępne +@msg no formats to export brak formatów do wyeksportowania +@msg no gradient preset `{name}` (see gradient.presets.list) brak ustawienia gradientu `{name}` (patrz gradient.presets.list) +@msg no graphic style `{n}` in `{_1}` brak stylu graficznego `{n}` w `{_1}` +@msg no graphic style library `{key}` (see graphicStyle.libraries) brak biblioteki stylów graficznych `{key}` (patrz graphicStyle.libraries) +@msg no guide selected nie zaznaczono linii pomocniczej +@msg no guide selected (or give an index) nie zaznaczono linii pomocniczej (albo podaj indeks) +@msg no guide {i} brak linii pomocniczej {i} +@msg no images in the folder brak obrazów w folderze +@msg no item at index {_1} brak elementu o indeksie {_1} +@msg no item at index {from} brak elementu o indeksie {from} +@msg no item at one of the indices {idx} brak elementu o jednym z indeksów {idx} +@msg no layer brak warstwy +@msg no layer {id} (see layer.list) brak warstwy {id} (patrz layer.list) +@msg no layers to export brak warstw do wyeksportowania +@msg no library `{key}` brak biblioteki `{key}` +@msg no metafile format brak formatu metapliku +@msg no object {_1} brak obiektu {_1} +@msg no objects brak obiektów +@msg no parent layer brak warstwy nadrzędnej +@msg no perspective grid preset named `{b}` (see perspective.presets.list) brak ustawienia siatki perspektywy o nazwie `{b}` (patrz perspective.presets.list) +@msg no perspective grid preset named `{n}` brak ustawienia siatki perspektywy o nazwie `{n}` +@msg no point selected (give `index`) nie zaznaczono punktu (podaj `index`) +@msg no preset called `{from}` (see file.newPresets) brak ustawienia o nazwie `{from}` (patrz file.newPresets) +@msg no preset called `{name}` (see file.newPresets) brak ustawienia o nazwie `{name}` (patrz file.newPresets) +@msg no preset named `{n}` brak ustawienia o nazwie `{n}` +@msg no print preset named `{b}` (see print.presets.list) brak ustawienia drukowania o nazwie `{b}` (patrz print.presets.list) +@msg no print preset named `{name}` (presets: {_1}) brak ustawienia drukowania o nazwie `{name}` (ustawienia: {_1}) +@msg no print preset named `{n}` brak ustawienia drukowania o nazwie `{n}` +@msg no profile named `{name}` brak profilu o nazwie `{name}` +@msg no readable files in the folder brak czytelnych plików w folderze +@msg no recovery copy `{f}` (see file.recovery.list) brak kopii odzyskiwania `{f}` (patrz file.recovery.list) +@msg no rows brak wierszy +@msg no saved PDF preset named `{name}` brak zapisanego ustawienia PDF o nazwie `{name}` +@msg no saved export preset `{name}` brak zapisanego ustawienia eksportu `{name}` +@msg no saved gradient preset called {name} brak zapisanego ustawienia gradientu o nazwie {name} +@msg no saved gradient presets brak zapisanych ustawień gradientu +@msg no saved preset called `{name}` brak zapisanego ustawienia o nazwie `{name}` +@msg no saved presets to export (name [Default] in `names` to export it) brak zapisanych ustawień do wyeksportowania (wymień [Default] w `names`, aby je wyeksportować) +@msg no saved presets to export (name built-in ones in `names`) brak zapisanych ustawień do wyeksportowania (wbudowane wymień w `names`) +@msg no saved print preset named `{name}` brak zapisanego ustawienia drukowania o nazwie `{name}` +@msg no saved profile called {name} brak zapisanego profilu o nazwie {name} +@msg no saved selection `{name}` brak zapisanego zaznaczenia `{name}` +@msg no saved theme called {name} (see colorTheme.list) brak zapisanego motywu o nazwie {name} (patrz colorTheme.list) +@msg no saved views brak zapisanych widoków +@msg no series {i} brak serii {i} +@msg no slice {n} in the image (see slice.list) brak plasterka {n} w obrazie (patrz slice.list) +@msg no source art brak grafiki źródłowej +@msg no stop {i} (the gradient has {n}) brak punktu koloru {i} (gradient ma {n}) +@msg no style `{name}` brak stylu `{name}` +@msg no such assets (see assets.list) brak takich zasobów (patrz assets.list) +@msg no such frame anchor, or the frame would reach past the canvas brak takiego punktu kontrolnego ramki albo ramka wykroczyłaby poza płótno +@msg no such objects brak takich obiektów +@msg no such path anchor, or the path would reach past the canvas brak takiego punktu kontrolnego ścieżki albo ścieżka wykroczyłaby poza płótno +@msg no such rows brak takich wierszy +@msg no swatch `{keep}` brak próbki `{keep}` +@msg no swatch `{n}` brak próbki `{n}` +@msg no swatch `{n}` (swatches and colour groups move separately) brak próbki `{n}` (próbki i grupy kolorów przenosi się osobno) +@msg no swatch library `{key}` (see swatch.library.list) brak biblioteki próbek `{key}` (patrz swatch.library.list) +@msg no swatch library `{key}` (see swatch.library.list; "document": the document's swatches) brak biblioteki próbek `{key}` (patrz swatch.library.list; "document": próbki dokumentu) +@msg no swatch library `{key}` (see swatch.library.list; "{DOCUMENT_SWATCHES}": the document's swatches) brak biblioteki próbek `{key}` (patrz swatch.library.list; "{DOCUMENT_SWATCHES}": próbki dokumentu) +@msg no swatch named `{n}` brak próbki o nazwie `{n}` +@msg no swatch or colour group `{n}` brak próbki lub grupy kolorów `{n}` +@msg no swatch or colour group `{n}` in `{_1}` brak próbki lub grupy kolorów `{n}` w `{_1}` +@msg no symbol named `{name}` brak symbolu o nazwie `{name}` +@msg no text objects selected nie zaznaczono obiektów tekstowych +@msg no toolbar named `{_1}` brak paska narzędzi o nazwie `{_1}` +@msg no toolbar named `{name}` brak paska narzędzi o nazwie `{name}` +@msg no tracing preset `{preset}` (see imageTrace.presets) brak ustawienia obrysu `{preset}` (patrz imageTrace.presets) +@msg no user library folder here (save with a path, or without one to get the data) nie ma tu folderu bibliotek użytkownika (zapisz, podając ścieżkę, albo bez niej, aby otrzymać dane) +@msg no variable named `{from}` brak zmiennej o nazwie `{from}` +@msg no variable named `{name}` brak zmiennej o nazwie `{name}` +@msg no variable named `{var}` brak zmiennej o nazwie `{var}` +@msg no variable named `{v}` brak zmiennej o nazwie `{v}` +@msg no view named `{name}` brak widoku o nazwie `{name}` +@msg node {_1} is not a graph węzeł {_1} nie jest wykresem +@msg node {_1} is not an image węzeł {_1} nie jest obrazem +@msg node {_1} is not type węzeł {_1} nie jest tekstem +@msg not a PDF presets file (format `{_1}`) to nie jest plik ustawień PDF (format `{_1}`) +@msg not a PDF presets file: {e} to nie jest plik ustawień PDF: {e} +@msg not a Word document: its WordDocument stream doesn't start with a file information block to nie jest dokument Word: jego strumień WordDocument nie zaczyna się od bloku informacji o pliku +@msg not a Word document: its compound file has no WordDocument stream to nie jest dokument Word: jego plik złożony nie ma strumienia WordDocument +@msg not a Word document: its main part is not a WordprocessingML document to nie jest dokument Word: jego część główna nie jest dokumentem WordprocessingML +@msg not a Word document: its package has no main document part to nie jest dokument Word: jego pakiet nie ma głównej części dokumentu +@msg not a closed path to nie jest ścieżka zamknięta +@msg not a flattener presets file (format `{_1}`) to nie jest plik ustawień spłaszczania (format `{_1}`) +@msg not a flattener presets file: {e} to nie jest plik ustawień spłaszczania: {e} +@msg not a layer or group to nie jest warstwa ani grupa +@msg not a library file: {e} to nie jest plik biblioteki: {e} +@msg not a mesh envelope point to nie jest punkt koperty siatkowej +@msg not a perspective grid presets file (format `{_1}`) to nie jest plik ustawień siatki perspektywy (format `{_1}`) +@msg not a perspective grid presets file: {e} to nie jest plik ustawień siatki perspektywy: {e} +@msg not a print presets file (format `{_1}`) to nie jest plik ustawień drukowania (format `{_1}`) +@msg not a print presets file: {e} to nie jest plik ustawień drukowania: {e} +@msg not a stored or deflated central record to nie jest rekord centralny zapisany bez kompresji ani skompresowany metodą deflate +@msg not a valid SVGZ file: {e} to nie jest prawidłowy plik SVGZ: {e} +@msg not an RTF file: it doesn't start with {\\rtf to nie jest plik RTF: nie zaczyna się od {\\rtf +@msg not an image VectorCraft reads (see document.formats) to nie jest obraz odczytywany przez VectorCraft (patrz document.formats) +@msg not area type (text in a frame) outside perspective to nie jest tekst akapitowy (tekst w ramce) poza perspektywą +@msg not editing an opacity mask maska krycia nie jest edytowana +@msg not type on a path outside perspective to nie jest tekst na ścieżce poza perspektywą +@msg nothing prints nic nie jest drukowane +@msg nothing to bind nie ma czego powiązać +@msg nothing to change nie ma czego zmienić +@msg nothing to change: give dx, dy, hScale, vScale or rotation nie ma czego zmienić: podaj dx, dy, hScale, vScale lub rotation +@msg nothing to crop nie ma czego kadrować +@msg nothing to export nie ma czego eksportować +@msg nothing to export: the document has no visible art nie ma czego eksportować: dokument nie zawiera widocznej grafiki +@msg nothing to mark nie ma czego oznaczać +@msg nothing to print: every artboard picked is blank nie ma czego drukować: każdy wybrany obszar kompozycji jest pusty +@msg nothing to print: the document has no art that prints nie ma czego drukować: dokument nie zawiera grafiki przeznaczonej do druku +@msg object is not a path obiekt nie jest ścieżką +@msg object transparency cannot be sampled onto highlighted characters; disable Transparency in Eyedropper Options or select the whole object przezroczystości obiektu nie można próbkować na wyróżnione znaki; wyłącz Przezroczystość w Opcjach kroplomierza albo zaznacz cały obiekt +@msg object {_1} can't be set as point type obiektu {_1} nie można ustawić jako tekstu punktowego +@msg object {_1} has lost its file's contents: relink it obiekt {_1} utracił zawartość swojego pliku: połącz go ponownie +@msg object {_1} has no path obiekt {_1} nie ma ścieżki +@msg object {_1} has no size obiekt {_1} nie ma rozmiaru +@msg object {_1} is hidden or locked, or on a locked artboard obiekt {_1} jest ukryty lub zablokowany albo znajduje się na zablokowanym obszarze kompozycji +@msg object {_1} is not a placed document obiekt {_1} nie jest umieszczonym dokumentem +@msg object {_1} is not an Intertwine group obiekt {_1} nie jest grupą przeplatania +@msg object {_1} is not an image obiekt {_1} nie jest obrazem +@msg object {_1} is not an image or a linked file obiekt {_1} nie jest obrazem ani połączonym plikiem +@msg object {_1} is not an image or a placed document obiekt {_1} nie jest obrazem ani umieszczonym dokumentem +@msg object {_1} is not in this Intertwine group obiekt {_1} nie należy do tej grupy przeplatania +@msg object {_1} needs a 3D effect at index {index} obiekt {_1} wymaga efektu 3D o indeksie {index} +@msg object {id} has anchors 0–{_1} for `corners`, not {past} obiekt {id} ma dla `corners` punkty kontrolne 0–{_1}, a nie {past} +@msg object {id} has {n} anchors, so no anchor {past} obiekt {id} ma {n} punktów kontrolnych, więc nie ma punktu {past} +@msg objects must be none, move or copy objects musi mieć wartość none, move lub copy +@msg objects were left out pominięto obiekty +@msg offset out of range przesunięcie poza zakresem +@msg on must be true or false on musi mieć wartość true lub false +@msg only groups, layers, type and images have a Contents (Characters) row tylko grupy, warstwy, tekst i obrazy mają wiersz Zawartość (Znaki) +@msg only interior mesh lines can be deleted usuwać można tylko wewnętrzne linie siatki +@msg only solid colours can be added (not gradients or patterns) dodawać można tylko kolory jednolite (nie gradienty ani wzorki) +@msg only solid-colour swatches can be spot colours kolorami dodatkowymi mogą być tylko próbki kolorów jednolitych +@msg only this Affinity file's embedded preview could be read: use File › Open to see it with its warning, or export SVG or PDF from Affinity first udało się odczytać tylko osadzony podgląd tego pliku Affinity: użyj polecenia Plik › Otwórz, aby zobaczyć go wraz z ostrzeżeniem, albo najpierw wyeksportuj SVG lub PDF z programu Affinity +@msg only this Affinity file's embedded preview could be read; use File › Open to see it with its warning udało się odczytać tylko osadzony podgląd tego pliku Affinity; użyj polecenia Plik › Otwórz, aby zobaczyć go wraz z ostrzeżeniem +@msg onto, above, below, icon and a column place belong to window.panel.float and window.panel.dock onto, above, below, icon i miejsce w kolumnie należą do window.panel.float i window.panel.dock +@msg onto, above, below, icon and a column place take no anchor, side, zone or before onto, above, below, icon i miejsce w kolumnie nie przyjmują anchor, side, zone ani before +@msg onto, above, below, icon and a column place take no x, y, width or height onto, above, below, icon i miejsce w kolumnie nie przyjmują x, y, width ani height +@msg open a document to look for its linked files otwórz dokument, aby wyszukać jego połączone pliki +@msg options must be an object (see file.formatOptions) options musi być obiektem (patrz file.formatOptions) +@msg order must be leftToRight or rightToLeft order musi mieć wartość leftToRight lub rightToLeft +@msg orientation must be portrait or landscape, not `{o}` orientation musi mieć wartość portrait lub landscape, a nie `{o}` +@msg outlineText {v}: true or false outlineText {v}: true lub false +@msg output intent profile: {e} profil docelowych warunków wyjściowych: {e} +@msg output.destination: no RGB or CMYK profile is called “{name}” output.destination: żaden profil RGB ani CMYK nie nosi nazwy „{name}” +@msg output.destination: {_1} files are CMYK, and “{name}” is an RGB profile output.destination: pliki {_1} są w CMYK, a „{name}” to profil RGB +@msg output.destination: {e} output.destination: {e} +@msg output.inks: no ink is set to print output.inks: żadna farba nie jest ustawiona do druku +@msg output.outputIntent: no profile is called “{name}”, and a {std} output intent embeds its profile output.outputIntent: żaden profil nie nosi nazwy „{name}”, a docelowe warunki wyjściowe {std} osadzają swój profil +@msg output.outputIntent: no profile is called “{name}”: a {std} output intent embeds a profile, or names a registered printing condition (outputConditionId and registry) output.outputIntent: żaden profil nie nosi nazwy „{name}”: docelowe warunki wyjściowe {std} osadzają profil albo wskazują zarejestrowane warunki drukowania (outputConditionId i registry) +@msg output.outputIntent: {std} files print in CMYK, and “{name}” is an RGB profile output.outputIntent: pliki {std} są drukowane w CMYK, a „{name}” to profil RGB +@msg output.outputIntent: “{name}” is a grey profile, which can't be a {std} output intent output.outputIntent: „{name}” to profil szarości, który nie może stanowić docelowych warunków wyjściowych {std} +@msg overlap: {o} pt is half a tile or more overlap: {o} pt to co najmniej połowa kafelka +@msg overlapping Shaper paths must be in the same layer or group nakładające się ścieżki narzędzia Kształtowanie muszą znajdować się w tej samej warstwie lub grupie +@msg overlapping edits nakładające się edycje +@msg page art conflicts with image data for {key} grafika strony jest sprzeczna z danymi obrazu dla {key} +@msg page art conflicts with pattern {name} grafika strony jest sprzeczna z wzorkiem {name} +@msg page art conflicts with swatch {name} grafika strony jest sprzeczna z próbką {name} +@msg page art is missing image data for {key} w grafice strony brakuje danych obrazu dla {key} +@msg page art is missing pattern {name} w grafice strony brakuje wzorka {name} +@msg page art is missing swatch {name} w grafice strony brakuje próbki {name} +@msg page must be a whole number from 1 page musi być liczbą całkowitą od 1 +@msg page thumbnail: {e} miniatura strony: {e} +@msg page {page} of the PDF has no objects strona {page} pliku PDF nie zawiera obiektów +@msg page {page}: `{file}` has {n} {artboards} strona {page}: `{file}` ma {n} {artboards} +@msg page {page}: `{name}` has {n} {pages} strona {page}: `{name}` ma {n} {pages} +@msg pages must be a range such as "2-3" or a page number, not {v} pages musi być zakresem, na przykład "2-3", albo numerem strony, a nie {v} +@msg pages: {e} pages: {e} +@msg panel position must be finite położenie panelu musi być skończone +@msg parameters must be an object parametry muszą być obiektem +@msg params must be an object params musi być obiektem +@msg passwords can have up to {MAX_PASSWORD} bytes hasła mogą mieć najwyżej {MAX_PASSWORD} bajtów +@msg path has no open end ścieżka nie ma otwartego końca +@msg paths must be strings paths musi zawierać ciągi znaków +@msg pdfCompatible: false needs every artboard to keep the editable artwork pdfCompatible: false wymaga wszystkich obszarów kompozycji, aby zachować edytowalną grafikę +@msg pdfs `{m}`: single or multiple pdfs `{m}`: single lub multiple +@msg pickColorFrom is "artwork" or "swatches", not {v} pickColorFrom ma wartość "artwork" lub "swatches", a nie {v} +@msg pins and moved must be non-empty lists of the same length pins i moved muszą być niepustymi listami tej samej długości +@msg pins must be [[x,y]…] pins musi mieć postać [[x,y]…] +@msg pins must be finite pins musi zawierać wartości skończone +@msg place is above, below or inside, not `{other}` place ma wartość above, below lub inside, a nie `{other}` +@msg plane must be left|right|ground plane musi mieć wartość left|right|ground +@msg plane must be left|right|ground|none plane musi mieć wartość left|right|ground|none +@msg point is outside the mesh punkt leży poza siatką +@msg points must be [t, left, right] with non-negative widths points musi mieć postać [t, left, right] z nieujemnymi szerokościami +@msg points must be a non-empty [[x,y,pressure?]…] list points musi być niepustą listą [[x,y,pressure?]…] +@msg points must be a non-empty list of finite [x,y] points musi być niepustą listą skończonych wartości [x,y] +@msg points must be an array or null points musi być tablicą lub null +@msg points must be finite points musi zawierać wartości skończone +@msg points must be finite [x,y] pairs points musi zawierać skończone pary [x,y] +@msg points must contain 1–4096 coordinates points musi zawierać od 1 do 4096 współrzędnych +@msg position must be normal, superscript or subscript position musi mieć wartość normal, superscript lub subscript +@msg position must be topLeft, topRight, bottomLeft or bottomRight position musi mieć wartość topLeft, topRight, bottomLeft lub bottomRight +@msg positions must be between 0 and 100000 pt positions musi mieścić się w zakresie od 0 do 100000 pt +@msg ppi must be a positive number, not {ppi} ppi musi być liczbą dodatnią, a nie {ppi} +@msg ppi must be between 1 and 2400 ppi musi mieścić się w zakresie od 1 do 2400 +@msg preserve `{v}` is not transforms|bounds|fileDimensions|fit|fill preserve `{v}` nie jest jedną z wartości transforms|bounds|fileDimensions|fit|fill +@msg preserveShape must be clippingMask|transparency preserveShape musi mieć wartość clippingMask|transparency +@msg preset `{id}`: mobile or density preset `{id}`: mobile lub density +@msg preset must be standard, diffuse, topLeft or right preset musi mieć wartość standard, diffuse, topLeft lub right +@msg preset must be the name of a print preset preset musi być nazwą ustawienia drukowania +@msg previewMode must be default, pixel or overprint previewMode musi mieć wartość default, pixel lub overprint +@msg print settings: {e} ustawienia drukowania: {e} +@msg procedures nest too deeply procedury są zbyt głęboko zagnieżdżone +@msg procedures nested too deeply zbyt głęboko zagnieżdżone procedury +@msg quotes must be {double?, single?} quotes musi mieć postać {double?, single?} +@msg quotes.{k} must be an opening and a closing quote, e.g. "“”" quotes.{k} musi zawierać cudzysłów otwierający i zamykający, np. "“”" +@msg rasterEffectsPpi must be 1–2400 (72 screen, 150 medium, 300 high) rasterEffectsPpi musi wynosić 1–2400 (72 screen, 150 medium, 300 high) +@msg rating must be a whole number from 0 to {MAX_RATING} rating musi być liczbą całkowitą od 0 do {MAX_RATING} +@msg rect and {k} contradict each other: give the area or the artboards rect i {k} wykluczają się wzajemnie: podaj obszar albo obszary kompozycji +@msg rect applies to raster formats, not {_1} rect dotyczy formatów rastrowych, a nie {_1} +@msg rect is [x, y, width, height] in points rect ma postać [x, y, width, height] w punktach +@msg rect must be [x, y, width, height] rect musi mieć postać [x, y, width, height] +@msg rect must be [x, y, width, height] with a positive width and height rect musi mieć postać [x, y, width, height] z dodatnią szerokością i wysokością +@msg rect needs finite numbers and a positive width and height rect wymaga liczb skończonych oraz dodatniej szerokości i wysokości +@msg redraw needs id redraw wymaga id +@msg redraw within must be a finite distance of 0 or more within w redraw musi być skończoną odległością równą 0 lub większą +@msg registration must be 0..8 registration musi mieścić się w zakresie 0..8 +@msg release a layer or a group uwolnij warstwę lub grupę +@msg replace keeps the replaced object's place and transform: drop template, at and rect replace zachowuje położenie i przekształcenie zastępowanego obiektu: pomiń template, at i rect +@msg replace: select the one object to replace replace: zaznacz jeden obiekt do zastąpienia +@msg resolution must be a number or screen|medium|high resolution musi być liczbą lub mieć wartość screen|medium|high +@msg resolution must be between 1 and 2400 ppi resolution musi mieścić się w zakresie od 1 do 2400 ppi +@msg rotation must be a number of degrees rotation musi być liczbą stopni +@msg rotation must be finite rotation musi być wartością skończoną +@msg rows and cols must be 1..50 rows i cols muszą mieścić się w zakresie 1..50 +@msg rows and columns must be 1..500 rows i columns muszą mieścić się w zakresie 1..500 +@msg rows of objects whose appearances differ can't be reordered together wierszy obiektów o różnym wyglądzie nie można razem zmieniać kolejności +@msg save the document first: Package collects a saved document najpierw zapisz dokument: Pakiet zbiera zapisany dokument +@msg save the document first: copy puts the file in its folder najpierw zapisz dokument: copy umieszcza plik w jego folderze +@msg savedPreset: {e} savedPreset: {e} +@msg scale `{s}`: a factor such as 2x, a width (100w), a height (100h) or a resolution (72ppi) scale `{s}`: współczynnik, na przykład 2x, szerokość (100w), wysokość (100h) lub rozdzielczość (72ppi) +@msg scale must be a number above 0, at most 64 scale musi być liczbą większą od 0 i nie większą niż 64 +@msg scale must be non-zero scale musi być różne od zera +@msg scope must be selection or all (got {other}) scope musi mieć wartość selection lub all (podano {other}) +@msg scribble is too long gryzmoł jest zbyt długi +@msg segment does not exist segment nie istnieje +@msg select a Shaper group zaznacz grupę narzędzia Kształtowanie +@msg select a blend to set easing or color shift zaznacz przejście, aby ustawić wygładzanie tempa lub przesunięcie koloru +@msg select a compound shape zaznacz kształt złożony +@msg select a graph zaznacz wykres +@msg select a group or layer with visible, unlocked members zaznacz grupę lub warstwę z widocznymi, odblokowanymi elementami +@msg select a layer zaznacz warstwę +@msg select a text object zaznacz obiekt tekstowy +@msg select an image (or an Image Trace group) zaznacz obraz (lub grupę obrysu obrazu) +@msg select an image, or pass id zaznacz obraz albo przekaż id +@msg select an object (or pass `id`) zaznacz obiekt (albo przekaż `id`) +@msg select an object with a freeform gradient zaznacz obiekt z gradientem dowolnym +@msg select an object with an opacity mask zaznacz obiekt z maską krycia +@msg select area type zaznacz tekst akapitowy +@msg select area type (text in a frame) zaznacz tekst akapitowy (tekst w ramce) +@msg select area type and closed paths (at least one area type object) zaznacz tekst akapitowy i ścieżki zamknięte (co najmniej jeden obiekt tekstu akapitowego) +@msg select area type whose first line can fit its frame zaznacz tekst akapitowy, którego pierwszy wiersz mieści się w ramce +@msg select artwork to add its colours zaznacz grafikę, aby dodać jej kolory +@msg select artwork to make a group of its colours zaznacz grafikę, aby utworzyć grupę z jej kolorów +@msg select artwork to recolour, or give a colour `group` zaznacz grafikę do zmiany kolorów albo podaj `group` kolorów +@msg select exactly two path ends to join zaznacz dokładnie dwa końce ścieżek do połączenia +@msg select members of a compound shape zaznacz elementy kształtu złożonego +@msg select objects or give ids zaznacz obiekty albo podaj ids +@msg select objects to align to the guide zaznacz obiekty do wyrównania do linii pomocniczej +@msg select one Intertwine group zaznacz jedną grupę przeplatania +@msg select one image or pass id zaznacz jeden obraz albo przekaż id +@msg select paths zaznacz ścieżki +@msg select paths or compound paths zaznacz ścieżki lub ścieżki złożone +@msg select rows or objects to collect zaznacz wiersze lub obiekty do zebrania +@msg select something to export zaznacz coś do wyeksportowania +@msg select something to export (or turn off selectedOnly) zaznacz coś do wyeksportowania (albo wyłącz selectedOnly) +@msg select text to redefine the style from zaznacz tekst, na podstawie którego styl ma zostać zdefiniowany ponownie +@msg select the art and, on top of it, the mask object zaznacz grafikę oraz leżący nad nią obiekt maski +@msg select the art for the design zaznacz grafikę dla wzoru +@msg select the art for the pattern tile zaznacz grafikę dla kafelka wzorka +@msg select the art to add first najpierw zaznacz grafikę do dodania +@msg select the art to collect (or give its ids) zaznacz grafikę do zebrania (albo podaj jej identyfikatory) +@msg select the content and a path on top zaznacz zawartość oraz leżącą nad nią ścieżkę +@msg select the images to relink, or pass ids zaznacz obrazy do ponownego połączenia albo przekaż ids +@msg select the images, or pass ids zaznacz obrazy albo przekaż ids +@msg select the linked images or placed documents, or pass ids zaznacz połączone obrazy lub umieszczone dokumenty albo przekaż ids +@msg select the object to copy from zaznacz obiekt, z którego ma nastąpić kopiowanie +@msg select the objects (or give their ids) zaznacz obiekty (albo podaj ich identyfikatory) +@msg select the objects to attach to the path zaznacz obiekty do dołączenia do ścieżki +@msg select the objects to bind zaznacz obiekty do powiązania +@msg select two or more objects to intertwine zaznacz co najmniej dwa obiekty do przeplecenia +@msg select two or more slices to combine zaznacz co najmniej dwa plasterki do połączenia +@msg select type on a path zaznacz tekst na ścieżce +@msg selection `{m}`: one or each selection `{m}`: one lub each +@msg settings is an object of document.exportForScreens params settings to obiekt z parametrami document.exportForScreens +@msg settings must be an object settings musi być obiektem +@msg show `{show}`: all, missing, modified or embedded show `{show}`: all, missing, modified lub embedded +@msg show must be true or false show musi mieć wartość true lub false +@msg size must be "small", "medium", "large" or a number of points over 0 up to {_1} size musi mieć wartość "small", "medium", "large" lub być liczbą punktów większą od 0 i nie większą niż {_1} +@msg size must be positive size musi być wartością dodatnią +@msg sizeMode is "fixed" or "pressure", not `{other}` sizeMode ma wartość "fixed" lub "pressure", a nie `{other}` +@msg sizeMode is "fixed" or "pressure", not {other} sizeMode ma wartość "fixed" lub "pressure", a nie {other} +@msg sizeVariation must be 0 or more sizeVariation musi wynosić 0 lub więcej +@msg smallCaps must be true or false smallCaps musi mieć wartość true lub false +@msg sort `{x}`: name, kind or status sort `{x}`: name, kind lub status +@msg source paths are too large for Shaper ścieżki źródłowe są zbyt duże dla narzędzia Kształtowanie +@msg spot, mode and group apply to solid colours only spot, mode i group dotyczą tylko kolorów jednolitych +@msg status `{s}`: linked, embedded, missing or modified status `{s}`: linked, embedded, missing lub modified +@msg steps must be 1..1000 steps musi mieścić się w zakresie 1..1000 +@msg steps must be 1..{MAX_STEPS} steps musi mieścić się w zakresie 1..{MAX_STEPS} +@msg stop {i}: `plates` must be four numbers from 0 to 1 (C, M, Y, K) punkt koloru {i}: `plates` musi zawierać cztery liczby od 0 do 1 (C, M, Y, K) +@msg stopped before the archive was finished zatrzymano przed ukończeniem archiwum +@msg strokeMode must be within|along|across, got {m} strokeMode musi mieć wartość within|along|across, podano {m} +@msg strokeOptions must be an object of stroke.set options strokeOptions musi być obiektem z opcjami stroke.set +@msg strokeWidth must be a positive number of pixels strokeWidth musi być dodatnią liczbą pikseli +@msg subpath {si} is not an open subpath ścieżka podrzędna {si} nie jest otwartą ścieżką podrzędną +@msg subpaths required when joining the same path subpaths jest wymagane przy łączeniu tej samej ścieżki +@msg swatchConflict must be "merge" or "add", not {v} swatchConflict musi mieć wartość "merge" lub "add", a nie {v} +@msg text must be {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} text musi mieć postać {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} +@msg text transform is collapsed or unrepresentable przekształcenie tekstu jest zdegenerowane lub nie da się go przedstawić +@msg text.replaceSpaces must be a whole number from 2 to 100 text.replaceSpaces musi być liczbą całkowitą od 2 do 100 +@msg text.{key} `{v}`: use "{_1}" or "{_2}" text.{key} `{v}`: użyj "{_1}" lub "{_2}" +@msg textureImage: give {path} or {name, dataBase64} of an image file, or a texture as effect.list gives it textureImage: podaj {path} lub {name, dataBase64} pliku obrazu albo teksturę w postaci zwracanej przez effect.list +@msg textureImage: {e} textureImage: {e} +@msg that makes more than {MAX_PIECES} slices to daje więcej niż {MAX_PIECES} plasterków +@msg that object is not in the overlap ten obiekt nie znajduje się w obszarze nakładania +@msg the Affinity document has no page with a size dokument Affinity nie ma strony o określonym rozmiarze +@msg the CMYK image couldn't be written nie udało się zapisać obrazu CMYK +@msg the PDF security settings were saved without their passwords: give openPassword or permissionsPassword again, or security without passwordRequired to export unprotected ustawienia zabezpieczeń PDF zostały zapisane bez haseł: podaj ponownie openPassword lub permissionsPassword albo security bez passwordRequired, aby wyeksportować bez zabezpieczeń +@msg the RTF file has too many paragraphs or formatting changes to place as type (at most {MAX_PARAGRAPHS} paragraphs and {MAX_RUNS} runs) plik RTF ma zbyt wiele akapitów lub zmian formatowania, aby umieścić go jako tekst (najwyżej {MAX_PARAGRAPHS} akapitów i {MAX_RUNS} ciągów formatowania) +@msg the RTF file is too large to place as type (at most {_1} MB) plik RTF jest zbyt duży, aby umieścić go jako tekst (najwyżej {_1} MB) +@msg the SVG expands to more than {0} nested SVG images SVG rozwija się do ponad {0} zagnieżdżonych obrazów SVG +@msg the SVG expands to more than {0} objects SVG rozwija się do ponad {0} obiektów +@msg the SVG has no drawable objects SVG nie zawiera obiektów, które można narysować +@msg the SVGZ file unpacks to more than {_1} MB plik SVGZ po rozpakowaniu ma ponad {_1} MB +@msg the Word document has more than {MAX_PAGES} pages of properties, too many to place dokument Word ma ponad {MAX_PAGES} stron właściwości, zbyt wiele, aby go umieścić +@msg the Word document has more than {MAX_RUNS} runs of character or paragraph properties, too many to place dokument Word ma ponad {MAX_RUNS} ciągów właściwości znaków lub akapitów, zbyt wiele, aby go umieścić +@msg the Word document has more than {_1} MB of formatting properties, too many to place dokument Word ma ponad {_1} MB właściwości formatowania, zbyt wiele, aby go umieścić +@msg the Word document has too much text or formatting to place as type (at most {MAX_PARAGRAPHS} paragraphs, {MAX_RUNS} runs and {_1} MB of text) dokument Word ma zbyt dużo tekstu lub formatowania, aby umieścić go jako tekst (najwyżej {MAX_PARAGRAPHS} akapitów, {MAX_RUNS} ciągów formatowania i {_1} MB tekstu) +@msg the Word document has too much text to place as type (at most {_1} MB) dokument Word ma zbyt dużo tekstu, aby umieścić go jako tekst (najwyżej {_1} MB) +@msg the Word document is encrypted or protected with a password; save it without one to place it dokument Word jest zaszyfrowany lub chroniony hasłem; zapisz go bez hasła, aby go umieścić +@msg the Word document is too large to place (its {name} stream holds more than {_1} MB) dokument Word jest zbyt duży, aby go umieścić (jego strumień {name} zawiera ponad {_1} MB) +@msg the Word document was last saved with fast save, which VectorCraft doesn't read; save it again with fast save turned off dokument Word został ostatnio zapisany z użyciem szybkiego zapisywania, którego VectorCraft nie odczytuje; zapisz go ponownie z wyłączonym szybkim zapisywaniem +@msg the Word document was saved by Word 6.0 or Word 95, which VectorCraft doesn't read; save it as a Word 97-2003 document dokument Word został zapisany w programie Word 6.0 lub Word 95, których VectorCraft nie odczytuje; zapisz go jako dokument Word 97-2003 +@msg the Word document's text is made of more than {MAX_PIECES} pieces, too many to place tekst dokumentu Word składa się z ponad {MAX_PIECES} części, zbyt wielu, aby go umieścić +@msg the action set ids are not a list identyfikatory zestawów operacji nie są listą +@msg the active paint is not a gradient aktywne malowanie nie jest gradientem +@msg the artboards don't fit on the canvas: fewer artboards, less spacing or a smaller size obszary kompozycji nie mieszczą się na płótnie: użyj mniejszej liczby obszarów, mniejszych odstępów lub mniejszego rozmiaru +@msg the character's size can't be measured nie można zmierzyć rozmiaru znaku +@msg the compound shape is too complex to expand kształt złożony jest zbyt skomplikowany, aby go rozszerzyć +@msg the container of the listed objects is gone kontener wymienionych obiektów już nie istnieje +@msg the copy `{user_id}` can't be read as a library kopii `{user_id}` nie można odczytać jako biblioteki +@msg the copy would leave the canvas kopia wykroczyłaby poza płótno +@msg the cut cannot be made on this art: {e} na tej grafice nie można wykonać cięcia: {e} +@msg the data isn't an EMF or WMF picture dane nie są ilustracją EMF ani WMF +@msg the data isn't an EPS or PostScript picture dane nie są ilustracją EPS ani PostScript +@msg the deferred paste is no longer available odroczone wklejanie nie jest już dostępne +@msg the design is too big to draw at every data point of this graph wzór jest zbyt duży, aby narysować go w każdym punkcie danych tego wykresu +@msg the design is too big to draw in every column of this graph wzór jest zbyt duży, aby narysować go w każdej kolumnie tego wykresu +@msg the dialog it was opened over is no longer open okno dialogowe, nad którym zostało otwarte, nie jest już otwarte +@msg the dictionary stack overflowed stos słowników został przepełniony +@msg the editing data's hash has no place na skrót danych edycyjnych nie ma miejsca +@msg the entities the document declares expand to too much text encje deklarowane przez dokument rozwijają się do zbyt dużej ilości tekstu +@msg the envelope's content has no bounds zawartość koperty nie ma granic +@msg the envelope's mesh is malformed siatka koperty jest nieprawidłowo zbudowana +@msg the file holds no `variableSets` element plik nie zawiera elementu `variableSets` +@msg the file is larger than {_1} MB plik jest większy niż {_1} MB +@msg the file is too large plik jest zbyt duży +@msg the file was updated or encrypted already plik został już zaktualizowany lub zaszyfrowany +@msg the first character of a line has no character before it to kern: it moves only up and down (dy) pierwszy znak wiersza nie ma przed sobą znaku, względem którego można ustawić kerning: przesuwa się tylko w górę i w dół (dy) +@msg the font {_1} is not available czcionka {_1} nie jest dostępna +@msg the format has no file extension format nie ma rozszerzenia pliku +@msg the graphic can't be read: {e} nie można odczytać grafiki: {e} +@msg the graphic is empty grafika jest pusta +@msg the graphic's data is damaged dane grafiki są uszkodzone +@msg the graphic's document has no artboard dokument grafiki nie ma obszaru kompozycji +@msg the header `{cell}` for `{name}` would read back as the variable `{other}`: rename one of them nagłówek `{cell}` dla `{name}` zostałby odczytany jako zmienna `{other}`: zmień nazwę jednego z nich +@msg the image `{path}` isn't followed: {r} obraz `{path}` nie jest pobierany: {r} +@msg the image has no embedded pixels obraz nie ma osadzonych pikseli +@msg the image is empty obraz jest pusty +@msg the image is fully transparent obraz jest całkowicie przezroczysty +@msg the image is not on an artboard; pass rect obraz nie znajduje się na obszarze kompozycji; przekaż rect +@msg the image's pixels are missing brakuje pikseli obrazu +@msg the image's pixels aren't in the document piksele obrazu nie znajdują się w dokumencie +@msg the image's pixels can't be read: {e} nie można odczytać pikseli obrazu: {e} +@msg the image's transparency doesn't fit it przezroczystość obrazu do niego nie pasuje +@msg the job would print more than {MAX_PAGES} pages zadanie wydrukowałoby ponad {MAX_PAGES} stron +@msg the job would print more than {_1} pages zadanie wydrukowałoby ponad {_1} stron +@msg the layers hold no art to mask warstwy nie zawierają grafiki do zamaskowania +@msg the layout moved układ uległ przesunięciu +@msg the library has a group `{name}` already biblioteka ma już grupę `{name}` +@msg the library has no group `{name}` biblioteka nie ma grupy `{name}` +@msg the library has no item `{item}` biblioteka nie ma elementu `{item}` +@msg the library has no item `{other}` biblioteka nie ma elementu `{other}` +@msg the library holds {MAX_GROUPS} groups already biblioteka zawiera już {MAX_GROUPS} grup +@msg the library holds {MAX_ITEMS} items of this kind already biblioteka zawiera już {MAX_ITEMS} elementów tego rodzaju +@msg the name is empty nazwa jest pusta +@msg the object has no fill, stroke or effect obiekt nie ma wypełnienia, obrysu ani efektu +@msg the object has no graphic style (pass `name`) obiekt nie ma stylu graficznego (przekaż `name`) +@msg the objects don't match the plan obiekty nie odpowiadają planowi +@msg the open and permissions passwords must differ hasło otwarcia i hasło uprawnień muszą się różnić +@msg the operand stack overflowed stos operandów został przepełniony +@msg the page has no area strona nie ma powierzchni +@msg the page's type in an unread object's box isn't in its page art tekstu strony w polu nieodczytanego obiektu nie ma w grafice tej strony +@msg the paint behind the proxy is not a gradient malowanie wskazywane przez wskaźnik wypełnienia lub obrysu nie jest gradientem +@msg the parent must be a layer or sublayer elementem nadrzędnym musi być warstwa lub podwarstwa +@msg the path can't be extended ścieżki nie można przedłużyć +@msg the path can't be inside one of the objects to attach ścieżka nie może znajdować się wewnątrz jednego z dołączanych obiektów +@msg the path has no segments to measure ścieżka nie ma segmentów do zmierzenia +@msg the path is empty ścieżka jest pusta +@msg the path is too short to shorten that much ścieżka jest zbyt krótka, aby skrócić ją o tyle +@msg the picture has no objects ilustracja nie zawiera obiektów +@msg the program runs too long program działa zbyt długo +@msg the program uses too much memory program zużywa zbyt dużo pamięci +@msg the rectangle must have a width and a height prostokąt musi mieć szerokość i wysokość +@msg the rectangle needs a size and must lie on the canvas prostokąt wymaga rozmiaru i musi leżeć na płótnie +@msg the selected art has no width zaznaczona grafika nie ma szerokości +@msg the selection draws nothing zaznaczenie niczego nie rysuje +@msg the selection has no area zaznaczenie nie ma powierzchni +@msg the selection has no art to export zaznaczenie nie zawiera grafiki do wyeksportowania +@msg the selection has no bounds zaznaczenie nie ma granic +@msg the selection has no graphic style zaznaczenie nie ma stylu graficznego +@msg the slice would leave the canvas plasterek wykroczyłby poza płótno +@msg the spot colour couldn't be added nie udało się dodać koloru dodatkowego +@msg the subpath has no ends to extend (it is closed or a single point) ścieżka podrzędna nie ma końców do przedłużenia (jest zamknięta lub jest pojedynczym punktem) +@msg the symbols are nested too deeply to expand their instances symbole są zbyt głęboko zagnieżdżone, aby rozszerzyć ich wystąpienia +@msg the text file is too large to place as type (at most {_1} MB) plik tekstowy jest zbyt duży, aby umieścić go jako tekst (najwyżej {_1} MB) +@msg the text is empty tekst jest pusty +@msg the text is over {_1} MB tekst ma ponad {_1} MB +@msg the top object must be a path górny obiekt musi być ścieżką +@msg the trace was cancelled obrys został anulowany +@msg the trailer has no size sekcja trailer nie ma rozmiaru +@msg the type object is flattened to nothing po spłaszczeniu z obiektu tekstowego nic nie pozostaje +@msg the value of axis `{tag}` must be a number or null wartość osi `{tag}` musi być liczbą lub null +@msg the variable library declares more than {MAX_LIBRARY_DATASETS} data sets biblioteka zmiennych deklaruje więcej niż {MAX_LIBRARY_DATASETS} zestawów danych +@msg the variable library declares more than {MAX_LIBRARY_ENTITIES} entities biblioteka zmiennych deklaruje więcej niż {MAX_LIBRARY_ENTITIES} encji +@msg the variable library declares more than {MAX_LIBRARY_VARIABLES} variables biblioteka zmiennych deklaruje więcej niż {MAX_LIBRARY_VARIABLES} zmiennych +@msg the variable library declares no variables biblioteka zmiennych nie deklaruje żadnych zmiennych +@msg the variable library is larger than {MAX_LIBRARY_BYTES} bytes biblioteka zmiennych jest większa niż {MAX_LIBRARY_BYTES} bajtów +@msg the variable library is not UTF-8 biblioteka zmiennych nie jest w kodowaniu UTF-8 +@msg the variable library is not well-formed XML: {e} biblioteka zmiennych nie jest poprawnie sformułowanym kodem XML: {e} +@msg the variable library nests elements more than {MAX_LIBRARY_NESTING} deep biblioteka zmiennych zagnieżdża elementy głębiej niż na {MAX_LIBRARY_NESTING} poziomów +@msg the variable library's document type declaration holds something other than entities of plain text deklaracja typu dokumentu biblioteki zmiennych zawiera coś innego niż encje zwykłego tekstu +@msg the variable library's entities expand to more than {MAX_LIBRARY_BYTES} bytes encje biblioteki zmiennych rozwijają się do ponad {MAX_LIBRARY_BYTES} bajtów +@msg the window has no dock okno nie ma doku +@msg the written PDF has no catalog zapisany plik PDF nie ma katalogu +@msg the written PDF has no cross-reference table zapisany plik PDF nie ma tabeli odsyłaczy +@msg the written PDF's metadata can't be edited nie można edytować metadanych zapisanego pliku PDF +@msg there are no colour swatches to draw nie ma próbek kolorów do narysowania +@msg there is already a design named `{name}` istnieje już wzór o nazwie `{name}` +@msg there is already a design named `{to}` istnieje już wzór o nazwie `{to}` +@msg there is already a toolbar named `{name}` istnieje już pasek narzędzi o nazwie `{name}` +@msg there is already a toolbar named `{to}` istnieje już pasek narzędzi o nazwie `{to}` +@msg there is no library: create one first nie ma biblioteki: najpierw ją utwórz +@msg these paths are too degenerate for Shaper te ścieżki są zbyt zdegenerowane dla narzędzia Kształtowanie +@msg thumbnail: no page {v} (the {what} has {count}) thumbnail: brak strony {v} ({what} ma {count}) +@msg tileRange of {what}: {e} tileRange dla {what}: {e} +@msg title can't be empty title nie może być puste +@msg to (the new name) is required to (nowa nazwa) jest wymagane +@msg to must be fill or stroke to musi mieć wartość fill lub stroke +@msg to must be smooth or corner to musi mieć wartość smooth lub corner +@msg too large for a zip archive: package to a folder zbyt duże dla archiwum zip: spakuj do folderu +@msg too many Shaper edits zbyt wiele edycji narzędzia Kształtowanie +@msg too many `points` (at most 100000) zbyt wiele `points` (najwyżej 100000) +@msg too many characters: at most {MAX_CHARS} zbyt wiele znaków: najwyżej {MAX_CHARS} +@msg too many dots for this size: lower the frequency zbyt wiele kropek dla tego rozmiaru: zmniejsz częstotliwość +@msg too many filters over one file zbyt wiele filtrów na jednym pliku +@msg too many overlapping paths for Shaper zbyt wiele nakładających się ścieżek dla narzędzia Kształtowanie +@msg too many saved clips zbyt wiele zapisanych obszarów przycinania +@msg too many saved graphics states zbyt wiele zapisanych stanów grafiki +@msg toolbar (a toolbar's name) must be a string toolbar (nazwa paska narzędzi) musi być ciągiem znaków +@msg toolbar name can't be empty nazwa paska narzędzi nie może być pusta +@msg transparentImages {v}: "flatten" (the default) or "omit" transparentImages {v}: "flatten" (domyślnie) lub "omit" +@msg two saved selections would be named `{_1}` dwa zapisane zaznaczenia miałyby nazwę `{_1}` +@msg type dimension cannot be represented with this text transform wymiaru tekstu nie można przedstawić przy tym przekształceniu tekstu +@msg type dimension must be finite wymiar tekstu musi być skończony +@msg unexpected resources nieoczekiwane zasoby +@msg unknown CMYK profile `{name}` nieznany profil CMYK `{name}` +@msg unknown File Info field `{k}` nieznane pole informacji o pliku `{k}` +@msg unknown OpenType feature `{t}` in featureChanges (the tags `features` takes) nieznana funkcja OpenType `{t}` w featureChanges (znaczniki przyjmowane przez `features`) +@msg unknown PDF preset `{name}` (presets: {_1}) nieznane ustawienie PDF `{name}` (ustawienia: {_1}) +@msg unknown Warp style nieznany styl wypaczenia +@msg unknown alignToPath `{a}` nieznane alignToPath `{a}` +@msg unknown arrowhead {v} nieznany grot strzałki {v} +@msg unknown artboardLayout key `{k}` (layout, columns, spacing, rightToLeft) nieznany klucz artboardLayout `{k}` (layout, columns, spacing, rightToLeft) +@msg unknown attribute `{attribute}` nieznany atrybut `{attribute}` +@msg unknown attribute `{k}` nieznany atrybut `{k}` +@msg unknown axis `{other}` (vertical|horizontal|free) nieznana oś `{other}` (vertical|horizontal|free) +@msg unknown blend mode `{b}` nieznany tryb mieszania `{b}` +@msg unknown blend mode {b} nieznany tryb mieszania {b} +@msg unknown brush type `{o}` nieznany typ pędzla `{o}` +@msg unknown category `{c}` nieznana kategoria `{c}` +@msg unknown category `{c}` ({_1}) nieznana kategoria `{c}` ({_1}) +@msg unknown character `{c}` nieznany znak `{c}` +@msg unknown character style number field nieznane pole liczbowe stylu znakowego +@msg unknown effect `{e}` nieznany efekt `{e}` +@msg unknown end {e} nieznany koniec {e} +@msg unknown flattenerPreset `{name}` (High Resolution, Medium Resolution, Low Resolution or a saved one: see flattener.presets.list) nieznane flattenerPreset `{name}` (High Resolution, Medium Resolution, Low Resolution lub zapisane ustawienie: patrz flattener.presets.list) +@msg unknown format `{f}` (vcswatches, gpl, ase or css) nieznany format `{f}` (vcswatches, gpl, ase lub css) +@msg unknown from {f} nieznane from {f} +@msg unknown graph type `{t}` nieznany typ wykresu `{t}` +@msg unknown grid colours `{name}` (one of {_1}) nieznane kolory siatki `{name}` (jedna z wartości: {_1}) +@msg unknown gridType `{t}` nieznane gridType `{t}` +@msg unknown highlight `{v}` nieznane wyróżnienie `{v}` +@msg unknown intent `{i}` nieznana metoda konwersji kolorów `{i}` +@msg unknown issue kind {id} nieznany rodzaj problemu {id} +@msg unknown issue kind {v} nieznany rodzaj problemu {v} +@msg unknown knockout state {k} nieznany stan wybijania {k} +@msg unknown language `{language}` (one of {_1}) nieznany język `{language}` (jedna z wartości: {_1}) +@msg unknown language `{l}` (one of {_1}) nieznany język `{l}` (jedna z wartości: {_1}) +@msg unknown method `{m}` ({_1}) nieznana metoda `{m}` ({_1}) +@msg unknown mode `{other}` (gray, rgb, hsb, lab, cmyk or web) nieznany tryb `{other}` (gray, rgb, hsb, lab, cmyk lub web) +@msg unknown mode `{other}` (mono|cmyk) nieznany tryb `{other}` (mono|cmyk) +@msg unknown mode `{other}` (rgb|cmyk|gray|global) nieznany tryb `{other}` (rgb|cmyk|gray|global) +@msg unknown mode `{other}` (set, add, subtract) nieznany tryb `{other}` (set, add, subtract) +@msg unknown mode `{o}` nieznany tryb `{o}` +@msg unknown mode {m} nieznany tryb {m} +@msg unknown model `{other}` nieznany model `{other}` +@msg unknown model `{other}` (keep, new or document) nieznany model `{other}` (keep, new lub document) +@msg unknown op {o} nieznane op {o} +@msg unknown order `{o}`: toggle, front, forward, backward or back nieznane order `{o}`: toggle, front, forward, backward lub back +@msg unknown overprints `{v}` (preserve, simulate or discard) nieznane overprints `{v}` (preserve, simulate lub discard) +@msg unknown panel nieznany panel +@msg unknown pieLegend `{v}` (none, standard or wedges) nieznane pieLegend `{v}` (none, standard lub wedges) +@msg unknown piePosition `{v}` (even, ratio or stacked) nieznane piePosition `{v}` (even, ratio lub stacked) +@msg unknown pieSort `{v}` (none, all or first) nieznane pieSort `{v}` (none, all lub first) +@msg unknown plate `{n}` nieznana płyta `{n}` +@msg unknown preference `{k}` nieznana preferencja `{k}` +@msg unknown profile {id} (see stroke.widthProfile.list) nieznany profil {id} (patrz stroke.widthProfile.list) +@msg unknown proof target `{t}` nieznany cel próby kolorów `{t}` +@msg unknown quotes key `{k}` (double, single) nieznany klucz quotes `{k}` (double, single) +@msg unknown resolution `{v}` nieznana rozdzielczość `{v}` +@msg unknown rule `{rule}` ({_1}) nieznana reguła `{rule}` ({_1}) +@msg unknown rule `{r}` (see color.harmony) nieznana reguła `{r}` (patrz color.harmony) +@msg unknown setting `{k}` nieznane ustawienie `{k}` +@msg unknown shape `{v}` (circle|ellipse|square|diamond|line) nieznany kształt `{v}` (circle|ellipse|square|diamond|line) +@msg unknown spacing `{o}` (smooth|steps|distance) nieznane spacing `{o}` (smooth|steps|distance) +@msg unknown tileType `{t}` ({_1}) nieznane tileType `{t}` ({_1}) +@msg unknown units nieznane jednostki +@msg unknown units `{u}` nieznane jednostki `{u}` +@msg unknown value axis `{v}` (left, right or both) nieznana oś wartości `{v}` (left, right lub both) +@msg unknown variation `{v}` (tintsShades|warmCool|vividMuted) nieznana odmiana `{v}` (tintsShades|warmCool|vividMuted) +@msg unknown warp style `{s}` nieznany styl wypaczenia `{s}` +@msg unknown {key} `{v}` (none, short or full) nieznane {key} `{v}` (none, short lub full) +@msg unknown {key} profile `{n}` nieznany profil {key} `{n}` +@msg unknown {k} key `{key}` (size, position) nieznany klucz {k} `{key}` (size, position) +@msg unreadable object nieczytelny obiekt +@msg unsafe destination file name niebezpieczna nazwa pliku docelowego +@msg use paths or compound paths użyj ścieżek lub ścieżek złożonych +@msg useArtboards must be true or false, not {v} useArtboards musi mieć wartość true lub false, a nie {v} +@msg value for `{var}` must match its variable kind wartość dla `{var}` musi odpowiadać rodzajowi zmiennej +@msg variable `{_1}` is already defined zmienna `{_1}` jest już zdefiniowana +@msg variable `{name}` has no `trait` zmienna `{name}` nie ma `trait` +@msg variable `{name}` is already defined zmienna `{name}` jest już zdefiniowana +@msg variable `{name}` is declared twice zmienną `{name}` zadeklarowano dwa razy +@msg variable `{to}` already exists zmienna `{to}` już istnieje +@msg view is required view jest wymagane +@msg view must be one of {_1} view musi mieć jedną z wartości: {_1} +@msg warpStyle can only edit an applied Warp effect warpStyle może edytować tylko zastosowany efekt Wypaczenie +@msg width and height must be more than 0 and at most {limit} width i height muszą być większe od 0 i nie większe niż {limit} +@msg width factors must be finite współczynniki szerokości muszą być skończone +@msg width must be positive width musi być wartością dodatnią +@msg width out of range szerokość poza zakresem +@msg width/height must be > 0 width/height muszą być > 0 +@msg x and y must be finite numbers x i y muszą być liczbami skończonymi +@msg x and y must be given together x i y muszą być podane razem +@msg zone needs an anchor: dock beside a panel with anchor, or in a new dock column with side (Start or End) zone wymaga punktu odniesienia: zadokuj obok panelu za pomocą anchor albo w nowej kolumnie doku za pomocą side (Start lub End) +@msg zoom must be positive zoom musi być wartością dodatnią +@msg {C}: no effect at index {list} {C}: brak efektu o indeksie {list} +@msg {DEFAULT_PRESET} is protected and stays {DEFAULT_PRESET} jest chronione i pozostaje +@msg {DEFAULT_PRESET} is protected: save the settings under another name {DEFAULT_PRESET} jest chronione: zapisz ustawienia pod inną nazwą +@msg {LABEL} produced an empty result {LABEL}: wynik jest pusty +@msg {_1} MB of document, at most {_2} MB {_1} MB dokumentu, dozwolone najwyżej {_2} MB +@msg {_1} MB of images, at most {_2} MB {_1} MB obrazów, dozwolone najwyżej {_2} MB +@msg {_1} bytes of RGBA data for a {width} × {height} image {_1} bajtów danych RGBA dla obrazu {width} × {height} +@msg {_1} can't be read, or changed since it was read: relink or update it first {_1} nie można odczytać albo zmieniło się od czasu odczytu: najpierw połącz ponownie lub zaktualizuj +@msg {_1} can't go into {into} {_1} nie można umieścić w {into} +@msg {_1} can't limit printing to low resolution: choose PDF 1.4 or later, or allow high-resolution printing {_1} nie może ograniczyć drukowania do niskiej rozdzielczości: wybierz PDF 1.4 lub nowszy albo zezwól na drukowanie w wysokiej rozdzielczości +@msg {_1} files can't be opened yet plików {_1} nie można jeszcze otwierać +@msg {_1} files can't be password-protected: remove the passwords or choose no standard plików {_1} nie można chronić hasłem: usuń hasła albo nie wybieraj standardu +@msg {_1} files can't be {_2} pliki {_1} nie mogą być {_2} +@msg {_1} files can't carry editing data: turn off preserveEditing pliki {_1} nie mogą zawierać danych edycyjnych: wyłącz preserveEditing +@msg {_1} files can't have PDF layers: turn off createLayers pliki {_1} nie mogą mieć warstw PDF: wyłącz createLayers +@msg {_1} files need a creation date, and this platform has no clock to give one pliki {_1} wymagają daty utworzenia, a ta platforma nie ma zegara, który by ją podał +@msg {_1} isn't a path {_1} nie jest ścieżką +@msg {_1} options: {e} opcje {_1}: {e} +@msg {_1} paints nothing to rasterize {_1} nie maluje niczego, co można zrasteryzować +@msg {_1} passwords can have up to {MAX_LEGACY_PASSWORD} ASCII characters (PDF 1.7 and later take any) hasła {_1} mogą mieć najwyżej {MAX_LEGACY_PASSWORD} znaków ASCII (PDF 1.7 i nowsze przyjmują dowolne) +@msg {_1} with linked images or an image map writes several files: use document.export {_1} z połączonymi obrazami lub mapą obrazu zapisuje kilka plików: użyj document.export +@msg {_1} writes one file per artboard here: use document.export, or name one artboard {_1} zapisuje tu jeden plik na obszar kompozycji: użyj document.export albo wskaż jeden obszar kompozycji +@msg {_1} × {_2} pixels is too large for {_3} (at most {max} pixels a side): lower the scale {_1} × {_2} pikseli to zbyt dużo dla {_3} (najwyżej {max} pikseli na bok): zmniejsz skalę +@msg {_1}: belongs to another account {_1}: należy do innego konta +@msg {_1}: not a folder of its own {_1}: to nie jest osobny folder +@msg {_1}: not a plain file {_1}: to nie jest zwykły plik +@msg {dest}: {e} {dest}: {e} +@msg {doc} has no folder {doc} nie ma folderu +@msg {file} isn't linked {file} nie jest połączony +@msg {folder} is not a package folder {folder} nie jest folderem pakietu +@msg {folder}: more than {max} files and folders {folder}: więcej niż {max} plików i folderów +@msg {folder}: {e} {folder}: {e} +@msg {g} is not a Live Paint group {g} nie jest grupą aktywnego malowania +@msg {id} is not a slice {id} nie jest plasterkiem +@msg {key} must be 0–{MAX_ADD_AROUND} pt {key} musi wynosić 0–{MAX_ADD_AROUND} pt +@msg {key} must be [x,y] {key} musi mieć postać [x,y] +@msg {key} must be a percentage {min}..100 {key} musi być wartością procentową z zakresu {min}..100 +@msg {key} must be a positive number, not {n} {key} musi być liczbą dodatnią, a nie {n} +@msg {key} must be a positive number, not {v} {key} musi być liczbą dodatnią, a nie {v} +@msg {key} must be one of {_1} {key} musi mieć jedną z wartości: {_1} +@msg {key} must be {_1}, got {s} {key} musi mieć wartość {_1}, podano {s} +@msg {key} must name a floating panel {key} musi wskazywać panel pływający +@msg {key} must name a panel in another group {key} musi wskazywać panel w innej grupie +@msg {key} must name a panel that shows {key} musi wskazywać wyświetlany panel +@msg {key} must name a registered panel {key} musi wskazywać zarejestrowany panel +@msg {kind} files have no transparency, and the file would have {what}: flatten it first (object.flattenTransparency) pliki {kind} nie obsługują przezroczystości, a plik zawierałby {what}: najpierw spłaszcz przezroczystość (object.flattenTransparency) +@msg {kind} images can't be opened (see document.formats) obrazów {kind} nie można otwierać (patrz document.formats) +@msg {k} `{v}` is not one of the choices {k} `{v}` nie jest jedną z dostępnych opcji +@msg {k} has control characters{_1} {k} zawiera znaki sterujące{_1} +@msg {k} is too long (at most {MAX_TEXT} characters) {k} jest zbyt długie (najwyżej {MAX_TEXT} znaków) +@msg {k} must be > 0 {k} musi być > 0 +@msg {k} must be a number (pt) or a length such as "210 mm" {k} musi być liczbą (pt) lub długością, na przykład "210 mm" +@msg {k} must be a number from {min} to {max} {k} musi być liczbą od {min} do {max} +@msg {k} must be a number or "auto" {k} musi być liczbą lub wartością "auto" +@msg {k} must be a string {k} musi być ciągiem znaków +@msg {k} must be text {k} musi być tekstem +@msg {k} must be true or false {k} musi mieć wartość true lub false +@msg {k} must be {{size?, position?}} {k} musi mieć postać {{size?, position?}} +@msg {k}: can't read `{s}` as a length {k}: nie można odczytać `{s}` jako długości +@msg {label} must be a number at most {max} {label} musi być liczbą nie większą niż {max} +@msg {label} must be a number from -1296 to 1296 {label} musi być liczbą od -1296 do 1296 +@msg {label} must be a number from 1 to 10000 {label} musi być liczbą od 1 do 10000 +@msg {name} `{s}`: {ids} {name} `{s}`: {ids} +@msg {name} is built in and can't be deleted {name} jest wbudowane i nie można go usunąć +@msg {name} must be {lo}–{hi}{unit} (got {v}) {name} musi wynosić {lo}–{hi}{unit} (podano {v}) +@msg {name}: CRC or size mismatch {name}: niezgodność CRC lub rozmiaru +@msg {name}: only this Affinity file's embedded preview could be read; use File › Open to see it with its warning, or export SVG or PDF from Affinity before placing {name}: udało się odczytać tylko osadzony podgląd tego pliku Affinity; użyj polecenia Plik › Otwórz, aby zobaczyć go wraz z ostrzeżeniem, albo przed umieszczeniem wyeksportuj SVG lub PDF z programu Affinity +@msg {name}: {e} {name}: {e} +@msg {native}; its embedded preview can't be read either ({e}) {native}; jego osadzonego podglądu również nie można odczytać ({e}) +@msg {std} files are CMYK, and the file would have colours in {_1} pliki {std} są w CMYK, a plik zawierałby kolory w {_1} +@msg {std} files embed their fonts, and the file would have one that isn't pliki {std} osadzają swoje czcionki, a plik zawierałby czcionkę nieosadzoną +@msg {target} is the file this document was read from, and reading it left things out ({what}): writing over it would lose them for good. Write another file instead, or pass acknowledgeLoss: true to replace it anyway {target} to plik, z którego odczytano ten dokument, a przy odczycie pominięto część zawartości ({what}): nadpisanie go spowodowałoby jej trwałą utratę. Zapisz zamiast tego inny plik albo przekaż acknowledgeLoss: true, aby mimo to go zastąpić +@msg {ty} brushes need selected art (or params.{k}) pędzle {ty} wymagają zaznaczonej grafiki (lub params.{k}) +@msg {v} is not an asset id {v} nie jest identyfikatorem zasobu +@msg {what} can't be intertwined {what} nie można przeplatać +@msg {what} doesn't fit the paper with its bleed and marks {what} nie mieści się na papierze wraz ze spadem i znacznikami +@msg {what} would print on more than {MAX_TILES} tiles: scale it down {what}: wydruk zająłby ponad {MAX_TILES} kafelków: zmniejsz skalę diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index d4a2493914..50690fa0c7 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -7102,3 +7102,1814 @@ breakText Glyphs Гліфи Grommets Люверси Grommet Inset Відступ люверсів від краю Diameter Діаметр +@msg 'caller', 'callee' and 'arguments' cannot be used on strict mode functions 'caller', 'callee' і 'arguments' не можна використовувати для функцій суворого режиму +@msg A profile supports one Revolve effect. Edit the existing effect's options instead. Профіль підтримує один ефект «Обертання». Змініть натомість параметри наявного ефекту. +@msg Add Points at Crossings: a path went missing Додати точки на перетинах: контур зник +@msg Boolean.prototype.{name} was called on a value that is not a Boolean Boolean.prototype.{name} викликано для значення, яке не є Boolean +@msg CMYK images whose samples couldn't be read in CMYK were imported in RGB Зображення CMYK, відліки яких не вдалося прочитати в CMYK, імпортовано в RGB +@msg CSS options: {e} Параметри CSS: {e} +@msg CSV has a header but no data rows CSV має заголовок, але не має рядків даних +@msg CSV holds NUL bytes: save it as UTF-8, or as UTF-16 with a byte-order mark CSV містить байти NUL: збережіть його як UTF-8 або як UTF-16 з міткою порядку байтів +@msg CSV is empty CSV порожній +@msg CSV is larger than {MAX_CSV_BYTES} bytes CSV більший за {MAX_CSV_BYTES} байтів +@msg CSV is not UTF-16 CSV не є UTF-16 +@msg CSV is not UTF-8 CSV не є UTF-8 +@msg CSV would be larger than {MAX_CSV_BYTES} bytes CSV був би більшим за {MAX_CSV_BYTES} байтів +@msg Cannot write to the location of “{name}”; choose where to save it Не вдається записати в розташування «{name}»; виберіть, куди зберегти файл +@msg Choose original artwork, not a dimension's generated paths Виберіть вихідну графіку, а не створені розміром контури +@msg Contour: select paths or shapes Еквідистанта: виділіть контури або фігури +@msg Contour: the Offset Path effect is not available Еквідистанта: ефект «Зміщення контуру» недоступний +@msg Create needs fills, strokes or both Для створення потрібні заливки, обведення або те й інше +@msg DCS files can only be placed linked: use File › Place with Link on Файли DCS можна помістити лише як пов’язані: скористайтеся командою Файл › Помістити з увімкненим параметром «Зв’язати» +@msg DXF options: {e} Параметри DXF: {e} +@msg DXF scale must be a positive number up to {_1}, not {scale} Масштаб DXF має бути додатним числом не більше {_1}, а не {scale} +@msg DXF {field} `{s}`: {allowed} DXF {field} `{s}`: {allowed} +@msg Date.prototype method called on a value that is not a Date object Метод Date.prototype викликано для значення, яке не є об’єктом Date +@msg Dimension is locked or hidden Розмір заблоковано або приховано +@msg Dimension mode does not match its source Режим розміру не відповідає його джерелу +@msg Draw Inside needs exactly one selected path, compound path or text Для режиму «Малювати всередині» потрібен рівно один виділений контур, складений контур або текст +@msg EPS Save writes all artwork: use document.export for selected-only EPS Збереження EPS записує всю графіку: для EPS лише з виділеним скористайтеся document.export +@msg EPS flattener: {e} Зведення прозорості EPS: {e} +@msg EPS options: {e} Параметри EPS: {e} +@msg EPS {field} `{s}`: {allowed} EPS {field} `{s}`: {allowed} +@msg Error.prototype.toString was called on a value that is not an object Error.prototype.toString викликано для значення, яке не є об’єктом +@msg Export for Screens writes png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai or vectorcraft Експорт для екранів записує png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai або vectorcraft +@msg Flare click coordinates must be finite numbers Координати клацання для відблиску мають бути скінченними числами +@msg Function.prototype.toString was called on a value that is not a function Function.prototype.toString викликано для значення, яке не є функцією +@msg HTML Text applies to object slices of type only Текст HTML застосовується лише до фрагментів на основі текстових об’єктів +@msg Identify Objects By is XML ID: the name must be a valid XML ID (start with a letter, underscore or colon; no spaces) Об’єкти ідентифікуються за XML ID: ім’я має бути припустимим XML ID (починатися з літери, підкреслення або двокрапки; без пробілів) +@msg Image Trace failed: internal error: its thread stopped (please report this bug) Трасування зображення не вдалося: внутрішня помилка: його потік зупинився (будь ласка, повідомте про цю помилку) +@msg Image Trace failed: {e} Трасування зображення не вдалося: {e} +@msg Image Trace finished, but its document was closed Трасування зображення завершено, але його документ закрито +@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Трасування зображення завершено, але зображення або його параметри тим часом змінилися: виконайте трасування ще раз +@msg Import SVG Filter reads SVG files, not SVGZ Імпорт фільтра SVG читає файли SVG, а не SVGZ +@msg Invalid dimension offset Неприпустиме зміщення розміру +@msg Invalid point Неприпустима точка +@msg JSON.parse: {why} (at offset {at}) JSON.parse: {why} (зі зміщенням {at}) +@msg JSON.stringify cannot write a structure that contains itself JSON.stringify не може записати структуру, яка містить саму себе +@msg Join: a subpath went missing З’єднання: вкладений контур зник +@msg Lock Workspace is not available in VectorCraft Блокування робочого середовища недоступне у VectorCraft +@msg Move Panel to New Window is not available: floating panels stay in the main window Переміщення панелі в нове вікно недоступне: плаваючі панелі залишаються в головному вікні +@msg Namespace.prototype.toString needs a Namespace Для Namespace.prototype.toString потрібен Namespace +@msg New Document profiles need the preferences folder, which this run doesn't have Профілям нових документів потрібна папка налаштувань, якої в цьому запуску немає +@msg Number.prototype.{name} was called on a value that is not a number Number.prototype.{name} викликано для значення, яке не є числом +@msg Object.create's prototype must be an object or null Прототип для Object.create має бути об’єктом або null +@msg Object.{function} was given a value that is not an object Object.{function} отримала значення, яке не є об’єктом +@msg Offset Path: the path is too complex to offset Зміщення контуру: контур занадто складний для зміщення +@msg Offset Path: {e} Зміщення контуру: {e} +@msg PDF content is incomplete or exceeds the reader's limits; no document was imported Вміст PDF неповний або перевищує обмеження засобу читання; документ не імпортовано +@msg PDF flattener: {e} Зведення прозорості PDF: {e} +@msg PDF options: {e} Параметри PDF: {e} +@msg QName.prototype.toString needs a QName Для QName.prototype.toString потрібен QName +@msg Recolor Artwork is no longer open Вікно «Перефарбувати малюнок» уже закрито +@msg RegExp.prototype.{name} was called on a value that is not a RegExp object RegExp.prototype.{name} викликано для значення, яке не є об’єктом RegExp +@msg SVG is not UTF-8, UTF-16 or ISO 8859-1 SVG не є UTF-8, UTF-16 або ISO 8859-1 +@msg Save writes one artboard: name one, or export several with document.export Збереження записує одну монтажну область: укажіть одну або експортуйте кілька за допомогою document.export +@msg Select a dimension first Спочатку виділіть розмір +@msg Select dimensions to update Виділіть розміри для оновлення +@msg Select only dimensions Виділіть лише розміри +@msg Select two or more objects, or a group Виділіть два або більше об’єктів чи групу +@msg Shaper needs 1–64 source paths Для формоутворення потрібно 1–64 вихідних контурів +@msg Stencil Bridges: the selected art is too large or too detailed to bridge Містки трафарету: виділена графіка завелика або занадто детальна для створення містків +@msg String.prototype.toString was called on a value that is not a string String.prototype.toString викликано для значення, яке не є рядком +@msg Switch x/y is for scatter graphs Команда «Поміняти x/y» призначена для точкових діаграм +@msg Text options: {e} Параметри тексту: {e} +@msg The {name} profile could not be read, so the new document has the default settings: {reason} Не вдалося прочитати профіль {name}, тому новий документ має параметри за замовчуванням: {reason} +@msg Trap: more than {_1} pairs of objects lie close enough to trap, or too many objects share a horizontal range; trap fewer objects at a time Трепінг: понад {_1} пар об’єктів розташовані достатньо близько для трепінгу або забагато об’єктів мають спільний горизонтальний діапазон; обробляйте менше об’єктів за раз +@msg Weed Box and Lines: no weeding line fits outside the art, and the weed box is off Рамка й лінії вибірки: жодна лінія вибірки не вміщується поза графікою, а рамку вибірки вимкнено +@msg \\ at end of pattern \\ наприкінці шаблону +@msg `alignOn` cannot be empty `alignOn` не може бути порожнім +@msg `alignOn` must be a string `alignOn` має бути рядком +@msg `align` is start, center or end `align` — це start, center або end +@msg `align` must be a string `align` має бути рядком +@msg `anchors` must be an array of [subpath, anchor] pairs `anchors` має бути масивом пар [subpath, anchor] +@msg `anchors` must list anchor indices (0, 1, 2…), not {k} `anchors` має містити індекси опорних точок (0, 1, 2…), а не {k} +@msg `anchors` must list anchor indices (0, 1, 2…), not {v} `anchors` має містити індекси опорних точок (0, 1, 2…), а не {v} +@msg `answer` for this {kind} dialog must be one of: {_1} `answer` для цього діалогового вікна ({kind}) має бути одним з: {_1} +@msg `answers` has more than {MAX_ANSWERS} answers `answers` містить понад {MAX_ANSWERS} відповідей +@msg `answers` is larger than 1 MiB `answers` більший за 1 МіБ +@msg `answers` must be a list of answers `answers` має бути списком відповідей +@msg `artboard` must be the index of an artboard of the document `artboard` має бути індексом монтажної області документа +@msg `artboardsAt` must be [x, y] `artboardsAt` має бути [x, y] +@msg `artboards` must be a list of artboard indices `artboards` має бути списком індексів монтажних областей +@msg `artboards` names an artboard the document does not have `artboards` указує монтажну область, якої немає в документі +@msg `artboards` names an artboard twice `artboards` указує монтажну область двічі +@msg `asset` is the asset id (see assets.list) `asset` — це ідентифікатор ресурсу (див. assets.list) +@msg `at` must be [x, y] (got {at}) `at` має бути [x, y] (отримано {at}) +@msg `at` must be a byte offset `at` має бути зміщенням у байтах +@msg `autoLeading` must be a number `autoLeading` має бути числом +@msg `background` must be "", "matte" or #rrggbb `background` має бути "", "matte" або #rrggbb +@msg `beside` needs `side` для `beside` потрібен `side` +@msg `burasagari` must be "none", "standard" or "forced" `burasagari` має бути "none", "standard" або "forced" +@msg `center` must be [x, y] `center` має бути [x, y] +@msg `charAlign` must be "romanBaseline", "emBoxTop", "emBoxCenter", "emBoxBottom", "icfTop" or "icfBottom" `charAlign` має бути "romanBaseline", "emBoxTop", "emBoxCenter", "emBoxBottom", "icfTop" або "icfBottom" +@msg `charDirection` must be "default", "leftToRight" or "rightToLeft" `charDirection` має бути "default", "leftToRight" або "rightToLeft" +@msg `clearStroke` requires `stroke: false`, `ids: []` and no `stop` для `clearStroke` потрібні `stroke: false`, `ids: []` і відсутність `stop` +@msg `clear` must be a list of type object ids, not {v} `clear` має бути списком ідентифікаторів текстових об’єктів, а не {v} +@msg `clear` must list type objects; {_1} is not one `clear` має містити текстові об’єкти; {_1} не є текстовим об’єктом +@msg `clear` must not list `id` `clear` не має містити `id` +@msg `code` must be a whole number `code` має бути цілим числом +@msg `colorMode` must be one of rgb, cmyk `colorMode` має бути одним з: rgb, cmyk +@msg `color` needs a `rule` to make the theme from для `color` потрібне `rule`, за яким створюється тема +@msg `colors` does not apply to the {name} reduction `colors` не застосовується до скорочення кольорів {name} +@msg `colors` is empty `colors` порожній +@msg `colors` must be a whole number from 2 to 256 `colors` має бути цілим числом від 2 до 256 +@msg `colors` must be at least 9 for the uniform reduction `colors` має бути не менше 9 для рівномірного скорочення кольорів +@msg `colors` must be between 1 and {MAX_THEME_COLORS} (got {n}) `colors` має бути від 1 до {MAX_THEME_COLORS} (отримано {n}) +@msg `columnType` is vertical, uniform, repeating or sliding `columnType` — це vertical, uniform, repeating або sliding +@msg `columns` must be a whole number 1..50 `columns` має бути цілим числом 1..50 +@msg `commands` must not be empty `commands` не має бути порожнім +@msg `contents` goes with `to` `contents` використовується разом із `to` +@msg `corners` must be sharp, round or square, not `{other}` `corners` має бути sharp, round або square, а не `{other}` +@msg `corners` must list anchor indices (0, 1, 2…), not {v} `corners` має містити індекси опорних точок (0, 1, 2…), а не {v} +@msg `count` must be a whole number from 0 to {MAX_COUNT} `count` має бути цілим числом від 0 до {MAX_COUNT} +@msg `count` must be a whole number from 1 to 100 `count` має бути цілим числом від 1 до 100 +@msg `dataBase64` is larger than the module limit `dataBase64` перевищує обмеження модуля +@msg `dataBase64` is not valid base64 `dataBase64` не є припустимим base64 +@msg `defaultsOnly` cannot be combined with `ids`, `reverse` or `append` `defaultsOnly` не можна поєднувати з `ids`, `reverse` або `append` +@msg `depth` and `childLimit` slice the summary: pass `summary: true` `depth` і `childLimit` обмежують зведення: передайте `summary: true` +@msg `design` is a design name, or null for plain columns `design` — це назва дизайну або null для звичайних стовпців +@msg `design` is a design name, or null for the default marker `design` — це назва дизайну або null для стандартного маркера +@msg `destinationFolder` is required when destination is `folder` `destinationFolder` обов’язковий, коли призначенням є `folder` +@msg `destination` must be `none`, `saveAndClose` or `folder` `destination` має бути `none`, `saveAndClose` або `folder` +@msg `diameter` must be from 0.1 to 2500 pt `diameter` має бути від 0.1 до 2500 pt +@msg `digits` must be one of {_1} `digits` має бути одним з: {_1} +@msg `dimImages` is a percentage or false `dimImages` — це відсоток або false +@msg `direction` must be "auto", "leftToRight" or "rightToLeft" `direction` має бути "auto", "leftToRight" або "rightToLeft" +@msg `ditherAmount` must be a number from 0 to 100 `ditherAmount` має бути числом від 0 до 100 +@msg `each` is the value one design stands for, more than 0 `each` — це значення, якому відповідає один дизайн, більше 0 +@msg `end` must be "start" or "end" `end` має бути "start" або "end" +@msg `ends` applies to joining exactly two paths `ends` застосовується до з’єднання рівно двох контурів +@msg `event` must be one of {_1} `event` має бути одним з: {_1} +@msg `every` must be "all", "odd" or "even", not {v} `every` має бути "all", "odd" або "even", а не {v} +@msg `expand` must be true or false `expand` має бути true або false +@msg `fidelity` must be from {lo} to {hi} pt `fidelity` має бути від {lo} до {hi} pt +@msg `files` must be 1 to 1000 paths of font files the last text.findFontFiles search found `files` має містити від 1 до 1000 шляхів файлів шрифтів, які знайшов останній пошук text.findFontFiles +@msg `focal` and `radius` cannot be used together `focal` і `radius` не можна використовувати разом +@msg `focal` must be an array of [subpath, anchor] pairs `focal` має бути масивом пар [subpath, anchor] +@msg `focal` names [{si}, {ai}], which is not an anchor of the path `focal` указує [{si}, {ai}], що не є опорною точкою контуру +@msg `folder` must be an absolute folder path `folder` має бути абсолютним шляхом до папки +@msg `fontAxes` must be an object of axis tags and values, such as {"wght"} `fontAxes` має бути об’єктом тегів осей і значень, наприклад {"wght"} +@msg `format` must be a string `format` має бути рядком +@msg `format` must be one of {_1} `format` має бути одним з: {_1} +@msg `fractions` is chop or scale `fractions` — це chop або scale +@msg `from` and `to` must differ `from` і `to` мають відрізнятися +@msg `from` has an empty frame `from` має порожню рамку +@msg `from` must be a non-negative integer `from` має бути невід’ємним цілим числом +@msg `from` must be area type or type on a path `from` має бути текстом в області або текстом за контуром +@msg `gid` must be a glyph id, not {v} `gid` має бути ідентифікатором гліфа, а не {v} +@msg `glyphAlternate` belongs to one character, not to a character style (text.setGlyphAlternate sets it) `glyphAlternate` стосується одного символу, а не стилю символу (його задає text.setGlyphAlternate) +@msg `glyphAlternate` takes only null, which takes a glyph choice away (text.setGlyphAlternate makes one) `glyphAlternate` приймає лише null, що скасовує вибір гліфа (вибір робить text.setGlyphAlternate) +@msg `group` must be one of {_1} `group` має бути одним з: {_1} +@msg `group` must be the Objects on Path group of `member` and `target` `group` має бути групою «Об’єкти на контурі», до якої належать `member` і `target` +@msg `guide` must be a guide index (guide.list) `guide` має бути індексом напрямної (guide.list) +@msg `hAlign` must be default, left, center or right `hAlign` має бути default, left, center або right +@msg `id` is an object id, not {v} `id` — це ідентифікатор об’єкта, а не {v} +@msg `id` must be a node id `id` має бути ідентифікатором вузла +@msg `id` must be an object id, not {v} `id` має бути ідентифікатором об’єкта, а не {v} +@msg `ids` must name Objects on Path groups or objects in them `ids` має вказувати групи «Об’єкти на контурі» або об’єкти в них +@msg `ids` takes at most {MAX_INSPECT_IDS} ids `ids` приймає не більше {MAX_INSPECT_IDS} ідентифікаторів +@msg `imageMap` must be none, rectangle or polygon `imageMap` має бути none, rectangle або polygon +@msg `includeArtboardFill` must be true or false `includeArtboardFill` має бути true або false +@msg `includeSubdirs` must be true or false `includeSubdirs` має бути true або false +@msg `index` must be a point index `index` має бути індексом точки +@msg `index` must be a whole number or null `index` має бути цілим числом або null +@msg `indices` must be a non-empty array of item indices `indices` має бути непорожнім масивом індексів елементів +@msg `item` needs `index` для `item` потрібен `index` +@msg `items` is a list of {kind, item} `items` — це список {kind, item} +@msg `items` is empty `items` порожній +@msg `items` must be a list of {id, points} `items` має бути списком {id, points} +@msg `items` must be a list of {{id, anchors?}}, not {v} `items` має бути списком {{id, anchors?}}, а не {v} +@msg `items` must be an array of {id, anchors} `items` має бути масивом {id, anchors} +@msg `items` must be an array of {{id, corners?}}, not {v} `items` має бути масивом {{id, corners?}}, а не {v} +@msg `kashida` must be "none", "short", "medium", "long" or "stylistic" `kashida` має бути "none", "short", "medium", "long" або "stylistic" +@msg `kerningBefore` belongs to a line's first character, not to a character style (text.setRangeStyle sets it) `kerningBefore` стосується першого символу рядка, а не стилю символу (його задає text.setRangeStyle) +@msg `kind` is one of {_1} `kind` — це одне з: {_1} +@msg `kind` must be "round", "invertedRound" or "chamfer", not {v} `kind` має бути "round", "invertedRound" або "chamfer", а не {v} +@msg `kind` must be `text`, `visibility`, `image` or `graph` `kind` має бути `text`, `visibility`, `image` або `graph` +@msg `kind` must be a string `kind` має бути рядком +@msg `kind` must be image, noImage or htmlText `kind` має бути image, noImage або htmlText +@msg `kinsokuType` must be "pushInFirst", "pushOutFirst" or "pushOutOnly" `kinsokuType` має бути "pushInFirst", "pushOutFirst" або "pushOutOnly" +@msg `kinsoku` must be "none", "hard" or "soft" `kinsoku` має бути "none", "hard" або "soft" +@msg `label` must be a non-empty name of at most 200 characters `label` має бути непорожнім іменем довжиною не більше 200 символів +@msg `language` must be a language name or tag, such as "Turkish" or "tr" `language` має бути назвою або тегом мови, наприклад "Turkish" або "tr" +@msg `leader` must be a string `leader` має бути рядком +@msg `leadingModel` must be "romanBaseline" or "emBoxTop" `leadingModel` має бути "romanBaseline" або "emBoxTop" +@msg `leading` must be from 0.1 to 5000, or null for Auto `leading` має бути від 0.1 до 5000 або null для значення «Авто» +@msg `length` must be a number of at most 1000000 pt either way `length` має бути числом не більше 1000000 pt у будь-який бік +@msg `line` must be true or false `line` має бути true або false +@msg `max` must be 1 to {MAX_SUGGESTIONS} `max` має бути від 1 до {MAX_SUGGESTIONS} +@msg `minAngle` ({min_angle}°) can't be more than `maxAngle` ({max_angle}°) `minAngle` ({min_angle}°) не може бути більшим за `maxAngle` ({max_angle}°) +@msg `mode` must be "handles", "straight" or "smooth" `mode` має бути "handles", "straight" або "smooth" +@msg `mode` must be "straight", "bezier" or "arc" `mode` має бути "straight", "bezier" або "arc" +@msg `mode` must be one of {_1} `mode` має бути одним з: {_1} +@msg `mojikumi` must be "none", "yakumonoHankaku", "gyomatsuYakumonoHankaku", "gyomatsuYakumonoZenkaku", "yakumonoZenkaku" or "lineEndHalf" `mojikumi` має бути "none", "yakumonoHankaku", "gyomatsuYakumonoHankaku", "gyomatsuYakumonoZenkaku", "yakumonoZenkaku" або "lineEndHalf" +@msg `name` must be a name that is not empty `name` має бути непорожнім іменем +@msg `name` must not be empty `name` не має бути порожнім +@msg `names` is a list of preset names `names` — це список імен наборів +@msg `names` lists preset names `names` містить імена наборів +@msg `names` must be a list of names `names` має бути списком імен +@msg `names` must be a list of swatch names `names` має бути списком імен зразків +@msg `names` must be an array of style names `names` має бути масивом імен стилів +@msg `new` is a design name, or true `new` — це назва дизайну або true +@msg `origin` must be [x, y] in points `origin` має бути [x, y] у пунктах +@msg `path` must be a folder `path` має бути папкою +@msg `path` must be a path object `path` має бути об’єктом-контуром +@msg `picks` must be an array (got {v}) `picks` має бути масивом (отримано {v}) +@msg `picks` must hold 1 to {MAX_PICKS} picks (got {_1}) `picks` має містити від 1 до {MAX_PICKS} виборів (отримано {_1}) +@msg `pivot` must be a whole number from 0 to 8 `pivot` має бути цілим числом від 0 до 8 +@msg `points` must be a list of [x, y] points `points` має бути списком точок [x, y] +@msg `points` must be a list of point indexes `points` має бути списком індексів точок +@msg `points` must be an array of point indices `points` має бути масивом індексів точок +@msg `points` must be point indexes `points` має містити індекси точок +@msg `port` must be "in" or "out" `port` має бути "in" або "out" +@msg `position` is above or below `position` — це above або below +@msg `preset` must be a string `preset` має бути рядком +@msg `radius` must be 0 or more `radius` має бути 0 або більше +@msg `ratio` must be from 0.1 to 0.5 `ratio` має бути від 0.1 до 0.5 +@msg `rect` must be [x, y, width, height] with a positive size `rect` має бути [x, y, width, height] з додатним розміром +@msg `rect` must be [x0, y0, x1, y1] (got {r}) `rect` має бути [x0, y0, x1, y1] (отримано {r}) +@msg `relation` must be overlap, inside or outside `relation` має бути overlap, inside або outside +@msg `replace` must be a string `replace` має бути рядком +@msg `reversed` must be true or false `reversed` має бути true або false +@msg `rotate` must be a finite number `rotate` має бути скінченним числом +@msg `rows` must be lists of numbers or nulls, not {r} `rows` має містити списки чисел або значень null, а не {r} +@msg `rule` must be nonZero or evenOdd `rule` має бути nonZero або evenOdd +@msg `scale` must be a number from 0.001 to 1000 `scale` має бути числом від 0.001 до 1000 +@msg `scale` must be a number in (0, 100] `scale` має бути числом у діапазоні (0, 100] +@msg `scope.{key}` must be a non-empty array `scope.{key}` має бути непорожнім масивом +@msg `scope` must be "document", {artboards} or {layers} `scope` має бути "document", {artboards} або {layers} +@msg `scope` must be "selection" or "document", not {other} `scope` має бути "selection" або "document", а не {other} +@msg `script` must be a string `script` має бути рядком +@msg `seriesIndexes` is a non-empty list of series indexes `seriesIndexes` — це непорожній список індексів рядів +@msg `seriesIndexes` needs a `type` or a `valueAxis` для `seriesIndexes` потрібен `type` або `valueAxis` +@msg `shift` must be a number of points `shift` має бути числом пунктів +@msg `showCenter` must be true or false `showCenter` має бути true або false +@msg `side` must be "left", "right", "top" or "bottom" `side` має бути "left", "right", "top" або "bottom" +@msg `side` places the artboard: leave out x, y, width and height `side` розміщує монтажну область: не вказуйте x, y, width і height +@msg `singleWordJustification` must be "fullJustify", "alignLeft", "alignCenter" or "alignRight" `singleWordJustification` має бути "fullJustify", "alignLeft", "alignCenter" або "alignRight" +@msg `size` is a percentage of the base text's size, 1 to 100 `size` — це відсоток від розміру основного тексту, від 1 до 100 +@msg `source` and `target` are the same object `source` і `target` — той самий об’єкт +@msg `source` is the only path in series group `target` `source` — єдиний контур у групі серії `target` +@msg `source` must be `folder` or `datasets` `source` має бути `folder` або `datasets` +@msg `spacing` makes more than {MAX_COUNT} lines across the box `spacing` створює понад {MAX_COUNT} ліній упоперек рамки +@msg `spacing` must be a number `spacing` має бути числом +@msg `spacing` must be a number of points, 0 or more, or "auto" `spacing` має бути числом пунктів, 0 або більше, чи "auto" +@msg `spacing` must be more than 0 and at most {MAX_DISTANCE} pt `spacing` має бути більше 0 і не більше {MAX_DISTANCE} pt +@msg `start` must be a finite number `start` має бути скінченним числом +@msg `starts` must be an array of anchor indices (or nulls) `starts` має бути масивом індексів опорних точок (або значень null) +@msg `status` must be linked, embedded, missing or modified, or a list of them `status` має бути linked, embedded, missing або modified чи списком цих значень +@msg `stop` must be a stop index `stop` має бути індексом точки переходу +@msg `story` styles the whole story: give no `start` or `end` `story` оформлює весь матеріал: не вказуйте `start` або `end` +@msg `story` takes the whole story: give no `start` or `end` `story` охоплює весь матеріал: не вказуйте `start` або `end` +@msg `strokeMode` applies to strokes (stroke: true) `strokeMode` застосовується до обведень (stroke: true) +@msg `style` must be roman or japanese `style` має бути roman або japanese +@msg `subpaths` must be two integer indices `subpaths` має містити два цілочислові індекси +@msg `symbol` must be a symbol name `symbol` має бути іменем символу +@msg `target` must be "object" or "contents", not {v} `target` має бути "object" або "contents", а не {v} +@msg `target` must be an object of the same Objects on Path group as `member` `target` має бути об’єктом тієї самої групи «Об’єкти на контурі», що й `member` +@msg `tint` applies to global and spot colours `tint` застосовується до глобальних і плашкових кольорів +@msg `tint` goes with a global or spot `swatch` `tint` використовується разом із глобальним або плашковим `swatch` +@msg `tint` must be a number (%) `tint` має бути числом (%) +@msg `tint` needs a global or spot colour для `tint` потрібен глобальний або плашковий колір +@msg `to` is already threaded `to` уже пов’язано +@msg `to` is the design's new name `to` — це нова назва дизайну +@msg `to` must be [x, y] `to` має бути [x, y] +@msg `to` must be a closed path, area type or type on a path other than `from` `to` має бути замкненим контуром, текстом в області або текстом за контуром, відмінним від `from` +@msg `to` must be a whole number `to` має бути цілим числом +@msg `to` takes the rows of one object's stack, not aligned rows `to` приймає рядки стосу одного об’єкта, а не вирівняні рядки +@msg `useLab` must be true or false `useLab` має бути true або false +@msg `vAlign` must be default, top, middle, baseline or bottom `vAlign` має бути default, top, middle, baseline або bottom +@msg `values` must be a list `values` має бути списком +@msg `values` must be an object `values` має бути об’єктом +@msg `values` must name hex, rgb, cmyk, lab or gray `values` має вказувати hex, rgb, cmyk, lab або gray +@msg `values` names a kind twice `values` указує один вид двічі +@msg `version` must be 0 or {_1} `version` має бути 0 або {_1} +@msg `version` must be 0 or {newest} `version` має бути 0 або {newest} +@msg `weight` must be from 0.01 to 1000 pt `weight` має бути від 0.01 до 1000 pt +@msg `weights` must be a list of {_1} numbers, one per row (got {v}) `weights` має бути списком із {_1} чисел, по одному на рядок (отримано {v}) +@msg `xml` must be a string `xml` має бути рядком +@msg `{KEY}` entry {n} gives the paragraph at byte {start} of {_1} other indents than an entry before it `{KEY}`, запис {n}: абзац із байта {start} об’єкта {_1} отримує інші відступи, ніж у попередньому записі +@msg `{KEY}` entry {n} must be an object `{KEY}`, запис {n}: має бути об’єктом +@msg `{KEY}` entry {n} sets neither `leftIndent` nor `firstLineIndent` `{KEY}`, запис {n}: не задає ні `leftIndent`, ні `firstLineIndent` +@msg `{KEY}` entry {n}: `id` must be an object id `{KEY}`, запис {n}: `id` має бути ідентифікатором об’єкта +@msg `{KEY}` entry {n}: `start` must be a byte offset `{KEY}`, запис {n}: `start` має бути зміщенням у байтах +@msg `{KEY}` entry {n}: `{k}` must be a number from -{MAX_PARA} to {MAX_PARA} pt `{KEY}`, запис {n}: `{k}` має бути числом від -{MAX_PARA} до {MAX_PARA} pt +@msg `{KEY}` entry {n}: no paragraph of {_1} starts at byte {start} `{KEY}`, запис {n}: жоден абзац об’єкта {_1} не починається з байта {start} +@msg `{KEY}` entry {n}: unknown key `{k}` `{KEY}`, запис {n}: невідомий ключ `{k}` +@msg `{KEY}` entry {n}: {_1} is not a type object `{KEY}`, запис {n}: {_1} не є текстовим об’єктом +@msg `{KEY}` is empty `{KEY}` порожній +@msg `{KEY}` must be a list `{KEY}` має бути списком +@msg `{KEY}` takes at most {MAX_PARAGRAPH_INDENTS} entries (got {_1}) `{KEY}` приймає не більше {MAX_PARAGRAPH_INDENTS} записів (отримано {_1}) +@msg `{KEY}` takes no `{other}` beside it `{KEY}` не допускає `{other}` поруч із собою +@msg `{_1}` can't be edited or removed `{_1}` не можна змінити або вилучити +@msg `{_1}` is built in and always listed `{_1}` є вбудованим і завжди присутній у списку +@msg `{_1}` is not a font file the last text.findFontFiles search found `{_1}` не є файлом шрифту, який знайшов останній пошук text.findFontFiles +@msg `{_1}` would be overwritten by the package: choose a different folder or name `{_1}` буде перезаписано пакетом: виберіть іншу папку або ім’я +@msg `{base}` is larger than {_1} MB `{base}` більший за {_1} МБ +@msg `{base}` is not in the DCS file's folder `{base}` немає в папці файлу DCS +@msg `{file}` has no art to place `{file}` не містить графіки для розміщення +@msg `{file}` is over {_1} MB `{file}` перевищує {_1} МБ +@msg `{f}` belongs to a VectorCraft that is running `{f}` належить запущеному екземпляру VectorCraft +@msg `{f}` is the copy of a document open now `{f}` — це копія документа, відкритого зараз +@msg `{id}` is no writable format (see document.formats) `{id}` не є форматом, доступним для запису (див. document.formats) +@msg `{id}` isn't a loaded library `{id}` не є завантаженою бібліотекою +@msg `{key}` has no colours `{key}` не містить кольорів +@msg `{key}` holds more than {MAX_EDIT_WORDS} words `{key}` містить понад {MAX_EDIT_WORDS} слів +@msg `{key}` is a design name `{key}` — це назва дизайну +@msg `{key}` is a design name or a list of them `{key}` — це назва дизайну або список таких назв +@msg `{key}` is longer than {MAX_NAME} characters `{key}` довший за {MAX_NAME} символів +@msg `{key}` is out of range `{key}` поза межами діапазону +@msg `{key}` must be 0 or more `{key}` має бути 0 або більше +@msg `{key}` must be [min, desired, max] or {{min?, desired?, max?}}, in percent `{key}` має бути [min, desired, max] або {{min?, desired?, max?}}, у відсотках +@msg `{key}` must be [x, y] numbers `{key}` має бути числами [x, y] +@msg `{key}` must be a list of words `{key}` має бути списком слів +@msg `{key}` must be a list, not {v} `{key}` має бути списком, а не {v} +@msg `{key}` must be a non-negative integer `{key}` має бути невід’ємним цілим числом +@msg `{key}` must be a number or null, not {v} `{key}` має бути числом або null, а не {v} +@msg `{key}` must be a number {_1}..{_2} `{key}` має бути числом {_1}..{_2} +@msg `{key}` must be a whole number of 0 or more `{key}` має бути цілим числом, 0 або більше +@msg `{key}` must be a whole number of at least 0, not {n} `{key}` має бути цілим числом не менше 0, а не {n} +@msg `{key}` must be an appearance item index (paint order) or null `{key}` має бути індексом елемента оформлення (порядок зафарбовування) або null +@msg `{key}` must be an array of asset ids (see assets.list) `{key}` має бути масивом ідентифікаторів ресурсів (див. assets.list) +@msg `{key}` must be from 0 to 180 degrees, not {a} `{key}` має бути від 0 до 180 градусів, а не {a} +@msg `{key}` must be from 0 to {MAX_DISTANCE} pt `{key}` має бути від 0 до {MAX_DISTANCE} pt +@msg `{key}` must be from {_1} to {shift_max} `{key}` має бути від {_1} до {shift_max} +@msg `{key}` must be from {lo} to {hi}, not {v} `{key}` має бути від {lo} до {hi}, а не {v} +@msg `{key}` must be one of auto, always, never `{key}` має бути одним з: auto, always, never +@msg `{key}` must be one of miter, round, bevel `{key}` має бути одним з: miter, round, bevel +@msg `{key}` must be one word of at most {_1} characters `{key}` має бути одним словом довжиною не більше {_1} символів +@msg `{key}` must hold single words of at most {_1} characters `{key}` має містити окремі слова довжиною не більше {_1} символів +@msg `{key}` must name an object attached to the path of an Objects on Path group `{key}` має вказувати об’єкт, прикріплений до контуру групи «Об’єкти на контурі» +@msg `{key}` names an object that is hidden or locked `{key}` указує об’єкт, який приховано або заблоковано +@msg `{key}`: not a colour: {v} `{key}`: не колір: {v} +@msg `{k}.family` is required `{k}.family` є обов’язковим +@msg `{k}` is a number 0..1 `{k}` — це число 0..1 +@msg `{k}` is true or false `{k}` — це true або false +@msg `{k}` isn't an export setting: {_1} `{k}` не є параметром експорту: {_1} +@msg `{k}` must be a byte offset `{k}` має бути зміщенням у байтах +@msg `{k}` must be a number `{k}` має бути числом +@msg `{k}` must be a number of points `{k}` має бути числом пунктів +@msg `{k}` must be a string `{k}` має бути рядком +@msg `{k}` must be a whole number `{k}` має бути цілим числом +@msg `{k}` must be from {lo} to {hi} for {key} `{k}` має бути від {lo} до {hi} для {key} +@msg `{k}` must be {what}, not {v} `{k}`: потрібно {what}, а не {v} +@msg `{l}` isn't a global or spot colour `{l}` не є глобальним або плашковим кольором +@msg `{m}` isn't a bitmap: use clipboard.importSvg, importPdf or importText `{m}` не є растровим зображенням: скористайтеся clipboard.importSvg, importPdf або importText +@msg `{name}` can't be deleted `{name}` не можна видалити +@msg `{name}` can't be duplicated `{name}` не можна дублювати +@msg `{name}` can't be edited `{name}` не можна редагувати +@msg `{name}` can't be edited this way `{name}` не можна редагувати в такий спосіб +@msg `{name}` can't be renamed `{name}` не можна перейменувати +@msg `{name}` can't name a folder `{name}` не може вказувати папку +@msg `{name}` has no art to place `{name}` не містить графіки для розміщення +@msg `{name}` has no text to place `{name}` не містить тексту для розміщення +@msg `{name}` in the Word document is not UTF-8 or UTF-16 text `{name}` у документі Word не є текстом UTF-8 або UTF-16 +@msg `{name}` in the Word document is not well-formed XML: {e} `{name}` у документі Word не є правильно сформованим XML: {e} +@msg `{name}` in the Word document nests elements more than {MAX_NESTING} deep `{name}` у документі Word має вкладеність елементів понад {MAX_NESTING} рівнів +@msg `{name}` is a built-in preset and is read-only: save it under another name `{name}` — це вбудований набір, доступний лише для читання: збережіть його під іншим іменем +@msg `{name}` is a built-in preset: save under another name `{name}` — це вбудований набір: збережіть під іншим іменем +@msg `{name}` is a built-in profile and stays `{name}` — це вбудований профіль, він залишається +@msg `{name}` is a file of its own, which can only be found next to the DCS file's path `{name}` — це окремий файл, який можна знайти лише поруч зі шляхом файлу DCS +@msg `{name}` is a tint of `{base}`: edit `{base}` (a tint swatch only takes a new name) `{name}` — це відтінок `{base}`: змініть `{base}` (зразку відтінку можна лише дати нове ім’я) +@msg `{name}` is a working space: choose another with edit.colorSettings first `{name}` — це робочий простір: спочатку виберіть інший за допомогою edit.colorSettings +@msg `{name}` is built in and stays `{name}` є вбудованим і залишається +@msg `{name}` takes a paint of its own kind (colour, gradient or pattern) `{name}` приймає фарбу лише свого виду (колір, градієнт або візерунок) +@msg `{name}`: {_1}: {e} `{name}`: {_1}: {e} +@msg `{n}` can't be deleted `{n}` не можна видалити +@msg `{n}` can't be merged `{n}` не можна об’єднати +@msg `{n}` can't be moved `{n}` не можна перемістити +@msg `{n}` is not a colour swatch `{n}` не є зразком кольору +@msg `{n}` isn't a solid colour `{n}` не є суцільним кольором +@msg `{n}`: colour groups hold solid colours only `{n}`: групи кольорів містять лише суцільні кольори +@msg `{other}` doesn't trace an image `{other}` не трасує зображення +@msg `{s}`: the step's references copy in more than {_1} MB of values `{s}`: посилання кроку копіюють понад {_1} МБ значень +@msg `{tag}` is not an axis tag: a tag is four characters, such as "wght" `{tag}` не є тегом осі: тег складається з чотирьох символів, наприклад "wght" +@msg `{to}` is empty or already used `{to}` порожній або вже використовується +@msg `{u}` is no Unicode character `{u}` не є символом Unicode +@msg `{what}` is longer than {MAX_TEXT} bytes `{what}` довший за {MAX_TEXT} байтів +@msg `{what}` must be text `{what}` має бути текстом +@msg `{word}` isn't in the custom dictionary `{word}` немає у словнику користувача +@msg a CMap has too many mappings CMap містить забагато відображень +@msg a DXF drawing has one origin: pass useArtboards: true for one drawing per artboard креслення DXF має одну точку початку координат: передайте useArtboards: true, щоб отримати одне креслення на монтажну область +@msg a PDF presets file with over {_1} presets файл наборів PDF, що містить понад {_1} наборів +@msg a \\u escape needs four hexadecimal digits для екранування \\u потрібні чотири шістнадцяткові цифри +@msg a batch preview cannot switch documents попередній перегляд пакета не може перемикати документи +@msg a brush named `{nn}` exists пензель з іменем `{nn}` уже існує +@msg a comma in an XPath expression must separate function arguments кома у виразі XPath має розділяти аргументи функції +@msg a container of the listed objects is gone контейнера перелічених об’єктів більше немає +@msg a content stream can't be read не вдалося прочитати потік вмісту +@msg a content stream isn't a stream потік вмісту не є потоком +@msg a design holds at most {_1} objects дизайн містить не більше {_1} об’єктів +@msg a design needs a name дизайну потрібна назва +@msg a dictionary grew too large словник став завеликим +@msg a document holds at most {_1} SVG filters документ містить не більше {_1} фільтрів SVG +@msg a document keeps at most {_1} graph designs документ зберігає не більше {_1} дизайнів діаграм +@msg a document keeps at most {_1} saved selections документ зберігає не більше {_1} збережених виділень +@msg a document keeps at most {_1} views документ зберігає не більше {_1} виглядів +@msg a document links at most {MAX_SVG_SCRIPTS} JavaScript files документ може посилатися не більше ніж на {MAX_SVG_SCRIPTS} файлів JavaScript +@msg a document with unsaved changes has no recovery copy документ із незбереженими змінами не має копії для відновлення +@msg a feConvolveMatrix filter's order is {x}×{y}, which overflows the kernel-size multiply usvg makes порядок фільтра feConvolveMatrix дорівнює {x}×{y}, що переповнює множення розміру ядра, яке виконує usvg +@msg a font's data is too large дані шрифту завеликі +@msg a font's subroutines are too large підпрограми шрифту завеликі +@msg a function declaration without a name оголошення функції без імені +@msg a gradient preset is already called {n} набір градієнта з іменем {n} уже існує +@msg a graph has at most {_1} series, so it transposes with at most that many categories діаграма має не більше {_1} рядів, тому її можна транспонувати лише з такою самою найбільшою кількістю категорій +@msg a host value has too many entries значення хоста містить забагато записів +@msg a host value is nested too deep значення хоста має завелику вкладеність +@msg a layer can't be merged into its own sublayer шар не можна об’єднати з його власним підшаром +@msg a layer's form box isn't an array рамка форми шару не є масивом +@msg a layer's form can't be read не вдалося прочитати форму шару +@msg a layer's form has no box форма шару не має рамки +@msg a layer's form has no dictionary форма шару не має словника +@msg a legend draws at most {MAX_CHIPS} swatches легенда малює не більше {MAX_CHIPS} зразків +@msg a name names one asset: give multiple: false, or one object ім’я вказує один ресурс: задайте multiple: false або один об’єкт +@msg a namespace declaration uses a reserved prefix or URI оголошення простору імен використовує зарезервований префікс або URI +@msg a namespace qualifier is undefined кваліфікатор простору імен не визначено +@msg a namespace with an empty URI cannot have a prefix простір імен із порожнім URI не може мати префікса +@msg a number has no digits число не має цифр +@msg a number's exponent has no digits показник степеня числа не має цифр +@msg a number's fraction has no digits дробова частина числа не має цифр +@msg a page can't be read не вдалося прочитати сторінку +@msg a page object is used by something else об’єкт сторінки використовується чимось іншим +@msg a page thumbnail must be RGB pixels, 1 to {THUMBNAIL_SIZE} a side (got {w} × {h}) мініатюра сторінки має складатися з пікселів RGB, від 1 до {THUMBNAIL_SIZE} по кожній стороні (отримано {w} × {h}) +@msg a pattern layer doesn't end what it starts шар візерунка не завершує те, що починає +@msg a pattern layer's colors hold something else кольори шару візерунка містять щось інше +@msg a pattern named `{n}` exists візерунок з іменем `{n}` уже існує +@msg a plug-in with id {_1} is already installed модуль з ідентифікатором {_1} уже встановлено +@msg a preset named `{n}` exists набір з іменем `{n}` уже існує +@msg a print presets file with over {_1} presets файл наборів друку, що містить понад {_1} наборів +@msg a profile is already called {n} профіль з іменем {n} уже існує +@msg a property descriptor cannot have both a value or writable and a get or set дескриптор властивості не може мати одночасно value або writable і get або set +@msg a property descriptor must be an object дескриптор властивості має бути об’єктом +@msg a property's {name} must be a function or undefined {name} властивості має бути функцією або undefined +@msg a row can't go into itself рядок не можна помістити в самого себе +@msg a series goes on the left or the right value axis ряд розміщується на лівій або правій осі значень +@msg a start must be an anchor index ≥ 0 or null початок має бути індексом опорної точки ≥ 0 або null +@msg a stream in it would decode to more than 256 MB, or its decode parameters can't be applied потік у ньому після декодування перевищив би 256 МБ або його параметри декодування не можна застосувати +@msg a string holds a control character рядок містить керівний символ +@msg a string holds an escape sequence JSON does not have рядок містить екрановану послідовність, якої немає в JSON +@msg a string is not closed рядок не закрито +@msg a style named `{name}` already exists стиль з іменем `{name}` уже існує +@msg a style named `{to}` already exists стиль з іменем `{to}` уже існує +@msg a swatch needs a colour, gradient or pattern зразку потрібен колір, градієнт або візерунок +@msg a symbol named `{n}` already exists символ з іменем `{n}` уже існує +@msg a theme has 1 to {THEME_SIZE} colours тема містить від 1 до {THEME_SIZE} кольорів +@msg a theme is already called {name} (replace: "{name}" overwrites it) тема з іменем {name} уже існує (replace: "{name}" перезаписує її) +@msg a toolbar name has at most {MAX_NAME} characters ім’я панелі інструментів містить не більше {MAX_NAME} символів +@msg a view named `{_1}` exists вигляд з іменем `{_1}` уже існує +@msg a view named `{name}` exists вигляд з іменем `{name}` уже існує +@msg a workspace keeps at most {MAX} toolbars робоче середовище зберігає не більше {MAX} панелей інструментів +@msg a {_1} series can't go in a {_2} graph ряд типу {_1} не можна помістити в діаграму типу {_2} +@msg aiVersion {v}: "pdf" (PDF-compatible, the default) or "7" (legacy .ai, version 7) aiVersion {v}: "pdf" (сумісний із PDF, за замовчуванням) або "7" (застарілий .ai, версія 7) +@msg already editing an opacity mask маска непрозорості вже редагується +@msg already editing another object's opacity mask уже редагується маска непрозорості іншого об’єкта +@msg already in pattern editing mode режим редагування візерунка вже ввімкнено +@msg an SVG filter is named by its id: give `xml` with `name` фільтр SVG іменується своїм ідентифікатором: укажіть `xml` разом із `name` +@msg an XML element has two attributes with the same name елемент XML має два атрибути з однаковим іменем +@msg an XML value cannot be inserted into itself or its descendants значення XML не можна вставити в самого себе або у своїх нащадків +@msg an XML value's children cannot be assigned by position дочірні елементи значення XML не можна призначати за позицією +@msg an XML value's children cannot be deleted by position дочірні елементи значення XML не можна видаляти за позицією +@msg an XMLList converts to XML only when it has one item XMLList перетворюється на XML, лише коли містить один елемент +@msg an XPath node test is missing відсутня перевірка вузла XPath +@msg an XPath operand is missing відсутній операнд XPath +@msg an XPath operator is missing відсутній оператор XPath +@msg an XPath predicate or step cannot follow here предикат або крок XPath не може йти тут +@msg an XPath predicate or step follows a value that is not a node-set предикат або крок XPath іде після значення, яке не є набором вузлів +@msg an XPath step is missing відсутній крок XPath +@msg an artboard is listed twice монтажну область указано двічі +@msg an empty artboard has no width or height to scale to порожня монтажна область не має ширини або висоти, до якої можна масштабувати +@msg an image couldn't be decoded and is missing from the picture не вдалося декодувати зображення, тому його немає на малюнку +@msg an image is too large for DXF and was left out зображення завелике для DXF, тому його пропущено +@msg an image of {_1} MB, at most {_2} MB зображення розміром {_1} МБ, дозволено не більше {_2} МБ +@msg an image of {declared_w} × {declared_h} pixels is too large to draw зображення розміром {declared_w} × {declared_h} пікселів завелике для малювання +@msg an image of {width} × {height} pixels is too large to draw зображення розміром {width} × {height} пікселів завелике для малювання +@msg an image of {w} × {h} pixels is too large to convert (at most {_1} pixels) зображення розміром {w} × {h} пікселів завелике для перетворення (не більше {_1} пікселів) +@msg an index must be a whole number індекс має бути цілим числом +@msg an inline graphic has no glyphs вбудована в рядок графіка не має гліфів +@msg an invisible text form can't be read не вдалося прочитати форму невидимого тексту +@msg an object is missing відсутній об’єкт +@msg an object's header is missing відсутній заголовок об’єкта +@msg an overprinting form can't be read не вдалося прочитати форму з накладенням +@msg an unread object has no readable bounds непрочитаний об’єкт не має меж, які можна прочитати +@msg an unread object holds a frame of threaded type непрочитаний об’єкт містить рамку пов’язаного тексту +@msg an unread object is missing from its layer непрочитаного об’єкта немає в його шарі +@msg anchor `smooth` must be true or false `smooth` опорної точки має бути true або false +@msg anchor `{key}` must be [x, y] `{key}` опорної точки має бути [x, y] +@msg anchor `{key}` must be a number `{key}` опорної точки має бути числом +@msg angle and roundness must be finite angle і roundness мають бути скінченними +@msg angles must be a list as long as pins (degrees or null) angles має бути списком такої самої довжини, як pins (градуси або null) +@msg appearance must be flat|center|edge appearance має бути flat|center|edge +@msg apply is "fill" or "stroke", not `{other}` apply — це "fill" або "stroke", а не `{other}` +@msg apply was called on a value that is not a function apply викликано для значення, яке не є функцією +@msg area must be a closed polygon of 3 to 100000 [x, y] points area має бути замкненим багатокутником із 3–100000 точок [x, y] +@msg area type in a thread cannot use Dynamic Text: {frames} текст в області у пов’язаному тексті не може використовувати динамічний текст: {frames} +@msg area type needs a path that encloses an area для тексту в області потрібен контур, який охоплює область +@msg area type {_1} is named twice текст в області {_1} указано двічі +@msg array literal too long літерал масиву задовгий +@msg arrowAlign must be extend|tip, got {o} arrowAlign має бути extend|tip, отримано {o} +@msg arrowScale must be [start, end] arrowScale має бути [start, end] +@msg artboard is a 0-based index artboard — це індекс, що починається з 0 +@msg artboard must be a 0-based index artboard має бути індексом, що починається з 0 +@msg artboard {i} doesn't print монтажна область {i} не друкується +@msg artboardLayout must be {layout?, columns?, spacing?, rightToLeft?} artboardLayout має бути {layout?, columns?, spacing?, rightToLeft?} +@msg artboardLayout.columns must be 1 or more artboardLayout.columns має бути 1 або більше +@msg artboardLayout.layout must be gridByRow, gridByColumn, row or column artboardLayout.layout має бути gridByRow, gridByColumn, row або column +@msg artboardLayout.rightToLeft must be true or false artboardLayout.rightToLeft має бути true або false +@msg artboardLayout.spacing must be 0–{MAX_SPACING} pt artboardLayout.spacing має бути 0–{MAX_SPACING} pt +@msg artboards must be a non-empty list artboards має бути непорожнім списком +@msg artboards must be a number artboards має бути числом +@msg asset `{_1}` has no art to export ресурс `{_1}` не містить графіки для експорту +@msg assignment to a constant binding присвоєння константній прив’язці +@msg at least one row that isn't excluded needs a weight above 0 принаймні один невиключений рядок повинен мати вагу понад 0 +@msg at most {MAX_KEYWORDS} keywords не більше {MAX_KEYWORDS} ключових слів +@msg at most {MAX_MATCHES} matches are kept зберігається не більше {MAX_MATCHES} збігів +@msg at most {MAX_POINTS} points не більше {MAX_POINTS} точок +@msg at most {MAX_QUEUE} files не більше {MAX_QUEUE} файлів +@msg at must be [x, y] at має бути [x, y] +@msg at/rect lie outside the canvas at/rect лежать поза полотном +@msg attribute must be size|leading|tracking|kerning|baselineShift attribute має бути size|leading|tracking|kerning|baselineShift +@msg attrs must be an object attrs має бути об’єктом +@msg automation path rejected: the folder's name isn't valid text шлях автоматизації відхилено: ім’я папки не є припустимим текстом +@msg automation path rejected: {_1} isn't valid text шлях автоматизації відхилено: {_1} не є припустимим текстом +@msg automation path rejected: {why}: {path} шлях автоматизації відхилено: {why}: {path} +@msg axis must be "vertical", "horizontal" or an angle in degrees, not `{given}` axis має бути "vertical", "horizontal" або кутом у градусах, а не `{given}` +@msg backgroundContents must be transparent or white backgroundContents має бути transparent або white +@msg bad AES key неправильний ключ AES +@msg bad `runs`: {e} неправильний `runs`: {e} +@msg bad arrowScale неправильний arrowScale +@msg bad base64 неправильний base64 +@msg bad color {c} неправильний колір {c} +@msg bad colour неправильний колір +@msg bad colour in `colors` неправильний колір у `colors` +@msg bad colour {v} неправильний колір {v} +@msg bad colour {v} in groupColors неправильний колір {v} у groupColors +@msg bad cross-reference entry неправильний запис перехресних посилань +@msg bad cross-reference table неправильна таблиця перехресних посилань +@msg bad current colour {v} неправильний поточний колір {v} +@msg bad dataBase64 неправильний dataBase64 +@msg bad edit неправильна правка +@msg bad fill {v} неправильна заливка {v} +@msg bad fit: {e} неправильне припасування: {e} +@msg bad model {other} (keep, new or document) неправильна модель {other} (keep, new або document) +@msg bad new colour {v} неправильний новий колір {v} +@msg bad object неправильний об’єкт +@msg bad object number неправильний номер об’єкта +@msg bad offset неправильне зміщення +@msg bad path data: {e} неправильні дані контуру: {e} +@msg bad point {v}: expected [x, y] or [x, y, pressure] неправильна точка {v}: очікується [x, y] або [x, y, pressure] +@msg bad reference неправильне посилання +@msg bad trailer size неправильний розмір трейлера +@msg bad {k} colour неправильний колір {k} +@msg batches cannot nest пакети не можна вкладати один в один +@msg bind something to a variable first спочатку прив’яжіть що-небудь до змінної +@msg bleed must be 0–{MAX_BLEED} pt: a number, [top, bottom, left, right] or {{top, bottom, left, right}} bleed має бути 0–{MAX_BLEED} pt: число, [top, bottom, left, right] або {{top, bottom, left, right}} +@msg blend must be a mode name blend має бути назвою режиму +@msg both sides of an XPath | must select nodes обидві сторони оператора | в XPath мають вибирати вузли +@msg brush must be a name or null brush має бути іменем або null +@msg by must be a number by має бути числом +@msg can't add page thumbnails: {why} не вдалося додати мініатюри сторінок: {why} +@msg can't add the editing data for other apps: {why} не вдалося додати дані редагування для інших програм: {why} +@msg can't edit the written PDF: {why} не вдалося змінити записаний PDF: {why} +@msg can't encrypt the PDF: {why} не вдалося зашифрувати PDF: {why} +@msg can't linearise the PDF: {why} не вдалося лінеаризувати PDF: {why} +@msg can't open `{_1}`: {_2} не вдалося відкрити `{_1}`: {_2} +@msg can't open `{_1}`: {e} не вдалося відкрити `{_1}`: {e} +@msg can't open `{name}`: not a format VectorCraft reads (see document.formats) не вдалося відкрити `{name}`: VectorCraft не читає цей формат (див. document.formats) +@msg can't place `{name}`: not a format VectorCraft reads (see document.formats) не вдалося помістити `{name}`: VectorCraft не читає цей формат (див. document.formats) +@msg can't read back the written PDF: {e} не вдалося прочитати записаний PDF: {e} +@msg can't read this Word document: {why} не вдалося прочитати цей документ Word: {why} +@msg can't write .{e} images: use .png, .jpg, .gif, .webp, .tif or .bmp не можна записувати зображення .{e}: скористайтеся .png, .jpg, .gif, .webp, .tif або .bmp +@msg can't write PDF layers, overprint or invisible text: {why} не вдалося записати шари PDF, накладення або невидимий текст: {why} +@msg can't write the file's copyright: {why} не вдалося записати відомості про авторські права файлу: {why} +@msg can't write the file's modification date: {why} не вдалося записати дату змінення файлу: {why} +@msg can't write the pages' user units: {why} не вдалося записати користувацькі одиниці сторінок: {why} +@msg canceled скасовано +@msg cannot convert the object to a primitive value не вдається перетворити об’єкт на примітивне значення +@msg cannot convert undefined or null to an object не вдається перетворити undefined або null на об’єкт +@msg cannot distort a zero-size or non-finite bounding box не можна спотворити обмежувальну рамку нульового або нескінченного розміру +@msg cannot move an object into itself не можна перемістити об’єкт у самого себе +@msg case must be upper|lower|title|sentence case має бути upper|lower|title|sentence +@msg category `{c}`: one of {_1} category `{c}`: одне з: {_1} +@msg center must be [x, y] center має бути [x, y] +@msg character dimensions cannot be represented with the source text transform розміри символів не можна передати з трансформацією вихідного тексту +@msg character dimensions cannot be represented with the target text transform розміри символів не можна передати з трансформацією цільового тексту +@msg choose at least one artboard виберіть принаймні одну монтажну область +@msg choose at least one status виберіть принаймні один стан +@msg clip must be true or false clip має бути true або false +@msg clippingMask must be true or false clippingMask має бути true або false +@msg closed must be a boolean closed має бути логічним значенням +@msg collapsed must be true or false collapsed має бути true або false +@msg color.profile: no RGB or CMYK profile is called “{profile}” color.profile: немає профілю RGB або CMYK з іменем «{profile}» +@msg colorMode must be rgb or cmyk, not `{m}` colorMode має бути rgb або cmyk, а не `{m}` +@msg colorModel must be {own} (the document's mode), grayscale or bitmap colorModel має бути {own} (режим документа), grayscale або bitmap +@msg colour groups can't go into colour groups групи кольорів не можна поміщати в групи кольорів +@msg colour, mode and spot apply to solid-colour swatches only colour, mode і spot застосовуються лише до зразків суцільного кольору +@msg column {column}: `{cell}` is a `%` column of graph data files, which are not read стовпець {column}: `{cell}` — це стовпець `%` файлів даних діаграм, які не читаються +@msg column {column}: `{cell}` names `{name}`, which is a {_1} variable стовпець {column}: `{cell}` указує `{name}`, а це змінна типу {_1} +@msg column {column}: `{cell}` names no variable стовпець {column}: `{cell}` не вказує жодної змінної +@msg column {column}: the variable name is longer than {MAX_NAME} characters стовпець {column}: ім’я змінної довше за {MAX_NAME} символів +@msg column: true floats the whole column and takes no onto, above or below column: true робить плаваючим увесь стовпець і не приймає onto, above або below +@msg command must be a shape.* command command має бути командою shape.* +@msg commands[{i}]: missing `command` commands[{i}]: відсутній `command` +@msg composer must be "singleLine" or "everyLine" composer має бути "singleLine" або "everyLine" +@msg compound shapes take paths, compound paths, groups, compound shapes, type, blends and envelopes складені фігури приймають контури, складені контури, групи, складені фігури, текст, переходи й оболонки +@msg compound {_1} must contain exactly one open path to join складений об’єкт {_1} має містити рівно один відкритий контур для з’єднання +@msg connect needs a path other than the one extended для connect потрібен контур, відмінний від того, що продовжується +@msg connect needs id для connect потрібен id +@msg connect path has no open end контур для connect не має відкритого кінця +@msg continuation must be an array of path chunks continuation має бути масивом частин контуру +@msg continuation requires points для continuation потрібні points +@msg copy needs path: the file to copy into the document's folder для copy потрібен path: файл, який треба скопіювати в папку документа +@msg copy takes images only: relink placed documents where their files are copy приймає лише зображення: поміщені документи зв’яжіть повторно там, де розташовані їхні файли +@msg copying a file isn't available on the web копіювання файлу недоступне у вебверсії +@msg copyrightStatus must be unknown, copyrighted or publicDomain copyrightStatus має бути unknown, copyrighted або publicDomain +@msg copyrightUrl must be a URL (no spaces, at most 2048 characters) copyrightUrl має бути URL-адресою (без пробілів, не більше 2048 символів) +@msg corners must be 4 [x, y] points (TL, TR, BR, BL) corners має містити 4 точки [x, y] (TL, TR, BR, BL) +@msg counterPer `{c}`: item or file counterPer `{c}`: item або file +@msg crop `{_1}`: only PDF pages have art, trim, bleed and media boxes; use "crop" or "bounding" crop `{_1}`: лише сторінки PDF мають рамки art, trim, bleed і media; використайте "crop" або "bounding" +@msg crop rectangle doesn't overlap the image прямокутник обрізання не перетинається із зображенням +@msg cross-reference and object streams aren't supported потоки перехресних посилань і потоки об’єктів не підтримуються +@msg damaged compressed data: {e} пошкоджені стиснуті дані: {e} +@msg dash lengths must be numbers, got {v} довжини штрихів мають бути числами, отримано {v} +@msg dash must be a list of lengths or null, got {v} dash має бути списком довжин або null, отримано {v} +@msg data key `{k}`: letters, digits, -, _ and . (not name or vc-…) ключ даних `{k}`: літери, цифри, -, _ і . (не name і не vc-…) +@msg data must be an object of key: value, not {v} data має бути об’єктом із пар ключ: значення, а не {v} +@msg data set `{name}` holds a value for `{var}`, which the library doesn't declare набір даних `{name}` містить значення для `{var}`, яку бібліотека не оголошує +@msg data set `{name}` holds two values for `{var}` набір даних `{name}` містить два значення для `{var}` +@msg data set `{name}` is declared twice набір даних `{name}` оголошено двічі +@msg data takes at most {MAX_DATA} keys at once data приймає не більше {MAX_DATA} ключів за раз +@msg dataset `{name}` already exists набір даних `{name}` уже існує +@msg dataset `{to}` already exists набір даних `{to}` уже існує +@msg date `{d}`: YYYY-MM-DD date `{d}`: YYYY-MM-DD +@msg decoded data is too large декодовані дані завеликі +@msg define a variable first спочатку визначте змінну +@msg detect must be true or false detect має бути true або false +@msg direct-select anchor points of a path виділіть опорні точки контуру прямим виділенням +@msg distance must be > 0 distance має бути > 0 +@msg dx and dy give the arrow's direction dx і dy задають напрямок стрілки +@msg dx and dy must be numbers dx і dy мають бути числами +@msg dxf fitTo must be [width, height], positive dxf fitTo має бути [width, height] з додатними значеннями +@msg dxf must be an object of DXF import options dxf має бути об’єктом параметрів імпорту DXF +@msg dxf scale must be a positive number up to {_1}, not {s} dxf scale має бути додатним числом не більше {_1}, а не {s} +@msg dxf unit `{u}`: a unit such as mm, cm, in or pt dxf unit `{u}`: одиниця на зразок mm, cm, in або pt +@msg dxf: {e} dxf: {e} +@msg each format is an object {format, scale?, suffix?} кожен формат — це об’єкт {format, scale?, suffix?} +@msg each item needs an id кожному елементу потрібен id +@msg each match needs `kind` кожному збігу потрібен `kind` +@msg each match needs a `name` кожному збігу потрібен `name` +@msg each of `fonts` is {family, style?}; 1 to 1000 of them кожен елемент `fonts` — це {family, style?}; їх має бути від 1 до 1000 +@msg each of `items` is {kind, item} кожен елемент `items` — це {kind, item} +@msg each of `items` is {{id, corners?}} with an object id, not {it} кожен елемент `items` — це {{id, corners?}} з ідентифікатором об’єкта, а не {it} +@msg each path chunk must contain 1 to 4096 points кожна частина контуру має містити від 1 до 4096 точок +@msg each pick is {{at: [x, y]}} or {{rect: [x0, y0, x1, y1]}} (got {v}) кожен вибір — це {{at: [x, y]}} або {{rect: [x0, y0, x1, y1]}} (отримано {v}) +@msg each row needs `from` кожному рядку потрібен `from` +@msg each stop needs a position кожній точці переходу потрібна позиція +@msg each subpath needs an anchors array кожному вкладеному контуру потрібен масив anchors +@msg each weight must be a number of 0 or more (got {v}) кожна вага має бути числом, 0 або більше (отримано {v}) +@msg easingType must be easeIn, easeOut, easeInOut or easeOutIn easingType має бути easeIn, easeOut, easeInOut або easeOutIn +@msg editingData must be true or false editingData має бути true або false +@msg editingData must be true, false or "always" editingData має бути true, false або "always" +@msg edits overlap правки перекриваються +@msg effects of objects whose appearances differ can't be moved together ефекти об’єктів із різним оформленням не можна переміщувати разом +@msg empty header in column {_1} порожній заголовок у стовпці {_1} +@msg encoding `{_1}`: utf8 or utf16 encoding `{_1}`: utf8 або utf16 +@msg ends must be two of "first" and "last" ends має містити два значення з "first" і "last" +@msg every numbered name for the result is taken усі нумеровані імена для результату вже зайняті +@msg expanded SVG styles exceed the import size limit розгорнуті стилі SVG перевищують обмеження розміру імпорту +@msg export presets file is larger than {MAX_PRESET_FILE_BYTES} bytes файл наборів експорту більший за {MAX_PRESET_FILE_BYTES} байтів +@msg exportText must be editable or appearance exportText має бути editable або appearance +@msg exportType must be movieClip or graphic, not `{s}` exportType має бути movieClip або graphic, а не `{s}` +@msg extend needs id для extend потрібен id +@msg featureChanges lists at most {MAX_FEATURE_CHANGES} tags featureChanges містить не більше {MAX_FEATURE_CHANGES} тегів +@msg featureChanges must be a list of tags featureChanges має бути списком тегів +@msg features must be a list of tags features має бути списком тегів +@msg fidelity must be 0..100 fidelity має бути 0..100 +@msg files must be {name, dataBase64} files має бути {name, dataBase64} +@msg finally table {t} out of range таблиця finally {t} поза межами діапазону +@msg fit must be none|autoHeight|shrinkText|block, got {id} fit має бути none|autoHeight|shrinkText|block, отримано {id} +@msg flags cannot be given with a RegExp object прапорці не можна задавати разом з об’єктом RegExp +@msg flattener: {e} зведення прозорості: {e} +@msg flattenerPreset `{name}`: high, medium, low or a saved one (see flattener.presets.list) flattenerPreset `{name}`: high, medium, low або збережений набір (див. flattener.presets.list) +@msg flipProfile must be along|across, got {o} flipProfile має бути along|across, отримано {o} +@msg folders `{f}`: none, rows, format, item or itemFormat folders `{f}`: none, rows, format, item або itemFormat +@msg folders deeper than {MAX_BATCH_DEPTH} levels вкладеність папок понад {MAX_BATCH_DEPTH} рівнів +@msg folders deeper than {MAX_DEPTH} levels вкладеність папок понад {MAX_DEPTH} рівнів +@msg font family `{family}` is not available гарнітура `{family}` недоступна +@msg font family `{tf}` is not available гарнітура `{tf}` недоступна +@msg format `{f}`: pdf or postscript format `{f}`: pdf або postscript +@msg format `{f}`: text or json format `{f}`: text або json +@msg format is `{format}` формат: `{format}` +@msg formats must be an array of rows, not {v} formats має бути масивом рядків, а не {v} +@msg frequency must be between 1 and 300 lines per inch frequency має бути від 1 до 300 ліній на дюйм +@msg from and to must be finite from і to мають бути скінченними +@msg from must be [x0, y0, x1, y1] from має бути [x0, y0, x1, y1] +@msg function declaration index out of range індекс оголошення функції поза межами діапазону +@msg give `before` or `after`, not both укажіть `before` або `after`, але не обидва +@msg give `char`, `text`, `code` or `unicode` укажіть `char`, `text`, `code` або `unicode` +@msg give `colors`, or `color` and `rule` укажіть `colors` або `color` і `rule` +@msg give `count` or `spacing`, not both укажіть `count` або `spacing`, але не обидва +@msg give `event`, such as onclick укажіть `event`, наприклад onclick +@msg give `file`, the JavaScript file's path or URL укажіть `file` — шлях або URL-адресу файлу JavaScript +@msg give `fill` and/or `stroke` укажіть `fill` і/або `stroke` +@msg give `fill`, `stroke` or both укажіть `fill`, `stroke` або обидва +@msg give `folder` укажіть `folder` +@msg give `fonts`, or open a document укажіть `fonts` або відкрийте документ +@msg give `from` or `indices`, not both укажіть `from` або `indices`, але не обидва +@msg give `id` (no text is being edited) укажіть `id` (жоден текст зараз не редагується) +@msg give `id` and `anchors`, or `items`, not both укажіть `id` і `anchors` або `items`, але не те й інше +@msg give `id` or `guide`, not both укажіть `id` або `guide`, але не обидва +@msg give `length` or `to` укажіть `length` або `to` +@msg give `matches`: [{kind, name, target}] укажіть `matches`: [{kind, name, target}] +@msg give `name` (or edit a pattern) укажіть `name` (або редагуйте візерунок) +@msg give `name` or `names` укажіть `name` або `names` +@msg give `name`, an SVG filter's name укажіть `name` — ім’я фільтра SVG +@msg give `path` (a .wasm file) or `dataBase64` (the module) укажіть `path` (файл .wasm) або `dataBase64` (модуль) +@msg give `path`, `data` or `dataBase64` укажіть `path`, `data` або `dataBase64` +@msg give `path`, `data`, `dataBase64` or `csv` укажіть `path`, `data`, `dataBase64` або `csv` +@msg give `path`, `xml` or `dataBase64` укажіть `path`, `xml` або `dataBase64` +@msg give `path`, an SVG file, or `svg`, SVG text укажіть `path` (файл SVG) або `svg` (текст SVG) +@msg give `script`, the JavaScript the event runs ("" removes the event) укажіть `script` — код JavaScript, який виконує подія ("" вилучає подію) +@msg give `text` (the reading) or `remove` укажіть `text` (читання) або `remove` +@msg give `x` and `y` (and a `tolerance` of 0 or more) укажіть `x` і `y` (а також `tolerance`, 0 або більше) +@msg give `xml`, one SVG element укажіть `xml` — один елемент SVG +@msg give a mode or r/g/b, c/m/y/k, gray or tint adjustments укажіть mode або корекції r/g/b, c/m/y/k, gray чи tint +@msg give a name, or paint the active proxy with a saved preset укажіть ім’я або зафарбуйте активний індикатор збереженим набором +@msg give a name, or select a stroke with a saved profile укажіть ім’я або виділіть обведення зі збереженим профілем +@msg give a pattern name or select an object painted with a pattern укажіть ім’я візерунка або виділіть об’єкт, зафарбований візерунком +@msg give at least one of clip, invert, disabled, linked укажіть принаймні одне з: clip, invert, disabled, linked +@msg give color, none, swatch or gradient укажіть color, none, swatch або gradient +@msg give dataBase64 укажіть dataBase64 +@msg give either at (a click) or area (a path drawn around the overlaps) укажіть at (клацання) або area (контур, намальований навколо перекриттів) +@msg give exactly one of `path`, `data` and `dataBase64` укажіть рівно одне з: `path`, `data`, `dataBase64` +@msg give formats or a preset, not both укажіть formats або набір, але не те й інше +@msg give index or indexes, not both укажіть index або indexes, але не обидва +@msg give newName or delete укажіть newName або delete +@msg give offset or by укажіть offset або by +@msg give one element укажіть один елемент +@msg give one of `to`, `rect` or `at` укажіть одне з: `to`, `rect` або `at` +@msg give one of assets, layers, selection or fullDocument укажіть одне з: assets, layers, selection або fullDocument +@msg give only one of onto, above, below, icon and a column place укажіть лише одне з: onto, above, below, icon або місце у стовпці +@msg give opacity or blend укажіть opacity або blend +@msg give origin: [x, y], or reset: true укажіть origin: [x, y] або reset: true +@msg give overprintFill, overprintStroke, showCenter, imageMap, url or note укажіть overprintFill, overprintStroke, showCenter, imageMap, url або note +@msg give path (a file) or folder укажіть path (файл) або folder +@msg give path, or name and dataBase64 укажіть path або name і dataBase64 +@msg give paths or files укажіть paths або files +@msg give rows, rowHeight, columns or columnWidth укажіть rows, rowHeight, columns або columnWidth +@msg give svg, or dataBase64 of an SVG or SVGZ file укажіть svg або dataBase64 файлу SVG чи SVGZ +@msg give text укажіть text +@msg give the asset a name дайте ресурсу ім’я +@msg give the preset a `name` дайте набору `name` +@msg give the preset a name дайте набору ім’я +@msg give the preset a name (1–64 characters) дайте набору ім’я (1–64 символи) +@msg give the settings to change, e.g. {"formats"}]} укажіть параметри, які треба змінити, наприклад {"formats"}]} +@msg give the style a name дайте стилю ім’я +@msg give two or more style `names` укажіть два або більше стилів у `names` +@msg give two or more swatches укажіть два або більше зразків +@msg give x, y, or a handle's length or angle укажіть x, y або довжину чи кут маркера +@msg give {key, value} or {values} укажіть {key, value} або {values} +@msg global must be true or false global має бути true або false +@msg glyph {_1} is not drawn for {ch} with the character's style (such as All Caps, Small Caps or a numeral system) гліф {_1} не малюється для {ch} зі стилем цього символу (як-от «Усі великі», «Капітель» або система числення) +@msg glyph {g} is not an alternate of {ch} in {_1} {_2} гліф {g} не є альтернативою для {ch} у {_1} {_2} +@msg gradient must be "objects" or "mesh" gradient має бути "objects" або "mesh" +@msg grays must be "profile" or "black", not `{g}` grays має бути "profile" або "black", а не `{g}` +@msg gridColors must be a preset name or two colours gridColors має бути іменем набору або двома кольорами +@msg gridSize must be small, medium or large gridSize має бути small, medium або large +@msg guide {g} is not selected напрямну {g} не виділено +@msg handle must be 0..3 handle має бути 0..3 +@msg handler at {_1} expects {_2} values but its range starts with {d} обробник за адресою {_1} очікує значень: {_2}, але його діапазон починається з {d} +@msg handler depth too large глибина обробника завелика +@msg handler range {_1}..{_2} out of range діапазон обробника {_1}..{_2} поза допустимими межами +@msg hiddenLayers must be true or false hiddenLayers має бути true або false +@msg hiddenObjects {v}: "layer" (the default), "omit" or "visible" hiddenObjects {v}: "layer" (за замовчуванням), "omit" або "visible" +@msg highlight a layer to merge into виділіть шар, з яким треба об’єднати +@msg highlight two or more rows in one layer or group виділіть два або більше рядків в одному шарі чи групі +@msg highlight two or more rows to merge виділіть два або більше рядків для об’єднання +@msg hvcC hvcC +@msg icon docks a panel in the icon column: use window.panel.dock icon закріплює панель у стовпці значків: скористайтеся window.panel.dock +@msg id must be a dimension id id має бути ідентифікатором розміру +@msg image has no bounds зображення не має меж +@msg image {_1} is linked already зображення {_1} уже пов’язане +@msg imageMap `{m}`: none, client or server imageMap `{m}`: none, client або server +@msg images in a spot ink whose samples couldn't be read were imported in RGB зображення у плашковій фарбі, відліки яких не вдалося прочитати, імпортовано в RGB +@msg images past the most pixels one file may hold were left out зображення понад найбільшу кількість пікселів, дозволену для одного файлу, пропущено +@msg images too large to read were left out зображення, завеликі для читання, пропущено +@msg index out of range індекс поза межами діапазону +@msg indexes may hold at most {MAX_GUIDE_INDEXES} entries indexes може містити не більше {MAX_GUIDE_INDEXES} записів +@msg indexes must be an array of guide indexes indexes має бути масивом індексів напрямних +@msg instances must be 1..1000 instances має бути 1..1000 +@msg instruction out of range інструкція поза межами діапазону +@msg instruction {pc} ({op}) pops below the stack інструкція {pc} ({op}) знімає значення нижче дна стека +@msg instruction {pc} reached with stack depths {seen} and {d} до інструкції {pc} можна дійти з глибинами стека {seen} і {d} +@msg invalid `color` неприпустимий `color` +@msg invalid anchor index {v}: expected a non-negative integer неприпустимий індекс опорної точки {v}: очікується невід’ємне ціле число +@msg invalid anchor reference {v}: expected [subpath, anchor] неприпустиме посилання на опорну точку {v}: очікується [subpath, anchor] +@msg invalid angle неприпустимий кут +@msg invalid array length неприпустима довжина масиву +@msg invalid brush: {e} неприпустимий пензель: {e} +@msg invalid color неприпустимий колір +@msg invalid colour {c} неприпустимий колір {c} +@msg invalid delta неприпустима дельта +@msg invalid group неприпустима група +@msg invalid object id {v}: expected a non-negative integer неприпустимий ідентифікатор об’єкта {v}: очікується невід’ємне ціле число +@msg invalid point неприпустима точка +@msg invalid regular expression flag '{_1}' неприпустимий прапорець регулярного виразу '{_1}' +@msg invalid regular expression: {m} неприпустимий регулярний вираз: {m} +@msg invalid size неприпустимий розмір +@msg invalid t неприпустиме значення t +@msg invalid time value неприпустиме значення часу +@msg invalid tolerance неприпустимий допуск +@msg is a confirm's answer, whose `value` must be true or false є відповіддю на confirm, чиє `value` має бути true або false +@msg is a prompt's answer, whose `value` must be a string or null є відповіддю на prompt, чиє `value` має бути рядком або null +@msg is an alert's answer, whose `value` must be "ok" є відповіддю на alert, чиє `value` має бути "ok" +@msg is longer than 16 KiB довший за 16 КіБ +@msg it draws its image through a clipping path він малює своє зображення через відсічний контур +@msg it draws no image він не малює жодного зображення +@msg it is larger than {MAX_DICTIONARY_FILE_BYTES} bytes він більший за {MAX_DICTIONARY_FILE_BYTES} байтів +@msg it isn't a file це не файл +@msg it names {_1} plates, and at most {MAX_PLATES} are read він називає форм: {_1}, а читається не більше {MAX_PLATES} +@msg its art is too long or too detailed for a head його графіка задовга або занадто детальна для наконечника +@msg its art paints nothing його графіка нічого не зафарбовує +@msg its artboards all lie beyond the canvas (more than {_1} pt from the origin) усі його монтажні області лежать поза полотном (далі ніж {_1} pt від початку координат) +@msg its clipping masks are nested too deeply його відсічні маски мають завелику вкладеність +@msg its image is too large to read його зображення завелике для читання +@msg its metadata has no description його метадані не мають опису +@msg its metadata has no direct length його метадані не мають прямо заданої довжини +@msg its plates are too large: more than {MAX_SAMPLES} pixels together його форми завеликі: разом понад {MAX_SAMPLES} пікселів +@msg its plates are too large: {_1} plates of {w} × {h} pixels його форми завеликі: форм {_1}, кожна {w} × {h} пікселів +@msg its plates can't be kept together його форми не можна зберегти разом +@msg its shapes could not be combined into one його фігури не вдалося об’єднати в одну +@msg join two different paths з’єднуйте два різні контури +@msg jump to {pc}, past the end перехід до {pc}, за межі кінця +@msg justify must be auto|left|center|right|justifyAll justify має бути auto|left|center|right|justifyAll +@msg kbps must be a positive number, not {kbps} kbps має бути додатним числом, а не {kbps} +@msg keywords must be a list of words or a comma-separated string keywords має бути списком слів або рядком зі словами через кому +@msg keywords must be at most {MAX_KEYWORD} characters, without control characters кожне значення keywords має містити не більше {MAX_KEYWORD} символів і не мати керівних символів +@msg kind must be 1, 2 or 3, or give a preset `name` (see perspective.presets.list) kind має бути 1, 2 або 3 чи вкажіть `name` набору (див. perspective.presets.list) +@msg kind must be graphic, fillColor, strokeColor, fillGradient, strokeGradient, fillPattern, strokePattern, charStyle or paraStyle kind має бути graphic, fillColor, strokeColor, fillGradient, strokeGradient, fillPattern, strokePattern, charStyle або paraStyle +@msg knockout must be "on", "off", "neutral" or a bool, not {v} knockout має бути "on", "off", "neutral" або логічним значенням, а не {v} +@msg layer `{name}` has no art to export шар `{name}` не містить графіки для експорту +@msg layer must name a layer or sublayer layer має вказувати шар або підшар +@msg layers can't be intertwined: select the objects in them шари не можна переплітати: виділіть об’єкти в них +@msg layers go only at the top level or in layers, objects in layers and groups шари розміщуються лише на верхньому рівні або в шарах, об’єкти — у шарах і групах +@msg layers must be true or false layers має бути true або false +@msg layout must be gridByRow, gridByColumn, row or column layout має бути gridByRow, gridByColumn, row або column +@msg leading must be a number or "auto" leading має бути числом або "auto" +@msg left/right must be non-negative widths left/right мають бути невід’ємними ширинами +@msg legacyNameEncoding must be one of {_1} legacyNameEncoding має бути одним з: {_1} +@msg level `{t}`: 2 or 3 level `{t}`: 2 або 3 +@msg line {line}: more than {MAX_CSV_COLS} columns рядок {line}: понад {MAX_CSV_COLS} стовпців +@msg line {line}: unclosed quote рядок {line}: незакриті лапки +@msg line {line}: value for `{var}` must match its variable kind рядок {line}: значення `{var}` має відповідати типу її змінної +@msg lineEndings `{other}`: lf or crlf lineEndings `{other}`: lf або crlf +@msg loading profiles from disk isn't available in the browser завантаження профілів із диска недоступне у браузері +@msg localize: the first argument must be a localization object or a string localize: перший аргумент має бути об’єктом локалізації або рядком +@msg margin: a {m} pt margin leaves no imageable area on the paper поле: поле {m} pt не залишає на папері області друку +@msg matrix must be finite and invertible, depth finite matrix має бути скінченною й оборотною, depth — скінченною +@msg matte: {e} підкладка: {e} +@msg member is for order front, forward, backward or back member призначений для order front, forward, backward або back +@msg missing `artboards` відсутній `artboards` +@msg missing `at` [x, y] відсутній `at` [x, y] +@msg missing `attrs` відсутній `attrs` +@msg missing `color` or `opacity` відсутній `color` або `opacity` +@msg missing `colors` відсутній `colors` +@msg missing `commands` відсутній `commands` +@msg missing `destinationFolder` відсутній `destinationFolder` +@msg missing `effect` id відсутній ідентифікатор `effect` +@msg missing `family` відсутній `family` +@msg missing `find` відсутній `find` +@msg missing `gid` (a glyph id, or null for the default glyph) відсутній `gid` (ідентифікатор гліфа або null для стандартного гліфа) +@msg missing `group` відсутній `group` +@msg missing `id` відсутній `id` +@msg missing `id`: give one, or select one type object відсутній `id`: укажіть його або виділіть один текстовий об’єкт +@msg missing `index` (a point index, or null to clear) відсутній `index` (індекс точки або null для очищення) +@msg missing `index` (a stop index, or null to clear) відсутній `index` (індекс точки переходу або null для очищення) +@msg missing `index` (an item index or null) відсутній `index` (індекс елемента або null) +@msg missing `item` відсутній `item` +@msg missing `library` відсутній `library` +@msg missing `library` (see graphicStyle.libraries) відсутній `library` (див. graphicStyle.libraries) +@msg missing `library` (see swatch.library.list) відсутній `library` (див. swatch.library.list) +@msg missing `map` (rows [{from, to}] or {current}) відсутній `map` (рядки [{from, to}] або {current}) +@msg missing `matrix` [a,b,c,d,e,f] відсутній `matrix` [a,b,c,d,e,f] +@msg missing `name` (see gradient.presets.list) відсутній `name` (див. gradient.presets.list) +@msg missing `offset` (a distance in points) відсутній `offset` (відстань у пунктах) +@msg missing `path` відсутній `path` +@msg missing `path` (a path object id) відсутній `path` (ідентифікатор об’єкта-контуру) +@msg missing `picks` відсутній `picks` +@msg missing `rule` відсутній `rule` +@msg missing `source` id відсутній ідентифікатор `source` +@msg missing `start` (the byte offset of a character) відсутній `start` (зміщення символу в байтах) +@msg missing `status`: linked, embedded, missing or modified відсутній `status`: linked, embedded, missing або modified +@msg missing `target` id відсутній ідентифікатор `target` +@msg missing `text` відсутній `text` +@msg missing `to` відсутній `to` +@msg missing `to` (an index) відсутній `to` (індекс) +@msg missing `to`: a non-negative integer відсутній `to`: невід’ємне ціле число +@msg missing `type` відсутній `type` +@msg missing `value` відсутній `value` +@msg missing `word` відсутній `word` +@msg missing `{key}` відсутній `{key}` +@msg missing `{k}` відсутній `{k}` +@msg missing anchor відсутня опорна точка +@msg missing anchors відсутні опорні точки +@msg missing anchors [[subpath, anchor]…] відсутні anchors [[subpath, anchor]…] +@msg missing array `{key}` відсутній масив `{key}` +@msg missing case відсутній case +@msg missing color відсутній колір +@msg missing commands відсутні команди +@msg missing destination folder відсутня папка призначення +@msg missing from відсутній from +@msg missing group відсутня група +@msg missing id or ids відсутній id або ids +@msg missing ids відсутній ids +@msg missing indexes відсутній indexes +@msg missing matrix [a,b,c,d,e,f] відсутня matrix [a,b,c,d,e,f] +@msg missing name відсутнє ім’я +@msg missing op відсутній op +@msg missing or invalid `color` відсутній або неприпустимий `color` +@msg missing or unknown `tool` відсутній або невідомий `tool` +@msg missing point відсутня точка +@msg missing point [x,y] відсутня точка [x,y] +@msg missing point `{key}` ([x, y]) відсутня точка `{key}` ([x, y]) +@msg missing points відсутні точки +@msg missing points [[x,y]…] відсутні точки [[x,y]…] +@msg missing segment відсутній сегмент +@msg missing stops відсутні точки переходу +@msg missing subpaths відсутні вкладені контури +@msg missing target відсутній target +@msg missing to відсутній to +@msg missing x, y відсутні x, y +@msg mode is set, add or toggle, not `{other}` mode — це set, add або toggle, а не `{other}` +@msg mode must be "cmyk" or "rgb" mode має бути "cmyk" або "rgb" +@msg mode must be area|onPath, got {o} mode має бути area|onPath, отримано {o} +@msg more than 10000 linked files: package dependencies in smaller parts понад 10000 пов’язаних файлів: упаковуйте залежності меншими частинами +@msg more than 256 commands понад 256 команд +@msg more than {MAX_BATCH_FILES} data sets понад {MAX_BATCH_FILES} наборів даних +@msg more than {MAX_BATCH_FILES} files понад {MAX_BATCH_FILES} файлів +@msg more than {MAX_CSV_ROWS} data rows понад {MAX_CSV_ROWS} рядків даних +@msg more than {MAX_FILES} images понад {MAX_FILES} зображень +@msg more than {MAX_IMPORT} presets понад {MAX_IMPORT} наборів +@msg moved must be [[x,y]…] moved має бути [[x,y]…] +@msg must be an object with `kind` and `value` має бути об’єктом із `kind` і `value` +@msg must have `kind` alert, confirm or prompt повинен мати `kind` зі значенням alert, confirm або prompt +@msg must have exactly `kind` and `value` повинен мати рівно `kind` і `value` +@msg name (a toolbar's name) is required name (ім’я панелі інструментів) є обов’язковим +@msg name (a toolbar's name) must be a string name (ім’я панелі інструментів) має бути рядком +@msg name must be a toolbar's name name має бути іменем панелі інструментів +@msg names is empty names порожній +@msg names must be an array of symbol names names має бути масивом імен символів +@msg need `anchor` or `segment` + `t` потрібен `anchor` або `segment` + `t` +@msg need at least one anchor потрібна принаймні одна опорна точка +@msg need at least one point потрібна принаймні одна точка +@msg need at least two points потрібні принаймні дві точки +@msg needs a closing quote after the name потрібні закривні лапки після імені +@msg needs a name потрібне ім’я +@msg needs a name of at most 64 bytes потрібне ім’я довжиною не більше 64 байтів +@msg needs a name of letters, digits and _, or a quoted name потрібне ім’я з літер, цифр і _ або ім’я в лапках +@msg needs a name without control characters потрібне ім’я без керівних символів +@msg needs points потрібні точки +@msg nesting too deep завелика вкладеність +@msg nineSlice must be true or false nineSlice має бути true або false +@msg nineSliceGuides must be [left, top, right, bottom], each -16..16, with left + right < 1 and top + bottom < 1 nineSliceGuides має бути [left, top, right, bottom], кожне значення -16..16, причому left + right < 1 і top + bottom < 1 +@msg no HP-GL format немає формату HP-GL +@msg no New Document profile called `{shown}` ({_1}) немає профілю нового документа з іменем `{shown}` ({_1}) +@msg no PDF preset named `{n}` немає набору PDF з іменем `{n}` +@msg no SVG filter at index {k} немає фільтра SVG з індексом {k} +@msg no action set is current немає поточного набору дій +@msg no active data set немає активного набору даних +@msg no appearance item {index} немає елемента оформлення {index} +@msg no arrowheads file here тут немає файлу стрілок +@msg no artboard {_1} немає монтажної області {_1} +@msg no artboard {artboard} (0-based; the document has {_1}) немає монтажної області {artboard} (нумерація з 0; у документі їх {_1}) +@msg no asset {id} немає ресурсу {id} +@msg no asset {id} (see assets.list) немає ресурсу {id} (див. assets.list) +@msg no assets to export немає ресурсів для експорту +@msg no assets yet: collect art for export first (assets.add) ресурсів ще немає: спочатку зберіть графіку для експорту (assets.add) +@msg no brush named `{n}` немає пензля з іменем `{n}` +@msg no character at byte {start} немає символу в байті {start} +@msg no character has code {code} жоден символ не має коду {code} +@msg no colour немає кольору +@msg no colour group `{group}` немає групи кольорів `{group}` +@msg no colour group `{name}` немає групи кольорів `{name}` +@msg no custom arrowhead {name} (see stroke.arrowheads.list) немає користувацької стрілки {name} (див. stroke.arrowheads.list) +@msg no data sets немає наборів даних +@msg no dataset named `{from}` немає набору даних з іменем `{from}` +@msg no dataset named `{name}` немає набору даних з іменем `{name}` +@msg no datasets немає наборів даних +@msg no design named `{name}` немає дизайну з назвою `{name}` +@msg no design named `{n}` немає дизайну з назвою `{n}` +@msg no design named `{old}` немає дизайну з назвою `{old}` +@msg no encoder for {_1} yet кодувальника для {_1} ще немає +@msg no export preset `{name}` (see document.exportPresets.list) немає набору експорту `{name}` (див. document.exportPresets.list) +@msg no file to open немає файлу для відкриття +@msg no folder: pass `path` or set Preferences › Plug-ins & Scratch Disks › Additional Plug-ins Folder немає папки: передайте `path` або задайте Налаштування › Модулі та робочі диски › Додаткова папка модулів +@msg no fonts to look for: they are all available немає шрифтів для пошуку: усі вони доступні +@msg no formats to export немає форматів для експорту +@msg no gradient preset `{name}` (see gradient.presets.list) немає набору градієнта `{name}` (див. gradient.presets.list) +@msg no graphic style `{n}` in `{_1}` немає графічного стилю `{n}` у `{_1}` +@msg no graphic style library `{key}` (see graphicStyle.libraries) немає бібліотеки графічних стилів `{key}` (див. graphicStyle.libraries) +@msg no guide selected не виділено жодної напрямної +@msg no guide selected (or give an index) не виділено жодної напрямної (або вкажіть індекс) +@msg no guide {i} немає напрямної {i} +@msg no images in the folder у папці немає зображень +@msg no instructions немає інструкцій +@msg no item at index {_1} немає елемента з індексом {_1} +@msg no item at index {from} немає елемента з індексом {from} +@msg no item at one of the indices {idx} немає елемента з одним з індексів {idx} +@msg no layer немає шару +@msg no layer to rename немає шару для перейменування +@msg no layer {id} (see layer.list) немає шару {id} (див. layer.list) +@msg no layers to export немає шарів для експорту +@msg no library `{key}` немає бібліотеки `{key}` +@msg no metafile format немає формату метафайлу +@msg no object {_1} немає об’єкта {_1} +@msg no objects немає об’єктів +@msg no parent layer немає батьківського шару +@msg no perspective grid preset named `{b}` (see perspective.presets.list) немає набору сітки перспективи з іменем `{b}` (див. perspective.presets.list) +@msg no perspective grid preset named `{n}` немає набору сітки перспективи з іменем `{n}` +@msg no point selected (give `index`) не виділено жодної точки (укажіть `index`) +@msg no preset called `{from}` (see file.newPresets) немає набору з іменем `{from}` (див. file.newPresets) +@msg no preset called `{name}` (see file.newPresets) немає набору з іменем `{name}` (див. file.newPresets) +@msg no preset named `{n}` немає набору з іменем `{n}` +@msg no print preset named `{b}` (see print.presets.list) немає набору друку з іменем `{b}` (див. print.presets.list) +@msg no print preset named `{name}` (presets: {_1}) немає набору друку з іменем `{name}` (набори: {_1}) +@msg no print preset named `{n}` немає набору друку з іменем `{n}` +@msg no profile named `{name}` немає профілю з іменем `{name}` +@msg no random numbers ({e}) немає випадкових чисел ({e}) +@msg no readable files in the folder у папці немає файлів, які можна прочитати +@msg no recovery copy `{f}` (see file.recovery.list) немає копії для відновлення `{f}` (див. file.recovery.list) +@msg no rows немає рядків +@msg no saved PDF preset named `{name}` немає збереженого набору PDF з іменем `{name}` +@msg no saved export preset `{name}` немає збереженого набору експорту `{name}` +@msg no saved gradient preset called {name} немає збереженого набору градієнта з іменем {name} +@msg no saved gradient presets немає збережених наборів градієнта +@msg no saved preset called `{name}` немає збереженого набору з іменем `{name}` +@msg no saved presets to export (name [Default] in `names` to export it) немає збережених наборів для експорту (укажіть [Default] у `names`, щоб експортувати його) +@msg no saved presets to export (name built-in ones in `names`) немає збережених наборів для експорту (вбудовані вкажіть у `names`) +@msg no saved print preset named `{name}` немає збереженого набору друку з іменем `{name}` +@msg no saved profile called {name} немає збереженого профілю з іменем {name} +@msg no saved selection `{name}` немає збереженого виділення `{name}` +@msg no saved theme called {name} (see colorTheme.list) немає збереженої теми з іменем {name} (див. colorTheme.list) +@msg no saved views немає збережених виглядів +@msg no selected or given object has a visible 3D effect жоден виділений або вказаний об’єкт не має видимого 3D-ефекту +@msg no series {i} немає ряду {i} +@msg no slice {n} in the image (see slice.list) у зображенні немає фрагмента {n} (див. slice.list) +@msg no source art немає вихідної графіки +@msg no stop {i} (the gradient has {n}) немає точки переходу {i} (у градієнті їх {n}) +@msg no style `{name}` немає стилю `{name}` +@msg no such artboard {v} такої монтажної області немає: {v} +@msg no such assets (see assets.list) таких ресурсів немає (див. assets.list) +@msg no such frame anchor, or the frame would reach past the canvas такої опорної точки рамки немає або рамка вийшла б за межі полотна +@msg no such objects таких об’єктів немає +@msg no such path anchor, or the path would reach past the canvas такої опорної точки контуру немає або контур вийшов би за межі полотна +@msg no such rows таких рядків немає +@msg no swatch `{keep}` немає зразка `{keep}` +@msg no swatch `{n}` немає зразка `{n}` +@msg no swatch `{n}` (swatches and colour groups move separately) немає зразка `{n}` (зразки та групи кольорів переміщуються окремо) +@msg no swatch library `{key}` (see swatch.library.list) немає бібліотеки зразків `{key}` (див. swatch.library.list) +@msg no swatch library `{key}` (see swatch.library.list; "document": the document's swatches) немає бібліотеки зразків `{key}` (див. swatch.library.list; "document": зразки документа) +@msg no swatch library `{key}` (see swatch.library.list; "{DOCUMENT_SWATCHES}": the document's swatches) немає бібліотеки зразків `{key}` (див. swatch.library.list; "{DOCUMENT_SWATCHES}": зразки документа) +@msg no swatch named `{n}` немає зразка з іменем `{n}` +@msg no swatch or colour group `{n}` немає зразка або групи кольорів `{n}` +@msg no swatch or colour group `{n}` in `{_1}` немає зразка або групи кольорів `{n}` у `{_1}` +@msg no symbol named `{_1}` немає символу з іменем `{_1}` +@msg no symbol named `{name}` немає символу з іменем `{name}` +@msg no text objects selected не виділено жодного текстового об’єкта +@msg no toolbar named `{_1}` немає панелі інструментів з іменем `{_1}` +@msg no toolbar named `{name}` немає панелі інструментів з іменем `{name}` +@msg no tracing preset `{preset}` (see imageTrace.presets) немає набору трасування `{preset}` (див. imageTrace.presets) +@msg no user library folder here (save with a path, or without one to get the data) тут немає папки користувацьких бібліотек (збережіть зі шляхом або без нього, щоб отримати дані) +@msg no variable named `{from}` немає змінної з іменем `{from}` +@msg no variable named `{name}` немає змінної з іменем `{name}` +@msg no variable named `{var}` немає змінної з іменем `{var}` +@msg no variable named `{v}` немає змінної з іменем `{v}` +@msg no view named `{name}` немає вигляду з іменем `{name}` +@msg node {_1} already has the text variable `{_2}` вузол {_1} уже має текстову змінну `{_2}` +@msg node {_1} is not a graph вузол {_1} не є діаграмою +@msg node {_1} is not an image вузол {_1} не є зображенням +@msg node {_1} is not type вузол {_1} не є текстом +@msg not a DCS file це не файл DCS +@msg not a PDF presets file (format `{_1}`) це не файл наборів PDF (формат `{_1}`) +@msg not a PDF presets file: {e} це не файл наборів PDF: {e} +@msg not a RegExp object це не об’єкт RegExp +@msg not a Word document: its WordDocument stream doesn't start with a file information block це не документ Word: його потік WordDocument не починається з блоку відомостей про файл +@msg not a Word document: its compound file has no WordDocument stream це не документ Word: його складений файл не має потоку WordDocument +@msg not a Word document: its main part is not a WordprocessingML document це не документ Word: його основна частина не є документом WordprocessingML +@msg not a Word document: its package has no main document part це не документ Word: його пакет не має основної частини документа +@msg not a closed path це не замкнений контур +@msg not a flattener presets file (format `{_1}`) це не файл наборів зведення прозорості (формат `{_1}`) +@msg not a flattener presets file: {e} це не файл наборів зведення прозорості: {e} +@msg not a layer or group це не шар і не група +@msg not a library file: {e} це не файл бібліотеки: {e} +@msg not a mesh envelope point це не точка сітки оболонки +@msg not a perspective grid presets file (format `{_1}`) це не файл наборів сітки перспективи (формат `{_1}`) +@msg not a perspective grid presets file: {e} це не файл наборів сітки перспективи: {e} +@msg not a print presets file (format `{_1}`) це не файл наборів друку (формат `{_1}`) +@msg not a print presets file: {e} це не файл наборів друку: {e} +@msg not a regular expression це не регулярний вираз +@msg not a stored or deflated central record це не збережений і не стиснутий методом deflate центральний запис +@msg not a valid SVGZ file: {e} це не припустимий файл SVGZ: {e} +@msg not an RTF file: it doesn't start with {\\rtf це не файл RTF: він не починається з {\\rtf +@msg not an action set: the text doesn't start with /version and a number це не набір дій: текст не починається з /version і числа +@msg not an image VectorCraft reads (see document.formats) це не зображення, яке читає VectorCraft (див. document.formats) +@msg not area type (text in a frame) outside perspective це не текст в області (текст у рамці) поза перспективою +@msg not editing an opacity mask маска непрозорості не редагується +@msg not type on a path outside perspective це не текст за контуром поза перспективою +@msg nothing prints нічого не друкується +@msg nothing to bind немає чого прив’язувати +@msg nothing to change немає чого змінювати +@msg nothing to change: give dx, dy, hScale, vScale or rotation немає чого змінювати: укажіть dx, dy, hScale, vScale або rotation +@msg nothing to crop немає чого обрізати +@msg nothing to export немає чого експортувати +@msg nothing to export: the document has no visible art немає чого експортувати: документ не містить видимої графіки +@msg nothing to mark немає чого позначати +@msg nothing to print: every artboard picked is blank немає чого друкувати: усі вибрані монтажні області порожні +@msg nothing to print: the document has no art that prints немає чого друкувати: документ не містить графіки, яка друкується +@msg nothing to repeat немає чого повторювати +@msg numbers out of order in {_1} quantifier числа в неправильному порядку у квантифікаторі {_1} +@msg object is not a path об’єкт не є контуром +@msg object transparency cannot be sampled onto highlighted characters; disable Transparency in Eyedropper Options or select the whole object прозорість об’єкта не можна перенести на виділені символи; вимкніть «Прозорість» у параметрах піпетки або виділіть увесь об’єкт +@msg object {_1} can't be set as point type об’єкт {_1} не можна зробити текстом із точки +@msg object {_1} has lost its file's contents: relink it об’єкт {_1} втратив вміст свого файлу: зв’яжіть його повторно +@msg object {_1} has no path об’єкт {_1} не має контуру +@msg object {_1} has no size об’єкт {_1} не має розміру +@msg object {_1} is hidden or locked, or on a locked artboard об’єкт {_1} приховано чи заблоковано або він розташований на заблокованій монтажній області +@msg object {_1} is not a placed document об’єкт {_1} не є поміщеним документом +@msg object {_1} is not an Intertwine group об’єкт {_1} не є групою переплетення +@msg object {_1} is not an image об’єкт {_1} не є зображенням +@msg object {_1} is not an image or a linked file об’єкт {_1} не є зображенням або пов’язаним файлом +@msg object {_1} is not an image or a placed document об’єкт {_1} не є зображенням або поміщеним документом +@msg object {_1} is not in this Intertwine group об’єкт {_1} не входить до цієї групи переплетення +@msg object {_1} needs a 3D effect об’єкту {_1} потрібен 3D-ефект +@msg object {_1} needs a 3D effect at index {index} об’єкту {_1} потрібен 3D-ефект з індексом {index} +@msg object {_1}: a hollow Extrude & Bevel has no caps: turn on Cap to map a graphic об’єкт {_1}: порожнисте «Видавлювання та фаска» не має торців: увімкніть «Торець», щоб накласти графіку +@msg object {_1}: with a depth of 0 the object has one face: map its graphics onto the front об’єкт {_1}: за глибини 0 об’єкт має одну грань: накладіть його графіку на передню грань +@msg object {_1}: {_2} об’єкт {_1}: {_2} +@msg object {_1}: {e} об’єкт {_1}: {e} +@msg object {_1}: {name} at index {index} has no lighting presets; set its lights with effect.setParams об’єкт {_1}: {name} з індексом {index} не має наборів освітлення; задайте його джерела світла за допомогою effect.setParams +@msg object {id} has anchors 0–{_1} for `corners`, not {past} об’єкт {id} має для `corners` опорні точки 0–{_1}, а не {past} +@msg object {id} has {n} anchors, so no anchor {past} об’єкт {id} має опорних точок: {n}, тому точки {past} немає +@msg objects must be none, move or copy objects має бути none, move або copy +@msg objects were left out об’єкти пропущено +@msg offset out of range зміщення поза межами діапазону +@msg on must be true or false on має бути true або false +@msg only groups, layers, type and images have a Contents (Characters) row рядок «Вміст (символи)» мають лише групи, шари, текст і зображення +@msg only interior mesh lines can be deleted видаляти можна лише внутрішні лінії сітки +@msg only solid colours can be added (not gradients or patterns) додавати можна лише суцільні кольори (не градієнти й не візерунки) +@msg only solid-colour swatches can be spot colours плашковими кольорами можуть бути лише зразки суцільного кольору +@msg only this Affinity file's embedded preview could be read: use File › Open to see it with its warning, or export SVG or PDF from Affinity first вдалося прочитати лише вбудований попередній перегляд цього файлу Affinity: скористайтеся командою Файл › Відкрити, щоб побачити його з попередженням, або спочатку експортуйте SVG чи PDF з Affinity +@msg only this Affinity file's embedded preview could be read; use File › Open to see it with its warning вдалося прочитати лише вбудований попередній перегляд цього файлу Affinity; скористайтеся командою Файл › Відкрити, щоб побачити його з попередженням +@msg onto, above, below, icon and a column place belong to window.panel.float and window.panel.dock onto, above, below, icon і місце у стовпці належать до window.panel.float і window.panel.dock +@msg onto, above, below, icon and a column place take no anchor, side, zone or before onto, above, below, icon і місце у стовпці не приймають anchor, side, zone або before +@msg onto, above, below, icon and a column place take no x, y, width or height onto, above, below, icon і місце у стовпці не приймають x, y, width або height +@msg opacity must be a number opacity має бути числом +@msg open a document to look for its linked files відкрийте документ, щоб шукати його пов’язані файли +@msg operand too large операнд завеликий +@msg options must be an object (see file.formatOptions) options має бути об’єктом (див. file.formatOptions) +@msg order is a whole number from 0 to {others}, not `{v}` order — це ціле число від 0 до {others}, а не `{v}` +@msg order must be leftToRight or rightToLeft order має бути leftToRight або rightToLeft +@msg orientation must be portrait or landscape, not `{o}` orientation має бути portrait або landscape, а не `{o}` +@msg outlineText {v}: true or false outlineText {v}: true або false +@msg output intent profile: {e} профіль призначення виведення: {e} +@msg output.destination: no RGB or CMYK profile is called “{name}” output.destination: немає профілю RGB або CMYK з іменем «{name}» +@msg output.destination: {_1} files are CMYK, and “{name}” is an RGB profile output.destination: файли {_1} мають модель CMYK, а «{name}» — це профіль RGB +@msg output.destination: {e} output.destination: {e} +@msg output.inks: no ink is set to print output.inks: жодну фарбу не призначено для друку +@msg output.outputIntent: no profile is called “{name}”, and a {std} output intent embeds its profile output.outputIntent: немає профілю з іменем «{name}», а призначення виведення {std} вбудовує свій профіль +@msg output.outputIntent: no profile is called “{name}”: a {std} output intent embeds a profile, or names a registered printing condition (outputConditionId and registry) output.outputIntent: немає профілю з іменем «{name}»: призначення виведення {std} вбудовує профіль або вказує зареєстровану умову друку (outputConditionId і registry) +@msg output.outputIntent: {std} files print in CMYK, and “{name}” is an RGB profile output.outputIntent: файли {std} друкуються в CMYK, а «{name}» — це профіль RGB +@msg output.outputIntent: “{name}” is a grey profile, which can't be a {std} output intent output.outputIntent: «{name}» — це профіль відтінків сірого, який не може бути призначенням виведення {std} +@msg overlap: {o} pt is half a tile or more перекриття: {o} pt — це половина плитки або більше +@msg overlapping Shaper paths must be in the same layer or group контури формоутворення, що перекриваються, мають бути в одному шарі або групі +@msg overlapping edits правки перекриваються +@msg page art conflicts with image data for {key} графіка сторінки конфліктує з даними зображення для {key} +@msg page art conflicts with pattern {name} графіка сторінки конфліктує з візерунком {name} +@msg page art conflicts with swatch {name} графіка сторінки конфліктує зі зразком {name} +@msg page art is missing image data for {key} у графіці сторінки бракує даних зображення для {key} +@msg page art is missing pattern {name} у графіці сторінки бракує візерунка {name} +@msg page art is missing swatch {name} у графіці сторінки бракує зразка {name} +@msg page must be a whole number from 1 page має бути цілим числом від 1 +@msg page thumbnail: {e} мініатюра сторінки: {e} +@msg page {page} of the PDF has no objects сторінка {page} файлу PDF не містить об’єктів +@msg page {page}: `{file}` has {n} {artboards} сторінка {page}: `{file}` має {n} {artboards} +@msg page {page}: `{name}` has {n} {pages} сторінка {page}: `{name}` має {n} {pages} +@msg pages must be a range such as "2-3" or a page number, not {v} pages має бути діапазоном на зразок "2-3" або номером сторінки, а не {v} +@msg pages: {e} pages: {e} +@msg panel position must be finite положення панелі має бути скінченним +@msg parameters must be an object parameters має бути об’єктом +@msg params must be an object params має бути об’єктом +@msg passwords can have up to {MAX_PASSWORD} bytes паролі можуть містити до {MAX_PASSWORD} байтів +@msg path chunks must share their boundary point частини контуру повинні мати спільну граничну точку +@msg path has no open end контур не має відкритого кінця +@msg paths must be strings paths має містити рядки +@msg pdfCompatible: false needs every artboard to keep the editable artwork pdfCompatible: false потребує всіх монтажних областей, щоб зберегти редаговану графіку +@msg pdfCompatible: false needs the artboards to keep the editable artwork when useArtboards is false pdfCompatible: false потребує монтажних областей, щоб зберегти редаговану графіку, коли useArtboards дорівнює false +@msg pdfs `{m}`: single or multiple pdfs `{m}`: single або multiple +@msg pickColorFrom is "artwork" or "swatches", not {v} pickColorFrom — це "artwork" або "swatches", а не {v} +@msg pins and moved must be non-empty lists of the same length pins і moved мають бути непорожніми списками однакової довжини +@msg pins must be [[x,y]…] pins має бути [[x,y]…] +@msg pins must be finite pins мають бути скінченними +@msg place is above, below or inside, not `{other}` place — це above, below або inside, а не `{other}` +@msg plane must be left|right|ground plane має бути left|right|ground +@msg plane must be left|right|ground|none plane має бути left|right|ground|none +@msg point is outside the mesh точка лежить поза сіткою +@msg point x must be a number x точки має бути числом +@msg point y must be a number y точки має бути числом +@msg points must be [t, left, right] with non-negative widths points має бути [t, left, right] з невід’ємними ширинами +@msg points must be [x,y] pairs points має містити пари [x,y] +@msg points must be a non-empty [[x,y,pressure?]…] list points має бути непорожнім списком [[x,y,pressure?]…] +@msg points must be a non-empty list of finite [x,y] points має бути непорожнім списком скінченних [x,y] +@msg points must be an array or null points має бути масивом або null +@msg points must be finite points мають бути скінченними +@msg points must be finite [x,y] pairs points має містити скінченні пари [x,y] +@msg points must be finite canvas points points має містити скінченні точки полотна +@msg points must contain 1–4096 coordinates points має містити 1–4096 координат +@msg position must be normal, superscript or subscript position має бути normal, superscript або subscript +@msg position must be topLeft, topRight, bottomLeft or bottomRight position має бути topLeft, topRight, bottomLeft або bottomRight +@msg positions must be between 0 and 100000 pt positions мають бути від 0 до 100000 pt +@msg ppi must be a positive number, not {ppi} ppi має бути додатним числом, а не {ppi} +@msg ppi must be between 1 and 2400 ppi має бути від 1 до 2400 +@msg preserve `{v}` is not transforms|bounds|fileDimensions|fit|fill preserve `{v}` не є transforms|bounds|fileDimensions|fit|fill +@msg preserveShape must be clippingMask|transparency preserveShape має бути clippingMask|transparency +@msg preset `{id}`: mobile or density preset `{id}`: mobile або density +@msg preset must be standard, diffuse, topLeft or right preset має бути standard, diffuse, topLeft або right +@msg preset must be the name of a print preset preset має бути іменем набору друку +@msg previewMode must be default, pixel or overprint previewMode має бути default, pixel або overprint +@msg print settings: {e} параметри друку: {e} +@msg procedures nest too deeply процедури мають завелику вкладеність +@msg procedures nested too deeply вкладеність процедур завелика +@msg quotes must be {double?, single?} quotes має бути {double?, single?} +@msg quotes.{k} must be an opening and a closing quote, e.g. "“”" quotes.{k} має складатися з відкривних і закривних лапок, наприклад "“”" +@msg range out of order in character class діапазон у неправильному порядку в класі символів +@msg rasterEffectsPpi must be 1–2400 (72 screen, 150 medium, 300 high) rasterEffectsPpi має бути 1–2400 (72 — екран, 150 — середня, 300 — висока) +@msg rating must be a whole number from 0 to {MAX_RATING} rating має бути цілим числом від 0 до {MAX_RATING} +@msg rect and {k} contradict each other: give the area or the artboards rect і {k} суперечать один одному: укажіть область або монтажні області +@msg rect applies to raster formats, not {_1} rect застосовується до растрових форматів, а не до {_1} +@msg rect is [x, y, width, height] in points rect — це [x, y, width, height] у пунктах +@msg rect must be [x, y, width, height] rect має бути [x, y, width, height] +@msg rect must be [x, y, width, height] with a positive width and height rect має бути [x, y, width, height] з додатними шириною та висотою +@msg rect needs finite numbers and a positive width and height для rect потрібні скінченні числа й додатні ширина та висота +@msg redraw needs id для redraw потрібен id +@msg redraw within must be a finite distance of 0 or more within для redraw має бути скінченною відстанню, 0 або більше +@msg reduce of an empty array with no initial value reduce для порожнього масиву без початкового значення +@msg registration must be 0..8 registration має бути 0..8 +@msg regular expression flag '{_1}' given twice прапорець регулярного виразу '{_1}' указано двічі +@msg release a layer or a group звільніть шар або групу +@msg replace keeps the replaced object's place and transform: drop template, at and rect replace зберігає місце й трансформацію заміненого об’єкта: не вказуйте template, at і rect +@msg replace: select the one object to replace replace: виділіть один об’єкт, який треба замінити +@msg resolution must be a number or screen|medium|high resolution має бути числом або screen|medium|high +@msg resolution must be between 1 and 2400 ppi resolution має бути від 1 до 2400 ppi +@msg rotation must be a number of degrees rotation має бути числом градусів +@msg rotation must be finite rotation має бути скінченним +@msg rows and cols must be 1..50 rows і cols мають бути 1..50 +@msg rows and columns must be 1..500 rows і columns мають бути 1..500 +@msg rows of objects whose appearances differ can't be reordered together рядки об’єктів із різним оформленням не можна перевпорядковувати разом +@msg sampled text would exceed the canvas (coordinates out of range) текст, з якого взято зразок, вийшов би за межі полотна (координати поза діапазоном) +@msg save the document first: Package collects a saved document спочатку збережіть документ: команда «Упакувати» збирає збережений документ +@msg save the document first: copy puts the file in its folder спочатку збережіть документ: copy поміщає файл у його папку +@msg savedPreset: {e} savedPreset: {e} +@msg scale `{s}`: a factor such as 2x, a width (100w), a height (100h) or a resolution (72ppi) scale `{s}`: коефіцієнт на зразок 2x, ширина (100w), висота (100h) або роздільна здатність (72ppi) +@msg scale must be a number above 0, at most 64 scale має бути числом більше 0 і не більше 64 +@msg scale must be non-zero scale не має дорівнювати нулю +@msg scope must be selection or all (got {other}) scope має бути selection або all (отримано {other}) +@msg scribble is too long розчерк задовгий +@msg segment does not exist сегмент не існує +@msg select a Shaper group виділіть групу формоутворення +@msg select a blend to set easing or color shift виділіть перехід, щоб задати плавність або зсув кольору +@msg select a graph виділіть діаграму +@msg select a group or layer with visible, unlocked members виділіть групу або шар із видимими незаблокованими елементами +@msg select a layer виділіть шар +@msg select a text object виділіть текстовий об’єкт +@msg select an SVG filter виділіть фільтр SVG +@msg select an image (or an Image Trace group) виділіть зображення (або групу трасування зображення) +@msg select an image, or pass id виділіть зображення або передайте id +@msg select an object (or pass `id`) виділіть об’єкт (або передайте `id`) +@msg select an object with a 3D effect виділіть об’єкт із 3D-ефектом +@msg select an object with a 3D effect, or give its id in ids виділіть об’єкт із 3D-ефектом або вкажіть його ідентифікатор в ids +@msg select an object with a freeform gradient виділіть об’єкт із довільним градієнтом +@msg select an object with an opacity mask виділіть об’єкт із маскою непрозорості +@msg select area type виділіть текст в області +@msg select area type (text in a frame) виділіть текст в області (текст у рамці) +@msg select area type and closed paths (at least one area type object) виділіть текст в області й замкнені контури (принаймні один об’єкт тексту в області) +@msg select area type whose first line can fit its frame виділіть текст в області, перший рядок якого вміщується в його рамку +@msg select artwork to add its colours виділіть графіку, щоб додати її кольори +@msg select artwork to make a group of its colours виділіть графіку, щоб створити групу з її кольорів +@msg select artwork to recolour, or give a colour `group` виділіть графіку для перефарбування або вкажіть `group` кольорів +@msg select exactly two path ends to join виділіть рівно два кінці контурів для з’єднання +@msg select objects or give ids виділіть об’єкти або вкажіть ids +@msg select objects to align to the guide виділіть об’єкти, які треба вирівняти за напрямною +@msg select one Intertwine group виділіть одну групу переплетення +@msg select one image or pass id виділіть одне зображення або передайте id +@msg select one layer, group or object to rename виділіть один шар, групу або об’єкт для перейменування +@msg select paths виділіть контури +@msg select paths or compound paths виділіть контури або складені контури +@msg select rows or objects to collect виділіть рядки або об’єкти, які треба зібрати +@msg select something to export виділіть що-небудь для експорту +@msg select something to export (or turn off selectedOnly) виділіть що-небудь для експорту (або вимкніть selectedOnly) +@msg select text to redefine the style from виділіть текст, за яким треба перевизначити стиль +@msg select the art and, on top of it, the mask object виділіть графіку і розташований поверх неї об’єкт маски +@msg select the art for the design виділіть графіку для дизайну +@msg select the art for the pattern tile виділіть графіку для плитки візерунка +@msg select the art to add first спочатку виділіть графіку, яку треба додати +@msg select the art to collect (or give its ids) виділіть графіку, яку треба зібрати (або вкажіть її ідентифікатори) +@msg select the art to weed виділіть графіку для вибірки +@msg select the content and a path on top виділіть вміст і контур поверх нього +@msg select the images to relink, or pass ids виділіть зображення для повторного зв’язування або передайте ids +@msg select the images, or pass ids виділіть зображення або передайте ids +@msg select the linked images or placed documents, or pass ids виділіть пов’язані зображення чи поміщені документи або передайте ids +@msg select the object to copy from виділіть об’єкт, з якого треба копіювати +@msg select the objects (or give their ids) виділіть об’єкти (або вкажіть їхні ідентифікатори) +@msg select the objects to attach to the path виділіть об’єкти, які треба прикріпити до контуру +@msg select the objects to bind виділіть об’єкти, які треба прив’язати +@msg select two or more objects to intertwine виділіть два або більше об’єктів для переплетення +@msg select two or more slices to combine виділіть два або більше фрагментів для об’єднання +@msg select type on a path виділіть текст за контуром +@msg select type on a path or area type виділіть текст за контуром або текст в області +@msg selection `{m}`: one or each selection `{m}`: one або each +@msg settings is an object of document.exportForScreens params settings — це об’єкт параметрів document.exportForScreens +@msg settings must be an object settings має бути об’єктом +@msg show `{show}`: all, missing, modified or embedded show `{show}`: all, missing, modified або embedded +@msg show must be true or false show має бути true або false +@msg side is left or right, not `{v}` side — це left або right, а не `{v}` +@msg size must be "small", "medium", "large" or a number of points over 0 up to {_1} size має бути "small", "medium", "large" або числом пунктів більше 0 і не більше {_1} +@msg size must be positive size має бути додатним +@msg sizeMode is "fixed" or "pressure", not `{other}` sizeMode — це "fixed" або "pressure", а не `{other}` +@msg sizeMode is "fixed" or "pressure", not {other} sizeMode — це "fixed" або "pressure", а не {other} +@msg sizeVariation must be 0 or more sizeVariation має бути 0 або більше +@msg smallCaps must be true or false smallCaps має бути true або false +@msg sort `{x}`: name, kind or status sort `{x}`: name, kind або status +@msg source paths are too large for Shaper вихідні контури завеликі для формоутворення +@msg source text transform is collapsed or unrepresentable трансформація вихідного тексту вироджена або її не можна передати +@msg spot, mode and group apply to solid colours only spot, mode і group застосовуються лише до суцільних кольорів +@msg status `{s}`: linked, embedded, missing or modified status `{s}`: linked, embedded, missing або modified +@msg steps must be 1..1000 steps має бути 1..1000 +@msg steps must be 1..{MAX_STEPS} steps має бути 1..{MAX_STEPS} +@msg stop {i}: `plates` must be four numbers from 0 to 1 (C, M, Y, K) точка переходу {i}: `plates` має містити чотири числа від 0 до 1 (C, M, Y, K) +@msg stopped before the archive was finished зупинено до завершення архіву +@msg strokeMode must be within|along|across, got {m} strokeMode має бути within|along|across, отримано {m} +@msg strokeOptions must be an object of stroke.set options strokeOptions має бути об’єктом параметрів stroke.set +@msg strokeWidth must be a positive number of pixels strokeWidth має бути додатним числом пікселів +@msg subpath {si} is not an open subpath вкладений контур {si} не є відкритим +@msg subpaths required when joining the same path для з’єднання того самого контуру потрібен subpaths +@msg swatchConflict must be "merge" or "add", not {v} swatchConflict має бути "merge" або "add", а не {v} +@msg table must be true or false table має бути true або false +@msg takes one name приймає одне ім’я +@msg target text transform is collapsed or unrepresentable трансформація цільового тексту вироджена або її не можна передати +@msg text must be {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} text має бути {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} +@msg text transform is collapsed or unrepresentable трансформація тексту вироджена або її не можна передати +@msg text.replaceSpaces must be a whole number from 2 to 100 text.replaceSpaces має бути цілим числом від 2 до 100 +@msg text.{key} `{v}`: use "{_1}" or "{_2}" text.{key} `{v}`: використайте "{_1}" або "{_2}" +@msg textureImage: give {path} or {name, dataBase64} of an image file, or a texture as effect.list gives it textureImage: укажіть {path} або {name, dataBase64} файлу зображення чи текстуру в тому вигляді, у якому її подає effect.list +@msg textureImage: {e} textureImage: {e} +@msg that makes more than {MAX_PIECES} slices це створює понад {MAX_PIECES} фрагментів +@msg that makes too many pieces (at most 100000) or dash steps: simplify the dash pattern or make the dashes longer це створює забагато частин (не більше 100000) або кроків штриха: спростіть шаблон штрихів або зробіть штрихи довшими +@msg that object is not in the overlap цей об’єкт не входить до перекриття +@msg the Affinity document has no page with a size документ Affinity не має сторінки з розміром +@msg the CMYK image couldn't be written не вдалося записати зображення CMYK +@msg the Layers panel is not shown панель «Шари» не показано +@msg the Layers panel's search, filter or Show Layers Only hides its row пошук, фільтр або режим «Показати лише шари» на панелі «Шари» приховує його рядок +@msg the Objects on Path group is hidden or locked групу «Об’єкти на контурі» приховано або заблоковано +@msg the PDF security settings were saved without their passwords: give openPassword or permissionsPassword again, or security without passwordRequired to export unprotected параметри захисту PDF збережено без паролів: укажіть openPassword або permissionsPassword ще раз чи задайте security без passwordRequired, щоб експортувати без захисту +@msg the RTF file has too many paragraphs or formatting changes to place as type (at most {MAX_PARAGRAPHS} paragraphs and {MAX_RUNS} runs) файл RTF містить забагато абзаців або змін форматування, щоб помістити його як текст (не більше {MAX_PARAGRAPHS} абзаців і {MAX_RUNS} фрагментів форматування) +@msg the RTF file is too large to place as type (at most {_1} MB) файл RTF завеликий, щоб помістити його як текст (не більше {_1} МБ) +@msg the SVG expands to more than {0} nested SVG images SVG розгортається у понад {0} вкладених зображень SVG +@msg the SVG expands to more than {0} objects SVG розгортається у понад {0} об’єктів +@msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes файл SVG більший за {MAX_IMPORT_BYTES} байтів +@msg the SVG has no drawable objects SVG не містить об’єктів, які можна намалювати +@msg the SVGZ file unpacks to more than {_1} MB файл SVGZ розпаковується у понад {_1} МБ +@msg the Word document has more than {MAX_PAGES} pages of properties, too many to place документ Word містить понад {MAX_PAGES} сторінок властивостей, це забагато для розміщення +@msg the Word document has more than {MAX_RUNS} runs of character or paragraph properties, too many to place документ Word містить понад {MAX_RUNS} фрагментів властивостей символів або абзаців, це забагато для розміщення +@msg the Word document has more than {_1} MB of formatting properties, too many to place документ Word містить понад {_1} МБ властивостей форматування, це забагато для розміщення +@msg the Word document has too much text or formatting to place as type (at most {MAX_PARAGRAPHS} paragraphs, {MAX_RUNS} runs and {_1} MB of text) документ Word містить забагато тексту або форматування, щоб помістити його як текст (не більше {MAX_PARAGRAPHS} абзаців, {MAX_RUNS} фрагментів форматування і {_1} МБ тексту) +@msg the Word document has too much text to place as type (at most {_1} MB) документ Word містить забагато тексту, щоб помістити його як текст (не більше {_1} МБ) +@msg the Word document is encrypted or protected with a password; save it without one to place it документ Word зашифровано або захищено паролем; збережіть його без пароля, щоб помістити +@msg the Word document is too large to place (its {name} stream holds more than {_1} MB) документ Word завеликий для розміщення (його потік {name} містить понад {_1} МБ) +@msg the Word document was last saved with fast save, which VectorCraft doesn't read; save it again with fast save turned off документ Word востаннє збережено зі швидким збереженням, яке VectorCraft не читає; збережіть його ще раз, вимкнувши швидке збереження +@msg the Word document was saved by Word 6.0 or Word 95, which VectorCraft doesn't read; save it as a Word 97-2003 document документ Word збережено у Word 6.0 або Word 95, а такі файли VectorCraft не читає; збережіть його як документ Word 97-2003 +@msg the Word document's text is made of more than {MAX_PIECES} pieces, too many to place текст документа Word складається з понад {MAX_PIECES} частин, це забагато для розміщення +@msg the XML operation needs an XML or XMLList value для операції XML потрібне значення XML або XMLList +@msg the XPath expression does not evaluate to a node-set результат виразу XPath не є набором вузлів +@msg the XPath expression ends early вираз XPath закінчується передчасно +@msg the XPath expression has an unmatched ) вираз XPath містить непарну дужку ) +@msg the XPath expression has an unmatched ] вираз XPath містить непарну дужку ] +@msg the XPath expression has an unmatched closing bracket вираз XPath містить непарну закривну дужку +@msg the XPath expression selects a namespace node, which is not an XML value вираз XPath вибирає вузол простору імен, який не є значенням XML +@msg the XPath expression selects the root node, which is not an XML value вираз XPath вибирає кореневий вузол, який не є значенням XML +@msg the XPath function {name} needs a node-set функції XPath {name} потрібен набір вузлів +@msg the XPath function {name} takes the wrong number of arguments функція XPath {name} отримала неправильну кількість аргументів +@msg the XPath name functions need a node-set функціям імен XPath потрібен набір вузлів +@msg the XPath prefix {shown} is not bound to a namespace префікс XPath {shown} не прив’язано до простору імен +@msg the XPath variable ${shown} is not bound змінну XPath ${shown} не прив’язано +@msg the action set ids are not a list ідентифікатори наборів дій не є списком +@msg the active paint is not a gradient активна фарба не є градієнтом +@msg the argument list is not an object список аргументів не є об’єктом +@msg the artboards don't fit on the canvas: fewer artboards, less spacing or a smaller size монтажні області не вміщуються на полотні: зменште їх кількість, інтервал або розмір +@msg the artwork is too large for EPS: what follows 256 MB of PostScript was left out графіка завелика для EPS: усе, що йде після 256 МБ коду PostScript, пропущено +@msg the bitmaps hold more pixels than one file may растрові зображення містять більше пікселів, ніж дозволено для одного файлу +@msg the character's size can't be measured розмір символу не можна виміряти +@msg the code runs past its last instruction код виконується далі своєї останньої інструкції +@msg the compound shape is too complex to expand складена фігура занадто складна для розбирання +@msg the container of the listed objects is gone контейнера перелічених об’єктів більше немає +@msg the copy `{user_id}` can't be read as a library копію `{user_id}` не вдалося прочитати як бібліотеку +@msg the copy would leave the canvas копія вийшла б за межі полотна +@msg the curve tolerance must be from 0.01 to 10 points допуск кривої має бути від 0.01 до 10 пунктів +@msg the custom dictionary couldn't be saved to {_1}: {e} не вдалося зберегти словник користувача в {_1}: {e} +@msg the custom dictionary {_1} can't be read ({why}), so it is left as it is не вдалося прочитати словник користувача {_1} ({why}), тому його залишено без змін +@msg the cut cannot be made on this art: {e} на цій графіці не можна зробити розріз: {e} +@msg the data isn't an EMF or WMF picture дані не є малюнком EMF або WMF +@msg the data isn't an EPS or PostScript picture дані не є малюнком EPS або PostScript +@msg the deferred paste is no longer available відкладена вставка вже недоступна +@msg the design is too big to draw at every data point of this graph дизайн завеликий, щоб малювати його в кожній точці даних цієї діаграми +@msg the design is too big to draw in every column of this graph дизайн завеликий, щоб малювати його в кожному стовпці цієї діаграми +@msg the dialog it was opened over is no longer open діалогове вікно, поверх якого його відкрито, уже закрито +@msg the dictionary stack overflowed стек словників переповнено +@msg the document already has an SVG filter named {name} документ уже має фільтр SVG з іменем {name} +@msg the document has another SVG filter named {name}: use svgFilter.apply, or svgFilter.define with `replace` to edit it документ має інший фільтр SVG з іменем {name}: скористайтеся svgFilter.apply або svgFilter.define із `replace`, щоб змінити його +@msg the document has no SVG filter named {name} документ не має фільтра SVG з іменем {name} +@msg the document has no SVG filter named {r} документ не має фільтра SVG з іменем {r} +@msg the document has no color swatches документ не має зразків кольору +@msg the document's swatches hold {_1} colors; the document reduction takes at most 255 зразки документа містять кольорів: {_1}; скорочення кольорів document приймає не більше 255 +@msg the editing data's hash has no place для хешу даних редагування немає місця +@msg the entities the document declares expand to too much text сутності, які оголошує документ, розгортаються в завеликий текст +@msg the envelope's content has no bounds вміст оболонки не має меж +@msg the envelope's mesh is malformed сітка оболонки має неправильну структуру +@msg the file holds no `variableSets` element файл не містить елемента `variableSets` +@msg the file is larger than {_1} MB файл більший за {_1} МБ +@msg the file is too large файл завеликий +@msg the file isn't valid SVG: {e} файл не є припустимим SVG: {e} +@msg the file names no plate файл не вказує жодної форми +@msg the file was updated or encrypted already файл уже оновлено або зашифровано +@msg the first character of a line has no character before it to kern: it moves only up and down (dy) перед першим символом рядка немає символу для кернінгу: він зміщується лише вгору й униз (dy) +@msg the font {_1} is not available шрифт {_1} недоступний +@msg the format has no file extension формат не має розширення файлу +@msg the function's prototype is not an object прототип функції не є об’єктом +@msg the graphic can't be read: {e} не вдалося прочитати графіку: {e} +@msg the graphic is empty графіка порожня +@msg the graphic's data is damaged дані графіки пошкоджено +@msg the graphic's document has no artboard документ графіки не має монтажної області +@msg the guide is hidden or locked напрямну приховано або заблоковано +@msg the header `{cell}` for `{name}` would read back as the variable `{other}`: rename one of them заголовок `{cell}` для `{name}` під час читання дав би змінну `{other}`: перейменуйте одну з них +@msg the image `{path}` isn't followed: {r} перехід до зображення `{path}` не виконується: {r} +@msg the image has no embedded pixels зображення не має вбудованих пікселів +@msg the image is empty зображення порожнє +@msg the image is fully transparent зображення повністю прозоре +@msg the image is not on an artboard; pass rect зображення не розташоване на монтажній області; передайте rect +@msg the image's pixels are missing пікселі зображення відсутні +@msg the image's pixels aren't in the document пікселів зображення немає в документі +@msg the image's pixels can't be read: {e} не вдалося прочитати пікселі зображення: {e} +@msg the image's transparency doesn't fit it прозорість зображення не відповідає йому +@msg the job would print more than {MAX_PAGES} pages завдання надрукувало б понад {MAX_PAGES} сторінок +@msg the job would print more than {_1} pages завдання надрукувало б понад {_1} сторінок +@msg the layers hold no art to mask шари не містять графіки для маскування +@msg the layout moved макет змістився +@msg the library has a group `{name}` already бібліотека вже має групу `{name}` +@msg the library has no group `{name}` бібліотека не має групи `{name}` +@msg the library has no item `{item}` бібліотека не має елемента `{item}` +@msg the library has no item `{other}` бібліотека не має елемента `{other}` +@msg the library holds {MAX_GROUPS} groups already бібліотека вже містить груп: {MAX_GROUPS} +@msg the library holds {MAX_ITEMS} items of this kind already бібліотека вже містить елементів цього виду: {MAX_ITEMS} +@msg the library's file is outside the read roots файл бібліотеки розташований поза кореневими папками читання +@msg the method needs an XML value методу потрібне значення XML +@msg the name is empty ім’я порожнє +@msg the object has no fill, stroke or effect об’єкт не має заливки, обведення або ефекту +@msg the object has no graphic style (pass `name`) об’єкт не має графічного стилю (передайте `name`) +@msg the objects don't match the plan об’єкти не відповідають плану +@msg the open and permissions passwords must differ пароль для відкриття і пароль прав доступу мають відрізнятися +@msg the operand stack overflowed стек операндів переповнено +@msg the page has no area сторінка не має площі +@msg the page's type in an unread object's box isn't in its page art тексту сторінки в рамці непрочитаного об’єкта немає в графіці цієї сторінки +@msg the paint behind the proxy is not a gradient фарба за індикатором не є градієнтом +@msg the paint is not a freeform gradient (apply one with paint.editGradient {kind}) фарба не є довільним градієнтом (застосуйте його за допомогою paint.editGradient {kind}) +@msg the parameters or body do not form one function параметри або тіло не утворюють одну функцію +@msg the parent must be a layer or sublayer батьківським елементом має бути шар або підшар +@msg the pasted SVG filter {name} draws differently from the document's filter of that name, and no free name fits it вставлений фільтр SVG {name} малює інакше, ніж фільтр документа з таким іменем, а вільного імені для нього немає +@msg the path can't be extended контур не можна продовжити +@msg the path can't be inside one of the objects to attach контур не може бути всередині одного з об’єктів, які прикріплюються +@msg the path has no segments to measure контур не має сегментів для вимірювання +@msg the path is empty контур порожній +@msg the path is too short to shorten that much контур закороткий, щоб укоротити його настільки +@msg the pen table holds more than 255 pens таблиця пер містить понад 255 пер +@msg the picture has no objects малюнок не містить об’єктів +@msg the plates can't be kept форми не можна зберегти +@msg the position table does not match the instructions таблиця позицій не відповідає інструкціям +@msg the program runs too long програма виконується задовго +@msg the program uses too much memory програма використовує забагато пам’яті +@msg the prompt's text is longer than {MAX_PROMPT_BYTES} bytes текст запиту довший за {MAX_PROMPT_BYTES} байтів +@msg the radix must be between 2 and 36 основа системи числення має бути від 2 до 36 +@msg the rectangle must have a width and a height прямокутник повинен мати ширину й висоту +@msg the rectangle needs a size and must lie on the canvas прямокутнику потрібен розмір, і він має лежати на полотні +@msg the right side of 'in' is not an object права частина 'in' не є об’єктом +@msg the right side of 'instanceof' is not a function права частина 'instanceof' не є функцією +@msg the selected art has no width виділена графіка не має ширини +@msg the selected art is nested more than {MAX_DEPTH} levels deep виділена графіка має вкладеність понад {MAX_DEPTH} рівнів +@msg the selected art is too large to measure виділена графіка завелика для вимірювання +@msg the selection draws nothing виділення нічого не малює +@msg the selection has no area виділення не має площі +@msg the selection has no art to export виділення не містить графіки для експорту +@msg the selection has no bounds виділення не має меж +@msg the selection has no graphic style виділення не має графічного стилю +@msg the selection has no outlines to weed around виділення не має обрисів, навколо яких можна робити вибірку +@msg the slice would leave the canvas фрагмент вийшов би за межі полотна +@msg the spot colour couldn't be added не вдалося додати плашковий колір +@msg the subpath has no ends to extend (it is closed or a single point) вкладений контур не має кінців для продовження (він замкнений або є однією точкою) +@msg the symbols are nested too deeply to expand their instances символи мають завелику вкладеність, щоб розібрати їхні екземпляри +@msg the text file is too large to place as type (at most {_1} MB) текстовий файл завеликий, щоб помістити його як текст (не більше {_1} МБ) +@msg the text is empty текст порожній +@msg the text is over {_1} MB текст перевищує {_1} МБ +@msg the top object must be a path верхній об’єкт має бути контуром +@msg the trace was cancelled трасування скасовано +@msg the trailer has no size трейлер не має розміру +@msg the type object is flattened to nothing після зведення від текстового об’єкта нічого не залишається +@msg the value bind was called on is not a function значення, для якого викликано bind, не є функцією +@msg the value is not a constructor значення не є конструктором +@msg the value is not a function значення не є функцією +@msg the value is not a valid XML name значення не є припустимим іменем XML +@msg the value is not an XML attribute name значення не є іменем атрибута XML +@msg the value is not an XML name значення не є іменем XML +@msg the value of axis `{tag}` must be a number or null значення осі `{tag}` має бути числом або null +@msg the variable library declares more than {MAX_LIBRARY_DATASETS} data sets бібліотека змінних оголошує понад {MAX_LIBRARY_DATASETS} наборів даних +@msg the variable library declares more than {MAX_LIBRARY_ENTITIES} entities бібліотека змінних оголошує понад {MAX_LIBRARY_ENTITIES} сутностей +@msg the variable library declares more than {MAX_LIBRARY_VARIABLES} variables бібліотека змінних оголошує понад {MAX_LIBRARY_VARIABLES} змінних +@msg the variable library declares no variables бібліотека змінних не оголошує жодної змінної +@msg the variable library is larger than {MAX_LIBRARY_BYTES} bytes бібліотека змінних більша за {MAX_LIBRARY_BYTES} байтів +@msg the variable library is not UTF-8 бібліотека змінних не є UTF-8 +@msg the variable library is not well-formed XML: {e} бібліотека змінних не є правильно сформованим XML: {e} +@msg the variable library nests elements more than {MAX_LIBRARY_NESTING} deep бібліотека змінних має вкладеність елементів понад {MAX_LIBRARY_NESTING} рівнів +@msg the variable library's document type declaration holds something other than entities of plain text оголошення типу документа бібліотеки змінних містить щось інше, крім сутностей зі звичайним текстом +@msg the variable library's entities expand to more than {MAX_LIBRARY_BYTES} bytes сутності бібліотеки змінних розгортаються у понад {MAX_LIBRARY_BYTES} байтів +@msg the weeding lines cross the art's outlines too many times to measure; use fewer lines лінії вибірки перетинають обриси графіки забагато разів для вимірювання; використайте менше ліній +@msg the weeding lines pass too close to too many outline segments to measure; use fewer lines or a smaller gap лінії вибірки проходять заблизько до завеликої кількості сегментів обрисів для вимірювання; використайте менше ліній або менший проміжок +@msg the weeding lines would be more than {max_pieces} pieces ліній вибірки вийшло б понад {max_pieces} частин +@msg the window has no dock вікно не має області закріплення +@msg the written PDF has no catalog записаний PDF не має каталогу +@msg the written PDF has no cross-reference table записаний PDF не має таблиці перехресних посилань +@msg the written PDF's metadata can't be edited метадані записаного PDF не можна змінити +@msg the {_1} plate lies outside the file форма {_1} лежить поза файлом +@msg there are no colour swatches to draw немає зразків кольору для малювання +@msg there is already a design named `{name}` дизайн з назвою `{name}` уже існує +@msg there is already a design named `{to}` дизайн з назвою `{to}` уже існує +@msg there is already a toolbar named `{name}` панель інструментів з іменем `{name}` уже існує +@msg there is already a toolbar named `{to}` панель інструментів з іменем `{to}` уже існує +@msg there is no library: create one first бібліотеки немає: спочатку створіть її +@msg these paths are too degenerate for Shaper ці контури занадто вироджені для формоутворення +@msg this is a binary DXF file, which can't be read: save it from the CAD app as an ASCII DXF and open that це двійковий файл DXF, який не можна прочитати: збережіть його з програми САПР як ASCII DXF і відкрийте отриманий файл +@msg this warp's points can't be edited: use Reset with Mesh first точки цієї деформації не можна редагувати: спочатку скористайтеся командою «Скинути із сіткою» +@msg thumbnail: no page {v} (the {what} has {count}) thumbnail: немає сторінки {v} ({what} має сторінок: {count}) +@msg tileRange of {what}: {e} tileRange для {what}: {e} +@msg title can't be empty title не може бути порожнім +@msg to (the new name) is required to (нове ім’я) є обов’язковим +@msg to must be fill or stroke to має бути fill або stroke +@msg to must be smooth or corner to має бути smooth або corner +@msg toExponential() digits must be between 0 and 20 кількість цифр для toExponential() має бути від 0 до 20 +@msg toFixed() digits must be between 0 and 20 кількість цифр для toFixed() має бути від 0 до 20 +@msg toISOString is not a function toISOString не є функцією +@msg toPrecision() argument must be between 1 and 21 аргумент toPrecision() має бути від 1 до 21 +@msg toSource: a getter cannot be written as source toSource: гетер не можна записати як вихідний код +@msg toSource: an array with properties besides its elements, a property that is not enumerable or another prototype cannot be written as source toSource: масив із властивостями, крім його елементів, з неперелічуваною властивістю або з іншим прототипом не можна записати як вихідний код +@msg toSource: an object with a property that is not enumerable, or whose prototype is not Object.prototype, cannot be written as source toSource: об’єкт із неперелічуваною властивістю або з прототипом, відмінним від Object.prototype, не можна записати як вихідний код +@msg toSource: the source is too long toSource: вихідний код задовгий +@msg toSource: the value contains itself toSource: значення містить саме себе +@msg toSource: the value has too many entries toSource: значення містить забагато записів +@msg toSource: the value is nested too deep toSource: значення має завелику вкладеність +@msg toString is not a function toString не є функцією +@msg too large for a zip archive: package to a folder завелике для архіву zip: упакуйте в папку +@msg too many Shaper edits забагато правок формоутворення +@msg too many `points` (at most 100000) забагато `points` (не більше 100000) +@msg too many arguments забагато аргументів +@msg too many characters: at most {MAX_CHARS} забагато символів: не більше {MAX_CHARS} +@msg too many dots for this size: lower the frequency забагато точок для цього розміру: зменште частоту +@msg too many filters over one file забагато фільтрів для одного файлу +@msg too many overlapping paths for Shaper забагато контурів, що перекриваються, для формоутворення +@msg too many quantifiers забагато квантифікаторів +@msg too many saved clips забагато збережених відсікань +@msg too many saved graphics states забагато збережених графічних станів +@msg toolbar (a toolbar's name) must be a string toolbar (ім’я панелі інструментів) має бути рядком +@msg toolbar name can't be empty ім’я панелі інструментів не може бути порожнім +@msg transparentImages {v}: "flatten" (the default) or "omit" transparentImages {v}: "flatten" (за замовчуванням) або "omit" +@msg two saved selections would be named `{_1}` два збережені виділення отримали б ім’я `{_1}` +@msg type dimension cannot be represented with this text transform розмір тексту не можна передати з цією трансформацією тексту +@msg type dimension must be finite розмір тексту має бути скінченним +@msg unexpected resources неочікувані ресурси +@msg unknown CMYK profile `{name}` невідомий профіль CMYK `{name}` +@msg unknown File Info field `{k}` невідоме поле відомостей про файл `{k}` +@msg unknown OpenType feature `{t}` (liga, calt, dlig, smcp, frac, onum, tnum, ordn, swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom, aalt; prefix - to turn off; swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom and aalt take an alternate's number as `tag=N` with N from 0 to {_1}, as `salt=2`) невідома функція OpenType `{t}` (liga, calt, dlig, smcp, frac, onum, tnum, ordn, swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom, aalt; префікс - вимикає функцію; swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom і aalt приймають номер альтернативи у вигляді `tag=N`, де N від 0 до {_1}, наприклад `salt=2`) +@msg unknown OpenType feature `{t}` in featureChanges (the tags `features` takes) невідома функція OpenType `{t}` у featureChanges (допустимі теги, які приймає `features`) +@msg unknown PDF preset `{name}` (presets: {_1}) невідомий набір PDF `{name}` (набори: {_1}) +@msg unknown Warp style невідомий стиль деформації +@msg unknown alignToPath `{a}` невідомий alignToPath `{a}` +@msg unknown arrowhead {v} невідома стрілка {v} +@msg unknown artboardLayout key `{k}` (layout, columns, spacing, rightToLeft) невідомий ключ artboardLayout `{k}` (layout, columns, spacing, rightToLeft) +@msg unknown attribute `{attribute}` невідомий атрибут `{attribute}` +@msg unknown attribute `{k}` невідомий атрибут `{k}` +@msg unknown axis `{other}` (vertical|horizontal|free) невідома вісь `{other}` (vertical|horizontal|free) +@msg unknown blend mode `{b}` невідомий режим накладання `{b}` +@msg unknown blend mode {b} невідомий режим накладання {b} +@msg unknown brush type `{o}` невідомий тип пензля `{o}` +@msg unknown category `{c}` невідома категорія `{c}` +@msg unknown category `{c}` ({_1}) невідома категорія `{c}` ({_1}) +@msg unknown character `{c}` невідомий символ `{c}` +@msg unknown character style number field невідоме числове поле стилю символу +@msg unknown dither `{d}` (diffusion, pattern, noise or none) невідомий dither `{d}` (diffusion, pattern, noise або none) +@msg unknown effect `{e}` невідомий ефект `{e}` +@msg unknown end {e} невідомий кінець {e} +@msg unknown flattenerPreset `{name}` (High Resolution, Medium Resolution, Low Resolution or a saved one: see flattener.presets.list) невідомий flattenerPreset `{name}` (High Resolution, Medium Resolution, Low Resolution або збережений набір: див. flattener.presets.list) +@msg unknown format `{f}` (vcswatches, gpl, ase or css) невідомий формат `{f}` (vcswatches, gpl, ase або css) +@msg unknown from {f} невідомий from {f} +@msg unknown graph type `{t}` невідомий тип діаграми `{t}` +@msg unknown grid colours `{name}` (one of {_1}) невідомі кольори сітки `{name}` (одне з: {_1}) +@msg unknown gridType `{t}` невідомий gridType `{t}` +@msg unknown highlight `{v}` невідомий highlight `{v}` +@msg unknown intent `{i}` невідомий intent `{i}` +@msg unknown issue kind {id} невідомий вид проблеми {id} +@msg unknown issue kind {v} невідомий вид проблеми {v} +@msg unknown knockout state {k} невідомий стан вирізування {k} +@msg unknown language `{language}` (one of {_1}) невідома мова `{language}` (одна з: {_1}) +@msg unknown language `{l}` (one of {_1}) невідома мова `{l}` (одна з: {_1}) +@msg unknown method `{m}` ({_1}) невідомий метод `{m}` ({_1}) +@msg unknown mode `{other}` (gray, rgb, hsb, lab, cmyk or web) невідомий режим `{other}` (gray, rgb, hsb, lab, cmyk або web) +@msg unknown mode `{other}` (mono|cmyk) невідомий режим `{other}` (mono|cmyk) +@msg unknown mode `{other}` (rgb|cmyk|gray|global) невідомий режим `{other}` (rgb|cmyk|gray|global) +@msg unknown mode `{other}` (set, add, subtract) невідомий режим `{other}` (set, add, subtract) +@msg unknown mode `{o}` невідомий режим `{o}` +@msg unknown mode {m} невідомий режим {m} +@msg unknown model `{other}` невідома модель `{other}` +@msg unknown model `{other}` (keep, new or document) невідома модель `{other}` (keep, new або document) +@msg unknown op {o} невідомий op {o} +@msg unknown order `{o}`: toggle, front, forward, backward or back невідомий order `{o}`: toggle, front, forward, backward або back +@msg unknown overprints `{v}` (preserve, simulate or discard) невідомий overprints `{v}` (preserve, simulate або discard) +@msg unknown panel невідома панель +@msg unknown panel `{panel}` невідома панель `{panel}` +@msg unknown parameter `{key}` невідомий параметр `{key}` +@msg unknown parameter `{within}settings.{format}`; {why} невідомий параметр `{within}settings.{format}`; {why} +@msg unknown parameter `{within}{key}`; {why} невідомий параметр `{within}{key}`; {why} +@msg unknown pieLegend `{v}` (none, standard or wedges) невідомий pieLegend `{v}` (none, standard або wedges) +@msg unknown piePosition `{v}` (even, ratio or stacked) невідомий piePosition `{v}` (even, ratio або stacked) +@msg unknown pieSort `{v}` (none, all or first) невідомий pieSort `{v}` (none, all або first) +@msg unknown plate `{n}` невідома форма `{n}` +@msg unknown preference `{k}` невідоме налаштування `{k}` +@msg unknown profile {id} (see stroke.widthProfile.list) невідомий профіль {id} (див. stroke.widthProfile.list) +@msg unknown proof target `{t}` невідома ціль проби `{t}` +@msg unknown quotes key `{k}` (double, single) невідомий ключ quotes `{k}` (double, single) +@msg unknown reduction `{reduction}` (selective, perceptual, adaptive, web, gray, blackWhite, uniform or document) невідоме скорочення кольорів `{reduction}` (selective, perceptual, adaptive, web, gray, blackWhite, uniform або document) +@msg unknown resolution `{v}` невідома роздільна здатність `{v}` +@msg unknown rule `{rule}` ({_1}) невідоме правило `{rule}` ({_1}) +@msg unknown rule `{r}` (see color.harmony) невідоме правило `{r}` (див. color.harmony) +@msg unknown setting `{k}` невідомий параметр `{k}` +@msg unknown shape `{v}` (circle|ellipse|square|diamond|line) невідома фігура `{v}` (circle|ellipse|square|diamond|line) +@msg unknown spacing `{o}` (smooth|steps|distance) невідомий spacing `{o}` (smooth|steps|distance) +@msg unknown tileType `{t}` ({_1}) невідомий tileType `{t}` ({_1}) +@msg unknown units невідомі одиниці +@msg unknown units `{u}` невідомі одиниці `{u}` +@msg unknown value axis `{v}` (left, right or both) невідома вісь значень `{v}` (left, right або both) +@msg unknown variation `{v}` (tintsShades|warmCool|vividMuted) невідома варіація `{v}` (tintsShades|warmCool|vividMuted) +@msg unknown warp style `{s}` невідомий стиль деформації `{s}` +@msg unknown {key} `{v}` (none, short or full) невідомий {key} `{v}` (none, short або full) +@msg unknown {key} profile `{n}` невідомий профіль {key} `{n}` +@msg unknown {k} key `{key}` (size, position) невідомий ключ {k} `{key}` (size, position) +@msg unmatched ')' непарна дужка ')' +@msg unreadable object об’єкт не вдалося прочитати +@msg unsafe destination file name небезпечне ім’я файлу призначення +@msg unterminated character class незавершений клас символів +@msg unterminated group незавершена група +@msg use paths or compound paths використовуйте контури або складені контури +@msg useArtboards must be true or false, not {v} useArtboards має бути true або false, а не {v} +@msg value for `{var}` must match its variable kind значення `{var}` має відповідати типу її змінної +@msg variable `{_1}` is already defined змінну `{_1}` уже визначено +@msg variable `{name}` has no `trait` змінна `{name}` не має `trait` +@msg variable `{name}` is already defined змінну `{name}` уже визначено +@msg variable `{name}` is declared twice змінну `{name}` оголошено двічі +@msg variable `{to}` already exists змінна `{to}` уже існує +@msg view is required view є обов’язковим +@msg view must be one of {_1} view має бути одним з: {_1} +@msg warpStyle can only edit an applied Warp effect warpStyle може змінювати лише застосований ефект деформації +@msg width and height must be more than 0 and at most {limit} width і height мають бути більше 0 і не більше {limit} +@msg width factors must be finite коефіцієнти ширини мають бути скінченними +@msg width must be positive width має бути додатним +@msg width out of range ширина поза межами діапазону +@msg width/height must be > 0 width/height мають бути > 0 +@msg wordGap and lineGap need area type in the selection для wordGap і lineGap у виділенні потрібен текст в області +@msg x and y must be finite numbers x і y мають бути скінченними числами +@msg x and y must be given together x і y треба вказувати разом +@msg xpath needs its variables as an object для xpath змінні мають бути об’єктом +@msg xpath needs the expression as a string для xpath вираз має бути рядком +@msg zone needs an anchor: dock beside a panel with anchor, or in a new dock column with side (Start or End) для zone потрібен anchor: закріпіть поруч із панеллю за допомогою anchor або в новому стовпці закріплення за допомогою side (Start або End) +@msg zoom must be positive zoom має бути додатним +@msg {C}: no effect at index {list} {C}: немає ефекту з індексом {list} +@msg {DEFAULT_PRESET} is protected and stays {DEFAULT_PRESET} захищено, він залишається +@msg {DEFAULT_PRESET} is protected: save the settings under another name {DEFAULT_PRESET} захищено: збережіть параметри під іншим іменем +@msg {GRANT_NOT_REMOVED}, and its settings and cache can't be moved back from {_1} to {_2}: {e} {GRANT_NOT_REMOVED}, а його параметри й кеш не вдалося перемістити назад із {_1} до {_2}: {e} +@msg {LABEL} produced an empty result {LABEL}: отримано порожній результат +@msg {_1} MB of document, at most {_2} MB обсяг документа {_1} МБ, дозволено не більше {_2} МБ +@msg {_1} MB of images, at most {_2} MB обсяг зображень {_1} МБ, дозволено не більше {_2} МБ +@msg {_1} bytes of RGBA data for a {width} × {height} image {_1} байтів даних RGBA для зображення {width} × {height} +@msg {_1} can't be read, or changed since it was read: relink or update it first {_1} не вдалося прочитати або його змінено після читання: спочатку зв’яжіть його повторно чи оновіть +@msg {_1} can't go into {into} {_1} не можна помістити в {into} +@msg {_1} can't limit printing to low resolution: choose PDF 1.4 or later, or allow high-resolution printing {_1} не може обмежити друк низькою роздільною здатністю: виберіть PDF 1.4 або новіший чи дозвольте друк із високою роздільною здатністю +@msg {_1} files can't be opened yet файли {_1} поки не можна відкривати +@msg {_1} files can't be password-protected: remove the passwords or choose no standard файли {_1} не можна захищати паролем: приберіть паролі або не вибирайте стандарт +@msg {_1} files can't be {_2} файли {_1} не можуть бути файлами {_2} +@msg {_1} files can't carry editing data: turn off preserveEditing файли {_1} не можуть містити дані редагування: вимкніть preserveEditing +@msg {_1} files can't have PDF layers: turn off createLayers файли {_1} не можуть мати шари PDF: вимкніть createLayers +@msg {_1} files need a creation date, and this platform has no clock to give one файлам {_1} потрібна дата створення, а ця платформа не має годинника, щоб її надати +@msg {_1} is not a folder: {e} {_1} не є папкою: {e} +@msg {_1} isn't a path {_1} не є контуром +@msg {_1} options: {e} параметри {_1}: {e} +@msg {_1} paints nothing to rasterize {_1} не малює нічого, що можна растеризувати +@msg {_1} passwords can have up to {MAX_LEGACY_PASSWORD} ASCII characters (PDF 1.7 and later take any) паролі {_1} можуть містити до {MAX_LEGACY_PASSWORD} символів ASCII (PDF 1.7 і новіші приймають будь-які символи) +@msg {_1} with linked images or an image map writes several files: use document.export {_1} з пов’язаними зображеннями або картою зображення записує кілька файлів: скористайтеся document.export +@msg {_1} writes one file per artboard here: use document.export, or name one artboard {_1} записує тут по одному файлу на монтажну область: скористайтеся document.export або вкажіть одну монтажну область +@msg {_1} × {_2} pixels is too large for {_3} (at most {max} pixels a side): lower the scale {_1} × {_2} пікселів — це забагато для {_3} (не більше {max} пікселів по кожній стороні): зменште масштаб +@msg {_1}: belongs to another account {_1}: належить іншому обліковому запису +@msg {_1}: not a folder of its own {_1}: не є власною папкою +@msg {_1}: not a plain file {_1}: не є звичайним файлом +@msg {_1}: {_2} and {_3} are in the way {_1}: заважають {_2} і {_3} +@msg {code}: {0} {code}: {0} +@msg {dest}: {e} {dest}: {e} +@msg {dir}: {e} {dir}: {e} +@msg {doc} has no folder {doc} не має папки +@msg {file} isn't linked {file} не пов’язано +@msg {file} names more than one linked JavaScript file {file} указує більше одного пов’язаного файлу JavaScript +@msg {folder} is not a package folder {folder} не є папкою пакета +@msg {folder}: more than {max} files and folders {folder}: понад {max} файлів і папок +@msg {folder}: {e} {folder}: {e} +@msg {g} is not a Live Paint group {g} не є групою швидкої заливки +@msg {id} is not a slice {id} не є фрагментом +@msg {key} must be 0–{MAX_ADD_AROUND} pt {key} має бути 0–{MAX_ADD_AROUND} pt +@msg {key} must be [x,y] {key} має бути [x,y] +@msg {key} must be a percentage {min}..100 {key} має бути відсотком {min}..100 +@msg {key} must be a positive number, not {n} {key} має бути додатним числом, а не {n} +@msg {key} must be a positive number, not {v} {key} має бути додатним числом, а не {v} +@msg {key} must be one of {_1} {key} має бути одним з: {_1} +@msg {key} must be {_1}, got {s} {key} має бути {_1}, отримано {s} +@msg {key} must name a floating panel {key} має вказувати плаваючу панель +@msg {key} must name a panel in another group {key} має вказувати панель в іншій групі +@msg {key} must name a panel that shows {key} має вказувати панель, яку показано +@msg {key} must name a registered panel {key} має вказувати зареєстровану панель +@msg {kind} files have no transparency, and the file would have {what}: flatten it first (object.flattenTransparency) файли {kind} не мають прозорості, а файл містив би таке: {what}; спочатку зведіть прозорість (object.flattenTransparency) +@msg {kind} images can't be opened (see document.formats) зображення {kind} не можна відкрити (див. document.formats) +@msg {k} `{v}` is not one of the choices {k} `{v}` не є одним із варіантів +@msg {k} has control characters{_1} {k} містить керівні символи{_1} +@msg {k} is too long (at most {MAX_TEXT} characters) {k} задовгий (не більше {MAX_TEXT} символів) +@msg {k} must be > 0 {k} має бути > 0 +@msg {k} must be a number (pt) or a length such as "210 mm" {k} має бути числом (pt) або довжиною на зразок "210 mm" +@msg {k} must be a number from {min} to {max} {k} має бути числом від {min} до {max} +@msg {k} must be a number or "auto" {k} має бути числом або "auto" +@msg {k} must be a string {k} має бути рядком +@msg {k} must be text {k} має бути текстом +@msg {k} must be true or false {k} має бути true або false +@msg {k} must be {{size?, position?}} {k} має бути {{size?, position?}} +@msg {k}: a custom arrowhead's path needs an area to fill and at most {most} anchors and {most} subpaths, each anchor within {far} head units of its tip {k}: контуру користувацької стрілки потрібна площа для заливки і не більше {most} опорних точок та {most} вкладених контурів, причому кожна опорна точка має бути не далі ніж {far} одиниць наконечника від його вістря +@msg {k}: bad custom arrowhead path: {e} {k}: неправильний контур користувацької стрілки: {e} +@msg {k}: bad custom arrowhead: {e} {k}: неправильна користувацька стрілка: {e} +@msg {k}: can't read `{s}` as a length {k}: не вдалося прочитати `{s}` як довжину +@msg {k}: custom must be a name {k}: custom має бути іменем +@msg {label} must be a number at most {max} {label} має бути числом не більше {max} +@msg {label} must be a number from -1296 to 1296 {label} має бути числом від -1296 до 1296 +@msg {label} must be a number from 1 to 10000 {label} має бути числом від 1 до 10000 +@msg {name} `{s}`: {ids} {name} `{s}`: {ids} +@msg {name} is built in and can't be deleted {name} є вбудованим, його не можна видалити +@msg {name} must be {lo}–{hi}{unit} (got {v}) {name} має бути {lo}–{hi}{unit} (отримано {v}) +@msg {name}: CRC or size mismatch {name}: невідповідність CRC або розміру +@msg {name}: only this Affinity file's embedded preview could be read; use File › Open to see it with its warning, or export SVG or PDF from Affinity before placing {name}: вдалося прочитати лише вбудований попередній перегляд цього файлу Affinity; скористайтеся командою Файл › Відкрити, щоб побачити його з попередженням, або перед розміщенням експортуйте SVG чи PDF з Affinity +@msg {name}: {e} {name}: {e} +@msg {native}; its embedded preview can't be read either ({e}) {native}; його вбудований попередній перегляд теж не вдалося прочитати ({e}) +@msg {path}: copy takes a DCS file only when its plates are inside it; relink to it where its plate files are {path}: copy приймає файл DCS, лише коли його форми містяться в ньому самому; зв’яжіть його повторно там, де розташовані файли його форм +@msg {path}: larger than {_1} MB {path}: більший за {_1} МБ +@msg {shown} is not an XPath 1.0 function {shown} не є функцією XPath 1.0 +@msg {std} files are CMYK, and the file would have colours in {_1} файли {std} мають модель CMYK, а файл містив би кольори в {_1} +@msg {std} files embed their fonts, and the file would have one that isn't файли {std} вбудовують свої шрифти, а файл містив би невбудований шрифт +@msg {target} is the file this document was read from, and reading it left things out ({what}): writing over it would lose them for good. Write another file instead, or pass acknowledgeLoss: true to replace it anyway {target} — це файл, з якого прочитано цей документ, і під час читання дещо було пропущено ({what}): запис поверх нього призвів би до остаточної втрати пропущеного. Запишіть інший файл або передайте acknowledgeLoss: true, щоб усе одно замінити його +@msg {ty} brushes need selected art (or params.{k}) пензлям типу {ty} потрібна виділена графіка (або params.{k}) +@msg {v} is not an asset id {v} не є ідентифікатором ресурсу +@msg {v} names no layer or sublayer {v} не вказує жодного шару або підшару +@msg {what} can't be intertwined {what}: переплетення неможливе +@msg {what} doesn't fit the paper with its bleed and marks {what}: не вміщується на папері разом із вильотом і мітками +@msg {what} is not a function {what} не є функцією +@msg {what} would print more than {MAX_COPIES_PER_SHEET} copies on a sheet: scale it up {what}: на аркуші було б надруковано понад {MAX_COPIES_PER_SHEET} копій: збільште масштаб +@msg {what} would print on more than {MAX_TILES} tiles: scale it down {what}: друк зайняв би понад {MAX_TILES} плиток: зменште масштаб +@msg {what} {i} out of range {what} {i} поза межами діапазону +@msg Alignment must be one of the choices Вирівнювання має бути одним із варіантів +@msg Line Gap must be a number Проміжок між рядками має бути числом +@msg `at` must be a point [x, y] `at` має бути точкою [x, y] +@msg `points` must hold from 2 to 100000 points `points` має містити від 2 до 100000 точок +@msg `rect` must be [x, y, width, height] `rect` має бути [x, y, width, height] +@msg `tolerance` must be from 0 to 100 pt `tolerance` має бути від 0 до 100 pt +@msg `warichuAlign` must be one of {_1} `warichuAlign` має бути одним з: {_1} +@msg `warichuLines` must be a whole number from {_1} to {_2} `warichuLines` має бути цілим числом від {_1} до {_2} +@msg bad point {v}: expected [x, y] неправильна точка {v}: очікується [x, y] +@msg give exactly one of `at`, `rect` and `points` укажіть рівно одне з: `at`, `rect`, `points` +@msg the line is too long, or the paths it passes too many, to check лінія задовга або проходить через забагато контурів, щоб її можна було перевірити +@msg the paths are too many or too tangled to find where they cross контурів забагато або вони занадто заплутані, щоб знайти місця їх перетину +@msg the rectangle or line reaches too many paths to check прямокутник або лінія охоплює забагато контурів для перевірки +@msg {name} must be a number {name} має бути числом +@msg `{key}` must be from 0.01 to 1000 pt `{key}` має бути від 0.01 до 1000 pt +@msg select the banner, or mark every artboard виділіть банер або розмітьте всі монтажні області +@msg the banner has no width or height банер не має ширини або висоти +@msg the grommet inset is too large for the banner відступ люверсів від краю завеликий для банера +@msg the hem is too deep for the banner підгин заглибокий для банера +@msg the spacing makes more than {MAX_GROMMETS} grommets за такого інтервалу виходить понад {MAX_GROMMETS} люверсів +@msg there is no banner to mark немає банера для розмітки +@msg turn on at least one side увімкніть принаймні одну сторону +@msg with no hem and no grommets there is nothing to mark без підгину й люверсів немає чого розмічати +@msg {saving} failed: {e} {saving}: не вдалося: {e} diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 8ab185e5f9..d9d9110276 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -7331,3 +7331,1817 @@ breakText Glyphs 字形 Grommets 扣眼 Grommet Inset 扣眼边距 Diameter 直径 +# Status and error messages of commands, scripts, file import and export, and plug-ins. +@msg 'caller', 'callee' and 'arguments' cannot be used on strict mode functions 严格模式的函数不能使用 'caller'、'callee' 和 'arguments' +@msg Alignment must be one of the choices 对齐方式必须是给出的选项之一 +@msg Boolean.prototype.{name} was called on a value that is not a Boolean Boolean.prototype.{name} 的调用对象不是 Boolean 值 +@msg CMYK images whose samples couldn't be read in CMYK were imported in RGB 采样无法按 CMYK 读取的 CMYK 图像已按 RGB 导入 +@msg Cannot write to the location of “{name}”; choose where to save it 无法写入“{name}”所在的位置;请选择保存位置 +@msg DCS files can only be placed linked: use File › Place with Link on DCS 文件只能以链接方式置入:请使用 文件 › 置入 并勾选“链接” +@msg Date.prototype method called on a value that is not a Date object Date.prototype 方法的调用对象不是 Date 对象 +@msg Error.prototype.toString was called on a value that is not an object Error.prototype.toString 的调用对象不是对象 +@msg Function.prototype.toString was called on a value that is not a function Function.prototype.toString 的调用对象不是函数 +@msg Import SVG Filter reads SVG files, not SVGZ 导入 SVG 滤镜读取的是 SVG 文件,不是 SVGZ +@msg JSON.parse: {why} (at offset {at}) JSON.parse:{why} (位于偏移 {at}) +@msg JSON.stringify cannot write a structure that contains itself JSON.stringify 无法写出包含自身的结构 +@msg Line Gap must be a number 行间距必须是数字 +@msg Namespace.prototype.toString needs a Namespace Namespace.prototype.toString 需要一个 Namespace +@msg New Document profiles need the preferences folder, which this run doesn't have 新建文档配置文件需要首选项文件夹,而本次运行没有该文件夹 +@msg Number.prototype.{name} was called on a value that is not a number Number.prototype.{name} 的调用对象不是数字 +@msg Object.create's prototype must be an object or null Object.create 的原型必须是对象或 null +@msg Object.{function} was given a value that is not an object 传给 Object.{function} 的值不是对象 +@msg QName.prototype.toString needs a QName QName.prototype.toString 需要一个 QName +@msg RegExp.prototype.{name} was called on a value that is not a RegExp object RegExp.prototype.{name} 的调用对象不是 RegExp 对象 +@msg Stencil Bridges: the selected art is too large or too detailed to bridge 镂空版连接桥:所选图稿过大或过于复杂,无法添加连接桥 +@msg String.prototype.toString was called on a value that is not a string String.prototype.toString 的调用对象不是字符串 +@msg The {name} profile could not be read, so the new document has the default settings: {reason} 无法读取配置文件 {name},因此新文档使用默认设置:{reason} +@msg Trap: more than {_1} pairs of objects lie close enough to trap, or too many objects share a horizontal range; trap fewer objects at a time 陷印:距离近到需要陷印的对象超过 {_1} 对,或处于同一水平范围的对象过多;请减少每次陷印的对象 +@msg Weed Box and Lines: no weeding line fits outside the art, and the weed box is off 除废框和除废线:图稿外侧放不下任何除废线,且除废框已关闭 +@msg \ at end of pattern 模式以 \ 结尾 +@msg `alignOn` cannot be empty `alignOn` 不能为空 +@msg `alignOn` must be a string `alignOn` 必须是字符串 +@msg `align` must be a string `align` 必须是字符串 +@msg `answer` for this {kind} dialog must be one of: {_1} 此 {kind} 对话框的 `answer` 必须是以下之一:{_1} +@msg `answers` has more than {MAX_ANSWERS} answers `answers` 中的回答超过 {MAX_ANSWERS} 个 +@msg `answers` is larger than 1 MiB `answers` 大于 1 MiB +@msg `answers` must be a list of answers `answers` 必须是回答的列表 +@msg `artboard` must be the index of an artboard of the document `artboard` 必须是文档中某个画板的索引 +@msg `artboardsAt` must be [x, y] `artboardsAt` 必须是 [x, y] +@msg `artboards` names an artboard the document does not have `artboards` 指定了文档中没有的画板 +@msg `artboards` names an artboard twice `artboards` 重复指定了同一个画板 +@msg `at` must be [x, y] (got {at}) `at` 必须是 [x, y] (实际为 {at}) +@msg `at` must be a point [x, y] `at` 必须是点 [x, y] +@msg `beside` needs `side` `beside` 需要 `side` +@msg `code` must be a whole number `code` 必须是整数 +@msg `colorMode` must be one of rgb, cmyk `colorMode` 必须是 rgb、cmyk 之一 +@msg `colors` does not apply to the {name} reduction `colors` 不适用于 {name} 减色方式 +@msg `colors` must be a whole number from 2 to 256 `colors` 必须是 2 到 256 之间的整数 +@msg `colors` must be at least 9 for the uniform reduction 使用 uniform 减色方式时,`colors` 至少为 9 +@msg `colors` must be between 1 and {MAX_THEME_COLORS} (got {n}) `colors` 必须介于 1 到 {MAX_THEME_COLORS} 之间 (实际为 {n}) +@msg `count` must be a whole number from 0 to {MAX_COUNT} `count` 必须是 0 到 {MAX_COUNT} 之间的整数 +@msg `ditherAmount` must be a number from 0 to 100 `ditherAmount` 必须是 0 到 100 之间的数字 +@msg `fidelity` must be from {lo} to {hi} pt `fidelity` 必须介于 {lo} 到 {hi} pt 之间 +@msg `focal` and `radius` cannot be used together `focal` 和 `radius` 不能同时使用 +@msg `focal` must be an array of [subpath, anchor] pairs `focal` 必须是 [subpath, anchor] 对的数组 +@msg `focal` names [{si}, {ai}], which is not an anchor of the path `focal` 指定了 [{si}, {ai}],它不是该路径的锚点 +@msg `glyphAlternate` takes only null, which takes a glyph choice away (text.setGlyphAlternate makes one) `glyphAlternate` 只接受 null,用于取消字形选择 (text.setGlyphAlternate 用于设置选择) +@msg `group` must be one of {_1} `group` 必须是 {_1} 之一 +@msg `group` must be the Objects on Path group of `member` and `target` `group` 必须是 `member` 和 `target` 所在的“路径上的对象”组 +@msg `id` is an object id, not {v} `id` 是对象 ID,不是 {v} +@msg `item` needs `index` `item` 需要 `index` +@msg `kerningBefore` belongs to a line's first character, not to a character style (text.setRangeStyle sets it) `kerningBefore` 属于行首字符,不属于字符样式 (由 text.setRangeStyle 设置) +@msg `kinsokuType` must be "pushInFirst", "pushOutFirst" or "pushOutOnly" `kinsokuType` 必须是 "pushInFirst"、"pushOutFirst" 或 "pushOutOnly" +@msg `leader` must be a string `leader` 必须是字符串 +@msg `max` must be 1 to {MAX_SUGGESTIONS} `max` 必须为 1 到 {MAX_SUGGESTIONS} +@msg `name` must be a name that is not empty `name` 必须是非空的名称 +@msg `name` must not be empty `name` 不能为空 +@msg `origin` must be [x, y] in points `origin` 必须是以点为单位的 [x, y] +@msg `picks` must be an array (got {v}) `picks` 必须是数组 (实际为 {v}) +@msg `picks` must hold 1 to {MAX_PICKS} picks (got {_1}) `picks` 必须包含 1 到 {MAX_PICKS} 个拾取项 (实际为 {_1}) +@msg `points` must hold from 2 to 100000 points `points` 必须包含 2 到 100000 个点 +@msg `radius` must be 0 or more `radius` 必须大于或等于 0 +@msg `rect` must be [x, y, width, height] `rect` 必须是 [x, y, width, height] +@msg `rect` must be [x0, y0, x1, y1] (got {r}) `rect` 必须是 [x0, y0, x1, y1] (实际为 {r}) +@msg `replace` must be a string `replace` 必须是字符串 +@msg `rows` must be lists of numbers or nulls, not {r} `rows` 必须是由数字或 null 组成的列表,不能是 {r} +@msg `scale` must be a number from 0.001 to 1000 `scale` 必须是 0.001 到 1000 之间的数字 +@msg `scope.{key}` must be a non-empty array `scope.{key}` 必须是非空数组 +@msg `scope` must be "document", {artboards} or {layers} `scope` 必须是 "document"、{artboards} 或 {layers} +@msg `side` must be "left", "right", "top" or "bottom" `side` 必须是 "left"、"right"、"top" 或 "bottom" +@msg `side` places the artboard: leave out x, y, width and height `side` 决定画板的位置:请不要给出 x、y、width 和 height +@msg `source` is the only path in series group `target` `source` 是系列组 `target` 中唯一的路径 +@msg `spacing` makes more than {MAX_COUNT} lines across the box `spacing` 会在框内生成超过 {MAX_COUNT} 条线 +@msg `spacing` must be more than 0 and at most {MAX_DISTANCE} pt `spacing` 必须大于 0 且不超过 {MAX_DISTANCE} pt +@msg `target` must be an object of the same Objects on Path group as `member` `target` 必须是与 `member` 同属一个“路径上的对象”组的对象 +@msg `tolerance` must be from 0 to 100 pt `tolerance` 必须为 0 到 100 pt +@msg `version` must be 0 or {_1} `version` 必须是 0 或 {_1} +@msg `version` must be 0 or {newest} `version` 必须是 0 或 {newest} +@msg `warichuAlign` must be one of {_1} `warichuAlign` 必须是 {_1} 之一 +@msg `warichuLines` must be a whole number from {_1} to {_2} `warichuLines` 必须是 {_1} 到 {_2} 之间的整数 +@msg `weight` must be from 0.01 to 1000 pt `weight` 必须为 0.01 到 1000 pt +@msg `weights` must be a list of {_1} numbers, one per row (got {v}) `weights` 必须是 {_1} 个数字的列表,每行一个 (实际为 {v}) +@msg `xml` must be a string `xml` 必须是字符串 +@msg `{KEY}` entry {n} gives the paragraph at byte {start} of {_1} other indents than an entry before it `{KEY}` 的第 {n} 项为 {_1} 中字节 {start} 处的段落指定的缩进与前面某一项不同 +@msg `{KEY}` entry {n} must be an object `{KEY}` 的第 {n} 项必须是对象 +@msg `{KEY}` entry {n} sets neither `leftIndent` nor `firstLineIndent` `{KEY}` 的第 {n} 项既未设置 `leftIndent`,也未设置 `firstLineIndent` +@msg `{KEY}` entry {n}: `id` must be an object id `{KEY}` 的第 {n} 项:`id` 必须是对象 ID +@msg `{KEY}` entry {n}: `start` must be a byte offset `{KEY}` 的第 {n} 项:`start` 必须是字节偏移 +@msg `{KEY}` entry {n}: `{k}` must be a number from -{MAX_PARA} to {MAX_PARA} pt `{KEY}` 的第 {n} 项:`{k}` 必须是 -{MAX_PARA} 到 {MAX_PARA} pt 之间的数字 +@msg `{KEY}` entry {n}: no paragraph of {_1} starts at byte {start} `{KEY}` 的第 {n} 项:{_1} 中没有从字节 {start} 开始的段落 +@msg `{KEY}` entry {n}: unknown key `{k}` `{KEY}` 的第 {n} 项:未知的键 `{k}` +@msg `{KEY}` entry {n}: {_1} is not a type object `{KEY}` 的第 {n} 项:{_1} 不是文字对象 +@msg `{KEY}` is empty `{KEY}` 为空 +@msg `{KEY}` must be a list `{KEY}` 必须是列表 +@msg `{KEY}` takes at most {MAX_PARAGRAPH_INDENTS} entries (got {_1}) `{KEY}` 最多包含 {MAX_PARAGRAPH_INDENTS} 项 (实际为 {_1}) +@msg `{KEY}` takes no `{other}` beside it `{KEY}` 不能与 `{other}` 同时给出 +@msg `{base}` is larger than {_1} MB `{base}` 大于 {_1} MB +@msg `{base}` is not in the DCS file's folder `{base}` 不在 DCS 文件所在的文件夹中 +@msg `{key}` holds more than {MAX_EDIT_WORDS} words `{key}` 中的单词超过 {MAX_EDIT_WORDS} 个 +@msg `{key}` must be 0 or more `{key}` 必须大于或等于 0 +@msg `{key}` must be [x, y] numbers `{key}` 必须是数字 [x, y] +@msg `{key}` must be a list of words `{key}` 必须是单词的列表 +@msg `{key}` must be a list, not {v} `{key}` 必须是列表,不能是 {v} +@msg `{key}` must be a number or null, not {v} `{key}` 必须是数字或 null,不能是 {v} +@msg `{key}` must be a whole number of 0 or more `{key}` 必须是大于或等于 0 的整数 +@msg `{key}` must be from 0 to {MAX_DISTANCE} pt `{key}` 必须为 0 到 {MAX_DISTANCE} pt +@msg `{key}` must be from 0.01 to 1000 pt `{key}` 必须为 0.01 到 1000 pt +@msg `{key}` must be from {lo} to {hi}, not {v} `{key}` 必须介于 {lo} 到 {hi} 之间,不能是 {v} +@msg `{key}` must be one of auto, always, never `{key}` 必须是 auto、always、never 之一 +@msg `{key}` must be one of miter, round, bevel `{key}` 必须是 miter、round、bevel 之一 +@msg `{key}` must be one word of at most {_1} characters `{key}` 必须是一个不超过 {_1} 个字符的单词 +@msg `{key}` must hold single words of at most {_1} characters `{key}` 中的每一项必须是不超过 {_1} 个字符的单个单词 +@msg `{key}` must name an object attached to the path of an Objects on Path group `{key}` 必须指定附着在“路径上的对象”组的路径上的对象 +@msg `{key}` names an object that is hidden or locked `{key}` 指定的对象已隐藏或锁定 +@msg `{name}` is a file of its own, which can only be found next to the DCS file's path `{name}` 是一个单独的文件,只能在 DCS 文件的路径旁找到 +@msg `{name}`: {_1}: {e} `{name}`:{_1}:{e} +@msg `{u}` is no Unicode character `{u}` 不是 Unicode 字符 +@msg `{word}` isn't in the custom dictionary `{word}` 不在自定义词典中 +@msg a CMap has too many mappings 某个 CMap 的映射过多 +@msg a \u escape needs four hexadecimal digits \u 转义需要四位十六进制数字 +@msg a comma in an XPath expression must separate function arguments XPath 表达式中的逗号只能用来分隔函数参数 +@msg a document holds at most {_1} SVG filters 一个文档最多包含 {_1} 个 SVG 滤镜 +@msg a document with unsaved changes has no recovery copy 有未保存更改的文档没有恢复副本 +@msg a font's data is too large 某个字体的数据过大 +@msg a font's subroutines are too large 某个字体的子程序过大 +@msg a function declaration without a name 函数声明没有名称 +@msg a host value has too many entries 宿主值的条目过多 +@msg a host value is nested too deep 宿主值嵌套过深 +@msg a namespace declaration uses a reserved prefix or URI 命名空间声明使用了保留的前缀或 URI +@msg a namespace qualifier is undefined 命名空间限定符未定义 +@msg a namespace with an empty URI cannot have a prefix URI 为空的命名空间不能有前缀 +@msg a number has no digits 数字中没有数位 +@msg a number's exponent has no digits 数字的指数部分没有数位 +@msg a number's fraction has no digits 数字的小数部分没有数位 +@msg a property descriptor cannot have both a value or writable and a get or set 属性描述符不能同时包含 value 或 writable 以及 get 或 set +@msg a property descriptor must be an object 属性描述符必须是对象 +@msg a property's {name} must be a function or undefined 属性的 {name} 必须是函数或 undefined +@msg a stream in it would decode to more than 256 MB, or its decode parameters can't be applied 其中某个数据流解码后会超过 256 MB,或无法应用其解码参数 +@msg a string holds a control character 字符串中含有控制字符 +@msg a string holds an escape sequence JSON does not have 字符串中含有 JSON 不支持的转义序列 +@msg a string is not closed 字符串没有结束 +@msg an SVG filter is named by its id: give `xml` with `name` SVG 滤镜以其 id 命名:请同时给出 `xml` 和 `name` +@msg an XML element has two attributes with the same name XML 元素有两个同名的属性 +@msg an XML value cannot be inserted into itself or its descendants XML 值不能插入到自身或其后代中 +@msg an XML value's children cannot be assigned by position 不能按位置为 XML 值的子项赋值 +@msg an XML value's children cannot be deleted by position 不能按位置删除 XML 值的子项 +@msg an XMLList converts to XML only when it has one item XMLList 只有在仅含一项时才能转换为 XML +@msg an XPath node test is missing 缺少 XPath 节点测试 +@msg an XPath operand is missing 缺少 XPath 操作数 +@msg an XPath operator is missing 缺少 XPath 运算符 +@msg an XPath predicate or step cannot follow here 此处不能接 XPath 谓词或步 +@msg an XPath predicate or step follows a value that is not a node-set XPath 谓词或步接在了不是节点集的值之后 +@msg an XPath step is missing 缺少 XPath 步 +@msg an image couldn't be decoded and is missing from the picture 有一个图像无法解码,因此图片中缺少该图像 +@msg an image of {w} × {h} pixels is too large to convert (at most {_1} pixels) {w} × {h} 像素的图像过大,无法转换 (最多 {_1} 像素) +@msg apply was called on a value that is not a function apply 的调用对象不是函数 +@msg area type in a thread cannot use Dynamic Text: {frames} 串接中的区域文字不能使用动态文本:{frames} +@msg array literal too long 数组字面量过长 +@msg assignment to a constant binding 对常量绑定赋值 +@msg at least one row that isn't excluded needs a weight above 0 至少要有一个未被排除的行的权重大于 0 +@msg bad point {v}: expected [x, y] 点 {v} 无效:应为 [x, y] +@msg blend must be a mode name blend 必须是模式名称 +@msg both sides of an XPath | must select nodes XPath 的 | 两侧都必须选择节点 +@msg canceled 已取消 +@msg cannot convert the object to a primitive value 无法将对象转换为原始值 +@msg cannot convert undefined or null to an object 无法将 undefined 或 null 转换为对象 +@msg character dimensions cannot be represented with the source text transform 无法用源文本的变换表示字符尺寸 +@msg character dimensions cannot be represented with the target text transform 无法用目标文本的变换表示字符尺寸 +@msg continuation must be an array of path chunks continuation 必须是路径分段的数组 +@msg continuation requires points continuation 需要 points +@msg each path chunk must contain 1 to 4096 points 每个路径分段必须包含 1 到 4096 个点 +@msg each pick is {{at: [x, y]}} or {{rect: [x0, y0, x1, y1]}} (got {v}) 每个拾取项是 {{at: [x, y]}} 或 {{rect: [x0, y0, x1, y1]}} (实际为 {v}) +@msg each weight must be a number of 0 or more (got {v}) 每个权重必须是大于或等于 0 的数字 (实际为 {v}) +@msg finally table {t} out of range finally 表 {t} 超出范围 +@msg flags cannot be given with a RegExp object 不能在给出 RegExp 对象的同时给出 flags +@msg function declaration index out of range 函数声明索引超出范围 +@msg give `char`, `text`, `code` or `unicode` 请给出 `char`、`text`、`code` 或 `unicode` +@msg give `count` or `spacing`, not both 请给出 `count` 或 `spacing`,不能两者都给 +@msg give `name`, an SVG filter's name 请给出 `name`,即 SVG 滤镜的名称 +@msg give `path`, an SVG file, or `svg`, SVG text 请给出 `path` (SVG 文件) 或 `svg` (SVG 文本) +@msg give `xml`, one SVG element 请给出 `xml`,即一个 SVG 元素 +@msg give exactly one of `at`, `rect` and `points` `at`、`rect` 和 `points` 中必须且只能给出一个 +@msg give exactly one of `path`, `data` and `dataBase64` `path`、`data` 和 `dataBase64` 中必须且只能给出一个 +@msg give index or indexes, not both 请给出 index 或 indexes,不能两者都给 +@msg give one element 请给出一个 元素 +@msg give opacity or blend 请给出 opacity 或 blend +@msg handler at {_1} expects {_2} values but its range starts with {d} 位于 {_1} 的处理程序需要 {_2} 个值,但其范围开始时有 {d} 个 +@msg handler depth too large 处理程序深度过大 +@msg handler range {_1}..{_2} out of range 处理程序范围 {_1}..{_2} 超出范围 +@msg hiddenLayers must be true or false hiddenLayers 必须为 true 或 false +@msg hvcC hvcC +@msg images in a spot ink whose samples couldn't be read were imported in RGB 采样无法读取的专色油墨图像已按 RGB 导入 +@msg images past the most pixels one file may hold were left out 超出单个文件像素上限的图像已被略去 +@msg images too large to read were left out 过大而无法读取的图像已被略去 +@msg indexes may hold at most {MAX_GUIDE_INDEXES} entries indexes 最多包含 {MAX_GUIDE_INDEXES} 项 +@msg indexes must be an array of guide indexes indexes 必须是参考线索引的数组 +@msg instruction out of range 指令超出范围 +@msg instruction {pc} ({op}) pops below the stack 指令 {pc} ({op}) 的出栈超出了栈底 +@msg instruction {pc} reached with stack depths {seen} and {d} 到达指令 {pc} 时的栈深度分别为 {seen} 和 {d} +@msg invalid array length 数组长度无效 +@msg invalid group 分组无效 +@msg invalid object id {v}: expected a non-negative integer 对象 ID {v} 无效:应为非负整数 +@msg invalid regular expression flag '{_1}' 正则表达式标志 '{_1}' 无效 +@msg invalid regular expression: {m} 正则表达式无效:{m} +@msg invalid time value 时间值无效 +@msg is a confirm's answer, whose `value` must be true or false 是 confirm 的回答,其 `value` 必须为 true 或 false +@msg is a prompt's answer, whose `value` must be a string or null 是 prompt 的回答,其 `value` 必须是字符串或 null +@msg is an alert's answer, whose `value` must be "ok" 是 alert 的回答,其 `value` 必须是 "ok" +@msg is longer than 16 KiB 长度超过 16 KiB +@msg it draws its image through a clipping path 它通过剪切路径绘制图像 +@msg it draws no image 它没有绘制图像 +@msg it is larger than {MAX_DICTIONARY_FILE_BYTES} bytes 它大于 {MAX_DICTIONARY_FILE_BYTES} 字节 +@msg it isn't a file 它不是文件 +@msg it names {_1} plates, and at most {MAX_PLATES} are read 它列出了 {_1} 个印版,而最多读取 {MAX_PLATES} 个 +@msg its art is too long or too detailed for a head 其图稿过长或过于复杂,不能用作箭头 +@msg its art paints nothing 其图稿没有绘制任何内容 +@msg its image is too large to read 其图像过大,无法读取 +@msg its plates are too large: more than {MAX_SAMPLES} pixels together 其印版过大:合计超过 {MAX_SAMPLES} 像素 +@msg its plates are too large: {_1} plates of {w} × {h} pixels 其印版过大:{_1} 个 {w} × {h} 像素的印版 +@msg its plates can't be kept together 其印版无法保存在一起 +@msg its shapes could not be combined into one 其形状无法合并为一个 +@msg jump to {pc}, past the end 跳转到 {pc},超出了末尾 +@msg legacyNameEncoding must be one of {_1} legacyNameEncoding 必须是 {_1} 之一 +@msg localize: the first argument must be a localization object or a string localize:第一个参数必须是本地化对象或字符串 +@msg missing `picks` 缺少 `picks` +@msg missing `word` 缺少 `word` +@msg must be an object with `kind` and `value` 必须是包含 `kind` 和 `value` 的对象 +@msg must have `kind` alert, confirm or prompt `kind` 必须是 alert、confirm 或 prompt +@msg must have exactly `kind` and `value` 必须只包含 `kind` 和 `value` +@msg needs a closing quote after the name 名称后需要右引号 +@msg needs a name 需要名称 +@msg needs a name of at most 64 bytes 需要不超过 64 字节的名称 +@msg needs a name of letters, digits and _, or a quoted name 需要由字母、数字和 _ 组成的名称,或带引号的名称 +@msg needs a name without control characters 需要不含控制字符的名称 +@msg nesting too deep 嵌套过深 +@msg no HP-GL format 没有 HP-GL 格式 +@msg no New Document profile called `{shown}` ({_1}) 没有名为 `{shown}` 的新建文档配置文件 ({_1}) +@msg no SVG filter at index {k} 索引 {k} 处没有 SVG 滤镜 +@msg no arrowheads file here 这里没有箭头文件 +@msg no character has code {code} 没有代码为 {code} 的字符 +@msg no custom arrowhead {name} (see stroke.arrowheads.list) 没有自定义箭头 {name} (参见 stroke.arrowheads.list) +@msg no file to open 没有要打开的文件 +@msg no instructions 没有指令 +@msg no layer to rename 没有要重命名的图层 +@msg no random numbers ({e}) 无法获取随机数 ({e}) +@msg no selected or given object has a visible 3D effect 所选或指定的对象都没有可见的 3D 效果 +@msg no such artboard {v} 没有画板 {v} +@msg no symbol named `{_1}` 没有名为 `{_1}` 的符号 +@msg node {_1} already has the text variable `{_2}` 节点 {_1} 已有文本变量 `{_2}` +@msg not a DCS file 不是 DCS 文件 +@msg not a RegExp object 不是 RegExp 对象 +@msg not a regular expression 不是正则表达式 +@msg not an action set: the text doesn't start with /version and a number 不是动作组:文本不是以 /version 和一个数字开头 +@msg nothing to repeat 没有可重复的内容 +@msg numbers out of order in {_1} quantifier 量词 {_1} 中的数字顺序颠倒 +@msg object {_1} needs a 3D effect 对象 {_1} 需要有 3D 效果 +@msg object {_1}: a hollow Extrude & Bevel has no caps: turn on Cap to map a graphic 对象 {_1}:空心的突出与斜角没有端面:请打开“端点”后再贴图 +@msg object {_1}: with a depth of 0 the object has one face: map its graphics onto the front 对象 {_1}:深度为 0 时对象只有一个面:请将图形贴到正面 +@msg object {_1}: {_2} 对象 {_1}:{_2} +@msg object {_1}: {e} 对象 {_1}:{e} +@msg object {_1}: {name} at index {index} has no lighting presets; set its lights with effect.setParams 对象 {_1}:索引 {index} 处的 {name} 没有照明预设;请用 effect.setParams 设置其光源 +@msg opacity must be a number opacity 必须是数字 +@msg operand too large 操作数过大 +@msg order is a whole number from 0 to {others}, not `{v}` order 是 0 到 {others} 之间的整数,不能是 `{v}` +@msg path chunks must share their boundary point 相邻的路径分段必须共用边界点 +@msg pdfCompatible: false needs the artboards to keep the editable artwork when useArtboards is false pdfCompatible: false 在 useArtboards 为 false 时需要用画板来保留可编辑的图稿 +@msg point x must be a number 点的 x 必须是数字 +@msg point y must be a number 点的 y 必须是数字 +@msg points must be [x,y] pairs points 必须是 [x,y] 对 +@msg points must be finite canvas points points 必须是画布上的有限坐标点 +@msg range out of order in character class 字符类中的范围顺序颠倒 +@msg reduce of an empty array with no initial value 对空数组调用 reduce 且没有初始值 +@msg regular expression flag '{_1}' given twice 正则表达式标志 '{_1}' 给出了两次 +@msg sampled text would exceed the canvas (coordinates out of range) 取样的文本会超出画布 (坐标超出范围) +@msg select an SVG filter 请选择一个 SVG 滤镜 +@msg select an object with a 3D effect 请选择带有 3D 效果的对象 +@msg select an object with a 3D effect, or give its id in ids 请选择带有 3D 效果的对象,或在 ids 中给出其 ID +@msg select one layer, group or object to rename 请选择一个要重命名的图层、编组或对象 +@msg select the art to weed 请选择要除废的图稿 +@msg select the banner, or mark every artboard 请选择横幅,或为每个画板添加标记 +@msg select type on a path or area type 请选择路径文字或区域文字 +@msg side is left or right, not `{v}` side 是 left 或 right,不能是 `{v}` +@msg source text transform is collapsed or unrepresentable 源文本的变换已塌缩或无法表示 +@msg table must be true or false table 必须为 true 或 false +@msg takes one name 只接受一个名称 +@msg target text transform is collapsed or unrepresentable 目标文本的变换已塌缩或无法表示 +@msg that makes too many pieces (at most 100000) or dash steps: simplify the dash pattern or make the dashes longer 这样生成的片段 (最多 100000 个) 或虚线步数过多:请简化虚线图案或加长虚线 +@msg the Layers panel is not shown “图层”面板未显示 +@msg the Layers panel's search, filter or Show Layers Only hides its row “图层”面板的搜索、筛选或“仅显示图层”隐藏了它所在的行 +@msg the Objects on Path group is hidden or locked “路径上的对象”组已隐藏或锁定 +@msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes SVG 文件大于 {MAX_IMPORT_BYTES} 字节 +@msg the XML operation needs an XML or XMLList value 此 XML 操作需要 XML 或 XMLList 值 +@msg the XPath expression does not evaluate to a node-set XPath 表达式的求值结果不是节点集 +@msg the XPath expression ends early XPath 表达式提前结束 +@msg the XPath expression has an unmatched ) XPath 表达式中有不匹配的 ) +@msg the XPath expression has an unmatched ] XPath 表达式中有不匹配的 ] +@msg the XPath expression has an unmatched closing bracket XPath 表达式中有不匹配的右括号 +@msg the XPath expression selects a namespace node, which is not an XML value XPath 表达式选中了命名空间节点,它不是 XML 值 +@msg the XPath expression selects the root node, which is not an XML value XPath 表达式选中了根节点,它不是 XML 值 +@msg the XPath function {name} needs a node-set XPath 函数 {name} 需要节点集 +@msg the XPath function {name} takes the wrong number of arguments XPath 函数 {name} 的参数个数不正确 +@msg the XPath name functions need a node-set XPath 的名称函数需要节点集 +@msg the XPath prefix {shown} is not bound to a namespace XPath 前缀 {shown} 未绑定到命名空间 +@msg the XPath variable ${shown} is not bound XPath 变量 ${shown} 未绑定 +@msg the argument list is not an object 参数列表不是对象 +@msg the artwork is too large for EPS: what follows 256 MB of PostScript was left out 图稿过大,无法完整写入 EPS:256 MB 之后的 PostScript 内容已被略去 +@msg the banner has no width or height 横幅没有宽度或高度 +@msg the bitmaps hold more pixels than one file may 位图的像素数超过了单个文件的上限 +@msg the code runs past its last instruction 代码运行到了最后一条指令之后 +@msg the curve tolerance must be from 0.01 to 10 points 曲线容差必须为 0.01 到 10 点 +@msg the custom dictionary couldn't be saved to {_1}: {e} 无法将自定义词典保存到 {_1}:{e} +@msg the custom dictionary {_1} can't be read ({why}), so it is left as it is 无法读取自定义词典 {_1} ({why}),因此保持原样 +@msg the document already has an SVG filter named {name} 文档中已有名为 {name} 的 SVG 滤镜 +@msg the document has another SVG filter named {name}: use svgFilter.apply, or svgFilter.define with `replace` to edit it 文档中已有另一个名为 {name} 的 SVG 滤镜:请使用 svgFilter.apply,或使用带 `replace` 的 svgFilter.define 来编辑它 +@msg the document has no SVG filter named {name} 文档中没有名为 {name} 的 SVG 滤镜 +@msg the document has no SVG filter named {r} 文档中没有名为 {r} 的 SVG 滤镜 +@msg the document has no color swatches 文档中没有颜色色板 +@msg the document's swatches hold {_1} colors; the document reduction takes at most 255 文档的色板含有 {_1} 种颜色;document 减色方式最多使用 255 种 +@msg the file isn't valid SVG: {e} 文件不是有效的 SVG:{e} +@msg the file names no plate 文件没有列出任何印版 +@msg the function's prototype is not an object 函数的原型不是对象 +@msg the grommet inset is too large for the banner 扣眼边距对横幅而言过大 +@msg the guide is hidden or locked 参考线已隐藏或锁定 +@msg the hem is too deep for the banner 折边对横幅而言过深 +@msg the library's file is outside the read roots 库文件位于可读取的根目录之外 +@msg the line is too long, or the paths it passes too many, to check 线条过长,或它经过的路径过多,无法检查 +@msg the method needs an XML value 此方法需要 XML 值 +@msg the paint is not a freeform gradient (apply one with paint.editGradient {kind}) 该上色不是自由渐变 (请用 paint.editGradient {kind} 应用一个) +@msg the parameters or body do not form one function 参数或函数体不能构成一个函数 +@msg the pasted SVG filter {name} draws differently from the document's filter of that name, and no free name fits it 粘贴的 SVG 滤镜 {name} 与文档中同名滤镜的绘制结果不同,且没有可用的空闲名称 +@msg the paths are too many or too tangled to find where they cross 路径过多或过于交错,无法找出它们的交叉位置 +@msg the pen table holds more than 255 pens 笔表中的笔超过 255 支 +@msg the plates can't be kept 无法保留这些印版 +@msg the position table does not match the instructions 位置表与指令不匹配 +@msg the prompt's text is longer than {MAX_PROMPT_BYTES} bytes 提示文本的长度超过 {MAX_PROMPT_BYTES} 字节 +@msg the radix must be between 2 and 36 基数必须介于 2 到 36 之间 +@msg the rectangle or line reaches too many paths to check 矩形或线条涉及的路径过多,无法检查 +@msg the right side of 'in' is not an object 'in' 的右侧不是对象 +@msg the right side of 'instanceof' is not a function 'instanceof' 的右侧不是函数 +@msg the selected art is nested more than {MAX_DEPTH} levels deep 所选图稿的嵌套超过 {MAX_DEPTH} 层 +@msg the selected art is too large to measure 所选图稿过大,无法测量 +@msg the selection has no outlines to weed around 所选对象没有可供除废的轮廓 +@msg the spacing makes more than {MAX_GROMMETS} grommets 此间距会生成超过 {MAX_GROMMETS} 个扣眼 +@msg the value bind was called on is not a function 调用 bind 的值不是函数 +@msg the value is not a constructor 该值不是构造函数 +@msg the value is not a function 该值不是函数 +@msg the value is not a valid XML name 该值不是有效的 XML 名称 +@msg the value is not an XML attribute name 该值不是 XML 属性名称 +@msg the value is not an XML name 该值不是 XML 名称 +@msg the weeding lines cross the art's outlines too many times to measure; use fewer lines 除废线与图稿轮廓的交叉次数过多,无法测量;请减少除废线 +@msg the weeding lines pass too close to too many outline segments to measure; use fewer lines or a smaller gap 除废线离过多的轮廓线段太近,无法测量;请减少除废线或缩小间隙 +@msg the weeding lines would be more than {max_pieces} pieces 除废线会超过 {max_pieces} 段 +@msg the {_1} plate lies outside the file {_1} 印版位于文件之外 +@msg there is no banner to mark 没有可添加标记的横幅 +@msg this is a binary DXF file, which can't be read: save it from the CAD app as an ASCII DXF and open that 这是二进制 DXF 文件,无法读取:请在 CAD 应用中将其另存为 ASCII DXF 后再打开 +@msg this warp's points can't be edited: use Reset with Mesh first 此变形的点无法编辑:请先使用“以网格重置” +@msg toExponential() digits must be between 0 and 20 toExponential() 的位数必须介于 0 到 20 之间 +@msg toFixed() digits must be between 0 and 20 toFixed() 的位数必须介于 0 到 20 之间 +@msg toISOString is not a function toISOString 不是函数 +@msg toPrecision() argument must be between 1 and 21 toPrecision() 的参数必须介于 1 到 21 之间 +@msg toSource: a getter cannot be written as source toSource:getter 无法写成源代码 +@msg toSource: an array with properties besides its elements, a property that is not enumerable or another prototype cannot be written as source toSource:除元素外还有其他属性、含不可枚举属性或使用其他原型的数组无法写成源代码 +@msg toSource: an object with a property that is not enumerable, or whose prototype is not Object.prototype, cannot be written as source toSource:含不可枚举属性或原型不是 Object.prototype 的对象无法写成源代码 +@msg toSource: the source is too long toSource:源代码过长 +@msg toSource: the value contains itself toSource:该值包含自身 +@msg toSource: the value has too many entries toSource:该值的条目过多 +@msg toSource: the value is nested too deep toSource:该值嵌套过深 +@msg toString is not a function toString 不是函数 +@msg too many arguments 参数过多 +@msg too many quantifiers 量词过多 +@msg turn on at least one side 请至少打开一条边 +@msg unknown OpenType feature `{t}` (liga, calt, dlig, smcp, frac, onum, tnum, ordn, swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom, aalt; prefix - to turn off; swsh, ss01–ss20, salt, titl, pnum, lnum, sups, subs, numr, dnom and aalt take an alternate's number as `tag=N` with N from 0 to {_1}, as `salt=2`) 未知的 OpenType 特性 `{t}` (liga、calt、dlig、smcp、frac、onum、tnum、ordn、swsh、ss01–ss20、salt、titl、pnum、lnum、sups、subs、numr、dnom、aalt;加前缀 - 表示关闭;swsh、ss01–ss20、salt、titl、pnum、lnum、sups、subs、numr、dnom 和 aalt 可用 `tag=N` 指定替代字形的编号,N 为 0 到 {_1},例如 `salt=2`) +@msg unknown dither `{d}` (diffusion, pattern, noise or none) 未知的仿色 `{d}` (diffusion、pattern、noise 或 none) +@msg unknown panel `{panel}` 未知的面板 `{panel}` +@msg unknown parameter `{key}` 未知的参数 `{key}` +@msg unknown parameter `{within}settings.{format}`; {why} 未知的参数 `{within}settings.{format}`;{why} +@msg unknown parameter `{within}{key}`; {why} 未知的参数 `{within}{key}`;{why} +@msg unknown reduction `{reduction}` (selective, perceptual, adaptive, web, gray, blackWhite, uniform or document) 未知的减色方式 `{reduction}` (selective、perceptual、adaptive、web、gray、blackWhite、uniform 或 document) +@msg unmatched ')' 不匹配的 ')' +@msg unterminated character class 字符类没有结束 +@msg unterminated group 分组没有结束 +@msg with no hem and no grommets there is nothing to mark 没有折边也没有扣眼,因此没有可标记的内容 +@msg wordGap and lineGap need area type in the selection wordGap 和 lineGap 需要所选对象中有区域文字 +@msg xpath needs its variables as an object xpath 的变量必须以对象形式给出 +@msg xpath needs the expression as a string xpath 的表达式必须以字符串形式给出 +@msg {GRANT_NOT_REMOVED}, and its settings and cache can't be moved back from {_1} to {_2}: {e} {GRANT_NOT_REMOVED},而且其设置和缓存无法从 {_1} 移回 {_2}:{e} +@msg {_1} is not a folder: {e} {_1} 不是文件夹:{e} +@msg {_1}: {_2} and {_3} are in the way {_1}:被 {_2} 和 {_3} 挡住 +@msg {code}: {0} {code}:{0} +@msg {dir}: {e} {dir}:{e} +@msg {file} names more than one linked JavaScript file {file} 指定了多个链接的 JavaScript 文件 +@msg {k}: a custom arrowhead's path needs an area to fill and at most {most} anchors and {most} subpaths, each anchor within {far} head units of its tip {k}:自定义箭头的路径需要有可填充的面积,最多 {most} 个锚点和 {most} 条子路径,且每个锚点距箭头尖端不超过 {far} 个箭头单位 +@msg {k}: bad custom arrowhead path: {e} {k}:自定义箭头路径无效:{e} +@msg {k}: bad custom arrowhead: {e} {k}:自定义箭头无效:{e} +@msg {k}: custom must be a name {k}:custom 必须是名称 +@msg {name} must be a number {name} 必须是数字 +@msg {path}: copy takes a DCS file only when its plates are inside it; relink to it where its plate files are {path}:只有印版包含在文件内时才能复制 DCS 文件;请在其印版文件所在的位置重新链接它 +@msg {path}: larger than {_1} MB {path}:大于 {_1} MB +@msg {saving} failed: {e} {saving} 失败:{e} +@msg {shown} is not an XPath 1.0 function {shown} 不是 XPath 1.0 函数 +@msg {v} names no layer or sublayer {v} 不对应任何图层或子图层 +@msg {what} is not a function {what} 不是函数 +@msg {what} would print more than {MAX_COPIES_PER_SHEET} copies on a sheet: scale it up {what} 在一张纸上会打印超过 {MAX_COPIES_PER_SHEET} 份:请将其放大 +@msg {what} {i} out of range {what} {i} 超出范围 +@msg A profile supports one Revolve effect. Edit the existing effect's options instead. 一个轮廓只支持一个回转效果。请改为编辑现有效果的选项。 +@msg Add Points at Crossings: a path went missing 在交叉处添加锚点:有一条路径丢失 +@msg CSS options: {e} CSS 选项:{e} +@msg CSV has a header but no data rows CSV 有标题行,但没有数据行 +@msg CSV holds NUL bytes: save it as UTF-8, or as UTF-16 with a byte-order mark CSV 中含有 NUL 字节:请将其保存为 UTF-8,或带字节顺序标记的 UTF-16 +@msg CSV is empty CSV 为空 +@msg CSV is larger than {MAX_CSV_BYTES} bytes CSV 大于 {MAX_CSV_BYTES} 字节 +@msg CSV is not UTF-16 CSV 不是 UTF-16 +@msg CSV is not UTF-8 CSV 不是 UTF-8 +@msg CSV would be larger than {MAX_CSV_BYTES} bytes CSV 会大于 {MAX_CSV_BYTES} 字节 +@msg Choose original artwork, not a dimension's generated paths 请选择原始图稿,不要选择尺寸标注生成的路径 +@msg Contour: select paths or shapes 轮廓:请选择路径或形状 +@msg Contour: the Offset Path effect is not available 轮廓:偏移路径效果不可用 +@msg Create needs fills, strokes or both 创建时需要填色、描边或两者 +@msg DXF options: {e} DXF 选项:{e} +@msg DXF scale must be a positive number up to {_1}, not {scale} DXF 缩放比例必须是不超过 {_1} 的正数,不能是 {scale} +@msg DXF {field} `{s}`: {allowed} DXF {field} `{s}`:{allowed} +@msg Dimension is locked or hidden 尺寸标注已锁定或隐藏 +@msg Dimension mode does not match its source 尺寸标注的模式与其来源不匹配 +@msg Draw Inside needs exactly one selected path, compound path or text 内部绘图需要恰好选中一条路径、一条复合路径或一个文本 +@msg EPS Save writes all artwork: use document.export for selected-only EPS 保存 EPS 会写入全部图稿:要只导出所选对象的 EPS,请使用 document.export +@msg EPS flattener: {e} EPS 拼合器:{e} +@msg EPS options: {e} EPS 选项:{e} +@msg EPS {field} `{s}`: {allowed} EPS {field} `{s}`:{allowed} +@msg Export for Screens writes png, png8, jpg, webp, gif, tiff, bmp, tga, psd, svg, svgz, pdf, eps, ai or vectorcraft 导出为屏幕所用格式可写出 png、png8、jpg、webp、gif、tiff、bmp、tga、psd、svg、svgz、pdf、eps、ai 或 vectorcraft +@msg Flare click coordinates must be finite numbers 光晕的单击坐标必须是有限的数字 +@msg HTML Text applies to object slices of type only HTML 文本只适用于文字对象的切片 +@msg Identify Objects By is XML ID: the name must be a valid XML ID (start with a letter, underscore or colon; no spaces) 对象识别方式为 XML ID:名称必须是有效的 XML ID (以字母、下划线或冒号开头;不含空格) +@msg Image Trace failed: internal error: its thread stopped (please report this bug) 图像描摹失败:内部错误:其线程已停止 (请报告此错误) +@msg Image Trace failed: {e} 图像描摹失败:{e} +@msg Image Trace finished, but its document was closed 图像描摹已完成,但其文档已关闭 +@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again 图像描摹已完成,但图像或其设置在此期间发生了更改:请重新描摹 +@msg Invalid dimension offset 尺寸标注的偏移无效 +@msg Invalid point 点无效 +@msg Join: a subpath went missing 连接:有一条子路径丢失 +@msg Lock Workspace is not available in VectorCraft VectorCraft 不提供锁定工作区 +@msg Move Panel to New Window is not available: floating panels stay in the main window 无法将面板移到新窗口:浮动面板只能留在主窗口中 +@msg Offset Path: the path is too complex to offset 偏移路径:路径过于复杂,无法偏移 +@msg Offset Path: {e} 偏移路径:{e} +@msg PDF content is incomplete or exceeds the reader's limits; no document was imported PDF 内容不完整或超出读取器的限制;未导入任何文档 +@msg PDF flattener: {e} PDF 拼合器:{e} +@msg PDF options: {e} PDF 选项:{e} +@msg Recolor Artwork is no longer open 重新着色图稿已不再打开 +@msg SVG is not UTF-8, UTF-16 or ISO 8859-1 SVG 不是 UTF-8、UTF-16 或 ISO 8859-1 +@msg Save writes one artboard: name one, or export several with document.export 保存只写入一个画板:请指定一个画板,或用 document.export 导出多个 +@msg Select a dimension first 请先选择一个尺寸标注 +@msg Select dimensions to update 请选择要更新的尺寸标注 +@msg Select only dimensions 请只选择尺寸标注 +@msg Select two or more objects, or a group 请选择两个或更多对象,或一个编组 +@msg Shaper needs 1–64 source paths Shaper 需要 1–64 条源路径 +@msg Switch x/y is for scatter graphs 切换 x/y 用于散点图 +@msg Text options: {e} 文本选项:{e} +@msg `align` is start, center or end `align` 为 start、center 或 end +@msg `anchors` must be an array of [subpath, anchor] pairs `anchors` 必须是 [subpath, anchor] 对的数组 +@msg `anchors` must list anchor indices (0, 1, 2…), not {k} `anchors` 必须列出锚点索引 (0, 1, 2…),不能是 {k} +@msg `anchors` must list anchor indices (0, 1, 2…), not {v} `anchors` 必须列出锚点索引 (0, 1, 2…),不能是 {v} +@msg `artboards` must be a list of artboard indices `artboards` 必须是画板索引的列表 +@msg `asset` is the asset id (see assets.list) `asset` 是资源 ID (参见 assets.list) +@msg `at` must be a byte offset `at` 必须是字节偏移 +@msg `autoLeading` must be a number `autoLeading` 必须是数字 +@msg `background` must be "", "matte" or #rrggbb `background` 必须是 ""、"matte" 或 #rrggbb +@msg `burasagari` must be "none", "standard" or "forced" `burasagari` 必须是 "none"、"standard" 或 "forced" +@msg `center` must be [x, y] `center` 必须是 [x, y] +@msg `charAlign` must be "romanBaseline", "emBoxTop", "emBoxCenter", "emBoxBottom", "icfTop" or "icfBottom" `charAlign` 必须是 "romanBaseline"、"emBoxTop"、"emBoxCenter"、"emBoxBottom"、"icfTop" 或 "icfBottom" +@msg `charDirection` must be "default", "leftToRight" or "rightToLeft" `charDirection` 必须是 "default"、"leftToRight" 或 "rightToLeft" +@msg `clearStroke` requires `stroke: false`, `ids: []` and no `stop` `clearStroke` 要求 `stroke: false`、`ids: []`,且不给出 `stop` +@msg `clear` must be a list of type object ids, not {v} `clear` 必须是文字对象 ID 的列表,不能是 {v} +@msg `clear` must list type objects; {_1} is not one `clear` 必须列出文字对象;{_1} 不是文字对象 +@msg `clear` must not list `id` `clear` 不能列出 `id` +@msg `color` needs a `rule` to make the theme from `color` 需要用于生成主题的 `rule` +@msg `colors` is empty `colors` 为空 +@msg `columnType` is vertical, uniform, repeating or sliding `columnType` 为 vertical、uniform、repeating 或 sliding +@msg `columns` must be a whole number 1..50 `columns` 必须是 1..50 的整数 +@msg `commands` must not be empty `commands` 不能为空 +@msg `contents` goes with `to` `contents` 要与 `to` 一起给出 +@msg `corners` must be sharp, round or square, not `{other}` `corners` 必须是 sharp、round 或 square,不能是 `{other}` +@msg `corners` must list anchor indices (0, 1, 2…), not {v} `corners` 必须列出锚点索引 (0, 1, 2…),不能是 {v} +@msg `count` must be a whole number from 1 to 100 `count` 必须是 1 到 100 之间的整数 +@msg `dataBase64` is larger than the module limit `dataBase64` 超过了模块大小上限 +@msg `dataBase64` is not valid base64 `dataBase64` 不是有效的 base64 +@msg `defaultsOnly` cannot be combined with `ids`, `reverse` or `append` `defaultsOnly` 不能与 `ids`、`reverse` 或 `append` 同时使用 +@msg `depth` and `childLimit` slice the summary: pass `summary: true` `depth` 和 `childLimit` 用于截取摘要:请传入 `summary: true` +@msg `design` is a design name, or null for plain columns `design` 是设计名称,或用 null 表示普通柱形 +@msg `design` is a design name, or null for the default marker `design` 是设计名称,或用 null 表示默认标记 +@msg `destinationFolder` is required when destination is `folder` destination 为 `folder` 时必须给出 `destinationFolder` +@msg `destination` must be `none`, `saveAndClose` or `folder` `destination` 必须是 `none`、`saveAndClose` 或 `folder` +@msg `diameter` must be from 0.1 to 2500 pt `diameter` 必须为 0.1 到 2500 pt +@msg `digits` must be one of {_1} `digits` 必须是 {_1} 之一 +@msg `dimImages` is a percentage or false `dimImages` 是百分比或 false +@msg `direction` must be "auto", "leftToRight" or "rightToLeft" `direction` 必须是 "auto"、"leftToRight" 或 "rightToLeft" +@msg `each` is the value one design stands for, more than 0 `each` 是一个设计所代表的数值,须大于 0 +@msg `end` must be "start" or "end" `end` 必须是 "start" 或 "end" +@msg `ends` applies to joining exactly two paths `ends` 只适用于恰好连接两条路径的情况 +@msg `event` must be one of {_1} `event` 必须是 {_1} 之一 +@msg `every` must be "all", "odd" or "even", not {v} `every` 必须是 "all"、"odd" 或 "even",不能是 {v} +@msg `expand` must be true or false `expand` 必须为 true 或 false +@msg `files` must be 1 to 1000 paths of font files the last text.findFontFiles search found `files` 必须是上次 text.findFontFiles 搜索找到的 1 到 1000 个字体文件路径 +@msg `folder` must be an absolute folder path `folder` 必须是文件夹的绝对路径 +@msg `fontAxes` must be an object of axis tags and values, such as {"wght"} `fontAxes` 必须是由轴标签和值组成的对象,例如 {"wght"} +@msg `format` must be a string `format` 必须是字符串 +@msg `format` must be one of {_1} `format` 必须是 {_1} 之一 +@msg `fractions` is chop or scale `fractions` 为 chop 或 scale +@msg `from` and `to` must differ `from` 和 `to` 必须不同 +@msg `from` has an empty frame `from` 的文本框为空 +@msg `from` must be a non-negative integer `from` 必须是非负整数 +@msg `from` must be area type or type on a path `from` 必须是区域文字或路径文字 +@msg `gid` must be a glyph id, not {v} `gid` 必须是字形 ID,不能是 {v} +@msg `glyphAlternate` belongs to one character, not to a character style (text.setGlyphAlternate sets it) `glyphAlternate` 属于单个字符,不属于字符样式 (由 text.setGlyphAlternate 设置) +@msg `guide` must be a guide index (guide.list) `guide` 必须是参考线索引 (guide.list) +@msg `hAlign` must be default, left, center or right `hAlign` 必须是 default、left、center 或 right +@msg `id` must be a node id `id` 必须是节点 ID +@msg `id` must be an object id, not {v} `id` 必须是对象 ID,不能是 {v} +@msg `ids` must name Objects on Path groups or objects in them `ids` 必须指定“路径上的对象”组或其中的对象 +@msg `ids` takes at most {MAX_INSPECT_IDS} ids `ids` 最多接受 {MAX_INSPECT_IDS} 个 ID +@msg `imageMap` must be none, rectangle or polygon `imageMap` 必须是 none、rectangle 或 polygon +@msg `includeArtboardFill` must be true or false `includeArtboardFill` 必须为 true 或 false +@msg `includeSubdirs` must be true or false `includeSubdirs` 必须为 true 或 false +@msg `index` must be a point index `index` 必须是点索引 +@msg `index` must be a whole number or null `index` 必须是整数或 null +@msg `indices` must be a non-empty array of item indices `indices` 必须是项目索引的非空数组 +@msg `items` is a list of {kind, item} `items` 是 {kind, item} 的列表 +@msg `items` is empty `items` 为空 +@msg `items` must be a list of {id, points} `items` 必须是 {id, points} 的列表 +@msg `items` must be a list of {{id, anchors?}}, not {v} `items` 必须是 {{id, anchors?}} 的列表,不能是 {v} +@msg `items` must be an array of {id, anchors} `items` 必须是 {id, anchors} 的数组 +@msg `items` must be an array of {{id, corners?}}, not {v} `items` 必须是 {{id, corners?}} 的数组,不能是 {v} +@msg `kashida` must be "none", "short", "medium", "long" or "stylistic" `kashida` 必须是 "none"、"short"、"medium"、"long" 或 "stylistic" +@msg `kind` is one of {_1} `kind` 为 {_1} 之一 +@msg `kind` must be "round", "invertedRound" or "chamfer", not {v} `kind` 必须是 "round"、"invertedRound" 或 "chamfer",不能是 {v} +@msg `kind` must be `text`, `visibility`, `image` or `graph` `kind` 必须是 `text`、`visibility`、`image` 或 `graph` +@msg `kind` must be a string `kind` 必须是字符串 +@msg `kind` must be image, noImage or htmlText `kind` 必须是 image、noImage 或 htmlText +@msg `kinsoku` must be "none", "hard" or "soft" `kinsoku` 必须是 "none"、"hard" 或 "soft" +@msg `label` must be a non-empty name of at most 200 characters `label` 必须是不超过 200 个字符的非空名称 +@msg `language` must be a language name or tag, such as "Turkish" or "tr" `language` 必须是语言名称或标签,例如 "Turkish" 或 "tr" +@msg `leadingModel` must be "romanBaseline" or "emBoxTop" `leadingModel` 必须是 "romanBaseline" 或 "emBoxTop" +@msg `leading` must be from 0.1 to 5000, or null for Auto `leading` 必须为 0.1 到 5000,或用 null 表示自动 +@msg `length` must be a number of at most 1000000 pt either way `length` 必须是数字,正负方向均不超过 1000000 pt +@msg `line` must be true or false `line` 必须为 true 或 false +@msg `minAngle` ({min_angle}°) can't be more than `maxAngle` ({max_angle}°) `minAngle` ({min_angle}°) 不能大于 `maxAngle` ({max_angle}°) +@msg `mode` must be "handles", "straight" or "smooth" `mode` 必须是 "handles"、"straight" 或 "smooth" +@msg `mode` must be "straight", "bezier" or "arc" `mode` 必须是 "straight"、"bezier" 或 "arc" +@msg `mode` must be one of {_1} `mode` 必须是 {_1} 之一 +@msg `mojikumi` must be "none", "yakumonoHankaku", "gyomatsuYakumonoHankaku", "gyomatsuYakumonoZenkaku", "yakumonoZenkaku" or "lineEndHalf" `mojikumi` 必须是 "none"、"yakumonoHankaku"、"gyomatsuYakumonoHankaku"、"gyomatsuYakumonoZenkaku"、"yakumonoZenkaku" 或 "lineEndHalf" +@msg `names` is a list of preset names `names` 是预设名称的列表 +@msg `names` lists preset names `names` 用于列出预设名称 +@msg `names` must be a list of names `names` 必须是名称的列表 +@msg `names` must be a list of swatch names `names` 必须是色板名称的列表 +@msg `names` must be an array of style names `names` 必须是样式名称的数组 +@msg `new` is a design name, or true `new` 是设计名称,或 true +@msg `path` must be a folder `path` 必须是文件夹 +@msg `path` must be a path object `path` 必须是路径对象 +@msg `pivot` must be a whole number from 0 to 8 `pivot` 必须是 0 到 8 之间的整数 +@msg `points` must be a list of [x, y] points `points` 必须是 [x, y] 点的列表 +@msg `points` must be a list of point indexes `points` 必须是点索引的列表 +@msg `points` must be an array of point indices `points` 必须是点索引的数组 +@msg `points` must be point indexes `points` 必须是点索引 +@msg `port` must be "in" or "out" `port` 必须是 "in" 或 "out" +@msg `position` is above or below `position` 为 above 或 below +@msg `preset` must be a string `preset` 必须是字符串 +@msg `ratio` must be from 0.1 to 0.5 `ratio` 必须为 0.1 到 0.5 +@msg `rect` must be [x, y, width, height] with a positive size `rect` 必须是尺寸为正的 [x, y, width, height] +@msg `relation` must be overlap, inside or outside `relation` 必须是 overlap、inside 或 outside +@msg `reversed` must be true or false `reversed` 必须为 true 或 false +@msg `rotate` must be a finite number `rotate` 必须是有限的数字 +@msg `rule` must be nonZero or evenOdd `rule` 必须是 nonZero 或 evenOdd +@msg `scale` must be a number in (0, 100] `scale` 必须是 (0, 100] 范围内的数字 +@msg `scope` must be "selection" or "document", not {other} `scope` 必须是 "selection" 或 "document",不能是 {other} +@msg `script` must be a string `script` 必须是字符串 +@msg `seriesIndexes` is a non-empty list of series indexes `seriesIndexes` 是系列索引的非空列表 +@msg `seriesIndexes` needs a `type` or a `valueAxis` `seriesIndexes` 需要 `type` 或 `valueAxis` +@msg `shift` must be a number of points `shift` 必须是以点为单位的数字 +@msg `showCenter` must be true or false `showCenter` 必须为 true 或 false +@msg `singleWordJustification` must be "fullJustify", "alignLeft", "alignCenter" or "alignRight" `singleWordJustification` 必须是 "fullJustify"、"alignLeft"、"alignCenter" 或 "alignRight" +@msg `size` is a percentage of the base text's size, 1 to 100 `size` 是相对于基础文本大小的百分比,取值 1 到 100 +@msg `source` and `target` are the same object `source` 和 `target` 是同一个对象 +@msg `source` must be `folder` or `datasets` `source` 必须是 `folder` 或 `datasets` +@msg `spacing` must be a number `spacing` 必须是数字 +@msg `spacing` must be a number of points, 0 or more, or "auto" `spacing` 必须是以点为单位且大于或等于 0 的数字,或 "auto" +@msg `start` must be a finite number `start` 必须是有限的数字 +@msg `starts` must be an array of anchor indices (or nulls) `starts` 必须是锚点索引 (或 null) 的数组 +@msg `status` must be linked, embedded, missing or modified, or a list of them `status` 必须是 linked、embedded、missing 或 modified,或由它们组成的列表 +@msg `stop` must be a stop index `stop` 必须是色标索引 +@msg `story` styles the whole story: give no `start` or `end` `story` 为整篇文章设置样式:请不要给出 `start` 或 `end` +@msg `story` takes the whole story: give no `start` or `end` `story` 针对整篇文章:请不要给出 `start` 或 `end` +@msg `strokeMode` applies to strokes (stroke: true) `strokeMode` 适用于描边 (stroke: true) +@msg `style` must be roman or japanese `style` 必须是 roman 或 japanese +@msg `subpaths` must be two integer indices `subpaths` 必须是两个整数索引 +@msg `symbol` must be a symbol name `symbol` 必须是符号名称 +@msg `target` must be "object" or "contents", not {v} `target` 必须是 "object" 或 "contents",不能是 {v} +@msg `tint` applies to global and spot colours `tint` 适用于全局色和专色 +@msg `tint` goes with a global or spot `swatch` `tint` 要与全局色或专色的 `swatch` 一起给出 +@msg `tint` must be a number (%) `tint` 必须是数字 (%) +@msg `tint` needs a global or spot colour `tint` 需要全局色或专色 +@msg `to` is already threaded `to` 已被串接 +@msg `to` is the design's new name `to` 是设计的新名称 +@msg `to` must be [x, y] `to` 必须是 [x, y] +@msg `to` must be a closed path, area type or type on a path other than `from` `to` 必须是 `from` 以外的闭合路径、区域文字或路径文字 +@msg `to` must be a whole number `to` 必须是整数 +@msg `to` takes the rows of one object's stack, not aligned rows `to` 接受的是单个对象堆栈中的行,不是对齐的行 +@msg `useLab` must be true or false `useLab` 必须为 true 或 false +@msg `vAlign` must be default, top, middle, baseline or bottom `vAlign` 必须是 default、top、middle、baseline 或 bottom +@msg `values` must be a list `values` 必须是列表 +@msg `values` must be an object `values` 必须是对象 +@msg `values` must name hex, rgb, cmyk, lab or gray `values` 必须指定 hex、rgb、cmyk、lab 或 gray +@msg `values` names a kind twice `values` 重复指定了同一种类型 +@msg `{_1}` can't be edited or removed `{_1}` 不能编辑或移除 +@msg `{_1}` is built in and always listed `{_1}` 是内置项,始终会列出 +@msg `{_1}` is not a font file the last text.findFontFiles search found `{_1}` 不是上次 text.findFontFiles 搜索找到的字体文件 +@msg `{_1}` would be overwritten by the package: choose a different folder or name 打包会覆盖 `{_1}`:请选择其他文件夹或名称 +@msg `{file}` has no art to place `{file}` 中没有可置入的图稿 +@msg `{file}` is over {_1} MB `{file}` 超过 {_1} MB +@msg `{f}` belongs to a VectorCraft that is running `{f}` 属于正在运行的 VectorCraft +@msg `{f}` is the copy of a document open now `{f}` 是当前已打开文档的副本 +@msg `{id}` is no writable format (see document.formats) `{id}` 不是可写入的格式 (参见 document.formats) +@msg `{id}` isn't a loaded library `{id}` 不是已载入的库 +@msg `{key}` has no colours `{key}` 中没有颜色 +@msg `{key}` is a design name `{key}` 是设计名称 +@msg `{key}` is a design name or a list of them `{key}` 是一个设计名称或设计名称的列表 +@msg `{key}` is longer than {MAX_NAME} characters `{key}` 超过 {MAX_NAME} 个字符 +@msg `{key}` is out of range `{key}` 超出范围 +@msg `{key}` must be [min, desired, max] or {{min?, desired?, max?}}, in percent `{key}` 必须是以百分比表示的 [min, desired, max] 或 {{min?, desired?, max?}} +@msg `{key}` must be a non-negative integer `{key}` 必须是非负整数 +@msg `{key}` must be a number {_1}..{_2} `{key}` 必须是 {_1}..{_2} 的数字 +@msg `{key}` must be a whole number of at least 0, not {n} `{key}` 必须是不小于 0 的整数,不能是 {n} +@msg `{key}` must be an appearance item index (paint order) or null `{key}` 必须是外观项索引 (绘制顺序) 或 null +@msg `{key}` must be an array of asset ids (see assets.list) `{key}` 必须是资源 ID 的数组 (参见 assets.list) +@msg `{key}` must be from 0 to 180 degrees, not {a} `{key}` 必须为 0 到 180 度,不能是 {a} +@msg `{key}` must be from {_1} to {shift_max} `{key}` 必须介于 {_1} 到 {shift_max} 之间 +@msg `{key}`: not a colour: {v} `{key}`:不是颜色:{v} +@msg `{k}.family` is required 必须给出 `{k}.family` +@msg `{k}` is a number 0..1 `{k}` 是 0..1 的数字 +@msg `{k}` is true or false `{k}` 为 true 或 false +@msg `{k}` isn't an export setting: {_1} `{k}` 不是导出设置:{_1} +@msg `{k}` must be a byte offset `{k}` 必须是字节偏移 +@msg `{k}` must be a number `{k}` 必须是数字 +@msg `{k}` must be a number of points `{k}` 必须是以点为单位的数字 +@msg `{k}` must be a string `{k}` 必须是字符串 +@msg `{k}` must be a whole number `{k}` 必须是整数 +@msg `{k}` must be from {lo} to {hi} for {key} 对于 {key},`{k}` 必须介于 {lo} 到 {hi} 之间 +@msg `{k}` must be {what}, not {v} `{k}` 必须是 {what},不能是 {v} +@msg `{l}` isn't a global or spot colour `{l}` 不是全局色或专色 +@msg `{m}` isn't a bitmap: use clipboard.importSvg, importPdf or importText `{m}` 不是位图:请使用 clipboard.importSvg、importPdf 或 importText +@msg `{name}` can't be deleted `{name}` 不能删除 +@msg `{name}` can't be duplicated `{name}` 不能复制 +@msg `{name}` can't be edited `{name}` 不能编辑 +@msg `{name}` can't be edited this way `{name}` 不能以这种方式编辑 +@msg `{name}` can't be renamed `{name}` 不能重命名 +@msg `{name}` can't name a folder `{name}` 不能用作文件夹名称 +@msg `{name}` has no art to place `{name}` 中没有可置入的图稿 +@msg `{name}` has no text to place `{name}` 中没有可置入的文本 +@msg `{name}` in the Word document is not UTF-8 or UTF-16 text Word 文档中的 `{name}` 不是 UTF-8 或 UTF-16 文本 +@msg `{name}` in the Word document is not well-formed XML: {e} Word 文档中的 `{name}` 不是格式正确的 XML:{e} +@msg `{name}` in the Word document nests elements more than {MAX_NESTING} deep Word 文档中的 `{name}` 的元素嵌套超过 {MAX_NESTING} 层 +@msg `{name}` is a built-in preset and is read-only: save it under another name `{name}` 是内置预设,为只读:请用其他名称保存 +@msg `{name}` is a built-in preset: save under another name `{name}` 是内置预设:请用其他名称保存 +@msg `{name}` is a built-in profile and stays `{name}` 是内置配置文件,会保留 +@msg `{name}` is a tint of `{base}`: edit `{base}` (a tint swatch only takes a new name) `{name}` 是 `{base}` 的色调:请编辑 `{base}` (色调色板只能改名) +@msg `{name}` is a working space: choose another with edit.colorSettings first `{name}` 是工作空间:请先用 edit.colorSettings 选择另一个 +@msg `{name}` is built in and stays `{name}` 是内置项,会保留 +@msg `{name}` takes a paint of its own kind (colour, gradient or pattern) `{name}` 只接受同类的上色 (颜色、渐变或图案) +@msg `{n}` can't be deleted `{n}` 不能删除 +@msg `{n}` can't be merged `{n}` 不能合并 +@msg `{n}` can't be moved `{n}` 不能移动 +@msg `{n}` is not a colour swatch `{n}` 不是颜色色板 +@msg `{n}` isn't a solid colour `{n}` 不是纯色 +@msg `{n}`: colour groups hold solid colours only `{n}`:颜色组只能包含纯色 +@msg `{other}` doesn't trace an image `{other}` 不能描摹图像 +@msg `{s}`: the step's references copy in more than {_1} MB of values `{s}`:该步骤的引用会复制超过 {_1} MB 的值 +@msg `{tag}` is not an axis tag: a tag is four characters, such as "wght" `{tag}` 不是轴标签:标签为四个字符,例如 "wght" +@msg `{to}` is empty or already used `{to}` 为空或已被使用 +@msg `{what}` is longer than {MAX_TEXT} bytes `{what}` 的长度超过 {MAX_TEXT} 字节 +@msg `{what}` must be text `{what}` 必须是文本 +@msg a DXF drawing has one origin: pass useArtboards: true for one drawing per artboard 一个 DXF 图形只有一个原点:要让每个画板各成一个图形,请传入 useArtboards: true +@msg a PDF presets file with over {_1} presets PDF 预设文件中的预设超过 {_1} 个 +@msg a batch preview cannot switch documents 批处理预览不能切换文档 +@msg a brush named `{nn}` exists 已存在名为 `{nn}` 的画笔 +@msg a container of the listed objects is gone 所列对象的某个容器已不存在 +@msg a content stream can't be read 有一个内容流无法读取 +@msg a content stream isn't a stream 有一个内容流不是数据流 +@msg a design holds at most {_1} objects 一个设计最多包含 {_1} 个对象 +@msg a design needs a name 设计需要名称 +@msg a dictionary grew too large 有一个字典变得过大 +@msg a document keeps at most {_1} graph designs 一个文档最多保留 {_1} 个图表设计 +@msg a document keeps at most {_1} saved selections 一个文档最多保留 {_1} 个已保存的选区 +@msg a document keeps at most {_1} views 一个文档最多保留 {_1} 个视图 +@msg a document links at most {MAX_SVG_SCRIPTS} JavaScript files 一个文档最多链接 {MAX_SVG_SCRIPTS} 个 JavaScript 文件 +@msg a feConvolveMatrix filter's order is {x}×{y}, which overflows the kernel-size multiply usvg makes 某个 feConvolveMatrix 滤镜的 order 为 {x}×{y},会使 usvg 计算卷积核大小的乘法溢出 +@msg a gradient preset is already called {n} 已有名为 {n} 的渐变预设 +@msg a graph has at most {_1} series, so it transposes with at most that many categories 一个图表最多有 {_1} 个系列,因此转置时类别数不能超过这个数量 +@msg a layer can't be merged into its own sublayer 图层不能合并到自己的子图层中 +@msg a layer's form box isn't an array 某个图层的表单外框不是数组 +@msg a layer's form can't be read 某个图层的表单无法读取 +@msg a layer's form has no box 某个图层的表单没有外框 +@msg a layer's form has no dictionary 某个图层的表单没有字典 +@msg a legend draws at most {MAX_CHIPS} swatches 一个图例最多绘制 {MAX_CHIPS} 个色板 +@msg a name names one asset: give multiple: false, or one object 一个名称只对应一个资源:请给出 multiple: false,或只给出一个对象 +@msg a page can't be read 有一个页面无法读取 +@msg a page object is used by something else 有一个页面对象已被其他内容使用 +@msg a page thumbnail must be RGB pixels, 1 to {THUMBNAIL_SIZE} a side (got {w} × {h}) 页面缩略图必须是 RGB 像素,每边 1 到 {THUMBNAIL_SIZE} 像素 (实际为 {w} × {h}) +@msg a pattern layer doesn't end what it starts 某个图案图层没有结束它开始的内容 +@msg a pattern layer's colors hold something else 某个图案图层的颜色中含有其他内容 +@msg a pattern named `{n}` exists 已存在名为 `{n}` 的图案 +@msg a plug-in with id {_1} is already installed 已安装 ID 为 {_1} 的增效工具 +@msg a preset named `{n}` exists 已存在名为 `{n}` 的预设 +@msg a print presets file with over {_1} presets 打印预设文件中的预设超过 {_1} 个 +@msg a profile is already called {n} 已有名为 {n} 的配置文件 +@msg a row can't go into itself 行不能放入其自身 +@msg a series goes on the left or the right value axis 系列只能放在左侧或右侧的数值轴上 +@msg a start must be an anchor index ≥ 0 or null 起点必须是 ≥ 0 的锚点索引或 null +@msg a style named `{name}` already exists 已存在名为 `{name}` 的样式 +@msg a style named `{to}` already exists 已存在名为 `{to}` 的样式 +@msg a swatch needs a colour, gradient or pattern 色板需要颜色、渐变或图案 +@msg a symbol named `{n}` already exists 已存在名为 `{n}` 的符号 +@msg a theme has 1 to {THEME_SIZE} colours 一个主题有 1 到 {THEME_SIZE} 种颜色 +@msg a theme is already called {name} (replace: "{name}" overwrites it) 已有名为 {name} 的主题 (replace: "{name}" 会覆盖它) +@msg a toolbar name has at most {MAX_NAME} characters 工具栏名称最多 {MAX_NAME} 个字符 +@msg a view named `{_1}` exists 已存在名为 `{_1}` 的视图 +@msg a view named `{name}` exists 已存在名为 `{name}` 的视图 +@msg a workspace keeps at most {MAX} toolbars 一个工作区最多保留 {MAX} 个工具栏 +@msg a {_1} series can't go in a {_2} graph {_1} 系列不能放入 {_2} 图表 +@msg aiVersion {v}: "pdf" (PDF-compatible, the default) or "7" (legacy .ai, version 7) aiVersion {v}:"pdf" (兼容 PDF,默认值) 或 "7" (旧版 .ai,版本 7) +@msg already editing an opacity mask 已在编辑不透明度蒙版 +@msg already editing another object's opacity mask 已在编辑另一个对象的不透明度蒙版 +@msg already in pattern editing mode 已处于图案编辑模式 +@msg an artboard is listed twice 有一个画板被列出了两次 +@msg an empty artboard has no width or height to scale to 空画板没有可供缩放的宽度或高度 +@msg an image is too large for DXF and was left out 有一个图像对 DXF 而言过大,已被略去 +@msg an image of {_1} MB, at most {_2} MB 图像为 {_1} MB,最多允许 {_2} MB +@msg an image of {declared_w} × {declared_h} pixels is too large to draw {declared_w} × {declared_h} 像素的图像过大,无法绘制 +@msg an image of {width} × {height} pixels is too large to draw {width} × {height} 像素的图像过大,无法绘制 +@msg an index must be a whole number 索引必须是整数 +@msg an inline graphic has no glyphs 有一个随文图形没有字形 +@msg an invisible text form can't be read 有一个不可见文本表单无法读取 +@msg an object is missing 缺少一个对象 +@msg an object's header is missing 缺少某个对象的头部 +@msg an overprinting form can't be read 有一个叠印表单无法读取 +@msg an unread object has no readable bounds 有一个未读取的对象没有可读取的边界 +@msg an unread object holds a frame of threaded type 有一个未读取的对象包含串接文字的文本框 +@msg an unread object is missing from its layer 有一个未读取的对象不在其图层中 +@msg anchor `smooth` must be true or false 锚点的 `smooth` 必须为 true 或 false +@msg anchor `{key}` must be [x, y] 锚点的 `{key}` 必须是 [x, y] +@msg anchor `{key}` must be a number 锚点的 `{key}` 必须是数字 +@msg angle and roundness must be finite angle 和 roundness 必须是有限值 +@msg angles must be a list as long as pins (degrees or null) angles 必须是与 pins 等长的列表 (度数或 null) +@msg appearance must be flat|center|edge appearance 必须是 flat|center|edge +@msg apply is "fill" or "stroke", not `{other}` apply 为 "fill" 或 "stroke",不能是 `{other}` +@msg area must be a closed polygon of 3 to 100000 [x, y] points area 必须是由 3 到 100000 个 [x, y] 点组成的闭合多边形 +@msg area type needs a path that encloses an area 区域文字需要一条围出区域的路径 +@msg area type {_1} is named twice 区域文字 {_1} 被指定了两次 +@msg arrowAlign must be extend|tip, got {o} arrowAlign 必须是 extend|tip,实际为 {o} +@msg arrowScale must be [start, end] arrowScale 必须是 [start, end] +@msg artboard is a 0-based index artboard 是从 0 开始的索引 +@msg artboard must be a 0-based index artboard 必须是从 0 开始的索引 +@msg artboard {i} doesn't print 画板 {i} 不打印 +@msg artboardLayout must be {layout?, columns?, spacing?, rightToLeft?} artboardLayout 必须是 {layout?, columns?, spacing?, rightToLeft?} +@msg artboardLayout.columns must be 1 or more artboardLayout.columns 必须大于或等于 1 +@msg artboardLayout.layout must be gridByRow, gridByColumn, row or column artboardLayout.layout 必须是 gridByRow、gridByColumn、row 或 column +@msg artboardLayout.rightToLeft must be true or false artboardLayout.rightToLeft 必须为 true 或 false +@msg artboardLayout.spacing must be 0–{MAX_SPACING} pt artboardLayout.spacing 必须为 0–{MAX_SPACING} pt +@msg artboards must be a non-empty list artboards 必须是非空列表 +@msg artboards must be a number artboards 必须是数字 +@msg asset `{_1}` has no art to export 资源 `{_1}` 中没有可导出的图稿 +@msg at most {MAX_KEYWORDS} keywords 最多 {MAX_KEYWORDS} 个关键字 +@msg at most {MAX_MATCHES} matches are kept 最多保留 {MAX_MATCHES} 个匹配项 +@msg at most {MAX_POINTS} points 最多 {MAX_POINTS} 个点 +@msg at most {MAX_QUEUE} files 最多 {MAX_QUEUE} 个文件 +@msg at must be [x, y] at 必须是 [x, y] +@msg at/rect lie outside the canvas at/rect 位于画布之外 +@msg attribute must be size|leading|tracking|kerning|baselineShift attribute 必须是 size|leading|tracking|kerning|baselineShift +@msg attrs must be an object attrs 必须是对象 +@msg automation path rejected: the folder's name isn't valid text 自动化路径被拒绝:文件夹名称不是有效的文本 +@msg automation path rejected: {_1} isn't valid text 自动化路径被拒绝:{_1} 不是有效的文本 +@msg automation path rejected: {why}: {path} 自动化路径被拒绝:{why}:{path} +@msg axis must be "vertical", "horizontal" or an angle in degrees, not `{given}` axis 必须是 "vertical"、"horizontal" 或以度为单位的角度,不能是 `{given}` +@msg backgroundContents must be transparent or white backgroundContents 必须是 transparent 或 white +@msg bad AES key AES 密钥无效 +@msg bad `runs`: {e} `runs` 无效:{e} +@msg bad arrowScale arrowScale 无效 +@msg bad base64 base64 无效 +@msg bad color {c} 颜色 {c} 无效 +@msg bad colour 颜色无效 +@msg bad colour in `colors` `colors` 中有无效的颜色 +@msg bad colour {v} 颜色 {v} 无效 +@msg bad colour {v} in groupColors groupColors 中的颜色 {v} 无效 +@msg bad cross-reference entry 交叉引用条目无效 +@msg bad cross-reference table 交叉引用表无效 +@msg bad current colour {v} 当前颜色 {v} 无效 +@msg bad dataBase64 dataBase64 无效 +@msg bad edit 编辑无效 +@msg bad fill {v} 填色 {v} 无效 +@msg bad fit: {e} 适合方式无效:{e} +@msg bad model {other} (keep, new or document) 模型 {other} 无效 (keep、new 或 document) +@msg bad new colour {v} 新颜色 {v} 无效 +@msg bad object 对象无效 +@msg bad object number 对象编号无效 +@msg bad offset 偏移无效 +@msg bad path data: {e} 路径数据无效:{e} +@msg bad point {v}: expected [x, y] or [x, y, pressure] 点 {v} 无效:应为 [x, y] 或 [x, y, pressure] +@msg bad reference 引用无效 +@msg bad trailer size 尾部的大小无效 +@msg bad {k} colour {k} 颜色无效 +@msg batches cannot nest 批处理不能嵌套 +@msg bind something to a variable first 请先将某个对象绑定到变量 +@msg bleed must be 0–{MAX_BLEED} pt: a number, [top, bottom, left, right] or {{top, bottom, left, right}} bleed 必须为 0–{MAX_BLEED} pt:一个数字、[top, bottom, left, right] 或 {{top, bottom, left, right}} +@msg brush must be a name or null brush 必须是名称或 null +@msg by must be a number by 必须是数字 +@msg can't add page thumbnails: {why} 无法添加页面缩略图:{why} +@msg can't add the editing data for other apps: {why} 无法添加供其他应用使用的编辑数据:{why} +@msg can't edit the written PDF: {why} 无法编辑已写出的 PDF:{why} +@msg can't encrypt the PDF: {why} 无法加密 PDF:{why} +@msg can't linearise the PDF: {why} 无法线性化 PDF:{why} +@msg can't open `{_1}`: {_2} 无法打开 `{_1}`:{_2} +@msg can't open `{_1}`: {e} 无法打开 `{_1}`:{e} +@msg can't open `{name}`: not a format VectorCraft reads (see document.formats) 无法打开 `{name}`:不是 VectorCraft 可读取的格式 (参见 document.formats) +@msg can't place `{name}`: not a format VectorCraft reads (see document.formats) 无法置入 `{name}`:不是 VectorCraft 可读取的格式 (参见 document.formats) +@msg can't read back the written PDF: {e} 无法读回已写出的 PDF:{e} +@msg can't read this Word document: {why} 无法读取此 Word 文档:{why} +@msg can't write .{e} images: use .png, .jpg, .gif, .webp, .tif or .bmp 无法写出 .{e} 图像:请使用 .png、.jpg、.gif、.webp、.tif 或 .bmp +@msg can't write PDF layers, overprint or invisible text: {why} 无法写出 PDF 图层、叠印或不可见文本:{why} +@msg can't write the file's copyright: {why} 无法写入文件的版权信息:{why} +@msg can't write the file's modification date: {why} 无法写入文件的修改日期:{why} +@msg can't write the pages' user units: {why} 无法写入页面的用户单位:{why} +@msg cannot distort a zero-size or non-finite bounding box 无法扭曲大小为零或非有限的定界框 +@msg cannot move an object into itself 不能将对象移入其自身 +@msg case must be upper|lower|title|sentence case 必须是 upper|lower|title|sentence +@msg category `{c}`: one of {_1} 类别 `{c}`:应为 {_1} 之一 +@msg center must be [x, y] center 必须是 [x, y] +@msg choose at least one artboard 请至少选择一个画板 +@msg choose at least one status 请至少选择一种状态 +@msg clip must be true or false clip 必须为 true 或 false +@msg clippingMask must be true or false clippingMask 必须为 true 或 false +@msg closed must be a boolean closed 必须是布尔值 +@msg collapsed must be true or false collapsed 必须为 true 或 false +@msg color.profile: no RGB or CMYK profile is called “{profile}” color.profile:没有名为“{profile}”的 RGB 或 CMYK 配置文件 +@msg colorMode must be rgb or cmyk, not `{m}` colorMode 必须是 rgb 或 cmyk,不能是 `{m}` +@msg colorModel must be {own} (the document's mode), grayscale or bitmap colorModel 必须是 {own} (文档的模式)、grayscale 或 bitmap +@msg colour groups can't go into colour groups 颜色组不能放入颜色组 +@msg colour, mode and spot apply to solid-colour swatches only colour、mode 和 spot 只适用于纯色色板 +@msg column {column}: `{cell}` is a `%` column of graph data files, which are not read 第 {column} 列:`{cell}` 是图表数据文件的 `%` 列,不会读取 +@msg column {column}: `{cell}` names `{name}`, which is a {_1} variable 第 {column} 列:`{cell}` 指定了 `{name}`,而它是 {_1} 变量 +@msg column {column}: `{cell}` names no variable 第 {column} 列:`{cell}` 没有对应的变量 +@msg column {column}: the variable name is longer than {MAX_NAME} characters 第 {column} 列:变量名称超过 {MAX_NAME} 个字符 +@msg column: true floats the whole column and takes no onto, above or below column: true 会使整列浮动,不能再给出 onto、above 或 below +@msg command must be a shape.* command command 必须是 shape.* 命令 +@msg commands[{i}]: missing `command` commands[{i}]:缺少 `command` +@msg composer must be "singleLine" or "everyLine" composer 必须是 "singleLine" 或 "everyLine" +@msg compound shapes take paths, compound paths, groups, compound shapes, type, blends and envelopes 复合形状接受路径、复合路径、编组、复合形状、文字、混合和封套 +@msg compound {_1} must contain exactly one open path to join 复合对象 {_1} 必须恰好包含一条要连接的开放路径 +@msg connect needs a path other than the one extended connect 需要一条不同于被延伸路径的路径 +@msg connect needs id connect 需要 id +@msg connect path has no open end connect 的路径没有开放的端点 +@msg copy needs path: the file to copy into the document's folder copy 需要 path:即要复制到文档所在文件夹的文件 +@msg copy takes images only: relink placed documents where their files are copy 只接受图像:置入的文档请在其文件所在位置重新链接 +@msg copying a file isn't available on the web 网页版无法复制文件 +@msg copyrightStatus must be unknown, copyrighted or publicDomain copyrightStatus 必须是 unknown、copyrighted 或 publicDomain +@msg copyrightUrl must be a URL (no spaces, at most 2048 characters) copyrightUrl 必须是 URL (不含空格,最多 2048 个字符) +@msg corners must be 4 [x, y] points (TL, TR, BR, BL) corners 必须是 4 个 [x, y] 点 (TL, TR, BR, BL) +@msg counterPer `{c}`: item or file counterPer `{c}`:应为 item 或 file +@msg crop `{_1}`: only PDF pages have art, trim, bleed and media boxes; use "crop" or "bounding" crop `{_1}`:只有 PDF 页面才有 art、trim、bleed 和 media 框;请使用 "crop" 或 "bounding" +@msg crop rectangle doesn't overlap the image 裁剪矩形与图像不重叠 +@msg cross-reference and object streams aren't supported 不支持交叉引用流和对象流 +@msg damaged compressed data: {e} 压缩数据已损坏:{e} +@msg dash lengths must be numbers, got {v} 虚线长度必须是数字,实际为 {v} +@msg dash must be a list of lengths or null, got {v} dash 必须是长度的列表或 null,实际为 {v} +@msg data key `{k}`: letters, digits, -, _ and . (not name or vc-…) 数据键 `{k}`:只能使用字母、数字、-、_ 和 . (不能是 name 或 vc-…) +@msg data must be an object of key: value, not {v} data 必须是 key: value 形式的对象,不能是 {v} +@msg data set `{name}` holds a value for `{var}`, which the library doesn't declare 数据集 `{name}` 含有 `{var}` 的值,而库中没有声明该变量 +@msg data set `{name}` holds two values for `{var}` 数据集 `{name}` 含有 `{var}` 的两个值 +@msg data set `{name}` is declared twice 数据集 `{name}` 被声明了两次 +@msg data takes at most {MAX_DATA} keys at once data 一次最多接受 {MAX_DATA} 个键 +@msg dataset `{name}` already exists 数据集 `{name}` 已存在 +@msg dataset `{to}` already exists 数据集 `{to}` 已存在 +@msg date `{d}`: YYYY-MM-DD 日期 `{d}`:应为 YYYY-MM-DD +@msg decoded data is too large 解码后的数据过大 +@msg define a variable first 请先定义一个变量 +@msg detect must be true or false detect 必须为 true 或 false +@msg direct-select anchor points of a path 请直接选择路径的锚点 +@msg distance must be > 0 distance 必须 > 0 +@msg dx and dy give the arrow's direction dx 和 dy 给出箭头的方向 +@msg dx and dy must be numbers dx 和 dy 必须是数字 +@msg dxf fitTo must be [width, height], positive dxf 的 fitTo 必须是正数 [width, height] +@msg dxf must be an object of DXF import options dxf 必须是 DXF 导入选项的对象 +@msg dxf scale must be a positive number up to {_1}, not {s} dxf 的 scale 必须是不超过 {_1} 的正数,不能是 {s} +@msg dxf unit `{u}`: a unit such as mm, cm, in or pt dxf 的 unit `{u}`:应为 mm、cm、in 或 pt 之类的单位 +@msg dxf: {e} dxf:{e} +@msg each format is an object {format, scale?, suffix?} 每个格式都是对象 {format, scale?, suffix?} +@msg each item needs an id 每一项都需要 id +@msg each match needs `kind` 每个匹配项都需要 `kind` +@msg each match needs a `name` 每个匹配项都需要 `name` +@msg each of `fonts` is {family, style?}; 1 to 1000 of them `fonts` 的每一项为 {family, style?};共 1 到 1000 项 +@msg each of `items` is {kind, item} `items` 的每一项为 {kind, item} +@msg each of `items` is {{id, corners?}} with an object id, not {it} `items` 的每一项为带对象 ID 的 {{id, corners?}},不能是 {it} +@msg each row needs `from` 每一行都需要 `from` +@msg each stop needs a position 每个色标都需要位置 +@msg each subpath needs an anchors array 每条子路径都需要 anchors 数组 +@msg easingType must be easeIn, easeOut, easeInOut or easeOutIn easingType 必须是 easeIn、easeOut、easeInOut 或 easeOutIn +@msg editingData must be true or false editingData 必须为 true 或 false +@msg editingData must be true, false or "always" editingData 必须为 true、false 或 "always" +@msg edits overlap 编辑范围相互重叠 +@msg effects of objects whose appearances differ can't be moved together 外观不同的对象的效果不能一起移动 +@msg empty header in column {_1} 第 {_1} 列的标题为空 +@msg encoding `{_1}`: utf8 or utf16 编码 `{_1}`:应为 utf8 或 utf16 +@msg ends must be two of "first" and "last" ends 必须是两个取自 "first" 和 "last" 的值 +@msg every numbered name for the result is taken 可用于结果的带编号名称都已被占用 +@msg expanded SVG styles exceed the import size limit 展开后的 SVG 样式超出了导入大小上限 +@msg export presets file is larger than {MAX_PRESET_FILE_BYTES} bytes 导出预设文件大于 {MAX_PRESET_FILE_BYTES} 字节 +@msg exportText must be editable or appearance exportText 必须是 editable 或 appearance +@msg exportType must be movieClip or graphic, not `{s}` exportType 必须是 movieClip 或 graphic,不能是 `{s}` +@msg extend needs id extend 需要 id +@msg featureChanges lists at most {MAX_FEATURE_CHANGES} tags featureChanges 最多列出 {MAX_FEATURE_CHANGES} 个标签 +@msg featureChanges must be a list of tags featureChanges 必须是标签的列表 +@msg features must be a list of tags features 必须是标签的列表 +@msg fidelity must be 0..100 fidelity 必须为 0..100 +@msg files must be {name, dataBase64} files 必须是 {name, dataBase64} +@msg fit must be none|autoHeight|shrinkText|block, got {id} fit 必须是 none|autoHeight|shrinkText|block,实际为 {id} +@msg flattener: {e} 拼合器:{e} +@msg flattenerPreset `{name}`: high, medium, low or a saved one (see flattener.presets.list) flattenerPreset `{name}`:应为 high、medium、low 或已保存的预设 (参见 flattener.presets.list) +@msg flipProfile must be along|across, got {o} flipProfile 必须是 along|across,实际为 {o} +@msg folders `{f}`: none, rows, format, item or itemFormat folders `{f}`:应为 none、rows、format、item 或 itemFormat +@msg folders deeper than {MAX_BATCH_DEPTH} levels 文件夹层级超过 {MAX_BATCH_DEPTH} 层 +@msg folders deeper than {MAX_DEPTH} levels 文件夹层级超过 {MAX_DEPTH} 层 +@msg font family `{family}` is not available 字体系列 `{family}` 不可用 +@msg font family `{tf}` is not available 字体系列 `{tf}` 不可用 +@msg format `{f}`: pdf or postscript 格式 `{f}`:应为 pdf 或 postscript +@msg format `{f}`: text or json 格式 `{f}`:应为 text 或 json +@msg format is `{format}` 格式为 `{format}` +@msg formats must be an array of rows, not {v} formats 必须是行的数组,不能是 {v} +@msg frequency must be between 1 and 300 lines per inch frequency 必须介于每英寸 1 到 300 线之间 +@msg from and to must be finite from 和 to 必须是有限值 +@msg from must be [x0, y0, x1, y1] from 必须是 [x0, y0, x1, y1] +@msg give `before` or `after`, not both 请给出 `before` 或 `after`,不能两者都给 +@msg give `colors`, or `color` and `rule` 请给出 `colors`,或 `color` 和 `rule` +@msg give `event`, such as onclick 请给出 `event`,例如 onclick +@msg give `file`, the JavaScript file's path or URL 请给出 `file`,即 JavaScript 文件的路径或 URL +@msg give `fill` and/or `stroke` 请给出 `fill` 和/或 `stroke` +@msg give `fill`, `stroke` or both 请给出 `fill`、`stroke` 或两者 +@msg give `folder` 请给出 `folder` +@msg give `fonts`, or open a document 请给出 `fonts`,或打开一个文档 +@msg give `from` or `indices`, not both 请给出 `from` 或 `indices`,不能两者都给 +@msg give `id` (no text is being edited) 请给出 `id` (当前没有正在编辑的文本) +@msg give `id` and `anchors`, or `items`, not both 请给出 `id` 和 `anchors`,或给出 `items`,不能两者都给 +@msg give `id` or `guide`, not both 请给出 `id` 或 `guide`,不能两者都给 +@msg give `length` or `to` 请给出 `length` 或 `to` +@msg give `matches`: [{kind, name, target}] 请给出 `matches`: [{kind, name, target}] +@msg give `name` (or edit a pattern) 请给出 `name` (或编辑一个图案) +@msg give `name` or `names` 请给出 `name` 或 `names` +@msg give `path` (a .wasm file) or `dataBase64` (the module) 请给出 `path` (.wasm 文件) 或 `dataBase64` (模块) +@msg give `path`, `data` or `dataBase64` 请给出 `path`、`data` 或 `dataBase64` +@msg give `path`, `data`, `dataBase64` or `csv` 请给出 `path`、`data`、`dataBase64` 或 `csv` +@msg give `path`, `xml` or `dataBase64` 请给出 `path`、`xml` 或 `dataBase64` +@msg give `script`, the JavaScript the event runs ("" removes the event) 请给出 `script`,即事件要运行的 JavaScript ("" 会移除该事件) +@msg give `text` (the reading) or `remove` 请给出 `text` (读音) 或 `remove` +@msg give `x` and `y` (and a `tolerance` of 0 or more) 请给出 `x` 和 `y` (以及大于或等于 0 的 `tolerance`) +@msg give a mode or r/g/b, c/m/y/k, gray or tint adjustments 请给出模式,或 r/g/b、c/m/y/k、gray 或 tint 的调整值 +@msg give a name, or paint the active proxy with a saved preset 请给出名称,或用已保存的预设为当前代理上色 +@msg give a name, or select a stroke with a saved profile 请给出名称,或选择使用已保存配置文件的描边 +@msg give a pattern name or select an object painted with a pattern 请给出图案名称,或选择用图案上色的对象 +@msg give at least one of clip, invert, disabled, linked 请至少给出 clip、invert、disabled、linked 之一 +@msg give color, none, swatch or gradient 请给出 color、none、swatch 或 gradient +@msg give dataBase64 请给出 dataBase64 +@msg give either at (a click) or area (a path drawn around the overlaps) 请给出 at (一次单击) 或 area (围绕重叠处绘制的路径) +@msg give formats or a preset, not both 请给出 formats 或一个预设,不能两者都给 +@msg give newName or delete 请给出 newName 或 delete +@msg give offset or by 请给出 offset 或 by +@msg give one of `to`, `rect` or `at` 请给出 `to`、`rect` 或 `at` 之一 +@msg give one of assets, layers, selection or fullDocument 请给出 assets、layers、selection 或 fullDocument 之一 +@msg give only one of onto, above, below, icon and a column place onto、above、below、icon 和列位置中只能给出一个 +@msg give origin: [x, y], or reset: true 请给出 origin: [x, y],或 reset: true +@msg give overprintFill, overprintStroke, showCenter, imageMap, url or note 请给出 overprintFill、overprintStroke、showCenter、imageMap、url 或 note +@msg give path (a file) or folder 请给出 path (文件) 或 folder +@msg give path, or name and dataBase64 请给出 path,或 name 和 dataBase64 +@msg give paths or files 请给出 paths 或 files +@msg give rows, rowHeight, columns or columnWidth 请给出 rows、rowHeight、columns 或 columnWidth +@msg give svg, or dataBase64 of an SVG or SVGZ file 请给出 svg,或 SVG/SVGZ 文件的 dataBase64 +@msg give text 请给出 text +@msg give the asset a name 请为资源命名 +@msg give the preset a `name` 请为预设给出 `name` +@msg give the preset a name 请为预设命名 +@msg give the preset a name (1–64 characters) 请为预设命名 (1–64 个字符) +@msg give the settings to change, e.g. {"formats"}]} 请给出要更改的设置,例如 {"formats"}]} +@msg give the style a name 请为样式命名 +@msg give two or more style `names` 请在 `names` 中给出两个或更多样式 +@msg give two or more swatches 请给出两个或更多色板 +@msg give x, y, or a handle's length or angle 请给出 x、y,或手柄的长度或角度 +@msg give {key, value} or {values} 请给出 {key, value} 或 {values} +@msg global must be true or false global 必须为 true 或 false +@msg glyph {_1} is not drawn for {ch} with the character's style (such as All Caps, Small Caps or a numeral system) 按该字符的样式 (例如全部大写、小型大写或某种数字系统),{ch} 不会绘制为字形 {_1} +@msg glyph {g} is not an alternate of {ch} in {_1} {_2} 在 {_1} {_2} 中,字形 {g} 不是 {ch} 的替代字形 +@msg gradient must be "objects" or "mesh" gradient 必须是 "objects" 或 "mesh" +@msg grays must be "profile" or "black", not `{g}` grays 必须是 "profile" 或 "black",不能是 `{g}` +@msg gridColors must be a preset name or two colours gridColors 必须是预设名称或两种颜色 +@msg gridSize must be small, medium or large gridSize 必须是 small、medium 或 large +@msg guide {g} is not selected 参考线 {g} 未被选中 +@msg handle must be 0..3 handle 必须为 0..3 +@msg hiddenObjects {v}: "layer" (the default), "omit" or "visible" hiddenObjects {v}:应为 "layer" (默认值)、"omit" 或 "visible" +@msg highlight a layer to merge into 请高亮显示要合并到的图层 +@msg highlight two or more rows in one layer or group 请在同一图层或编组中高亮显示两行或更多行 +@msg highlight two or more rows to merge 请高亮显示两行或更多行以合并 +@msg icon docks a panel in the icon column: use window.panel.dock icon 会将面板停放在图标列中:请使用 window.panel.dock +@msg id must be a dimension id id 必须是尺寸标注 ID +@msg image has no bounds 图像没有边界 +@msg image {_1} is linked already 图像 {_1} 已是链接图像 +@msg imageMap `{m}`: none, client or server imageMap `{m}`:应为 none、client 或 server +@msg index out of range 索引超出范围 +@msg instances must be 1..1000 instances 必须为 1..1000 +@msg invalid `color` `color` 无效 +@msg invalid anchor index {v}: expected a non-negative integer 锚点索引 {v} 无效:应为非负整数 +@msg invalid anchor reference {v}: expected [subpath, anchor] 锚点引用 {v} 无效:应为 [subpath, anchor] +@msg invalid angle 角度无效 +@msg invalid brush: {e} 画笔无效:{e} +@msg invalid color 颜色无效 +@msg invalid colour {c} 颜色 {c} 无效 +@msg invalid delta 增量无效 +@msg invalid point 点无效 +@msg invalid size 大小无效 +@msg invalid t t 无效 +@msg invalid tolerance 容差无效 +@msg its artboards all lie beyond the canvas (more than {_1} pt from the origin) 其画板全部位于画布之外 (距原点超过 {_1} pt) +@msg its clipping masks are nested too deeply 其剪切蒙版嵌套过深 +@msg its metadata has no description 其元数据没有说明 +@msg its metadata has no direct length 其元数据没有直接给出的长度 +@msg join two different paths 请连接两条不同的路径 +@msg justify must be auto|left|center|right|justifyAll justify 必须是 auto|left|center|right|justifyAll +@msg kbps must be a positive number, not {kbps} kbps 必须是正数,不能是 {kbps} +@msg keywords must be a list of words or a comma-separated string keywords 必须是单词的列表或以逗号分隔的字符串 +@msg keywords must be at most {MAX_KEYWORD} characters, without control characters keywords 的每一项最多 {MAX_KEYWORD} 个字符,且不含控制字符 +@msg kind must be 1, 2 or 3, or give a preset `name` (see perspective.presets.list) kind 必须是 1、2 或 3,或者给出预设的 `name` (参见 perspective.presets.list) +@msg kind must be graphic, fillColor, strokeColor, fillGradient, strokeGradient, fillPattern, strokePattern, charStyle or paraStyle kind 必须是 graphic、fillColor、strokeColor、fillGradient、strokeGradient、fillPattern、strokePattern、charStyle 或 paraStyle +@msg knockout must be "on", "off", "neutral" or a bool, not {v} knockout 必须是 "on"、"off"、"neutral" 或布尔值,不能是 {v} +@msg layer `{name}` has no art to export 图层 `{name}` 中没有可导出的图稿 +@msg layer must name a layer or sublayer layer 必须指定一个图层或子图层 +@msg layers can't be intertwined: select the objects in them 图层不能交织:请选择图层中的对象 +@msg layers go only at the top level or in layers, objects in layers and groups 图层只能位于顶层或图层内,对象只能位于图层和编组内 +@msg layers must be true or false layers 必须为 true 或 false +@msg layout must be gridByRow, gridByColumn, row or column layout 必须是 gridByRow、gridByColumn、row 或 column +@msg leading must be a number or "auto" leading 必须是数字或 "auto" +@msg left/right must be non-negative widths left/right 必须是非负的宽度 +@msg level `{t}`: 2 or 3 level `{t}`:应为 2 或 3 +@msg line {line}: more than {MAX_CSV_COLS} columns 第 {line} 行:超过 {MAX_CSV_COLS} 列 +@msg line {line}: unclosed quote 第 {line} 行:引号未闭合 +@msg line {line}: value for `{var}` must match its variable kind 第 {line} 行:`{var}` 的值必须与其变量类型相符 +@msg lineEndings `{other}`: lf or crlf lineEndings `{other}`:应为 lf 或 crlf +@msg loading profiles from disk isn't available in the browser 浏览器中无法从磁盘载入配置文件 +@msg margin: a {m} pt margin leaves no imageable area on the paper margin:{m} pt 的边距使纸张上没有可成像区域 +@msg matrix must be finite and invertible, depth finite matrix 必须是有限且可逆的,depth 必须是有限值 +@msg matte: {e} matte:{e} +@msg member is for order front, forward, backward or back member 用于 order 为 front、forward、backward 或 back 的情况 +@msg missing `artboards` 缺少 `artboards` +@msg missing `at` [x, y] 缺少 `at` [x, y] +@msg missing `attrs` 缺少 `attrs` +@msg missing `color` or `opacity` 缺少 `color` 或 `opacity` +@msg missing `colors` 缺少 `colors` +@msg missing `commands` 缺少 `commands` +@msg missing `destinationFolder` 缺少 `destinationFolder` +@msg missing `effect` id 缺少 `effect` ID +@msg missing `family` 缺少 `family` +@msg missing `find` 缺少 `find` +@msg missing `gid` (a glyph id, or null for the default glyph) 缺少 `gid` (字形 ID,或用 null 表示默认字形) +@msg missing `group` 缺少 `group` +@msg missing `id` 缺少 `id` +@msg missing `id`: give one, or select one type object 缺少 `id`:请给出一个,或选择一个文字对象 +@msg missing `index` (a point index, or null to clear) 缺少 `index` (点索引,或用 null 清除) +@msg missing `index` (a stop index, or null to clear) 缺少 `index` (色标索引,或用 null 清除) +@msg missing `index` (an item index or null) 缺少 `index` (项目索引或 null) +@msg missing `item` 缺少 `item` +@msg missing `library` 缺少 `library` +@msg missing `library` (see graphicStyle.libraries) 缺少 `library` (参见 graphicStyle.libraries) +@msg missing `library` (see swatch.library.list) 缺少 `library` (参见 swatch.library.list) +@msg missing `map` (rows [{from, to}] or {current}) 缺少 `map` (行 [{from, to}] 或 {current}) +@msg missing `matrix` [a,b,c,d,e,f] 缺少 `matrix` [a,b,c,d,e,f] +@msg missing `name` (see gradient.presets.list) 缺少 `name` (参见 gradient.presets.list) +@msg missing `offset` (a distance in points) 缺少 `offset` (以点为单位的距离) +@msg missing `path` 缺少 `path` +@msg missing `path` (a path object id) 缺少 `path` (路径对象 ID) +@msg missing `rule` 缺少 `rule` +@msg missing `source` id 缺少 `source` ID +@msg missing `start` (the byte offset of a character) 缺少 `start` (字符的字节偏移) +@msg missing `status`: linked, embedded, missing or modified 缺少 `status`:应为 linked、embedded、missing 或 modified +@msg missing `target` id 缺少 `target` ID +@msg missing `text` 缺少 `text` +@msg missing `to` 缺少 `to` +@msg missing `to` (an index) 缺少 `to` (索引) +@msg missing `to`: a non-negative integer 缺少 `to`:应为非负整数 +@msg missing `type` 缺少 `type` +@msg missing `value` 缺少 `value` +@msg missing `{key}` 缺少 `{key}` +@msg missing `{k}` 缺少 `{k}` +@msg missing anchor 缺少锚点 +@msg missing anchors 缺少锚点 +@msg missing anchors [[subpath, anchor]…] 缺少锚点 [[subpath, anchor]…] +@msg missing array `{key}` 缺少数组 `{key}` +@msg missing case 缺少 case +@msg missing color 缺少颜色 +@msg missing commands 缺少命令 +@msg missing destination folder 缺少目标文件夹 +@msg missing from 缺少 from +@msg missing group 缺少 group +@msg missing id or ids 缺少 id 或 ids +@msg missing ids 缺少 ids +@msg missing indexes 缺少 indexes +@msg missing matrix [a,b,c,d,e,f] 缺少 matrix [a,b,c,d,e,f] +@msg missing name 缺少名称 +@msg missing op 缺少 op +@msg missing or invalid `color` `color` 缺失或无效 +@msg missing or unknown `tool` `tool` 缺失或未知 +@msg missing point 缺少点 +@msg missing point [x,y] 缺少点 [x,y] +@msg missing point `{key}` ([x, y]) 缺少点 `{key}` ([x, y]) +@msg missing points 缺少点 +@msg missing points [[x,y]…] 缺少点 [[x,y]…] +@msg missing segment 缺少线段 +@msg missing stops 缺少色标 +@msg missing subpaths 缺少子路径 +@msg missing target 缺少目标 +@msg missing to 缺少 to +@msg missing x, y 缺少 x、y +@msg mode is set, add or toggle, not `{other}` mode 为 set、add 或 toggle,不能是 `{other}` +@msg mode must be "cmyk" or "rgb" mode 必须是 "cmyk" 或 "rgb" +@msg mode must be area|onPath, got {o} mode 必须是 area|onPath,实际为 {o} +@msg more than 10000 linked files: package dependencies in smaller parts 链接文件超过 10000 个:请分成较小的部分打包依赖项 +@msg more than 256 commands 命令超过 256 条 +@msg more than {MAX_BATCH_FILES} data sets 数据集超过 {MAX_BATCH_FILES} 个 +@msg more than {MAX_BATCH_FILES} files 文件超过 {MAX_BATCH_FILES} 个 +@msg more than {MAX_CSV_ROWS} data rows 数据行超过 {MAX_CSV_ROWS} 行 +@msg more than {MAX_FILES} images 图像超过 {MAX_FILES} 个 +@msg more than {MAX_IMPORT} presets 预设超过 {MAX_IMPORT} 个 +@msg moved must be [[x,y]…] moved 必须是 [[x,y]…] +@msg name (a toolbar's name) is required 必须给出 name (工具栏名称) +@msg name (a toolbar's name) must be a string name (工具栏名称) 必须是字符串 +@msg name must be a toolbar's name name 必须是工具栏的名称 +@msg names is empty names 为空 +@msg names must be an array of symbol names names 必须是符号名称的数组 +@msg need `anchor` or `segment` + `t` 需要 `anchor`,或 `segment` + `t` +@msg need at least one anchor 至少需要一个锚点 +@msg need at least one point 至少需要一个点 +@msg need at least two points 至少需要两个点 +@msg needs points 需要点 +@msg nineSlice must be true or false nineSlice 必须为 true 或 false +@msg nineSliceGuides must be [left, top, right, bottom], each -16..16, with left + right < 1 and top + bottom < 1 nineSliceGuides 必须是 [left, top, right, bottom],每个值为 -16..16,且 left + right < 1、top + bottom < 1 +@msg no PDF preset named `{n}` 没有名为 `{n}` 的 PDF 预设 +@msg no action set is current 当前没有动作组 +@msg no active data set 没有活动的数据集 +@msg no appearance item {index} 没有外观项 {index} +@msg no artboard {_1} 没有画板 {_1} +@msg no artboard {artboard} (0-based; the document has {_1}) 没有画板 {artboard} (从 0 开始计数;文档有 {_1} 个) +@msg no asset {id} 没有资源 {id} +@msg no asset {id} (see assets.list) 没有资源 {id} (参见 assets.list) +@msg no assets to export 没有可导出的资源 +@msg no assets yet: collect art for export first (assets.add) 还没有资源:请先收集要导出的图稿 (assets.add) +@msg no brush named `{n}` 没有名为 `{n}` 的画笔 +@msg no character at byte {start} 字节 {start} 处没有字符 +@msg no colour 没有颜色 +@msg no colour group `{group}` 没有颜色组 `{group}` +@msg no colour group `{name}` 没有颜色组 `{name}` +@msg no data sets 没有数据集 +@msg no dataset named `{from}` 没有名为 `{from}` 的数据集 +@msg no dataset named `{name}` 没有名为 `{name}` 的数据集 +@msg no datasets 没有数据集 +@msg no design named `{name}` 没有名为 `{name}` 的设计 +@msg no design named `{n}` 没有名为 `{n}` 的设计 +@msg no design named `{old}` 没有名为 `{old}` 的设计 +@msg no encoder for {_1} yet 还没有 {_1} 的编码器 +@msg no export preset `{name}` (see document.exportPresets.list) 没有导出预设 `{name}` (参见 document.exportPresets.list) +@msg no folder: pass `path` or set Preferences › Plug-ins & Scratch Disks › Additional Plug-ins Folder 没有文件夹:请传入 `path`,或设置 首选项 › 增效工具 & 暂存盘 › 附加增效工具文件夹 +@msg no fonts to look for: they are all available 没有需要查找的字体:字体全部可用 +@msg no formats to export 没有要导出的格式 +@msg no gradient preset `{name}` (see gradient.presets.list) 没有渐变预设 `{name}` (参见 gradient.presets.list) +@msg no graphic style `{n}` in `{_1}` `{_1}` 中没有图形样式 `{n}` +@msg no graphic style library `{key}` (see graphicStyle.libraries) 没有图形样式库 `{key}` (参见 graphicStyle.libraries) +@msg no guide selected 没有选中参考线 +@msg no guide selected (or give an index) 没有选中参考线 (或给出索引) +@msg no guide {i} 没有参考线 {i} +@msg no images in the folder 文件夹中没有图像 +@msg no item at index {_1} 索引 {_1} 处没有项目 +@msg no item at index {from} 索引 {from} 处没有项目 +@msg no item at one of the indices {idx} 索引 {idx} 中有一处没有项目 +@msg no layer 没有图层 +@msg no layer {id} (see layer.list) 没有图层 {id} (参见 layer.list) +@msg no layers to export 没有可导出的图层 +@msg no library `{key}` 没有库 `{key}` +@msg no metafile format 没有图元文件格式 +@msg no object {_1} 没有对象 {_1} +@msg no objects 没有对象 +@msg no parent layer 没有父图层 +@msg no perspective grid preset named `{b}` (see perspective.presets.list) 没有名为 `{b}` 的透视网格预设 (参见 perspective.presets.list) +@msg no perspective grid preset named `{n}` 没有名为 `{n}` 的透视网格预设 +@msg no point selected (give `index`) 没有选中点 (请给出 `index`) +@msg no preset called `{from}` (see file.newPresets) 没有名为 `{from}` 的预设 (参见 file.newPresets) +@msg no preset called `{name}` (see file.newPresets) 没有名为 `{name}` 的预设 (参见 file.newPresets) +@msg no preset named `{n}` 没有名为 `{n}` 的预设 +@msg no print preset named `{b}` (see print.presets.list) 没有名为 `{b}` 的打印预设 (参见 print.presets.list) +@msg no print preset named `{name}` (presets: {_1}) 没有名为 `{name}` 的打印预设 (现有预设:{_1}) +@msg no print preset named `{n}` 没有名为 `{n}` 的打印预设 +@msg no profile named `{name}` 没有名为 `{name}` 的配置文件 +@msg no readable files in the folder 文件夹中没有可读取的文件 +@msg no recovery copy `{f}` (see file.recovery.list) 没有恢复副本 `{f}` (参见 file.recovery.list) +@msg no rows 没有行 +@msg no saved PDF preset named `{name}` 没有名为 `{name}` 的已保存 PDF 预设 +@msg no saved export preset `{name}` 没有已保存的导出预设 `{name}` +@msg no saved gradient preset called {name} 没有名为 {name} 的已保存渐变预设 +@msg no saved gradient presets 没有已保存的渐变预设 +@msg no saved preset called `{name}` 没有名为 `{name}` 的已保存预设 +@msg no saved presets to export (name [Default] in `names` to export it) 没有可导出的已保存预设 (要导出 [Default],请在 `names` 中指定它) +@msg no saved presets to export (name built-in ones in `names`) 没有可导出的已保存预设 (内置预设请在 `names` 中指定) +@msg no saved print preset named `{name}` 没有名为 `{name}` 的已保存打印预设 +@msg no saved profile called {name} 没有名为 {name} 的已保存配置文件 +@msg no saved selection `{name}` 没有已保存的选区 `{name}` +@msg no saved theme called {name} (see colorTheme.list) 没有名为 {name} 的已保存主题 (参见 colorTheme.list) +@msg no saved views 没有已保存的视图 +@msg no series {i} 没有系列 {i} +@msg no slice {n} in the image (see slice.list) 图像中没有切片 {n} (参见 slice.list) +@msg no source art 没有源图稿 +@msg no stop {i} (the gradient has {n}) 没有色标 {i} (渐变有 {n} 个) +@msg no style `{name}` 没有样式 `{name}` +@msg no such assets (see assets.list) 没有这些资源 (参见 assets.list) +@msg no such frame anchor, or the frame would reach past the canvas 没有此文本框锚点,或文本框会超出画布 +@msg no such objects 没有这些对象 +@msg no such path anchor, or the path would reach past the canvas 没有此路径锚点,或路径会超出画布 +@msg no such rows 没有这些行 +@msg no swatch `{keep}` 没有色板 `{keep}` +@msg no swatch `{n}` 没有色板 `{n}` +@msg no swatch `{n}` (swatches and colour groups move separately) 没有色板 `{n}` (色板和颜色组要分别移动) +@msg no swatch library `{key}` (see swatch.library.list) 没有色板库 `{key}` (参见 swatch.library.list) +@msg no swatch library `{key}` (see swatch.library.list; "document": the document's swatches) 没有色板库 `{key}` (参见 swatch.library.list;"document" 表示文档的色板) +@msg no swatch library `{key}` (see swatch.library.list; "{DOCUMENT_SWATCHES}": the document's swatches) 没有色板库 `{key}` (参见 swatch.library.list;"{DOCUMENT_SWATCHES}" 表示文档的色板) +@msg no swatch named `{n}` 没有名为 `{n}` 的色板 +@msg no swatch or colour group `{n}` 没有色板或颜色组 `{n}` +@msg no swatch or colour group `{n}` in `{_1}` `{_1}` 中没有色板或颜色组 `{n}` +@msg no symbol named `{name}` 没有名为 `{name}` 的符号 +@msg no text objects selected 没有选中文本对象 +@msg no toolbar named `{_1}` 没有名为 `{_1}` 的工具栏 +@msg no toolbar named `{name}` 没有名为 `{name}` 的工具栏 +@msg no tracing preset `{preset}` (see imageTrace.presets) 没有描摹预设 `{preset}` (参见 imageTrace.presets) +@msg no user library folder here (save with a path, or without one to get the data) 这里没有用户库文件夹 (请指定路径保存,或不指定路径以取得数据) +@msg no variable named `{from}` 没有名为 `{from}` 的变量 +@msg no variable named `{name}` 没有名为 `{name}` 的变量 +@msg no variable named `{var}` 没有名为 `{var}` 的变量 +@msg no variable named `{v}` 没有名为 `{v}` 的变量 +@msg no view named `{name}` 没有名为 `{name}` 的视图 +@msg node {_1} is not a graph 节点 {_1} 不是图表 +@msg node {_1} is not an image 节点 {_1} 不是图像 +@msg node {_1} is not type 节点 {_1} 不是文字 +@msg not a PDF presets file (format `{_1}`) 不是 PDF 预设文件 (格式为 `{_1}`) +@msg not a PDF presets file: {e} 不是 PDF 预设文件:{e} +@msg not a Word document: its WordDocument stream doesn't start with a file information block 不是 Word 文档:其 WordDocument 流不是以文件信息块开头 +@msg not a Word document: its compound file has no WordDocument stream 不是 Word 文档:其复合文件中没有 WordDocument 流 +@msg not a Word document: its main part is not a WordprocessingML document 不是 Word 文档:其主部件不是 WordprocessingML 文档 +@msg not a Word document: its package has no main document part 不是 Word 文档:其包中没有主文档部件 +@msg not a closed path 不是闭合路径 +@msg not a flattener presets file (format `{_1}`) 不是拼合器预设文件 (格式为 `{_1}`) +@msg not a flattener presets file: {e} 不是拼合器预设文件:{e} +@msg not a layer or group 不是图层或编组 +@msg not a library file: {e} 不是库文件:{e} +@msg not a mesh envelope point 不是网格封套的点 +@msg not a perspective grid presets file (format `{_1}`) 不是透视网格预设文件 (格式为 `{_1}`) +@msg not a perspective grid presets file: {e} 不是透视网格预设文件:{e} +@msg not a print presets file (format `{_1}`) 不是打印预设文件 (格式为 `{_1}`) +@msg not a print presets file: {e} 不是打印预设文件:{e} +@msg not a stored or deflated central record 不是以存储或 deflate 方式保存的中央记录 +@msg not a valid SVGZ file: {e} 不是有效的 SVGZ 文件:{e} +@msg not an RTF file: it doesn't start with {\rtf 不是 RTF 文件:它不是以 {\rtf 开头 +@msg not an image VectorCraft reads (see document.formats) 不是 VectorCraft 可读取的图像 (参见 document.formats) +@msg not area type (text in a frame) outside perspective 不是透视之外的区域文字 (文本框中的文本) +@msg not editing an opacity mask 当前没有在编辑不透明度蒙版 +@msg not type on a path outside perspective 不是透视之外的路径文字 +@msg nothing prints 没有可打印的内容 +@msg nothing to bind 没有可绑定的内容 +@msg nothing to change 没有可更改的内容 +@msg nothing to change: give dx, dy, hScale, vScale or rotation 没有可更改的内容:请给出 dx、dy、hScale、vScale 或 rotation +@msg nothing to crop 没有可裁剪的内容 +@msg nothing to export 没有可导出的内容 +@msg nothing to export: the document has no visible art 没有可导出的内容:文档中没有可见的图稿 +@msg nothing to mark 没有可标记的内容 +@msg nothing to print: every artboard picked is blank 没有可打印的内容:所选的画板都是空白的 +@msg nothing to print: the document has no art that prints 没有可打印的内容:文档中没有会打印的图稿 +@msg object is not a path 对象不是路径 +@msg object transparency cannot be sampled onto highlighted characters; disable Transparency in Eyedropper Options or select the whole object 对象的透明度不能取样到高亮显示的字符上;请在吸管选项中停用“透明度”,或选择整个对象 +@msg object {_1} can't be set as point type 对象 {_1} 不能设为点文字 +@msg object {_1} has lost its file's contents: relink it 对象 {_1} 已丢失其文件的内容:请重新链接 +@msg object {_1} has no path 对象 {_1} 没有路径 +@msg object {_1} has no size 对象 {_1} 没有大小 +@msg object {_1} is hidden or locked, or on a locked artboard 对象 {_1} 已隐藏或锁定,或位于已锁定的画板上 +@msg object {_1} is not a placed document 对象 {_1} 不是置入的文档 +@msg object {_1} is not an Intertwine group 对象 {_1} 不是交织组 +@msg object {_1} is not an image 对象 {_1} 不是图像 +@msg object {_1} is not an image or a linked file 对象 {_1} 不是图像或链接文件 +@msg object {_1} is not an image or a placed document 对象 {_1} 不是图像或置入的文档 +@msg object {_1} is not in this Intertwine group 对象 {_1} 不在此交织组中 +@msg object {_1} needs a 3D effect at index {index} 对象 {_1} 在索引 {index} 处需要有 3D 效果 +@msg object {id} has anchors 0–{_1} for `corners`, not {past} 对象 {id} 可用于 `corners` 的锚点为 0–{_1},没有 {past} +@msg object {id} has {n} anchors, so no anchor {past} 对象 {id} 有 {n} 个锚点,因此没有锚点 {past} +@msg objects must be none, move or copy objects 必须是 none、move 或 copy +@msg objects were left out 有对象被略去 +@msg offset out of range 偏移超出范围 +@msg on must be true or false on 必须为 true 或 false +@msg only groups, layers, type and images have a Contents (Characters) row 只有编组、图层、文字和图像才有“内容 (字符)”行 +@msg only interior mesh lines can be deleted 只能删除内部的网格线 +@msg only solid colours can be added (not gradients or patterns) 只能添加纯色 (不能添加渐变或图案) +@msg only solid-colour swatches can be spot colours 只有纯色色板才能设为专色 +@msg only this Affinity file's embedded preview could be read: use File › Open to see it with its warning, or export SVG or PDF from Affinity first 只能读取此 Affinity 文件的嵌入预览:请使用 文件 › 打开 查看预览及其警告,或先从 Affinity 导出 SVG 或 PDF +@msg only this Affinity file's embedded preview could be read; use File › Open to see it with its warning 只能读取此 Affinity 文件的嵌入预览;请使用 文件 › 打开 查看预览及其警告 +@msg onto, above, below, icon and a column place belong to window.panel.float and window.panel.dock onto、above、below、icon 和列位置属于 window.panel.float 和 window.panel.dock +@msg onto, above, below, icon and a column place take no anchor, side, zone or before onto、above、below、icon 和列位置不能与 anchor、side、zone 或 before 同时给出 +@msg onto, above, below, icon and a column place take no x, y, width or height onto、above、below、icon 和列位置不能与 x、y、width 或 height 同时给出 +@msg open a document to look for its linked files 请打开一个文档以查找其链接文件 +@msg options must be an object (see file.formatOptions) options 必须是对象 (参见 file.formatOptions) +@msg order must be leftToRight or rightToLeft order 必须是 leftToRight 或 rightToLeft +@msg orientation must be portrait or landscape, not `{o}` orientation 必须是 portrait 或 landscape,不能是 `{o}` +@msg outlineText {v}: true or false outlineText {v}:应为 true 或 false +@msg output intent profile: {e} 输出意图配置文件:{e} +@msg output.destination: no RGB or CMYK profile is called “{name}” output.destination:没有名为“{name}”的 RGB 或 CMYK 配置文件 +@msg output.destination: {_1} files are CMYK, and “{name}” is an RGB profile output.destination:{_1} 文件为 CMYK,而“{name}”是 RGB 配置文件 +@msg output.destination: {e} output.destination:{e} +@msg output.inks: no ink is set to print output.inks:没有设为打印的油墨 +@msg output.outputIntent: no profile is called “{name}”, and a {std} output intent embeds its profile output.outputIntent:没有名为“{name}”的配置文件,而 {std} 输出意图需要嵌入其配置文件 +@msg output.outputIntent: no profile is called “{name}”: a {std} output intent embeds a profile, or names a registered printing condition (outputConditionId and registry) output.outputIntent:没有名为“{name}”的配置文件:{std} 输出意图需要嵌入配置文件,或指定已注册的印刷条件 (outputConditionId 和 registry) +@msg output.outputIntent: {std} files print in CMYK, and “{name}” is an RGB profile output.outputIntent:{std} 文件以 CMYK 印刷,而“{name}”是 RGB 配置文件 +@msg output.outputIntent: “{name}” is a grey profile, which can't be a {std} output intent output.outputIntent:“{name}”是灰度配置文件,不能用作 {std} 输出意图 +@msg overlap: {o} pt is half a tile or more overlap:{o} pt 已达到或超过拼贴的一半 +@msg overlapping Shaper paths must be in the same layer or group 重叠的 Shaper 路径必须位于同一图层或编组中 +@msg overlapping edits 编辑范围相互重叠 +@msg page art conflicts with image data for {key} 页面图稿与 {key} 的图像数据冲突 +@msg page art conflicts with pattern {name} 页面图稿与图案 {name} 冲突 +@msg page art conflicts with swatch {name} 页面图稿与色板 {name} 冲突 +@msg page art is missing image data for {key} 页面图稿缺少 {key} 的图像数据 +@msg page art is missing pattern {name} 页面图稿缺少图案 {name} +@msg page art is missing swatch {name} 页面图稿缺少色板 {name} +@msg page must be a whole number from 1 page 必须是从 1 开始的整数 +@msg page thumbnail: {e} 页面缩略图:{e} +@msg page {page} of the PDF has no objects PDF 的第 {page} 页没有对象 +@msg page {page}: `{file}` has {n} {artboards} 第 {page} 页:`{file}` 有 {n} {artboards} +@msg page {page}: `{name}` has {n} {pages} 第 {page} 页:`{name}` 有 {n} {pages} +@msg pages must be a range such as "2-3" or a page number, not {v} pages 必须是 "2-3" 这样的范围或一个页码,不能是 {v} +@msg pages: {e} pages:{e} +@msg panel position must be finite 面板位置必须是有限值 +@msg parameters must be an object 参数必须是对象 +@msg params must be an object params 必须是对象 +@msg passwords can have up to {MAX_PASSWORD} bytes 密码最多 {MAX_PASSWORD} 字节 +@msg path has no open end 路径没有开放的端点 +@msg paths must be strings paths 必须是字符串 +@msg pdfCompatible: false needs every artboard to keep the editable artwork pdfCompatible: false 需要用全部画板来保留可编辑的图稿 +@msg pdfs `{m}`: single or multiple pdfs `{m}`:应为 single 或 multiple +@msg pickColorFrom is "artwork" or "swatches", not {v} pickColorFrom 为 "artwork" 或 "swatches",不能是 {v} +@msg pins and moved must be non-empty lists of the same length pins 和 moved 必须是长度相同的非空列表 +@msg pins must be [[x,y]…] pins 必须是 [[x,y]…] +@msg pins must be finite pins 必须是有限值 +@msg place is above, below or inside, not `{other}` place 为 above、below 或 inside,不能是 `{other}` +@msg plane must be left|right|ground plane 必须是 left|right|ground +@msg plane must be left|right|ground|none plane 必须是 left|right|ground|none +@msg point is outside the mesh 点位于网格之外 +@msg points must be [t, left, right] with non-negative widths points 必须是宽度非负的 [t, left, right] +@msg points must be a non-empty [[x,y,pressure?]…] list points 必须是非空的 [[x,y,pressure?]…] 列表 +@msg points must be a non-empty list of finite [x,y] points 必须是由有限 [x,y] 组成的非空列表 +@msg points must be an array or null points 必须是数组或 null +@msg points must be finite points 必须是有限值 +@msg points must be finite [x,y] pairs points 必须是有限的 [x,y] 对 +@msg points must contain 1–4096 coordinates points 必须包含 1–4096 个坐标 +@msg position must be normal, superscript or subscript position 必须是 normal、superscript 或 subscript +@msg position must be topLeft, topRight, bottomLeft or bottomRight position 必须是 topLeft、topRight、bottomLeft 或 bottomRight +@msg positions must be between 0 and 100000 pt positions 必须介于 0 到 100000 pt 之间 +@msg ppi must be a positive number, not {ppi} ppi 必须是正数,不能是 {ppi} +@msg ppi must be between 1 and 2400 ppi 必须介于 1 到 2400 之间 +@msg preserve `{v}` is not transforms|bounds|fileDimensions|fit|fill preserve `{v}` 不是 transforms|bounds|fileDimensions|fit|fill +@msg preserveShape must be clippingMask|transparency preserveShape 必须是 clippingMask|transparency +@msg preset `{id}`: mobile or density preset `{id}`:应为 mobile 或 density +@msg preset must be standard, diffuse, topLeft or right preset 必须是 standard、diffuse、topLeft 或 right +@msg preset must be the name of a print preset preset 必须是打印预设的名称 +@msg previewMode must be default, pixel or overprint previewMode 必须是 default、pixel 或 overprint +@msg print settings: {e} 打印设置:{e} +@msg procedures nest too deeply 过程嵌套过深 +@msg procedures nested too deeply 过程嵌套得过深 +@msg quotes must be {double?, single?} quotes 必须是 {double?, single?} +@msg quotes.{k} must be an opening and a closing quote, e.g. "“”" quotes.{k} 必须是一个左引号和一个右引号,例如 "“”" +@msg rasterEffectsPpi must be 1–2400 (72 screen, 150 medium, 300 high) rasterEffectsPpi 必须为 1–2400 (72 为屏幕,150 为中,300 为高) +@msg rating must be a whole number from 0 to {MAX_RATING} rating 必须是 0 到 {MAX_RATING} 之间的整数 +@msg rect and {k} contradict each other: give the area or the artboards rect 与 {k} 相互矛盾:请只给出区域或画板 +@msg rect applies to raster formats, not {_1} rect 适用于栅格格式,不适用于 {_1} +@msg rect is [x, y, width, height] in points rect 是以点为单位的 [x, y, width, height] +@msg rect must be [x, y, width, height] rect 必须是 [x, y, width, height] +@msg rect must be [x, y, width, height] with a positive width and height rect 必须是宽度和高度为正的 [x, y, width, height] +@msg rect needs finite numbers and a positive width and height rect 需要有限的数字以及为正的宽度和高度 +@msg redraw needs id redraw 需要 id +@msg redraw within must be a finite distance of 0 or more redraw 的 within 必须是大于或等于 0 的有限距离 +@msg registration must be 0..8 registration 必须为 0..8 +@msg release a layer or a group 请释放一个图层或编组 +@msg replace keeps the replaced object's place and transform: drop template, at and rect replace 会保留被替换对象的位置和变换:请去掉 template、at 和 rect +@msg replace: select the one object to replace replace:请选择要替换的那一个对象 +@msg resolution must be a number or screen|medium|high resolution 必须是数字或 screen|medium|high +@msg resolution must be between 1 and 2400 ppi resolution 必须介于 1 到 2400 ppi 之间 +@msg rotation must be a number of degrees rotation 必须是以度为单位的数字 +@msg rotation must be finite rotation 必须是有限值 +@msg rows and cols must be 1..50 rows 和 cols 必须为 1..50 +@msg rows and columns must be 1..500 rows 和 columns 必须为 1..500 +@msg rows of objects whose appearances differ can't be reordered together 外观不同的对象的行不能一起重新排序 +@msg save the document first: Package collects a saved document 请先保存文档:打包只收集已保存的文档 +@msg save the document first: copy puts the file in its folder 请先保存文档:copy 会把文件放到文档所在的文件夹中 +@msg savedPreset: {e} savedPreset:{e} +@msg scale `{s}`: a factor such as 2x, a width (100w), a height (100h) or a resolution (72ppi) scale `{s}`:应为 2x 这样的倍数、宽度 (100w)、高度 (100h) 或分辨率 (72ppi) +@msg scale must be a number above 0, at most 64 scale 必须是大于 0 且不超过 64 的数字 +@msg scale must be non-zero scale 不能为零 +@msg scope must be selection or all (got {other}) scope 必须是 selection 或 all (实际为 {other}) +@msg scribble is too long 涂抹线过长 +@msg segment does not exist 线段不存在 +@msg select a Shaper group 请选择一个 Shaper 组 +@msg select a blend to set easing or color shift 请选择一个混合对象以设置缓动或颜色偏移 +@msg select a compound shape 请选择一个复合形状 +@msg select a graph 请选择一个图表 +@msg select a group or layer with visible, unlocked members 请选择含有可见且未锁定成员的编组或图层 +@msg select a layer 请选择一个图层 +@msg select a text object 请选择一个文本对象 +@msg select an image (or an Image Trace group) 请选择一个图像 (或图像描摹组) +@msg select an image, or pass id 请选择一个图像,或传入 id +@msg select an object (or pass `id`) 请选择一个对象 (或传入 `id`) +@msg select an object with a freeform gradient 请选择带有自由渐变的对象 +@msg select an object with an opacity mask 请选择带有不透明度蒙版的对象 +@msg select area type 请选择区域文字 +@msg select area type (text in a frame) 请选择区域文字 (文本框中的文本) +@msg select area type and closed paths (at least one area type object) 请选择区域文字和闭合路径 (至少一个区域文字对象) +@msg select area type whose first line can fit its frame 请选择首行能放入其文本框的区域文字 +@msg select artwork to add its colours 请选择图稿以添加其颜色 +@msg select artwork to make a group of its colours 请选择图稿以用其颜色创建颜色组 +@msg select artwork to recolour, or give a colour `group` 请选择要重新着色的图稿,或给出颜色 `group` +@msg select exactly two path ends to join 请恰好选择两个要连接的路径端点 +@msg select members of a compound shape 请选择复合形状的成员 +@msg select objects or give ids 请选择对象或给出 ids +@msg select objects to align to the guide 请选择要与参考线对齐的对象 +@msg select one Intertwine group 请选择一个交织组 +@msg select one image or pass id 请选择一个图像或传入 id +@msg select paths 请选择路径 +@msg select paths or compound paths 请选择路径或复合路径 +@msg select rows or objects to collect 请选择要收集的行或对象 +@msg select something to export 请选择要导出的内容 +@msg select something to export (or turn off selectedOnly) 请选择要导出的内容 (或关闭 selectedOnly) +@msg select text to redefine the style from 请选择用来重新定义样式的文本 +@msg select the art and, on top of it, the mask object 请选择图稿以及位于其上方的蒙版对象 +@msg select the art for the design 请选择用于设计的图稿 +@msg select the art for the pattern tile 请选择用于图案拼贴的图稿 +@msg select the art to add first 请先选择要添加的图稿 +@msg select the art to collect (or give its ids) 请选择要收集的图稿 (或给出其 ids) +@msg select the content and a path on top 请选择内容以及位于其上方的一条路径 +@msg select the images to relink, or pass ids 请选择要重新链接的图像,或传入 ids +@msg select the images, or pass ids 请选择图像,或传入 ids +@msg select the linked images or placed documents, or pass ids 请选择链接的图像或置入的文档,或传入 ids +@msg select the object to copy from 请选择要从中复制的对象 +@msg select the objects (or give their ids) 请选择对象 (或给出其 ids) +@msg select the objects to attach to the path 请选择要附着到路径上的对象 +@msg select the objects to bind 请选择要绑定的对象 +@msg select two or more objects to intertwine 请选择两个或更多要交织的对象 +@msg select two or more slices to combine 请选择两个或更多要组合的切片 +@msg select type on a path 请选择路径文字 +@msg selection `{m}`: one or each selection `{m}`:应为 one 或 each +@msg settings is an object of document.exportForScreens params settings 是由 document.exportForScreens 的参数组成的对象 +@msg settings must be an object settings 必须是对象 +@msg show `{show}`: all, missing, modified or embedded show `{show}`:应为 all、missing、modified 或 embedded +@msg show must be true or false show 必须为 true 或 false +@msg size must be "small", "medium", "large" or a number of points over 0 up to {_1} size 必须是 "small"、"medium"、"large",或大于 0 且不超过 {_1} 的点数 +@msg size must be positive size 必须为正数 +@msg sizeMode is "fixed" or "pressure", not `{other}` sizeMode 为 "fixed" 或 "pressure",不能是 `{other}` +@msg sizeMode is "fixed" or "pressure", not {other} sizeMode 为 "fixed" 或 "pressure",不能是 {other} +@msg sizeVariation must be 0 or more sizeVariation 必须大于或等于 0 +@msg smallCaps must be true or false smallCaps 必须为 true 或 false +@msg sort `{x}`: name, kind or status sort `{x}`:应为 name、kind 或 status +@msg source paths are too large for Shaper 源路径对 Shaper 而言过大 +@msg spot, mode and group apply to solid colours only spot、mode 和 group 只适用于纯色 +@msg status `{s}`: linked, embedded, missing or modified status `{s}`:应为 linked、embedded、missing 或 modified +@msg steps must be 1..1000 steps 必须为 1..1000 +@msg steps must be 1..{MAX_STEPS} steps 必须为 1..{MAX_STEPS} +@msg stop {i}: `plates` must be four numbers from 0 to 1 (C, M, Y, K) 色标 {i}:`plates` 必须是四个 0 到 1 之间的数字 (C, M, Y, K) +@msg stopped before the archive was finished 在归档完成之前已停止 +@msg strokeMode must be within|along|across, got {m} strokeMode 必须是 within|along|across,实际为 {m} +@msg strokeOptions must be an object of stroke.set options strokeOptions 必须是由 stroke.set 的选项组成的对象 +@msg strokeWidth must be a positive number of pixels strokeWidth 必须是以像素为单位的正数 +@msg subpath {si} is not an open subpath 子路径 {si} 不是开放的子路径 +@msg subpaths required when joining the same path 连接同一条路径时必须给出 subpaths +@msg swatchConflict must be "merge" or "add", not {v} swatchConflict 必须是 "merge" 或 "add",不能是 {v} +@msg text must be {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} text 必须是 {characterSet?, platform?, removeLineReturns?, removeParagraphReturns?, replaceSpaces?} +@msg text transform is collapsed or unrepresentable 文本的变换已塌缩或无法表示 +@msg text.replaceSpaces must be a whole number from 2 to 100 text.replaceSpaces 必须是 2 到 100 之间的整数 +@msg text.{key} `{v}`: use "{_1}" or "{_2}" text.{key} `{v}`:请使用 "{_1}" 或 "{_2}" +@msg textureImage: give {path} or {name, dataBase64} of an image file, or a texture as effect.list gives it textureImage:请给出图像文件的 {path} 或 {name, dataBase64},或 effect.list 所给出的纹理 +@msg textureImage: {e} textureImage:{e} +@msg that makes more than {MAX_PIECES} slices 这样会生成超过 {MAX_PIECES} 个切片 +@msg that object is not in the overlap 该对象不在重叠处 +@msg the Affinity document has no page with a size Affinity 文档中没有带尺寸的页面 +@msg the CMYK image couldn't be written 无法写出 CMYK 图像 +@msg the PDF security settings were saved without their passwords: give openPassword or permissionsPassword again, or security without passwordRequired to export unprotected PDF 安全性设置保存时未包含密码:请重新给出 openPassword 或 permissionsPassword,或给出不含 passwordRequired 的 security 以便不加保护地导出 +@msg the RTF file has too many paragraphs or formatting changes to place as type (at most {MAX_PARAGRAPHS} paragraphs and {MAX_RUNS} runs) RTF 文件的段落或格式变化过多,无法作为文字置入 (最多 {MAX_PARAGRAPHS} 个段落和 {MAX_RUNS} 个文本段) +@msg the RTF file is too large to place as type (at most {_1} MB) RTF 文件过大,无法作为文字置入 (最多 {_1} MB) +@msg the SVG expands to more than {0} nested SVG images SVG 展开后的嵌套 SVG 图像超过 {0} 个 +@msg the SVG expands to more than {0} objects SVG 展开后的对象超过 {0} 个 +@msg the SVG has no drawable objects SVG 中没有可绘制的对象 +@msg the SVGZ file unpacks to more than {_1} MB SVGZ 文件解压后超过 {_1} MB +@msg the Word document has more than {MAX_PAGES} pages of properties, too many to place Word 文档的属性页超过 {MAX_PAGES} 页,过多而无法置入 +@msg the Word document has more than {MAX_RUNS} runs of character or paragraph properties, too many to place Word 文档的字符或段落属性段超过 {MAX_RUNS} 个,过多而无法置入 +@msg the Word document has more than {_1} MB of formatting properties, too many to place Word 文档的格式属性超过 {_1} MB,过多而无法置入 +@msg the Word document has too much text or formatting to place as type (at most {MAX_PARAGRAPHS} paragraphs, {MAX_RUNS} runs and {_1} MB of text) Word 文档的文本或格式过多,无法作为文字置入 (最多 {MAX_PARAGRAPHS} 个段落、{MAX_RUNS} 个文本段和 {_1} MB 文本) +@msg the Word document has too much text to place as type (at most {_1} MB) Word 文档的文本过多,无法作为文字置入 (最多 {_1} MB) +@msg the Word document is encrypted or protected with a password; save it without one to place it Word 文档已加密或受密码保护;请去掉密码保存后再置入 +@msg the Word document is too large to place (its {name} stream holds more than {_1} MB) Word 文档过大,无法置入 (其 {name} 流超过 {_1} MB) +@msg the Word document was last saved with fast save, which VectorCraft doesn't read; save it again with fast save turned off Word 文档上次是以快速保存方式保存的,VectorCraft 无法读取;请关闭快速保存后重新保存 +@msg the Word document was saved by Word 6.0 or Word 95, which VectorCraft doesn't read; save it as a Word 97-2003 document Word 文档是由 Word 6.0 或 Word 95 保存的,VectorCraft 无法读取;请将其另存为 Word 97-2003 文档 +@msg the Word document's text is made of more than {MAX_PIECES} pieces, too many to place Word 文档的文本由超过 {MAX_PIECES} 个片段组成,过多而无法置入 +@msg the action set ids are not a list 动作组 ID 不是列表 +@msg the active paint is not a gradient 当前上色不是渐变 +@msg the artboards don't fit on the canvas: fewer artboards, less spacing or a smaller size 画板在画布上放不下:请减少画板、缩小间距或减小尺寸 +@msg the character's size can't be measured 无法测量该字符的大小 +@msg the compound shape is too complex to expand 复合形状过于复杂,无法扩展 +@msg the container of the listed objects is gone 所列对象的容器已不存在 +@msg the copy `{user_id}` can't be read as a library 副本 `{user_id}` 无法作为库读取 +@msg the copy would leave the canvas 副本会超出画布 +@msg the cut cannot be made on this art: {e} 无法在此图稿上进行切割:{e} +@msg the data isn't an EMF or WMF picture 该数据不是 EMF 或 WMF 图片 +@msg the data isn't an EPS or PostScript picture 该数据不是 EPS 或 PostScript 图片 +@msg the deferred paste is no longer available 延迟粘贴的内容已不可用 +@msg the design is too big to draw at every data point of this graph 设计过大,无法在此图表的每个数据点上绘制 +@msg the design is too big to draw in every column of this graph 设计过大,无法在此图表的每个柱形中绘制 +@msg the dialog it was opened over is no longer open 它所依附的对话框已不再打开 +@msg the dictionary stack overflowed 字典栈溢出 +@msg the editing data's hash has no place 编辑数据的哈希值没有存放位置 +@msg the entities the document declares expand to too much text 文档声明的实体展开后的文本过多 +@msg the envelope's content has no bounds 封套的内容没有边界 +@msg the envelope's mesh is malformed 封套的网格格式不正确 +@msg the file holds no `variableSets` element 文件中没有 `variableSets` 元素 +@msg the file is larger than {_1} MB 文件大于 {_1} MB +@msg the file is too large 文件过大 +@msg the file was updated or encrypted already 文件已被更新或加密 +@msg the first character of a line has no character before it to kern: it moves only up and down (dy) 行首字符前面没有可供调整字偶距的字符:它只能上下移动 (dy) +@msg the font {_1} is not available 字体 {_1} 不可用 +@msg the format has no file extension 该格式没有文件扩展名 +@msg the graphic can't be read: {e} 无法读取该图形:{e} +@msg the graphic is empty 该图形为空 +@msg the graphic's data is damaged 该图形的数据已损坏 +@msg the graphic's document has no artboard 该图形的文档没有画板 +@msg the header `{cell}` for `{name}` would read back as the variable `{other}`: rename one of them `{name}` 的标题 `{cell}` 读回时会被当作变量 `{other}`:请重命名其中一个 +@msg the image `{path}` isn't followed: {r} 未跟随图像 `{path}`:{r} +@msg the image has no embedded pixels 该图像没有嵌入的像素 +@msg the image is empty 图像为空 +@msg the image is fully transparent 图像完全透明 +@msg the image is not on an artboard; pass rect 图像不在画板上;请传入 rect +@msg the image's pixels are missing 图像的像素缺失 +@msg the image's pixels aren't in the document 图像的像素不在文档中 +@msg the image's pixels can't be read: {e} 无法读取图像的像素:{e} +@msg the image's transparency doesn't fit it 图像的透明度数据与图像不相符 +@msg the job would print more than {MAX_PAGES} pages 此作业会打印超过 {MAX_PAGES} 页 +@msg the job would print more than {_1} pages 此作业会打印超过 {_1} 页 +@msg the layers hold no art to mask 这些图层中没有可添加蒙版的图稿 +@msg the layout moved 布局已移动 +@msg the library has a group `{name}` already 库中已有组 `{name}` +@msg the library has no group `{name}` 库中没有组 `{name}` +@msg the library has no item `{item}` 库中没有项目 `{item}` +@msg the library has no item `{other}` 库中没有项目 `{other}` +@msg the library holds {MAX_GROUPS} groups already 库中已有 {MAX_GROUPS} 个组 +@msg the library holds {MAX_ITEMS} items of this kind already 库中已有 {MAX_ITEMS} 个此类项目 +@msg the name is empty 名称为空 +@msg the object has no fill, stroke or effect 该对象没有填色、描边或效果 +@msg the object has no graphic style (pass `name`) 该对象没有图形样式 (请传入 `name`) +@msg the objects don't match the plan 对象与计划不相符 +@msg the open and permissions passwords must differ 打开密码和权限密码必须不同 +@msg the operand stack overflowed 操作数栈溢出 +@msg the page has no area 该页面没有面积 +@msg the page's type in an unread object's box isn't in its page art 页面中位于某个未读取对象框内的文字不在其页面图稿中 +@msg the paint behind the proxy is not a gradient 代理对应的上色不是渐变 +@msg the parent must be a layer or sublayer 父项必须是图层或子图层 +@msg the path can't be extended 该路径无法延伸 +@msg the path can't be inside one of the objects to attach 路径不能位于要附着的某个对象内部 +@msg the path has no segments to measure 该路径没有可测量的线段 +@msg the path is empty 路径为空 +@msg the path is too short to shorten that much 路径太短,无法缩短这么多 +@msg the picture has no objects 图片中没有对象 +@msg the program runs too long 程序运行时间过长 +@msg the program uses too much memory 程序占用的内存过多 +@msg the rectangle must have a width and a height 矩形必须有宽度和高度 +@msg the rectangle needs a size and must lie on the canvas 矩形需要有大小,且必须位于画布上 +@msg the selected art has no width 所选图稿没有宽度 +@msg the selection draws nothing 所选对象没有绘制任何内容 +@msg the selection has no area 所选对象没有面积 +@msg the selection has no art to export 所选对象中没有可导出的图稿 +@msg the selection has no bounds 所选对象没有边界 +@msg the selection has no graphic style 所选对象没有图形样式 +@msg the slice would leave the canvas 切片会超出画布 +@msg the spot colour couldn't be added 无法添加该专色 +@msg the subpath has no ends to extend (it is closed or a single point) 该子路径没有可延伸的端点 (它是闭合的或只有一个点) +@msg the symbols are nested too deeply to expand their instances 符号嵌套过深,无法扩展其实例 +@msg the text file is too large to place as type (at most {_1} MB) 文本文件过大,无法作为文字置入 (最多 {_1} MB) +@msg the text is empty 文本为空 +@msg the text is over {_1} MB 文本超过 {_1} MB +@msg the top object must be a path 最上方的对象必须是路径 +@msg the trace was cancelled 描摹已取消 +@msg the trailer has no size 尾部没有大小 +@msg the type object is flattened to nothing 文字对象拼合后没有任何内容 +@msg the value of axis `{tag}` must be a number or null 轴 `{tag}` 的值必须是数字或 null +@msg the variable library declares more than {MAX_LIBRARY_DATASETS} data sets 变量库声明的数据集超过 {MAX_LIBRARY_DATASETS} 个 +@msg the variable library declares more than {MAX_LIBRARY_ENTITIES} entities 变量库声明的实体超过 {MAX_LIBRARY_ENTITIES} 个 +@msg the variable library declares more than {MAX_LIBRARY_VARIABLES} variables 变量库声明的变量超过 {MAX_LIBRARY_VARIABLES} 个 +@msg the variable library declares no variables 变量库没有声明任何变量 +@msg the variable library is larger than {MAX_LIBRARY_BYTES} bytes 变量库大于 {MAX_LIBRARY_BYTES} 字节 +@msg the variable library is not UTF-8 变量库不是 UTF-8 +@msg the variable library is not well-formed XML: {e} 变量库不是格式正确的 XML:{e} +@msg the variable library nests elements more than {MAX_LIBRARY_NESTING} deep 变量库的元素嵌套超过 {MAX_LIBRARY_NESTING} 层 +@msg the variable library's document type declaration holds something other than entities of plain text 变量库的文档类型声明中含有纯文本实体以外的内容 +@msg the variable library's entities expand to more than {MAX_LIBRARY_BYTES} bytes 变量库的实体展开后超过 {MAX_LIBRARY_BYTES} 字节 +@msg the window has no dock 该窗口没有停放区 +@msg the written PDF has no catalog 已写出的 PDF 没有目录 +@msg the written PDF has no cross-reference table 已写出的 PDF 没有交叉引用表 +@msg the written PDF's metadata can't be edited 无法编辑已写出的 PDF 的元数据 +@msg there are no colour swatches to draw 没有可绘制的颜色色板 +@msg there is already a design named `{name}` 已有名为 `{name}` 的设计 +@msg there is already a design named `{to}` 已有名为 `{to}` 的设计 +@msg there is already a toolbar named `{name}` 已有名为 `{name}` 的工具栏 +@msg there is already a toolbar named `{to}` 已有名为 `{to}` 的工具栏 +@msg there is no library: create one first 没有库:请先创建一个 +@msg these paths are too degenerate for Shaper 这些路径过于退化,Shaper 无法处理 +@msg thumbnail: no page {v} (the {what} has {count}) thumbnail:没有第 {v} 页 ({what} 有 {count} 页) +@msg tileRange of {what}: {e} {what} 的 tileRange:{e} +@msg title can't be empty title 不能为空 +@msg to (the new name) is required 必须给出 to (新名称) +@msg to must be fill or stroke to 必须是 fill 或 stroke +@msg to must be smooth or corner to 必须是 smooth 或 corner +@msg too large for a zip archive: package to a folder 对 zip 归档而言过大:请打包到文件夹 +@msg too many Shaper edits Shaper 编辑过多 +@msg too many `points` (at most 100000) `points` 过多 (最多 100000 个) +@msg too many characters: at most {MAX_CHARS} 字符过多:最多 {MAX_CHARS} 个 +@msg too many dots for this size: lower the frequency 此尺寸下的网点过多:请降低频率 +@msg too many filters over one file 单个文件上的滤镜过多 +@msg too many overlapping paths for Shaper 重叠的路径过多,Shaper 无法处理 +@msg too many saved clips 已保存的剪切过多 +@msg too many saved graphics states 已保存的图形状态过多 +@msg toolbar (a toolbar's name) must be a string toolbar (工具栏名称) 必须是字符串 +@msg toolbar name can't be empty 工具栏名称不能为空 +@msg transparentImages {v}: "flatten" (the default) or "omit" transparentImages {v}:应为 "flatten" (默认值) 或 "omit" +@msg two saved selections would be named `{_1}` 会有两个已保存的选区都名为 `{_1}` +@msg type dimension cannot be represented with this text transform 无法用此文本变换表示文字尺寸 +@msg type dimension must be finite 文字尺寸必须是有限值 +@msg unexpected resources 出现了意外的资源 +@msg unknown CMYK profile `{name}` 未知的 CMYK 配置文件 `{name}` +@msg unknown File Info field `{k}` 未知的文件信息字段 `{k}` +@msg unknown OpenType feature `{t}` in featureChanges (the tags `features` takes) featureChanges 中有未知的 OpenType 特性 `{t}` (应为 `features` 接受的标签) +@msg unknown PDF preset `{name}` (presets: {_1}) 未知的 PDF 预设 `{name}` (现有预设:{_1}) +@msg unknown Warp style 未知的变形样式 +@msg unknown alignToPath `{a}` 未知的 alignToPath `{a}` +@msg unknown arrowhead {v} 未知的箭头 {v} +@msg unknown artboardLayout key `{k}` (layout, columns, spacing, rightToLeft) 未知的 artboardLayout 键 `{k}` (layout、columns、spacing、rightToLeft) +@msg unknown attribute `{attribute}` 未知的属性 `{attribute}` +@msg unknown attribute `{k}` 未知的属性 `{k}` +@msg unknown axis `{other}` (vertical|horizontal|free) 未知的轴 `{other}` (vertical|horizontal|free) +@msg unknown blend mode `{b}` 未知的混合模式 `{b}` +@msg unknown blend mode {b} 未知的混合模式 {b} +@msg unknown brush type `{o}` 未知的画笔类型 `{o}` +@msg unknown category `{c}` 未知的类别 `{c}` +@msg unknown category `{c}` ({_1}) 未知的类别 `{c}` ({_1}) +@msg unknown character `{c}` 未知的字符 `{c}` +@msg unknown character style number field 未知的字符样式数值字段 +@msg unknown effect `{e}` 未知的效果 `{e}` +@msg unknown end {e} 未知的端点 {e} +@msg unknown flattenerPreset `{name}` (High Resolution, Medium Resolution, Low Resolution or a saved one: see flattener.presets.list) 未知的 flattenerPreset `{name}` (应为 High Resolution、Medium Resolution、Low Resolution 或已保存的预设:参见 flattener.presets.list) +@msg unknown format `{f}` (vcswatches, gpl, ase or css) 未知的格式 `{f}` (vcswatches、gpl、ase 或 css) +@msg unknown from {f} 未知的 from {f} +@msg unknown graph type `{t}` 未知的图表类型 `{t}` +@msg unknown grid colours `{name}` (one of {_1}) 未知的网格颜色 `{name}` (应为 {_1} 之一) +@msg unknown gridType `{t}` 未知的 gridType `{t}` +@msg unknown highlight `{v}` 未知的 highlight `{v}` +@msg unknown intent `{i}` 未知的意图 `{i}` +@msg unknown issue kind {id} 未知的问题类型 {id} +@msg unknown issue kind {v} 未知的问题类型 {v} +@msg unknown knockout state {k} 未知的挖空状态 {k} +@msg unknown language `{language}` (one of {_1}) 未知的语言 `{language}` (应为 {_1} 之一) +@msg unknown language `{l}` (one of {_1}) 未知的语言 `{l}` (应为 {_1} 之一) +@msg unknown method `{m}` ({_1}) 未知的方法 `{m}` ({_1}) +@msg unknown mode `{other}` (gray, rgb, hsb, lab, cmyk or web) 未知的模式 `{other}` (gray、rgb、hsb、lab、cmyk 或 web) +@msg unknown mode `{other}` (mono|cmyk) 未知的模式 `{other}` (mono|cmyk) +@msg unknown mode `{other}` (rgb|cmyk|gray|global) 未知的模式 `{other}` (rgb|cmyk|gray|global) +@msg unknown mode `{other}` (set, add, subtract) 未知的模式 `{other}` (set、add、subtract) +@msg unknown mode `{o}` 未知的模式 `{o}` +@msg unknown mode {m} 未知的模式 {m} +@msg unknown model `{other}` 未知的模型 `{other}` +@msg unknown model `{other}` (keep, new or document) 未知的模型 `{other}` (keep、new 或 document) +@msg unknown op {o} 未知的 op {o} +@msg unknown order `{o}`: toggle, front, forward, backward or back 未知的 order `{o}`:应为 toggle、front、forward、backward 或 back +@msg unknown overprints `{v}` (preserve, simulate or discard) 未知的 overprints `{v}` (preserve、simulate 或 discard) +@msg unknown panel 未知的面板 +@msg unknown pieLegend `{v}` (none, standard or wedges) 未知的 pieLegend `{v}` (none、standard 或 wedges) +@msg unknown piePosition `{v}` (even, ratio or stacked) 未知的 piePosition `{v}` (even、ratio 或 stacked) +@msg unknown pieSort `{v}` (none, all or first) 未知的 pieSort `{v}` (none、all 或 first) +@msg unknown plate `{n}` 未知的印版 `{n}` +@msg unknown preference `{k}` 未知的首选项 `{k}` +@msg unknown profile {id} (see stroke.widthProfile.list) 未知的配置文件 {id} (参见 stroke.widthProfile.list) +@msg unknown proof target `{t}` 未知的校样目标 `{t}` +@msg unknown quotes key `{k}` (double, single) 未知的 quotes 键 `{k}` (double、single) +@msg unknown resolution `{v}` 未知的分辨率 `{v}` +@msg unknown rule `{rule}` ({_1}) 未知的规则 `{rule}` ({_1}) +@msg unknown rule `{r}` (see color.harmony) 未知的规则 `{r}` (参见 color.harmony) +@msg unknown setting `{k}` 未知的设置 `{k}` +@msg unknown shape `{v}` (circle|ellipse|square|diamond|line) 未知的形状 `{v}` (circle|ellipse|square|diamond|line) +@msg unknown spacing `{o}` (smooth|steps|distance) 未知的间距 `{o}` (smooth|steps|distance) +@msg unknown tileType `{t}` ({_1}) 未知的 tileType `{t}` ({_1}) +@msg unknown units 未知的单位 +@msg unknown units `{u}` 未知的单位 `{u}` +@msg unknown value axis `{v}` (left, right or both) 未知的数值轴 `{v}` (left、right 或 both) +@msg unknown variation `{v}` (tintsShades|warmCool|vividMuted) 未知的变化 `{v}` (tintsShades|warmCool|vividMuted) +@msg unknown warp style `{s}` 未知的变形样式 `{s}` +@msg unknown {key} `{v}` (none, short or full) 未知的 {key} `{v}` (none、short 或 full) +@msg unknown {key} profile `{n}` 未知的 {key} 配置文件 `{n}` +@msg unknown {k} key `{key}` (size, position) 未知的 {k} 键 `{key}` (size、position) +@msg unreadable object 对象无法读取 +@msg unsafe destination file name 目标文件名不安全 +@msg use paths or compound paths 请使用路径或复合路径 +@msg useArtboards must be true or false, not {v} useArtboards 必须为 true 或 false,不能是 {v} +@msg value for `{var}` must match its variable kind `{var}` 的值必须与其变量类型相符 +@msg variable `{_1}` is already defined 变量 `{_1}` 已定义 +@msg variable `{name}` has no `trait` 变量 `{name}` 没有 `trait` +@msg variable `{name}` is already defined 变量 `{name}` 已定义 +@msg variable `{name}` is declared twice 变量 `{name}` 被声明了两次 +@msg variable `{to}` already exists 变量 `{to}` 已存在 +@msg view is required 必须给出 view +@msg view must be one of {_1} view 必须是 {_1} 之一 +@msg warpStyle can only edit an applied Warp effect warpStyle 只能编辑已应用的变形效果 +@msg width and height must be more than 0 and at most {limit} width 和 height 必须大于 0 且不超过 {limit} +@msg width factors must be finite 宽度系数必须是有限值 +@msg width must be positive width 必须为正数 +@msg width out of range 宽度超出范围 +@msg width/height must be > 0 width/height 必须 > 0 +@msg x and y must be finite numbers x 和 y 必须是有限的数字 +@msg x and y must be given together x 和 y 必须一起给出 +@msg zone needs an anchor: dock beside a panel with anchor, or in a new dock column with side (Start or End) zone 需要 anchor:请用 anchor 停放在某个面板旁,或用 side (Start 或 End) 停放到新的停放列中 +@msg zoom must be positive zoom 必须为正数 +@msg {C}: no effect at index {list} {C}:索引 {list} 处没有效果 +@msg {DEFAULT_PRESET} is protected and stays {DEFAULT_PRESET} 受保护,会保留 +@msg {DEFAULT_PRESET} is protected: save the settings under another name {DEFAULT_PRESET} 受保护:请用其他名称保存这些设置 +@msg {LABEL} produced an empty result {LABEL} 得到了空结果 +@msg {_1} MB of document, at most {_2} MB 文档为 {_1} MB,最多允许 {_2} MB +@msg {_1} MB of images, at most {_2} MB 图像共 {_1} MB,最多允许 {_2} MB +@msg {_1} bytes of RGBA data for a {width} × {height} image {width} × {height} 的图像却有 {_1} 字节的 RGBA 数据 +@msg {_1} can't be read, or changed since it was read: relink or update it first {_1} 无法读取,或在读取后已被更改:请先重新链接或更新它 +@msg {_1} can't go into {into} {_1} 不能放入 {into} +@msg {_1} can't limit printing to low resolution: choose PDF 1.4 or later, or allow high-resolution printing {_1} 不能将打印限制为低分辨率:请选择 PDF 1.4 或更高版本,或允许高分辨率打印 +@msg {_1} files can't be opened yet 目前还无法打开 {_1} 文件 +@msg {_1} files can't be password-protected: remove the passwords or choose no standard {_1} 文件不能用密码保护:请移除密码或不选择标准 +@msg {_1} files can't be {_2} {_1} 文件不能 {_2} +@msg {_1} files can't carry editing data: turn off preserveEditing {_1} 文件不能包含编辑数据:请关闭 preserveEditing +@msg {_1} files can't have PDF layers: turn off createLayers {_1} 文件不能包含 PDF 图层:请关闭 createLayers +@msg {_1} files need a creation date, and this platform has no clock to give one {_1} 文件需要创建日期,而此平台没有可提供日期的时钟 +@msg {_1} isn't a path {_1} 不是路径 +@msg {_1} options: {e} {_1} 选项:{e} +@msg {_1} paints nothing to rasterize {_1} 没有绘制任何可栅格化的内容 +@msg {_1} passwords can have up to {MAX_LEGACY_PASSWORD} ASCII characters (PDF 1.7 and later take any) {_1} 的密码最多 {MAX_LEGACY_PASSWORD} 个 ASCII 字符 (PDF 1.7 及更高版本可使用任意字符) +@msg {_1} with linked images or an image map writes several files: use document.export 带有链接图像或图像映射的 {_1} 会写出多个文件:请使用 document.export +@msg {_1} writes one file per artboard here: use document.export, or name one artboard {_1} 在这里会为每个画板写出一个文件:请使用 document.export,或指定一个画板 +@msg {_1} × {_2} pixels is too large for {_3} (at most {max} pixels a side): lower the scale {_1} × {_2} 像素对 {_3} 而言过大 (每边最多 {max} 像素):请降低缩放比例 +@msg {_1}: belongs to another account {_1}:属于其他帐户 +@msg {_1}: not a folder of its own {_1}:不是独立的文件夹 +@msg {_1}: not a plain file {_1}:不是普通文件 +@msg {dest}: {e} {dest}:{e} +@msg {doc} has no folder {doc} 没有所在的文件夹 +@msg {file} isn't linked {file} 不是链接文件 +@msg {folder} is not a package folder {folder} 不是打包文件夹 +@msg {folder}: more than {max} files and folders {folder}:文件和文件夹超过 {max} 个 +@msg {folder}: {e} {folder}:{e} +@msg {g} is not a Live Paint group {g} 不是实时上色组 +@msg {id} is not a slice {id} 不是切片 +@msg {key} must be 0–{MAX_ADD_AROUND} pt {key} 必须为 0–{MAX_ADD_AROUND} pt +@msg {key} must be [x,y] {key} 必须是 [x,y] +@msg {key} must be a percentage {min}..100 {key} 必须是 {min}..100 的百分比 +@msg {key} must be a positive number, not {n} {key} 必须是正数,不能是 {n} +@msg {key} must be a positive number, not {v} {key} 必须是正数,不能是 {v} +@msg {key} must be one of {_1} {key} 必须是 {_1} 之一 +@msg {key} must be {_1}, got {s} {key} 必须是 {_1},实际为 {s} +@msg {key} must name a floating panel {key} 必须指定一个浮动面板 +@msg {key} must name a panel in another group {key} 必须指定另一个组中的面板 +@msg {key} must name a panel that shows {key} 必须指定一个已显示的面板 +@msg {key} must name a registered panel {key} 必须指定一个已注册的面板 +@msg {kind} files have no transparency, and the file would have {what}: flatten it first (object.flattenTransparency) {kind} 文件不支持透明度,而该文件会包含 {what}:请先拼合 (object.flattenTransparency) +@msg {kind} images can't be opened (see document.formats) 无法打开 {kind} 图像 (参见 document.formats) +@msg {k} `{v}` is not one of the choices {k} `{v}` 不在可选项之中 +@msg {k} has control characters{_1} {k} 含有控制字符{_1} +@msg {k} is too long (at most {MAX_TEXT} characters) {k} 过长 (最多 {MAX_TEXT} 个字符) +@msg {k} must be > 0 {k} 必须 > 0 +@msg {k} must be a number (pt) or a length such as "210 mm" {k} 必须是数字 (pt) 或 "210 mm" 这样的长度 +@msg {k} must be a number from {min} to {max} {k} 必须是 {min} 到 {max} 之间的数字 +@msg {k} must be a number or "auto" {k} 必须是数字或 "auto" +@msg {k} must be a string {k} 必须是字符串 +@msg {k} must be text {k} 必须是文本 +@msg {k} must be true or false {k} 必须为 true 或 false +@msg {k} must be {{size?, position?}} {k} 必须是 {{size?, position?}} +@msg {k}: can't read `{s}` as a length {k}:无法将 `{s}` 读作长度 +@msg {label} must be a number at most {max} {label} 必须是不超过 {max} 的数字 +@msg {label} must be a number from -1296 to 1296 {label} 必须是 -1296 到 1296 之间的数字 +@msg {label} must be a number from 1 to 10000 {label} 必须是 1 到 10000 之间的数字 +@msg {name} `{s}`: {ids} {name} `{s}`:{ids} +@msg {name} is built in and can't be deleted {name} 是内置项,不能删除 +@msg {name} must be {lo}–{hi}{unit} (got {v}) {name} 必须为 {lo}–{hi}{unit} (实际为 {v}) +@msg {name}: CRC or size mismatch {name}:CRC 或大小不匹配 +@msg {name}: only this Affinity file's embedded preview could be read; use File › Open to see it with its warning, or export SVG or PDF from Affinity before placing {name}:只能读取此 Affinity 文件的嵌入预览;请使用 文件 › 打开 查看预览及其警告,或在置入前先从 Affinity 导出 SVG 或 PDF +@msg {name}: {e} {name}:{e} +@msg {native}; its embedded preview can't be read either ({e}) {native};其嵌入的预览也无法读取 ({e}) +@msg {std} files are CMYK, and the file would have colours in {_1} {std} 文件为 CMYK,而该文件会包含 {_1} 颜色 +@msg {std} files embed their fonts, and the file would have one that isn't {std} 文件需要嵌入字体,而该文件会有一个未嵌入的字体 +@msg {target} is the file this document was read from, and reading it left things out ({what}): writing over it would lose them for good. Write another file instead, or pass acknowledgeLoss: true to replace it anyway {target} 是读取此文档时所用的文件,读取时略去了一些内容 ({what}):覆盖该文件会永久丢失这些内容。请改为写入另一个文件,或传入 acknowledgeLoss: true 以仍然替换它 +@msg {ty} brushes need selected art (or params.{k}) {ty} 画笔需要选中的图稿 (或 params.{k}) +@msg {v} is not an asset id {v} 不是资源 ID +@msg {what} can't be intertwined {what} 不能交织 +@msg {what} doesn't fit the paper with its bleed and marks {what} 连同出血和标记在纸张上放不下 +@msg {what} would print on more than {MAX_TILES} tiles: scale it down {what} 会打印成超过 {MAX_TILES} 个拼贴:请将其缩小 diff --git a/crates/ui-egui/src/menus/ui_commands.rs b/crates/ui-egui/src/menus/ui_commands.rs index e0e84b137f..cd311d45a8 100644 --- a/crates/ui-egui/src/menus/ui_commands.rs +++ b/crates/ui-egui/src/menus/ui_commands.rs @@ -926,7 +926,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "tool.options", "Tool Options…", "", - "{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x, y and preview (on initially), previews one there and accepts it as one Undo step; Cancel rolls back the preview), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (px for pencil, paintbrush and smooth, the same at any zoom; pt for blobBrush), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), livePaintBucket → Live Paint Bucket Options (dialog `livePaintBucketOptions`, fields paintFills (on) and paintStrokes (off), highlight (on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the face highlight's width, 1–20 px; 4; an edge's highlight is half as wide); OK runs tool.setOption {tool: \"livePaintBucket\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values}; a highlightColor with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), objectsOnPath → Objects on Path Tool Options (dialog `objectsOnPathOptions`, fields pivot (0–8, row by row from the top left; 4, the center) and rotate (°, −360–360; 0); Reset puts 4 and 0 back; Save runs tool.setOption {tool: \"objectsOnPath\", values}: the objects attached next use them, groups attached before keep theirs)", + "{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x, y and preview (on initially), previews one there and accepts it as one Undo step; Cancel rolls back the preview), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (px for pencil, paintbrush and smooth, the same at any zoom; pt for blobBrush), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), livePaintBucket → Live Paint Bucket Options (dialog `livePaintBucketOptions`, fields paintFills (on) and paintStrokes (off), cursorSwatchPreview (on: the active fill or stroke shows above the pointer between the color swatches before and after it; Left and Right without modifiers step it through the color swatches whether it is on or off), highlight (on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the face highlight's width, 1–20 px; 4; an edge's highlight is half as wide); OK runs tool.setOption {tool: \"livePaintBucket\", values}; a color with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values}; a highlightColor with an alpha part (#rrggbbaa or #rgba) is an error and OK changes nothing), objectsOnPath → Objects on Path Tool Options (dialog `objectsOnPathOptions`, fields pivot (0–8, row by row from the top left; 4, the center) and rotate (°, −360–360; 0); Reset puts 4 and 0 back; Save runs tool.setOption {tool: \"objectsOnPath\", values}: the objects attached next use them, groups attached before keep theirs)", ), ( "ui.colorGuideOptions", diff --git a/crates/ui-egui/src/shortcuts.rs b/crates/ui-egui/src/shortcuts.rs index 0b5794b615..ea32f6c078 100644 --- a/crates/ui-egui/src/shortcuts.rs +++ b/crates/ui-egui/src/shortcuts.rs @@ -625,8 +625,10 @@ fn dialog_or_palette_open(app: &VectorcraftApp) -> bool { /// Route Alt+arrows to spacing controls when text objects are selected. fn alt_type_arrows(app: &mut VectorcraftApp, ctx: &egui::Context) -> bool { - let m = ctx.input(|i| i.modifiers); - if !m.alt { + let keys = [(Key::ArrowLeft, ToolKey::Left), (Key::ArrowRight, ToolKey::Right), (Key::ArrowUp, ToolKey::Up), (Key::ArrowDown, ToolKey::Down)]; + // The modifiers held when each arrow went down, as `nudge_and_clear` reads them. + let pressed = keys.map(|(key, tool_key)| (key, tool_key, ctx.input(|i| press_modifiers(i, key)))); + if !pressed.iter().any(|(.., m)| m.alt) { return false; } let orientation = app.session.active().and_then(|st| { @@ -644,9 +646,8 @@ fn alt_type_arrows(app: &mut VectorcraftApp, ctx: &egui::Context) -> bool { let Some(vertical) = orientation else { return false; }; - let keys = [(Key::ArrowLeft, ToolKey::Left), (Key::ArrowRight, ToolKey::Right), (Key::ArrowUp, ToolKey::Up), (Key::ArrowDown, ToolKey::Down)]; - for (key, tool_key) in keys { - if ctx.input_mut(|i| i.consume_key(m, key)) { + for (key, tool_key, m) in pressed { + if m.alt && ctx.input_mut(|i| i.consume_key(m, key)) { if let Some((attribute, by)) = vectorcraft_tools::text::step_key(tool_key, m.shift, false, vertical) { let by = if m.command { by * 5.0 } else { by }; let _ = app.run("type.step", json!({"attribute": attribute, "by": by})); @@ -685,13 +686,27 @@ fn type_tool_input(app: &mut VectorcraftApp, ctx: &egui::Context, composing: boo settings_on_a_mac(app, ctx, mac(ctx)); } +/// The modifiers held when `key` last went down in this frame, which can differ from the frame's +/// at its end; the frame's when the key did not go down. +fn press_modifiers(i: &egui::InputState, key: Key) -> Modifiers { + i.events + .iter() + .rev() + .find_map(|e| match e { + egui::Event::Key { key: k, pressed: true, modifiers, .. } if *k == key => Some(*modifiers), + _ => None, + }) + .unwrap_or(i.modifiers) +} + /// Apply arrow-key movement and clear selected art when no text editor owns input, unless a Layers /// or Appearance row has Delete/Backspace (`rows_keys`). fn nudge_and_clear(app: &mut VectorcraftApp, ctx: &egui::Context, rows_keys: bool) { // Arrow nudges (Shift = ×10, Alt = copy). let arrows = [(Key::ArrowLeft, -1.0, 0.0), (Key::ArrowRight, 1.0, 0.0), (Key::ArrowUp, 0.0, -1.0), (Key::ArrowDown, 0.0, 1.0)]; for (k, dx, dy) in arrows { - let m = ctx.input(|i| i.modifiers); + // The modifiers held when the key went down, as `claimed_tool_keys` reads them. + let m = ctx.input(|i| press_modifiers(i, k)); if ctx.input_mut(|i| i.consume_key(m, k)) && app.session.active().is_some_and(|d| d.selection.has_objects_or_guides()) { let _ = app.run("object.nudge", json!({"dx": dx, "dy": dy, "big": m.shift, "copy": m.alt})); } @@ -878,8 +893,13 @@ fn claimed_tool_keys(app: &mut VectorcraftApp, ctx: &egui::Context, view: ViewIn // The Smart Pen Tool's Tab while it draws a path (the key otherwise hides the panels). (Key::Tab, ToolKey::Tab), ] { - if !rows_take(k) && ctx.input(|i| i.key_pressed(k)) && app.session.tool_claims_key(tk, view) && ctx.input_mut(|i| i.consume_key(m, k)) { - let r = app.session.tool_key(tk, crate::canvas::mods(m, false), view); + let pm = ctx.input(|i| press_modifiers(i, k)); + if !rows_take(k) + && ctx.input(|i| i.key_pressed(k)) + && app.session.tool_claims_key_with(tk, crate::canvas::mods(pm, false), view) + && ctx.input_mut(|i| i.consume_key(pm, k)) + { + let r = app.session.tool_key(tk, crate::canvas::mods(pm, false), view); // Keyboard actions can change the Artboard tool's active board too. Keep the // navigator aligned with its valid survivor, as pointer dispatch does. if r.is_ok() diff --git a/crates/ui-egui/src/shortcuts/tests.rs b/crates/ui-egui/src/shortcuts/tests.rs index 60b8c5eacd..92a1ab9768 100644 --- a/crates/ui-egui/src/shortcuts/tests.rs +++ b/crates/ui-egui/src/shortcuts/tests.rs @@ -2220,6 +2220,15 @@ fn alt_arrows_step_selected_type_object() { assert_eq!(r["runs"][0]["style"]["tracking"], json!(20.0)); assert_eq!(app.session.active().unwrap().selection.objects, [vectorcraft_doc::NodeId(id)]); + // Alt released within the frame of the press: the press's Alt still steps the spacing. + frame( + &mut app, + vec![egui::Event::ModifiersChanged(Modifiers::ALT), press(Key::ArrowRight, Modifiers::ALT), egui::Event::ModifiersChanged(Modifiers::NONE)], + ); + let r = app.session.execute("text.getRange", &json!({"id": id})).unwrap(); + assert_eq!(r["runs"][0]["style"]["tracking"], json!(40.0)); + assert_eq!(app.session.active().unwrap().selection.objects, [vectorcraft_doc::NodeId(id)], "the text is not copied"); + frame(&mut app, vec![egui::Event::ModifiersChanged(Modifiers::ALT), press(Key::ArrowDown, Modifiers::ALT)]); let r = app.session.execute("text.getRange", &json!({"id": id})).unwrap(); assert_eq!(r["runs"][0]["style"]["leading"], json!(26.0)); @@ -2245,6 +2254,65 @@ fn alt_arrows_step_selected_type_object() { assert_ne!(selected[0], vectorcraft_doc::NodeId(rect), "a non-type object is still copied by Alt+arrow"); } +/// With the Live Paint Bucket, a plain Right picks the next color swatch, while Alt+Right keeps +/// copying and nudging the selection, and a Shift+Right released within the same frame is still a +/// Shift+Right that picks no swatch. +#[test] +fn live_paint_bucket_takes_only_plain_arrows_for_swatches() { + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap(); + let rect = app.session.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap()["id"].as_u64().unwrap(); + app.session.execute("select.set", &json!({"ids": [rect]})).unwrap(); + let first = vectorcraft_tools::builder::color_swatches(&app.session.active().unwrap().doc)[0].name.clone(); + app.session.execute("paint.setFill", &json!({"swatch": first, "ids": []})).unwrap(); + app.select_tool("livePaintBucket"); + let fill = app.session.paint.fill.clone(); + + frame(&mut app, press(Key::ArrowRight, Modifiers::ALT)); + assert_eq!(app.session.paint.fill, fill, "Alt+Right picks no swatch"); + let selected = &app.session.active().unwrap().selection.objects; + assert_ne!(selected.as_slice(), [vectorcraft_doc::NodeId(rect)], "Alt+Right copies and nudges the selection"); + + let shift_then_released = vec![ + egui::Event::ModifiersChanged(Modifiers::SHIFT), + egui::Event::Key { key: Key::ArrowRight, physical_key: Some(Key::ArrowRight), pressed: true, repeat: false, modifiers: Modifiers::SHIFT }, + egui::Event::ModifiersChanged(Modifiers::NONE), + ]; + frame(&mut app, shift_then_released); + assert_eq!(app.session.paint.fill, fill, "Shift+Right picks no swatch"); + + frame(&mut app, press(Key::ArrowRight, Modifiers::NONE)); + assert_ne!(app.session.paint.fill, fill, "a plain Right picks the next swatch"); +} + +/// An arrow nudge takes Shift and Alt from the key press, also when they are released within the +/// same frame: Shift+Right moves 10 points, and Alt+Right copies. +#[test] +fn arrow_nudge_takes_the_modifiers_of_the_key_press() { + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap(); + let rect = app.session.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap()["id"].as_u64().unwrap(); + let rect = vectorcraft_doc::NodeId(rect); + app.select_tool("selection"); + app.session.execute("select.set", &json!({"ids": [rect.0]})).unwrap(); + let released = |modifiers| { + vec![ + egui::Event::ModifiersChanged(modifiers), + egui::Event::Key { key: Key::ArrowRight, physical_key: Some(Key::ArrowRight), pressed: true, repeat: false, modifiers }, + egui::Event::ModifiersChanged(Modifiers::NONE), + ] + }; + let left = |app: &VectorcraftApp, id| app.session.active().unwrap().doc.bounds_of(&[id], false).unwrap().x0; + + frame(&mut app, released(Modifiers::SHIFT)); + assert_eq!(left(&app, rect), 10.0, "Shift+Right moves 10 points"); + + frame(&mut app, released(Modifiers::ALT)); + let selected = app.session.active().unwrap().selection.objects.clone(); + assert_ne!(selected.as_slice(), [rect], "Alt+Right copies"); + assert_eq!(left(&app, rect), 10.0, "the original stays"); +} + /// #793: with a layout without Latin letters the one-key shortcuts go by the key's position: /// the P key typing Persian `ح` chooses the Pen, the V key typing Russian `м` the Selection /// tool. A Latin layout keeps the letter typed: AZERTY's A (the Q key's place) is A. diff --git a/crates/ui-egui/src/widgets.rs b/crates/ui-egui/src/widgets.rs index 4e1bc4f6a5..36145224d5 100644 --- a/crates/ui-egui/src/widgets.rs +++ b/crates/ui-egui/src/widgets.rs @@ -56,18 +56,18 @@ pub use labels::{dim_label, dim_name, divider, field_label, label_row, link_labe pub(crate) use labels::{label_field, take_previous_label, text_width}; pub(crate) use numeric::{ANY, round_to, set_bare_numbers_are_points, typed_unit}; pub use numeric::{ - SpinPick, mixed_field, mixed_field_named, num_field, num_field_live, num_field_named, num_field_within, num_field_within_empty, opt_field, - opt_field_named, plain_field_live, range_field, range_field_live, range_field_named, range_field_stepped, size_field, size_field_named, slider, - spin_field, spin_field_auto, spin_field_auto_named, spin_field_named, spin_field_stops_named, spin_kerning, spin_length_within, spin_plain, - spin_plain_named, spin_range, + SpinPick, mixed_field, mixed_field_named, num_field, num_field_live, num_field_named, num_field_refusing, num_field_within, + num_field_within_empty, opt_field, opt_field_named, plain_field_live, range_field, range_field_live, range_field_named, range_field_stepped, + size_field, size_field_named, slider, spin_field, spin_field_auto, spin_field_auto_named, spin_field_named, spin_field_stops_named, spin_kerning, + spin_length_within, spin_plain, spin_plain_named, spin_range, }; #[cfg(test)] use numeric::{decimal_point, field_number, share_of, spinner_step, step_through, step_to_multiple, within_a_millionth}; pub(crate) use panel_chrome::{PANEL_FOOTER, panel_footer, panel_footer_bottom, panel_footer_space, panel_list_height}; pub use panel_chrome::{bottom_bar, layout_button, list_box, orientation_button, tab_bar}; pub(crate) use text::{ - arm_field_focus, dialog_focus_flag, dialog_reject_commit_flag, disarm_field_focus, enter_modifiers, focus_field, own_field_shift_enter, - reject_dialog_commit, set_dialog_open, take_dialog_focus, + arm_field_focus, dialog_focus_flag, dialog_reject_commit_flag, dialog_reject_pass, disarm_field_focus, enter_modifiers, focus_field, + own_field_shift_enter, reject_dialog_commit, set_dialog_open, take_dialog_focus, }; pub use text::{ exact_text_field, exact_text_field_named, plain_field, plain_field_named, search_field, text_field, text_field_named, text_presets, diff --git a/crates/ui-egui/src/widgets/numeric.rs b/crates/ui-egui/src/widgets/numeric.rs index 3eec21b928..89ce8d70d5 100644 --- a/crates/ui-egui/src/widgets/numeric.rs +++ b/crates/ui-egui/src/widgets/numeric.rs @@ -67,6 +67,21 @@ pub fn num_field_within( unit_field(ui, id, label, None, value, unit, width, false, bounds, &[], false, "") } +/// [`num_field_within`] that refuses a value typed outside `bounds` (points), as it refuses text +/// that doesn't read: the field flashes, keeps its value and holds the dialog open. ↑/↓, the wheel +/// and a scrub still stop at the ends. +pub fn num_field_refusing( + ui: &mut Ui, + id: impl std::hash::Hash, + value: Option, + unit: Unit, + width: f32, + bounds: RangeInclusive, +) -> Option { + let label = take_previous_label(ui); + unit_field_from(ui, id, label, None, value, unit, width, false, bounds, &[], false, None, "", true) +} + /// [`num_field_within`] whose empty value reads `empty` (Transform Each's Absolute scales read /// "Mixed" when the selected objects differ): typing replaces it, as it replaces the value shown. pub fn num_field_within_empty( @@ -122,11 +137,12 @@ fn unit_field( live: bool, empty: &str, ) -> Option { - unit_field_from(ui, id, label, name, value, unit, width, share_of_value, bounds, stops, live, None, empty) + unit_field_from(ui, id, label, name, value, unit, width, share_of_value, bounds, stops, live, None, empty, false) } /// [`unit_field`] whose blank field (`value` is `None`) steps from `blank_from` (points) with -/// ↑/↓ and the wheel instead of doing nothing. +/// ↑/↓ and the wheel instead of doing nothing. With `refuse_outside`, a value typed outside +/// `bounds` is refused as text that doesn't read is, rather than kept at the nearer end. #[allow(clippy::too_many_arguments)] fn unit_field_from( ui: &mut Ui, @@ -142,6 +158,7 @@ fn unit_field_from( live: bool, blank_from: Option, empty: &str, + refuse_outside: bool, ) -> Option { let id = id_with(ui.scope_id(), id); let shown = value.map(|v| unit.format(v)).unwrap_or_else(|| empty.to_string()); @@ -163,7 +180,11 @@ fn unit_field_from( let scrubbed = scrub::field(ui, id, rect, &buf, value.map(|v| unit.from_pt(v)), STEP_DECIMALS, &bounds_unit); let commit = commit && buf != shown; if commit { - match read(&buf).or_else(|| if share_of_value { share_of(&buf, value?) } else { None }) { + let typed_value = read(&buf).or_else(|| if share_of_value { share_of(&buf, value?) } else { None }); + // A refused value is one outside `bounds` that the field doesn't show as an end: the end + // shown in the field's unit ("352.7778 mm" for 1000 pt) reads back as that end. + let typed_value = typed_value.filter(|&v| !refuse_outside || bounds.contains(&v) || unit.format(within(v, &bounds)) == unit.format(v)); + match typed_value { Some(v) => { let clamped = within(v, &bounds); let formatted = unit.format(clamped); @@ -1017,7 +1038,7 @@ pub fn spin_field_stops_named( let stops = if value.is_none() { &BLANK_WEIGHT_STOPS[..] } else { presets }; let fmt = |v: f64| unit.format(v); spin_generic(ui, label, value, Some(blank_from), None, None, None, width, step, min, presets, stops, &fmt, &mut |ui, fw, label| { - unit_field_from(ui, id, label, name, value, unit, fw, false, min..=f64::INFINITY, stops, false, Some(blank_from), "") + unit_field_from(ui, id, label, name, value, unit, fw, false, min..=f64::INFINITY, stops, false, Some(blank_from), "", false) }) .and_then(SpinPick::value) } diff --git a/crates/ui-egui/src/widgets/text.rs b/crates/ui-egui/src/widgets/text.rs index eec3cd3a94..8a9bfe1b8d 100644 --- a/crates/ui-egui/src/widgets/text.rs +++ b/crates/ui-egui/src/widgets/text.rs @@ -94,9 +94,20 @@ pub(crate) fn dialog_reject_commit_flag() -> egui::Id { egui::Id::unique("dialog-reject-commit") } -/// Suppress confirming an open dialog on Enter during this frame when an invalid value was committed. +/// The pass (`cumulative_pass_nr`) in which a field last rejected an invalid commit: a click on a +/// dialog's OK whose press came at or before it doesn't confirm the dialog. +pub(crate) fn dialog_reject_pass() -> egui::Id { + egui::Id::unique("dialog-reject-pass") +} + +/// Suppress confirming an open dialog on Enter during this frame, or by the click on OK that took +/// the focus from the field, when an invalid value was committed. pub(crate) fn reject_dialog_commit(ctx: &egui::Context) { - ctx.data_mut(|d| d.insert_temp(dialog_reject_commit_flag(), true)); + let pass = ctx.cumulative_pass_nr(); + ctx.data_mut(|d| { + d.insert_temp(dialog_reject_commit_flag(), true); + d.insert_temp(dialog_reject_pass(), pass); + }); } /// The app sets this at the start of each frame: while a dialog is open, Shift+Enter in a field diff --git a/docs/file-format-parity.md b/docs/file-format-parity.md index ca7c2a3e81..623675fda9 100644 --- a/docs/file-format-parity.md +++ b/docs/file-format-parity.md @@ -264,7 +264,7 @@ private editing data. VectorCraft: ### Illustrator's private editing data -The app's own editing copy of a file (an EPS after its `%%EOF`, a `.ai`'s `AIPrivateData` streams, a PDF's `AIPDFPrivateData` streams when it was saved with the editing data (#868), Zstandard or zlib, the EPS's in ASCII85) is not documented as a whole. VectorCraft reads its structure: layers and sublayers (names, order, visibility, lock, printing, preview, dimming, colour), groups as they were nested, compound paths (painted by their last path, or the last painted one, with the paths of groups inside them kept as their paths: #1410), clipping groups and layer clipping (several clipping paths in a clipping group, a layer or an opacity mask's art clip to their intersection, and a compound path of clipping paths stays one clip; a filled clipping path keeps its fill, which paints under the art it clips, except the path of a mask that covers several layers, whose fill is read as a path of its own in the layer that holds the mask's path, and a compound clipping path whose subpaths paint differently, whose filled subpaths are read as a compound path of their own under the art it clips; clipping paths that would nest the art past the document's 32 levels stop the editing data from being read: #5789), object names, hidden and locked objects, fills and strokes (grey, CMYK, RGB, named and spot colours, spot colours defined in Lab with their Lab values (#1032), global process colours as global swatches at their tint; a stroke of width 0, `0 w`, on a path, a gradient-filled path, legacy type or in an art style comes in as a 0.25 pt hairline, as from PDF: #1671), linear and radial gradients, pattern fills with their patterns as pattern swatches (#1025), gradient and pattern names in the file up to their first newline (a name that another swatch, or a gradient or pattern defined earlier, already has is numbered "Sky 2"; a name without a newline is kept, and when another swatch has it, the pattern's swatch, or a named color sharing a gradient or pattern swatch's name, is numbered the same way), opacity, blend modes, isolation and knockout, embedded images where their matrix puts them, rotated ones too (#2269), with their alpha channel (CMYK images keep their ink amounts, as they do when a `.ai` opens from its PDF part, and an alpha channel that hides part of a CMYK image becomes a grayscale opacity mask), placed (linked) files as linked images in their place, each showing the low-resolution preview the file keeps of it until its file is found or relinked in the Links panel (#1264), with the folder the file keeps relative to the document's, where the link is looked for when its path is gone, placed PDF and `.ai` pages as placed documents of the [page and Crop to box](https://helpx.adobe.com/illustrator/desktop/add-and-import-files/import-other-file-types/adobe-pdf-placement-options.html) their dictionary names (`AI11 PlacedPDFPageIndex`, `AI11 PlacedPDFCropTo`; a value VectorCraft doesn't read, or a binding to an image variable, leaves a linked image), guides, and every artboard where it is, with its center mark, cross hairs, video safe areas and video ruler pixel aspect ratio. VectorCraft reads `CropAreaActive`, an `/Int` in the dictionary that holds the artboard array, as the index of the active artboard in that array, and the file opens with that artboard active; without it, or when it names no artboard that opens, the first artboard is active. It also reads the Document Raster Effects Settings (resolution, color model, background, anti-alias, clipping mask, Add Around Object and Preserve Spot Colors), the author from the header's `%%For` (an EPS's own header when the editing data's has none), swatches for the header's `%%CMYKCustomColor` and `%%RGBCustomColor` colors that the document has none of, and `%%TemplateBox` in older files; a setting with a value of another type or out of range keeps its default. Objects on Path groups open live, with their path, their objects in order along it, Pivot and Rotate; one with a dragged spacing or other options opens as a plain group. A gradient with stops in the middle runs its whole ramp across its shape, and a gradient object does not pass its fill to the next path (#1390). An object whose art style is one fill and one stroke at most (solid colours, its own gradient, a variable-width profile on a Stroke Offset stroke or written as each side's widths) with Drop Shadow, Inner Glow, Outer Glow, Feather, Round Corners, Scribble, Offset Path, Outline Object, Outline Stroke, Convert to Shape, Tweak (only when it moves nothing), Pucker & Bloat at 0 or Bas Relief (read from its settings block: [raster effects reference](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/apply-filter-effects/raster-effects-reference.html), [Photoshop File Formats Specification](https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/), [scripting the filter gallery](https://community.adobe.com/questions-712/scripting-support-for-the-filter-gallery-1064646)) comes in as itself with them and their saved settings. A path, compound path or group (not a clipping group) whose only effect is Transform (not with copies or Random) or a Free Distort whose corners make a parallelogram comes in as itself with it too, when neither it nor anything in it paints with a gradient or pattern and everything in it is a path, compound path or group with no opacity mask and no effects of its own; Transform that scales, rotates or reflects needs nothing in it to be stroked. Twist as the only effect is read the same way when nothing in the object is stroked: up to 180° either way (a limit VectorCraft sets) on a path or compound path whose segments are all straight, and up to 90° either way (a limit VectorCraft sets) on another path, compound path or group with no guide in it. One with more, other effects (Zig Zag, a Pucker & Bloat of another amount, a Free Distort with other corners), an effect setting that is not read (an unknown key, a missing or out-of-range value, a Scribble with a color of its own), a variable-width stroke with one centered width array, dashes aligned to corners, a brush other than a Calligraphic or Art one, a Calligraphic brush with settings of its own, an entry that isn't read, a variable width or an angle that follows the path, a path followed by samples of the pen (`(…) Xt n XD`) whose Calligraphic brush varies with the pen, or an Art brush other than the ones described next comes in as its drawn look (a group named after it). Objects in a symbol defined before the file's art styles section, as newer files write it, take the same styles as the layers' objects. A path with a Calligraphic brush otherwise comes in as the path, the brush on its stroke at the stroke's weight, which scales the brush (#372), and so does a path with an Art brush, whose weight scales the art across the path, when all of these hold: the brush stretches its art along the path, unflipped, at 100% in Tints; the path's settings are the brush's own, with no entry that isn't read, no variable width and no effects; its stroke isn't a swatch; and the art is paths, compound paths and groups in solid fills, with no strokes, masks or effects, and has some length along the path. A stroke takes the brush the Brushes panel keeps under its name, and one whose name the panel doesn't keep comes in as its drawn look. Type with an Art brush keeps its drawn look under the type. A Calligraphic brush's Pressure, Tilt, Bearing and Rotation come in as those channels (a 6D Art Pen's brushes vary with the pressure, the bearing and the barrel's rotation); its Stylus Wheel varies at random. The file's Calligraphic, Scatter, Art and Bristle brushes replace the default ones in the Brushes panel, in the file's order, also when the file comes in as its PDF part (a brush library has no layers); pattern brushes and brushes it can't read are left out with a note. When the file opens from its layers, the spot colors in the art of each brush that comes in become swatches, and that art's colors count toward the document's color mode, as a pattern's do. The swatches take at most 20,000 color names in all across the brush art, and each brush-art section keeps at most 20,000 names. Each name keeps its first definition, with the color operators' names before the gradient stops' names. A spot color past those limits makes no swatch, and its color still counts toward the color mode. A spot color that the page's art, a pattern or a symbol also defines keeps the value defined there. Type keeps its art style as a live appearance whatever its stack (an Art brush aside), so it can be retyped: each fill and stroke of the style's stack (solid colours, gradients and pattern fills, placed as the drawn look places them) with its own opacity, blend mode and effects, the effects on the whole object, and where the characters paint among them; the effects read are Warp, Offset Path, Outline Object, Outline Stroke, Transform (with copies, Transform Objects, Transform Patterns and Scale Strokes & Effects; not with Random), Free Distort, Pucker & Bloat, Twist, Zig Zag, Tweak (only when it moves nothing, the file holding none of its random outline), Drop Shadow, Inner Glow, Outer Glow, Feather, Round Corners, Scribble, Gaussian Blur, Bas Relief (its detail, smoothness and light direction from its settings block, or the effect's defaults when the style holds no settings block; a settings block that isn't read keeps the drawn look) and Convert to Shape, and a style with others, or with an effect setting that isn't read, keeps the type's drawn look. Convert to Shape keeps its Rectangle, Rounded Rectangle or Ellipse, its Absolute or Relative size (a relative size in the file is added to each side) and its corner radius; a relative Ellipse, or a setting that isn't read, keeps the drawn look. The page's drawing of such a style isn't held to look like VectorCraft's where its drawn look lay. Gradients take their matrix (`Xm`, radials and skewed ones too), focal point and the order of stops sharing a ramp point; gradient meshes, a clipping path's own fill and its stroke, and the artboards' names are read too. `editingData: "always"` (`convert --editing-data`) opens a `.ai` or an Illustrator EPS from its editing data even where it draws differently from its page, which can be older, with a note. Type is made from the file's text document, whole and editable, shown or not: point type (its frame's matrix, which newer files leave out when it is neither turned nor scaled, read as none), area type (a story in several frames as threaded type) and type on a path, with its characters, fonts, size, leading, tracking, scaling, baseline shift, fill and stroke (grey, RGB or CMYK), alignment, indents and paragraph spacing (a character attribute a run doesn't set comes from its character style, then the style that one is based on, then the document's defaults); area type keeps its frame's Area Type Options rows and columns, the gutter between rows and the gutter between columns, and its first baseline (Fixed, Cap Height, Leading or x Height) with its minimum; type on a path keeps its frame's Type on a Path effect, Align to Path and Flip (a frame whose options set key 6 to true keeps their defaults), and the first frame's Spacing is fitted from the file's layout, not read from the dialog's value; the distance from the path under Align to Path is measured for each character at its size and vertical scale (in vertical type, its horizontal scale), from the top of its font's em box (Ascender), half the height of the top of its font's H (Center) or the bottom of its font's bounding box (Descender); the fit under Gravity does not reproduce the file's layout, and its glyphs can lie up to 7.4 pt from the positions the file keeps; the page's drawing of it (often in pieces) is left out. Vertical type keeps its orientation, its columns from right to left, and a run set to Tate-chu-yoko keeps that setting. When it makes the type of every text object that shows, the page's type is only compared with it, each text object keeps its own group, frame and layer, and a line break inside a paragraph stays one. Where it can't make a text object's type (a frame of another kind), that text object takes the page's type where the text document puts its lines, or else what is left of the page's type in painting order (no group around it); the page's type where made type draws stays that type's, and hidden type is left out with a note. Text wrap is read too: an object whose dictionary has the wrap options (offset and Invert Wrap), or any graphic of a legacy wraparound group (`*w` … `*W`, before or after its type, with no offset), is a wrap object, and area type below it in its layer flows around it when the file opens, threaded type included (#2763). Kerning, underline and the other character and paragraph options aren't read yet. A `.ai` saved without PDF compatibility (a placeholder page) opens from its editing data alone, its point type, area type and type on a path made from the text document. A `.ai` whose PDF part shows only text isn't taken for that placeholder when its page states an art, trim or bleed box: it opens from its editing data alone where that reads, else from its PDF part (#1387). A `.ai` whose PDF part draws nothing at all (an empty page, with or without those boxes) opens from its editing data alone where that reads too: there is no page art to check its layers against, and the empty page would lose all of it. Text objects with an appearance keep their own text and frame, type of hidden layers stays hidden, and type on later artboards lands on its text objects (#1391); area type whose frame is too short for a line of the fallback font shows its first line (the frame is made taller, with a warning in the open result) (#1392). In a PDF saved with some of its artboards, the type on each page after the first goes to an artboard of that page's size after the previous page's artboard, and only to one that leaves an artboard for each later page; the first page's artboard also leaves one for each later page. When several artboards fit a later page, VectorCraft takes the one whose art draws most like the page, and compares at most 16 artboards for all the later pages together. Symbols are read into the Symbols panel, in the file's symbol list order, with their art, their registration point and the instances in their art, and their instances come in live with their matrix, name, hide, lock, opacity, blending mode, isolation, knockout and opacity mask; a symbol whose art isn't read whole (type, placed files, an image it leaves out or anything else it doesn't read) isn't kept. A file that comes in as its page or PDF part because its editing data has no layers (a symbol library), or because its layers can't be read or used (any of the cases below), gets the symbols its editing data defines before its first layer, in the symbol list's order, while its page art stays as the page draws it. Instances of symbols it can't read, instances with appearance changes of their own (a dynamic symbol's), pattern fills whose pattern it can't read, placed files the data keeps no preview of and anything else it doesn't read make the file come in as its page (on a layer that doesn't show, they are left out of that layer), with a warning saying what. An unread object on a shown layer whose box can be found instead comes in as a group of the page's objects inside that box, named after it, with the rest of the layers and groups kept and a warning listing what came in as the page's art; the file still comes in as its page when live art or another unread object shares that page art, when the object spans two artboards or lies on an artboard that has no page, when no page art lies inside its box, when that page art is inside a page group with a clip, mask, transparency or appearance, when the object holds a frame of threaded type, when the page art uses a pattern, image or swatch that the page lacks or that differs from the editing data's, or when the page art doesn't carry its transparency (#4806). The layers' art is also compared with the page (by lightness, so colours written as their CMYK equivalents compare alike, and by whether a pixel is inked at all); the page is used when they differ by more than 5% (away from type, when all the type is made from the text document), where one draws an object the other doesn't (away from type, whose lines may be laid out afresh), and when an EPS whose page is its art's box has art printed outside it (#735). A `.ai` is not compared with its page, and its PDF part is not imported, when its text document makes the type of every text object (at least one shows, and none is drawn by the appearance of the layer or group it is in), no object is unread, no placed file has a second placement, no live envelope keeps its drawn art, it declares no large canvas, and its artboards are its pages' trim boxes one for one, in points or in the first page's `UserUnit`: it opens from its layers, with the bleed of its pages' bleed boxes. When they differ because some objects draw differently (an object in another color, or one that only one of them draws), each top-level object of the layers that holds such a difference comes in as a group of the page's objects inside its box and the layers stay, with a warning that names the layer or sublayer of each such object as the Layers panel shows it (`` for one without a name) and how many came in from it; an export or Save As to the file's own path then needs `acknowledgeLoss: true`, and a wrap object replaced this way keeps its wrap options. The file still comes in as its page when only edges or type differ, when a difference lies outside every top-level object, when more than half of the top-level objects or more than 64 hold one, when such an object is or holds type or holds a wrap object inside a group, when the page's type of a text object that stays lies inside such an object's box, when the page's art can't replace such an object for one of the reasons above for an unread object, when matching the differences to the objects would take too much work, or when the result still differs from the page. `editingData: "always"` keeps the objects as read, and placed files at the other point their data gives are tried as well. An EPS whose page is its art's box keeps that page when it comes in through its layers, not the editing data's artboard, and a text object counts as drawn by the page by its colours, not only its lightness, so a red stroke stacked over a dark red one stays (#1102). `textAs: "outlines"` opens a `.ai` whose type shows from its PDF part, which has the outlines; `editingData: false` opens any of them as its page or PDF part only, for print pipelines (#735). A file whose import left something out (hidden text, art or layers) is never written over by an export or Save As to its own path unless `acknowledgeLoss: true` (`convert --replace-lossy`), so the original keeps what the document lacks. Where a `.ai` can't be read that way (or its layers are turned off in the import options), we read its PDF-compatible part, so Illustrator-only live objects arrive as appearance, and plain groups arrive ungrouped: that part draws each object on its own and marks only layers, clipping groups and groups with opacity, blending or a mask (those come back). Art outside the artboards isn't in that part at all (Illustrator's PDF part leaves it out), so it doesn't open; the import says so in a note (#472). Its pages still go where the editing data puts the artboards (a grid stays a grid), with the art on each, when it has as many artboards as pages, of the same sizes (#1068); the page of the artboard `CropAreaActive` names is then the active artboard. A `.ai` whose editing data has artboards but no layers also opens on that page under the same check, and its pages stay where they are. A `.ai` whose PDF part's pages are cropped to its art (each page the box of all the art, which is the editing data's bounding box) instead of its artboards opens from its layers, with its own artboards, where they draw as that page does. Its pages are laid out so that art one of them draws past its artboard (notes beside a design, which the part doesn't clip) doesn't lie over the page before it in the row, where it was taken for that page's art: the check against the editing data then found art its layers don't have there and opened the file as its PDF part, without the art outside the artboards. That part also has no paragraphs: area type is written line by line, and comes back as area type only where its font is installed and lays the lines out with the same breaks, else as a point type object per line (#508). Art off the page that a PDF does draw opens on the pasteboard. +The app's own editing copy of a file (an EPS after its `%%EOF`, a `.ai`'s `AIPrivateData` streams, a PDF's `AIPDFPrivateData` streams when it was saved with the editing data (#868), Zstandard or zlib, the EPS's in ASCII85) is not documented as a whole. VectorCraft reads its structure: layers and sublayers (names, order, visibility, lock, printing, preview, dimming, colour), groups as they were nested, compound paths (painted by their last path, or the last painted one, with the paths of groups inside them kept as their paths: #1410), clipping groups and layer clipping (several clipping paths in a clipping group, a layer or an opacity mask's art clip to their intersection, and a compound path of clipping paths stays one clip; a filled clipping path keeps its fill, which paints under the art it clips, except the path of a mask that covers several layers, whose fill is read as a path of its own in the layer that holds the mask's path, and a compound clipping path whose subpaths paint differently, whose filled subpaths are read as a compound path of their own under the art it clips; clipping paths that would nest the art past the document's 32 levels stop the editing data from being read: #5789), object names, hidden and locked objects, fills and strokes (grey, CMYK, RGB, named and spot colours, spot colours defined in Lab with their Lab values (#1032), global process colours as global swatches at their tint; a stroke of width 0, `0 w`, on a path, a gradient-filled path, legacy type or in an art style comes in as a 0.25 pt hairline, as from PDF: #1671), linear and radial gradients, pattern fills with their patterns as pattern swatches (#1025), gradient and pattern names in the file up to their first newline (a name that another swatch, or a gradient or pattern defined earlier, already has is numbered "Sky 2"; a name without a newline is kept, and when another swatch has it, the pattern's swatch, or a named color sharing a gradient or pattern swatch's name, is numbered the same way), opacity, blend modes, isolation and knockout, embedded images where their matrix puts them, rotated ones too (#2269), with their alpha channel (CMYK images keep their ink amounts, as they do when a `.ai` opens from its PDF part, and an alpha channel that hides part of a CMYK image becomes a grayscale opacity mask), placed (linked) files as linked images in their place, each showing the low-resolution preview the file keeps of it until its file is found or relinked in the Links panel (#1264), with the folder the file keeps relative to the document's, where the link is looked for when its path is gone, placed PDF and `.ai` pages as placed documents of the [page and Crop to box](https://helpx.adobe.com/illustrator/desktop/add-and-import-files/import-other-file-types/adobe-pdf-placement-options.html) their dictionary names (`AI11 PlacedPDFPageIndex`, `AI11 PlacedPDFCropTo`; a value VectorCraft doesn't read, or a binding to an image variable, leaves a linked image), guides, and every artboard where it is, with its center mark, cross hairs, video safe areas and video ruler pixel aspect ratio. VectorCraft reads `CropAreaActive`, an `/Int` in the dictionary that holds the artboard array, as the index of the active artboard in that array, and the file opens with that artboard active; without it, or when it names no artboard that opens, the first artboard is active. It also reads the Document Raster Effects Settings (resolution, color model, background, anti-alias, clipping mask, Add Around Object and Preserve Spot Colors), the author from the header's `%%For` (an EPS's own header when the editing data's has none), swatches for the header's `%%CMYKCustomColor` and `%%RGBCustomColor` colors that the document has none of, and `%%TemplateBox` in older files; a setting with a value of another type or out of range keeps its default. Objects on Path groups open live, with their path, their objects in order along it, Pivot and Rotate; one with a dragged spacing or other options opens as a plain group. A gradient with stops in the middle runs its whole ramp across its shape, and a gradient object does not pass its fill to the next path (#1390). An object whose art style is one fill and one stroke at most (solid colours, its own gradient, a variable-width profile on a Stroke Offset stroke or written as each side's widths) with Drop Shadow, Inner Glow, Outer Glow, Feather, Round Corners, Scribble, Offset Path, Outline Object, Outline Stroke, Convert to Shape, Tweak (only when it moves nothing), Pucker & Bloat at 0 or Bas Relief (read from its settings block: [raster effects reference](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/apply-filter-effects/raster-effects-reference.html), [Photoshop File Formats Specification](https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/), [scripting the filter gallery](https://community.adobe.com/questions-712/scripting-support-for-the-filter-gallery-1064646)) comes in as itself with them and their saved settings. A path, compound path or group (not a clipping group) whose only effect is Transform (not with copies or Random) or a Free Distort whose corners make a parallelogram comes in as itself with it too, when neither it nor anything in it paints with a gradient or pattern and everything in it is a path, compound path or group with no opacity mask and no effects of its own; Transform that scales, rotates or reflects needs nothing in it to be stroked. Twist as the only effect is read the same way when nothing in the object is stroked: up to 180° either way (a limit VectorCraft sets) on a path or compound path whose segments are all straight, except a compound path with a guide member that reaches past its other members at an angle other than 0°, and up to 90° either way (a limit VectorCraft sets) on another path, compound path or group with no guide in it. One with more, other effects (Zig Zag, a Pucker & Bloat of another amount, a Free Distort with other corners), an effect setting that is not read (an unknown key, a missing or out-of-range value, a Scribble with a color of its own), a variable-width stroke with one centered width array, dashes aligned to corners, a brush other than a Calligraphic or Art one, a Calligraphic brush with settings of its own, an entry that isn't read, a variable width or an angle that follows the path, a path followed by samples of the pen (`(…) Xt n XD`) whose Calligraphic brush varies with the pen, or an Art brush other than the ones described next comes in as its drawn look (a group named after it). Objects in a symbol defined before the file's art styles section, as newer files write it, take the same styles as the layers' objects. A path with a Calligraphic brush otherwise comes in as the path, the brush on its stroke at the stroke's weight, which scales the brush (#372), and so does a path with an Art brush, whose weight scales the art across the path, when all of these hold: the brush stretches its art along the path, unflipped, at 100% in Tints; the path's settings are the brush's own, with no entry that isn't read, no variable width and no effects; its stroke isn't a swatch; and the art is paths, compound paths and groups in solid fills, with no strokes, masks or effects, and has some length along the path. A stroke takes the brush the Brushes panel keeps under its name, and one whose name the panel doesn't keep comes in as its drawn look. Type with an Art brush keeps its drawn look under the type. A Calligraphic brush's Pressure, Tilt, Bearing and Rotation come in as those channels (a 6D Art Pen's brushes vary with the pressure, the bearing and the barrel's rotation); its Stylus Wheel varies at random. The file's Calligraphic, Scatter, Art and Bristle brushes replace the default ones in the Brushes panel, in the file's order, also when the file comes in as its PDF part (a brush library has no layers); pattern brushes and brushes it can't read are left out with a note. When the file opens from its layers, the spot colors in the art of each brush that comes in become swatches, and that art's colors count toward the document's color mode, as a pattern's do. The swatches take at most 20,000 color names in all across the brush art, and each brush-art section keeps at most 20,000 names. Each name keeps its first definition, with the color operators' names before the gradient stops' names. A spot color past those limits makes no swatch, and its color still counts toward the color mode. A spot color that the page's art, a pattern or a symbol also defines keeps the value defined there. Type keeps its art style as a live appearance whatever its stack (an Art brush aside), so it can be retyped: each fill and stroke of the style's stack (solid colours, gradients and pattern fills, placed as the drawn look places them) with its own opacity, blend mode and effects, the effects on the whole object, and where the characters paint among them; the effects read are Warp, Offset Path, Outline Object, Outline Stroke, Transform (with copies, Transform Objects, Transform Patterns and Scale Strokes & Effects; not with Random), Free Distort, Pucker & Bloat, Twist, Zig Zag, Tweak (only when it moves nothing, the file holding none of its random outline), Drop Shadow, Inner Glow, Outer Glow, Feather, Round Corners, Scribble, Gaussian Blur, Bas Relief (its detail, smoothness and light direction from its settings block, or the effect's defaults when the style holds no settings block; a settings block that isn't read keeps the drawn look) and Convert to Shape, and a style with others, or with an effect setting that isn't read, keeps the type's drawn look. Convert to Shape keeps its Rectangle, Rounded Rectangle or Ellipse, its Absolute or Relative size (a relative size in the file is added to each side) and its corner radius; a relative Ellipse, or a setting that isn't read, keeps the drawn look. The page's drawing of such a style isn't held to look like VectorCraft's where its drawn look lay. Gradients take their matrix (`Xm`, radials and skewed ones too), focal point and the order of stops sharing a ramp point; gradient meshes, a clipping path's own fill and its stroke, and the artboards' names are read too. `editingData: "always"` (`convert --editing-data`) opens a `.ai` or an Illustrator EPS from its editing data even where it draws differently from its page, which can be older, with a note. Type is made from the file's text document, whole and editable, shown or not: point type (its frame's matrix, which newer files leave out when it is neither turned nor scaled, read as none), area type (a story in several frames as threaded type) and type on a path, with its characters, fonts, size, leading, tracking, scaling, baseline shift, fill and stroke (grey, RGB or CMYK), alignment, indents and paragraph spacing (a character attribute a run doesn't set comes from its character style, then the style that one is based on, then the document's defaults); area type keeps its frame's Area Type Options rows and columns, the gutter between rows and the gutter between columns, and its first baseline (Fixed, Cap Height, Leading or x Height) with its minimum; type on a path keeps its frame's Type on a Path effect, Align to Path and Flip (a frame whose options set key 6 to true keeps their defaults), and the first frame's Spacing is fitted from the file's layout, not read from the dialog's value; the distance from the path under Align to Path is measured for each character at its size and vertical scale (in vertical type, its horizontal scale), from the top of its font's em box (Ascender), half the height of the top of its font's H (Center) or the bottom of its font's bounding box (Descender); the fit under Gravity does not reproduce the file's layout, and its glyphs can lie up to 7.4 pt from the positions the file keeps; the page's drawing of it (often in pieces) is left out. Vertical type keeps its orientation, its columns from right to left, and a run set to Tate-chu-yoko keeps that setting. When it makes the type of every text object that shows, the page's type is only compared with it, each text object keeps its own group, frame and layer, and a line break inside a paragraph stays one. Where it can't make a text object's type (a frame of another kind), that text object takes the page's type where the text document puts its lines, or else what is left of the page's type in painting order (no group around it); the page's type where made type draws stays that type's, and hidden type is left out with a note. Text wrap is read too: an object whose dictionary has the wrap options (offset and Invert Wrap), or any graphic of a legacy wraparound group (`*w` … `*W`, before or after its type, with no offset), is a wrap object, and area type below it in its layer flows around it when the file opens, threaded type included (#2763). Kerning, underline and the other character and paragraph options aren't read yet. A `.ai` saved without PDF compatibility (a placeholder page) opens from its editing data alone, its point type, area type and type on a path made from the text document. A `.ai` whose PDF part shows only text isn't taken for that placeholder when its page states an art, trim or bleed box: it opens from its editing data alone where that reads, else from its PDF part (#1387). A `.ai` whose PDF part draws nothing at all (an empty page, with or without those boxes) opens from its editing data alone where that reads too: there is no page art to check its layers against, and the empty page would lose all of it. Text objects with an appearance keep their own text and frame, type of hidden layers stays hidden, and type on later artboards lands on its text objects (#1391); area type whose frame is too short for a line of the fallback font shows its first line (the frame is made taller, with a warning in the open result) (#1392). In a PDF saved with some of its artboards, the type on each page after the first goes to an artboard of that page's size after the previous page's artboard, and only to one that leaves an artboard for each later page; the first page's artboard also leaves one for each later page. When several artboards fit a later page, VectorCraft takes the one whose art draws most like the page, and compares at most 16 artboards for all the later pages together. Symbols are read into the Symbols panel, in the file's symbol list order, with their art, their registration point and the instances in their art, and their instances come in live with their matrix, name, hide, lock, opacity, blending mode, isolation, knockout and opacity mask; a symbol whose art isn't read whole (type, placed files, an image it leaves out or anything else it doesn't read) isn't kept. A file that comes in as its page or PDF part because its editing data has no layers (a symbol library), or because its layers can't be read or used (any of the cases below), gets the symbols its editing data defines before its first layer, in the symbol list's order, while its page art stays as the page draws it. Instances of symbols it can't read, instances with appearance changes of their own (a dynamic symbol's), pattern fills whose pattern it can't read, placed files the data keeps no preview of and anything else it doesn't read make the file come in as its page (on a layer that doesn't show, they are left out of that layer), with a warning saying what. An unread object on a shown layer whose box can be found instead comes in as a group of the page's objects inside that box, named after it, with the rest of the layers and groups kept and a warning listing what came in as the page's art; the file still comes in as its page when live art or another unread object shares that page art, when the object spans two artboards or lies on an artboard that has no page, when no page art lies inside its box, when that page art is inside a page group with a clip, mask, transparency or appearance, when the object holds a frame of threaded type, when the page art uses a pattern, image or swatch that the page lacks or that differs from the editing data's, or when the page art doesn't carry its transparency (#4806). The layers' art is also compared with the page (by lightness, so colours written as their CMYK equivalents compare alike, and by whether a pixel is inked at all); the page is used when they differ by more than 5% (away from type, when all the type is made from the text document), where one draws an object the other doesn't (away from type, whose lines may be laid out afresh), and when an EPS whose page is its art's box has art printed outside it (#735). A `.ai` is not compared with its page, and its PDF part is not imported, when its text document makes the type of every text object (at least one shows, and none is drawn by the appearance of the layer or group it is in), no object is unread, no placed file has a second placement, no live envelope keeps its drawn art, it declares no large canvas, and its artboards are its pages' trim boxes one for one, in points or in the first page's `UserUnit`: it opens from its layers, with the bleed of its pages' bleed boxes. When they differ because some objects draw differently (an object in another color, or one that only one of them draws), each top-level object of the layers that holds such a difference comes in as a group of the page's objects inside its box and the layers stay, with a warning that names the layer or sublayer of each such object as the Layers panel shows it (`` for one without a name) and how many came in from it; an export or Save As to the file's own path then needs `acknowledgeLoss: true`, and a wrap object replaced this way keeps its wrap options. The file still comes in as its page when only edges or type differ, when a difference lies outside every top-level object, when more than half of the top-level objects or more than 64 hold one, when such an object is or holds type or holds a wrap object inside a group, when the page's type of a text object that stays lies inside such an object's box, when the page's art can't replace such an object for one of the reasons above for an unread object, when matching the differences to the objects would take too much work, or when the result still differs from the page. `editingData: "always"` keeps the objects as read, and placed files at the other point their data gives are tried as well. An EPS whose page is its art's box keeps that page when it comes in through its layers, not the editing data's artboard, and a text object counts as drawn by the page by its colours, not only its lightness, so a red stroke stacked over a dark red one stays (#1102). `textAs: "outlines"` opens a `.ai` whose type shows from its PDF part, which has the outlines; `editingData: false` opens any of them as its page or PDF part only, for print pipelines (#735). A file whose import left something out (hidden text, art or layers) is never written over by an export or Save As to its own path unless `acknowledgeLoss: true` (`convert --replace-lossy`), so the original keeps what the document lacks. Where a `.ai` can't be read that way (or its layers are turned off in the import options), we read its PDF-compatible part, so Illustrator-only live objects arrive as appearance, and plain groups arrive ungrouped: that part draws each object on its own and marks only layers, clipping groups and groups with opacity, blending or a mask (those come back). Art outside the artboards isn't in that part at all (Illustrator's PDF part leaves it out), so it doesn't open; the import says so in a note (#472). Its pages still go where the editing data puts the artboards (a grid stays a grid), with the art on each, when it has as many artboards as pages, of the same sizes (#1068); the page of the artboard `CropAreaActive` names is then the active artboard. A `.ai` whose editing data has artboards but no layers also opens on that page under the same check, and its pages stay where they are. A `.ai` whose PDF part's pages are cropped to its art (each page the box of all the art, which is the editing data's bounding box) instead of its artboards opens from its layers, with its own artboards, where they draw as that page does. Its pages are laid out so that art one of them draws past its artboard (notes beside a design, which the part doesn't clip) doesn't lie over the page before it in the row, where it was taken for that page's art: the check against the editing data then found art its layers don't have there and opened the file as its PDF part, without the art outside the artboards. That part also has no paragraphs: area type is written line by line, and comes back as area type only where its font is installed and lays the lines out with the same breaks, else as a point type object per line (#508). Art off the page that a PDF does draw opens on the pasteboard. A run of type in the editing data whose baseline direction is 1 opens with Standard Vertical Roman Alignment (https://helpx.adobe.com/illustrator/using/formatting-asian-characters.html) on, which is VectorCraft's own mapping: its half-width characters stand upright in vertical type, and horizontal type keeps the mark with no change to its layout. A run whose baseline direction is 2 or 3 (Tate-chu-yoko), or that names none in the run, its character style or the document's defaults, opens with it off. The scripting reference lists 1, 2 and 3 as the Standard, vertical rotated and Tate-chu-yoko baseline directions (https://web.archive.org/web/20170621180804/https://wwwimages.adobe.com/content/dam/Adobe/en/devnet/illustrator/sdk/CC2015_3/Illustrator%20VBScript%20Reference.pdf, page 256). A Scatter brush in the editing data whose last 15 numbers start with 1 comes into the Brushes panel in Tints. Each brush art section is read without its frame: an unnamed, unpainted rectangle with no settings of its own at the art's bounds (within 1/1000 pt), closed, or open with its first corner again at the end. A wider frame stays in the art, and an art group with a state or look of its own (hidden, locked, isolated, knockout, an opacity, a blend mode, a name, a mask, a note or an appearance) stays a group. diff --git a/docs/localization-parity.md b/docs/localization-parity.md index 42b90cf48c..6cbad8f5e3 100644 --- a/docs/localization-parity.md +++ b/docs/localization-parity.md @@ -27,7 +27,7 @@ Chinese by `imachus`). Only Georgian is recorded as reviewed by a native speaker | Language | Code | UI strings translated | Dialogs / tooltips / messages | Script support | Native review | Status | To `full` (h) | |---|---|---|---|---|---|---|---| | English | `en` | source, 100% | all | Latin | — | full | — | -| Simplified Chinese (Mandarin) | `zh-hans` | 5,102 rows, 791 of them `@msg` (counted 2026-10-21): menus, `tl!` literals and messages complete when counted | all | CJK UI font from craft-fonts (BIZ UDPGothic) when embedded, else a system font; IME with marked text at the caret; vertical type partial ([type-parity.md](type-parity.md)) | no | full | — (review) | +| Simplified Chinese (Mandarin) | `zh-hans` | 5,102 rows, 791 of them `@msg` (counted 2026-10-21): menus, `tl!` literals and messages complete when counted | all (3,439 `@msg` and 48 `@msgplural` rows, counted 2026-11-13: the untranslated report lists 40 missing messages for it) | CJK UI font from craft-fonts (BIZ UDPGothic) when embedded, else a system font; IME with marked text at the caret; vertical type partial ([type-parity.md](type-parity.md)) | no | full | — (review) | | Spanish | `es` | 4,009 / 4,020 (99.7%) | all (604 messages) | Latin | no | full | — (review) | | Hindi | `hi` | 8,782 rows (2026-11-13): 3,014 `@msg`, 47 `@msgplural`, 41 `@plural`; no gaps in the untranslated report | menus, dialogs, tooltips and scanned messages; contributor-approved loanword terminology; agent wording pass | UI and document text shape with HarfRust; installed desktop Devanagari fallback, or a `Deva` craft-fonts face; web font still needed | contributor terminology review; 2026-11-13 wording pass on messages and longer labels, with a glossary-term test; wider proofread welcome | complete catalog, machine-assisted draft | native review, layout and web font | | Arabic | `ar` | 0 | none | document text: bidi layout and Paragraph Direction; interface: no right-to-left layout, no Arabic shaping in egui | no | none | 25–40 | @@ -54,9 +54,9 @@ plus review. Native-speaker review is human work and isn't in the hours. | Dutch | `nl` | 7,299 rows, 1,609 of them `@msg` and 47 `@msgplural` (counted 2026-11-13 on `main` at `9a1a158a3`): in `COMPLETE_MESSAGES`, and the untranslated report lists the same missing messages for it as for German; one/other plurals | full | | Danish | `da` | 5,279 rows, 750 of them `@msg` (counted 2026-10-21): menus and `tl!` literals complete when counted; its messages are partial; one/other plurals | full | | Russian | `ru` | 4,009 / 4,020 | full | -| Ukrainian | `uk` | 4,009 / 4,020 (one/few/many plurals) | full | +| Ukrainian | `uk` | 8,802 rows, 3,439 of them `@msg` and 48 `@msgplural` (counted 2026-11-13); one/few/many plurals | full | | Hungarian | `hu` | 5,253 rows (counted 2026-10-21): menus, `tl!` literals and messages complete when counted; one plural form | full | -| Polish | `pl` | 5,130 rows (counted 2026-10-21): menus, `tl!` literals and messages complete when counted; one/few/many plurals | full; native review pending | +| Polish | `pl` | 9,044 rows, 3,439 of them `@msg` and 48 `@msgplural` (counted 2026-11-13): the untranslated report lists 46 missing messages for it, and 47 menu strings, 26 `tl!` literals, 11 undo labels and 45 swatch names; one/few/many plurals | full; native review pending | | Finnish | `fi` | 5,318 rows (counted 2026-10-21): menus, `tl!` literals and messages complete when counted; one/other plurals, 797 `@msg` rows | full; AI-assisted, native proofreading pending | | Czech | `cs` | 5,240 catalog entries, including 795 `@msg` rows (counted 2026-10-21); menus, literals and messages complete when counted | catalog complete; render-site gaps reduced; native review pending | | Bosnian | `bs` | 5,841 rows (counted 2026-10-30): menus, `tl!` literals and messages complete when counted; one/few/other plurals | full; AI-assisted, native review pending | diff --git a/docs/mcp.md b/docs/mcp.md index f7d99cbd04..f756bc8c97 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -3170,8 +3170,13 @@ already walks Image Trace. Short agent entry points: reply's `defined` lists the variables the import defined. While the variables are locked, an import whose header would define a variable fails with "variables are locked". A `dataset.import` file that isn't UTF-8 is read as Windows-1252, unless it starts with the UTF-8 byte-order mark. - A file that starts with a UTF-16 byte-order mark is read as UTF-16, and a file without one that holds NUL bytes is - refused. `csv` and `data` are read as the text they hold. + A file that starts with a UTF-16 byte-order mark is read as UTF-16. A file without one that holds NUL bytes is read + as UTF-16 when at least half of its two-byte units hold a NUL byte, as characters from U+0001 to U+00FF do, in the + byte order that reads a line break (`\n` or `\r`). It is refused when fewer of its units hold a NUL byte (UTF-8 or + Windows-1252 text with stray NUL bytes, or UTF-16 text made mostly of other characters, which needs a byte-order + mark), when both byte orders read a line break (the text holds U+0A00 or U+0D00), when it has an odd length, and + when it isn't valid UTF-16 in that order or holds a NUL character. A file with no line break has no data rows and is + refused for that. `csv` and `data` are read as the text they hold. - Variable libraries: `variable.loadLibrary {path|xml|dataBase64}` (the Variables panel menu's Load Variable Library…) replaces the document's variables and data sets with a variable library's in one undo step. A load, like a `dataset.import`, adds no undo step when it leaves the variables and data sets as they were. The library @@ -3516,7 +3521,8 @@ already walks Image Trace. Short agent entry points: at the pointer selects under these rules: the arrow with a filled square for a face, with a short line for an edge, and with an x for nothing. It keeps the look it had at the press until the release. The Live Paint Bucket's options (`tool.setOption {tool: "livePaintBucket", values}`; double-clicking the tool opens - them, dialog `livePaintBucketOptions`) are `paintFills` (on), `paintStrokes` (off), `highlight` (on), `color` (the + them, dialog `livePaintBucketOptions`) are `paintFills` (on), `paintStrokes` (off), `cursorSwatchPreview` (on), + `highlight` (on), `color` (the highlight color, `#rrggbb` or a layer color's name; `#ff2a2a`) and `width` (the face highlight's width, 1 to 20 screen pixels; 4; an edge's highlight is half as wide). The dialog's OK gives an error for a `color` with an alpha part (`#rrggbbaa` or `#rgba`) and changes nothing. `tool.setOption` gives an error that names the option and sets none of @@ -3529,6 +3535,14 @@ already walks Image Trace. Short agent entry points: `livePaint.strokeEdge` when an edge is within 4 screen pixels of the pointer and `livePaint.fill` otherwise, and Shift-click runs `livePaint.fill`. With both off, a click runs nothing. With `highlight` off, the face or edge under the pointer is not outlined. + With the Live Paint Bucket selected and no drag in progress, Left and Right without Shift, Alt or Cmd/Ctrl (which + keep their shortcuts) run `paint.setFill {swatch, ids: []}` (or + `paint.setStroke` when the Stroke proxy is in front) with the color swatch before or after the active paint in the + Swatches panel, wrapping around at the ends; from a color that is no swatch, Right picks the first swatch and Left + the last, and with no color swatch the tool does not take the keys. The selected art keeps its paint. With + `cursorSwatchPreview` on, the active paint shows as a ringed chip above the pointer between the swatches before and + after it, except during a fill drag or with Alt held; a solid color that is no swatch shows alone, and a paint that is not a solid color shows no chip. Left and + Right step the swatches with `cursorSwatchPreview` off too. `livePaint.merge` keeps the bottom Live Paint group's id, name, lock, visibility, transparency, appearance, opacity mask and graphic style link. With a Live Paint group among the objects, `livePaint.make` adds the others to it as `livePaint.merge` does, and so does `livePaint.fill {ids}` when `point` is outside that group's faces. @@ -7218,7 +7232,7 @@ hatches filled, pattern hatches as their boundaries), text and multiline text po (one per look when their art takes colour "by block"), anonymous blocks such as dimensions groups. Indexed colours (7 is black on paper), true colour, lineweights (`scaleLineweights` scales them with the art), linetypes and transparency resolve through layers and blocks. What is left out (viewports, images, meshes, unknown entities) is -listed in `warnings`. Binary DXF and DWG files answer an error saying to save them as ASCII DXF. +listed in `warnings`. ASCII and binary DXF files are read; DWG files answer an error saying to save them as DXF. ```json {"name":"run_command","arguments":{"command":"document.dxfInfo","params":{"path":"/tmp/plan.dxf"}}} @@ -9897,8 +9911,8 @@ The Shape Builder tool's options are its Shape Builder Tool Options (dialog `sha `openFilledAsClosed` (on: a filled open path bounds a region as if an invisible edge closed it; off: it cuts regions as an unfilled path does), `pickColorFrom` (`artwork`, the default: a merged shape takes the appearance, opacity and blending mode of the front-most selected object under the drag's first point, else of the one under its last point, -else of the front-most selected object; `swatches`: the current fill, and the Left and Right arrow keys step the -current fill through the document's color swatches), `cursorSwatchPreview` (off; with `swatches`, chips above the +else of the front-most selected object; `swatches`: the current fill, and the Left and Right arrow keys without +Shift, Alt or Cmd/Ctrl step the current fill through the document's color swatches), `cursorSwatchPreview` (off; with `swatches`, chips above the pointer show the current fill and the swatches before and after it), `selection` (`freeform`, the default, or `straightLine`: a drag touches what the line from its first point to the pointer crosses), `highlightFill` (on by default; when it is off, merge mode shades no regions), `gapDetection` (off) with `gapLength` (pt, 0 to 72; 3), `clickStrokeSplitsPath` (In Merge Mode, @@ -10798,7 +10812,8 @@ Commands: - `addon.pathtools.cornerSet {ids?, anchors?, items?, radius, kind?, every?, minAngle?, maxAngle?}` cuts live corners, the ones Direct Selection's corner widgets and the Corners dialog edit, as one undo step. `ids` (default: the selection) are the paths and `anchors` the anchor indices of each path's outline with no corners cut; without `anchors`, a path's direct-selected - anchors, or all of them. `items: [{id, anchors?}…]` gives each path its own instead. Only anchors where two sides meet + anchors, or all of them. `items: [{id, anchors?}…]` gives each path its own instead; a member key other than `id` + and `anchors`, or `items` given with `ids`, is an error. Only anchors where two sides meet at an angle take a corner: smooth anchors and open ends are skipped, and it is an error if none is left. `radius` is 0 to 1,000,000 pt, drawn no larger than fits; `kind` is `round`, `invertedRound` or `chamfer` (default: each corner's own). `every` (`all`, `odd` or `even`; default `all`) keeps, of those anchors, only the odd- or even-numbered ones, @@ -10808,7 +10823,7 @@ Commands: be more than `maxAngle`, and it is an error, saying so, if no chosen corner is in the range. Object › Plug-ins › Path Precision Tools › Set Corners… (also in the Anchor Inspector's Corners section) sets these with Preview. → `{ids, corners}`. - `addon.pathtools.cornerRemove {ids?, anchors?, items?}` makes those corners sharp again, as one undo step; a plain path - with none left is plain again. → `{ids, corners}`. + with none left is plain again. Its `items` take the same keys as `cornerSet`'s. → `{ids, corners}`. - `addon.pathtools.slideAnchor {id, subpath?, anchor, t}` moves an anchor along its path, the segments beside it refitted so the outline stays (the anchor count and index stay). `t`, -0.98 to 0.98, says where: positive, a curve parameter on the segment after the anchor; negative, back from the end of the one before. An anchor at a sharp corner loses it, as diff --git a/docs/roadmap.md b/docs/roadmap.md index 6f631fe88b..74dac90ec8 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -10,6 +10,8 @@ > > Numeric spinner update (2026-11-10): held mouse arrows repeat past the click timeout; scores and estimates unchanged (#6307). +> **PDF import status (2026-11-14, #6957):** Outlined Indic glyphs retain their full stroke properties; translucent glyphs stay separate, and a soft mask attaches to each glyph separately. Scores and estimates unchanged. + ## Feature submission evidence M4: Explicitly requested editing data keeps a single artboard larger than its 14,400 pt capped PDF page (#6865). Scores and estimates unchanged. @@ -56,6 +58,7 @@ M7 type: Touch Type moves a right-to-left character along its line and up from i | 2026-11-13 | minor | PDF import: glyphs inside a marked-content span with an empty `ActualText` come in as outlines in their fill and stroke instead of being left out, adding no text (#6971; `empty_actual_text_keeps_the_glyphs_art` in `crates/pdf/src/tests/actual_text.rs`). Scores and estimates unchanged. | | 2026-11-13 | minor | Library panels (swatch, Color Book, brush, symbol and graphic style libraries): in a panel made taller the list fills the space above the footer instead of scrolling inside 220 or 280 pt (#2992; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/library_panel/tests.rs`). Scores and estimates unchanged. | | 2026-11-13 | minor | Swatches: in a panel made taller the swatch list fills the space above the footer instead of scrolling inside 150 or 200 pt (#1638; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/swatches/tests.rs`). Scores and estimates unchanged. | +| 2026-11-13 | minor | M4: PDF import (#5235, #6906): Indic type keeps its marks on their line, and a line whose type would not draw as the file does keeps the file's glyphs as outlines (opaque, alike-stroked ones share a path except under a soft mask, where each glyph keeps its own path and mask; translucent ones keep their own). Scores and estimates unchanged. Evidence: `crates/pdf/src/tests/reshaped.rs`. | | 2026-11-10 | minor | M13 / G6: MCP catalogue (#6460): headless lists UI commands, eight prompts, 33 tools, effect vs command ids; scores and estimates unchanged. | | 2026-11-08 | minor | Character Styles panel: a double-click on a user style's row opens its Character Style Options (`ui.charStyleOptions`); the dialog keeps a fixed width and scrolls its sections in a shorter window, so OK and Cancel stay on screen. Tests `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options` and `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list`. Scores and estimates unchanged. | | 2026-11-08 | minor | #3380, deletion only: preserve gradient placement and exact surviving geometry; consume owned subpaths with a shared original-node snapshot; consolidate status/evidence and document command/helper contracts. Compound behavior and the existing M2 status entry are retained. Endpoint highlighting remains open; scores and estimates unchanged. | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 19b9c8d319..296bd84b2b 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -12,6 +12,8 @@ > > **Flyout update:** 2026-11-06 — resizable icon-strip flyouts and bottom-aligned panel footers (#5713); scores and estimates unchanged. +> **PDF import status (2026-11-14, #6957):** Outlined Indic glyphs retain their full stroke properties; translucent glyphs stay separate, and a soft mask attaches to each glyph separately. Scores and estimates unchanged. + ## Feature submission evidence EPS embedded fonts, 2026-11-09 (#6023–#6067): the fonts an EPS carries draw their glyphs instead of being set as type in an installed font: composite (Type 0) fonts with the 8/8 mapping, plain Type 42 fonts (characters from their glyph names or character map, widths from the font), CID-keyed fonts over CMaps (Type 0 and Type 2 CIDFonts, CIDFonts in a FontSet's Compact Font Format data, base-font CMaps, named CIDFonts over predefined Unicode CMaps set as type) and embedded Type 1 fonts; the show operators' spacing along the baseline is kept as tracking, `kshow` included. Each step is charged to the interpreter's budgets. Hand-written test files only (no corpus file uses these fonts); scores and estimates unchanged. Evidence: `crates/eps/src/import/tests_composite.rs`, `tests_type42.rs`, `tests_cid.rs`, `tests_type1.rs`; details in [file-format-parity.md](file-format-parity.md). @@ -60,6 +62,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard | 2026-11-13 | minor | Library panels (swatch, Color Book, brush, symbol and graphic style libraries): in a panel made taller the list fills the space above the footer instead of scrolling inside 220 or 280 pt (#2992; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/library_panel/tests.rs`). Scores and estimates unchanged. | | 2026-11-13 | minor | Swatches: in a panel made taller the swatch list fills the space above the footer instead of scrolling inside 150 or 200 pt (#1638; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/swatches/tests.rs`). Scores and estimates unchanged. | | 2026-11-13 | minor | Swatches panel: its menu's Show Recent Colors hides and shows the panel's Recent Colors row, checked by default and kept between sessions apart from the Color panel's (#6617); scores unchanged. | +| 2026-11-13 | minor | M4: PDF import (#5235, #6906): Indic type keeps its marks on their line, and a line whose type would not draw as the file does keeps the file's glyphs as outlines (opaque, alike-stroked ones share a path except under a soft mask, where each glyph keeps its own path and mask; translucent ones keep their own). Scores and estimates unchanged. Evidence: `crates/pdf/src/tests/reshaped.rs`. | | 2026-11-09 | minor | Stroke panel: Line Arrow, a 41st generated arrowhead: two arms of the head's weight (stroke weight × arrowhead scale, at least 0.25 pt: the line's weight at 100 % for lines of 0.25 pt or more) at right angles, a sharp tip and square-cut ends, twice as wide as the other heads; bounds and clicks follow each head's own reach (`stroke.set` `LineArrow`, #5421); scores and estimates unchanged | | 2026-11-09 | minor | Canvas: a 3D effect (Extrude & Bevel, Inflate, Rotate, Revolve) changed on type or a group draws again where its art was and is, measured by that art; the canvas measures through its renderer and draws the part with the art it made to measure it. Exports and Object › Rasterize take the solid of 3D type. Fit to Artwork Bounds and per-artboard SVG export measure every artboard through one renderer, building each solid once. A 3D effect on a fill or stroke that builds nothing (Revolve after Roughen) no longer overflows the stack on the canvas, in Object › Rasterize and in raster and EPS exports: the fill or stroke draws as without it. Tests `tests::changed::a_3d_effect_changed_on_type_or_a_group_changes_where_its_solid_was`, `fx::tests::a_renderer_measures_the_art_on_each_artboard_building_each_solid_once`, `canvas::tests::an_edit_to_a_3d_effect_redraws_with_the_art_measured`, `fx::tests::a_3d_effect_that_builds_nothing_draws_the_item_as_without_it`. Scores and estimates unchanged. | | 2026-11-08 | minor | Style panels: a double-click on a user character style's row opens its Character Style Options (`ui.charStyleOptions`), and on a paragraph style's row its Paragraph Style Options (rename); the Character Style Options dialog keeps a fixed width and scrolls its sections in a shorter window, so OK and Cancel stay on screen. Tests `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options` and `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list`. Scores and estimates unchanged. | @@ -568,6 +571,7 @@ since 2026-10-01. - **Save refusal (#6146):** ordinary File > Save to its own location offers Save As after a terminal permission/read-only refusal, suggesting the original name and format, preserving options for the unchanged format and opening the chosen format’s Save options on a change. Cancel keeps the failed-save state. Busy pickers, recovery-copy errors, other failures, explicit destinations and Close/Quit keep the existing dialog. Engine, UI and MCP regression cases are in `cmd/fileio/tests_readonly.rs`, `io/tests_read_only_save.rs` and MCP `tests/fileio.rs`; focused UI regressions passed; engine regression execution and native panel acceptance pending. Scores and hours unchanged. - **PDF authored replacement text (#6165):** `crates/pdf/src/tests/actual_text.rs` covers replacement once with suffix placement, PDF text-string decoding, empty and nested owners, sibling spans, page reset, multiple text-show operations, style/line changes, fill-and-stroke, reader windows and bounded input. Authored logical-order stretches are protected while adjacent ordinary text still undergoes reconstruction. The replacement takes its first placed glyph's style and line; its characters are not redistributed over later lines/styles. Exact mixed-direction paragraph layout is not claimed. No export changes; scores and hours stay at 75% / 10–20 h. +- **PDF Indic type (#5235, #6906):** `crates/pdf/src/tests/reshaped.rs` covers a vowel sign the file draws before its consonant (the line keeps the file's glyphs as outlines, with a note), text in reading order (stays type), a mark with no advance (stays on its line, not vertical type of its own), outlined glyphs stroked with different dashes and translucent outlined glyphs (each keeps its own path). Synthetic font only; one real Gujarati file checked by eye on page 1. Indic type in an uninstalled font keeps the file's glyphs as outlines; reordering signs so more lines stay editable is not done. Scores and hours stay at 75% / 10-20 h. - **Selection — disconnected path deletion (#3380, deletion only):** Clear/Delete and Cut turn surviving disconnected pieces of an ordinary contour into independent selected sibling objects. The first keeps its ID; all keep appearance, baked transforms and stacking order. `deletion_split_preserves_gradient_placement` compares rendered survivors with the original paint space and checks linear/radial fill/stroke vectors, already placed gradients and atomic Undo/Redo; connected remainders keep automatic fitting. Existing multi-subpath paths and explicit compound members retain their semantics. Original synthetic regressions in `crates/engine/tests/it/delete_path_pieces.rs` cover styled/transformed rectangles, cubic handles, compound preservation and atomic Undo/Redo; `crates/ui-egui/src/tests/removeanchors.rs` covers real-frame Delete/Backspace and a second Delete removing all survivors. Segment endpoint highlighting remains open. Scores and hours unchanged. @@ -788,6 +792,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - Variables (data merge): text, visibility and image variables bound to objects (an object may carry several), dataset rows applied in one undo step (`variable.*`, `dataset.*`) from a Variables panel and Window › Variables, with dialogs to define, bind and edit, Make Text/Visibility/Image Dynamic, Capture/Update Data Set, CSV import/export (`dataset.import` / `dataset.export`), and a row in italics when an edit leaves the art not matching it; an image dataset value is a file path and apply keeps the object's bounds; bindings let go of deleted art and locked art is left alone except by visibility values; every command, like the rest, is drivable over MCP and the CLI. - Export for Screens numbers distinct row files whose names collide, compared without case, as `-2`, `-3`… instead of leaving them out; identical rows still write one file. It puts row folders that differ only in case into one folder (`document.exportForScreens`). - Variables: Import Data Sets… (`dataset.import`) reads tab-separated files as well as comma-separated ones. Every header cell is a variable, and the rows replace the document's data sets as Data Set 1, Data Set 2 and so on. An import error about a row's values gives the file line the row starts on. + - Variables: Import Data Sets… (`dataset.import`) reads a UTF-16 file without a byte-order mark, instead of refusing it, when at least half of its two-byte units hold a NUL byte; it uses the byte order that reads its line breaks. - Variables: Import Data Sets… (`dataset.import`) defines the variables a file's header names that the document lacks, unbound. `#Shown` defines a visibility variable, `@Photo` defines an image variable, and a header without a prefix defines a text variable. A header that is a variable's exact name keeps naming it, and any other `%` header (graph data files) is refused. - Variables: Load Variable Library… in the Variables panel menu (`variable.loadLibrary`) replaces the document's variables and data sets with a variable library's, read from its XML file, in one undo step: every data set is deleted, and every variable is deleted with its bindings and values, except a text variable the library also declares, which stays bound so the library's data sets change its objects (#4136); then the library's other text variables are defined, unbound, and its data sets take the text of each value's `p` elements, one paragraph each. Variables of other kinds are left out with a warning that names their kinds. - Variables: Save Variable Library… in the Variables panel menu (`variable.saveLibrary`) writes the document's text variables and data sets as a variable library's XML file, which Load Variable Library reads back with the same text variables, data set names and text values. Variables of other kinds are left out with a warning that names their kinds. @@ -886,6 +891,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - Window › Help Bar shows or hides the tool-help strip at the bottom of the window apart from the status bar (`window.helpBar`). Each setting is kept with the UI preferences and in saved workspaces, and Presentation Mode hides both bars. Layouts saved before the setting existed show the Help Bar where they show the status bar (`help_bar_toggle_is_independent_and_saved_in_workspaces`, `help_bar_and_status_bar_render_independently`, `legacy_help_bar_visibility_follows_each_layouts_status_bar`, `a_help_bar_setting_the_file_lacks_is_saved`). - Czech render-site labels: desktop/web file filters, diagnostics, suggested preset names and contributor tooltips/plurals now use catalog lookups; gradients have Czech adjective agreement and printer marks have a separate context (PDF/Print and Summary). Search, Home, toolbar/panel tooltips and Preferences already look up their labels. Every complete catalog has rows for these labels and for the Roman and Japanese printer mark styles. Evidence: `i18n::tests::czech_render_site_follow_up`, `i18n::tests::complete_catalogs_translate_render_site_labels`, `dialogs::tests_modal::printer_mark_labels_are_distinct_from_language_names`; see [localization-parity.md](localization-parity.md). - The History panel, Edit › Undo and Edit › Redo translate the names of the steps that apply or redefine a character or paragraph style and of the step that redefines a graphic style: each such step keeps its template (`Apply {name}`, `Redefine {name}`, `Redefine Graphic Style “{name}”`) and the style's name, every complete catalog has a row for each template, and the panel and the menu show the style's name as the document holds it, except the Normal styles' names, which they show in the interface language (`steps_named_after_a_style_list_the_template_around_the_name`, `undo_and_redo_name_a_style_step_around_the_style_name`). + - The Polish catalog (`crates/ui-egui/src/i18n/pl.tsv`) has an `@msg` row for the status and error messages the untranslated report (`untranslated_report`) finds in the sources, 3,439 `@msg` rows in all: the errors of commands, scripts, file import and export and plug-ins. The report lists 46 Polish messages: 44 that open #7211, #7214, #7116, #7330 and #1931 translate, and 2 that no language has a row for. A message with two placeholders in a row (`Template::parse` in `crates/ui-egui/src/i18n/catalog.rs`) is still shown in English. - The status bar translates the limits a plug-in run can exceed (its instruction, time and memory budgets and its output size) and the error of a plug-in removal that leaves the plug-in's grant in the plug-in store, in every language that translates every message. The untranslated-strings report also lists messages that an error or a status takes from a `&str` constant (`plugin_limit_errors_are_translated`, `message_scan_reads_messages_held_in_constants`). - The status bar translates the plug-in host's other errors (manifest, module and run checks, the output an importer, exporter or effect returns, and the approval a plug-in's permissions need) in every language that translates every message. A JSON object or array inside a message stays as written, and a message that wraps another one, such as `plug-in manifest: {0}`, is matched by its own row before a row that starts with a placeholder. The reasons inside these errors (what is wrong with a parameter's spec or dialog keys, the value a parameter needs, what is wrong with an object, stroke, paint or effect in a plug-in's output) are translated with them, and the untranslated-strings report lists the reasons the plug-in host's error helpers take (`plugin_messages_are_translated_in_every_complete_catalog`, `plugin_errors_translate_with_their_values`, `plugin_error_reasons_are_translated_with_the_error`, `message_scan_reads_plugin_helpers`, `templates_that_start_with_text_match_first`). - The status bar translates the errors a script's `File` and `Folder` objects, `vc.run`, `$.evalFile`, the `$` object's properties and functions, `alert`, `confirm` and `prompt`, `vc.document` and `vc.log` raise, the limits a run can pass, and the errors of Drop Script Engine, and the line for a run that fails (a syntax error, a thrown error, a limit, a stop or an internal error, with the script's name, the line and column, the included file it is in and the files left written), in every language that translates every message. The script's name, paths, numbers, command ids and the text a script throws itself are shown as they are. A failure with no line and column, such as an error in code `eval` compiled, is shown with one colon after the script's name (`an_error_without_a_place_names_the_script_and_kind`). A message template that names a value twice matches only when both places hold the same text, so the line for a failed run is not taken for the message inside it (`a_repeated_placeholder_matches_the_same_text`). The untranslated-strings report also lists the messages the script host's `fail`, `value` and `over` helpers take and the errors the script interpreter throws, and a constant's text comes from the file or crate that declares it, so the Scripts menu's headers are not listed as messages (`script_errors_are_translated`, `script_host_errors_are_translated`, `message_scan_reads_script_interpreter_errors`, `message_scan_reads_constants_of_the_file_and_its_crate`, `message_scan_skips_test_modules_with_any_test_cfg`). @@ -893,6 +899,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur The counts that Package's status and question, the folder search of Missing Fonts and Find Linked Files, the modified and missing linked file prompts and the CSS Properties panel's notes show use the interface language's plural forms instead of a fixed "(s)" form. Evidence: `the_missing_links_note_uses_each_count_form` in `crates/ui-egui/src/dialogs/tests_package.rs`, `the_modified_links_question_uses_each_count_form` in `crates/ui-egui/src/dialogs/missing_links.rs`, `search_counts_use_each_count_form` in `crates/ui-egui/src/dialogs/missing_fonts/tests.rs` and `the_unnamed_objects_note_uses_each_count_form` in `crates/ui-egui/src/panels/tests_css_properties.rs`. The status bar's messages for relinked, replaced, updated and embedded images, broken links, linked files that can't be read or changed on disk, images that can't be decoded, added and unavailable fonts, copied CSS, downloads and exports with their notes name one item in the singular and more in the plural, in English and in each language's plural forms (`counted_status_messages_take_the_plural_form` in `crates/ui-egui/src/i18n/tests.rs`). The status bar's messages for documents opened or saved with notes and for discarded or restored recovered documents, and the Global Edit options' Results line, do the same (`open_save_and_recovery_messages_take_the_plural_form` in `crates/ui-egui/src/i18n/tests.rs`); the warnings for linked images and placed documents output as their previews and the errors for a page past a placed file's last page or artboard name their counts in the singular or the plural in English. + - The Simplified Chinese catalog (`crates/ui-egui/src/i18n/zh-hans.tsv`) has an `@msg` row for the status and error messages the untranslated report (`untranslated_report`) finds in the sources, 3,439 `@msg` rows in all: the errors of commands, scripts, file import and export and plug-ins. The report lists 40 Simplified Chinese messages: the composite font, justification order and Blob Brush connect end errors that open #7211, #7116 and #7330 translate, and two messages that no catalog has a row for yet. A message with two placeholders in a row (`Template::parse` in `crates/ui-egui/src/i18n/catalog.rs`) is still shown in English. - Edit › Undo and Edit › Redo, in the in-window and native menus, name the step in the interface language as the History panel lists it (`panels::history::step_name`), so when the catalog has no plain row for a step named after an effect, such as Feather, the menu shows the translation of the effect's menu row without its ellipsis (`undo_and_redo_name_the_step_as_the_history_panel_does`). - The History panel translates the undo step names the engine, the tools and the shell write as literals: the untranslated report (`untranslated_report`) lists any a complete catalog lacks, and a step whose catalog row exists only with an ellipsis (such as an effect's menu name) shows that row without the ellipsis. - The German catalog (`crates/ui-egui/src/i18n/de.tsv`) has an `@msg` row for the status and error messages the untranslated report (`untranslated_report`) finds in the sources, 3,433 `@msg` rows in all: the errors of commands, scripts, file import and export and plug-ins. The report lists 48 German messages; 38 of them are the composite font, select-a-path and justification order errors that open #7211, #7214 and #7116 translate. A message with two placeholders in a row (`Template::parse` in `crates/ui-egui/src/i18n/catalog.rs`) is still shown in English. @@ -1297,6 +1304,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur In area type of a shape other than a rectangle, each line's whole band, ascent to descent, stays inside the frame: where an edge pinches in within the band, the line ends at the narrowest point, and a line runs beside a hole that starts and ends within its band, not across it. In area type of any shape, a line also stays clear of a text wrap object that reaches into any part of its band, and inside an Invert Wrap object over its whole band (`crates/text/src/layout/region.rs` tests). In area type whose frame has several contours, a line runs across an edge two contours share only when their edges lie exactly on one line, so a gap between contours keeps lines from crossing it, even a gap one unit in the last place wide near the edge of the canvas; an edge divided by an anchor exactly on it still lets lines cross (`layout::region::separate_slanted_contours_keep_a_four_ulp_gap_near_canvas_limit`, `shared_slanted_edge_still_joins_near_canvas_limit`, `area_type_sets_no_line_across_a_four_ulp_gap_between_slanted_contours`). With Invert Wrap, the spans a line keeps inside a wrap shape of many parts (a comb of 500 teeth) are found by stepping through the line's spans and the shape's spans once for each piece of the band, so the work grows with the number of spans, not with its square (`crates/text/src/layout/region.rs` tests). + Text Wrap Options › Offset is a distance field in the document's units: a bare number is in those units, a typed unit ("12 pt") is read as typed, and OK sends points. In a document in picas, a bare number follows Preferences › Units › Numbers Without Units Are Points as the other length fields do: it is in points while that preference is on (the default) and in picas while it is off (`dialogs::command::tests::text_wrap_offset_in_picas_follows_numbers_without_units_are_points`). An Offset typed outside -1000 to 1000 pt, VectorCraft's own range for the command, or text that doesn't read, is refused: the field flashes and the dialog stays open, whether Enter or a click on OK ends the entry; in every dialog drawn by the shared dialog window, a click on OK no longer confirms it when the distance field it takes the focus from refuses its text (`dialogs::command::tests::text_wrap_offset_field_takes_document_units_and_refuses_values_outside_its_range`). Behavior reference: [the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/enter-values-in-panels-and-dialog-boxes.html). The Character panel's Small Caps, Superscript and Subscript buttons and the panel menu's items of the same names turn small caps and the superscript or subscript position on and off for the selected type, or for the text the Type tool has selected (`text.setFormat` or `text.setRangeStyle` `{smallCaps, position}`), in Document Setup's proportions. Turning Superscript on turns Subscript off, and turning Subscript on turns Superscript off. A button or item shows as on when the first selected character (at a caret, the character before it) has its attribute. The Character panel's Anti-aliasing Method dropdown, under Character Rotation, sets how the edges of the selected type objects are drawn as pixels (`text.setFormat {antiAlias}`), for the whole object, with each frame of a thread keeping its own method and graph labels keeping it when the graph is drawn again, on the canvas, in raster exports and when the type is rasterized. VectorCraft defines the methods: Sharp, the default, draws edges as before; None paints a pixel only where the type covers at least half of it; Crisp shows a pixel covered by a share c at `2c - 0.5`, and Strong shows it at `2c`, each kept between 0 and 1. SVG, PDF and EPS export are unchanged. Scores and hours unchanged. The OpenType panel's Stylistic Alternates and Titling Alternates checkboxes turn `salt` and `titl` on and off for the selected type, and its Figure menu lists Default Figure, Tabular Lining, Proportional Lining, Proportional Oldstyle and Tabular Oldstyle; Proportional Lining sets `pnum` and `lnum` and turns `tnum` and `onum` off, Tabular Lining turns `pnum` off and keeps `lnum`, Proportional Oldstyle turns `lnum` off and keeps `pnum`, and Default Figure and Tabular Oldstyle turn `pnum` and `lnum` off. Behavior reference: [Format text with OpenType features](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/format-text-with-opentype-features.html) and [Use swashes, titling alternates, or stylistic alternates](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/use-swashes-titling-alternates-or-stylistic-alternates.html) (public documentation). Tests: `panels::opentype::tests`. @@ -1437,6 +1445,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur Object › Live Paint › Merge adds the other selected paths and Live Paint groups to the bottom selected Live Paint group ([Live Paint groups](https://web.archive.org/web/20241230205225/https://helpx.adobe.com/illustrator/using/live-paint-groups.html)), which keeps its id, the paint of its faces and edges, and its name, lock, visibility, transparency, appearance, opacity mask and graphic style link. Object › Live Paint › Make with a Live Paint group selected, and a Live Paint Bucket click on a selected path beside a selected Live Paint group, add the paths to that group the same way. Make, Merge and the Live Paint Bucket take paths, compound paths and groups of them; with type, an image or another object among the selection they report that it has to be converted to paths first and change nothing, as type and raster images can't go into a Live Paint group directly ([Create Live Paint groups](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/create-live-paint-groups.html)); before, such an object went among the group's hidden sources and vanished from the canvas. Evidence: `tests_build::live_paint_refuses_type_and_images_and_changes_nothing`. With the Live Paint Bucket selected, Alt-click on vector art samples its fill, stroke and stroke weight into the paint defaults ([Paint with the Live Paint Bucket tool](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/paint-with-the-live-paint-bucket-tool.html)). On a placed image it samples the image pixel as a solid fill with no stroke. Alt+Shift-click samples only the color under the pointer, including an intermediate gradient color or image pixels, into the active fill or stroke ([Default keyboard shortcuts](https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html)). Neither click paints or changes the selection or selected art, and the next Bucket click paints with the sampled paint. Evidence: `tests_build::live_paint_bucket_alt_sample_paints_next_face_without_changing_selection`. Double-clicking the Live Paint Bucket opens Live Paint Bucket Options ([Paint with the Live Paint Bucket tool](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/paint-with-the-live-paint-bucket-tool.html)): Paint Fills (on) and Paint Strokes (off) set whether a click paints faces, edges or both, Highlight turns the outline of the face or edge under the pointer on or off, and Color and Width set it (red and 4 px by default). Faces are outlined at the Width and edges at half of it, as the page says faces are highlighted with a thick line and edges with a thin line. With both on, a click paints the edge within 4 px of the pointer, else the face, and Shift switches to Paint Fills only; with one on, Shift switches to the other. The options last across tool switches and are saved with the preferences (`tool.setOption {tool: "livePaintBucket"}`). Evidence: `builder::tests::{bucket_options_choose_what_a_click_paints, bucket_options_set_the_highlight, bucket_highlights_an_edge_thinner_than_a_face}`, `dialogs::live_paint_bucket::tests::double_clicking_the_tool_opens_its_options_and_ok_sets_them`. + Live Paint Bucket Options has Cursor Swatch Preview, as the [help page](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/paint-with-the-live-paint-bucket-tool.html) lists: with the Bucket selected, the active fill or stroke shows above the pointer between the color swatches before and after it in the Swatches panel, and the Left and Right arrow keys pick the swatch before or after it, as the page describes. The selected art keeps its paint. As VectorCraft's own rules, the option is on at first, the arrows step the stroke when the Stroke proxy is in front, they wrap around at the ends and still step with the preview off, a color that is no swatch shows alone until Right picks the first swatch or Left the last, and the arrows do nothing during a fill drag or with no color swatch. Evidence: `tests::build::{live_paint_bucket_arrow_keys_step_the_active_paint_through_the_swatches, live_paint_bucket_arrow_keys_handle_unmatched_paint_few_swatches_and_drags, live_paint_bucket_arrow_keys_pass_swatches_of_the_same_color_for_fill_and_stroke, swatch_arrow_keys_leave_modified_arrows_to_the_shortcuts}`. Live Paint Make preserves the front-most covering source's fill when compound paths share a curved boundary, and Expand keeps the face fills. Regression evidence: `planar::tests::coincident_curves_keep_their_source_faces` checks source order, winding, fill rules and nearby boundaries; `tests::build::live_paint_make_and_expand_keep_abutting_compound_colors` checks native compound paths, Make, Expand and Undo/Redo. This preserves VectorCraft's source-fill rule without changing arrangement precision. Live Paint Gap Options (Object › Live Paint › Gap Options…, `livePaint.gapOptions`): with Gap Detection on, paint stops at the gaps that run from a loose end of a path to the nearest path, up to Small (3 pt), Medium (6 pt), Large (12 pt) or a custom size; Close Gaps With Paths adds an unpainted path across each gap; Preview applies the options live and draws the gaps in the Gap Preview Color. The options are saved, copied and undone with the group, and Merge keeps the bottom group's options when its Gap Detection is on, or else turns Gap Detection on with Small when another merged group has it on. When Gap Detection is off in every merged group, it stays off. View › Show Live Paint Gaps (`view.livePaintGaps`) draws the gaps of the selected Live Paint groups up to their Paint Stops At size, each in its group's Gap Preview Color, until Hide Live Paint Gaps or Hide Edges hides them ([Live Paint gaps](https://web.archive.org/web/20260105111201/https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/find-and-close-gaps-in-live-paint-groups.html)). @@ -1661,7 +1670,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur In a `.ai` opened from its editing data, a path or type object with Offset Path, Outline Object or Outline Stroke on the whole object opens as itself with those effects live, in their order and shown or hidden; on a fill or stroke of type they stay on that fill or stroke. Offset Path keeps its Offset, Joins and Miter Limit, and Outline Stroke takes its width from the stroke. An Offset Path with a setting missing, out of range or not read keeps the drawn art, as does a path with a Path effect on one fill or stroke (`crates/eps/src/import/ai/style/tests.rs`, `crates/eps/src/import/ai/tests.rs`, `crates/eps/src/import/tests_native.rs`). In a `.ai` or EPS opened from its editing data, a Scatter brush whose last 15 numbers start with 1 comes into the Brushes panel in Tints, and each brush art section is read without its frame, an unnamed, unpainted rectangle with no settings of its own at the art's bounds (within 1/1000 pt). A wider frame stays in the art, and an art group with a state or look of its own (hidden, locked, isolated, knockout, an opacity, a blend mode, a name, a mask, a note or an appearance) stays a group (`crates/eps/src/import/ai/tests.rs`). In a `.ai` opened from its editing data, type with Warp on the object or on one of its fills or strokes opens as type with the effect live when the live warp draws as the art saved with it. When it draws differently, or when the file's limit of checks has no check left for it, it opens as that art, and one note says how many did. Type stays live without a comparison when the saved art paints nothing or draws type of its own, in frames of threaded type, when a text variable binds it, and when its text object doesn't come in as one text object (`crates/eps/src/import/ai/envelope.rs`, `crates/eps/src/import/tests_native.rs`). - In a `.ai` opened from its editing data, an object with a Tweak that moves nothing or Pucker & Bloat at 0 opens as itself with the effect live. A path, compound path or group whose only effect is Transform without copies, or a Free Distort whose corners make a parallelogram, opens as itself with it live, and so does an object with nothing stroked whose only effect is Twist: a path or compound path with straight segments at up to 180° either way, and another path, compound path or group with no guide in it at up to 90° either way (limits VectorCraft sets); one twisted further keeps the drawn art. A gradient or pattern, an image, type, a clipping group, an opacity mask or effects inside the object, or a stroke with a Transform that scales, rotates or reflects, keep the drawn art (`crates/eps/src/import/ai/style/tests.rs`, `crates/eps/src/import/ai/tests.rs`, `crates/eps/src/import/ai/read/ops.rs`). + In a `.ai` opened from its editing data, an object with a Tweak that moves nothing or Pucker & Bloat at 0 opens as itself with the effect live. A path, compound path or group whose only effect is Transform without copies, or a Free Distort whose corners make a parallelogram, opens as itself with it live, and so does an object with nothing stroked whose only effect is Twist: a path or compound path with straight segments at up to 180° either way, unless it is a compound path with a guide member that reaches past its other members and the angle is not 0°, and another path, compound path or group with no guide in it at up to 90° either way (limits VectorCraft sets); one twisted further keeps the drawn art. A gradient or pattern, an image, type, a clipping group, an opacity mask or effects inside the object, or a stroke with a Transform that scales, rotates or reflects, keep the drawn art (`crates/eps/src/import/ai/style/tests.rs`, `crates/eps/src/import/ai/tests.rs`, `crates/eps/src/import/ai/read/ops.rs`). A PDF page whose `UserUnit` (PDF 1.6) is above 1 opens at its size in points, its numbers times the `UserUnit` (one above 75,000 counts as 75,000), and `document.pdfInfo` gives its size and boxes in points too. A `.ai` whose editing data has its artboards in the units of such a page opens from that data at the page's size, with its layers, and when the layers can't be read its pages still take the artboard layout of the data, scaled the same way (part of #1482). `document.open`, `file.place` and `document.pdfInfo` reject a `cropTo`, `crop`, `password`, `colorMode` or `textAs` that is not a string, such as `"textAs": true`, and `document.pdfInfo` rejects a `thumbnailSize` that is not a number; the error names the param, and nothing opens or is placed. A param left out or given as null keeps its default (`crates/engine/src/cmd/fileio/tests_pdfimport.rs`). When the PDF content of a `.ai` has a page for each artboard, the layers are compared with every page on its artboard (until the pages compared take 8,388,608 pixels at the comparison's scale, about 67 letter-size pages, or number 128): art that only the layers or only a later page draws is handled as art that differs on the first page is, and a text object that a later page doesn't draw is left out unless its layer doesn't print (`crates/eps/src/import/tests_native.rs`). @@ -2083,6 +2092,9 @@ Corners section in the Anchor Inspector sets the radius and kind, counts the sel Set Corners… (in the submenu and the Corners section) sets the radius and kind with Preview, on all the chosen anchors or only the odd- or even-numbered ones (`every`, #5546), and only the corners whose angle is in a range (`minAngle`/`maxAngle`, #5545). +`cornerSet` and `cornerRemove` refuse an `items` member key other than `id` and `anchors`, and `items` given with `ids`; +saved steps still play (`corner_commands_refuse_an_unknown_item_key`, `corner_commands_refuse_items_with_ids`, +`saved_corner_steps_with_older_item_keys_still_play`). Slide Anchor Along Path drags an anchor along its curve, the two segments beside it refitted by the keep-shape kernel (Shift: where the tangent is a multiple of 45°). Commands `addon.pathtools.cornerSet`, `cornerRemove` and `slideAnchor`, each one undo step; `vectorcraft_pathops::addons::pathtools::slide_anchor`. Tests: `addons::pathtools` in