From bc2984a998dcef49844878871640ead076c9ed35 Mon Sep 17 00:00:00 2001 From: Patrik Lermon Date: Sat, 7 Nov 2026 07:55:28 +0100 Subject: [PATCH 1/3] i18n(sv): translate 69 new strings Brings the Swedish catalog up to date with upstream main (3635c230). Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/locales/sv.toml | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/crates/ui-egui/locales/sv.toml b/crates/ui-egui/locales/sv.toml index a94feb2a9..c3834d2b6 100644 --- a/crates/ui-egui/locales/sv.toml +++ b/crates/ui-egui/locales/sv.toml @@ -127,6 +127,7 @@ name = "Svenska" "Another server, or one that needs its key. The usual server is set in Preferences." = "En annan server, eller en som kräver sin nyckel. Standardservern anges i Inställningar." "Any status" = "Valfri status" "Anyone on your network with this code can edit the file, while this app stays open." = "Alla i ditt nätverk som har den här koden kan redigera filen så länge appen är öppen." +"Anyone on your network with this code can look at the file, not change it, while this app stays open." = "Alla i ditt nätverk som har den här koden kan titta på filen, men inte ändra den, så länge appen är öppen." "Anyone with the edit link can change the file; the view link only lets people look. The links carry their secrets: share them like passwords. `figcraft-server links` makes more and revokes them." = "Alla med redigeringslänken kan ändra filen; visningslänken låter bara andra titta. Länkarna innehåller sina hemligheter: dela dem som lösenord. `figcraft-server links` skapar fler och återkallar dem." "Anyone with this code can edit the file." = "Alla med den här koden kan redigera filen." "Anyone with this code can look at the file, not change it." = "Alla med den här koden kan titta på filen, men inte ändra den." @@ -387,6 +388,8 @@ name = "Svenska" "Crop marks" = "Skärmärken" "Ctrl+arrows" = "Ctrl+piltangenter" "Ctrl+click" = "Ctrl+klick" +"Ctrl+click a padding field" = "Ctrl+klicka på ett padding-fält" +"⌘ click a padding field" = "⌘ klicka på ett padding-fält" "Ctrl+scroll" = "Ctrl+rullning" "Current name" = "Aktuellt namn" "Current version" = "Aktuell version" @@ -406,6 +409,40 @@ name = "Svenska" "Decoration style" = "Dekorationsstil" "Decoration" = "Dekoration" "Deep select" = "Djupmarkering" +"Scrub a field faster (2x) or slower (1/2, 1/4)" = "Dragjustera ett fält snabbare (2x) eller långsammare (1/2, 1/4)" +"Move up or down while dragging its label" = "Flytta upp eller ned medan du drar dess etikett" +"Scrubbing at 2x" = "Dragjustering med 2x hastighet" +"Scrubbing at 1x" = "Dragjustering med 1x hastighet" +"Scrubbing at 1/2" = "Dragjustering med 1/2 hastighet" +"Scrubbing at 1/4" = "Dragjustering med 1/4 hastighet" +"Delete {n} variables" = { one = "Radera {n} variabel", other = "Radera {n} variabler" } +"Move out of any group" = "Flytta ut ur alla grupper" +"Move to group {group}" = "Flytta till gruppen {group}" +"Scope: all supported properties" = "Omfång: alla egenskaper som stöds" +"Scope: hidden from pickers" = "Omfång: dold i väljare" +"Scope: only {scope}" = "Omfång: endast {scope}" +"Disconnected. Reconnecting…" = "Frånkopplad. Återansluter…" +"Disconnected. Your edits stay here and sync when the connection returns. Reconnecting…" = "Frånkopplad. Dina redigeringar finns kvar här och synkas när anslutningen är tillbaka. Återansluter…" +"Dismiss" = "Stäng" +"Not connected: {reason}. Your work is still in this tab." = "Inte ansluten: {reason}. Ditt arbete finns kvar i den här fliken." +"Retry now" = "Försök igen nu" +"Save a copy…" = "Spara en kopia…" +"Wrap style" = "Radbrytningsstil" +"Text direction" = "Textriktning" +"Auto: by the first letter with a direction" = "Auto: efter den första bokstaven som har en riktning" +"Left to right" = "Vänster till höger" +"Right to left" = "Höger till vänster" +"Balance" = "Balans" +"Pretty" = "Snygg" +"Auto: as many words as fit on each line" = "Auto: så många ord som får plats på varje rad" +"Balance: every line close to the same length" = "Balans: alla rader ungefär lika långa" +"Pretty: full lines, no one word alone on the last" = "Snygg: fulla rader, inget ensamt ord på den sista" +"Set hug contents" = "Ställ in Omslut innehåll" +"Set fill container" = "Ställ in Fyll behållaren" +"Double-click an edge of an auto layout frame" = "Dubbelklicka på en kant av en auto layout-frame" +"{name}, disconnected from its live session" = "{name}, frånkopplad från sin livesession" +"⌥ double-click an edge of an auto layout child" = "⌥ dubbelklicka på en kant av ett underordnat objekt i auto layout" +"Alt+double-click an edge of an auto layout child" = "Alt+dubbelklicka på en kant av ett underordnat objekt i auto layout" "Default" = "Standard" "Default content" = "Standardinnehåll" "Default value (the top-left variant)" = "Standardvärde (varianten längst upp till vänster)" @@ -493,6 +530,7 @@ name = "Svenska" "Edit dev resource" = "Redigera utvecklarresurs" "Edit link" = "Redigeringslänk" "Edit link copied" = "Redigeringslänken har kopierats" +"Edit padding on all sides" = "Redigera padding på alla sidor" "Edit style" = "Redigera stil" "Edit variable" = "Redigera variabel" "Edit with the builder" = "Redigera med byggaren" @@ -530,6 +568,7 @@ name = "Svenska" "Exclusion" = "Uteslutning" "Exit focus view (Esc)" = "Lämna fokusvyn (Esc)" "Expand" = "Expandera" +"Expand the interface" = "Expandera gränssnittet" "Export" = "Exportera" "Export all" = "Exportera alla" "Export frames and layers as PNG, JPG, SVG or PDF" = "Exportera frames och lager som PNG, JPG, SVG eller PDF" @@ -1072,6 +1111,7 @@ name = "Svenska" "Pages: {pages}" = "Sidor: {pages}" "Paint bucket" = "Färghink" "Pan the canvas" = "Panorera arbetsytan" +"Show and move the placement crosshair (its tool chosen, nothing selected)" = "Visa och flytta placeringshårkorset (med dess verktyg valt och inget markerat)" "Pan with nothing selected (Shift: farther)" = "Panorera när inget är markerat (Shift: längre)" "Panels" = "Paneler" "Paper" = "Papper" @@ -1296,6 +1336,7 @@ name = "Svenska" "See all templates" = "Se alla mallar" "Select layers and they space themselves as their content changes" = "Markera lager så fördelar de avståndet själva när innehållet ändras" "SHA-256: {sha}…" = "SHA-256: {sha}…" +"Same as file ({profile})" = "Samma som filen ({profile})" "Same as layer" = "Samma som lagret" "Saturation" = "Mättnad" "Save" = "Spara" @@ -1968,6 +2009,17 @@ name = "Svenska" "⌘ click" = "⌘ klicka" "⌘ scroll" = "⌘ rulla" "⌥ drag" = "⌥ dra" +"Selection box: switch to pick select" = "Markeringsruta: växla till plockmarkering" +"Pick select: next or previous layer" = "Plockmarkering: nästa eller föregående lager" +"Pick select: into a layer, out to its parent" = "Plockmarkering: in i ett lager, ut till dess överordnade" +"Pick select: select the picked layer" = "Plockmarkering: markera det valda lagret" +"⇥ or ⌥ Space again" = "⇥ eller ⌥ Blanksteg igen" +"Tab or Ctrl+Space again" = "Tab eller Ctrl+Blanksteg igen" +"↵ / ⇧↵" = "↵ / ⇧↵" +"Enter / Shift+Enter" = "Enter / Shift+Enter" +"Space" = "Blanksteg" +"Nothing to pick: the page is empty" = "Inget att välja: sidan är tom" +"Pick select: Tab and Shift+Tab move between layers, Enter goes into one, Shift+Enter out, Space selects, Escape cancels" = "Plockmarkering: Tab och Shift+Tab flyttar mellan lager, Enter går in i ett, Shift+Enter ut, Blanksteg markerar, Esc avbryter" [commands] @@ -2004,6 +2056,7 @@ name = "Svenska" "board.label" = "Kopplingsetikett" "board.nextSticky" = "Nästa lapp" "board.reattach" = "Koppla om koppling" +"board.reshape" = "Omforma koppling" "board.setColor" = "Whiteboardfärg" "board.setStyle" = "Whiteboardstil" "board.shape" = "Form med text" @@ -2046,6 +2099,7 @@ name = "Svenska" "collab.openFile" = "Öppna onlinefil" "collab.peers" = "Personer i den här filen" "collab.publish" = "Publicera på server" +"collab.reconnect" = "Återanslut livesessionen" "collab.recoverFile" = "Återställ onlinefil" "collab.registerLinks" = "Öppna inbjudningslänkar i FigCraft" "collab.removePerson" = "Ta bort från session" @@ -2193,6 +2247,7 @@ name = "Svenska" "image.deletePreset" = "Radera förinställning" "image.place" = "Placera bild" "image.presets" = "Bildförinställningar" +"image.replace" = "Ersätt bild" "image.savePreset" = "Spara förinställning" "inspect.assets" = "Resurser" "inspect.code" = "Kod" @@ -2210,6 +2265,7 @@ name = "Svenska" "layers.collapseAll" = "Fäll ihop alla" "layout.add" = "Lägg till auto layout" "layout.remove" = "Ta bort auto layout" +"layout.removeAll" = "Ta bort all auto layout" "layout.setTrack" = "Ange spår" "layout.suggest" = "Föreslå layout" "libraries.open" = "Öppna bibliotek" @@ -2304,6 +2360,9 @@ name = "Svenska" "pref.showDimensions" = "Visa dimensioner på objekt" "pref.startOnHome" = "Börja på Start" "pref.uiScale" = "Gränssnittsstorlek" +"pref.uiScaleDown" = "Mindre gränssnitt" +"pref.uiScaleReset" = "Standardstorlek för gränssnittet" +"pref.uiScaleUp" = "Större gränssnitt" "pref.userName" = "Ditt namn" "proto.action.add" = "Lägg till prototypåtgärd" "proto.action.move" = "Ändra ordning på prototypåtgärd" @@ -2351,6 +2410,7 @@ name = "Svenska" "selection.applyColorStyle" = "Använd färgformatmall på markeringen" "selection.bindColorVariable" = "Använd färgvariabel på markeringen" "selection.colors" = "Markeringsfärger" +"selection.createColorStyle" = "Skapa färgstil från markeringen" "selection.detachColor" = "Koppla bort markeringsfärg" "selection.selectColor" = "Markera lager med den här färgen" "selection.setPaint" = "Ändra markeringens färg" @@ -2397,6 +2457,10 @@ name = "Svenska" "text.caseUpper" = "Versaler" "text.create" = "Text" "text.decoration" = "Dekoration" +"text.direction" = "Textriktning" +"text.directionAuto" = "Textriktning: auto" +"text.directionLtr" = "Textriktning: vänster till höger" +"text.directionRtl" = "Textriktning: höger till vänster" "text.edit.begin" = "Redigera text" "text.edit.caret" = "Placera markören" "text.edit.end" = "Sluta redigera text" @@ -2421,6 +2485,7 @@ name = "Svenska" "text.missingFonts" = "Saknade typsnitt" "text.numberList" = "Numrerad lista" "text.onPath" = "Text på bana" +"text.openLink" = "Öppna länk" "text.paragraphIndent" = "Styckeindrag" "text.paragraphSpacing" = "Styckeavstånd" "text.pathOptions" = "Alternativ för textbana" @@ -2440,9 +2505,11 @@ name = "Svenska" "text.underline" = "Understrykning" "text.weightDown" = "Minska teckenvikten" "text.weightUp" = "Öka teckenvikten" +"text.wrapStyle" = "Radbrytningsstil" "tool.arrow" = "Pil" "tool.comment" = "Kommentar" "tool.connector" = "Koppling" +"tool.crosshair" = "Flytta placeringshårkorset" "tool.ellipse" = "Ellips" "tool.eraser" = "Suddgummi" "tool.frame" = "Frame" @@ -2486,6 +2553,7 @@ name = "Svenska" "variable.deleteCollection" = "Radera samling" "variable.duplicate" = "Duplicera variabel" "variable.export" = "Exportera variabler" +"variable.extendCollection" = "Utöka samlingen" "variable.import" = "Importera variabler" "variable.list" = "Lista variabler" "variable.moveMode" = "Flytta läge" @@ -2559,6 +2627,7 @@ name = "Svenska" "view.layoutGrids" = "Layoutrutnät" "view.leftSidebar" = "Visa/dölj vänster sidofält" "view.maskOutlines" = "Konturlinjer för masker" +"view.minimize" = "Minimera gränssnittet" "view.multiplayerCursors" = "Samarbetsmarkörer" "view.nextFrame" = "Zooma till nästa frame" "view.nextPage" = "Nästa sida" From d252d35f27f8baad062dfc93c058b1c230f00fa7 Mon Sep 17 00:00:00 2001 From: Helen Kwok <107752876+helenkwok@users.noreply.github.com> Date: Sat, 7 Nov 2026 10:28:06 +0800 Subject: [PATCH 2/3] figcraft-web: inspect and openFile go through craft-web-api, so they time out and cancel like the other functions inspect is docInspect under its earlier name, and openFile calls the crate's execute with file.open, so a call the app does not answer within 30 seconds rejects and a request the app has not started is cancelled. --- apps/figcraft-web/src/api.rs | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/apps/figcraft-web/src/api.rs b/apps/figcraft-web/src/api.rs index 167ea7687..cb82820b7 100644 --- a/apps/figcraft-web/src/api.rs +++ b/apps/figcraft-web/src/api.rs @@ -37,7 +37,7 @@ use figcraft_ui_egui::{ControlReply, ControlRequest, RequestGate}; use serde_json::{Value, json}; use wasm_bindgen::JsCast; use wasm_bindgen::prelude::*; -use wasm_bindgen_futures::{JsFuture, future_to_promise}; +use wasm_bindgen_futures::JsFuture; use crate::saved_files::SavedFiles; @@ -150,15 +150,6 @@ async fn sleep(ms: i32) { let _ = JsFuture::from(promise).await; } -/// A reply as a promise outcome: the `result`, or an `Error` carrying the `error`. -fn outcome(reply: &Value) -> Result { - if reply.get("ok").and_then(Value::as_bool) == Some(true) { - Ok(to_js(reply.get("result").unwrap_or(&Value::Null))) - } else { - Err(js_sys::Error::new(reply.get("error").and_then(Value::as_str).unwrap_or("error")).into()) - } -} - fn set_fn(obj: &js_sys::Object, name: &str, f: JsValue) -> Result<(), JsValue> { js_sys::Reflect::set(obj, &name.into(), &f).map(|_| ()) } @@ -169,20 +160,20 @@ pub fn install() -> Result<(), JsValue> { Rc::new(PageApi::new(APP, Methods::default(), request)).install()?; let window = web_sys::window().ok_or("no window")?; let obj: js_sys::Object = js_sys::Reflect::get(&window, &APP.into())?.unchecked_into(); - set_fn( - &obj, - "inspect", - Closure:: js_sys::Promise>::new(|| future_to_promise(async { outcome(&send("document.inspect", json!({})).await) })) - .into_js_value(), - )?; + // `inspect` is `docInspect` under its earlier name: the crate's function, so it times out too. + let doc_inspect = js_sys::Reflect::get(&obj, &"docInspect".into())?; + js_sys::Reflect::set(&obj, &"inspect".into(), &doc_inspect)?; + // `openFile` runs `file.open` through the crate's `execute`, so a call the app does not answer times out and is cancelled. + let execute: js_sys::Function = js_sys::Reflect::get(&obj, &"execute".into())?.unchecked_into(); + let this = obj.clone(); set_fn( &obj, "openFile", - Closure:: js_sys::Promise>::new(|name: String, bytes: js_sys::Uint8Array| { + Closure:: JsValue>::new(move |name: String, bytes: js_sys::Uint8Array| { let data = base64::engine::general_purpose::STANDARD.encode(bytes.to_vec()); - future_to_promise(async move { - outcome(&send("engine.execute", json!({"command": "file.open", "params": {"name": name, "data": data}})).await) - }) + execute + .call2(&this, &"file.open".into(), &to_js(&json!({"name": name, "data": data}))) + .unwrap_or_else(|e| js_sys::Promise::reject(&e).into()) }) .into_js_value(), )?; From 2067a0b525c7a27e6f6ceecd697cd5c2adc40109 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 12 Nov 2026 10:25:44 +0700 Subject: [PATCH 3/3] Fix main: the slot test reads an unbound property's stored value; drop a stale Tamil string #2269 lists only the text properties bound to a layer on an instance, so the unbound base Text of #2126's test is no longer listed: the test now checks its stored value. #2242 reworded the colour profile note after #2160 translated it. --- crates/engine/src/slot_tests.rs | 11 ++++++++--- crates/ui-egui/locales/ta.toml | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/slot_tests.rs b/crates/engine/src/slot_tests.rs index adb96d541..4fbe5066a 100644 --- a/crates/engine/src/slot_tests.rs +++ b/crates/engine/src/slot_tests.rs @@ -417,12 +417,16 @@ fn assert_slot_text(s: &mut Session, instance: NodeId, expected: &str) { assert!(html.contains(&format!(">{expected}

