mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
Merge pull request #1259 from Losminek/cs-ui-code
i18n (cs): translate labels that bypass the catalog lookup (file filters, diagnostics, credits, gradients, print marks)
This commit is contained in:
15 files changed
+155
-32
No files matched your search
+1
-1
@@ -109,7 +109,7 @@ Weights, evidence and the missing items per area: [target-app-parity.md](docs/ta
|
||||
| Korean | `ko` | none | 0% |
|
||||
| Vietnamese | `vi` | none | 0% |
|
||||
|
||||
Also shipped: Traditional Chinese (partial, 80%), Italian, Russian and Ukrainian (full), Czech (menus only).
|
||||
Also shipped: Traditional Chinese (partial, 80%), Italian, Russian and Ukrainian (full), Czech (catalog complete; render-site gaps reduced; native review pending).
|
||||
No catalog has had a native speaker's review. Details: [localization-parity.md](docs/localization-parity.md).
|
||||
|
||||
## Upcoming
|
||||
|
||||
@@ -402,7 +402,10 @@ fn services(inbox: Inbox, place_inbox: PlaceInbox, ctx: egui::Context, locks: Op
|
||||
let inbox = picked.clone();
|
||||
let ctx = place_ctx.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let dialog = fileio::place_filters().fold(rfd::AsyncFileDialog::new().set_title("Place"), |d, (name, exts)| d.add_filter(name, exts));
|
||||
let dialog =
|
||||
fileio::place_filters().fold(rfd::AsyncFileDialog::new().set_title(vectorcraft_ui_egui::i18n::t("Place")), |d, (name, exts)| {
|
||||
d.add_filter(vectorcraft_ui_egui::i18n::tr_ctx(vectorcraft_ui_egui::i18n::current(), "file-filter", name), exts)
|
||||
});
|
||||
let Some(files) = dialog.pick_files().await else {
|
||||
return;
|
||||
};
|
||||
@@ -419,7 +422,9 @@ fn services(inbox: Inbox, place_inbox: PlaceInbox, ctx: egui::Context, locks: Op
|
||||
let inbox = open_inbox.clone();
|
||||
let ctx = ctx.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let dialog = fileio::open_filters().fold(rfd::AsyncFileDialog::new(), |d, (name, exts)| d.add_filter(name, exts));
|
||||
let dialog = fileio::open_filters().fold(rfd::AsyncFileDialog::new(), |d, (name, exts)| {
|
||||
d.add_filter(vectorcraft_ui_egui::i18n::tr_ctx(vectorcraft_ui_egui::i18n::current(), "file-filter", name), exts)
|
||||
});
|
||||
let Some(file) = dialog.pick_file().await else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -307,10 +307,17 @@ dialog_settings!(rfd::FileDialog, rfd::AsyncFileDialog);
|
||||
fn dialog_for<D: DialogSettings>(d: D, request: &PickRequest) -> D {
|
||||
let pick = match request {
|
||||
PickRequest::Open(pick) | PickRequest::Save(pick) => pick,
|
||||
PickRequest::OpenMany => return fileio::place_filters().fold(d.title("Place"), |d, (name, exts)| d.filter(name, exts)),
|
||||
PickRequest::OpenMany => {
|
||||
return fileio::place_filters().fold(d.title(vectorcraft_ui_egui::i18n::t("Place")), |d, (name, exts)| {
|
||||
d.filter(vectorcraft_ui_egui::i18n::tr_ctx(vectorcraft_ui_egui::i18n::current(), "file-filter", name), exts)
|
||||
});
|
||||
}
|
||||
PickRequest::Folder => return d,
|
||||
};
|
||||
let d = pick.filters.iter().fold(d, |d, (name, exts)| d.filter(name, exts));
|
||||
let d = pick
|
||||
.filters
|
||||
.iter()
|
||||
.fold(d, |d, (name, exts)| d.filter(vectorcraft_ui_egui::i18n::tr_ctx(vectorcraft_ui_egui::i18n::current(), "file-filter", name), exts));
|
||||
let d = match &pick.folder {
|
||||
Some(folder) => d.folder(folder),
|
||||
None => d,
|
||||
|
||||
@@ -562,8 +562,12 @@ pub fn status_bar(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
ui.label(
|
||||
egui::RichText::new(format!(
|
||||
"render {:.1} ms · ui {:.1} ms · {:.0} fps",
|
||||
app.perf.render_ms, app.perf.frame_ms, app.perf.fps
|
||||
"{} {:.1} ms · {} {:.1} ms · {:.0} fps",
|
||||
crate::i18n::tr_ctx(crate::i18n::current(), "diagnostics", "render"),
|
||||
app.perf.render_ms,
|
||||
crate::i18n::tr_ctx(crate::i18n::current(), "diagnostics", "ui"),
|
||||
app.perf.frame_ms,
|
||||
app.perf.fps
|
||||
))
|
||||
.size(10.5)
|
||||
.color(t.text_disabled),
|
||||
|
||||
@@ -87,11 +87,14 @@ impl SortKey {
|
||||
SortKey::LastCommit,
|
||||
];
|
||||
|
||||
/// Menu label and table header, in the UI language (the short count headers stay as they are).
|
||||
/// Menu label and table header, in the UI language (the symbolic count headers stay as they are).
|
||||
pub fn label(self) -> (&'static str, &'static str) {
|
||||
match self {
|
||||
SortKey::Name => (tl!("Name (A–Z)"), tl!("Name")),
|
||||
SortKey::Prs => (tl!("Merged PRs"), "PRs"),
|
||||
SortKey::Prs => {
|
||||
let header = "PRs";
|
||||
(tl!("Merged PRs"), tl!(header))
|
||||
}
|
||||
SortKey::Commits => (tl!("Commits"), tl!("Commits")),
|
||||
SortKey::LinesAdded => (tl!("Lines added"), "+LOC"),
|
||||
SortKey::LinesDeleted => (tl!("Lines deleted"), "−LOC"),
|
||||
@@ -125,18 +128,24 @@ impl Contributor {
|
||||
|
||||
/// One line with everything we know, for tooltips.
|
||||
pub fn summary(&self) -> String {
|
||||
format!(
|
||||
"@{}: {} PRs, {} commits, +{} / −{} lines (Δ {}), +{} / −{} binary assets, {} – {}",
|
||||
self.login,
|
||||
self.prs,
|
||||
self.commits,
|
||||
group(self.lines_added),
|
||||
group(self.lines_deleted),
|
||||
signed(self.lines_delta()),
|
||||
self.binary_added,
|
||||
self.binary_deleted,
|
||||
day(self.first_commit),
|
||||
day(self.last_commit),
|
||||
let lang = crate::i18n::current();
|
||||
let template = "@{login}: {prs}, {commits}, +{added} / −{deleted} lines (Δ {delta}), +{binary_added} / −{binary_deleted} binary assets, {first} – {last}";
|
||||
let prs = crate::i18n::trn(lang, self.prs, "{n} PR", "{n} PRs");
|
||||
let commits = crate::i18n::trn(lang, self.commits, "{n} commit", "{n} commits");
|
||||
crate::i18n::fmt(
|
||||
tl!(template),
|
||||
&[
|
||||
("login", self.login),
|
||||
("prs", &prs),
|
||||
("commits", &commits),
|
||||
("added", &group(self.lines_added)),
|
||||
("deleted", &group(self.lines_deleted)),
|
||||
("delta", &signed(self.lines_delta())),
|
||||
("binary_added", &self.binary_added.to_string()),
|
||||
("binary_deleted", &self.binary_deleted.to_string()),
|
||||
("first", day(self.first_commit)),
|
||||
("last", day(self.last_commit)),
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,9 @@ fn details(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog, b: &mut
|
||||
let saving = !d.bool(SAVING);
|
||||
d.fields.insert(SAVING.into(), json!(saving));
|
||||
if saving && d.str("presetName").is_empty() {
|
||||
d.fields.insert("presetName".into(), json!(format!("Preset {}", app.session.prefs.new_doc_presets.len() + 1)));
|
||||
let template = "Preset {number}";
|
||||
let name = crate::i18n::fmt(tl!(template), &[("number", &(app.session.prefs.new_doc_presets.len() + 1).to_string())]);
|
||||
d.fields.insert("presetName".into(), json!(name));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -272,13 +272,19 @@ pub(super) fn choice<T: Choice>(d: &Dialog, path: &str) -> Option<T> {
|
||||
/// A dropdown of the choices `T` (options for which `enabled` is false are greyed).
|
||||
pub(super) fn pick<T: Choice>(ui: &mut egui::Ui, d: &mut Dialog, path: &str, width: f32, enabled: impl Fn(T) -> bool) -> bool {
|
||||
let current = choice_index::<T>(d, path);
|
||||
let label = current.and_then(|i| T::LABELS.get(i)).copied().unwrap_or_default();
|
||||
let chosen = widgets::dropdown_with(ui, path, label, T::LABELS, width, |i| T::ALL.get(i).is_some_and(|c| enabled(*c)));
|
||||
let labels: Vec<_> = T::LABELS.iter().map(|label| choice_label(crate::i18n::current(), path, label)).collect();
|
||||
let label = current.and_then(|i| labels.get(i)).copied().unwrap_or_default();
|
||||
let chosen = widgets::dropdown_with(ui, path, label, &labels, width, |i| T::ALL.get(i).is_some_and(|c| enabled(*c)));
|
||||
let Some(id) = chosen.and_then(|i| T::IDS.get(i)) else { return false };
|
||||
set(d, path, json!(id));
|
||||
true
|
||||
}
|
||||
|
||||
/// Printer mark styles use adjectives, separately from interface language names.
|
||||
pub(super) fn choice_label<'a>(lang: crate::i18n::Lang, path: &str, label: &'a str) -> &'a str {
|
||||
if path == "marks.kind" { crate::i18n::tr_ctx(lang, "mark-style", label) } else { crate::i18n::tr(lang, label) }
|
||||
}
|
||||
|
||||
pub(super) fn number(ui: &mut egui::Ui, d: &mut Dialog, path: &str, suffix: &str, enabled: bool) {
|
||||
let v = get(d, path).as_f64().unwrap_or(0.0);
|
||||
ui.add_enabled_ui(enabled, |ui| {
|
||||
@@ -785,6 +791,7 @@ pub(super) fn option_rows<'a>(ui: &mut egui::Ui, changed: impl IntoIterator<Item
|
||||
for c in changed {
|
||||
let value = match &c["value"] {
|
||||
Value::Bool(b) => if *b { tl!("On") } else { tl!("Off") }.to_string(),
|
||||
Value::String(s) if c["option"] == "marks.kind" => choice_label(crate::i18n::current(), "marks.kind", s).to_string(),
|
||||
Value::String(s) => s.clone(),
|
||||
other => other.to_string(),
|
||||
};
|
||||
|
||||
@@ -296,3 +296,11 @@ fn simplify_dialog_ok_keeps_exactly_one_undo_with_or_without_preview() {
|
||||
assert!(app.session.doc().unwrap().selection.anchors.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn printer_mark_labels_are_distinct_from_language_names() {
|
||||
let cs = crate::i18n::Lang::from_code("cs").unwrap();
|
||||
assert_eq!(save_pdf::choice_label(cs, "marks.kind", "Japanese"), "Japonské");
|
||||
assert_eq!(save_pdf::choice_label(cs, "language", "Japanese"), "Japonština");
|
||||
assert_eq!(save_pdf::choice_label(crate::i18n::Lang::EN, "marks.kind", "Japanese"), "Japanese");
|
||||
}
|
||||
@@ -1651,7 +1651,7 @@ lighting Light Světlo
|
||||
Small Thumbnail View Malé miniatury
|
||||
Swatch Libraries Menu Nabídka knihoven vzorníku
|
||||
User Library Uživatelská knihovna
|
||||
{kind} Gradient Přechod: {kind}
|
||||
{kind} Gradient {kind} přechod
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document V tomto dokumentu nejsou žádné symboly
|
||||
Select art and click New Symbol to make one. Vyberte kresbu a symbol vytvořte tlačítkem Nový symbol.
|
||||
@@ -4472,3 +4472,24 @@ effect Regular Pravidelný
|
||||
Artistic Umělecké
|
||||
Film Grain… Filmové zrno…
|
||||
Highlight Area Oblast světel
|
||||
|
||||
# Czech render-site follow-up (AI drafts; native review requested).
|
||||
file-filter All readable files Všechny čitelné soubory
|
||||
file-filter All placeable files Všechny soubory pro umístění
|
||||
file-filter Swatch libraries Knihovny vzorníků
|
||||
file-filter Flattener presets Přednastavení sloučení průhlednosti
|
||||
file-filter PDF presets Přednastavení PDF
|
||||
file-filter Print presets Přednastavení tisku
|
||||
file-filter SVG Compressed Komprimované SVG
|
||||
file-filter PDF-compatible .ai .ai kompatibilní s PDF
|
||||
file-filter VectorCraft Template Šablona VectorCraft
|
||||
file-filter Templates Šablony
|
||||
diagnostics render vykreslení
|
||||
diagnostics ui rozhraní
|
||||
Preset {number} Přednastavení {number}
|
||||
PRs PR
|
||||
@{login}: {prs}, {commits}, +{added} / −{deleted} lines (Δ {delta}), +{binary_added} / −{binary_deleted} binary assets, {first} – {last} @{login}: {prs}, {commits}, řádky +{added} / −{deleted} (Δ {delta}), binární soubory +{binary_added} / −{binary_deleted}, {first} – {last}
|
||||
@plural {n} PR|{n} PRs {n} PR|{n} PR|{n} PR
|
||||
@plural {n} commit|{n} commits {n} commit|{n} commity|{n} commitů
|
||||
gradient-kind Radial Kruhový
|
||||
mark-style Japanese Japonské
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1120,3 +1120,38 @@ fn as_template(s: &str) -> String {
|
||||
out.push_str(rest);
|
||||
out
|
||||
}
|
||||
|
||||
/// Render-site labels keep English fallback, placeholders and Czech grammar independent of
|
||||
/// the plain language-name key. No global language changes: other UI tests may run alongside.
|
||||
#[test]
|
||||
fn czech_render_site_follow_up() {
|
||||
for (source, expected) in [
|
||||
("All readable files", "Všechny čitelné soubory"),
|
||||
("All placeable files", "Všechny soubory pro umístění"),
|
||||
("SVG Compressed", "Komprimované SVG"),
|
||||
("PDF-compatible .ai", ".ai kompatibilní s PDF"),
|
||||
("VectorCraft Template", "Šablona VectorCraft"),
|
||||
] {
|
||||
assert_eq!(tr_ctx(cs(), "file-filter", source), expected);
|
||||
assert_eq!(tr_ctx(Lang::EN, "file-filter", source), source);
|
||||
}
|
||||
for source in ["SVG", "PNG", "VectorCraft", "unregistered filter"] {
|
||||
assert_eq!(tr_ctx(cs(), "file-filter", source), source);
|
||||
}
|
||||
assert_eq!(tr_ctx(cs(), "diagnostics", "render"), "vykreslení");
|
||||
assert_eq!(tr_ctx(cs(), "diagnostics", "ui"), "rozhraní");
|
||||
assert_eq!(fmt(tr(cs(), "Preset {number}"), &[("number", "12")]), "Přednastavení 12");
|
||||
assert_eq!(fmt(tr(Lang::EN, "Preset {number}"), &[("number", "12")]), "Preset 12");
|
||||
for (kind, expected) in [("Linear", "Lineární přechod"), ("Radial", "Kruhový přechod"), ("Freeform", "Volný přechod")] {
|
||||
assert_eq!(fmt(tr(cs(), "{kind} Gradient"), &[("kind", tr_ctx(cs(), "gradient-kind", kind))]), expected);
|
||||
assert_eq!(fmt(tr(Lang::EN, "{kind} Gradient"), &[("kind", tr_ctx(Lang::EN, "gradient-kind", kind))]), format!("{kind} Gradient"));
|
||||
}
|
||||
assert_eq!(tr(cs(), "Japanese"), "Japonština");
|
||||
assert_eq!(tr_ctx(cs(), "mark-style", "Japanese"), "Japonské");
|
||||
assert_eq!(tr_ctx(Lang::EN, "mark-style", "Japanese"), "Japanese");
|
||||
assert_eq!(tr(cs(), "PRs"), "PR");
|
||||
for (n, expected) in [(0, "0 commitů"), (1, "1 commit"), (2, "2 commity"), (4, "4 commity"), (5, "5 commitů")] {
|
||||
assert_eq!(trn(cs(), n, "{n} commit", "{n} commits"), expected);
|
||||
assert_eq!(trn(cs(), n, "{n} PR", "{n} PRs"), format!("{n} PR"));
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,10 @@ pub(crate) fn describe(paint: &Paint, global: bool, spot: bool) -> String {
|
||||
};
|
||||
crate::i18n::fmt(tl!("{kind}, {model}"), &[("kind", kind), ("model", color.model_name())])
|
||||
}
|
||||
Paint::Gradient(g) => crate::i18n::fmt(tl!("{kind} Gradient"), &[("kind", tl!(g.gradient.kind.label()))]),
|
||||
Paint::Gradient(g) => crate::i18n::fmt(
|
||||
tl!("{kind} Gradient"),
|
||||
&[("kind", crate::i18n::tr_ctx(crate::i18n::current(), "gradient-kind", g.gradient.kind.label()))],
|
||||
),
|
||||
Paint::Pattern { .. } => tl!("Pattern").into(),
|
||||
Paint::None => tl!("None").into(),
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
# Gaps
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged; G11: valid selection after Simplify and Add Anchor Points (#1272); estimates unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; G10: RPM runtime dependency metadata (#1275); estimates unchanged; G15: texture-effect distance searches optimized (#1257); idle-machine/platform drag QA still pending; estimate unchanged; G1: Curvature point display improved (#1236, in part); estimates unchanged; G4: full-name font matching (#1258); Windows font-service QA pending; estimate unchanged; G11: no-op anchor Align keeps history and saved state (#1180 follow-up); estimates unchanged; G1: dedicated Eyedropper cursor and precise-cursor checks (#1269); estimates unchanged; G1: Eyedropper reads visible locked and outside-isolation sources (#1251); estimate unchanged; G11: Direct Selection segment Delete (#1278); estimates unchanged; G1: painted strokes regain the existing default after None/zero-width inheritance (#1253); estimate unchanged; G15: large-selection edits, cached live effects and faster Pathfinder, #1173; G4: proportional vertical metrics done, #966; G11: Shape Builder merge seams on grids of lines fixed, #893; scaled text controls corrected, #1034; group font-size preservation deferred) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Czech render-site localization follow-up; scores and estimates unchanged; Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged; G11: valid selection after Simplify and Add Anchor Points (#1272); estimates unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; G10: RPM runtime dependency metadata (#1275); estimates unchanged; G15: texture-effect distance searches optimized (#1257); idle-machine/platform drag QA still pending; estimate unchanged; G1: Curvature point display improved (#1236, in part); estimates unchanged; G4: full-name font matching (#1258); Windows font-service QA pending; estimate unchanged; G11: no-op anchor Align keeps history and saved state (#1180 follow-up); estimates unchanged; G1: dedicated Eyedropper cursor and precise-cursor checks (#1269); estimates unchanged; G1: Eyedropper reads visible locked and outside-isolation sources (#1251); estimate unchanged; G11: Direct Selection segment Delete (#1278); estimates unchanged; G1: painted strokes regain the existing default after None/zero-width inheritance (#1253); estimate unchanged; G15: large-selection edits, cached live effects and faster Pathfinder, #1173; G4: proportional vertical metrics done, #966; G11: Shape Builder merge seams on grids of lines fixed, #893; scaled text controls corrected, #1034; group font-size preservation deferred) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Every known shortfall against Illustrator, one entry each, **ranked by how much it stops a professional from
|
||||
switching**. This is the work list: unless you were given a task, pick the highest-ranked gap you can make
|
||||
@@ -194,6 +194,8 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
|
||||
## G16 Localization: the five missing key languages
|
||||
|
||||
- **Evidence:** Czech render-site bypasses reduced in file dialogs, diagnostics, preset names and contributor tooltips; gradient grammar and printer-mark context corrected (see [localization-parity.md](localization-parity.md)). Native review and the missing-language work remain; estimate unchanged.
|
||||
|
||||
- **Missing:** Hindi, Arabic, Indonesian, Korean, Vietnamese catalogs; a right-to-left interface and interface
|
||||
shaping for Arabic and Devanagari; messages for Simplified Chinese and Brazilian Portuguese; native review of
|
||||
every catalog. Measured in [localization-parity.md](localization-parity.md).
|
||||
@@ -224,6 +226,7 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-11 | minor | Czech render-site follow-up: file-dialog filters, diagnostics, preset numbering, contributor tooltips/plurals, gradient grammar and contextual printer mark styles; estimates unchanged |
|
||||
| 2026-10-12 | minor | Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | G11: clear stale component refs after Simplify/Add Anchor Points; preview and point counts give visible feedback (#1272); estimates unchanged |
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Localization parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (first per-language table, measured from the catalogs) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (Czech render-site localization follow-up; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Per-language status of VectorCraft's interface. How the catalogs work and how to add a language:
|
||||
[`development.md` › Localisation](development.md#localisation). Part of
|
||||
[target-app-parity.md](target-app-parity.md).
|
||||
|
||||
**How it is measured:** rows with a translation in each `crates/ui-egui/src/i18n/<code>.tsv`, counted on
|
||||
origin/main `01e165af`. The reference is the French catalog, which the tests hold complete: 3,416 interface
|
||||
origin/main `01e165af`, except the Czech row updated against the current local catalog.
|
||||
The reference is the French catalog, which the tests hold complete: 3,416 interface
|
||||
strings (menus, command labels, `tl!` literals: panels, dialogs, tooltips, Preferences) plus 604 `@msg` status and
|
||||
error messages, 4,020 in all. A language's % is its rows over 4,020 (capped at 100% per part). The
|
||||
`complete_menus` flag and `COMPLETE_MESSAGES` list make `i18n::tests` fail if a complete language misses a
|
||||
@@ -48,12 +49,26 @@ plus review. Native-speaker review is human work and isn't in the hours.
|
||||
| Italian | `it` | 4,011 / 4,020 | full |
|
||||
| Russian | `ru` | 4,009 / 4,020 | full |
|
||||
| Ukrainian | `uk` | 4,009 / 4,020 (one/few/many plurals) | full |
|
||||
| Czech | `cs` | 679 / 4,020 (17%): every menu label | menus only |
|
||||
| Czech | `cs` | 4,411 catalog entries, including 636 `@msg` rows (measured locally 2026-10-11); menu, literal and message coverage enforced by tests | catalog complete; render-site gaps reduced; native review pending |
|
||||
|
||||
Eleven non-English catalogs in all. Illustrator, as its public documentation lists, ships around two dozen
|
||||
interface languages (including Korean, Polish, Dutch, Turkish, the Nordic languages, Hungarian, and Middle East
|
||||
editions with Arabic and Hebrew); it doesn't ship Hindi, Indonesian or Vietnamese.
|
||||
|
||||
## Czech render-site follow-up
|
||||
|
||||
The desktop and web file pickers look up filter labels at assignment time; format names and
|
||||
extensions stay unchanged. Diagnostics retain numeric values and units. New Document's suggested
|
||||
preset name uses `Preset {number}`. Contributor tooltips use named placeholders and Czech plurals;
|
||||
handles and chosen names remain unchanged. Gradient descriptions reuse `{kind} Gradient` with a
|
||||
contextual radial adjective. PDF/Print mark styles use `mark-style`, so `Japanese` displays as
|
||||
`Japonské` while the language name stays `Japonština`; their Summary uses the same context.
|
||||
|
||||
The search placeholder, Home screen, toolbar/panel tooltips and Preferences already use lookups.
|
||||
No new `tl!("literal")` keys were needed: only `cs.tsv` adds 19 AI-draft rows and revises the gradient
|
||||
template. Other catalogs fall back to English for new variable/template lookups. Native review is
|
||||
still needed, and catalog coverage does not prove that every variable in the UI is translated.
|
||||
|
||||
## Not done in any language
|
||||
|
||||
Locale-aware number and date formats, a right-to-left interface, translated help, and a Traditional Chinese UI
|
||||
@@ -63,4 +78,5 @@ font for the web build.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-11 | minor | Czech render-site follow-up: file-dialog filters, diagnostics, preset numbering, contributor tooltips/plurals, gradient grammar and contextual printer mark styles; estimates unchanged |
|
||||
| 2026-10-10 | major | First per-language table, measured from the catalog row counts against the complete French catalog |
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
# Roadmap: milestones and what's next
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged; M6: Simplify preview/counts and valid topology selection (#1272); estimates unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; M14: RPM runtime metadata (#1275); estimates unchanged; M5: squared-distance texture redraws (#1257); clean-machine/platform drag measurements still pending; estimates unchanged; M2: Curvature point display improved (#1236, in part); estimates unchanged; M7: full-name font matching (#1258); Windows font-service QA pending; estimates unchanged; M1: no-op anchor Align keeps Undo, Redo and saved state (#1180 follow-up); estimates unchanged; M14: dedicated Eyedropper cursor (#1269); estimates unchanged; M3: Eyedropper reads visible locked and outside-isolation sources (#1251); estimates unchanged; M2: Direct Selection segment picks and Delete (#1278); estimates unchanged; M3: adding paint to an unpainted zero-width stroke restores 1 pt (#1253); estimates unchanged; M12: graph designs, graph data, Graph Type and label options; M14: native macOS save Format menu, #866; M6: compound appearance and member fill-rule fixes, #1197; estimates unchanged; M9: PDF raster-effect cap warnings; G11: #893 fixed, #937 open; M7: accurate character controls after scaling, #1034; estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Czech render-site localization follow-up; scores and estimates unchanged; Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged; M6: Simplify preview/counts and valid topology selection (#1272); estimates unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; M14: RPM runtime metadata (#1275); estimates unchanged; M5: squared-distance texture redraws (#1257); clean-machine/platform drag measurements still pending; estimates unchanged; M2: Curvature point display improved (#1236, in part); estimates unchanged; M7: full-name font matching (#1258); Windows font-service QA pending; estimates unchanged; M1: no-op anchor Align keeps Undo, Redo and saved state (#1180 follow-up); estimates unchanged; M14: dedicated Eyedropper cursor (#1269); estimates unchanged; M3: Eyedropper reads visible locked and outside-isolation sources (#1251); estimates unchanged; M2: Direct Selection segment picks and Delete (#1278); estimates unchanged; M3: adding paint to an unpainted zero-width stroke restores 1 pt (#1253); estimates unchanged; M12: graph designs, graph data, Graph Type and label options; M14: native macOS save Format menu, #866; M6: compound appearance and member fill-rule fixes, #1197; estimates unchanged; M9: PDF raster-effect cap warnings; G11: #893 fixed, #937 open; M7: accurate character controls after scaling, #1034; estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Forward-looking plan. Where VectorCraft stands is in [`ROADMAP.md`](../ROADMAP.md) and
|
||||
[target-app-parity.md](target-app-parity.md); the ranked work list is [gaps.md](gaps.md). Hours are Opus 5.5
|
||||
@@ -88,6 +88,7 @@ After placed documents (File › Place of a `.vectorcraft` file, linked), M4.14
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-11 | minor | Czech render-site follow-up: file-dialog filters, diagnostics, preset numbering, contributor tooltips/plurals, gradient grammar and contextual printer mark styles; estimates unchanged |
|
||||
| 2026-10-12 | minor | Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | M6: Simplify preview/counts and valid selection after topology changes (#1272); auto/slider/advanced UI remains open; estimates unchanged |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Parity with Adobe Illustrator
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged; Path operations: Simplify preview/counts and component selection (#1272); scores unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; Platforms: RPM runtime capabilities and glibc floor (#1275); scores unchanged; Raster effects: squared-distance texture redraws (#1257); pixels unchanged; scores and hours unchanged; Drawing: Curvature point display improved (#1236, in part); scores unchanged; Type core: full-name font matching (#1258), scores and hours unchanged; Selection: no-op anchor Align preserves history and saved state (#1180 follow-up); scores unchanged; UI chrome: Eyedropper cursor and precise-setting regressions (#1269); scores unchanged; Colour: Eyedropper reads visible locked and outside-isolation sources (#1251); scores and hours unchanged; Selection: segment click/Delete preserves neighboring edges (#1278); scores unchanged; Colour: unpainted zero-width strokes regain 1 pt when painted (#1253); scores and hours unchanged; graphs: designs and markers, data, Graph Type and label options; UI chrome: native macOS save Format menu, #866, scores unchanged; compound paths inherit the backmost appearance and member fill-rule edits reach their owner, #1197; scores unchanged; Type core: Middle Eastern digit types done, Character panel menu › Digits; PDF export warns when the pixel cap lowers raster-effect resolution; Drawing tools: Live Corners round corners between curved sides, #1144; Type advanced: proportional vertical metrics (`vpal`) done, #966; Shape Builder: #893 fixed, merged regions of crossing lines no longer keep seams; scores unchanged while #937 is open; #1034: document-point character controls after object/group scaling; full readiness recomputed as the standard's additive weighted sum, ~62%; per-audience hours; essentials-user score ~75% added; ready-for-real-work re-examined: 50% → 55%, mainstream 65% added; earlier the same day: full re-measure against Illustrator 2026 30.x; merged the ROADMAP's parity estimate, honest assessment and "Shipped so far" into this file) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Czech render-site localization follow-up; scores and estimates unchanged; Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged; Path operations: Simplify preview/counts and component selection (#1272); scores unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; Platforms: RPM runtime capabilities and glibc floor (#1275); scores unchanged; Raster effects: squared-distance texture redraws (#1257); pixels unchanged; scores and hours unchanged; Drawing: Curvature point display improved (#1236, in part); scores unchanged; Type core: full-name font matching (#1258), scores and hours unchanged; Selection: no-op anchor Align preserves history and saved state (#1180 follow-up); scores unchanged; UI chrome: Eyedropper cursor and precise-setting regressions (#1269); scores unchanged; Colour: Eyedropper reads visible locked and outside-isolation sources (#1251); scores and hours unchanged; Selection: segment click/Delete preserves neighboring edges (#1278); scores unchanged; Colour: unpainted zero-width strokes regain 1 pt when painted (#1253); scores and hours unchanged; graphs: designs and markers, data, Graph Type and label options; UI chrome: native macOS save Format menu, #866, scores unchanged; compound paths inherit the backmost appearance and member fill-rule edits reach their owner, #1197; scores unchanged; Type core: Middle Eastern digit types done, Character panel menu › Digits; PDF export warns when the pixel cap lowers raster-effect resolution; Drawing tools: Live Corners round corners between curved sides, #1144; Type advanced: proportional vertical metrics (`vpal`) done, #966; Shape Builder: #893 fixed, merged regions of crossing lines no longer keep seams; scores unchanged while #937 is open; #1034: document-point character controls after object/group scaling; full readiness recomputed as the standard's additive weighted sum, ~62%; per-audience hours; essentials-user score ~75% added; ready-for-real-work re-examined: 50% → 55%, mainstream 65% added; earlier the same day: full re-measure against Illustrator 2026 30.x; merged the ROADMAP's parity estimate, honest assessment and "Shipped so far" into this file) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
|
||||
The authoritative parity assessment. [`ROADMAP.md`](../ROADMAP.md) summarizes it; [`gaps.md`](gaps.md) is
|
||||
the work list made from it. Deep areas have their own checklists: [UI and interaction](ui-parity.md),
|
||||
@@ -398,6 +398,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- Tool flyouts tear off: dragging or clicking the tear-off bar on a flyout's right side (or releasing the long press over it) floats its group as a strip of tool buttons, moved by the same bar and put back in the toolbar by the × at its top (`window.floatTools`). While a group floats, the presses that would open its flyout raise the strip instead. Floating strips are kept with the preferences and in user workspaces. Not done: turning a strip vertical, docking it.
|
||||
- Panels undock (#495): a dock tab, a panel icon or a popped-out panel's title dragged out of the dock floats that panel inside the window, and the strip right of the dock's tabs floats the whole tabbed group. A floating group moves by its title bar, a tab dragged out of it floats on its own, and dropped on another group's title bar or tabs it stacks with that group; dropped on the dock, which lights up under the pointer, its panels go back where they live (the tabbed group or the icon column), as its × and the panel menus' Float Panel / Dock Panel do (`window.panel.float`, `window.panel.dock`). The Tools panel floats by its title bar and docks again on the window's left edge. Floating groups stack into sets: dropped on the upper or lower half of another group (a line shows where), a group joins it right above or below it, and the set's groups stack top to bottom, each showing one panel, moving together by the top group's title bar, whose × docks them all; a group dragged by its tab strip leaves the set (`window.panel.float {below, above}`). A double-click on a tab collapses a floating group to its tabs (`collapsed`). Sets dropped on the left edge of the icon column or of another dock column dock as dock columns (a multi-column dock, `window.panel.dock {column}`), whose groups stack, tab and tear out as a floating set's do, and whose top strip floats the column again. Floating panels, their sets and the Tools panel's position are kept with the preferences and in user workspaces, and clamped into a smaller window. Not done: panels in separate OS windows, docking a panel into the default tabbed group it doesn't belong to, reordering tabs by dragging, collapsing a set or dock column to icons, dock columns right of the default dock, resizing floating panels and the groups of a set.
|
||||
- The dock's double arrow collapses Properties, Layers and Libraries to icons at the top of the icon column, popping out like the other icon panels, and expands them again (`window.collapseDock`, kept with the preferences and in saved workspaces). The icon column's own arrow (expanding the icon panels into a full column) is not done.
|
||||
- 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; new variable keys fall back to English in other languages. Evidence: `i18n::tests::czech_render_site_follow_up`, `dialogs::tests_modal::printer_mark_labels_are_distinct_from_language_names`; see [localization-parity.md](localization-parity.md).
|
||||
- Localised UI: menus (in-window and native), panels, dialogs, toolbar and Preferences read from per-language catalogs (`crates/ui-egui/src/i18n`, see `docs/development.md`); Traditional Chinese (Taiwan), Simplified Chinese (mainland), Japanese, German, Spanish, French, Italian, Russian and Ukrainian ship complete, and Czech and Brazilian Portuguese cover every menu label (and more), with system-locale detection on macOS, Windows, Linux and the web (the browser's languages, or `?lang=`), a Language preference and, on macOS, a VectorCraft ▸ Language menu. Names are never translated (fonts and their styles, layers, artboards, saved presets, user libraries, custom workspaces, recent files, plug-ins).
|
||||
- Native macOS menu bar, vector tool cursors, a ⌘K command palette, middle-button panning with any tool. Native menus explicitly end tracking on command selection, outside window presses and Escape; menu updates wait until tracking ends, and a dismissing press never starts a canvas gesture (M14.8).
|
||||
- The macOS menu bar is built from the in-window menus (one model, `native_menu`) and laid out as a Mac app's: the VectorCraft menu holds About, Settings ▸ (each Preferences page, General… ⌘K), Language ▸, Appearance ▸ (UI brightness), Services, Hide VectorCraft ⌃⌘H (⌘H stays Hide Edges), Hide Others, Show All and Quit; Window gains Minimize ⌃⌘M, Zoom and Bring All to Front, and Help the system's search field. Its key equivalents go back to egui as key presses, so user shortcuts, focused text fields and the Type tool's input method behave as in the window, and nothing fires twice; enabled, check marks and labels update in place. `--in-window-menus` or `VECTORCRAFT_IN_WINDOW_MENUS=1` keeps the menus in the window; `ui.inspect` reports `nativeMenuBar`.
|
||||
@@ -506,6 +507,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-11 | minor | Czech render-site follow-up: file-dialog filters, diagnostics, preset numbering, contributor tooltips/plurals, gradient grammar and contextual printer mark styles; estimates unchanged |
|
||||
| 2026-10-12 | minor | Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | Artboards: Escape exits editing; an active drag cancels first; shortcut-routing regression; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | Path operations: Simplify preview/counts, valid component selection after refit/subdivision (#1272); slider/auto/advanced UI remains open; scores/hours unchanged |
|
||||
|
||||
Reference in new issue
Block a user