diff --git a/ROADMAP.md b/ROADMAP.md index bc679a5..5cd4084 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~26 points and ~162–292 h away (one Opus 5.5 agent; ~33–67 h wall-clock with 5 agents) -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow, native on macOS, Windows, Linux and FreeBSD and in the browser, fully drivable by agents through @@ -19,13 +19,13 @@ start with [`docs/gaps.md`](docs/gaps.md). | Essentials user | **~57%** | estimated: core features 77.8% × 0.92 launch/stability × 0.92 discoverability × 0.88 opening files people send ([method](docs/target-app-parity.md#essentials-user)) | | Mainstream practitioner | **~49%** | estimated: weekly areas 72.6% × 0.9 interaction × 0.9 stability × 0.85 file exchange with Figma users ([method](docs/target-app-parity.md#mainstream-practitioner)) | | Remaining to beta | **~155–280 h** one agent | estimated | -| Remaining to full parity | **~264–522 h** one agent (~83–145 h wall-clock with 5 agents) | estimated | +| Remaining to full parity | **~262–519 h** one agent (~83–145 h wall-clock with 5 agents) | estimated | ### Readiness by audience | Audience | Ready % | Opus 5.5 agent wall-clock hours to ~95% | Work that dominates | |---|---|---|---| -| Full target (ready for real work) | ~53% | ~270–525 h | multiplayer (42–84), localization (31–54), plugins (8–26), the interaction pass (40–60), GPU canvas (30–60), AI (30–60), the `.fig` import's tail (5–10) | +| Full target (ready for real work) | ~53% | ~268–522 h | multiplayer (42–84), localization (29–51), plugins (8–26), the interaction pass (40–60), GPU canvas (30–60), AI (30–60), the `.fig` import's tail (5–10) | | Mainstream practitioner | ~49% | ~130–244 h | core editor depth incl. the `.fig` import's tail (49–98), the interaction pass (40–60), real-file corpus and platform QA (25–50), `.fig` export for handing work back (15–30) | | Essentials user | ~57% | ~60–110 h | the `.fig` import's tail so the files people send open well (5–10), core tool polish (25–45), interaction pass on the core tools (15–25), stability QA (10–20), onboarding and starter templates (5–10) | @@ -63,7 +63,7 @@ native speakers' reviews of the six language drafts need people. | Stability | 55% | 20–40 | [gaps](docs/gaps.md) | | Performance | 60% | 30–60 | [hardware-parity](docs/hardware-parity.md) | | Hardware | 60% | 10–21 | [hardware-parity](docs/hardware-parity.md) | -| Localization | 36% (layer; English; Spanish with a Latin American overlay, French, German, Brazilian Portuguese, Japanese, Korean drafts; CJK UI fonts) | 31–54 | [localization-parity](docs/localization-parity.md) | +| Localization | 39% (layer; English; Spanish with a Latin American overlay, French, German, Brazilian Portuguese, Japanese, Korean, Simplified Chinese drafts; CJK UI fonts) | 29–51 | [localization-parity](docs/localization-parity.md) | | Platforms | 75% | 10–20 | [hardware-parity](docs/hardware-parity.md) | | Ecosystem / plugins | 38% (own WASM plugins with panels, settings and widgets; a self-hosted plugin directory) | 8–26 | [gaps](docs/gaps.md) | | AI features | 0% | 30–60 | [gaps](docs/gaps.md) | @@ -99,21 +99,22 @@ native speakers' reviews of the six language drafts need people. | Language | Code | Strings | Status | |---|---|---|---| | English | en | 100% | full | -| Simplified Chinese | zh-Hans | 0% | none | +| Simplified Chinese | zh-Hans | 100% | draft (needs native review) | | Spanish | es, es-419 | 100% (es-419: an overlay of 87 entries) | draft (needs native review) | | Hindi | hi | 0% | none | | Arabic | ar | 0% | none | -| French | fr | 100% | draft (needs native review) | -| Portuguese (Brazil) | pt-BR | 100% | draft (needs native review) | +| French | fr | 99% | draft (needs native review) | +| Portuguese (Brazil) | pt-BR | 99% | draft (needs native review) | | Indonesian | id | 0% | none | -| Japanese | ja | 100% | draft (needs native review) | -| German | de | 100% | draft (needs native review) | -| Korean | ko | 100% | draft (needs native review) | +| Japanese | ja | 99% | draft (needs native review) | +| German | de | 99% | draft (needs native review) | +| Korean | ko | 99% | draft (needs native review) | | Vietnamese | vi | 0% | none | No other languages. Figma ships English, Japanese, Korean, French, German, Spanish and Portuguese (Brazil); FigCraft has the localization layer, English and Spanish (Spain and Latin America), -French, German, Brazilian Portuguese, Japanese and Korean drafts (Preferences ▸ Language; CJK UI +French, German, Brazilian Portuguese, Japanese, Korean and Simplified Chinese drafts (Preferences ▸ +Language; Traditional Chinese has no catalog; CJK UI text uses an installed CJK font, loaded only when needed; adding a language: [`docs/translating.md`](docs/translating.md)). Document text in any script (bidi, Arabic shaping, IME) already works. Detail: [`docs/localization-parity.md`](docs/localization-parity.md). @@ -236,6 +237,7 @@ Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md). | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Simplified Chinese draft catalog (gap 5): `zh-Hans.toml` translates every UI string (1,371 keys; plurals give only `other`, and `plural_one` never picks "one"), command label (524) and menu wording (29), machine-drafted in a concise UI style with full-width punctuation and marked as a draft awaiting native review; Preferences ▸ Language lists 简体中文, System maps zh, zh-CN, zh-SG and zh-Hans to it, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and stays English (or the next OS language), never Simplified. A Chinese UI draws Han in a Chinese face first (Microsoft YaHei, PingFang SC, Noto Sans CJK SC), ahead of the craft-fonts build's Japanese BIZ UDPGothic, and changing the UI language lays the CJK faces out again (switching from Japanese to Chinese no longer keeps the Japanese face in front). String counts re-measured: 1,371 UI keys, 524 command labels and 29 menu wordings (1,924 entries); the French, German, Brazilian Portuguese, Japanese and Korean drafts have 1,899 of them (the 25 newer strings read English). Localization 36% → 39%, 31–54 h → 29–51 h; ready for real work unchanged (~53%); full parity ~267–527 h → ~265–524 h | | 2026-10-12 | minor | Latin American Spanish overlay (gap 5): `es-419.toml` lists only the 87 entries (61 UI strings, 26 command labels) whose wording differs in Latin American usage (agregar for añadir, presionar for pulsar, configuración for settings, Enter for the Intro key, control for a gamepad, resorte for a spring) and reads `es.toml`, then English, for the rest (a regional catalog overlays its language's); same tú register as Spanish; a draft awaiting native review. Preferences ▸ Language lists Español (Latinoamérica); System maps es-419, es-MX, es-AR, es-CO and the other Latin American and US Spanish tags to it, es-ES and es to Spanish. Localization 35% → 36%, 32–55 h → 31–54 h; ready for real work unchanged (~53%); full parity ~268–528 h → ~267–527 h | | 2026-10-12 | minor | Prototyping tail (gap 15, the part that doesn't need video): key/gamepad triggers take controller buttons (`Gamepad A` … `Gamepad Home`, the standard layout's 17 buttons, from a Controller menu beside the key field; the REST import maps controller triggers instead of skipping them); the player reads controllers on Windows (Windows.Gaming.Input through the `windows` crate the app already used; no new dependency) and in the browser (the Gamepad API), polling only while the prototype has such a trigger and the window has the focus, and the control channel presses buttons (`ui.input {gamepad}`); macOS, Linux and FreeBSD read no controllers yet. Widgets react to clicks in a presented prototype (the canvas's callback and sandbox limits, on the prototype's copy: the file and its history don't change, restarting starts over). `proto.evaluate` computes an expression where a layer's interaction would run (MCP); the mode lookup and set-variable-mode rules are cases in a behaviour suite (they already held). Prototyping breadth 90% → 92%, ready unchanged at 74%, 3–6 h → 2–5 h; area hours 120–260 → 119–259 (core 33–75 → 32–74), Features (depth) 29–68 h → 28–67 h; percentages unchanged at this rounding; full parity ~276–538 h → ~275–537 h | | 2026-10-12 | minor | Plugin directory on `figcraft-server` (gap 6): the server keeps plugin bundles (manifest, module, up to 32 assets; an uncompressed length-prefixed format named by its SHA-256) published with the server key (`figcraft-cli plugin publish`, `plugin.directory.publish`), checked in full before they are kept (size cap, manifest and plugin API version, a version newer than the one kept, the module compiled but never run, plain asset names) and capped (`max_plugins`, `max_plugin_mb`, `max_plugins_mb`); anyone who reaches the server lists, searches and fetches them (hash-checked again on read, a shared download budget); the operator moderates with `figcraft-server plugins [remove]`. The app's Plugins ▸ Manage plugins gains a Browse tab: a server's plugins with Install / Update / Remove, an install confirmation that shows the permissions asked for, the source and the SHA-256, the download checked against the listed hash before anything is read, plugins kept per user in hash-named folders; `plugin.directory.list` / `install` (needs `confirm: true`) / `publish` / `unpublish` for scripts and MCP. Not in the browser build yet; no public catalogue, publisher accounts, signatures, ratings or background update checks. Plugins & widgets 55%/32% → 60%/35%, 10–30 h → 8–26 h; Ecosystem dimension 34% → 38%; weighted totals unchanged at this rounding; full parity ~281–548 h → ~279–544 h | diff --git a/crates/engine/src/cmd/view.rs b/crates/engine/src/cmd/view.rs index a9a04f1..757b50c 100644 --- a/crates/engine/src/cmd/view.rs +++ b/crates/engine/src/cmd/view.rs @@ -272,7 +272,7 @@ pub fn specs() -> Vec { s.prefs.user_name = if name.is_empty() { super::comment::DEFAULT_AUTHOR.into() } else { name }; Ok(json!({"name": s.prefs.user_name})) }), - spec!("pref.language", "Interface language", "{language: system|en|es|es-419|fr|de|pt-BR|ja|ko|… (no catalog: English)}", false, |s, p| { + spec!("pref.language", "Interface language", "{language: system|en|es|es-419|fr|de|pt-BR|ja|ko|zh-Hans|…; else English}", false, |s, p| { let lang = req_string("pref.language", p, "language")?; let lang = lang.trim(); // A BCP 47-style tag ("es", "pt-BR", "zh_Hans") or "system". diff --git a/crates/ui-egui/locales/zh-Hans.toml b/crates/ui-egui/locales/zh-Hans.toml new file mode 100644 index 0000000..d98ed35 --- /dev/null +++ b/crates/ui-egui/locales/zh-Hans.toml @@ -0,0 +1,1941 @@ +# FigCraft interface strings: Simplified Chinese. +# +# Draft — needs native review: machine-drafted from the English catalog. Brand names, keyboard +# glyphs and {placeholders} stay as they are. Concise UI style, full-width punctuation ():,、。“” +# in Chinese text, a space between Chinese and Latin words or numbers. No plural forms: plural +# entries give only `other`. +# See docs/translating.md. + +[meta] +name = "简体中文" +status = "draft — needs native review" + +[ui] +"% of all commits" = "占全部提交的 %" +"(no longer published)" = "(已停止发布)" +"({n} warnings: some entries were skipped)" = { other = "({n} 条警告:已跳过部分条目)" } +"+ Create variable" = "+ 创建变量" +"1…9, 0" = "1…9, 0" +"@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{bin_added} / −{bin_deleted} binary assets, {first} – {last}" = "@{login}:{prs} 个 PR,{commits} 次提交,+{added} / −{deleted} 行(Δ {delta}),二进制资源 +{bin_added} / −{bin_deleted},{first} – {last}" +"A collection of this file with these modes and variables: override their values per mode and add variables of its own" = "本文件中带有这些模式和变量的集合:可按模式覆盖其值,并添加自己的变量" +"A spring plays until it settles: its mass, stiffness and damping set how long" = "弹簧动画播放至静止,时长由质量、刚度和阻尼决定" +"About" = "关于" +"About FigCraft" = "关于 FigCraft" +"Action" = "操作" +"Actions" = "操作" +"Actions…" = "操作…" +"Active" = "进行中" +"Actual size (100%)" = "实际大小(100%)" +"Add a category" = "添加类别" +"Add a comment" = "添加评论" +"Add a description" = "添加描述" +"Add a frame (F) or a shape (R) to get started" = "添加画框(F)或形状(R)以开始" +"Add a layer or component to tile first" = "请先添加要平铺的图层或组件" +"Add a note for developers" = "为开发者添加备注" +"Add action" = "添加操作" +"Add actions for when no condition holds" = "添加所有条件都不满足时的操作" +"Add an annotation for developers" = "为开发者添加标注" +"Add another condition" = "添加其他条件" +"Add auto layout" = "添加自动布局" +"Add background behind overlay" = "在浮层后添加背景" +"Add content to this slot" = "向此插槽添加内容" +"Add dev resource" = "添加开发资源" +"Add effect" = "添加效果" +"Add export setting" = "添加导出设置" +"Add fill" = "添加填充" +"Add interaction" = "添加交互" +"Add layout grid" = "添加布局网格" +"Add library" = "添加库" +"Add library file…" = "添加库文件…" +"Add max height" = "添加最大高度" +"Add max width" = "添加最大宽度" +"Add min height" = "添加最小高度" +"Add min width" = "添加最小宽度" +"Add mode" = "添加模式" +"Add new page" = "添加新页面" +"Add or update collections from a variables JSON" = "从变量 JSON 添加或更新集合" +"Add properties to make instances configurable" = "添加属性,使实例可配置" +"Add reaction" = "添加表情回应" +"Add starting point" = "添加起点" +"Add stroke" = "添加描边" +"Add variant" = "添加变体" +"Add variant with a new value" = "用新值添加变体" +"Added" = "已添加" +"Added the library \"{name}\"" = "已添加库“{name}”" +"Adjust" = "调整" +"Adjustment presets" = "调整预设" +"Advanced stroke" = "高级描边" +"After delay" = "延迟后" +"After delay {ms}ms" = "延迟 {ms} 毫秒后" +"Align" = "对齐" +"Align bottom" = "底部对齐" +"Align center" = "居中对齐" +"Align horizontal centers" = "水平居中对齐" +"Align left" = "左对齐" +"Align middle" = "垂直居中" +"Align right" = "右对齐" +"Align text baselines" = "对齐文本基线" +"Align top" = "顶部对齐" +"Align vertical centers" = "垂直居中对齐" +"Alignment" = "对齐" +"All" = "全部" +"All categories" = "全部类别" +"All comments" = "全部评论" +"All components" = "全部组件" +"All fonts" = "全部字体" +"All supported properties" = "所有支持的属性" +"All variables" = "全部变量" +"Alpha" = "Alpha" +"Alt+drag" = "Alt+拖动" +"Anchor" = "锚点" +"Android" = "Android" +"Angular" = "角度" +"Animation" = "动画" +"Annotations" = "标注" +"Annotations shown on the canvas" = "画布上显示的标注" +"Any status" = "任意状态" +"Anyone on your network who has the invite link can join." = "你所在网络中持有邀请链接的任何人都可以加入。" +"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." = "持有编辑链接的任何人都可以修改文件;查看链接只能查看。链接包含密钥,请像密码一样分享。`figcraft-server links` 可生成更多链接或将其撤销。" +"Appearance" = "外观" +"Apply a component property" = "应用组件属性" +"Apply variable" = "应用变量" +"Apply variable to text" = "将变量应用于文本" +"Apply variable to visibility" = "将变量应用于可见性" +"Arc" = "圆弧" +"Arc ratio" = "圆弧比例" +"Arc start" = "圆弧起点" +"Arc sweep" = "圆弧角度" +"Archive" = "归档" +"Archived" = "已归档" +"Arrange" = "排列" +"Arrow" = "箭头" +"As typed" = "原样" +"Assets" = "资源" +"Auto" = "自动" +"Auto (space around)" = "自动(环绕间距)" +"Auto (space between)" = "自动(两端间距)" +"Auto (space evenly)" = "自动(均匀间距)" +"Auto ({mode})" = "自动({mode})" +"Auto columns" = "自动列" +"Auto gap" = "自动间距" +"Auto height" = "自动高度" +"Auto layout" = "自动布局" +"Auto rows" = "自动行" +"Auto width" = "自动宽度" +"Back to the font's value" = "恢复为字体的值" +"Back" = "返回" +"Back to Ready for dev" = "退回可供开发" +"Back to Ready for dev: the next change compares with how it is now" = "退回可供开发:下次更改将与当前状态比较" +"Back to assets" = "返回资源" +"Back to current" = "返回当前" +"Back to styles" = "返回样式" +"Back to the canvas from a focused region" = "从聚焦区域返回画布" +"Back to the current version" = "返回当前版本" +"Back to the values the font style implies" = "恢复为字体样式对应的值" +"Background" = "背景" +"Background blur" = "背景模糊" +"Basics" = "基础" +"Before" = "之前" +"Bend" = "弯曲" +"Bevel" = "斜角" +"Binary assets added" = "新增的二进制资源" +"Binary assets removed" = "删除的二进制资源" +"Black & white" = "黑白" +"Bleed" = "出血" +"Bleed marks" = "出血标记" +"Bleed marks need a bleed" = "出血标记需要设置出血" +"Blend" = "混合" +"Blend mode" = "混合模式" +"Blue" = "蓝" +"Blur" = "模糊" +"Boolean" = "布尔" +"Boolean groups" = "布尔组" +"Both directions" = "双向" +"Bottom" = "底部" +"Bottom left radius" = "左下圆角" +"Bottom right radius" = "右下圆角" +"Branch" = "分支" +"Branch archived" = "分支已归档" +"Branch merged" = "分支已合并" +"Branch name" = "分支名称" +"Branch of {file}" = "{file} 的分支" +"Branch of {file} · merged or archived" = "{file} 的分支 · 已合并或已归档" +"Branch updated from main" = "已从主文件更新分支" +"Branch {name}" = "分支 {name}" +"Branches" = "分支" +"Bring forward" = "上移一层" +"Bring the main file's changes into the branch" = "将主文件的更改合入分支" +"Bring to front" = "置于顶层" +"Bristle" = "鬃毛" +"Brush" = "画笔" +"Brush rotation jitter" = "画笔旋转抖动" +"Brush scatter" = "画笔散布" +"Brush size jitter" = "画笔大小抖动" +"Brush spacing" = "画笔间距" +"Bulleted list" = "项目符号列表" +"CMYK colour" = "CMYK 颜色" +"Color profile: {name}" = "颜色配置文件:{name}" +"CSS custom properties…" = "CSS 自定义属性…" +"Can edit" = "可编辑" +"Can't read this library: {e}" = "无法读取此库:{e}" +"Cancel" = "取消" +"Canvas" = "画布" +"Canvas stacking" = "画布堆叠" +"Cap height to baseline" = "大写字母高度到基线" +"Case" = "大小写" +"Case-sensitive forms" = "区分大小写的字形" +"Categories" = "类别" +"Center" = "居中" +"Change alias" = "更改别名" +"Change resolved" = "更改已解决" +"Change style" = "更改样式" +"Change to" = "更改为" +"Change to needs a layer inside a variant" = "“更改为”需要变体内的图层" +"Changed" = "已更改" +"Changed on both sides: keep one" = "两边都有更改:保留其一" +"Changes on main" = "主文件上的更改" +"Changes on the branch" = "分支上的更改" +"Changes unknown" = "更改未知" +"Choose React, SwiftUI or Compose above to connect this component to its code." = "在上方选择 React、SwiftUI 或 Compose,将此组件关联到其代码。" +"Choose another profile to change it." = "选择其他配置文件以更改。" +"Choose collection" = "选择集合" +"Choose image" = "选择图片" +"Choose mode" = "选择模式" +"Choose variable" = "选择变量" +"Circle" = "圆形" +"Clear recent" = "清除最近项" +"Click + to replace mixed content" = "点击 + 替换混合内容" +"Click anywhere on the canvas to leave one." = "点击画布任意位置留下评论。" +"Click or drag to merge · {alt} removes" = "点击或拖动以合并 · {alt} 删除" +"Click or drag to remove · {alt} merges" = "点击或拖动以删除 · {alt} 合并" +"Click to record a key" = "点击以录制按键" +"Clip content" = "裁剪内容" +"Clip to shape" = "裁剪到形状" +"Close" = "关闭" +"Close overlay" = "关闭浮层" +"Close preview" = "关闭预览" +"Close tab" = "关闭标签页" +"Close version history" = "关闭版本历史" +"Close when clicking outside" = "点击外部时关闭" +"Close without saving" = "关闭但不保存" +"Code" = "代码" +"Code syntax" = "代码语法" +"Collapse" = "折叠" +"Collapse panel" = "折叠面板" +"Collection" = "集合" +"Collections" = "集合" +"Color" = "颜色" +"Color burn" = "颜色加深" +"Color dodge" = "颜色减淡" +"Color format" = "颜色格式" +"Color profile" = "颜色配置文件" +"Color styles" = "颜色样式" +"Color values in this file are in this color space." = "本文件中的颜色值使用此色彩空间。" +"Color variables" = "颜色变量" +"Colour" = "颜色" +"Column" = "列" +"Column gap" = "列间距" +"Column sizes" = "列宽" +"Column span" = "跨列" +"Columns" = "列" +"Columns {count}" = "{count} 列" +"Comment" = "评论" +"Comments" = "评论" +"Commits" = "提交" +"Community" = "社区" +"Company" = "公司" +"Compare changes" = "比较更改" +"Completed" = "已完成" +"Component" = "组件" +"Component name" = "组件名称" +"Component property" = "组件属性" +"Component set" = "组件集" +"Component sets" = "组件集" +"Components" = "组件" +"Conditional" = "条件" +"Confetti" = "彩纸" +"Conflicts" = "冲突" +"Connect to code" = "关联代码" +"Connected" = "已连接" +"Connected to code: {from}" = "已关联代码:{from}" +"Connection lost, reconnecting (attempt {attempt})…" = "连接已断开,正在重新连接(第 {attempt} 次尝试)…" +"Constrain proportions" = "锁定比例" +"Constraints" = "约束" +"Content" = "内容" +"Contents hidden" = "内容已隐藏" +"Contents only" = "仅内容" +"Contextual alternates" = "上下文替代字" +"Contrast" = "对比度" +"Contributors" = "贡献者" +"Contributors: {people} · Commits: {commits}" = "贡献者:{people} · 提交:{commits}" +"Cool" = "冷调" +"Copied as CSS" = "已复制为 CSS" +"Copied as PNG" = "已复制为 PNG" +"Copied as SVG" = "已复制为 SVG" +"Copied as text" = "已复制为文本" +"Copied {value}" = "已复制 {value}" +"Copy" = "复制" +"Copy as" = "复制为" +"Copy as CSS" = "复制为 CSS" +"Copy as PNG" = "复制为 PNG" +"Copy as SVG" = "复制为 SVG" +"Copy link" = "复制链接" +"Copy the {label}" = "复制{label}" +"Copy {value}" = "复制 {value}" +"Corner radius" = "圆角半径" +"Corner smoothing" = "圆角平滑" +"Count" = "数量" +"Create" = "创建" +"Create a variable collection first" = "请先创建变量集合" +"Create a variable first" = "请先创建变量" +"Create alias" = "创建别名" +"Create branch" = "创建分支" +"Create collection" = "创建集合" +"Create component" = "创建组件" +"Create component property" = "创建组件属性" +"Create components, styles or variables to publish them as a library." = "创建组件、样式或变量,即可将其发布为库。" +"Create property…" = "创建属性…" +"Create style" = "创建样式" +"Create style from the selected text" = "从所选文本创建样式" +"Crop" = "裁剪" +"Crop marks" = "裁切标记" +"Ctrl+arrows" = "Ctrl+方向键" +"Ctrl+click" = "Ctrl+点击" +"Ctrl+scroll" = "Ctrl+滚动" +"Current name" = "当前名称" +"Current version" = "当前版本" +"Cursor chat" = "光标聊天" +"Custom" = "自定义" +"Cut" = "剪切" +"Dark" = "深色" +"Darken" = "变暗" +"Dash" = "虚线" +"Decoration style" = "装饰线样式" +"Decoration" = "装饰线" +"Deep select" = "深度选择" +"Default" = "默认" +"Default content" = "默认内容" +"Default value (the top-left variant)" = "默认值(左上角的变体)" +"Delay" = "延迟" +"Delete" = "删除" +"Delete category (its annotations stay)" = "删除类别(保留其标注)" +"Delete collection" = "删除集合" +"Delete group" = "删除组" +"Delete mode" = "删除模式" +"Delete page" = "删除页面" +"Delete preset" = "删除预设" +"Delete property" = "删除属性" +"Delete the style (layers keep their values)" = "删除样式(图层保留其值)" +"Delete thread" = "删除讨论" +"Delete variable" = "删除变量" +"Delete “{name}”? This can't be undone." = "删除“{name}”?此操作无法撤销。" +"Density" = "密度" +"Depth" = "深度" +"Describe how and when to use this component" = "说明如何以及何时使用此组件" +"Describe what changed" = "描述更改内容" +"Description" = "描述" +"Description (optional)" = "描述(可选)" +"Design" = "设计" +"Desktop" = "桌面" +"Destination" = "目标" +"Detach alias" = "分离别名" +"Detach instance" = "分离实例" +"Detach property" = "分离属性" +"Detach style" = "分离样式" +"Detach styles" = "分离样式" +"Detach variable" = "分离变量" +"Details" = "详细" +"Dev Mode" = "开发模式" +"Dev resources" = "开发资源" +"Development" = "开发" +"Device" = "设备" +"Device at 100%" = "设备 100%" +"Diamond" = "菱形" +"Difference" = "差值" +"Dimensions" = "尺寸" +"Direction" = "方向" +"Disconnect from code" = "取消关联代码" +"Dispersion" = "色散" +"Display name" = "显示名称" +"Dissolve" = "溶解" +"Distribute and tidy" = "分布与整理" +"Distribute horizontal spacing" = "水平间距分布" +"Distribute vertical spacing" = "垂直间距分布" +"Divider" = "分隔线" +"Don't truncate" = "不截断" +"Done" = "完成" +"Done editing" = "完成编辑" +"Dots" = "圆点" +"Dotted" = "点线" +"Down" = "向下" +"Drafts" = "草稿" +"Drag the stroke to add a width point" = "拖动描边以添加宽度点" +"Draw" = "绘制" +"Drawing tools" = "绘图工具" +"Drop shadow" = "投影" +"Dual-licensed MIT OR Apache-2.0. Made by the ArtCraft team and community." = "采用 MIT 或 Apache-2.0 双重许可。由 ArtCraft 团队和社区打造。" +"Duo" = "双色" +"Duplicate" = "创建副本" +"Duplicate by dragging" = "拖动创建副本" +"Duplicate mode" = "复制模式" +"Duplicate page" = "复制页面" +"Edit" = "编辑" +"Edit as an expression" = "以表达式编辑" +"Edit colour" = "编辑颜色" +"Edit comment" = "编辑评论" +"Edit dev resource" = "编辑开发资源" +"Edit link" = "编辑链接" +"Edit link copied" = "已复制编辑链接" +"Edit style" = "编辑样式" +"Edit variable" = "编辑变量" +"Edit with the builder" = "使用构建器编辑" +"Effect settings" = "效果设置" +"Effect styles" = "效果样式" +"Effects" = "效果" +"Ellipse" = "椭圆" +"Ellipses" = "椭圆" +"Else" = "否则" +"Else if" = "否则如果" +"Embedded profile" = "嵌入的配置文件" +"Empty" = "空" +"End" = "末尾" +"End point" = "终点" +"Enter to save · Esc to cancel" = "Enter 保存 · Esc 取消" +"Eraser" = "橡皮擦" +"Esc" = "Esc" +"Essential" = "基本" +"Every conflict has a choice." = "所有冲突都已做出选择。" +"Every top-level frame already starts a flow" = "所有顶层画框都已是流程起点" +"Exact opacity (4 then 5: 45%)" = "精确不透明度(先按 4 再按 5:45%)" +"Exclude" = "排除" +"Excluded" = "已排除" +"Excluded from layout" = "已从布局中排除" +"Excludes" = "排除" +"Exclusion" = "排除" +"Exit focus view (Esc)" = "退出聚焦视图(Esc)" +"Expand" = "展开" +"Export" = "导出" +"Export all" = "全部导出" +"Export page as PNG" = "将页面导出为 PNG" +"Export settings" = "导出设置" +"Export variables" = "导出变量" +"Export {name}" = "导出 {name}" +"Export {n} layers" = { other = "导出 {n} 个图层" } +"Exported {file}" = "已导出 {file}" +"Exported {name}" = "已导出 {name}" +"Exported {n} files" = { other = "已导出 {n} 个文件" } +"Export…" = "导出…" +"Expose properties to instances" = "向实例公开属性" +"Exposure" = "曝光" +"Expression" = "表达式" +"Extend collection" = "扩展集合" +"Extends \"{name}\": overridden values are marked" = "扩展自“{name}”:已标记被覆盖的值" +"Eye" = "眼形" +"Fade" = "褪色" +"False" = "假" +"Fetching from the server…" = "正在从服务器获取…" +"File" = "文件" +"File name" = "文件名" +"Fill" = "填充" +"Fill (fr)" = "填充(fr)" +"Fill container" = "填充容器" +"Fill window" = "填满窗口" +"Fills" = "填充" +"Fill|sizing" = "填充" +"Filter and sort" = "筛选和排序" +"Find" = "查找" +"Find and replace" = "查找和替换" +"Find layers" = "查找图层" +"First" = "最早" +"First commit" = "首次提交" +"First on top" = "第一个在最上" +"Fit" = "适应" +"Fit device to window" = "设备适应窗口" +"Fit to contents" = "适应内容" +"Fit to window" = "适应窗口" +"Fit width" = "适应宽度" +"Fixed" = "固定" +"Fixed gap" = "固定间距" +"Fixed size" = "固定大小" +"Flatten" = "拼合" +"Flip" = "翻转" +"Flip horizontal" = "水平翻转" +"Flip text to the other side" = "将文本翻转到另一侧" +"Flip vertical" = "垂直翻转" +"Flip width profile" = "翻转宽度配置" +"Flow starting point" = "流程起点" +"Flow starting points" = "流程起点" +"Flows" = "流程" +"Focus view" = "聚焦视图" +"Fold autosaves" = "折叠自动保存" +"Folder: click to collapse" = "文件夹:点击折叠" +"Folder: click to expand" = "文件夹:点击展开" +"Follow" = "跟随" +"Follow {name}" = "跟随 {name}" +"Following" = "正在跟随" +"Following {name} · {key} to stop" = "正在跟随 {name} · 按 {key} 停止" +"Font" = "字体" +"Font not installed" = "字体未安装" +"Font size" = "字号" +"Font style" = "字体样式" +"Fractions" = "分数" +"Frame" = "画框" +"Frame selection" = "为所选项添加画框" +"Frame tools" = "画框工具" +"Frames" = "画框" +"From the library \"{name}\": read-only" = "来自库“{name}”:只读" +"From {name}" = "来自 {name}" +"Frost" = "磨砂" +"Gap" = "间距" +"Gap between columns" = "列间距" +"Gap between items" = "项目间距" +"Gap between rows" = "行间距" +"Glass" = "玻璃" +"Go to main component" = "转到主组件" +"Go to {name}" = "转到 {name}" +"Grab bag" = "卡片" +"Gradient" = "渐变" +"Gray" = "灰" +"Green" = "绿" +"Grid" = "网格" +"Grid ({size})" = "网格({size})" +"Grid styles" = "网格样式" +"Grid {size}" = "网格 {size}" +"Group" = "编组" +"Group selection" = "编组所选项" +"Groups" = "编组" +"Gutter" = "槽宽" +"Hand tool" = "抓手工具" +"Hanging list" = "悬挂列表" +"Hanging punctuation" = "标点悬挂" +"Hard light" = "强光" +"Height" = "高度" +"Help" = "帮助" +"Help and resources" = "帮助和资源" +"Help page" = "帮助页面" +"Hidden" = "已隐藏" +"Hide contents" = "隐藏内容" +"Hide from publishing" = "发布时隐藏" +"Hide section contents" = "隐藏分区内容" +"Highlight layers on hover" = "悬停时高亮图层" +"Highlights" = "高光" +"Hold Alt" = "按住 Alt" +"Hold Alt+Z" = "按住 Alt+Z" +"Hold Z" = "按住 Z" +"Hold ⌥" = "按住 ⌥" +"Hold ⌥Z" = "按住 ⌥Z" +"Home" = "主页" +"Horizontal" = "水平" +"Horizontal align" = "水平对齐" +"Horizontal hex" = "水平六边形" +"Horizontal padding" = "水平内边距" +"Horizontal spacing" = "水平间距" +"Hosting a session needs the desktop app; here you can join one." = "主持会话需要桌面应用;在这里可以加入会话。" +"Hover a layer to see its properties" = "悬停在图层上查看其属性" +"Hover other layers to measure the distance" = "悬停在其他图层上测量距离" +"Hue" = "色相" +"Hug" = "适应" +"Hug contents" = "适应内容" +"If" = "如果" +"If {condition}" = "如果 {condition}" +"Ignore auto layout (absolute position)" = "忽略自动布局(绝对定位)" +"Image" = "图片" +"Import" = "导入" +"Import path" = "导入路径" +"Import plugin from manifest" = "从清单导入插件" +"Import plugin from manifest…" = "从清单导入插件…" +"Import variables" = "导入变量" +"Imported {name}" = "已导入 {name}" +"Imported {n} new variables, updated {updated}" = { other = "已导入 {n} 个新变量,更新 {updated} 个" } +"Import…" = "导入…" +"In an instance, this comes from the main component" = "在实例中,此项来自主组件" +"In the browser you can join sessions the desktop app hosts and files on a FigCraft server. A page opened over https reaches other computers only through wss:// links (a server behind TLS)." = "在浏览器中,你可以加入桌面应用主持的会话以及 FigCraft 服务器上的文件。通过 https 打开的页面只能经由 wss:// 链接(TLS 后的服务器)访问其他计算机。" +"Include bounding box" = "包含边界框" +"Include id attribute" = "包含 id 属性" +"Included" = "已包含" +"Included in layout" = "已包含在布局中" +"Individual corners" = "独立圆角" +"Individual strokes" = "独立描边" +"Ink" = "墨水" +"Inner shadow" = "内阴影" +"Inside" = "内部" +"Inspect" = "检查" +"Inspect the layer under the pointer: size, colours, typography" = "检查指针下的图层:尺寸、颜色、排版" +"Instance" = "实例" +"Instance properties" = "实例属性" +"Instance swap" = "实例替换" +"Instance swap (no other component)" = "实例替换(无其他组件)" +"Instances" = "实例" +"Instant" = "即时" +"Interaction" = "交互" +"Interactions" = "交互" +"Interface design and prototyping. A free, open-source, clean-room design tool written from scratch in Rust, part of the ArtCraft Crafting Apps." = "界面设计与原型制作。一款以 Rust 从零编写的免费、开源、净室设计工具,属于 ArtCraft Crafting Apps 系列。" +"Intersect" = "相交" +"Intersects" = "相交" +"Invite link" = "邀请链接" +"Invite link copied" = "已复制邀请链接" +"Join" = "加入" +"Join a session…" = "加入会话…" +"Join live session" = "加入实时会话" +"Join us on Discord" = "加入我们的 Discord" +"Joined" = "已加入" +"Joined {file}" = "已加入 {file}" +"Joining…" = "正在加入…" +"Join|stroke" = "转角" +"Just now" = "刚刚" +"Justify" = "两端对齐" +"Keep appearance" = "保持外观" +"Keep appearance converts every color value to {profile} so colors look the same. Keep values leaves the numbers as they are, so colors shift." = "“保持外观”会将每个颜色值转换为 {profile},使颜色看起来不变。“保持数值”则保留数值不变,颜色会有偏移。" +"Keep tool selected after use" = "使用后保持工具选中" +"Keep values" = "保持数值" +"Key/Gamepad" = "按键/手柄" +"Key/Gamepad {key}" = "按键/手柄 {key}" +"Keyboard shortcuts" = "键盘快捷键" +"Language" = "语言" +"Lasso" = "套索" +"Last" = "最近" +"Last change: {note}" = "上次更改:{note}" +"Last commit" = "最近提交" +"Last on top" = "最后一个在最上" +"Layer blur" = "图层模糊" +"Layer name" = "图层名称" +"Layers" = "图层" +"Layers in an instance take their position from the main component" = "实例中的图层位置取自主组件" +"Layout" = "布局" +"Layout grid" = "布局网格" +"Layout grid settings" = "布局网格设置" +"Layout grids" = "布局网格" +"Leave session" = "离开会话" +"Leaves" = "树叶" +"Left" = "左" +"Left & right" = "左右" +"Left side" = "左侧" +"Left side width" = "左侧宽度" +"Letter case" = "字母大小写" +"Letter spacing" = "字间距" +"Libraries" = "库" +"Libraries in this file" = "本文件中的库" +"Library updates available" = "有可用的库更新" +"Library: click to collapse" = "库:点击折叠" +"Library: click to expand" = "库:点击展开" +"Library: its variables are read-only here; edit them in the library file and publish it" = "库:其变量在此为只读;请在库文件中编辑并发布" +"Light" = "浅色" +"Lighten" = "变亮" +"Light|glass" = "光照" +"Line" = "直线" +"Line arrow" = "线形箭头" +"Line delta" = "行数变化" +"Line height" = "行高" +"Linear" = "线性" +"Lines" = "直线" +"Lines +/−" = "行数 +/−" +"Lines added" = "新增行数" +"Lines deleted" = "删除行数" +"Link" = "链接" +"Link copied" = "已复制链接" +"Link docs, code or tickets for developers." = "为开发者链接文档、代码或工单。" +"Link this component to its code component: instances then show your real snippet with their values." = "将此组件关联到其代码组件:实例随后会以各自的值显示你的真实代码片段。" +"List spacing" = "列表间距" +"List style" = "列表样式" +"Live session" = "实时会话" +"Live · {people}" = "实时 · {people}" +"Local components" = "本地组件" +"Local styles" = "本地样式" +"Local variables" = "本地变量" +"Lock/Unlock" = "锁定/解锁" +"Locked" = "已锁定" +"Lowercase" = "小写" +"Luminance" = "亮度" +"Luminosity" = "明度" +"Main" = "主文件" +"Main component deleted" = "主组件已删除" +"Main menu" = "主菜单" +"Make slot" = "设为插槽" +"Margin" = "边距" +"Mark all as read" = "全部标为已读" +"Mark as resolved" = "标为已解决" +"Mark as unread" = "标为未读" +"Mark as unresolved" = "标为未解决" +"Mask" = "蒙版" +"Mass · Stiffness · Damping" = "质量 · 刚度 · 阻尼" +"Match (empty: the whole name)" = "匹配(留空:整个名称)" +"Max H" = "最大高" +"Max W" = "最大宽" +"Max lines" = "最大行数" +"Maximize" = "最大化" +"Measure to the selection" = "测量到所选项的距离" +"Merge into main" = "合并到主文件" +"Merge regions" = "合并区域" +"Merge the branch into the main file (one undo step) and archive it" = "将分支合并到主文件(一步撤销)并归档" +"Merged" = "已合并" +"Merged PRs" = "已合并的 PR" +"Min H" = "最小高" +"Min W" = "最小宽" +"Minimize" = "最小化" +"Mirror angle" = "镜像角度" +"Mirror angle and length" = "镜像角度和长度" +"Mirroring" = "镜像" +"Missing" = "缺失" +"Missing layer" = "缺失图层" +"Missing style" = "缺失样式" +"Missing variable" = "缺失变量" +"Miter" = "斜接" +"Miter angle" = "斜接角度" +"Mixed" = "混合" +"Mixed fonts" = "混合字体" +"Mixed interactions: click + to replace them" = "混合交互:点击 + 替换" +"Mode" = "模式" +"Model" = "模型" +"Models" = "模型" +"Mono" = "单色" +"More" = "更多" +"More instance actions" = "更多实例操作" +"Mouse down" = "鼠标按下" +"Mouse enter" = "鼠标移入" +"Mouse leave" = "鼠标移出" +"Mouse up" = "鼠标松开" +"Move" = "移动" +"Move column left" = "左移列" +"Move column right" = "右移列" +"Move down" = "下移" +"Move in" = "移入" +"Move out" = "移出" +"Move tools" = "移动工具" +"Move up" = "上移" +"Moved to {name}" = "已移至 {name}" +"Multi" = "多色" +"Multiply" = "正片叠底" +"Muted" = "柔和" +"Name" = "名称" +"Name (A–Z)" = "名称(A–Z)" +"Named instance" = "具名实例" +"Navigate to" = "导航到" +"Nested instance" = "嵌套实例" +"New design file" = "新建设计文件" +"Next or previous control in the focused region" = "聚焦区域中的下一个或上一个控件" +"Next ready for dev" = "下一个可供开发" +"Next size option" = "下一个尺寸选项" +"No assets: no export settings, icons or images. Add export settings in the Design tab." = "没有资源:没有导出设置、图标或图片。请在“设计”标签页中添加导出设置。" +"No boolean variables fit here." = "没有适用于此处的布尔变量。" +"No boolean variables yet. Create them in Local variables." = "还没有布尔变量。请在“本地变量”中创建。" +"No branches. A branch is a copy of the file to try changes in, then review and merge." = "没有分支。分支是文件的副本,可在其中尝试更改,再审阅并合并。" +"No category" = "无类别" +"No changes" = "无更改" +"No colour variables fit here." = "没有适用于此处的颜色变量。" +"No colour variables yet. Create them in Local variables." = "还没有颜色变量。请在“本地变量”中创建。" +"No comments yet" = "还没有评论" +"No components yet. Select layers and press {keys}." = "还没有组件。选择图层并按 {keys}。" +"No conflicts." = "没有冲突。" +"No contributor data was built into this copy." = "此副本未内置贡献者数据。" +"No fonts match" = "没有匹配的字体" +"No layer changes to show." = "没有可显示的图层更改。" +"No libraries yet. Add a .figcraft file that was published as a library, or paste a team library's link." = "还没有库。添加已发布为库的 .figcraft 文件,或粘贴团队库的链接。" +"No list" = "无列表" +"No matching comments" = "没有匹配的评论" +"No matching components" = "没有匹配的组件" +"No matching layers" = "没有匹配的图层" +"No matching styles" = "没有匹配的样式" +"No matching variables" = "没有匹配的变量" +"No mirroring" = "不镜像" +"No model credits were built into this copy." = "此副本未内置模型署名数据。" +"No number variables fit here." = "没有适用于此处的数字变量。" +"No number variables yet. Create them in Local variables." = "还没有数字变量。请在“本地变量”中创建。" +"No paints" = "无颜料" +"No plugins yet. Import a development plugin from its figcraft-plugin.json." = "还没有插件。可从开发插件的 figcraft-plugin.json 导入。" +"No preferred components" = "无首选组件" +"No preset" = "无预设" +"No saved versions yet. Save a version to mark a point in your work you can come back to." = "还没有保存的版本。保存版本可标记工作中的某个节点,以便日后返回。" +"No scrolling" = "不滚动" +"No shortcuts match" = "没有匹配的快捷键" +"No status" = "无状态" +"No string variables fit here." = "没有适用于此处的字符串变量。" +"No string variables yet. Create them in Local variables." = "还没有字符串变量。请在“本地变量”中创建。" +"No styles yet." = "还没有样式。" +"No styles yet. Click + to create one from the selection." = "还没有样式。点击 + 从所选项创建。" +"No text styles yet. Click + to create one from the selected text." = "还没有文本样式。点击 + 从所选文本创建。" +"No variables fit here." = "没有适用于此处的变量。" +"No variables yet. Create them in Local variables." = "还没有变量。请在“本地变量”中创建。" +"Nobody else is here yet" = "这里还没有其他人" +"Noise" = "杂色" +"None" = "无" +"None." = "无。" +"Normal" = "正常" +"Not bound" = "未绑定" +"Not in a live session" = "不在实时会话中" +"Not in this font" = "此字体不支持" +"Not properties, kept as written: {names}" = "不是属性,按原样保留:{names}" +"Not read yet" = "尚未读取" +"Note {n}" = "备注 {n}" +"Nothing changed since this was marked ready for dev." = "自标记为可供开发以来没有任何更改。" +"Nothing here yet. Set a frame's status to list it." = "这里还没有内容。设置画框的状态即可将其列出。" +"Nothing to export" = "没有可导出的内容" +"Now" = "现在" +"Nudge (Shift: big nudge)" = "微移(Shift:大幅微移)" +"Nudge amount" = "微移量" +"Number" = "数字" +"Number ↑" = "数字 ↑" +"Number ↓" = "数字 ↓" +"Numbered list" = "编号列表" +"Object" = "对象" +"Off" = "关" +"Offered first when filling the slot (any content is allowed)" = "填充插槽时优先提供(允许任何内容)" +"Offered first when swapping the instance (any component is allowed)" = "替换实例时优先提供(允许任何组件)" +"Offset" = "偏移" +"On click" = "点击时" +"On drag" = "拖动时" +"On the server's machine, `figcraft-server key` prints it." = "在服务器所在机器上运行 `figcraft-server key` 即可显示。" +"On this page" = "在此页面" +"Only the first changed layers are listed." = "仅列出前几个已更改的图层。" +"Only the first {n} changed layers are listed." = "仅列出前 {n} 个已更改的图层。" +"Only this computer can join (turn on network sharing to invite others)." = "只有本机可以加入(开启网络共享以邀请他人)。" +"Only your threads" = "仅你的讨论" +"Opacity" = "不透明度" +"Opacity & blend" = "不透明度与混合" +"Opacity 10%…90%, 0: 100%" = "不透明度 10%…90%,0:100%" +"Open" = "打开" +"Open .figcraft, .svg or images" = "打开 .figcraft、.svg 或图片" +"Open branch" = "打开分支" +"Open file" = "打开文件" +"Open files" = "打开的文件" +"Open in focus view" = "在聚焦视图中打开" +"Open in new window" = "在新窗口中打开" +"Open invite links in FigCraft" = "在 FigCraft 中打开邀请链接" +"Open link" = "打开链接" +"Open link {url}" = "打开链接 {url}" +"Open overlay" = "打开浮层" +"Open prototype preview" = "打开原型预览" +"Open variables ({count})" = "打开变量({count})" +"Opened “{name}” in a new tab" = "已在新标签页中打开“{name}”" +"Open|comments" = "未解决" +"Options" = "选项" +"Or keep the file on a FigCraft server and share links to edit or to view it." = "或者将文件保存在 FigCraft 服务器上,并分享编辑或查看链接。" +"Orange" = "橙" +"Outline stroke" = "轮廓化描边" +"Outline text" = "轮廓化文本" +"Outlines" = "轮廓" +"Outside" = "外部" +"Overflow" = "溢出" +"Overlay" = "浮层" +"Overlay position" = "浮层位置" +"Overridden here (the collection it extends has another value)" = "已在此覆盖(所扩展的集合中为其他值)" +"Overrides" = "覆盖" +"PDF print options" = "PDF 打印选项" +"PDF print settings" = "PDF 打印设置" +"Padding" = "内边距" +"Page" = "页面" +"Pages" = "页面" +"Pages: {pages}" = "页面:{pages}" +"Paint bucket" = "油漆桶" +"Pan the canvas" = "平移画布" +"Panels" = "面板" +"Paper" = "纸张" +"Paragraph indent" = "段落缩进" +"Paragraph indent applies to left-aligned text" = "段落缩进适用于左对齐文本" +"Paragraph spacing" = "段落间距" +"Pass through" = "穿透" +"Paste a link (https://…)" = "粘贴链接(https://…)" +"Paste a team library link (a view link)" = "粘贴团队库链接(查看链接)" +"Paste here" = "粘贴到此处" +"Paste the invite link the host shared with you." = "粘贴主持人分享给你的邀请链接。" +"Paste to replace" = "粘贴以替换" +"Pattern" = "图案" +"Pattern alignment" = "图案对齐" +"Pattern scale" = "图案缩放" +"Pattern source" = "图案来源" +"Pen" = "钢笔" +"Pencil" = "铅笔" +"People in this file" = "此文件中的成员" +"Phone" = "手机" +"Pick color" = "取色" +"Pick color (I)" = "取色(I)" +"Pick one font family first" = "请先选择一个字体系列" +"Pin a property" = "固定属性" +"Pinch" = "收窄" +"Pixel grid" = "像素网格" +"Pixel preview 1x" = "像素预览 1x" +"Pixel preview 2x" = "像素预览 2x" +"Place automatically" = "自动放置" +"Place image" = "置入图片" +"Plugins" = "插件" +"Plus darker" = "加深" +"Plus lighter" = "增亮" +"Point" = "点" +"Points" = "点数" +"Polygon" = "多边形" +"Polygons" = "多边形" +"Position" = "位置" +"Post" = "发布" +"Preferences" = "偏好设置" +"Preferred" = "首选" +"Present" = "演示" +"Present or preview" = "演示或预览" +"Present this flow" = "演示此流程" +"Presentation" = "演示" +"Preserve scroll position" = "保留滚动位置" +"Presets" = "预设" +"Press a key…" = "按下按键…" +"Preview" = "预览" +"Preview this flow" = "预览此流程" +"Preview this frame" = "预览此画框" +"Previous ready for dev" = "上一个可供开发" +"Progressive" = "渐进" +"Properties" = "属性" +"Prototype" = "原型" +"Prototype preview" = "原型预览" +"Prototype settings" = "原型设置" +"Publish" = "发布" +"Publish changes" = "发布更改" +"Publish to server" = "发布到服务器" +"Publish to server…" = "发布到服务器…" +"Published version {v}" = "已发布版本 {v}" +"Published version {v} to the server" = "已将版本 {v} 发布到服务器" +"Published version {v}: save the file so other files can use it" = "已发布版本 {v}:请保存文件,以便其他文件使用" +"Published · {people}" = "已发布 · {people}" +"Publishing to a server needs the desktop app; in the browser you can join a server's files" = "发布到服务器需要桌面应用;在浏览器中可以加入服务器上的文件" +"Publishing…" = "正在发布…" +"Push" = "推入" +"Push changes to main component" = "将更改推送到主组件" +"Put text on path" = "将文本放到路径上" +"Radial" = "径向" +"Radius" = "半径" +"Ratio" = "比例" +"Reading the library…" = "正在读取库…" +"Ready for dev" = "可供开发" +"Real name" = "真实姓名" +"Recent" = "最近" +"Recent files" = "最近的文件" +"Recents" = "最近" +"Recovered {n} unsaved files after the app quit unexpectedly: save them to keep them" = { other = "应用意外退出后恢复了 {n} 个未保存的文件:请保存以保留" } +"Rectangle" = "矩形" +"Rectangles" = "矩形" +"Red" = "红" +"Reduce motion" = "减少动态效果" +"Refraction" = "折射" +"Regular expression" = "正则表达式" +"Remove" = "移除" +"Remove all" = "全部移除" +"Remove annotation" = "移除标注" +"Remove auto layout" = "移除自动布局" +"Remove dev resource" = "移除开发资源" +"Remove export setting" = "移除导出设置" +"Remove guide" = "移除参考线" +"Remove interaction" = "移除交互" +"Remove library from this file" = "从此文件中移除库" +"Remove min and max" = "移除最小值和最大值" +"Remove min and max height" = "移除最小和最大高度" +"Remove min and max width" = "移除最小和最大宽度" +"Remove regions" = "移除区域" +"Remove slot" = "移除插槽" +"Remove starting point" = "移除起点" +"Remove stop" = "移除色标" +"Remove text from path" = "从路径上移除文本" +"Remove the else and its actions" = "移除“否则”及其操作" +"Remove this condition and its actions" = "移除此条件及其操作" +"Removed" = "已删除" +"Removed since it was marked" = "标记后已删除" +"Rename" = "重命名" +"Rename duplicated layers" = "重命名副本图层" +"Rename folder" = "重命名文件夹" +"Rename group" = "重命名组" +"Rename layers" = "重命名图层" +"Rename mode" = "重命名模式" +"Rename page" = "重命名页面" +"Rename to" = "重命名为" +"Replace all" = "全部替换" +"Replace mixed export settings" = "替换混合的导出设置" +"Replace with" = "替换为" +"Replace with a new interaction" = "替换为新交互" +"Reply" = "回复" +"Reset" = "重置" +"Reset adjustments" = "重置调整" +"Reset all changes" = "重置所有更改" +"Reset all overrides on this layer" = "重置此图层上的所有覆盖" +"Reset overrides" = "重置覆盖" +"Reset slot" = "重置插槽" +"Reset this override" = "重置此覆盖" +"Reset to style" = "重置为样式" +"Reset to the inherited value" = "重置为继承的值" +"Resize by the nudge amount" = "按微移量调整大小" +"Resize frames to the device's screen (or the window without a device): their constraints and auto layout respond" = "将画框调整为设备屏幕大小(无设备时为窗口大小):其约束和自动布局随之响应" +"Resize to fit" = "调整大小以适应" +"Resolve" = "解决" +"Resolve change" = "解决更改" +"Resolved" = "已解决" +"Resources" = "资源" +"Responsive" = "响应式" +"Restart" = "重新开始" +"Restore" = "恢复" +"Restore main component" = "恢复主组件" +"Restore this version" = "恢复此版本" +"Restored “{name}”" = "已恢复“{name}”" +"Reverse the order" = "反转顺序" +"Reversed triangle" = "反向三角形" +"Review and merge" = "审阅并合并" +"Ribbon" = "缎带" +"Right" = "右" +"Right side" = "右侧" +"Right side width" = "右侧宽度" +"Rotate 90°" = "旋转 90°" +"Rotate 90° right" = "向右旋转 90°" +"Rotate to landscape" = "旋转为横向" +"Rotate to portrait" = "旋转为纵向" +"Rotation" = "旋转" +"Rotation jitter" = "旋转抖动" +"Round" = "圆形" +"Rounded" = "圆润" +"Row" = "行" +"Row gap" = "行间距" +"Row sizes" = "行高" +"Row span" = "跨行" +"Rows" = "行" +"Rows {count}" = "{count} 行" +"Rulers" = "标尺" +"Run" = "运行" +"Run {label}" = "运行 {label}" +"Same as layer" = "与图层相同" +"Saturation" = "饱和度" +"Save" = "保存" +"Save as" = "另存为" +"Save as preset…" = "存储为预设…" +"Save version {key}" = "保存版本 {key}" +"Saved" = "已保存" +"Saved {name}" = "已保存 {name}" +"Say something" = "说点什么" +"Scale" = "缩放" +"Scatter" = "散布" +"Scoping: where pickers offer it" = "范围:选择器在哪些地方提供它" +"Screen" = "滤色" +"Scroll behavior" = "滚动行为" +"Scroll to" = "滚动到" +"Scroll to layer" = "滚动到图层" +"Scroll with parent" = "随父级滚动" +"Search" = "搜索" +"Search actions, layers and tools" = "搜索操作、图层和工具" +"Search assets" = "搜索资源" +"Search comments" = "搜索评论" +"Search fonts" = "搜索字体" +"Search layers" = "搜索图层" +"Search shortcuts" = "搜索快捷键" +"Section" = "分区" +"Section color" = "分区颜色" +"Sections" = "分区" +"Select a frame and add a starting point to present it as a flow." = "选择一个画框并添加起点,即可将其作为流程演示。" +"Select a frame to preview it" = "选择一个画框以预览" +"Select a layer to see its properties and code" = "选择一个图层以查看其属性和代码" +"Select all" = "全选" +"Select all with same" = "选择所有相同" +"Select layer" = "选择图层" +"Select layers to apply the style to" = "选择要应用样式的图层" +"Select overlapping shapes" = "选择重叠的形状" +"Select points to edit their position, radius and mirroring" = "选择点以编辑其位置、半径和镜像" +"Select slot" = "选择插槽" +"Selection" = "所选项" +"Selection box, {w} by {h} at {x}, {y}: arrows move it, Shift+arrows size it, Enter selects, Escape cancels" = "选框,{w} × {h},位于 {x}, {y}:方向键移动,Shift+方向键调整大小,Enter 选择,Esc 取消" +"Selection box: arrows move it, Shift+arrows size it, Enter selects, Escape cancels" = "选框:方向键移动,Shift+方向键调整大小,Enter 选择,Esc 取消" +"Send backward" = "下移一层" +"Send to back" = "置于底层" +"Server address" = "服务器地址" +"Set as default" = "设为默认" +"Set variable" = "设置变量" +"Set variable mode" = "设置变量模式" +"Set variable {name}" = "设置变量 {name}" +"Set {name} to {value}" = "将 {name} 设为 {value}" +"Shadows" = "阴影" +"Shape" = "形状" +"Shape builder" = "形状生成器" +"Shape tools" = "形状工具" +"Share" = "分享" +"Share on the local network" = "在局域网中共享" +"Share: live session, export" = "分享:实时会话、导出" +"Show" = "显示" +"Show as grid" = "以网格显示" +"Show as list" = "以列表显示" +"Show autosaves" = "显示自动保存" +"Show behind transparent areas" = "在透明区域后显示" +"Show comments (Shift+C)" = "显示评论(Shift+C)" +"Show device frame" = "显示设备外框" +"Show dimensions on objects" = "在对象上显示尺寸" +"Show hotspot hints" = "显示热区提示" +"Show only this on the canvas" = "画布上仅显示此项" +"Show open" = "显示未解决" +"Show section contents" = "显示分区内容" +"Show this layer" = "显示此图层" +"Show usage" = "显示用法" +"Show/Hide" = "显示/隐藏" +"Show/Hide UI" = "显示/隐藏界面" +"Side by side" = "并排" +"Sidebar" = "侧边栏" +"Simplify stroke" = "简化描边" +"Size" = "大小" +"Size jitter" = "大小抖动" +"Skip ink" = "避让下伸部" +"Slashed zero" = "带斜线的零" +"Slice" = "切片" +"Slices" = "切片" +"Slide in" = "滑入" +"Slide out" = "滑出" +"Slot" = "插槽" +"Slot content" = "插槽内容" +"Small capitals" = "小型大写字母" +"Small caps" = "小型大写" +"Smart animate" = "智能动画" +"Snap to pixel grid" = "对齐像素网格" +"Social media" = "社交媒体" +"Soft light" = "柔光" +"Solid" = "纯色" +"Some variants have the same property values: give each one a unique combination" = "部分变体的属性值相同:请为每个变体设置唯一的组合" +"Sort" = "排序" +"Sort by date" = "按日期排序" +"Sort by page" = "按页面排序" +"Space around" = "环绕间距" +"Space between" = "两端间距" +"Space drag" = "空格拖动" +"Space evenly" = "均匀间距" +"Space+drag" = "空格+拖动" +"Spacing" = "间距" +"Splay" = "张开" +"Spotlight me" = "聚焦于我" +"Spread" = "扩展" +"Square" = "方形" +"Standard" = "标准" +"Standard ligatures" = "标准连字" +"Star" = "星形" +"Stars" = "星形" +"Start" = "起点" +"Start ascending from / stop descending at" = "升序起点 / 降序终点" +"Start from a blank canvas" = "从空白画布开始" +"Start live session" = "开始实时会话" +"Start on path" = "路径起点" +"Start point" = "起点" +"Status" = "状态" +"Sticky" = "粘性" +"Stop" = "停止" +"Stop following {name}" = "停止跟随 {name}" +"Stop session" = "停止会话" +"Stop spotlighting" = "停止聚焦" +"Stop {n} {hex}" = "色标 {n} {hex}" +"Stretch" = "拉伸" +"Strikethrough" = "删除线" +"String" = "字符串" +"Stroke" = "描边" +"Stroke style" = "描边样式" +"Stroke weight" = "描边粗细" +"Strokes" = "描边" +"Style" = "样式" +"Styles" = "样式" +"Stylistic set 1" = "样式集 1" +"Stylistic set 2" = "样式集 2" +"Stylistic set 3" = "样式集 3" +"Stylistic set 4" = "样式集 4" +"Stylistic set 5" = "样式集 5" +"Subtract" = "减去" +"Subtracts" = "减去" +"Suffix" = "后缀" +"Swap instance" = "替换实例" +"Swap library: use another library's assets of the same names" = "替换库:使用另一个库中同名的资源" +"Swap orientation" = "切换方向" +"Swap overlay" = "替换浮层" +"Swap to {name}" = "替换为 {name}" +"Swap width and height" = "互换宽高" +"Swapped instance" = "已替换的实例" +"Swapped {n} assets" = { other = "已替换 {n} 个资源" } +"Swapped {n} assets; {missed} had no match and still use the old library" = { other = "已替换 {n} 个资源;{missed} 个没有匹配项,仍使用旧库" } +"Sweep" = "扫掠角" +"System" = "跟随系统" +"Tab / Shift+Tab" = "Tab / Shift+Tab" +"Table" = "表格" +"Tablet" = "平板" +"Tabular numbers" = "等宽数字" +"Take the values from the first selected layer" = "取第一个所选图层的值" +"Taper" = "渐细" +"Taper both ends" = "两端渐细" +"Temperature" = "色温" +"Template" = "模板" +"Text" = "文本" +"Text align" = "文本对齐" +"Text content" = "文本内容" +"Text style" = "文本样式" +"Text styles" = "文本样式" +"Texts" = "文本" +"Texture" = "纹理" +"The canvas previews colors in sRGB; exported PNG, JPG and WebP files are tagged Display P3." = "画布以 sRGB 预览颜色;导出的 PNG、JPG 和 WebP 文件标记为 Display P3。" +"The file now holds another library" = "该文件现在包含另一个库" +"The file now holds another library (\"{name}\")" = "该文件现在包含另一个库(“{name}”)" +"The link carries the session's secret: share it only with people you invite." = "链接包含会话密钥:只分享给你邀请的人。" +"The selection uses several text styles: click to apply one" = "所选项使用了多种文本样式:点击应用其中一种" +"Theme" = "主题" +"There's no destination for that action" = "该操作没有目标" +"Thickness" = "粗细" +"This branch can't be reviewed: {e}" = "无法审阅此分支:{e}" +"This branch was merged or archived." = "此分支已合并或已归档。" +"This condition is edited as an expression" = "此条件以表达式编辑" +"This file" = "此文件" +"This file has unsaved changes" = "此文件有未保存的更改" +"This frame is new on the branch." = "此画框是分支上新增的。" +"This frame isn't on the branch." = "此画框不在分支上。" +"Tidy up" = "整理" +"Tile" = "平铺" +"Tile type" = "平铺类型" +"Tint" = "色调" +"Title" = "标题" +"Title case" = "首字母大写" +"To share this library with your team, publish the file to a server (Share ▸ Publish to server…), then publish the library there." = "要与团队共享此库,请先将文件发布到服务器(分享 ▸ 发布到服务器…),然后在那里发布库。" +"Toggle" = "切换显示" +"Toggle light/dark theme" = "切换浅色/深色主题" +"Toggle visibility" = "切换可见性" +"Tools" = "工具" +"Top" = "顶部" +"Top & bottom" = "上下" +"Top left radius" = "左上圆角" +"Top right radius" = "右上圆角" +"Transform" = "变换" +"Triangle arrow" = "三角箭头" +"Trigger" = "触发器" +"True" = "真" +"Truncate text" = "截断文本" +"Truncate with an ellipsis" = "以省略号截断" +"Try another search or filter." = "请尝试其他搜索词或筛选条件。" +"Two digits" = "两位数" +"Type" = "类型" +"Type settings" = "文字设置" +"Typography" = "排版" +"Underline" = "下划线" +"Undo takes back only your own changes; what others changed since stays." = "撤销仅撤回你自己的更改;他人之后的更改会保留。" +"Ungroup" = "取消编组" +"Uniform" = "均匀" +"Union" = "合并" +"Unions" = "合并" +"Unknown — treated as sRGB" = "未知 — 按 sRGB 处理" +"Unread" = "未读" +"Unresolve" = "取消解决" +"Unsaved changes" = "未保存的更改" +"Unsaved changes in {names}. Close the window and lose them?" = "{names} 中有未保存的更改。要关闭窗口并丢弃这些更改吗?" +"Unsaved changes: save first ({save}), or close the tab with {alt}-click to discard" = "有未保存的更改:请先保存({save}),或按住 {alt} 点击关闭标签页以丢弃" +"Unsaved changes: save first, or close again with {key} to discard" = "有未保存的更改:请先保存,或再次按 {key} 关闭以丢弃" +"Up" = "向上" +"Update" = "更新" +"Update from main" = "从主文件更新" +"Update from selection" = "从所选项更新" +"Updated {components} and {styles}" = "已更新 {components} 和 {styles}" +"Uploads this file to a FigCraft server and keeps this tab in sync with it. You get a link to edit and a link to view." = "将此文件上传到 FigCraft 服务器,并使此标签页与之保持同步。你会获得一个编辑链接和一个查看链接。" +"Uppercase" = "大写" +"Use a fixed value" = "使用固定值" +"Use an expression, e.g. count + 1" = "使用表达式,例如 count + 1" +"Use as mask" = "用作蒙版" +"Use auto layout" = "使用自动布局" +"Use number keys for opacity" = "用数字键设置不透明度" +"Use the layer's fill" = "使用图层的填充" +"Used in {files} · {instances}" = "用于 {files} · {instances}" +"Username" = "用户名" +"Value" = "值" +"Variable" = "变量" +"Variable collections" = "变量集合" +"Variable modes" = "变量模式" +"Variable width" = "可变宽度" +"Variables" = "变量" +"Variables JSON…" = "变量 JSON…" +"Variables store reusable values (colours, numbers, strings, booleans) with modes such as Light and Dark." = "变量存储可复用的值(颜色、数字、字符串、布尔值),并可带有浅色、深色等模式。" +"Variant" = "变体" +"Vector" = "矢量" +"Vectors" = "矢量" +"Version" = "版本" +"Version history" = "版本历史" +"Version {version}" = "版本 {version}" +"Version {v} · {components} · {styles} · {variables}" = "版本 {v} · {components} · {styles} · {variables}" +"Vertical" = "垂直" +"Vertical align" = "垂直对齐" +"Vertical hex" = "垂直六边形" +"Vertical padding" = "垂直内边距" +"Vertical spacing" = "垂直间距" +"Vertical trim" = "垂直裁切" +"View" = "视图" +"View link" = "查看链接" +"View link copied" = "已复制查看链接" +"View only" = "仅查看" +"View only: you see every change as it happens but can't edit. Leave to keep a copy you can edit." = "仅查看:你能实时看到每处更改,但无法编辑。离开会话即可保留一份可编辑的副本。" +"Viewing “{name}”" = "正在查看“{name}”" +"Violet" = "紫" +"Visibility" = "可见性" +"Visible" = "可见" +"Vivid" = "鲜艳" +"Warm" = "暖调" +"Watch" = "手表" +"Wavy" = "波浪线" +"Web" = "Web" +"WebSocket URL" = "WebSocket URL" +"WebSocket URL copied" = "已复制 WebSocket URL" +"Wedge" = "楔形" +"Weight" = "粗细" +"What changed since it was marked ready for dev" = "自标记为可供开发以来的更改" +"What it's for" = "用途" +"What this changed from isn't known: it changed before FigCraft kept a copy of ready-for-dev frames. Resolve the change (or mark it ready again) to compare from now on." = "无法得知更改前的状态:它在 FigCraft 开始保存可供开发画框的副本之前就已更改。请解决此更改(或重新标记为可供开发),以便今后进行比较。" +"While hovering" = "悬停时" +"While pressing" = "按住时" +"White" = "白" +"Why it changed" = "更改原因" +"Widgets" = "小组件" +"Width" = "宽度" +"Width point" = "宽度点" +"Width profile" = "宽度配置" +"With the layers' export settings" = "使用图层的导出设置" +"Wrap" = "换行" +"Wrap in new section" = "包裹到新分区" +"Yellow" = "黄" +"Yesterday" = "昨天" +"You" = "你" +"You'll get the host's file as a new tab and edit it together." = "主持人的文件将在新标签页中打开,你们可以一起编辑。" +"You're spotlighting: everyone follows your view" = "你正在聚焦:所有人都在跟随你的视图" +"Your copy of the file stays open" = "你的文件副本保持打开" +"Your name" = "你的名字" +"Your name in comments" = "评论中显示的名字" +"Your system asks for reduced motion: animations stay off." = "系统要求减少动态效果:动画保持关闭。" +"Zoom" = "缩放" +"Zoom around the pointer" = "以指针为中心缩放" +"Zoom device to fill window" = "缩放设备以填满窗口" +"Zoom in" = "放大" +"Zoom out" = "缩小" +"Zoom to 100%" = "缩放至 100%" +"Zoom to 200%" = "缩放至 200%" +"Zoom to 50%" = "缩放至 50%" +"Zoom to fit" = "缩放以适应" +"Zoom to selection" = "缩放至所选项" +"Zoom tool: click to zoom in, drag an area" = "缩放工具:点击放大,或拖出一个区域" +"Zoom tool: zoom out" = "缩放工具:缩小" +"and {n} more" = { other = "以及另外 {n} 个" } +"bleed marks" = "出血标记" +"can edit the document" = "可编辑文档" +"crop marks" = "裁切标记" +"development: {path}" = "开发:{path}" +"e.g. count + 1" = "例如 count + 1" +"e.g. count >= 3 and not done" = "例如 count >= 3 and not done" +"figcraft:// links from a browser, chat or email open this app and join the session." = "来自浏览器、聊天或邮件的 figcraft:// 链接会打开此应用并加入会话。" +"hidden" = "已隐藏" +"iOS" = "iOS" +"locked" = "已锁定" +"no bleed" = "无出血" +"nobody else here yet" = "这里还没有其他人" +"now" = "刚刚" +"or" = "或" +"reads the document" = "读取文档" +"the plugin" = "插件" +"this session only" = "仅限本次会话" +"{instances} in {files}" = "{files} 中的 {instances}" +"{language}: draft translation, waiting for a native speaker's review." = "{language}:翻译草稿,等待母语者审校。" +"{length} bleed" = "出血 {length}" +"{name} is spotlighting" = "{name} 正在聚焦" +"{name}\nClick to apply to the selection" = "{name}\n点击应用于所选项" +"{name}\nDrag onto the canvas, or click to place in the middle of the view.\nHold Alt (Option) while dropping onto an instance to swap it." = "{name}\n拖到画布上,或点击放置在视图中央。\n拖放到实例上时按住 Alt(Option)可替换该实例。" +"{name} (from {library})" = "{name}(来自 {library})" +"{name} (you)" = "{name}(你)" +"{name} ({layers} layers)" = "{name}({layers} 个图层)" +"{name} ({tag}): {min} – {max}, default {default}. Double-click the slider to go back to the style's value; Escape while dragging cancels." = "{name}({tag}):{min} – {max},默认 {default}。双击滑块恢复为样式的值;拖动时按 Esc 取消。" +"{name} from {path}" = "来自 {path} 的 {name}" +"{name} · deleted on main" = "{name} · 已在主文件中删除" +"{name} · deleted on the branch" = "{name} · 已在分支中删除" +"{name} · not published" = "{name} · 未发布" +"{name} · on a server" = "{name} · 在服务器上" +"{name} · published version {v}" = "{name} · 已发布版本 {v}" +"{name} · version {v} on the server" = "{name} · 服务器上的版本 {v}" +"{name}, {kind}, {w} by {h}, selected" = "{name},{kind},{w} × {h},已选中" +"{n} added" = { other = "新增 {n} 个" } +"{n} autosave versions" = { other = "{n} 个自动保存版本" } +"{n} changed" = { other = "更改 {n} 个" } +"{n} columns" = { other = "{n} 列" } +"{n} components" = { other = "{n} 个组件" } +"{n} components and styles have newer versions" = { other = "{n} 个组件和样式有新版本" } +"{n} conflicts to resolve" = { other = "{n} 个冲突待解决" } +"{n} days ago" = { other = "{n} 天前" } +"{n} files" = { other = "{n} 个文件" } +"{n} hours ago" = { other = "{n} 小时前" } +"{n} instances" = { other = "{n} 个实例" } +"{n} layers" = { other = "{n} 个图层" } +"{n} layers as one file" = { other = "{n} 个图层合为一个文件" } +"{n} layers selected" = { other = "已选择 {n} 个图层" } +"{n} layers · {parts}" = { other = "{n} 个图层 · {parts}" } +"{n} matches" = { other = "{n} 个匹配项" } +"{n} minutes ago" = { other = "{n} 分钟前" } +"{n} months ago" = { other = "{n} 个月前" } +"{n} of {total}" = "第 {n} 个,共 {total} 个" +"{n} people joined" = { other = "{n} 人已加入" } +"{n} preferred components" = { other = "{n} 个首选组件" } +"{n} ready" = { other = "{n} 个可供开发" } +"{n} removed" = { other = "删除 {n} 个" } +"{n} replies" = { other = "{n} 条回复" } +"{n} rows" = { other = "{n} 行" } +"{n} styles" = { other = "{n} 个样式" } +"{n} variables" = { other = "{n} 个变量" } +"{n} weeks ago" = { other = "{n} 周前" } +"{n} years ago" = { other = "{n} 年前" } +"{n}d" = "{n}天" +"{n}h" = "{n}小时" +"{n}m" = "{n}分钟" +"{n}w" = "{n}周" +"{page}, nothing selected" = "{page},未选择任何内容" +"{profile} (current)" = "{profile}(当前)" +"{property} is its value; {property ? \"a\" : \"b\"} picks a string. Other {…} stays as written." = "{property} 表示其值;{property ? \"a\" : \"b\"} 选择一个字符串。其他 {…} 按原样保留。" +"{tool} hold {key}" = "{tool} 按住 {key}" +"{value} isn't a colour" = "{value} 不是颜色" +"{when} · edited" = "{when} · 已编辑" +"← ↑ → ↓" = "← ↑ → ↓" +"⇥ / ⇧⇥" = "⇥ / ⇧⇥" +"⌘ arrows" = "⌘ 方向键" +"⌘ click" = "⌘ 点击" +"⌘ scroll" = "⌘ 滚动" +"⌥ drag" = "⌥ 拖动" + +[commands] +"align.bottom" = "底部对齐" +"align.hcenter" = "水平居中对齐" +"align.left" = "左对齐" +"align.right" = "右对齐" +"align.top" = "顶部对齐" +"align.vcenter" = "垂直居中对齐" +"annotation.add" = "添加标注" +"annotation.addCategory" = "添加标注类别" +"annotation.categories" = "标注类别" +"annotation.edit" = "编辑标注" +"annotation.editCategory" = "编辑标注类别" +"annotation.list" = "列出标注" +"annotation.remove" = "移除标注" +"annotation.removeCategory" = "删除标注类别" +"app.actions" = "操作" +"app.preferences" = "偏好设置" +"arrange.back" = "置于底层" +"arrange.backward" = "下移一层" +"arrange.forward" = "上移一层" +"arrange.front" = "置于顶层" +"arrange.packH" = "水平紧凑排列" +"arrange.packV" = "垂直紧凑排列" +"arrange.roundToPixels" = "取整到像素" +"arrange.tidy" = "整理" +"bool.exclude" = "排除所选项" +"bool.flatten" = "拼合布尔组" +"bool.intersect" = "所选项相交" +"bool.subtract" = "减去所选项" +"bool.union" = "合并所选项" +"branch.archive" = "归档分支" +"branch.create" = "创建分支" +"branch.list" = "列出分支" +"branch.merge" = "合并分支" +"branch.open" = "打开分支" +"branch.review" = "审阅分支" +"branch.updateFromMain" = "从主文件更新" +"codeConnect.export" = "导出代码关联" +"codeConnect.import" = "导入代码关联" +"codeConnect.remove" = "取消关联代码" +"codeConnect.set" = "关联代码" +"collab.cursor" = "在指定位置显示光标" +"collab.cursorChat" = "光标聊天" +"collab.diff" = "显示同步更改" +"collab.follow" = "跟随" +"collab.host" = "开始实时会话" +"collab.join" = "加入实时会话" +"collab.leave" = "离开实时会话" +"collab.peers" = "此文件中的成员" +"collab.publish" = "发布到服务器" +"collab.registerLinks" = "在 FigCraft 中打开邀请链接" +"collab.spotlight" = "聚焦于我" +"collab.stop" = "停止实时会话" +"command.batch" = "运行多个命令" +"comment.add" = "添加评论" +"comment.delete" = "删除评论" +"comment.edit" = "编辑评论" +"comment.link" = "复制评论链接" +"comment.list" = "列出评论" +"comment.markRead" = "将评论标为已读" +"comment.move" = "移动评论" +"comment.next" = "下一条评论" +"comment.open" = "打开评论" +"comment.people" = "评论中的成员" +"comment.react" = "对评论做出表情回应" +"comment.reply" = "回复评论" +"comment.resolve" = "解决评论" +"comment.zoom" = "缩放至评论" +"component.addProperty" = "添加组件属性" +"component.addVariant" = "添加变体" +"component.bindProperty" = "将图层绑定到属性" +"component.combineVariants" = "合并为变体" +"component.create" = "创建组件" +"component.createMultiple" = "创建多个组件" +"component.deleteProperty" = "删除组件属性" +"component.detach" = "分离实例" +"component.editProperty" = "编辑组件属性" +"component.exposeInstance" = "公开嵌套实例" +"component.goToMain" = "转到主组件" +"component.list" = "列出组件" +"component.makeSlot" = "设为插槽" +"component.properties" = "组件属性" +"component.pushChanges" = "将更改推送到主组件" +"component.removeSlot" = "移除插槽" +"component.resetInstance" = "重置所有更改" +"component.resetOverride" = "重置覆盖" +"component.restoreMain" = "恢复主组件" +"dev.compare" = "比较更改" +"dev.focus" = "聚焦视图" +"dev.resolveChange" = "解决更改" +"dev.unfocus" = "退出聚焦视图" +"devResource.add" = "添加开发资源" +"devResource.edit" = "编辑开发资源" +"devResource.list" = "列出开发资源" +"devResource.remove" = "移除开发资源" +"distribute.horizontal" = "水平间距分布" +"distribute.vertical" = "垂直间距分布" +"doc.home" = "主页" +"doc.list" = "列出文档" +"doc.nextTab" = "下一个标签页" +"doc.previousTab" = "上一个标签页" +"doc.switch" = "切换文档" +"edit.copy" = "复制" +"edit.copyAsCss" = "复制为 CSS" +"edit.copyAsPng" = "复制为 PNG" +"edit.copyAsSvg" = "复制为 SVG" +"edit.copyAsText" = "复制为文本" +"edit.copyLink" = "复制所选项链接" +"edit.copyProperties" = "复制属性" +"edit.cut" = "剪切" +"edit.delete" = "删除" +"edit.duplicate" = "创建副本" +"edit.findReplace" = "查找和替换" +"edit.paste" = "粘贴" +"edit.pasteOver" = "粘贴到所选项上方" +"edit.pasteProperties" = "粘贴属性" +"edit.pasteReplace" = "粘贴以替换" +"edit.pickColor" = "取色" +"edit.redo" = "重做" +"edit.repeat" = "重复上一个命令" +"edit.setDefaultProperties" = "设为默认属性" +"edit.undo" = "撤销" +"effect.add" = "添加效果" +"effect.move" = "移动效果" +"effect.remove" = "移除效果" +"effect.set" = "设置效果" +"export.add" = "添加导出设置" +"export.remove" = "移除导出设置" +"export.update" = "编辑导出设置" +"file.close" = "关闭标签页" +"file.colorProfile" = "颜色配置文件" +"file.duplicate" = "创建文件副本" +"file.export" = "导出" +"file.exportFramesPdf" = "将画框导出为 PDF" +"file.exportLayers" = "导出图层" +"file.exportSvg" = "将所选项导出为 SVG" +"file.import" = "导入" +"file.new" = "新建设计文件" +"file.open" = "打开" +"file.openRecent" = "打开最近的文件" +"file.placeImage" = "置入图片" +"file.recover" = "恢复文件" +"file.rename" = "重命名文件" +"file.revert" = "还原到上次保存" +"file.save" = "保存" +"file.saveAs" = "另存为" +"file.saveVersion" = "保存到版本历史" +"file.versionHistory" = "显示版本历史" +"fill.add" = "添加填充" +"fill.move" = "移动填充" +"fill.pattern" = "图案填充" +"fill.remove" = "移除填充" +"fill.set" = "设置填充" +"frame.create" = "创建画框" +"frame.presets" = "列出画框预设" +"frame.swapOrientation" = "切换方向" +"grid.add" = "添加布局网格" +"grid.move" = "移动布局网格" +"grid.remove" = "移除布局网格" +"guide.add" = "添加参考线" +"guide.clear" = "移除所有参考线" +"guide.move" = "移动参考线" +"guide.remove" = "移除参考线" +"guide.select" = "选择参考线" +"help.about" = "关于 FigCraft" +"help.page" = "帮助页面" +"help.shortcuts" = "键盘快捷键" +"image.adjust" = "调整图片" +"image.deletePreset" = "删除图片预设" +"image.place" = "置入图片" +"image.presets" = "图片预设" +"image.savePreset" = "保存图片预设" +"inspect.assets" = "检查资源" +"inspect.code" = "图层代码" +"inspect.componentCode" = "组件代码" +"inspect.properties" = "检查属性" +"inspect.readyForDev" = "可供开发" +"instance.create" = "创建实例" +"instance.exposed" = "公开的嵌套实例" +"instance.place" = "放置实例" +"instance.resetSlot" = "重置插槽" +"instance.setProperties" = "设置实例属性" +"instance.slotInsert" = "插入插槽" +"instance.swap" = "替换实例" +"instance.swapAt" = "替换指定位置的实例" +"layers.collapseAll" = "折叠图层" +"layout.add" = "添加自动布局" +"layout.remove" = "移除自动布局" +"layout.setTrack" = "设置网格轨道大小" +"layout.suggest" = "建议自动布局" +"libraries.open" = "库" +"libraries.publish" = "发布库…" +"library.acceptUpdates" = "接受库更新" +"library.add" = "添加库" +"library.aliasVariable" = "为库变量创建别名" +"library.applyStyle" = "应用库样式" +"library.bindVariable" = "绑定库变量" +"library.extendCollection" = "扩展库集合" +"library.import" = "导入库组件" +"library.importVariable" = "导入库变量" +"library.list" = "列出库" +"library.place" = "放置库组件" +"library.publish" = "发布库" +"library.publishToServer" = "将库发布到服务器" +"library.remove" = "移除库" +"library.setVariableMode" = "设置库变量模式" +"library.swap" = "替换库" +"library.swapAt" = "将实例替换为库组件" +"library.updates" = "库更新" +"library.usage" = "库使用情况" +"measure.distances" = "测量距离" +"measure.padding" = "测量自动布局内边距" +"node.create" = "创建图层" +"node.get" = "获取图层" +"node.reorder" = "调整图层顺序" +"node.reparent" = "将图层移入" +"node.set" = "设置属性" +"object.batchRename" = "批量重命名" +"object.flipH" = "水平翻转" +"object.flipV" = "垂直翻转" +"object.frameSelection" = "为所选项添加画框" +"object.group" = "编组所选项" +"object.hideOthers" = "隐藏其他图层" +"object.mask" = "用作蒙版" +"object.moveToPage" = "移至页面" +"object.opacityKeys" = "用数字键设置不透明度" +"object.rasterize" = "栅格化所选项" +"object.releaseMask" = "释放蒙版" +"object.removeFill" = "移除填充" +"object.removeFrame" = "移除画框" +"object.removeStroke" = "移除描边" +"object.rename" = "重命名" +"object.resizeToFit" = "调整大小以适应" +"object.rotate180" = "旋转 180°" +"object.rotateLeft" = "向左旋转 90°" +"object.rotateRight" = "向右旋转 90°" +"object.setThumbnail" = "设为缩略图" +"object.swapFillStroke" = "互换填充和描边" +"object.toggleLock" = "锁定/解锁所选项" +"object.toggleVisible" = "显示/隐藏所选项" +"object.ungroup" = "取消编组所选项" +"object.wrapInSection" = "包裹到新分区" +"page.add" = "添加页面" +"page.delete" = "删除页面" +"page.duplicate" = "复制页面" +"page.list" = "列出页面" +"page.move" = "移动页面" +"page.rename" = "重命名页面" +"page.select" = "转到页面" +"page.setBackground" = "页面背景" +"paint.documentColors" = "文档颜色" +"plugin.close" = "关闭插件面板" +"plugin.event" = "使用插件面板控件" +"plugin.import" = "从清单导入插件…" +"plugin.list" = "列出插件" +"plugin.remove" = "移除插件" +"plugin.run" = "运行插件" +"plugin.ui" = "插件面板" +"plugins.manage" = "管理插件…" +"plugins.runLast" = "运行上一个插件" +"pref.highlightHover" = "悬停时高亮图层" +"pref.keepTool" = "使用后保持工具选中" +"pref.language" = "界面语言" +"pref.nudge" = "微移量" +"pref.numberKeysOpacity" = "用数字键设置不透明度" +"pref.reduceMotion" = "减少动态效果" +"pref.renameDuplicates" = "重命名副本图层" +"pref.showDimensions" = "在对象上显示尺寸" +"pref.userName" = "评论中显示的名字" +"proto.action.add" = "添加原型操作" +"proto.action.move" = "调整原型操作顺序" +"proto.action.remove" = "移除原型操作" +"proto.action.set" = "编辑原型操作" +"proto.closePreview" = "关闭原型预览" +"proto.conditional.addBlock" = "添加否则如果 / 否则" +"proto.conditional.removeBlock" = "移除如果 / 否则如果 / 否则" +"proto.conditional.setCondition" = "编辑条件" +"proto.flow.add" = "添加流程起点" +"proto.flow.remove" = "移除流程" +"proto.flow.rename" = "重命名流程" +"proto.interaction.add" = "添加交互" +"proto.interaction.clear" = "移除所有交互" +"proto.interaction.remove" = "移除交互" +"proto.interaction.set" = "编辑交互" +"proto.present" = "演示" +"proto.presentOptions" = "演示选项" +"proto.preview" = "打开原型预览" +"proto.settings" = "原型设置" +"section.toggleContents" = "隐藏/显示分区内容" +"select.add" = "添加到所选项" +"select.all" = "全选" +"select.area" = "框选区域" +"select.byName" = "按名称选择图层" +"select.children" = "选择子级" +"select.inverse" = "反选" +"select.layersAt" = "某点处的图层" +"select.matching" = "选择匹配的图层" +"select.next" = "选择下一个同级" +"select.none" = "取消选择" +"select.parent" = "选择父级" +"select.previous" = "选择上一个同级" +"select.remove" = "从所选项中移除" +"select.sameEffect" = "选择相同效果" +"select.sameFill" = "选择相同填充" +"select.sameFont" = "选择相同字体" +"select.sameInstance" = "选择相同实例" +"select.sameProperties" = "选择相同属性" +"select.sameStroke" = "选择相同描边" +"select.sameText" = "选择相同文本属性" +"select.set" = "选择" +"shape.arrow" = "箭头" +"shape.ellipse" = "椭圆" +"shape.line" = "直线" +"shape.polygon" = "多边形" +"shape.rectangle" = "矩形" +"shape.star" = "星形" +"shapeBuilder.merge" = "合并区域" +"shapeBuilder.mode" = "形状生成器模式" +"shapeBuilder.regions" = "形状生成器区域" +"shapeBuilder.remove" = "移除区域" +"stroke.add" = "添加描边" +"stroke.brush" = "画笔" +"stroke.move" = "移动描边" +"stroke.remove" = "移除描边" +"stroke.set" = "设置描边" +"stroke.widthProfile" = "宽度配置" +"style.apply" = "应用样式" +"style.create" = "创建样式" +"style.delete" = "删除样式" +"style.detach" = "分离样式" +"style.duplicate" = "复制样式" +"style.list" = "列出样式" +"style.move" = "移动样式" +"style.renameFolder" = "重命名样式文件夹" +"style.update" = "编辑样式" +"text.alignCenter" = "居中对齐" +"text.alignJustify" = "两端对齐" +"text.alignLeft" = "左对齐" +"text.alignRight" = "右对齐" +"text.bold" = "粗体" +"text.bulletList" = "项目符号列表" +"text.case" = "字母大小写" +"text.caseLower" = "小写" +"text.caseOriginal" = "原样" +"text.caseSmallCaps" = "小型大写" +"text.caseTitle" = "首字母大写" +"text.caseUpper" = "大写" +"text.create" = "文本" +"text.decoration" = "装饰线" +"text.edit.begin" = "编辑文本" +"text.edit.caret" = "设置插入点" +"text.edit.end" = "停止编辑文本" +"text.edit.insert" = "输入文本" +"text.edit.key" = "文本按键" +"text.edit.preedit" = "输入法组字(IME)" +"text.edit.selectLine" = "选择行" +"text.edit.selectWord" = "选择词" +"text.edit.selection" = "文本选区" +"text.endPreview" = "结束文本预览" +"text.fonts" = "列出字体" +"text.italic" = "斜体" +"text.lineHeightDown" = "减小行高" +"text.lineHeightUp" = "增大行高" +"text.link" = "创建链接" +"text.listStyle" = "列表样式" +"text.maxLines" = "最大行数" +"text.numberList" = "编号列表" +"text.onPath" = "路径文本" +"text.paragraphIndent" = "段落缩进" +"text.paragraphSpacing" = "段落间距" +"text.pathOptions" = "路径文本选项" +"text.preview" = "预览文本更改" +"text.removeFromPath" = "从路径上移除文本" +"text.set" = "设置文本" +"text.setFeatures" = "OpenType 特性" +"text.setVariations" = "可变字体轴" +"text.sizeDown" = "减小字号" +"text.sizeUp" = "增大字号" +"text.strikethrough" = "删除线" +"text.style" = "设置文本范围样式" +"text.trackingDown" = "减小字间距" +"text.trackingUp" = "增大字间距" +"text.underline" = "下划线" +"text.weightDown" = "减小字重" +"text.weightUp" = "增大字重" +"tool.arrow" = "箭头" +"tool.comment" = "评论" +"tool.ellipse" = "椭圆" +"tool.frame" = "画框" +"tool.hand" = "抓手" +"tool.line" = "直线" +"tool.move" = "移动" +"tool.pen" = "钢笔" +"tool.pencil" = "铅笔" +"tool.pencilBrush" = "铅笔画笔" +"tool.polygon" = "多边形" +"tool.rectangle" = "矩形" +"tool.scale" = "缩放" +"tool.scaleAnchor" = "缩放锚点" +"tool.section" = "分区" +"tool.set" = "选择工具" +"tool.shapeBuilder" = "形状生成器" +"tool.slice" = "切片" +"tool.star" = "星形" +"tool.text" = "文本" +"transform.move" = "移动" +"transform.moveTo" = "移动到" +"transform.nudge" = "微移" +"transform.nudgeSize" = "按微移量调整大小" +"transform.resize" = "调整大小" +"transform.rotate" = "旋转" +"transform.scale" = "缩放" +"variable.addMode" = "添加模式" +"variable.bind" = "绑定变量" +"variable.create" = "创建变量" +"variable.createCollection" = "创建变量集合" +"variable.delete" = "删除变量" +"variable.deleteCollection" = "删除集合" +"variable.duplicate" = "复制变量" +"variable.export" = "导出变量" +"variable.import" = "导入变量" +"variable.list" = "列出变量" +"variable.moveMode" = "移动模式" +"variable.removeMode" = "删除模式" +"variable.renameCollection" = "重命名集合" +"variable.renameMode" = "重命名模式" +"variable.resetOverride" = "重置变量覆盖" +"variable.set" = "设置变量值" +"variable.setMode" = "设置变量模式" +"variable.update" = "编辑变量" +"vector.create" = "矢量" +"vector.deleteHeal" = "删除并修复所选项" +"vector.edit.addVertex" = "添加点" +"vector.edit.begin" = "编辑矢量" +"vector.edit.bend" = "弯曲线段" +"vector.edit.bounds" = "所选点的边界" +"vector.edit.connect" = "连接点" +"vector.edit.cornerRadius" = "点圆角半径" +"vector.edit.cut" = "剪断路径" +"vector.edit.delete" = "删除点" +"vector.edit.end" = "完成编辑" +"vector.edit.erase" = "擦除" +"vector.edit.lasso" = "套索选择" +"vector.edit.mirroring" = "手柄镜像" +"vector.edit.moveHandles" = "移动手柄" +"vector.edit.moveVertices" = "移动点" +"vector.edit.nudge" = "微移点" +"vector.edit.paint" = "油漆桶" +"vector.edit.pen" = "钢笔点" +"vector.edit.penEnd" = "结束钢笔路径" +"vector.edit.position" = "点位置" +"vector.edit.resize" = "调整点的大小" +"vector.edit.rotate" = "旋转点" +"vector.edit.select" = "选择点" +"vector.edit.selectAll" = "选择所有点" +"vector.edit.setHandle" = "设置手柄" +"vector.edit.smooth" = "平滑或锐化点" +"vector.edit.state" = "矢量编辑状态" +"vector.edit.strokeCap" = "点的描边端点" +"vector.edit.strokeJoin" = "点的描边转角" +"vector.edit.tool" = "矢量编辑工具" +"vector.edit.transform" = "变换点" +"vector.edit.widthPoint" = "宽度点" +"vector.flatten" = "拼合" +"vector.join" = "连接所选项" +"vector.offset" = "偏移路径" +"vector.outlineStroke" = "轮廓化描边" +"vector.reverse" = "反转路径方向" +"vector.simplify" = "简化矢量" +"vector.smoothJoin" = "平滑连接所选项" +"version.autosave" = "自动保存版本" +"version.delete" = "删除版本" +"version.duplicate" = "复制版本" +"version.exitPreview" = "返回当前版本" +"version.list" = "列出版本" +"version.preview" = "查看版本" +"version.rename" = "重命名版本" +"version.restore" = "恢复版本" +"view.assets" = "资源面板" +"view.comments" = "评论" +"view.contextMenu" = "显示上下文菜单" +"view.design" = "设计面板" +"view.designPrototype" = "在设计和原型之间切换" +"view.devMode" = "开发模式" +"view.frameOutlines" = "画框轮廓" +"view.get" = "获取视图" +"view.layers" = "图层面板" +"view.layoutGrids" = "布局网格" +"view.leftSidebar" = "显示/隐藏左侧边栏" +"view.maskOutlines" = "蒙版轮廓" +"view.nextFrame" = "缩放至下一个画框" +"view.nextPage" = "下一页" +"view.nextRegion" = "聚焦下一个区域" +"view.outlines" = "轮廓" +"view.outlinesSelection" = "所选项轮廓" +"view.pixelGrid" = "像素网格" +"view.pixelPreview" = "像素预览" +"view.prevFrame" = "缩放至上一个画框" +"view.prevPage" = "上一页" +"view.previousRegion" = "聚焦上一个区域" +"view.proofSrgb" = "sRGB 软打样" +"view.prototype" = "原型面板" +"view.rulers" = "标尺" +"view.set" = "设置视图" +"view.slices" = "切片" +"view.snapGeometry" = "对齐几何图形" +"view.snapObjects" = "对齐对象" +"view.snapPixel" = "对齐像素网格" +"view.themeDark" = "深色主题" +"view.themeLight" = "浅色主题" +"view.themeSystem" = "跟随系统主题" +"view.toggleUi" = "显示/隐藏界面" +"view.zoom100" = "缩放至 100%" +"view.zoom200" = "缩放至 200%" +"view.zoom50" = "缩放至 50%" +"view.zoomAt" = "缩放工具" +"view.zoomFit" = "缩放以适应" +"view.zoomIn" = "放大" +"view.zoomOut" = "缩小" +"view.zoomSelection" = "缩放至所选项" +"widget.click" = "点击小组件" +"widget.insert" = "插入小组件" +"widget.list" = "列出小组件" +"window.focus" = "将窗口置于前台" +"window.new" = "新建窗口" + +[menu] +"bool.exclude" = "排除" +"bool.flatten" = "拼合" +"bool.intersect" = "相交" +"bool.subtract" = "减去" +"bool.union" = "合并" +"file.duplicate" = "创建副本" +"file.import" = "从文件导入…" +"file.rename" = "重命名" +"libraries.open" = "打开库" +"select.sameEffect" = "效果" +"select.sameFill" = "填充" +"select.sameFont" = "字体" +"select.sameInstance" = "实例" +"select.sameProperties" = "属性" +"select.sameStroke" = "描边" +"select.sameText" = "文本属性" +"text.alignCenter" = "文本居中对齐" +"text.alignJustify" = "文本两端对齐" +"text.alignLeft" = "文本左对齐" +"text.alignRight" = "文本右对齐" +"view.assets" = "资源" +"view.design" = "设计" +"view.layers" = "图层" +"view.outlines" = "显示轮廓" +"view.outlinesSelection" = "显示所选项轮廓" +"view.prototype" = "原型" +"view.themeDark" = "深色" +"view.themeLight" = "浅色" +"view.themeSystem" = "跟随系统" diff --git a/crates/ui-egui/src/cjk.rs b/crates/ui-egui/src/cjk.rs index 25b98dd..354d0e6 100644 --- a/crates/ui-egui/src/cjk.rs +++ b/crates/ui-egui/src/cjk.rs @@ -73,22 +73,25 @@ pub fn can_show(code: &str) -> bool { let need = language(code); need == 0 || !cfg!(target_arch = "wasm32") - || samples(need, false).iter().all(|(c, _)| figcraft_text::face_with_char(*c, &["BIZ UDPGothic", "Noto Sans CJK SC"]).is_some()) + || samples(need, 0).iter().all(|(c, _)| figcraft_text::face_with_char(*c, &["BIZ UDPGothic", "Noto Sans CJK SC"]).is_some()) } -/// A character standing for each script in `need`, with the families to look for it in, the -/// language's own script first. Han without kana in a non-Japanese, non-Korean UI reads as Chinese -/// (a simplified character, Chinese faces first); else a Japanese or Korean face draws it. -fn samples(need: u8, korean_first: bool) -> Vec<(char, Vec<&'static str>)> { - let chinese = need & HAN != 0 && need & KANA == 0 && !korean_first; - let han: (char, Vec<&str>) = match (chinese, korean_first) { +/// A character standing for each script in `need`, with the families to look for it in, the UI +/// language's script (`ui`, see [`language`]) first. Han reads as Chinese (a simplified character, +/// Chinese faces first) in a Chinese UI, and without kana in a UI that isn't Japanese or Korean; +/// else a Japanese or Korean face draws it. +fn samples(need: u8, ui: u8) -> Vec<(char, Vec<&'static str>)> { + let chinese = need & HAN != 0 && (ui == HAN || (ui == 0 && need & KANA == 0)); + let han: (char, Vec<&str>) = match (chinese, ui) { (true, _) => ('们', [CHINESE, JAPANESE, KOREAN].concat()), - (false, true) => ('漢', [KOREAN, JAPANESE, CHINESE].concat()), - (false, false) => ('漢', [JAPANESE, KOREAN, CHINESE].concat()), + (false, HANGUL) => ('漢', [KOREAN, JAPANESE, CHINESE].concat()), + (false, _) => ('漢', [JAPANESE, KOREAN, CHINESE].concat()), }; let mut v = vec![(KANA, ('あ', JAPANESE.to_vec())), (HAN, han), (HANGUL, ('한', KOREAN.to_vec()))]; - if korean_first { - v.reverse(); + match ui { + HANGUL => v.reverse(), + HAN => v.swap(0, 1), + _ => {} } v.into_iter().filter(|(bit, _)| need & bit != 0).map(|(_, s)| s).collect() } @@ -98,7 +101,7 @@ fn samples(need: u8, korean_first: bool) -> Vec<(char, Vec<&'static str>)> { /// tried are read from disk. pub fn faces(need: u8, lang: &str, have: &dyn Fn(char) -> bool) -> Vec> { let mut out: Vec> = Vec::new(); - for (c, families) in samples(need, language(lang) == HANGUL) { + for (c, families) in samples(need, language(lang)) { if have(c) || out.iter().any(|f| f.has_char(c)) { continue; } @@ -123,20 +126,27 @@ mod tests { assert_eq!(language("ja"), KANA | HAN); assert_eq!(language("ko"), HANGUL); assert_eq!(language("zh-Hant"), HAN); + assert_eq!(language("zh-Hans"), HAN); assert_eq!(language("fr"), 0); - assert!(["en", "es", "fr", "de", "pt-BR"].iter().all(|c| can_show(c))); + assert!(["en", "es", "es-419", "fr", "de", "pt-BR"].iter().all(|c| can_show(c))); } #[test] fn the_ui_language_script_comes_first() { - let order = |need, ko| samples(need, ko).into_iter().map(|(c, _)| c).collect::(); - assert_eq!(order(KANA | HAN | HANGUL, false), "あ漢한"); - assert_eq!(order(KANA | HAN | HANGUL, true), "한漢あ"); - assert_eq!(order(HANGUL, false), "한"); + let order = |need, ui| samples(need, ui).into_iter().map(|(c, _)| c).collect::(); + let first_face = |need, ui| samples(need, ui).first().and_then(|(_, f)| f.first()).copied(); + assert_eq!(order(KANA | HAN | HANGUL, 0), "あ漢한"); + assert_eq!(order(KANA | HAN | HANGUL, KANA | HAN), "あ漢한"); + assert_eq!(order(KANA | HAN | HANGUL, HANGUL), "한漢あ"); + assert_eq!(order(HANGUL, 0), "한"); // Han without kana outside a Japanese or Korean UI reads as Chinese. - assert_eq!(order(HAN, false), "们"); - assert_eq!(samples(HAN, false).first().and_then(|(_, f)| f.first()).copied(), Some("Noto Sans CJK SC")); - assert_eq!(samples(HAN, true).first().and_then(|(_, f)| f.first()).copied(), Some("Malgun Gothic")); + assert_eq!(order(HAN, 0), "们"); + assert_eq!(first_face(HAN, 0), Some("Noto Sans CJK SC")); + assert_eq!(first_face(HAN, HANGUL), Some("Malgun Gothic")); + // A Chinese UI draws Han in a Chinese face first, Japanese names in it too. + assert_eq!(order(KANA | HAN | HANGUL, HAN), "们あ한"); + assert_eq!(order(KANA | HAN, language("zh-Hans")), "们あ"); + assert!(["Microsoft YaHei UI", "PingFang SC", "Noto Sans CJK SC"].iter().all(|f| samples(HAN, HAN)[0].1[..4].contains(f))); assert!(faces(0, "en", &|_| false).is_empty()); assert!(faces(KANA | HANGUL | HAN, "ja", &|_| true).is_empty(), "nothing is looked up for scripts the UI draws"); } diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 0ebe2c8..3b8e1b1 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -69,12 +69,16 @@ const LATIN_AMERICA: &[&str] = /// The [`LANGS`] index for one tag: the exact tag ("pt-BR"), else its base language ("es" for /// "es_ES.UTF-8"), else a regional catalog of that language ("pt-BR" for "pt-PT"); Latin American -/// Spanish ("es-MX") reads es-419. A language the UI can't draw (CJK on the web without CJK faces -/// built in) doesn't count. +/// Spanish ("es-MX") reads es-419, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) none: it +/// has no catalog and Simplified isn't a stand-in. A language the UI can't draw (CJK on the web +/// without CJK faces built in) doesn't count. fn resolve_one(want: &str) -> Option { let tag = want.trim().split(['.', '@']).next().unwrap_or("").replace('_', "-"); let base = tag.split('-').next().unwrap_or(""); let has = |subtags: &[&str]| tag.split('-').skip(1).any(|t| subtags.iter().any(|s| s.eq_ignore_ascii_case(t))); + if base.eq_ignore_ascii_case("zh") && (has(&["Hant"]) || (!has(&["Hans"]) && has(&["TW", "HK", "MO"]))) { + return None; + } let find = |t: &str| LANGS.iter().position(|l| l.code.eq_ignore_ascii_case(t)); let alias = (base.eq_ignore_ascii_case("es") && has(LATIN_AMERICA)).then(|| find("es-419")).flatten(); let regional = || LANGS.iter().position(|l| !base.is_empty() && l.code.split('-').next().is_some_and(|b| b.eq_ignore_ascii_case(base))); @@ -130,12 +134,12 @@ pub fn trn(key: &str, n: usize, args: &[(&str, &dyn Display)]) -> String { } /// Whether count `n` takes the "one" form: 0 and 1 in French and Brazilian Portuguese, never in -/// Japanese and Korean (no plural forms: always "other"), 1 elsewhere (CLDR's integer rules). +/// Japanese, Korean and Chinese (no plural forms: always "other"), 1 elsewhere (CLDR's integer rules). // shortcut: CLDR's "many" (French, Spanish and Portuguese millions) reads as "other" here; add it // when a language needs a third form. fn plural_one(lang: usize, n: usize) -> bool { match LANGS.get(lang).map(|l| l.code) { - Some("ja" | "ko") => false, + Some("ja" | "ko" | "zh-Hans") => false, Some("fr" | "pt-BR") => n <= 1, _ => n == 1, } diff --git a/crates/ui-egui/src/i18n_tests.rs b/crates/ui-egui/src/i18n_tests.rs index b33ac41..398097a 100644 --- a/crates/ui-egui/src/i18n_tests.rs +++ b/crates/ui-egui/src/i18n_tests.rs @@ -359,12 +359,12 @@ fn french_and_portuguese_count_zero_as_singular() { } #[test] -fn japanese_and_korean_have_no_plural_forms() { +fn japanese_korean_and_chinese_have_no_plural_forms() { let code = |pref: &str, system: Option<&str>| LANGS[resolve(pref, system)].code; assert_eq!(code("system", Some("ja-JP")), "ja"); assert_eq!(code("system", Some("ko_KR.UTF-8")), "ko"); assert_eq!(code("system", Some("ja,en-US")), "ja"); - for code in ["ja", "ko"] { + for code in ["ja", "ko", "zh-Hans"] { let lang = LANGS.iter().position(|l| l.code == code).unwrap(); assert!(!plural_one(lang, 0) && !plural_one(lang, 1) && !plural_one(lang, 2), "{code}"); let ones: Vec<_> = LANGS[lang].ui.iter().filter(|(_, t)| matches!(t, Text::Plural(Some(_), _))).map(|(k, _)| k).collect(); @@ -372,6 +372,21 @@ fn japanese_and_korean_have_no_plural_forms() { } } +#[test] +fn chinese_reads_simplified_and_traditional_has_no_catalog() { + let code = |pref: &str, system: Option<&str>| LANGS[resolve(pref, system)].code; + for tag in ["zh-CN", "zh_CN.UTF-8", "zh-SG", "zh-Hans", "zh-Hans-CN", "zh-Hans-HK", "zh"] { + assert_eq!(code("system", Some(tag)), "zh-Hans", "{tag}"); + } + // No Traditional Chinese catalog: English, never Simplified; else the next OS language. + for tag in ["zh-TW", "zh-HK", "zh-MO", "zh-Hant", "zh-Hant-TW", "zh_TW.UTF-8"] { + assert_eq!(code("system", Some(tag)), "en", "{tag}"); + assert_eq!(code(tag, None), "en", "{tag}"); + } + assert_eq!(code("system", Some("zh-TW,ja-JP")), "ja"); + assert_eq!(LANGS[resolve("zh-Hans", None)].name, "简体中文"); +} + #[test] fn the_key_scanner_reads_rust_literals() { let src = r#"x(tr("A \"b\"")); trf( diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 5412e65..dcd66e5 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -419,8 +419,8 @@ pub struct FigApp { worker: Option, fonts_installed: bool, /// System faces for scripts the built-in fonts lack were added (after the font scan), with - /// faces for these CJK scripts ([`cjk`]). - script_fonts: Option, + /// faces for these CJK scripts ([`cjk`]) in this UI language's order. + script_fonts: Option<(u8, &'static str)>, /// The tab (uid) and revision whose names were last checked for CJK scripts. cjk_checked: Option<(u64, u64)>, /// The language preference the UI strings follow (applied when it changes). @@ -718,10 +718,12 @@ impl FigApp { } else if figcraft_text::system_fonts_scanned() { // Once the system fonts are indexed: faces for names in scripts the UI fonts lack, and // for each CJK script once something shows it. - let installed = self.script_fonts.unwrap_or(0); + let installed = self.script_fonts.map_or(0, |(s, _)| s); let cjk = installed | self.cjk_needed(ctx, installed); - if self.script_fonts != Some(cjk) { - self.script_fonts = Some(cjk); + // The UI language's script leads the CJK faces, so another language lays them out again. + let lang = i18n::current().map_or("en", |l| l.code); + if self.script_fonts != Some((cjk, lang)) { + self.script_fonts = Some((cjk, lang)); theme::install_fonts(ctx, true, cjk); } } diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index 15aff1f..080bce4 100644 --- a/crates/ui-egui/src/theme.rs +++ b/crates/ui-egui/src/theme.rs @@ -254,35 +254,34 @@ pub fn install_fonts(ctx: &Context, system: bool, cjk: u8) { fonts.families.insert(FontFamily::Name("semibold".into()), semi); // CJK and other scripts from craft-fonts as fallbacks (Noto Sans CJK only with FIGCRAFT_EMBED_CJK). const BUILT_IN: [&str; 4] = ["Inter", "BIZ UDPGothic", "Noto Sans CJK SC", "Noto Sans Arabic"]; - for f in figcraft_text::CRAFT_FONTS.iter().filter(|f| f.family != "Inter" && f.style == "Regular") { - if BUILT_IN.contains(&f.family) { - let key = format!("craft-{}", f.family); - fonts.font_data.insert(key.clone(), Arc::new(FontData::from_static(f.bytes))); - for fam in [FontFamily::Proportional, FontFamily::Name("semibold".into())] { - if let Some(list) = fonts.families.get_mut(&fam) { - list.push(key.clone()); - } - } - } - } + let lang = crate::i18n::current().map_or("en", |l| l.code); + // A Chinese UI draws Han in a Chinese face: the built-in Japanese one goes after the system faces. + let late = |family: &str| family == "BIZ UDPGothic" && crate::cjk::language(lang) == crate::cjk::HAN; + let craft = |last: bool| { + figcraft_text::CRAFT_FONTS + .iter() + .filter(move |f| f.family != "Inter" && f.style == "Regular" && BUILT_IN.contains(&f.family) && late(f.family) == last) + .map(|f| (format!("craft-{}", f.family), FontData::from_static(f.bytes))) + }; + let mut extra: Vec<(String, FontData)> = craft(false).collect(); if system { // What the built-in faces above already draw. let embedded = |c: char| { BUILT_IN .into_iter() - .filter(|f| figcraft_text::CRAFT_FONTS.iter().any(|cf| cf.family == *f)) + .filter(|f| !late(f) && figcraft_text::CRAFT_FONTS.iter().any(|cf| cf.family == *f)) .filter_map(|f| figcraft_text::find_face(f, "Regular")) .any(|x| x.has_char(c)) }; - let mut extra = crate::bidi::script_fallbacks(&embedded); - let lang = crate::i18n::current().map_or("en", |l| l.code); + extra.extend(crate::bidi::script_fallbacks(&embedded)); extra.extend(crate::cjk::faces(cjk, lang, &embedded).iter().map(|f| (format!("system-{}-{}", f.family, f.style), font_data(f)))); - for (key, data) in extra { - fonts.font_data.insert(key.clone(), Arc::new(data)); - for fam in [FontFamily::Proportional, FontFamily::Name("semibold".into())] { - if let Some(list) = fonts.families.get_mut(&fam) { - list.push(key.clone()); - } + } + extra.extend(craft(true)); + for (key, data) in extra { + fonts.font_data.insert(key.clone(), Arc::new(data)); + for fam in [FontFamily::Proportional, FontFamily::Name("semibold".into())] { + if let Some(list) = fonts.families.get_mut(&fam) { + list.push(key.clone()); } } } diff --git a/docs/gaps.md b/docs/gaps.md index 2de79d7..7b39dcd 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Where FigCraft falls short of Figma -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) Every known shortfall against Figma, one entry each, ranked by how much it stops a Figma user from doing real work in FigCraft. Agents: pick work from the top unless the owner says otherwise. The @@ -18,7 +18,7 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe | 2 | Multiplayer and sharing are a preview, without accounts (**beta blocker**) | Feature | 42–84 | [collaboration-parity](collaboration-parity.md) | | 3 | Nothing checked against real Figma files | Fidelity | 15–30 | [target-app-parity](target-app-parity.md) | | 4 | Interaction fidelity not compared tool by tool | UI/UX | 40–60 | [ui-parity](ui-parity.md) | -| 5 | Localization: English plus unreviewed Spanish (and Latin American Spanish), French, German, Brazilian Portuguese, Japanese and Korean drafts | Localization | 31–54 | [localization-parity](localization-parity.md) | +| 5 | Localization: English plus unreviewed Spanish (and Latin American Spanish), French, German, Brazilian Portuguese, Japanese, Korean and Simplified Chinese drafts | Localization | 29–51 | [localization-parity](localization-parity.md) | | 6 | Plugins: widgets take clicks only, a self-hosted directory but no public catalogue; Figma's plugins don't run | Ecosystem | 8–26 | [target-app-parity](target-app-parity.md) | | 7 | CPU canvas where Figma uses the GPU | Hardware/performance | 30–60 | [hardware-parity](hardware-parity.md) | | 8 | Platform QA: Linux and the browser left (Windows pass done 2026-10-11) | Stability/platforms | 10–20 | [hardware-parity](hardware-parity.md) | @@ -101,21 +101,23 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe - **Estimate:** 40–60 h. Detail in [`ui-parity.md`](ui-parity.md). ### 5. Localization: English plus unreviewed drafts -- **Missing:** native reviews of the Spanish, French, German, Brazilian Portuguese, Japanese and - Korean drafts and the Latin American Spanish overlay, localized engine messages and number +- **Missing:** native reviews of the Spanish, French, German, Brazilian Portuguese, Japanese, + Korean and Simplified Chinese drafts and the Latin American Spanish overlay, the 25 newest strings + in five drafts, Hindi, Arabic, Indonesian and Vietnamese, localized engine messages and number formatting; CJK UI text on the web without the craft-fonts CJK build. - **Evidence (measured from source):** the layer landed 2026-10-11: catalogs in - `crates/ui-egui/locales/` (1,351 UI keys plus 519 command labels and 29 menu wordings), + `crates/ui-egui/locales/` (1,371 UI keys plus 524 command labels and 29 menu wordings), Preferences ▸ Language, `pref.language`; `en.toml` is complete, and `es.toml`, `fr.toml`, - `de.toml`, `pt-BR.toml`, `ja.toml` and `ko.toml` (2026-10-12) are complete machine drafts, with - `es-419.toml` a Latin American overlay listing only what differs from Spanish (only Spanish is - held to completeness by the check; the others show English for strings added later). + `de.toml`, `pt-BR.toml`, `ja.toml`, `ko.toml` and `zh-Hans.toml` (2026-10-12) are machine drafts + (all but `zh-Hans.toml` lack the 25 newest strings), with `es-419.toml` a Latin American overlay + listing only what differs from Spanish (only Spanish is held to completeness by the check; the + others show English for strings added later). CJK UI text uses an installed CJK face the desktop app loads when something on screen needs it (`crates/ui-egui/src/cjk.rs`). Engine error messages and Dev Mode values stay English. - **Impact:** non-English designers get machine drafts nobody has reviewed yet, and English errors. - **Estimate:** 3–7 h per language plus native review, 4–6 h for engine messages and numbers; - 31–54 h for the key languages left and the drafts' follow-ups. Detail in + 29–51 h for the key languages left and the drafts' follow-ups. Detail in [`localization-parity.md`](localization-parity.md); how to add one in [`translating.md`](translating.md). @@ -350,6 +352,7 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Simplified Chinese draft catalog (gap 5): `zh-Hans.toml` translates every UI string (1,371 keys; plurals give only `other`, and `plural_one` never picks "one"), command label (524) and menu wording (29), machine-drafted in a concise UI style with full-width punctuation and marked as a draft awaiting native review; Preferences ▸ Language lists 简体中文, System maps zh, zh-CN, zh-SG and zh-Hans to it, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and stays English (or the next OS language), never Simplified. A Chinese UI draws Han in a Chinese face first (Microsoft YaHei, PingFang SC, Noto Sans CJK SC), ahead of the craft-fonts build's Japanese BIZ UDPGothic, and changing the UI language lays the CJK faces out again (switching from Japanese to Chinese no longer keeps the Japanese face in front). String counts re-measured: 1,371 UI keys, 524 command labels and 29 menu wordings (1,924 entries); the French, German, Brazilian Portuguese, Japanese and Korean drafts have 1,899 of them (the 25 newer strings read English). Gap 5 31–54 h → 29–51 h, rank unchanged | | 2026-10-12 | minor | Latin American Spanish overlay (gap 5): `es-419.toml` lists only the 87 entries (61 UI strings, 26 command labels) whose wording differs in Latin American usage (agregar for añadir, presionar for pulsar, configuración for settings, Enter for the Intro key, control for a gamepad, resorte for a spring) and reads `es.toml`, then English, for the rest (a regional catalog overlays its language's); same tú register as Spanish; a draft awaiting native review. Preferences ▸ Language lists Español (Latinoamérica); System maps es-419, es-MX, es-AR, es-CO and the other Latin American and US Spanish tags to it, es-ES and es to Spanish. Gap 5 32–55 h → 31–54 h, rank unchanged | | 2026-10-12 | minor | Gap 15: controller buttons on key/gamepad triggers (Windows and the browser), widgets reacting in prototypes and `proto.evaluate` landed; gap 15 now media plus controllers off Windows, 3–6 h → 2–5 h; ranking unchanged | | 2026-10-12 | minor | Plugin directory on `figcraft-server` (publish with the server key, browse, install after a permissions confirmation, hash-checked downloads, updates by version, operator moderation) added to gap 6's landed list; gap 6 10–30 h → 8–26 h; ranking unchanged | diff --git a/docs/localization-parity.md b/docs/localization-parity.md index 1d29f88..01f2024 100644 --- a/docs/localization-parity.md +++ b/docs/localization-parity.md @@ -1,11 +1,12 @@ # Localization parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Latin American Spanish overlay) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Simplified Chinese draft catalog) · **Target:** Figma Design (desktop app 126.10.7) -FigCraft's interface has a localization layer with an English catalog and complete Spanish (with a -Latin American overlay), French, German, Brazilian Portuguese, Japanese and Korean drafts -(machine-drafted, waiting for native speakers' review). This page lists the twelve key languages of the craftrules standard, then the other languages Figma -ships. How to add a language: [`translating.md`](translating.md). +FigCraft's interface has a localization layer with an English catalog and Spanish (with a Latin +American overlay), French, German, Brazilian Portuguese, Japanese, Korean and Simplified Chinese +drafts (machine-drafted, waiting for native speakers' review). This page lists the twelve key +languages of the craftrules standard, then the other languages Figma ships. How to add a +language: [`translating.md`](translating.md). ## What Figma ships @@ -23,16 +24,18 @@ supported by both apps (CJK, Arabic and Devanagari shaping, IME); Figma has no v (`tr("Fill")`, `trf` for `{named}` placeholders, `trn` for counts with one/other plural forms), so a missing translation shows English, never a raw key. One English text that needs two translations takes a context (`"Fill|sizing"`). -- **Strings:** 1,351 UI keys in `en.toml` (36 with plural forms; ~110 are labels from engine and - document data, such as tool names, blend modes and Dev Mode properties) plus 519 command labels - and 29 menu wordings by command id: 1,899 entries. Command ids, the CLI, MCP and the control +- **Strings:** 1,371 UI keys in `en.toml` (36 with plural forms; ~110 are labels from engine and + document data, such as tool names, blend modes and Dev Mode properties) plus 524 command labels + and 29 menu wordings by command id: 1,924 entries. Command ids, the CLI, MCP and the control channel stay English. Accessibility names come from the same strings. - **Language preference:** Preferences ▸ Language (System, English, Deutsch, Español, Español - (Latinoamérica), Français, 日本語, 한국어, Português (Brasil)), applied at once without a restart; - System takes the first of the OS's preferred languages that has a catalog (Windows' language - list, macOS AppleLanguages, `LANGUAGE` then the locale variables on Linux and BSD; a regional tag + (Latinoamérica), Français, 日本語, 한국어, Português (Brasil), 简体中文), applied at once without a + restart; System takes the first of the OS's preferred languages that has a catalog (Windows' + language list, macOS AppleLanguages, `LANGUAGE` then the locale variables on Linux and BSD; a regional tag falls back to its language, pt-PT or pt to pt-BR, and es-419, es-MX, es-AR, es-CO and the other - Latin American and US Spanish tags to es-419) or the browser's language on the web. + Latin American and US Spanish tags to es-419; zh, zh-CN, zh-SG and zh-Hans read zh-Hans, while + Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and reads English or the next OS + language, never Simplified) or the browser's language on the web. `pref.language {language}` sets it from the CLI, MCP and the control channel. - **Regional overlays:** a regional catalog whose language has a catalog lists only what differs (`es-419.toml` over `es.toml`); its UI strings, command labels and menu wordings read the @@ -40,13 +43,13 @@ supported by both apps (CJK, Arabic and Devanagari shaping, IME); Figma has no v - **Check:** `cargo test -p figcraft-ui-egui i18n` fails on keys the code uses that `en.toml` lacks, keys no code uses, unknown command ids, placeholders that differ from English, overlay entries that read as in their base language and, for complete languages (Spanish), anything - untranslated. The French, German, Brazilian Portuguese, Japanese and Korean drafts translate - everything today but are not held to it: a string added later shows English there until someone - translates it. + untranslated. The other drafts are not held to it: a string added later shows English there + until someone translates it. Simplified Chinese translates everything today; French, German, + Brazilian Portuguese, Japanese and Korean lack the 25 strings added since they were drafted. - **Not yet localized:** messages the engine writes (errors, a few toasts, Dev Mode property values such as "inside"), number formatting (decimal points stay `.`), and plural forms beyond one/other - (French and Brazilian Portuguese take the singular for 0 as well; Japanese and Korean have one - form; CLDR's "many" for millions reads as the plural). + (French and Brazilian Portuguese take the singular for 0 as well; Japanese, Korean and Chinese + have one form; CLDR's "many" for millions reads as the plural). - **Script support in documents:** Unicode bidi with Arabic shaping and mirrored brackets in text layers; right-to-left list markers and indents; right-to-left names in the layers panel, tabs and canvas labels (visual order, joined Arabic); inline IME composition with the candidate window @@ -63,27 +66,29 @@ supported by both apps (CJK, Arabic and Devanagari shaping, IME); Figma has no v Meiryo, Malgun Gothic, Microsoft YaHei; macOS: Hiragino Sans, Apple SD Gothic Neo, PingFang SC; Linux and BSD: Noto Sans CJK, Source Han Sans, Nanum, WenQuanYi; the craft-fonts build's BIZ UDPGothic first), the UI language's script first; Han without kana outside a Japanese or Korean UI - reads as Chinese. Only that face's file is read and egui shares its bytes, so English users load + reads as Chinese, and a Chinese UI puts its Chinese face (Microsoft YaHei, PingFang SC, Noto Sans + CJK SC) ahead of the built-in Japanese one, so Han takes Simplified Chinese shapes; changing the + UI language lays the faces out again. Only that face's file is read and egui shares its bytes, so English users load nothing (startup and memory measured unchanged); no CJK font installed means tofu, never a crash. The web build has no system fonts: built with craft-fonts and `FIGCRAFT_EMBED_CJK=1` it - embeds Noto Sans CJK (+16 MB) and offers Japanese and Korean; otherwise the language picker and + embeds Noto Sans CJK SC (+16 MB) and offers Japanese, Korean and Simplified Chinese; otherwise the language picker and System leave them out. No font file is in this repo. ## Languages | Language | Code | UI strings translated | Dialogs / tooltips / help | Script support | Native review | Status | Hours to full | |---|---|---|---|---|---|---|---| -| English | en | 1,899 / 1,899 (100%, source) | yes | Latin | yes (source) | full | 0 | -| Simplified Chinese (Mandarin) | zh-Hans | 0 (0%) | no | CJK text, IME and font fallback work in documents; CJK UI faces load on demand (desktop) | no | none | 3–5 | -| Spanish | es, es-419 | 1,899 / 1,899 (100%, draft); es-419 overlays 87 Latin American wordings (draft) | yes | Latin | no | draft | 0–1 (after native review) | +| English | en | 1,924 / 1,924 (100%, source) | yes | Latin | yes (source) | full | 0 | +| Simplified Chinese (Mandarin) | zh-Hans | 1,924 / 1,924 (100%, draft) | yes | CJK text and IME in documents; UI text in an installed Chinese face, ahead of Japanese ones (web: the `FIGCRAFT_EMBED_CJK` build); no Traditional Chinese catalog (zh-TW, zh-HK read English) | no | draft | 1–2 (after native review) | +| Spanish | es, es-419 | 1,924 / 1,924 (100%, draft); es-419 overlays 87 Latin American wordings (draft) | yes | Latin | no | draft | 0–1 (after native review) | | Hindi | hi | 0 (0%) | no | Devanagari shaping works in documents; UI font fallback to check | no | none | 4–7 | | Arabic | ar | 0 (0%) | no | Bidi, shaping and RTL names work; the UI does not mirror | no | none | 9–15 | -| French | fr | 1,899 / 1,899 (100%, draft) | yes | Latin | no | draft | 1–2 (after native review) | -| Portuguese | pt-BR | 1,899 / 1,899 (100%, draft) | yes | Latin | no | draft | 1–2 (after native review) | +| French | fr | 1,899 / 1,924 (99%, draft) | yes | Latin | no | draft | 1–2 (after native review) | +| Portuguese | pt-BR | 1,899 / 1,924 (99%, draft) | yes | Latin | no | draft | 1–2 (after native review) | | Indonesian | id | 0 (0%) | no | Latin | no | none | 3–5 | -| Japanese | ja | 1,899 / 1,899 (100%, draft) | yes | CJK text and IME in documents; UI text in an installed Japanese face (web: the `FIGCRAFT_EMBED_CJK` build) | no | draft | 1–2 (after native review) | -| German | de | 1,899 / 1,899 (100%, draft) | yes | Latin; long words elide in narrow fields | no | draft | 1–2 (after native review) | -| Korean | ko | 1,899 / 1,899 (100%, draft) | yes | Hangul text and IME in documents; UI text in an installed Korean face (web: the `FIGCRAFT_EMBED_CJK` build) | no | draft | 1–2 (after native review) | +| Japanese | ja | 1,899 / 1,924 (99%, draft) | yes | CJK text and IME in documents; UI text in an installed Japanese face (web: the `FIGCRAFT_EMBED_CJK` build) | no | draft | 1–2 (after native review) | +| German | de | 1,899 / 1,924 (99%, draft) | yes | Latin; long words elide in narrow fields | no | draft | 1–2 (after native review) | +| Korean | ko | 1,899 / 1,924 (99%, draft) | yes | Hangul text and IME in documents; UI text in an installed Korean face (web: the `FIGCRAFT_EMBED_CJK` build) | no | draft | 1–2 (after native review) | | Vietnamese | vi | 0 (0%) | no | Latin with stacked diacritics | no | none | 3–5 | Other languages: none shipped (Figma ships none beyond the eight above). @@ -92,15 +97,18 @@ The layer is done. Per-language hours above are agent hours for a catalog of ~1, (a machine draft, then a pass over the panels for overflow), plus each language's plural rule where it isn't one/other; every language also needs a native speaker's review (human). Left before full parity besides the languages: localizing engine messages and number formatting (4–6 h); -right-to-left mirroring of the panels is in Arabic's hours. Total: **31–54 h**. +right-to-left mirroring of the panels is in Arabic's hours. Total: **29–51 h**. -Priority: native reviews of the six drafts and the es-419 overlay (every one of Figma's languages -and variants now has one), then Simplified Chinese, whose UI fonts already work. +Priority: native reviews of the seven drafts and the es-419 overlay (every one of Figma's languages +and variants has one, plus Simplified Chinese, which Figma doesn't ship), the 25 newer strings in the +French, German, Brazilian Portuguese, Japanese and Korean drafts, then Hindi, Indonesian, +Vietnamese and Arabic. Traditional Chinese is not planned (no catalog; its users see English). ## Revision history | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Simplified Chinese draft catalog (gap 5): `zh-Hans.toml` translates every UI string (1,371 keys; plurals give only `other`, and `plural_one` never picks "one"), command label (524) and menu wording (29), machine-drafted in a concise UI style with full-width punctuation and marked as a draft awaiting native review; Preferences ▸ Language lists 简体中文, System maps zh, zh-CN, zh-SG and zh-Hans to it, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and stays English (or the next OS language), never Simplified. A Chinese UI draws Han in a Chinese face first (Microsoft YaHei, PingFang SC, Noto Sans CJK SC), ahead of the craft-fonts build's Japanese BIZ UDPGothic, and changing the UI language lays the CJK faces out again (switching from Japanese to Chinese no longer keeps the Japanese face in front). String counts re-measured: 1,371 UI keys, 524 command labels and 29 menu wordings (1,924 entries); the French, German, Brazilian Portuguese, Japanese and Korean drafts have 1,899 of them (the 25 newer strings read English). Localization 36% → 39%, 31–54 h → 29–51 h | | 2026-10-12 | minor | Latin American Spanish overlay (gap 5): `es-419.toml` lists only the 87 entries (61 UI strings, 26 command labels) whose wording differs in Latin American usage (agregar for añadir, presionar for pulsar, configuración for settings, Enter for the Intro key, control for a gamepad, resorte for a spring) and reads `es.toml`, then English, for the rest (a regional catalog overlays its language's); same tú register as Spanish; a draft awaiting native review. Preferences ▸ Language lists Español (Latinoamérica); System maps es-419, es-MX, es-AR, es-CO and the other Latin American and US Spanish tags to it, es-ES and es to Spanish. A regional catalog's lookups (UI strings, command labels, menu wordings) go overlay → base language → English; the check fails on an overlay entry that reads as in its base. Localization 35% → 36%, 32–55 h → 31–54 h | | 2026-10-12 | minor | Japanese and Korean draft catalogs and CJK UI fonts (gap 5): `ja.toml` and `ko.toml` translate every UI string (1,351 keys; plurals give only `other`, and `plural_one` never picks "one" in either), command label (519) and menu wording (29), machine-drafted and marked as drafts awaiting native review; Preferences ▸ Language lists 日本語 and 한국어, System picks ja* and ko*. CJK UI text renders: once the UI language, the open file's names or comments, typed text or the language picker needs Japanese kana, Hangul or Han, the desktop app appends one installed face per script to egui's fallbacks (Windows Yu Gothic UI / Meiryo / Malgun Gothic / Microsoft YaHei, macOS Hiragino Sans / Apple SD Gothic Neo / PingFang SC, Linux Noto Sans CJK; the craft-fonts build's BIZ UDPGothic first), reading only that face's file and sharing its bytes with egui (English users load none: startup and memory unchanged); the web shows Japanese and Korean only when built with craft-fonts' Noto Sans CJK (`FIGCRAFT_EMBED_CJK`), else it keeps them out of the picker and System. Localization 30% → 35%, 40–65 h → 32–55 h | | 2026-10-12 | minor | French, German and Brazilian Portuguese draft catalogs (gap 5): `fr.toml`, `de.toml` and `pt-BR.toml` translate every UI string (1,351 keys, 36 with plural forms), command label (519) and menu wording (29), machine-drafted and marked as drafts awaiting native review; they fall back to English per key, so new strings need only English and Spanish. French and Brazilian Portuguese count 0 as singular (`plural_one`); System picks the first OS language with a catalog (Windows' and macOS's preferred-language lists, `LANGUAGE` then the locale on Linux and BSD; pt-PT and pt read pt-BR); Preferences ▸ Language lists Français, Deutsch and Português (Brasil). Dropdowns, two-column labels and the home cards keep long translations on one line with an ellipsis and show them in full on hover. Localization 20% → 30%, 45–75 h → 40–65 h | diff --git a/docs/mcp.md b/docs/mcp.md index a6fa2e2..27519b8 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -271,7 +271,7 @@ on; `key` resolves keys the way the canvas does. Commands behind keys: nested layers), Escape or a click drops it. - `pref.reduceMotion {on?}`: reduced motion (the interface's own animations off; the system's accessibility setting turns it on too). Prototype transitions still play. -- `pref.language {language: system|en|es|es-419|fr|de|pt-BR|ja|ko|…}`: the app's interface language, applied live ("system": +- `pref.language {language: system|en|es|es-419|fr|de|pt-BR|ja|ko|zh-Hans|…}`: the app's interface language, applied live ("system": the OS or browser language; a language without a catalog shows English). Command ids, labels and every result stay English. diff --git a/docs/roadmap.md b/docs/roadmap.md index 37d7656..41ac809 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # FigCraft roadmap: milestones and what's next -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; `.fig` import, best effort; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~79%) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; `.fig` import, best effort; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~79%) · **Target:** Figma Design (desktop app 126.10.7) Forward-looking plan. Where FigCraft stands today: [`ROADMAP.md`](../ROADMAP.md) and [`target-app-parity.md`](target-app-parity.md); the full ranked list: [`gaps.md`](gaps.md). Hours @@ -15,8 +15,8 @@ are one Opus 5.5 agent; most milestones split across 4–6 agents on disjoint cr exports, turn estimated percentages into measured ones: 15–30 h. 3. **Tool-by-tool interaction pass** against the running Figma ([`ui-parity.md`](ui-parity.md)): 40–60 h, parallel by tool. -4. **Languages** on the landed localization layer: native reviews of the es, fr, de, pt-BR, ja and - ko drafts and the es-419 overlay (people), then the other key languages: 3–7 h per language +4. **Languages** on the landed localization layer: native reviews of the es, fr, de, pt-BR, ja, + ko and zh-Hans drafts and the es-419 overlay (people), then the other key languages: 3–7 h per language plus native review. 5. **Multiplayer M9**: accounts and teams on top of the live sessions and the standalone server (the WebSocket transport, hosting from the app, invite links that open the app, document sync, live cursors, selections, text carets, avatars and follow, per-user undo, reconnect with offline edits, collision-free ids for styles, variables, collections and comments, joining from the browser, and `figcraft-server` with persistence, publishing from the app and share links to edit or view landed), per [`collab-protocol.md`](collab-protocol.md) and [`server.md`](server.md): 45–90 h. @@ -73,6 +73,7 @@ blockers. | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Simplified Chinese draft catalog (gap 5): `zh-Hans.toml` translates every UI string (1,371 keys; plurals give only `other`, and `plural_one` never picks "one"), command label (524) and menu wording (29), machine-drafted in a concise UI style with full-width punctuation and marked as a draft awaiting native review; Preferences ▸ Language lists 简体中文, System maps zh, zh-CN, zh-SG and zh-Hans to it, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and stays English (or the next OS language), never Simplified. A Chinese UI draws Han in a Chinese face first (Microsoft YaHei, PingFang SC, Noto Sans CJK SC), ahead of the craft-fonts build's Japanese BIZ UDPGothic, and changing the UI language lays the CJK faces out again (switching from Japanese to Chinese no longer keeps the Japanese face in front). String counts re-measured: 1,371 UI keys, 524 command labels and 29 menu wordings (1,924 entries); the French, German, Brazilian Portuguese, Japanese and Korean drafts have 1,899 of them (the 25 newer strings read English). Focus item 4 adds the zh-Hans draft's review | | 2026-10-12 | minor | Latin American Spanish overlay (gap 5): `es-419.toml` lists only the 87 entries (61 UI strings, 26 command labels) whose wording differs in Latin American usage (agregar for añadir, presionar for pulsar, configuración for settings, Enter for the Intro key, control for a gamepad, resorte for a spring) and reads `es.toml`, then English, for the rest (a regional catalog overlays its language's); same tú register as Spanish; a draft awaiting native review. Preferences ▸ Language lists Español (Latinoamérica); System maps es-419, es-MX, es-AR, es-CO and the other Latin American and US Spanish tags to it, es-ES and es to Spanish. Focus item 4 no longer lists Latin American Spanish | | 2026-10-12 | minor | M5: prototyping tail: controller buttons on key/gamepad triggers (Windows and the browser), widgets reacting in prototypes, `proto.evaluate`; M5's tail 3–6 h → 2–5 h | | 2026-10-12 | minor | M11: a plugin directory on `figcraft-server` (bundles published with the server key and checked in full, browsed and installed from Plugins ▸ Manage plugins after a permissions confirmation, hash-checked downloads, updates by version, `plugin.directory.*`, `figcraft-cli plugin publish`); 10–30 h → 8–26 h | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 0a93dae..cec53df 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1,6 +1,6 @@ # FigCraft parity with Figma -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%; last major: full re-measure against Figma desktop 126.10.7) · **Target:** Figma Design (desktop app 126.10.7, macOS) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%; last major: full re-measure against Figma desktop 126.10.7) · **Target:** Figma Design (desktop app 126.10.7, macOS) The authoritative assessment of how close FigCraft is to Figma Design. [`ROADMAP.md`](../ROADMAP.md) summarizes it; [`gaps.md`](gaps.md) is the ranked work list; the measured menu checklist is @@ -21,7 +21,7 @@ summarizes it; [`gaps.md`](gaps.md) is the ranked work list; the measured menu c | Essentials user | **~57%** | estimated ([below](#essentials-user): core features 77.8% × discounts 0.92 × 0.92 × 0.88) | | Mainstream practitioner | **~49%** | estimated ([below](#mainstream-practitioner): weekly areas 72.6% × discounts 0.9 × 0.9 × 0.85) | | Remaining to beta | **~155–280 h** one Opus 5.5 agent (~32–64 h wall-clock with 5 parallel agents) | estimated | -| Remaining to full parity | **~264–522 h** one agent (~83–145 h wall-clock with 5 parallel agents) | estimated | +| Remaining to full parity | **~262–519 h** one agent (~83–145 h wall-clock with 5 parallel agents) | estimated | | Stage | **alpha**: the alpha gate passes ([roadmap](roadmap.md#alpha-gate)); multiplayer and checking the best-effort `.fig` import on real files are beta gaps (see [ROADMAP](../ROADMAP.md#stage)) | | The previous figures (ROADMAP of 2026-10-10, "feature depth ~79%", "full parity 115–195 h") were @@ -35,7 +35,7 @@ tool; presence was being graded as behaviour in places. | Audience | Ready % | Opus 5.5 agent wall-clock hours to ~95% | Work that dominates | |---|---|---|---| -| Full target (ready for real work) | ~53% | ~270–525 h | multiplayer (42–84), localization (31–54), plugins (8–26), the interaction pass (40–60), GPU canvas (30–60), AI (30–60), the `.fig` import's tail (5–10) | +| Full target (ready for real work) | ~53% | ~268–522 h | multiplayer (42–84), localization (29–51), plugins (8–26), the interaction pass (40–60), GPU canvas (30–60), AI (30–60), the `.fig` import's tail (5–10) | | Mainstream practitioner | ~49% | ~130–244 h | core editor depth incl. the `.fig` import's tail (49–98), the interaction pass (40–60), real-file corpus and platform QA (25–50), `.fig` export for handing work back (15–30) | | Essentials user | ~57% | ~60–110 h | the `.fig` import's tail so the files people send open well (5–10), core tool polish (25–45), interaction pass on the core tools (15–25), stability QA (10–20), onboarding and starter templates (5–10) | @@ -129,11 +129,11 @@ Breadth: does it exist. Ready: depth, correctness and fidelity for real projects | Stability | 8 | 55% | 20–40 | Never-crash lints, command guard with rollback, recovery copies, 963 tests incl. junk-parameter sweeps and a seeded retained-render walk; but two days old, one release (v0.2.0), no field reports, QA mostly on macOS | [gaps](gaps.md) | | Performance | 6 | 60% | 30–60 | `cargo xtask bench`: 50k-layer page ~8 ms zoomed out, 10k-layer edits ~0.2 ms, 2,000-instance design system edits 4–64 ms; CPU (tiny-skia) canvas where Figma renders on the GPU; nothing timed against Figma on the same file | [hardware-parity](hardware-parity.md) | | Hardware | 3 | 60% | 10–21 | Trackpad pinch and HiDPI yes; pen pressure on Windows and from browser styluses (none from macOS/Linux tablets); several windows (screen-reader tree in the main one only); no GPU canvas, no P3 on screen | [hardware-parity](hardware-parity.md) | -| Localization | 3 | 36% | 31–54 | The layer, an English catalog and complete machine drafts of Spanish (with a Latin American overlay), French, German, Brazilian Portuguese, Japanese and Korean (none reviewed by a native speaker), CJK UI text in installed faces loaded on demand (web: only the craft-fonts CJK build); engine messages stay English | [localization-parity](localization-parity.md) | +| Localization | 3 | 39% | 29–51 | The layer, an English catalog and machine drafts of Spanish (with a Latin American overlay), French, German, Brazilian Portuguese, Japanese, Korean and Simplified Chinese (none reviewed by a native speaker; five lack the 25 newest strings), CJK UI text in installed faces loaded on demand (web: only the craft-fonts CJK build); engine messages stay English | [localization-parity](localization-parity.md) | | Platforms | 3 | 75% | 10–20 | macOS, Windows (x64/x86/arm64), Linux, FreeBSD, web all packaged (v0.2.0); Figma also has iOS/Android apps; non-macOS QA thin | [hardware-parity](hardware-parity.md) | | Ecosystem/plugins | 3 | 38% | 8–26 | Own WASM plugins with a Rust SDK and three examples (#101), plugin panels and settings (ABI v2), widgets that take clicks (API 3), a self-hosted plugin directory on `figcraft-server`; no Figma plugin compatibility, no public catalogue or community files; the CLI, control channel and MCP server are ahead of Figma for agents | [gaps](gaps.md) | | AI features | 2 | 0% | 30–60 | None | [gaps](gaps.md) | -| **Ready for real work** | 100 | **~53%** | **~264–522** | | | +| **Ready for real work** | 100 | **~53%** | **~262–519** | | | Dimension hours add up to the full-parity total without double counting: the feature-area rows for import/export (14), multiplayer and team libraries (17, 19), plugins (18) and AI (21) are @@ -619,6 +619,7 @@ Carried over from the ROADMAP's "Shipped so far" (2026-10-10). The test count th | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Simplified Chinese draft catalog (gap 5): `zh-Hans.toml` translates every UI string (1,371 keys; plurals give only `other`, and `plural_one` never picks "one"), command label (524) and menu wording (29), machine-drafted in a concise UI style with full-width punctuation and marked as a draft awaiting native review; Preferences ▸ Language lists 简体中文, System maps zh, zh-CN, zh-SG and zh-Hans to it, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and stays English (or the next OS language), never Simplified. A Chinese UI draws Han in a Chinese face first (Microsoft YaHei, PingFang SC, Noto Sans CJK SC), ahead of the craft-fonts build's Japanese BIZ UDPGothic, and changing the UI language lays the CJK faces out again (switching from Japanese to Chinese no longer keeps the Japanese face in front). String counts re-measured: 1,371 UI keys, 524 command labels and 29 menu wordings (1,924 entries); the French, German, Brazilian Portuguese, Japanese and Korean drafts have 1,899 of them (the 25 newer strings read English). Localization 36% → 39%, 31–54 h → 29–51 h; ready for real work unchanged (~53%); full parity ~267–527 h → ~265–524 h | | 2026-10-12 | minor | Latin American Spanish overlay (gap 5): `es-419.toml` lists only the 87 entries (61 UI strings, 26 command labels) whose wording differs in Latin American usage (agregar for añadir, presionar for pulsar, configuración for settings, Enter for the Intro key, control for a gamepad, resorte for a spring) and reads `es.toml`, then English, for the rest (a regional catalog overlays its language's); same tú register as Spanish; a draft awaiting native review. Preferences ▸ Language lists Español (Latinoamérica); System maps es-419, es-MX, es-AR, es-CO and the other Latin American and US Spanish tags to it, es-ES and es to Spanish. Localization 35% → 36%, 32–55 h → 31–54 h; ready for real work unchanged (~53%); full parity ~268–528 h → ~267–527 h | | 2026-10-12 | minor | Prototyping tail (gap 15, the part that doesn't need video): key/gamepad triggers take controller buttons (`Gamepad A` … `Gamepad Home`, the standard layout's 17 buttons, from a Controller menu beside the key field; the REST import maps controller triggers instead of skipping them); the player reads controllers on Windows (Windows.Gaming.Input through the `windows` crate the app already used; no new dependency) and in the browser (the Gamepad API), polling only while the prototype has such a trigger and the window has the focus, and the control channel presses buttons (`ui.input {gamepad}`); macOS, Linux and FreeBSD read no controllers yet. Widgets react to clicks in a presented prototype (the canvas's callback and sandbox limits, on the prototype's copy: the file and its history don't change, restarting starts over). `proto.evaluate` computes an expression where a layer's interaction would run (MCP); the mode lookup and set-variable-mode rules are cases in a behaviour suite (they already held). Prototyping breadth 90% → 92%, ready unchanged at 74%, 3–6 h → 2–5 h; area hours 120–260 → 119–259 (core 33–75 → 32–74), Features (depth) 29–68 h → 28–67 h; percentages unchanged at this rounding; full parity ~276–538 h → ~275–537 h | | 2026-10-12 | minor | Plugin directory on `figcraft-server` (gap 6): the server keeps plugin bundles (manifest, module, up to 32 assets; an uncompressed length-prefixed format named by its SHA-256) published with the server key (`figcraft-cli plugin publish`, `plugin.directory.publish`), checked in full before they are kept (size cap, manifest and plugin API version, a version newer than the one kept, the module compiled but never run, plain asset names) and capped (`max_plugins`, `max_plugin_mb`, `max_plugins_mb`); anyone who reaches the server lists, searches and fetches them (hash-checked again on read, a shared download budget); the operator moderates with `figcraft-server plugins [remove]`. The app's Plugins ▸ Manage plugins gains a Browse tab: a server's plugins with Install / Update / Remove, an install confirmation that shows the permissions asked for, the source and the SHA-256, the download checked against the listed hash before anything is read, plugins kept per user in hash-named folders; `plugin.directory.list` / `install` (needs `confirm: true`) / `publish` / `unpublish` for scripts and MCP. Not in the browser build yet; no public catalogue, publisher accounts, signatures, ratings or background update checks. Plugins & widgets 55%/32% → 60%/35%, 10–30 h → 8–26 h; Ecosystem dimension 34% → 38%; weighted totals unchanged at this rounding; full parity ~281–548 h → ~279–544 h | diff --git a/docs/translating.md b/docs/translating.md index e679824..b7c26a4 100644 --- a/docs/translating.md +++ b/docs/translating.md @@ -7,11 +7,14 @@ and the interface switches at once. System takes the first of the OS's preferred a catalog (the browser's language on the web): a regional tag reads its language's catalog (`fr-CA` → `fr`), a language with only a regional catalog reads that one (`pt-PT` → `pt-BR`), and Latin American and US Spanish (`es-MX`, `es-AR`, `es-CO`, `es-US`, `es-419`…) read `es-419`. +Chinese (`zh`, `zh-CN`, `zh-SG`, `zh-Hans`) reads `zh-Hans`; Traditional Chinese (`zh-Hant`, +`zh-TW`, `zh-HK`, `zh-MO`) has no catalog and reads English (or the next OS language), not +Simplified. `pref.language {language}` does the same from the CLI, MCP and the control channel. The catalogs: English (`en`, the source), and Spanish (`es`, with the Latin American overlay -`es-419`), French (`fr`), German (`de`), Brazilian Portuguese (`pt-BR`), Japanese (`ja`) and Korean -(`ko`), machine-drafted and waiting for native speakers' review. +`es-419`), French (`fr`), German (`de`), Brazilian Portuguese (`pt-BR`), Japanese (`ja`), Korean (`ko`) +and Simplified Chinese (`zh-Hans`), machine-drafted and waiting for native speakers' review. ## The catalogs @@ -38,12 +41,15 @@ Portuguese uses Brazilian words (arquivo, salvar, tela, você), not European one Spanish overrides Spain's wording where it differs (agregar, presionar, configuración for settings, Enter for the key, control for a gamepad, resorte) and keeps Spanish's tú. Japanese is concise, without です/ます endings, with full-width ()「」:、。 where Japanese UI text has them; -Korean labels end without 합니다 (instructions in -세요). Neither has plural forms. +Korean labels end without 합니다 (instructions in -세요). Simplified Chinese is concise, with +full-width ():,、。“” in Chinese text and a space between Chinese and Latin words or numbers. +None of the three has plural forms. CJK text needs a CJK font, which egui and Inter lack: the desktop app adds an installed one when something on screen needs it (see `crates/ui-egui/src/cjk.rs`). The web build has no system fonts, -so Japanese and Korean appear there only in a build with craft-fonts and `FIGCRAFT_EMBED_CJK=1` -(Noto Sans CJK, +16 MB); otherwise they are left out of the picker. A new CJK or other non-Latin +so Japanese, Korean and Chinese appear there only in a build with craft-fonts and +`FIGCRAFT_EMBED_CJK=1` (Noto Sans CJK SC, +16 MB); otherwise they are left out of the picker. A +Chinese UI puts its Chinese face first so Han takes Simplified Chinese shapes. A new CJK or other non-Latin language also needs its script in `cjk::language`. ## Adding a language @@ -59,9 +65,8 @@ language also needs its script in `cjk::language`. 4. To require full coverage, add the code to `COMPLETE` in [`crates/ui-egui/src/i18n_tests.rs`](../crates/ui-egui/src/i18n_tests.rs). Every later PR that adds a string then has to translate it into each complete language, so only Spanish is there: - French, German, Brazilian Portuguese, Japanese and Korean are complete today but registered as - drafts, and a - string added later shows English in them until it is translated. To list what a draft lacks, + French, German, Brazilian Portuguese, Japanese, Korean and Simplified Chinese are registered as + drafts, and a string added later shows English in them until it is translated. To list what a draft lacks, add its code to `COMPLETE` locally and run the check. 5. Run the check and look at the panels in the app (longer words must fit the right panel):