")), "slot Label HTML: {html}"); } -fn assert_local_slot_text(s: &mut Session, instance: NodeId, expected: &str) { +fn assert_stored_slot_text(s: &Session, instance: NodeId, expected: &str) { assert!( matches!(&node(s, instance).kind, NodeKind::Instance { props, .. } if props.get("Text") == Some(&json!(expected))), "instance {instance} must store its own Text value {expected:?}: {:?}", node(s, instance).kind ); +} + +fn assert_local_slot_text(s: &mut Session, instance: NodeId, expected: &str) { + assert_stored_slot_text(s, instance, expected); let properties = props_of(s, instance); let text = properties.iter().find(|p| p["name"] == "Text").unwrap_or_else(|| panic!("instance {instance} has no Text property: {properties:?}")); assert_eq!(text["value"], expected, "instance {instance} Text property"); @@ -475,14 +479,15 @@ fn slot_text_properties_do_not_read_an_unbound_base_property() { ex(&mut s, "component.addProperty", json!({"id": base, "name": "Text", "type": "text", "default": "Wrong owner"})); let i = idv(&ex(&mut s, "instance.create", json!({"component": composition, "x": 400}))); let nested_base = kids(&s, i)[0]; - assert_local_slot_text(&mut s, nested_base, "Wrong owner"); + // Bound to no layer, the base's Text isn't listed on its instance (#2269); its value stays stored. + assert_stored_slot_text(&s, nested_base, "Wrong owner"); let nested = copy_of(&s, i, main_content); assert_local_slot_text(&mut s, nested, "Default"); assert_slot_text(&mut s, nested, "Default"); ex(&mut s, "instance.setProperties", json!({"ids": [nested], "properties": {"Text": "Custom"}})); assert_local_slot_text(&mut s, nested, "Custom"); assert_slot_text(&mut s, nested, "Custom"); - assert_local_slot_text(&mut s, nested_base, "Wrong owner"); + assert_stored_slot_text(&s, nested_base, "Wrong owner"); assert_slot_text(&mut s, main_content, "Default"); healthy(&s); } diff --git a/crates/ui-egui/locales/ta.toml b/crates/ui-egui/locales/ta.toml index 6ae9473ec..1fe649d13 100644 --- a/crates/ui-egui/locales/ta.toml +++ b/crates/ui-egui/locales/ta.toml @@ -1575,7 +1575,6 @@ status = "draft — needs native review" "Texts" = "உரைகள்" "Texture" = "அமைப்பு" "The bars are hidden. {shortcut} shows them again" = "பட்டைகள் மறைக்கப்பட்டுள்ளன. {shortcut} அவற்றை மீண்டும் காட்டும்" -"The canvas previews colors in sRGB; exported PNG, JPG and WebP files are tagged Display P3." = "கேன்வாஸ் நிறங்களை sRGB இல் காட்டுகிறது; ஏற்றுமதி செய்த PNG, JPG, WebP கோப்புகள் Display P3 எனக் குறிக்கப்படும்." "The destination document is unavailable. Nothing was imported." = "இலக்கு ஆவணம் கிடைக்கவில்லை. எதுவும் இறக்குமதி செய்யப்படவில்லை." "The destination document was closed. Nothing was imported." = "இலக்கு ஆவணம் மூடப்பட்டது. எதுவும் இறக்குமதி செய்யப்படவில்லை." "The destination page was removed. Nothing was imported." = "இலக்குப் பக்கம் அகற்றப்பட்டது. எதுவும் இறக்குமதி செய்யப்படவில்லை."