diff --git a/crates/engine/src/prefs.rs b/crates/engine/src/prefs.rs index b21656ac..12b4e0e6 100644 --- a/crates/engine/src/prefs.rs +++ b/crates/engine/src/prefs.rs @@ -23,7 +23,13 @@ pub const PREFS_VERSION: u32 = 2; pub const PREFS_FILE: &str = "prefs.json"; /// Settings ▸ General ▸ Language: (label, `general.language` value). -pub const LANGUAGES: &[(&str, &str)] = &[("Match System", "system"), ("English", "en"), ("日本語", "ja")]; +pub const LANGUAGES: &[(&str, &str)] = &[ + ("Match System", "system"), + ("English", "en"), + ("日本語", "ja"), + ("简体中文", "zh-hans"), + ("繁體中文", "zh-hant"), +]; /// Settings ▸ Startup & Repair ▸ Window Graphics: (label, `startup.windowGraphics` value). pub const WINDOW_GRAPHICS: &[(&str, &str)] = &[("Automatic", "auto"), ("OpenGL (compatibility)", "gl")]; diff --git a/crates/engine/src/tests_settings.rs b/crates/engine/src/tests_settings.rs index 231fe878..52d3fab7 100644 --- a/crates/engine/src/tests_settings.rs +++ b/crates/engine/src/tests_settings.rs @@ -514,6 +514,17 @@ fn interface_language_is_validated_persisted_and_backward_compatible() { assert_eq!(s.prefs.general.language, "ja"); assert_eq!(store.read(PREFS_FILE).unwrap(), saved); } + // zh-hans is registered alongside en and ja: it is accepted, persisted and read back. + s.execute("prefs.set", json!({"key": "general.language", "value": "zh-hans"})).unwrap(); + let mut zh = Session { config: Some(store.clone()), ..Default::default() }; + zh.load_settings(); + assert_eq!(zh.prefs.general.language, "zh-hans"); + // zh-hant is the same: another language of the registered set, not an error. + s.execute("prefs.set", json!({"key": "general.language", "value": "zh-hant"})).unwrap(); + let mut zh_hant = Session { config: Some(store.clone()), ..Default::default() }; + zh_hant.load_settings(); + assert_eq!(zh_hant.prefs.general.language, "zh-hant"); + s.execute("prefs.set", json!({"key": "general.language", "value": "ja"})).unwrap(); let mut reloaded = Session { config: Some(store), ..Default::default() }; reloaded.load_settings(); assert_eq!(reloaded.prefs.general.language, "ja"); diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index adebb950..d173c19b 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -1,18 +1,43 @@ -//! Japanese menu labels for EffectCraft's own engine tree. Commands remain locale-independent. -//! A command plus its source label distinguishes parameterised entries (e.g. blend modes). -//! Empty command keys identify submenus. Dynamic filenames, user names and effect plug-in names -//! remain verbatim; this catalog only translates the fixed menu tree. +//! Menu labels for EffectCraft's own engine tree in each translated language. Commands remain +//! locale-independent. A command plus its source label distinguishes parameterised entries (e.g. +//! blend modes). Empty command keys identify submenus. Dynamic filenames, user names and effect +//! plug-in names remain verbatim; these catalogs only translate the fixed menu tree. use crate::EffectcraftApp; use effectcraft_engine::menus::MenuEntry; -pub(crate) fn japanese(app: &EffectcraftApp) -> bool { +/// Every language with a catalog, in the order Settings ▸ General ▸ Language lists them. +const CATALOG_CODES: [&str; 3] = ["ja", "zh-hans", "zh-hant"]; + +/// The active interface language: the stored preference when it names a catalog, otherwise `en` +/// (English is the source of every label and needs no lookup). +pub(crate) fn language(app: &EffectcraftApp) -> &'static str { match app.session.prefs.general.language.as_str() { - "system" => system_language() == "ja", - l => l == "ja", + "system" => system_language(), + stored => code(stored), } } +/// `stored` as the language to show: a catalog's code, otherwise `en`. +fn code(stored: &str) -> &'static str { + CATALOG_CODES.iter().copied().find(|c| *c == stored).unwrap_or("en") +} + +/// The UI is in Japanese: the fast path for the menu builders. +pub(crate) fn japanese(app: &EffectcraftApp) -> bool { + language(app) == "ja" +} + +/// The UI is in Simplified Chinese. +pub(crate) fn simplified(app: &EffectcraftApp) -> bool { + language(app) == "zh-hans" +} + +/// The UI is in Traditional Chinese. +pub(crate) fn traditional(app: &EffectcraftApp) -> bool { + language(app) == "zh-hant" +} + /// Settings ▸ General ▸ Language ▸ Match System: the operating system's interface language /// where EffectCraft has it, else English (#229), as After Effects installs in the system's /// language. The browser build stays in English: it has no Japanese font of its own. @@ -27,25 +52,50 @@ fn system_language() -> &'static str { supported(None) } -/// The language EffectCraft shows for a BCP 47 locale (`ja-JP` → `ja`). +/// The language EffectCraft shows for a BCP 47 locale (`ja-JP` → `ja`, `zh-Hans-CN` → `zh-hans`, +/// `zh-TW` → `zh-hant`). fn supported(locale: Option<&str>) -> &'static str { - match locale.and_then(|l| l.split(['-', '_']).next()) { - Some(l) if l.eq_ignore_ascii_case("ja") => "ja", + let Some(locale) = locale else { return "en" }; + let mut parts = locale.split(['-', '_']); + let primary = parts.next().unwrap_or_default().to_ascii_lowercase(); + let rest: Vec = parts.map(|p| p.to_ascii_lowercase()).collect(); + match primary.as_str() { + "ja" => "ja", + "zh" => { + let traditional = rest.iter().any(|p| p.starts_with("hant") || p.starts_with("tw") || p.starts_with("hk") || p.starts_with("mo")); + if traditional { "zh-hant" } else { "zh-hans" } + } _ => "en", } } pub(crate) fn label<'a>(app: &EffectcraftApp, command: &str, source: &'a str) -> &'a str { - if japanese(app) { JAPANESE.iter().find(|(id, en, _)| *id == command && *en == source).map(|(_, _, ja)| *ja).unwrap_or(source) } else { source } + match language(app) { + "ja" => lookup(JAPANESE, command, source), + "zh-hans" => lookup(SIMPLIFIED_CHINESE, command, source), + "zh-hant" => lookup(TRADITIONAL_CHINESE, command, source), + _ => source, + } +} + +/// `source` looked up in `catalog` by (command, English label); the source itself when the pair is +/// absent, so computed labels and user names stay verbatim. +fn lookup<'a>(catalog: &[(&str, &str, &'a str)], command: &str, source: &'a str) -> &'a str { + catalog.iter().find(|(id, en, _)| *id == command && *en == source).map(|(_, _, translated)| *translated).unwrap_or(source) } pub(crate) fn entry(app: &EffectcraftApp, e: &MenuEntry, shown: String) -> String { - if !japanese(app) { - return shown; - } + // Undo/redo names come from the history, so they are formatted per language here rather than + // looked up in a catalog. An English (or untranslated) interface keeps the shown label. + let (undo, no_undo, redo, no_redo) = match language(app) { + "ja" => ("取り消し", "取り消しできません", "やり直し", "やり直しできません"), + "zh-hans" => ("撤销", "无可撤销的操作", "重做", "无可重做的操作"), + "zh-hant" => ("復原", "沒有可復原的操作", "重做", "沒有可重做的操作"), + _ => return shown, + }; match e.command.as_str() { - "edit.undo" => app.session.history.undo.last().map(|u| format!("取り消し {}", u.0)).unwrap_or_else(|| "取り消しできません".into()), - "edit.redo" => app.session.history.redo.last().map(|u| format!("やり直し {}", u.0)).unwrap_or_else(|| "やり直しできません".into()), + "edit.undo" => app.session.history.undo.last().map(|u| format!("{undo} {}", u.0)).unwrap_or_else(|| no_undo.into()), + "edit.redo" => app.session.history.redo.last().map(|u| format!("{redo} {}", u.0)).unwrap_or_else(|| no_redo.into()), "window.panel" => { let prefix = format!("{}: ", e.label); if let Some(name) = shown.strip_prefix(&prefix) { @@ -62,20 +112,1294 @@ pub(crate) fn entry(app: &EffectcraftApp, e: &MenuEntry, shown: String) -> Strin } pub(crate) fn submenu(app: &EffectcraftApp, source: &str, shown: String) -> String { - if japanese(app) { - if source == "Assign Shortcut to Workspace" { - if let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix("” Workspace")) { - return format!("ワークスペース「{name}」にショートカットを割り当て"); + match language(app) { + "ja" => { + if source == "Assign Shortcut to Workspace" { + if let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix("” Workspace")) { + return format!("ワークスペース「{name}」にショートカットを割り当て"); + } + } else if source == "Assign Shortcut to 3D View" + && let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix('”')) + { + return format!("「{name}」にショートカットを割り当て"); } - } else if source == "Assign Shortcut to 3D View" - && let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix('”')) - { - return format!("「{name}」にショートカットを割り当て"); } + "zh-hans" => { + if source == "Assign Shortcut to Workspace" { + if let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix("” Workspace")) { + return format!("为工作区“{name}”指定快捷键"); + } + } else if source == "Assign Shortcut to 3D View" + && let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix('”')) + { + return format!("为 3D 视图“{name}”指定快捷键"); + } + } + "zh-hant" => { + if source == "Assign Shortcut to Workspace" { + if let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix("” Workspace")) { + return format!("為工作區“{name}”指定快速鍵"); + } + } else if source == "Assign Shortcut to 3D View" + && let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix('”')) + { + return format!("為 3D 檢視“{name}”指定快速鍵"); + } + } + _ => {} } label(app, "", &shown).into() } +/// Simplified Chinese (zh-hans): the same (command, English label) keys as `JAPANESE`, one +/// entry per fixed menu row of the engine's menu tree. The wording follows Adobe's Simplified +/// Chinese After Effects documentation and the catalogs the sibling Craft apps ship; see the +/// pull request for the rows taken from #321. +const SIMPLIFIED_CHINESE: &[(&str, &str, &str)] = &[ + ("", "EffectCraft", "EffectCraft"), + ("app.about", "About EffectCraft...", "关于 EffectCraft..."), + ("", "Settings...", "设置..."), + ("app.settings", "General...", "常规..."), + ("app.settings", "Startup & Repair...", "启动和修复..."), + ("app.settings", "Project...", "项目..."), + ("app.settings", "Composition...", "合成..."), + ("app.settings", "Previews...", "预览..."), + ("app.settings", "Appearance...", "外观..."), + ("app.settings", "Grids & Guides...", "网格和参考线..."), + ("app.settings", "Labels...", "标签..."), + ("app.settings", "Type...", "文字..."), + ("app.settings", "Import...", "导入..."), + ("app.settings", "Export...", "导出..."), + ("app.settings", "Audio...", "音频..."), + ("app.settings", "Disk...", "磁盘..."), + ("app.settings", "Memory & CPU...", "内存和 CPU..."), + ("app.settings", "Video...", "视频..."), + ("app.settings", "3D...", "3D..."), + ("app.settings", "Scripting & Expressions...", "脚本和表达式..."), + ("app.hide", "Hide EffectCraft", "隐藏 EffectCraft"), + ("app.hideOthers", "Hide Others", "隐藏其他"), + ("app.showAll", "Show All", "全部显示"), + ("app.quit", "Quit EffectCraft", "退出 EffectCraft"), + ("", "File", "文件"), + ("", "New", "新建"), + ("file.newProject", "New Project", "新建项目"), + ("file.newFromTemplate", "New Project from Template...", "从模板新建项目..."), + ("project.newFolder", "New Folder", "新建文件夹"), + ("file.open", "Open Project...", "打开项目..."), + ("", "Open Recent", "打开最近文件"), + ("file.clearRecent", "Clear Recent Projects", "清除最近使用的项目"), + ("file.close", "Close", "关闭"), + ("file.closeProject", "Close Project", "关闭项目"), + ("file.save", "Save", "保存"), + ("", "Save As", "另存为"), + ("file.saveAs", "Save As...", "另存为..."), + ("file.saveCopy", "Save a Copy...", "保存副本..."), + ("file.saveCopyAsXml", "Save a Copy As XML...", "将副本另存为 XML..."), + ("templates.saveAs", "Save as Template...", "另存为模板..."), + ("file.incrementAndSave", "Increment and Save", "增量保存"), + ("file.revert", "Revert", "恢复"), + ("", "Import", "导入"), + ("file.import", "File...", "文件..."), + ("file.importMultiple", "Multiple Files...", "多个文件..."), + ("file.importTimeline", "Adobe Premiere Pro Project...", "Adobe Premiere Pro 项目..."), + ("file.importPlaceholder", "Placeholder...", "占位符..."), + ("file.importSolid", "Solid...", "纯色..."), + ("file.importLottie", "Lottie...", "Lottie..."), + ("file.importVanishingPoint", "Vanishing Point (.vpe)...", "消失点 (.vpe)..."), + ("essential.importTemplate", "Essential Graphics Template...", "动态图形模板..."), + ("", "Import Recent Footage", "导入最近使用的素材"), + ("file.clearRecentFootage", "Clear Recent Footage", "清除最近使用的素材"), + ("", "Export", "导出"), + ("renderQueue.add", "Add to Render Queue", "添加到渲染队列"), + ("file.exportTimeline", "Adobe Premiere Pro Project...", "Adobe Premiere Pro 项目..."), + ("file.exportLottie", "Lottie JSON...", "Lottie JSON..."), + ("essential.exportTemplate", "Essential Graphics Template...", "动态图形模板..."), + ("app.find", "Find", "查找"), + ("layer.addItem", "Add Footage to Comp", "将素材添加到合成"), + ("file.newCompFromSelection", "New Comp from Selection...", "从所选内容新建合成..."), + ("", "Dependencies", "依赖项"), + ("file.collectFiles", "Collect Files...", "收集文件..."), + ("file.consolidateFootage", "Consolidate All Footage", "整合所有素材"), + ("file.removeUnusedFootage", "Remove Unused Footage", "删除未使用的素材"), + ("file.reduceProject", "Reduce Project", "减少项目"), + ("file.findMissing", "Find Missing Effects", "查找缺失的效果"), + ("file.findMissing", "Find Missing Fonts", "查找缺失的字体"), + ("file.findMissing", "Find Missing Footage", "查找缺失的素材"), + ("file.watchFolder", "Watch Folder...", "监视文件夹..."), + ("", "Scripts", "脚本"), + ("file.installScript", "Install Script File...", "安装脚本文件..."), + ("file.installScriptUIPanel", "Install ScriptUI Panel...", "安装 ScriptUI 面板..."), + ("file.runScript", "Run Script File...", "运行脚本文件..."), + ("", "Create Proxy", "创建代理"), + ("file.createProxy", "Still...", "静止图像..."), + ("file.createProxy", "Movie...", "影片..."), + ("", "Set Proxy", "设置代理"), + ("file.setProxy", "File...", "文件..."), + ("file.setProxyNone", "None", "无"), + ("", "Interpret Footage", "解释素材"), + ("file.interpretFootage", "Main...", "主要..."), + ("file.interpretProxy", "Proxy...", "代理..."), + ("file.rememberInterpretation", "Remember Interpretation", "记住解释"), + ("file.applyInterpretation", "Apply Interpretation", "应用解释"), + ("", "Replace Footage", "替换素材"), + ("file.replaceFootage", "File...", "文件..."), + ("file.replaceWithPlaceholder", "Placeholder...", "占位符..."), + ("file.replaceWithSolid", "Solid...", "纯色..."), + ("file.replaceWithLayeredComp", "With Layered Comp", "使用分层合成"), + ("file.reloadFootage", "Reload Footage", "重新加载素材"), + ("file.revealInFinder", "Reveal in Finder", "在 Finder 中显示"), + ("file.projectSettings", "Project Settings...", "项目设置..."), + ("app.quit", "Exit", "退出"), + ("", "Edit", "编辑"), + ("edit.undo", "Undo", "撤销"), + ("edit.redo", "Redo", "重做"), + ("", "History", "历史记录"), + ("app.commandPalette", "Quick Apply...", "快速应用..."), + ("edit.cut", "Cut", "剪切"), + ("edit.copy", "Copy", "复制"), + ("edit.copyWithPropertyLinks", "Copy with Property Links", "复制属性链接"), + ("edit.copyWithRelativePropertyLinks", "Copy with Relative Property Links", "复制相对属性链接"), + ("edit.copyExpressionOnly", "Copy Expression Only", "仅复制表达式"), + ("edit.paste", "Paste", "粘贴"), + ("edit.pasteReversedKeyframes", "Paste Reversed Keyframes", "粘贴反转关键帧"), + ("edit.pasteTextMatchFormatting", "Paste Text and Match Formatting", "粘贴文本并匹配格式"), + ("edit.pasteTextFormattingOnly", "Paste Text Formatting Only", "仅粘贴文本格式"), + ("edit.clear", "Clear", "清除"), + ("edit.duplicate", "Duplicate", "重复"), + ("edit.splitLayer", "Split Layer", "拆分图层"), + ("edit.liftWorkArea", "Lift Work Area", "提升工作区域"), + ("edit.extractWorkArea", "Extract Work Area", "提取工作区域"), + ("edit.selectAll", "Select All", "全选"), + ("edit.deselectAll", "Deselect All", "取消全部选择"), + ("", "Label", "标签"), + ("edit.selectLabelGroup", "Select Label Group", "选择标签组"), + ("edit.label", "None", "无"), + ("edit.label", "Red", "红色"), + ("edit.label", "Yellow", "黄色"), + ("edit.label", "Aqua", "浅绿色"), + ("edit.label", "Pink", "粉色"), + ("edit.label", "Lavender", "淡紫色"), + ("edit.label", "Peach", "桃红色"), + ("edit.label", "Sea Foam", "海泡沫"), + ("edit.label", "Blue", "蓝色"), + ("edit.label", "Green", "绿色"), + ("edit.label", "Purple", "紫色"), + ("edit.label", "Orange", "橙色"), + ("edit.label", "Brown", "棕色"), + ("edit.label", "Fuchsia", "紫红色"), + ("edit.label", "Cyan", "青色"), + ("edit.label", "Sandstone", "砂岩"), + ("edit.label", "Dark Green", "深绿色"), + ("app.settings", "Edit Label Colors...", "编辑标签颜色..."), + ("", "Select Keyframe Label Group", "选择关键帧标签组"), + ("keys.selectLabelGroup", "On Selected Layers", "在选定的图层上"), + ("keys.selectLabelGroup", "On All Layers", "在所有图层上"), + ("keys.selectLabelGroup", "Visible Keyframes on Selected Layers", "选定图层上的可见关键帧"), + ("keys.selectLabelGroup", "Visible Keyframes on All Layers", "所有图层上的可见关键帧"), + ("", "Purge", "清理"), + ("edit.purge", "All Cache...", "所有缓存..."), + ("edit.purge", "All Memory & Disk Cache...", "所有内存和磁盘缓存..."), + ("edit.purge", "All Memory", "所有内存"), + ("edit.purge", "All Disk Cache...", "所有磁盘缓存..."), + ("edit.purge", "All 3D Cache...", "所有 3D 缓存..."), + ("edit.purgeUndo", "Undo", "撤销"), + ("edit.purge", "Image Cache Memory", "图像缓存内存"), + ("edit.purge", "Snapshot", "快照"), + ("edit.editOriginal", "Edit Original...", "编辑原稿..."), + ("", "Templates", "模板"), + ("app.templates", "Render Settings...", "渲染设置..."), + ("app.templates", "Output Module...", "输出模块..."), + ("app.keyboardShortcuts", "Keyboard Shortcuts", "键盘快捷键"), + ("", "Preferences", "首选项"), + ("", "Composition", "合成"), + ("comp.new", "New Composition...", "新建合成..."), + ("comp.settings", "Composition Settings...", "合成设置..."), + ("comp.setPosterTime", "Set Poster Time", "设置海报时间"), + ("comp.trimToWorkArea", "Trim Comp to Work Area", "将合成修剪到工作区域"), + ("comp.cropToRegionOfInterest", "Crop Comp to Region of Interest", "将合成裁剪到目标区域"), + ("comp.cropToLayerBounds", "Crop Comp to Selected Layer(s) Bounds", "将合成裁剪到所选图层(单个或多个)的边界"), + ("render.addOutputModule", "Add Output Module", "添加输出模块"), + ("", "Preview", "预览"), + ("playback.toggle", "Play Current Preview", "播放当前预览"), + ("playback.cacheWhenIdle", "Cache Frames When Idle", "空闲时缓存帧"), + ("playback.audio", "Audio", "音频"), + ("", "Save Frame As", "将帧另存为"), + ("comp.saveFrameAs", "File...", "文件..."), + ("comp.saveFrameAsPsd", "Photoshop Layers...", "Photoshop 图层..."), + ("comp.saveFrameAsExr", "ProEXR...", "ProEXR..."), + ("render.preRender", "Pre-render...", "预渲染..."), + ("render.saveCurrentPreview", "Save Current Preview...", "保存当前预览..."), + ("comp.openInEssentialGraphics", "Open in Essential Graphics", "在基本图形中打开"), + ("", "Responsive Design — Time", "响应式设计 — 时间"), + ("comp.responsiveTime", "Create Intro", "创建片头"), + ("comp.responsiveTime", "Create Outro", "创建片尾"), + ("comp.responsiveTime", "Create Protected Region from Work Area", "从工作区域创建受保护区域"), + ("comp.flowchart", "Composition Flowchart", "合成流程图"), + ("comp.miniFlowchart", "Composition Mini-Flowchart", "合成微型流程图"), + ("", "VR", "VR"), + ("comp.vr.createEnvironment", "Create VR Environment...", "创建 VR 环境..."), + ("comp.vr.extractCubemap", "Extract Cubemap...", "提取立方体贴图..."), + ("", "Layer", "图层"), + ("layer.newText", "Text", "文本"), + ("layer.newSolid", "Solid...", "纯色..."), + ("layer.newLight", "Light...", "灯光..."), + ("layer.newCamera", "Camera...", "摄像机..."), + ("layer.newNull", "Null Object", "空对象"), + ("layer.newShape", "Shape Layer", "形状图层"), + ("layer.newAdjustment", "Adjustment Layer", "调整图层"), + ("layer.newContentAwareFill", "Content-Aware Fill Layer...", "内容识别填充图层..."), + ("layer.new3dPrimitive", "Cube", "立方体"), + ("layer.new3dPrimitive", "Sphere", "球体"), + ("layer.new3dPrimitive", "Plane", "平面"), + ("layer.new3dPrimitive", "Torus", "圆环"), + ("layer.new3dPrimitive", "Cone", "圆锥"), + ("layer.new3dPrimitive", "Cylinder", "圆柱"), + ("layer.settings", "Layer Settings...", "图层设置..."), + ("layer.openLayer", "Open Layer", "打开图层"), + ("layer.openSource", "Open Layer Source", "打开图层源"), + ("layer.revealInFinder", "Reveal in Finder", "在 Finder 中显示"), + ("", "Mask", "蒙版"), + ("layer.addMask", "New Mask", "新建蒙版"), + ("layer.mask.shape", "Mask Shape...", "蒙版形状..."), + ("layer.mask.set", "Mask Feather...", "蒙版羽化..."), + ("layer.mask.set", "Mask Opacity...", "蒙版不透明度..."), + ("layer.mask.set", "Mask Expansion...", "蒙版扩展..."), + ("layer.mask.reset", "Reset Mask", "重置蒙版"), + ("layer.mask.remove", "Remove Mask", "移除蒙版"), + ("layer.mask.removeAll", "Remove All Masks", "移除所有蒙版"), + ("track.mask", "Track Mask", "跟踪蒙版"), + ("", "Mode", "模式"), + ("layer.mask.mode", "None", "无"), + ("layer.mask.mode", "Add", "相加"), + ("layer.mask.mode", "Subtract", "相减"), + ("layer.mask.mode", "Intersect", "相交"), + ("layer.mask.mode", "Lighten", "变亮"), + ("layer.mask.mode", "Darken", "变暗"), + ("layer.mask.mode", "Difference", "差值"), + ("layer.mask.invert", "Inverted", "反转"), + ("layer.mask.lock", "Locked", "已锁定"), + ("", "Motion Blur", "运动模糊"), + ("layer.mask.motionBlur", "Same As Layer", "与图层相同"), + ("layer.mask.motionBlur", "On", "开"), + ("layer.mask.motionBlur", "Off", "关"), + ("", "Feather Falloff", "羽化衰减"), + ("layer.mask.featherFalloff", "Smooth", "平滑"), + ("layer.mask.featherFalloff", "Linear", "线性"), + ("layer.mask.unlockAll", "Unlock All Masks", "解锁所有蒙版"), + ("layer.mask.lockOthers", "Lock Other Masks", "锁定其他蒙版"), + ("layer.mask.hideLocked", "Hide Locked Masks", "隐藏锁定的蒙版"), + ("", "Mask and Shape Path", "蒙版和形状路径"), + ("path.rotoBezier", "RotoBezier", "RotoBezier"), + ("mask.setClosed", "Closed", "封闭"), + ("path.convertToBezier", "Convert To Bezier Path", "转换为贝塞尔路径"), + ("path.setFirstVertex", "Set First Vertex", "设置第一个顶点"), + ("path.freeTransform", "Free Transform Points", "自由变换点"), + ("", "Quality", "品质"), + ("layer.quality", "Best", "最佳"), + ("layer.quality", "Draft", "草图"), + ("layer.quality", "Wireframe", "线框"), + ("layer.sampling", "Bilinear", "双线性"), + ("layer.sampling", "Bicubic", "双立方"), + ("", "Switches", "开关"), + ("layer.hideOtherVideo", "Hide Other Video", "隐藏其他视频"), + ("layer.showAllVideo", "Show All Video", "显示所有视频"), + ("layer.unlockAll", "Unlock All Layers", "解锁所有图层"), + ("layer.expressions", "Enable Expressions", "启用表达式"), + ("layer.expressions", "Disable Expressions", "禁用表达式"), + ("layer.setSwitch", "Shy", "消隐"), + ("layer.setSwitch", "Lock", "锁定"), + ("layer.setSwitch", "Audio", "音频"), + ("layer.setSwitch", "Video", "视频"), + ("layer.setSwitch", "Solo", "独奏"), + ("layer.setSwitch", "Effect", "效果"), + ("layer.setSwitch", "Collapse", "折叠"), + ("layer.setSwitch", "Motion Blur", "运动模糊"), + ("layer.setSwitch", "Adjustment Layer", "调整图层"), + ("", "Transform", "变换"), + ("layer.transform", "Reset", "重置"), + ("layer.setTransform", "Anchor Point...", "锚点..."), + ("layer.setTransform", "Position...", "位置..."), + ("layer.setTransform", "Scale...", "缩放..."), + ("layer.setTransform", "Orientation...", "方向..."), + ("layer.setTransform", "Rotation...", "旋转..."), + ("layer.setTransform", "Opacity...", "不透明度..."), + ("layer.transform", "Flip Horizontal", "水平翻转"), + ("layer.transform", "Flip Vertical", "垂直翻转"), + ("layer.transform", "Center In View", "在视图中居中"), + ("layer.centerAnchor", "Center Anchor Point in Layer Content", "将锚点居中到图层内容"), + ("layer.transform", "Fit to Comp", "适合合成"), + ("layer.transform", "Fit to Comp Width", "适合合成宽度"), + ("layer.transform", "Fit to Comp Height", "适合合成高度"), + ("layer.autoOrient", "Auto-Orient...", "自动定向..."), + ("", "Time", "时间"), + ("layer.enableTimeRemap", "Enable Time Remapping", "启用时间重映射"), + ("layer.timeReverse", "Time-Reverse Layer", "时间反向图层"), + ("layer.timeStretch", "Time Stretch...", "时间伸缩..."), + ("layer.freezeFrame", "Freeze Frame", "冻结帧"), + ("layer.freezeOnLastFrame", "Freeze On Last Frame", "冻结在最后一帧"), + ("layer.alignVideoToData", "Align Video to Data", "将视频对齐到数据"), + ("", "Frame Blending", "帧混合"), + ("layer.frameBlending", "Off", "关"), + ("layer.frameBlending", "Frame Mix", "帧混合"), + ("layer.frameBlending", "Pixel Motion", "像素运动"), + ("layer.setSwitch", "3D Layer", "3D 图层"), + ("layer.setSwitch", "Guide Layer", "参考图层"), + ("layer.environment", "Environment Layer", "环境图层"), + ("", "Markers", "标记"), + ("layer.addMarker", "Add Marker", "添加标记"), + ("layer.updateMarkersFromSource", "Update Markers From Source", "从源更新标记"), + ("layer.markersLock", "Lock Markers", "锁定标记"), + ("layer.deleteAllMarkers", "Delete All Markers", "删除所有标记"), + ("layer.setSwitch", "Preserve Transparency", "保留透明度"), + ("", "Blending Mode", "混合模式"), + ("layer.setBlendMode", "Normal", "正常"), + ("layer.setBlendMode", "Dissolve", "溶解"), + ("layer.setBlendMode", "Dancing Dissolve", "动态抖动溶解"), + ("layer.setBlendMode", "Darken", "变暗"), + ("layer.setBlendMode", "Multiply", "相乘"), + ("layer.setBlendMode", "Color Burn", "颜色加深"), + ("layer.setBlendMode", "Classic Color Burn", "经典颜色加深"), + ("layer.setBlendMode", "Linear Burn", "线性加深"), + ("layer.setBlendMode", "Darker Color", "深色"), + ("layer.setBlendMode", "Add", "相加"), + ("layer.setBlendMode", "Lighten", "变亮"), + ("layer.setBlendMode", "Screen", "滤色"), + ("layer.setBlendMode", "Color Dodge", "颜色减淡"), + ("layer.setBlendMode", "Classic Color Dodge", "经典颜色减淡"), + ("layer.setBlendMode", "Linear Dodge", "线性减淡"), + ("layer.setBlendMode", "Lighter Color", "浅色"), + ("layer.setBlendMode", "Overlay", "叠加"), + ("layer.setBlendMode", "Soft Light", "柔光"), + ("layer.setBlendMode", "Hard Light", "强光"), + ("layer.setBlendMode", "Linear Light", "线性光"), + ("layer.setBlendMode", "Vivid Light", "亮光"), + ("layer.setBlendMode", "Pin Light", "点光"), + ("layer.setBlendMode", "Hard Mix", "实色混合"), + ("layer.setBlendMode", "Difference", "差值"), + ("layer.setBlendMode", "Classic Difference", "经典差值"), + ("layer.setBlendMode", "Exclusion", "排除"), + ("layer.setBlendMode", "Subtract", "相减"), + ("layer.setBlendMode", "Divide", "相除"), + ("layer.setBlendMode", "Hue", "色相"), + ("layer.setBlendMode", "Saturation", "饱和度"), + ("layer.setBlendMode", "Color", "颜色"), + ("layer.setBlendMode", "Luminosity", "明度"), + ("layer.setBlendMode", "Stencil Alpha", "模板 Alpha"), + ("layer.setBlendMode", "Stencil Luma", "模板亮度"), + ("layer.setBlendMode", "Silhouette Alpha", "轮廓 Alpha"), + ("layer.setBlendMode", "Silhouette Luma", "轮廓亮度"), + ("layer.setBlendMode", "Alpha Add", "Alpha 添加"), + ("layer.setBlendMode", "Luminescent Premul", "冷光预乘"), + ("layer.setBlendMode", "Next Blending Mode", "下一个混合模式"), + ("layer.setBlendMode", "Previous Blending Mode", "上一个混合模式"), + ("", "Track Matte", "轨道遮罩"), + ("layer.trackMatte", "No Track Matte", "无轨道遮罩"), + ("layer.trackMatte", "Alpha Matte", "Alpha 遮罩"), + ("layer.trackMatte", "Alpha Inverted Matte", "Alpha 反转遮罩"), + ("layer.trackMatte", "Luma Matte", "亮度遮罩"), + ("layer.trackMatte", "Luma Inverted Matte", "亮度反转遮罩"), + ("layer.trackMatte", "Matte with Layer Above", "使用上方图层作为遮罩"), + ("layer.trackMatte", "Matte with Layer Below", "使用下方图层作为遮罩"), + ("", "Layer Styles", "图层样式"), + ("layer.style.options", "Layer Style Options...", "图层样式选项..."), + ("layer.style.convertToEditable", "Convert to Editable Styles", "转换为可编辑样式"), + ("layer.style.showAll", "Show All", "全部显示"), + ("layer.style.removeAll", "Remove All", "全部移除"), + ("layer.style.dropShadow", "Drop Shadow", "投影"), + ("layer.style.innerShadow", "Inner Shadow", "内阴影"), + ("layer.style.outerGlow", "Outer Glow", "外发光"), + ("layer.style.innerGlow", "Inner Glow", "内发光"), + ("layer.style.bevelEmboss", "Bevel and Emboss", "斜面和浮雕"), + ("layer.style.satin", "Satin", "光泽"), + ("layer.style.colorOverlay", "Color Overlay", "颜色叠加"), + ("layer.style.gradientOverlay", "Gradient Overlay", "渐变叠加"), + ("layer.style.stroke", "Stroke", "描边"), + ("path.groupShapes", "Group Shapes", "组合形状"), + ("path.ungroupShapes", "Ungroup Shapes", "取消组合形状"), + ("", "Arrange", "排列"), + ("layer.arrange", "Bring Layer to Front", "将图层置于顶层"), + ("layer.arrange", "Bring Layer Forward", "将图层前移一层"), + ("layer.arrange", "Send Layer Backward", "将图层后移一层"), + ("layer.arrange", "Send Layer to Back", "将图层置于底层"), + ("", "Reveal", "显示"), + ("layer.revealSource", "Reveal Layer Source in Project", "在项目中显示图层源"), + ("comp.flowchart", "Reveal Layer in Project Flowchart", "在项目流程图中显示图层"), + ("comp.revealInProject", "Reveal Composition in Project", "在项目中显示合成"), + ("layer.revealExpressionErrors", "Reveal Expression Errors", "显示表达式错误"), + ("", "Create", "创建"), + ("layer.create", "Convert to Editable Text", "转换为可编辑文本"), + ("layer.create", "Create Shapes from Text", "从文本创建形状"), + ("layer.create", "Create Masks from Text", "从文本创建蒙版"), + ("layer.create", "Create Shapes from Vector Layer", "从矢量图层创建形状"), + ("layer.create", "Create Keyframes from Data", "从数据创建关键帧"), + ("layer.create", "Null Controllers for Positional Points", "为位置点创建空对象控制器"), + ("layer.create", "Null Controllers for Path Points", "为路径点创建空对象控制器"), + ("layer.create", "Nulls Following Path Points", "跟随路径点的空对象"), + ("layer.create", "Null Tracing Along Path", "沿路径描边的空对象"), + ("layer.create", "Create 3D Layer Instance", "创建 3D 图层实例"), + ("", "Camera", "摄像机"), + ("camera.fromView", "Create Camera from 3D View", "从 3D 视图创建摄像机"), + ("camera.stereoRig", "Create Stereo 3D Rig", "创建立体 3D 装置"), + ("camera.orbitNull", "Create Orbit Null", "创建环绕空对象"), + ("camera.fromModel", "Create Cameras from 3D Model", "从 3D 模型创建摄像机"), + ("camera.linkFocusToPoi", "Link Focus Distance to Point of Interest", "将焦距链接到目标点"), + ("camera.linkFocusToLayer", "Link Focus Distance to Layer", "将焦距链接到图层"), + ("camera.setFocusToLayer", "Set Focus Distance to Layer", "将焦距设置为图层"), + ("layer.cameraSettings", "Camera Settings...", "摄像机设置..."), + ("view.reset3DView", "Reset 3D View", "重置 3D 视图"), + ("", "Light", "灯光"), + ("light.fromModel", "Create Lights from 3D Model", "从 3D 模型创建灯光"), + ("light.controlWithCamera", "Control Light with Camera", "用摄像机控制灯光"), + ("light.environmentBackground", "Create Environment Light Background Layer", "创建环境光背景图层"), + ("", "Material", "材质"), + ("material.revealSource", "Reveal Material Source in Project", "在项目中显示材质源"), + ("material.reset", "Reset Material", "重置材质"), + ("material.duplicateAssign", "Duplicate and Assign Material", "复制并指定材质"), + ("layer.autoTrace", "Auto-trace...", "自动追踪..."), + ("layer.precompose", "Pre-compose...", "预合成..."), + ("layer.sceneEditDetection", "Scene Edit Detection...", "场景编辑检测..."), + ("", "Effect", "效果"), + ("window.panel", "Effect Controls", "效果控件"), + ("effect.applyLast", "Last Effect", "上一个效果"), + ("effect.removeAll", "Remove All", "全部移除"), + ("effect.manage", "Manage Effects...", "管理效果..."), + ("effect.plugins.load", "Load Effect Plug-in...", "加载效果插件..."), + ("", "Animation", "动画"), + ("anim.savePreset", "Save Animation Preset...", "保存动画预设..."), + ("anim.applyPreset", "Apply Animation Preset...", "应用动画预设..."), + ("", "Recent Animation Presets", "最近的动画预设"), + ("anim.clearRecentPresets", "Clear Recent Presets", "清除最近的预设"), + ("anim.browsePresets", "Browse Presets...", "浏览预设..."), + ("", "Text Animation Presets", "文本动画预设"), + ("layer.applyTextPreset", "Typewriter", "打字机"), + ("layer.applyTextPreset", "Fade Up Characters", "字符淡入"), + ("layer.applyTextPreset", "Bounce In Words", "单词弹入"), + ("layer.applyTextPreset", "Tracking In", "字距进入"), + ("layer.applyTextPreset", "Scramble", "乱序"), + ("layer.applyTextPreset", "Blur In", "模糊进入"), + ("layer.applyTextPreset", "Jitter", "抖动"), + ("layer.applyTextPreset", "Drop In Lines", "行落下"), + ("anim.addKeyframe", "Add Keyframe", "添加关键帧"), + ("keys.toggleHold", "Toggle Hold Keyframe", "切换定格关键帧"), + ("keys.interpolation", "Keyframe Interpolation...", "关键帧插值..."), + ("keys.velocity", "Keyframe Velocity...", "关键帧速度..."), + ("", "Keyframe Assistant", "关键帧辅助"), + ("keys.audioToKeyframes", "Convert Audio to Keyframes", "将音频转换为关键帧"), + ("prop.convertExpressionToKeyframes", "Convert Expression to Keyframes", "将表达式转换为关键帧"), + ("keys.easyEase", "Easy Ease", "缓动"), + ("keys.easyEaseIn", "Easy Ease In", "缓入"), + ("keys.easyEaseOut", "Easy Ease Out", "缓出"), + ("keys.exponentialScale", "Exponential Scale", "指数比例"), + ("keys.rpfCameraImport", "RPF Camera Import", "RPF 摄像机导入"), + ("layer.sequence", "Sequence Layers...", "序列图层..."), + ("keys.timeReverse", "Time-Reverse Keyframes", "时间反向关键帧"), + ("", "Animate Text", "动画文字"), + ("layer.enablePerChar3D", "Enable Per-character 3D", "启用逐字符 3D"), + ("layer.addTextAnimator", "Anchor Point", "锚点"), + ("layer.addTextAnimator", "Position", "位置"), + ("layer.addTextAnimator", "Scale", "缩放"), + ("layer.addTextAnimator", "Skew", "倾斜"), + ("layer.addTextAnimator", "Rotation", "旋转"), + ("layer.addTextAnimator", "Opacity", "不透明度"), + ("layer.addTextAnimator", "All Transform Properties", "所有变换属性"), + ("", "Fill Color", "填充颜色"), + ("layer.addTextAnimator", "RGB", "RGB"), + ("layer.addTextAnimator", "Hue", "色相"), + ("layer.addTextAnimator", "Saturation", "饱和度"), + ("layer.addTextAnimator", "Brightness", "亮度"), + ("", "Stroke Color", "描边颜色"), + ("layer.addTextAnimator", "Stroke Width", "描边宽度"), + ("layer.addTextAnimator", "Tracking", "字符间距"), + ("layer.addTextAnimator", "Line Anchor", "行锚点"), + ("layer.addTextAnimator", "Line Spacing", "行距"), + ("layer.addTextAnimator", "Character Offset", "字符偏移"), + ("layer.addTextAnimator", "Character Value", "字符值"), + ("layer.addTextAnimator", "Blur", "模糊"), + ("text.animatorFontAxes", "Variable Font Axes", "可变字体轴"), + ("", "Add Text Selector", "添加文本选择器"), + ("text.addSelector", "Range", "范围"), + ("text.addSelector", "Wiggly", "摆动"), + ("text.addSelector", "Expression", "表达式"), + ("text.removeAllAnimators", "Remove All Text Animators", "移除所有文本动画制作器"), + ("prop.setExpression", "Add Expression", "添加表达式"), + ("essential.addProperty", "Add Property to Essential Graphics", "将属性添加到基本图形"), + ("prop.separateDimensions", "Separate Dimensions", "单独尺寸"), + ("track.camera", "Track Camera", "跟踪摄像机"), + ("track.warpStabilizer", "Warp Stabilizer VFX", "变形稳定器 VFX"), + ("track.motion", "Track Motion", "跟踪运动"), + ("track.stabilize", "Stabilize Motion", "稳定运动"), + ("track.property", "Track this Property", "跟踪此属性"), + ("anim.reveal", "Reveal Properties with Keyframes", "显示带关键帧的属性"), + ("anim.reveal", "Reveal Properties with Animation", "显示带动画的属性"), + ("anim.reveal", "Reveal All Modified Properties", "显示所有已修改的属性"), + ("", "View", "视图"), + ("view.newViewer", "New Viewer", "新建视图"), + ("view.splitLockedViewer", "Split with New Locked Viewer", "使用新的锁定视图拆分"), + ("view.zoomIn", "Zoom In", "放大"), + ("view.zoomOut", "Zoom Out", "缩小"), + ("", "Resolution", "分辨率"), + ("view.res.full", "Full", "完整"), + ("view.res.half", "Half", "二分之一"), + ("view.res.third", "Third", "三分之一"), + ("view.res.quarter", "Quarter", "四分之一"), + ("view.res.custom", "Custom...", "自定义..."), + ("view.displayColorManagement", "Use Display Color Management", "使用显示器色彩管理"), + ("", "Simulate Output", "模拟输出"), + ("view.simulateOutput", "No Output Simulation", "无输出模拟"), + ("view.simulateOutput", "HDTV (Rec. 709)", "HDTV (Rec. 709)"), + ("view.simulateOutput", "SDTV NTSC", "SDTV NTSC"), + ("view.simulateOutput", "SDTV PAL", "SDTV PAL"), + ("view.simulateOutput", "Legacy Macintosh RGB (Gamma 1.8)", "旧版 Macintosh RGB (灰度系数 1.8)"), + ("view.simulateOutput", "Internet Standard RGB (sRGB)", "Internet 标准 RGB (sRGB)"), + ("view.simulateOutput", "UHDTV (Rec. 2020)", "UHDTV (Rec. 2020)"), + ("view.simulateOutput", "Display P3", "Display P3"), + ("view.simulateOutput", "Linear (1.0 Gamma)", "线性 (1.0 Gamma)"), + ("view.customRgb", "My Custom RGB...", "我的自定义 RGB..."), + ("view.simulateOutput", "Custom...", "自定义..."), + ("view.rulers", "Show Rulers", "显示标尺"), + ("", "Panel Background Color", "面板背景颜色"), + ("view.panelBackground", "Black", "黑色"), + ("view.panelBackground", "Dark Gray", "深灰色"), + ("view.panelBackground", "Medium Gray (Default)", "中灰色 (默认)"), + ("view.panelBackground", "Light Gray", "浅灰色"), + ("view.panelBackground", "White", "白色"), + ("view.panelBackground", "Custom", "自定义"), + ("view.panelBackground", "Select Custom Background Color...", "选择自定义背景颜色..."), + ("view.guides", "Show Guides", "显示参考线"), + ("view.snapToGuides", "Snap to Guides", "对齐到参考线"), + ("view.lockGuides", "Lock Guides", "锁定参考线"), + ("view.addGuide", "Add Guide...", "添加参考线..."), + ("view.clearGuides", "Clear Guides", "清除参考线"), + ("view.importGuides", "Import Guides...", "导入参考线..."), + ("view.exportGuides", "Export Guides...", "导出参考线..."), + ("view.grid", "Show Grid", "显示网格"), + ("view.snapToGrid", "Snap to Grid", "对齐到网格"), + ("view.snapping", "Snapping", "对齐"), + ("view.options", "View Options...", "视图选项..."), + ("view.layerControls", "Show Layer Controls", "显示图层控件"), + ("", "Switch View Layout", "切换视图布局"), + ("view.layout", "1 View", "1 个视图"), + ("view.layout", "2 Views", "2 个视图"), + ("view.layout", "4 Views", "4 个视图"), + ("view.shareViewOptions", "Share View Options", "共享视图选项"), + ("", "Switch 3D View", "切换 3D 视图"), + ("view.3d.activeCamera", "Active Camera", "活动摄像机"), + ("view.3d.default", "Default", "默认"), + ("view.3d.front", "Front", "正面"), + ("view.3d.left", "Left", "左侧"), + ("view.3d.top", "Top", "顶部"), + ("view.3d.back", "Back", "背面"), + ("view.3d.right", "Right", "右侧"), + ("view.3d.bottom", "Bottom", "底部"), + ("view.3d.custom1", "Custom View 1", "自定义视图 1"), + ("view.3d.custom2", "Custom View 2", "自定义视图 2"), + ("view.3d.custom3", "Custom View 3", "自定义视图 3"), + ("", "Assign Shortcut to 3D View", "为 3D 视图指定快捷键"), + ("view.3d.last", "Switch to Last 3D View", "切换到上一个 3D 视图"), + ("view.lookAtSelected", "Look at Selected Layers", "查看选定图层"), + ("view.lookAtAll", "Look at All Layers", "查看所有图层"), + ("time.set", "Go to Time...", "转到时间..."), + ("view.fullScreen", "Enter Full Screen", "进入全屏"), + ("", "Window", "窗口"), + ("", "Workspace", "工作区"), + ("window.workspace", "Default", "默认"), + ("window.workspace", "Review", "审阅"), + ("window.workspace", "Learn", "学习"), + ("window.workspace", "Small Screen", "小屏幕"), + ("window.workspace", "Standard", "标准"), + ("window.workspace", "All Panels", "所有面板"), + ("window.workspace", "Animation", "动画"), + ("window.workspace", "Color", "颜色"), + ("window.workspace", "Effects", "效果"), + ("window.workspace", "Essential Graphics", "基本图形"), + ("window.workspace", "Minimal", "最小"), + ("window.workspace", "Motion Tracking", "运动跟踪"), + ("window.workspace", "Paint", "绘画"), + ("window.workspace", "Text", "文本"), + ("window.workspace", "Undocked Panels", "浮动面板"), + ("window.resetWorkspace", "Reset to Saved Layout", "重置为已保存的布局"), + ("window.saveWorkspace", "Save Changes to this Workspace", "将更改保存到此工作区"), + ("window.saveWorkspaceAs", "Save as New Workspace...", "另存为新工作区..."), + ("window.editWorkspaces", "Edit Workspaces...", "编辑工作区..."), + ("", "Assign Shortcut to Workspace", "为工作区指定快捷键"), + ("window.panel", "Align", "对齐"), + ("window.panel", "Audio", "音频"), + ("window.panel", "Brushes", "画笔"), + ("window.panel", "Character", "字符"), + ("window.panel", "Content-Aware Fill", "内容识别填充"), + ("window.panel", "Effects & Presets", "效果和预设"), + ("window.panel", "Essential Graphics", "基本图形"), + ("window.panel", "Info", "信息"), + ("help.inAppTutorials", "Learn", "学习"), + ("window.panel", "Lumetri Scopes", "Lumetri 示波器"), + ("window.panel", "Mask Interpolation", "蒙版插值"), + ("window.panel", "Media Browser", "媒体浏览器"), + ("window.panel", "Metadata", "元数据"), + ("window.panel", "Motion Sketch", "运动草图"), + ("window.panel", "Paint", "绘画"), + ("window.panel", "Paragraph", "段落"), + ("window.panel", "Preview", "预览"), + ("window.panel", "Progress", "进度"), + ("window.panel", "Properties", "属性"), + ("window.panel", "Script Console", "脚本控制台"), + ("window.panel", "Smoother", "平滑器"), + ("window.panel", "Tools", "工具"), + ("window.panel", "Tracker", "跟踪器"), + ("window.panel", "Wiggler", "摆动器"), + ("window.panel", "Composition", "合成"), + ("window.panel", "Flowchart", "流程图"), + ("window.panel", "Footage", "素材"), + ("window.panel", "Layer", "图层"), + ("window.panel", "Project", "项目"), + ("window.panel", "Render Queue", "渲染队列"), + ("window.panel", "Timeline", "时间轴"), + ("window.panel", "Create Nulls From Paths", "从路径创建空对象"), + ("window.panel", "Ease Presets", "缓动预设"), + ("window.panel", "VR Comp Editor", "VR 合成编辑器"), + ("", "Help", "帮助"), + ("help.docs", "EffectCraft Help...", "EffectCraft 帮助..."), + ("help.docs", "Scripting Help...", "脚本帮助..."), + ("help.docs", "Expression Reference...", "表达式参考..."), + ("help.docs", "Effect Reference...", "效果参考..."), + ("anim.browsePresets", "Animation Presets...", "动画预设..."), + ("app.keyboardShortcuts", "Keyboard Shortcuts...", "键盘快捷键..."), + ("help.inAppTutorials", "In-App Tutorials...", "应用内教程..."), + ("help.onlineTutorials", "Online Tutorials...", "在线教程..."), + ("help.systemReport", "System Compatibility Report...", "系统兼容性报告..."), + ("help.enableLogging", "Enable Logging", "启用日志记录"), + ("help.revealLogFile", "Reveal Logging File", "显示日志文件"), + ("help.discord", "Join the ArtCraft Discord...", "加入 ArtCraft 的 Discord 社区..."), + ("help.reportIssue", "Provide Feedback...", "提供反馈..."), + ("help.website", "ArtCraft Website", "ArtCraft 网站"), + ("help.appPage", "EffectCraft Home Page", "EffectCraft 主页"), + ("help.github", "EffectCraft on GitHub", "GitHub 上的 EffectCraft"), + ("file.openDemoProject", "Open Demo Project", "打开示例项目"), +]; + +/// Traditional Chinese (zh-hant): the same (command, English label) keys as `JAPANESE`, one +/// entry per fixed menu row of the engine's menu tree, mirroring `SIMPLIFIED_CHINESE` in the +/// vocabulary the sibling Craft apps' zh-hant catalogs use. +const TRADITIONAL_CHINESE: &[(&str, &str, &str)] = &[ + ("", "EffectCraft", "EffectCraft"), + ("app.about", "About EffectCraft...", "關於 EffectCraft..."), + ("", "Settings...", "設定..."), + ("app.settings", "General...", "一般..."), + ("app.settings", "Startup & Repair...", "啟動和修復..."), + ("app.settings", "Project...", "專案..."), + ("app.settings", "Composition...", "合成..."), + ("app.settings", "Previews...", "預覽..."), + ("app.settings", "Appearance...", "外觀..."), + ("app.settings", "Grids & Guides...", "格點和參考線..."), + ("app.settings", "Labels...", "標籤..."), + ("app.settings", "Type...", "文字..."), + ("app.settings", "Import...", "匯入..."), + ("app.settings", "Export...", "匯出..."), + ("app.settings", "Audio...", "音訊..."), + ("app.settings", "Disk...", "磁碟..."), + ("app.settings", "Memory & CPU...", "記憶體和 CPU..."), + ("app.settings", "Video...", "視訊..."), + ("app.settings", "3D...", "3D..."), + ("app.settings", "Scripting & Expressions...", "指令碼和運算式..."), + ("app.hide", "Hide EffectCraft", "隱藏 EffectCraft"), + ("app.hideOthers", "Hide Others", "隱藏其他"), + ("app.showAll", "Show All", "全部顯示"), + ("app.quit", "Quit EffectCraft", "結束 EffectCraft"), + ("", "File", "檔案"), + ("", "New", "新增"), + ("file.newProject", "New Project", "新增專案"), + ("file.newFromTemplate", "New Project from Template...", "從範本新增專案..."), + ("project.newFolder", "New Folder", "新增檔案夾"), + ("file.open", "Open Project...", "開啟專案..."), + ("", "Open Recent", "最近開啟的檔案"), + ("file.clearRecent", "Clear Recent Projects", "清除最近使用的專案"), + ("file.close", "Close", "關閉"), + ("file.closeProject", "Close Project", "關閉專案"), + ("file.save", "Save", "儲存"), + ("", "Save As", "另存新檔"), + ("file.saveAs", "Save As...", "另存新檔..."), + ("file.saveCopy", "Save a Copy...", "儲存拷貝..."), + ("file.saveCopyAsXml", "Save a Copy As XML...", "將拷貝另存為 XML..."), + ("templates.saveAs", "Save as Template...", "另存為範本..."), + ("file.incrementAndSave", "Increment and Save", "增量儲存"), + ("file.revert", "Revert", "回復"), + ("", "Import", "匯入"), + ("file.import", "File...", "檔案..."), + ("file.importMultiple", "Multiple Files...", "多個檔案..."), + ("file.importTimeline", "Adobe Premiere Pro Project...", "Adobe Premiere Pro 專案..."), + ("file.importPlaceholder", "Placeholder...", "預留位置..."), + ("file.importSolid", "Solid...", "純色..."), + ("file.importLottie", "Lottie...", "Lottie..."), + ("file.importVanishingPoint", "Vanishing Point (.vpe)...", "消失點 (.vpe)..."), + ("essential.importTemplate", "Essential Graphics Template...", "動態圖形範本..."), + ("", "Import Recent Footage", "匯入最近使用的素材"), + ("file.clearRecentFootage", "Clear Recent Footage", "清除最近使用的素材"), + ("", "Export", "匯出"), + ("renderQueue.add", "Add to Render Queue", "新增至渲染佇列"), + ("file.exportTimeline", "Adobe Premiere Pro Project...", "Adobe Premiere Pro 專案..."), + ("file.exportLottie", "Lottie JSON...", "Lottie JSON..."), + ("essential.exportTemplate", "Essential Graphics Template...", "動態圖形範本..."), + ("app.find", "Find", "尋找"), + ("layer.addItem", "Add Footage to Comp", "將素材新增至合成"), + ("file.newCompFromSelection", "New Comp from Selection...", "從選取範圍新增合成..."), + ("", "Dependencies", "相依性"), + ("file.collectFiles", "Collect Files...", "收集檔案..."), + ("file.consolidateFootage", "Consolidate All Footage", "整合所有素材"), + ("file.removeUnusedFootage", "Remove Unused Footage", "刪除未使用的素材"), + ("file.reduceProject", "Reduce Project", "減少專案"), + ("file.findMissing", "Find Missing Effects", "尋找遺失的效果"), + ("file.findMissing", "Find Missing Fonts", "尋找遺失的字體"), + ("file.findMissing", "Find Missing Footage", "尋找遺失的素材"), + ("file.watchFolder", "Watch Folder...", "監視檔案夾..."), + ("", "Scripts", "指令碼"), + ("file.installScript", "Install Script File...", "安裝指令碼檔案..."), + ("file.installScriptUIPanel", "Install ScriptUI Panel...", "安裝 ScriptUI 面板..."), + ("file.runScript", "Run Script File...", "執行指令碼檔案..."), + ("", "Create Proxy", "建立代理"), + ("file.createProxy", "Still...", "靜態影像..."), + ("file.createProxy", "Movie...", "影片..."), + ("", "Set Proxy", "設定代理"), + ("file.setProxy", "File...", "檔案..."), + ("file.setProxyNone", "None", "無"), + ("", "Interpret Footage", "解譯素材"), + ("file.interpretFootage", "Main...", "主要..."), + ("file.interpretProxy", "Proxy...", "代理..."), + ("file.rememberInterpretation", "Remember Interpretation", "記住解譯"), + ("file.applyInterpretation", "Apply Interpretation", "套用解譯"), + ("", "Replace Footage", "取代素材"), + ("file.replaceFootage", "File...", "檔案..."), + ("file.replaceWithPlaceholder", "Placeholder...", "預留位置..."), + ("file.replaceWithSolid", "Solid...", "純色..."), + ("file.replaceWithLayeredComp", "With Layered Comp", "使用分層合成"), + ("file.reloadFootage", "Reload Footage", "重新載入素材"), + ("file.revealInFinder", "Reveal in Finder", "在 Finder 中顯示"), + ("file.projectSettings", "Project Settings...", "專案設定..."), + ("app.quit", "Exit", "結束"), + ("", "Edit", "編輯"), + ("edit.undo", "Undo", "復原"), + ("edit.redo", "Redo", "重做"), + ("", "History", "步驟記錄"), + ("app.commandPalette", "Quick Apply...", "快速套用..."), + ("edit.cut", "Cut", "剪下"), + ("edit.copy", "Copy", "拷貝"), + ("edit.copyWithPropertyLinks", "Copy with Property Links", "拷貝屬性連結"), + ("edit.copyWithRelativePropertyLinks", "Copy with Relative Property Links", "拷貝相對屬性連結"), + ("edit.copyExpressionOnly", "Copy Expression Only", "僅拷貝運算式"), + ("edit.paste", "Paste", "貼上"), + ("edit.pasteReversedKeyframes", "Paste Reversed Keyframes", "貼上反轉關鍵影格"), + ("edit.pasteTextMatchFormatting", "Paste Text and Match Formatting", "貼上文字並符合格式"), + ("edit.pasteTextFormattingOnly", "Paste Text Formatting Only", "僅貼上文字格式"), + ("edit.clear", "Clear", "清除"), + ("edit.duplicate", "Duplicate", "重製"), + ("edit.splitLayer", "Split Layer", "分割圖層"), + ("edit.liftWorkArea", "Lift Work Area", "提起工作區域"), + ("edit.extractWorkArea", "Extract Work Area", "擷取工作區域"), + ("edit.selectAll", "Select All", "全選"), + ("edit.deselectAll", "Deselect All", "全部取消選取"), + ("", "Label", "標籤"), + ("edit.selectLabelGroup", "Select Label Group", "選取標籤群組"), + ("edit.label", "None", "無"), + ("edit.label", "Red", "紅色"), + ("edit.label", "Yellow", "黃色"), + ("edit.label", "Aqua", "淺綠色"), + ("edit.label", "Pink", "粉色"), + ("edit.label", "Lavender", "淡紫色"), + ("edit.label", "Peach", "桃紅色"), + ("edit.label", "Sea Foam", "海泡沫"), + ("edit.label", "Blue", "藍色"), + ("edit.label", "Green", "綠色"), + ("edit.label", "Purple", "紫色"), + ("edit.label", "Orange", "橙色"), + ("edit.label", "Brown", "棕色"), + ("edit.label", "Fuchsia", "紫紅色"), + ("edit.label", "Cyan", "青色"), + ("edit.label", "Sandstone", "砂岩"), + ("edit.label", "Dark Green", "深綠色"), + ("app.settings", "Edit Label Colors...", "編輯標籤顏色..."), + ("", "Select Keyframe Label Group", "選取關鍵影格標籤群組"), + ("keys.selectLabelGroup", "On Selected Layers", "在選取的圖層上"), + ("keys.selectLabelGroup", "On All Layers", "在所有圖層上"), + ("keys.selectLabelGroup", "Visible Keyframes on Selected Layers", "選取圖層上的可見關鍵影格"), + ("keys.selectLabelGroup", "Visible Keyframes on All Layers", "所有圖層上的可見關鍵影格"), + ("", "Purge", "清除記憶"), + ("edit.purge", "All Cache...", "所有快取..."), + ("edit.purge", "All Memory & Disk Cache...", "所有記憶體和磁碟快取..."), + ("edit.purge", "All Memory", "所有記憶體"), + ("edit.purge", "All Disk Cache...", "所有磁碟快取..."), + ("edit.purge", "All 3D Cache...", "所有 3D 快取..."), + ("edit.purgeUndo", "Undo", "復原"), + ("edit.purge", "Image Cache Memory", "影像快取記憶體"), + ("edit.purge", "Snapshot", "快照"), + ("edit.editOriginal", "Edit Original...", "編輯原稿..."), + ("", "Templates", "範本"), + ("app.templates", "Render Settings...", "渲染設定..."), + ("app.templates", "Output Module...", "輸出模組..."), + ("app.keyboardShortcuts", "Keyboard Shortcuts", "鍵盤快速鍵"), + ("", "Preferences", "偏好設定"), + ("", "Composition", "合成"), + ("comp.new", "New Composition...", "新增合成..."), + ("comp.settings", "Composition Settings...", "合成設定..."), + ("comp.setPosterTime", "Set Poster Time", "設定海報時間"), + ("comp.trimToWorkArea", "Trim Comp to Work Area", "將合成修剪至工作區域"), + ("comp.cropToRegionOfInterest", "Crop Comp to Region of Interest", "將合成裁切至目標區域"), + ("comp.cropToLayerBounds", "Crop Comp to Selected Layer(s) Bounds", "將合成裁切至所選圖層(單個或多個)的邊界"), + ("render.addOutputModule", "Add Output Module", "新增輸出模組"), + ("", "Preview", "預覽"), + ("playback.toggle", "Play Current Preview", "播放目前預覽"), + ("playback.cacheWhenIdle", "Cache Frames When Idle", "閒置時快取影格"), + ("playback.audio", "Audio", "音訊"), + ("", "Save Frame As", "將影格另存新檔"), + ("comp.saveFrameAs", "File...", "檔案..."), + ("comp.saveFrameAsPsd", "Photoshop Layers...", "Photoshop 圖層..."), + ("comp.saveFrameAsExr", "ProEXR...", "ProEXR..."), + ("render.preRender", "Pre-render...", "預先渲染..."), + ("render.saveCurrentPreview", "Save Current Preview...", "儲存目前預覽..."), + ("comp.openInEssentialGraphics", "Open in Essential Graphics", "在基本圖形中開啟"), + ("", "Responsive Design — Time", "回應式設計 — 時間"), + ("comp.responsiveTime", "Create Intro", "建立片頭"), + ("comp.responsiveTime", "Create Outro", "建立片尾"), + ("comp.responsiveTime", "Create Protected Region from Work Area", "從工作區域建立受保護區域"), + ("comp.flowchart", "Composition Flowchart", "合成流程圖"), + ("comp.miniFlowchart", "Composition Mini-Flowchart", "合成微型流程圖"), + ("", "VR", "VR"), + ("comp.vr.createEnvironment", "Create VR Environment...", "建立 VR 環境..."), + ("comp.vr.extractCubemap", "Extract Cubemap...", "擷取立方體貼圖..."), + ("", "Layer", "圖層"), + ("layer.newText", "Text", "文字"), + ("layer.newSolid", "Solid...", "純色..."), + ("layer.newLight", "Light...", "燈光..."), + ("layer.newCamera", "Camera...", "攝影機..."), + ("layer.newNull", "Null Object", "空物件"), + ("layer.newShape", "Shape Layer", "形狀圖層"), + ("layer.newAdjustment", "Adjustment Layer", "調整圖層"), + ("layer.newContentAwareFill", "Content-Aware Fill Layer...", "內容感知填滿圖層..."), + ("layer.new3dPrimitive", "Cube", "立方體"), + ("layer.new3dPrimitive", "Sphere", "球體"), + ("layer.new3dPrimitive", "Plane", "平面"), + ("layer.new3dPrimitive", "Torus", "圓環"), + ("layer.new3dPrimitive", "Cone", "圓錐"), + ("layer.new3dPrimitive", "Cylinder", "圓柱"), + ("layer.settings", "Layer Settings...", "圖層設定..."), + ("layer.openLayer", "Open Layer", "開啟圖層"), + ("layer.openSource", "Open Layer Source", "開啟圖層來源"), + ("layer.revealInFinder", "Reveal in Finder", "在 Finder 中顯示"), + ("", "Mask", "遮色片"), + ("layer.addMask", "New Mask", "新增遮色片"), + ("layer.mask.shape", "Mask Shape...", "遮色片形狀..."), + ("layer.mask.set", "Mask Feather...", "遮色片羽化..."), + ("layer.mask.set", "Mask Opacity...", "遮色片不透明度..."), + ("layer.mask.set", "Mask Expansion...", "遮色片擴充..."), + ("layer.mask.reset", "Reset Mask", "重設遮色片"), + ("layer.mask.remove", "Remove Mask", "移除遮色片"), + ("layer.mask.removeAll", "Remove All Masks", "移除所有遮色片"), + ("track.mask", "Track Mask", "追蹤遮色片"), + ("", "Mode", "模式"), + ("layer.mask.mode", "None", "無"), + ("layer.mask.mode", "Add", "相加"), + ("layer.mask.mode", "Subtract", "相減"), + ("layer.mask.mode", "Intersect", "交集"), + ("layer.mask.mode", "Lighten", "變亮"), + ("layer.mask.mode", "Darken", "變暗"), + ("layer.mask.mode", "Difference", "差異化"), + ("layer.mask.invert", "Inverted", "反轉"), + ("layer.mask.lock", "Locked", "已鎖定"), + ("", "Motion Blur", "動態模糊"), + ("layer.mask.motionBlur", "Same As Layer", "與圖層相同"), + ("layer.mask.motionBlur", "On", "開"), + ("layer.mask.motionBlur", "Off", "關"), + ("", "Feather Falloff", "羽化衰減"), + ("layer.mask.featherFalloff", "Smooth", "平滑"), + ("layer.mask.featherFalloff", "Linear", "線性"), + ("layer.mask.unlockAll", "Unlock All Masks", "解鎖所有遮色片"), + ("layer.mask.lockOthers", "Lock Other Masks", "鎖定其他遮色片"), + ("layer.mask.hideLocked", "Hide Locked Masks", "隱藏鎖定的遮色片"), + ("", "Mask and Shape Path", "遮色片和形狀路徑"), + ("path.rotoBezier", "RotoBezier", "RotoBezier"), + ("mask.setClosed", "Closed", "封閉"), + ("path.convertToBezier", "Convert To Bezier Path", "轉換為貝茲路徑"), + ("path.setFirstVertex", "Set First Vertex", "設定第一個頂點"), + ("path.freeTransform", "Free Transform Points", "自由變換點"), + ("", "Quality", "品質"), + ("layer.quality", "Best", "最佳"), + ("layer.quality", "Draft", "草圖"), + ("layer.quality", "Wireframe", "線框"), + ("layer.sampling", "Bilinear", "雙線性"), + ("layer.sampling", "Bicubic", "雙立方"), + ("", "Switches", "開關"), + ("layer.hideOtherVideo", "Hide Other Video", "隱藏其他視訊"), + ("layer.showAllVideo", "Show All Video", "顯示所有視訊"), + ("layer.unlockAll", "Unlock All Layers", "解除鎖定所有圖層"), + ("layer.expressions", "Enable Expressions", "啟用運算式"), + ("layer.expressions", "Disable Expressions", "停用運算式"), + ("layer.setSwitch", "Shy", "消隱"), + ("layer.setSwitch", "Lock", "鎖定"), + ("layer.setSwitch", "Audio", "音訊"), + ("layer.setSwitch", "Video", "視訊"), + ("layer.setSwitch", "Solo", "獨奏"), + ("layer.setSwitch", "Effect", "效果"), + ("layer.setSwitch", "Collapse", "收合"), + ("layer.setSwitch", "Motion Blur", "動態模糊"), + ("layer.setSwitch", "Adjustment Layer", "調整圖層"), + ("", "Transform", "變形"), + ("layer.transform", "Reset", "重設"), + ("layer.setTransform", "Anchor Point...", "錨點..."), + ("layer.setTransform", "Position...", "位置..."), + ("layer.setTransform", "Scale...", "縮放..."), + ("layer.setTransform", "Orientation...", "方向..."), + ("layer.setTransform", "Rotation...", "旋轉..."), + ("layer.setTransform", "Opacity...", "不透明度..."), + ("layer.transform", "Flip Horizontal", "水平翻轉"), + ("layer.transform", "Flip Vertical", "垂直翻轉"), + ("layer.transform", "Center In View", "置中於檢視"), + ("layer.centerAnchor", "Center Anchor Point in Layer Content", "將錨點置中於圖層內容"), + ("layer.transform", "Fit to Comp", "符合合成"), + ("layer.transform", "Fit to Comp Width", "符合合成寬度"), + ("layer.transform", "Fit to Comp Height", "符合合成高度"), + ("layer.autoOrient", "Auto-Orient...", "自動定向..."), + ("", "Time", "時間"), + ("layer.enableTimeRemap", "Enable Time Remapping", "啟用時間重新對應"), + ("layer.timeReverse", "Time-Reverse Layer", "時間反轉圖層"), + ("layer.timeStretch", "Time Stretch...", "時間伸縮..."), + ("layer.freezeFrame", "Freeze Frame", "凍結影格"), + ("layer.freezeOnLastFrame", "Freeze On Last Frame", "凍結於最後一個影格"), + ("layer.alignVideoToData", "Align Video to Data", "將視訊對齊至資料"), + ("", "Frame Blending", "影格混合"), + ("layer.frameBlending", "Off", "關"), + ("layer.frameBlending", "Frame Mix", "影格混合"), + ("layer.frameBlending", "Pixel Motion", "像素運動"), + ("layer.setSwitch", "3D Layer", "3D 圖層"), + ("layer.setSwitch", "Guide Layer", "參考圖層"), + ("layer.environment", "Environment Layer", "環境圖層"), + ("", "Markers", "標記"), + ("layer.addMarker", "Add Marker", "新增標記"), + ("layer.updateMarkersFromSource", "Update Markers From Source", "從來源更新標記"), + ("layer.markersLock", "Lock Markers", "鎖定標記"), + ("layer.deleteAllMarkers", "Delete All Markers", "刪除所有標記"), + ("layer.setSwitch", "Preserve Transparency", "保留透明度"), + ("", "Blending Mode", "混合模式"), + ("layer.setBlendMode", "Normal", "正常"), + ("layer.setBlendMode", "Dissolve", "溶解"), + ("layer.setBlendMode", "Dancing Dissolve", "動態抖動溶解"), + ("layer.setBlendMode", "Darken", "變暗"), + ("layer.setBlendMode", "Multiply", "相乘"), + ("layer.setBlendMode", "Color Burn", "加深顏色"), + ("layer.setBlendMode", "Classic Color Burn", "傳統加深顏色"), + ("layer.setBlendMode", "Linear Burn", "線性加深"), + ("layer.setBlendMode", "Darker Color", "顏色變暗"), + ("layer.setBlendMode", "Add", "相加"), + ("layer.setBlendMode", "Lighten", "變亮"), + ("layer.setBlendMode", "Screen", "濾色"), + ("layer.setBlendMode", "Color Dodge", "加亮顏色"), + ("layer.setBlendMode", "Classic Color Dodge", "傳統加亮顏色"), + ("layer.setBlendMode", "Linear Dodge", "線性加亮"), + ("layer.setBlendMode", "Lighter Color", "顏色變亮"), + ("layer.setBlendMode", "Overlay", "覆蓋"), + ("layer.setBlendMode", "Soft Light", "柔光"), + ("layer.setBlendMode", "Hard Light", "實光"), + ("layer.setBlendMode", "Linear Light", "線性光源"), + ("layer.setBlendMode", "Vivid Light", "強烈光源"), + ("layer.setBlendMode", "Pin Light", "小光源"), + ("layer.setBlendMode", "Hard Mix", "實色疊印混合"), + ("layer.setBlendMode", "Difference", "差異化"), + ("layer.setBlendMode", "Classic Difference", "傳統差異化"), + ("layer.setBlendMode", "Exclusion", "排除"), + ("layer.setBlendMode", "Subtract", "相減"), + ("layer.setBlendMode", "Divide", "相除"), + ("layer.setBlendMode", "Hue", "色相"), + ("layer.setBlendMode", "Saturation", "飽和度"), + ("layer.setBlendMode", "Color", "顏色"), + ("layer.setBlendMode", "Luminosity", "明度"), + ("layer.setBlendMode", "Stencil Alpha", "樣板 Alpha"), + ("layer.setBlendMode", "Stencil Luma", "樣板亮度"), + ("layer.setBlendMode", "Silhouette Alpha", "輪廓 Alpha"), + ("layer.setBlendMode", "Silhouette Luma", "輪廓亮度"), + ("layer.setBlendMode", "Alpha Add", "Alpha 增加"), + ("layer.setBlendMode", "Luminescent Premul", "冷光預乘"), + ("layer.setBlendMode", "Next Blending Mode", "下一個混合模式"), + ("layer.setBlendMode", "Previous Blending Mode", "上一個混合模式"), + ("", "Track Matte", "追蹤遮罩"), + ("layer.trackMatte", "No Track Matte", "無追蹤遮罩"), + ("layer.trackMatte", "Alpha Matte", "Alpha 遮罩"), + ("layer.trackMatte", "Alpha Inverted Matte", "Alpha 反轉遮罩"), + ("layer.trackMatte", "Luma Matte", "亮度遮罩"), + ("layer.trackMatte", "Luma Inverted Matte", "亮度反轉遮罩"), + ("layer.trackMatte", "Matte with Layer Above", "使用上方圖層做為遮罩"), + ("layer.trackMatte", "Matte with Layer Below", "使用下方圖層做為遮罩"), + ("", "Layer Styles", "圖層樣式"), + ("layer.style.options", "Layer Style Options...", "圖層樣式選項..."), + ("layer.style.convertToEditable", "Convert to Editable Styles", "轉換為可編輯樣式"), + ("layer.style.showAll", "Show All", "全部顯示"), + ("layer.style.removeAll", "Remove All", "全部移除"), + ("layer.style.dropShadow", "Drop Shadow", "陰影"), + ("layer.style.innerShadow", "Inner Shadow", "內陰影"), + ("layer.style.outerGlow", "Outer Glow", "外光暈"), + ("layer.style.innerGlow", "Inner Glow", "內光暈"), + ("layer.style.bevelEmboss", "Bevel and Emboss", "斜角和浮雕"), + ("layer.style.satin", "Satin", "緞面"), + ("layer.style.colorOverlay", "Color Overlay", "顏色覆蓋"), + ("layer.style.gradientOverlay", "Gradient Overlay", "漸層覆蓋"), + ("layer.style.stroke", "Stroke", "筆畫"), + ("path.groupShapes", "Group Shapes", "組成形狀"), + ("path.ungroupShapes", "Ungroup Shapes", "取消組成形狀"), + ("", "Arrange", "排列順序"), + ("layer.arrange", "Bring Layer to Front", "將圖層置於頂層"), + ("layer.arrange", "Bring Layer Forward", "將圖層向前移一層"), + ("layer.arrange", "Send Layer Backward", "將圖層向後移一層"), + ("layer.arrange", "Send Layer to Back", "將圖層置於底層"), + ("", "Reveal", "顯示"), + ("layer.revealSource", "Reveal Layer Source in Project", "在專案中顯示圖層來源"), + ("comp.flowchart", "Reveal Layer in Project Flowchart", "在專案流程圖中顯示圖層"), + ("comp.revealInProject", "Reveal Composition in Project", "在專案中顯示合成"), + ("layer.revealExpressionErrors", "Reveal Expression Errors", "顯示運算式錯誤"), + ("", "Create", "建立"), + ("layer.create", "Convert to Editable Text", "轉換為可編輯文字"), + ("layer.create", "Create Shapes from Text", "從文字建立形狀"), + ("layer.create", "Create Masks from Text", "從文字建立遮色片"), + ("layer.create", "Create Shapes from Vector Layer", "從向量圖層建立形狀"), + ("layer.create", "Create Keyframes from Data", "從資料建立關鍵影格"), + ("layer.create", "Null Controllers for Positional Points", "為位置點建立空物件控制器"), + ("layer.create", "Null Controllers for Path Points", "為路徑點建立空物件控制器"), + ("layer.create", "Nulls Following Path Points", "跟隨路徑點的空物件"), + ("layer.create", "Null Tracing Along Path", "沿路徑筆畫的空物件"), + ("layer.create", "Create 3D Layer Instance", "建立 3D 圖層實體"), + ("", "Camera", "攝影機"), + ("camera.fromView", "Create Camera from 3D View", "從 3D 檢視建立攝影機"), + ("camera.stereoRig", "Create Stereo 3D Rig", "建立立體 3D 裝置"), + ("camera.orbitNull", "Create Orbit Null", "建立環繞空物件"), + ("camera.fromModel", "Create Cameras from 3D Model", "從 3D 模型建立攝影機"), + ("camera.linkFocusToPoi", "Link Focus Distance to Point of Interest", "將焦距連結至目標點"), + ("camera.linkFocusToLayer", "Link Focus Distance to Layer", "將焦距連結至圖層"), + ("camera.setFocusToLayer", "Set Focus Distance to Layer", "將焦距設定為圖層"), + ("layer.cameraSettings", "Camera Settings...", "攝影機設定..."), + ("view.reset3DView", "Reset 3D View", "重設 3D 檢視"), + ("", "Light", "燈光"), + ("light.fromModel", "Create Lights from 3D Model", "從 3D 模型建立燈光"), + ("light.controlWithCamera", "Control Light with Camera", "用攝影機控制燈光"), + ("light.environmentBackground", "Create Environment Light Background Layer", "建立環境光背景圖層"), + ("", "Material", "材質"), + ("material.revealSource", "Reveal Material Source in Project", "在專案中顯示材質來源"), + ("material.reset", "Reset Material", "重設材質"), + ("material.duplicateAssign", "Duplicate and Assign Material", "重製並指定材質"), + ("layer.autoTrace", "Auto-trace...", "自動追蹤..."), + ("layer.precompose", "Pre-compose...", "預先合成..."), + ("layer.sceneEditDetection", "Scene Edit Detection...", "場景編輯偵測..."), + ("", "Effect", "效果"), + ("window.panel", "Effect Controls", "效果控制項"), + ("effect.applyLast", "Last Effect", "上一個效果"), + ("effect.removeAll", "Remove All", "全部移除"), + ("effect.manage", "Manage Effects...", "管理效果..."), + ("effect.plugins.load", "Load Effect Plug-in...", "載入效果外掛程式..."), + ("", "Animation", "動畫"), + ("anim.savePreset", "Save Animation Preset...", "儲存動畫預設集..."), + ("anim.applyPreset", "Apply Animation Preset...", "套用動畫預設集..."), + ("", "Recent Animation Presets", "最近的動畫預設集"), + ("anim.clearRecentPresets", "Clear Recent Presets", "清除最近的預設集"), + ("anim.browsePresets", "Browse Presets...", "瀏覽預設集..."), + ("", "Text Animation Presets", "文字動畫預設集"), + ("layer.applyTextPreset", "Typewriter", "打字機"), + ("layer.applyTextPreset", "Fade Up Characters", "字元淡入"), + ("layer.applyTextPreset", "Bounce In Words", "單字彈入"), + ("layer.applyTextPreset", "Tracking In", "字距進入"), + ("layer.applyTextPreset", "Scramble", "亂序"), + ("layer.applyTextPreset", "Blur In", "模糊進入"), + ("layer.applyTextPreset", "Jitter", "抖動"), + ("layer.applyTextPreset", "Drop In Lines", "行落下"), + ("anim.addKeyframe", "Add Keyframe", "新增關鍵影格"), + ("keys.toggleHold", "Toggle Hold Keyframe", "切換定格關鍵影格"), + ("keys.interpolation", "Keyframe Interpolation...", "關鍵影格插補..."), + ("keys.velocity", "Keyframe Velocity...", "關鍵影格速度..."), + ("", "Keyframe Assistant", "關鍵影格輔助"), + ("keys.audioToKeyframes", "Convert Audio to Keyframes", "將音訊轉換為關鍵影格"), + ("prop.convertExpressionToKeyframes", "Convert Expression to Keyframes", "將運算式轉換為關鍵影格"), + ("keys.easyEase", "Easy Ease", "緩動"), + ("keys.easyEaseIn", "Easy Ease In", "緩入"), + ("keys.easyEaseOut", "Easy Ease Out", "緩出"), + ("keys.exponentialScale", "Exponential Scale", "指數比例"), + ("keys.rpfCameraImport", "RPF Camera Import", "RPF 攝影機匯入"), + ("layer.sequence", "Sequence Layers...", "序列圖層..."), + ("keys.timeReverse", "Time-Reverse Keyframes", "時間反轉關鍵影格"), + ("", "Animate Text", "動畫文字"), + ("layer.enablePerChar3D", "Enable Per-character 3D", "啟用逐字元 3D"), + ("layer.addTextAnimator", "Anchor Point", "錨點"), + ("layer.addTextAnimator", "Position", "位置"), + ("layer.addTextAnimator", "Scale", "縮放"), + ("layer.addTextAnimator", "Skew", "傾斜"), + ("layer.addTextAnimator", "Rotation", "旋轉"), + ("layer.addTextAnimator", "Opacity", "不透明度"), + ("layer.addTextAnimator", "All Transform Properties", "所有變換屬性"), + ("", "Fill Color", "填色"), + ("layer.addTextAnimator", "RGB", "RGB"), + ("layer.addTextAnimator", "Hue", "色相"), + ("layer.addTextAnimator", "Saturation", "飽和度"), + ("layer.addTextAnimator", "Brightness", "亮度"), + ("", "Stroke Color", "筆畫色彩"), + ("layer.addTextAnimator", "Stroke Width", "筆畫寬度"), + ("layer.addTextAnimator", "Tracking", "字距"), + ("layer.addTextAnimator", "Line Anchor", "行錨點"), + ("layer.addTextAnimator", "Line Spacing", "行距"), + ("layer.addTextAnimator", "Character Offset", "字元位移"), + ("layer.addTextAnimator", "Character Value", "字元值"), + ("layer.addTextAnimator", "Blur", "模糊"), + ("text.animatorFontAxes", "Variable Font Axes", "可變字體軸"), + ("", "Add Text Selector", "新增文字選擇器"), + ("text.addSelector", "Range", "範圍"), + ("text.addSelector", "Wiggly", "擺動"), + ("text.addSelector", "Expression", "運算式"), + ("text.removeAllAnimators", "Remove All Text Animators", "移除所有文字動畫製作工具"), + ("prop.setExpression", "Add Expression", "新增運算式"), + ("essential.addProperty", "Add Property to Essential Graphics", "將屬性新增至基本圖形"), + ("prop.separateDimensions", "Separate Dimensions", "單獨尺寸"), + ("track.camera", "Track Camera", "追蹤攝影機"), + ("track.warpStabilizer", "Warp Stabilizer VFX", "變形穩定器 VFX"), + ("track.motion", "Track Motion", "追蹤運動"), + ("track.stabilize", "Stabilize Motion", "穩定運動"), + ("track.property", "Track this Property", "追蹤此屬性"), + ("anim.reveal", "Reveal Properties with Keyframes", "顯示含關鍵影格的屬性"), + ("anim.reveal", "Reveal Properties with Animation", "顯示含動畫的屬性"), + ("anim.reveal", "Reveal All Modified Properties", "顯示所有已修改的屬性"), + ("", "View", "檢視"), + ("view.newViewer", "New Viewer", "新增檢視"), + ("view.splitLockedViewer", "Split with New Locked Viewer", "以新的鎖定檢視分割"), + ("view.zoomIn", "Zoom In", "放大顯示"), + ("view.zoomOut", "Zoom Out", "縮小顯示"), + ("", "Resolution", "解析度"), + ("view.res.full", "Full", "完整"), + ("view.res.half", "Half", "二分之一"), + ("view.res.third", "Third", "三分之一"), + ("view.res.quarter", "Quarter", "四分之一"), + ("view.res.custom", "Custom...", "自訂..."), + ("view.displayColorManagement", "Use Display Color Management", "使用顯示器色彩管理"), + ("", "Simulate Output", "模擬輸出"), + ("view.simulateOutput", "No Output Simulation", "無輸出模擬"), + ("view.simulateOutput", "HDTV (Rec. 709)", "HDTV (Rec. 709)"), + ("view.simulateOutput", "SDTV NTSC", "SDTV NTSC"), + ("view.simulateOutput", "SDTV PAL", "SDTV PAL"), + ("view.simulateOutput", "Legacy Macintosh RGB (Gamma 1.8)", "舊版 Macintosh RGB (灰度係數 1.8)"), + ("view.simulateOutput", "Internet Standard RGB (sRGB)", "Internet 標準 RGB (sRGB)"), + ("view.simulateOutput", "UHDTV (Rec. 2020)", "UHDTV (Rec. 2020)"), + ("view.simulateOutput", "Display P3", "Display P3"), + ("view.simulateOutput", "Linear (1.0 Gamma)", "線性 (1.0 Gamma)"), + ("view.customRgb", "My Custom RGB...", "我的自訂 RGB..."), + ("view.simulateOutput", "Custom...", "自訂..."), + ("view.rulers", "Show Rulers", "顯示尺標"), + ("", "Panel Background Color", "面板背景顏色"), + ("view.panelBackground", "Black", "黑色"), + ("view.panelBackground", "Dark Gray", "深灰色"), + ("view.panelBackground", "Medium Gray (Default)", "中灰色 (預設)"), + ("view.panelBackground", "Light Gray", "淺灰色"), + ("view.panelBackground", "White", "白色"), + ("view.panelBackground", "Custom", "自訂"), + ("view.panelBackground", "Select Custom Background Color...", "選取自訂背景顏色..."), + ("view.guides", "Show Guides", "顯示參考線"), + ("view.snapToGuides", "Snap to Guides", "靠齊參考線"), + ("view.lockGuides", "Lock Guides", "鎖定參考線"), + ("view.addGuide", "Add Guide...", "新增參考線..."), + ("view.clearGuides", "Clear Guides", "清除參考線"), + ("view.importGuides", "Import Guides...", "匯入參考線..."), + ("view.exportGuides", "Export Guides...", "匯出參考線..."), + ("view.grid", "Show Grid", "顯示格點"), + ("view.snapToGrid", "Snap to Grid", "靠齊格點"), + ("view.snapping", "Snapping", "靠齊"), + ("view.options", "View Options...", "檢視選項..."), + ("view.layerControls", "Show Layer Controls", "顯示圖層控制項"), + ("", "Switch View Layout", "切換檢視版面"), + ("view.layout", "1 View", "1 個檢視"), + ("view.layout", "2 Views", "2 個檢視"), + ("view.layout", "4 Views", "4 個檢視"), + ("view.shareViewOptions", "Share View Options", "共用檢視選項"), + ("", "Switch 3D View", "切換 3D 檢視"), + ("view.3d.activeCamera", "Active Camera", "現用攝影機"), + ("view.3d.default", "Default", "預設"), + ("view.3d.front", "Front", "正面"), + ("view.3d.left", "Left", "左側"), + ("view.3d.top", "Top", "頂部"), + ("view.3d.back", "Back", "背面"), + ("view.3d.right", "Right", "右側"), + ("view.3d.bottom", "Bottom", "底部"), + ("view.3d.custom1", "Custom View 1", "自訂檢視 1"), + ("view.3d.custom2", "Custom View 2", "自訂檢視 2"), + ("view.3d.custom3", "Custom View 3", "自訂檢視 3"), + ("", "Assign Shortcut to 3D View", "為 3D 檢視指定快速鍵"), + ("view.3d.last", "Switch to Last 3D View", "切換到上一個 3D 檢視"), + ("view.lookAtSelected", "Look at Selected Layers", "檢視選取圖層"), + ("view.lookAtAll", "Look at All Layers", "檢視所有圖層"), + ("time.set", "Go to Time...", "移至時間..."), + ("view.fullScreen", "Enter Full Screen", "進入全螢幕"), + ("", "Window", "視窗"), + ("", "Workspace", "工作區"), + ("window.workspace", "Default", "預設"), + ("window.workspace", "Review", "審閱"), + ("window.workspace", "Learn", "學習"), + ("window.workspace", "Small Screen", "小螢幕"), + ("window.workspace", "Standard", "標準"), + ("window.workspace", "All Panels", "所有面板"), + ("window.workspace", "Animation", "動畫"), + ("window.workspace", "Color", "顏色"), + ("window.workspace", "Effects", "效果"), + ("window.workspace", "Essential Graphics", "基本圖形"), + ("window.workspace", "Minimal", "最少"), + ("window.workspace", "Motion Tracking", "動態追蹤"), + ("window.workspace", "Paint", "繪製"), + ("window.workspace", "Text", "文字"), + ("window.workspace", "Undocked Panels", "浮動面板"), + ("window.resetWorkspace", "Reset to Saved Layout", "重設為已儲存的版面"), + ("window.saveWorkspace", "Save Changes to this Workspace", "將變更儲存至此工作區"), + ("window.saveWorkspaceAs", "Save as New Workspace...", "另存為新工作區..."), + ("window.editWorkspaces", "Edit Workspaces...", "編輯工作區..."), + ("", "Assign Shortcut to Workspace", "為工作區指定快速鍵"), + ("window.panel", "Align", "對齊"), + ("window.panel", "Audio", "音訊"), + ("window.panel", "Brushes", "筆刷"), + ("window.panel", "Character", "字元"), + ("window.panel", "Content-Aware Fill", "內容感知填滿"), + ("window.panel", "Effects & Presets", "效果和預設集"), + ("window.panel", "Essential Graphics", "基本圖形"), + ("window.panel", "Info", "資訊"), + ("help.inAppTutorials", "Learn", "學習"), + ("window.panel", "Lumetri Scopes", "Lumetri 示波器"), + ("window.panel", "Mask Interpolation", "遮色片插補"), + ("window.panel", "Media Browser", "媒體瀏覽器"), + ("window.panel", "Metadata", "中繼資料"), + ("window.panel", "Motion Sketch", "動態草圖"), + ("window.panel", "Paint", "繪製"), + ("window.panel", "Paragraph", "段落"), + ("window.panel", "Preview", "預覽"), + ("window.panel", "Progress", "進度"), + ("window.panel", "Properties", "內容"), + ("window.panel", "Script Console", "指令碼主控台"), + ("window.panel", "Smoother", "平滑器"), + ("window.panel", "Tools", "工具"), + ("window.panel", "Tracker", "追蹤器"), + ("window.panel", "Wiggler", "擺動器"), + ("window.panel", "Composition", "合成"), + ("window.panel", "Flowchart", "流程圖"), + ("window.panel", "Footage", "素材"), + ("window.panel", "Layer", "圖層"), + ("window.panel", "Project", "專案"), + ("window.panel", "Render Queue", "渲染佇列"), + ("window.panel", "Timeline", "時間軸"), + ("window.panel", "Create Nulls From Paths", "從路徑建立空物件"), + ("window.panel", "Ease Presets", "緩動預設集"), + ("window.panel", "VR Comp Editor", "VR 合成編輯器"), + ("", "Help", "說明"), + ("help.docs", "EffectCraft Help...", "EffectCraft 說明..."), + ("help.docs", "Scripting Help...", "指令碼說明..."), + ("help.docs", "Expression Reference...", "運算式參考..."), + ("help.docs", "Effect Reference...", "效果參考..."), + ("anim.browsePresets", "Animation Presets...", "動畫預設集..."), + ("app.keyboardShortcuts", "Keyboard Shortcuts...", "鍵盤快速鍵..."), + ("help.inAppTutorials", "In-App Tutorials...", "應用程式內教學課程..."), + ("help.onlineTutorials", "Online Tutorials...", "線上教學課程..."), + ("help.systemReport", "System Compatibility Report...", "系統相容性報告..."), + ("help.enableLogging", "Enable Logging", "啟用日誌記錄"), + ("help.revealLogFile", "Reveal Logging File", "顯示日誌檔案"), + ("help.discord", "Join the ArtCraft Discord...", "加入 ArtCraft 的 Discord 社群..."), + ("help.reportIssue", "Provide Feedback...", "提供意見..."), + ("help.website", "ArtCraft Website", "ArtCraft 網站"), + ("help.appPage", "EffectCraft Home Page", "EffectCraft 首頁"), + ("help.github", "EffectCraft on GitHub", "GitHub 上的 EffectCraft"), + ("file.openDemoProject", "Open Demo Project", "開啟範例專案"), +]; + const JAPANESE: &[(&str, &str, &str)] = &[ ("", "EffectCraft", "EffectCraft"), ("app.about", "About EffectCraft...", "EffectCraftについて..."), @@ -725,25 +2049,36 @@ mod tests { for mac in [false, true] { keys(&parse(TREE, mac).unwrap(), &mut actual); } - let mut unique = BTreeSet::new(); - for (command, en, ja) in JAPANESE { - let key = (command.to_string(), en.to_string()); - assert!(actual.contains(&key), "stale translation: {key:?}"); - assert!(unique.insert(key), "duplicate translation: {command} / {en}"); - assert!(!ja.is_empty()); - } - // All fixed TREE entries are covered; @effects is a generated plug-in catalog, - // whose product/effect names are intentionally left as registered. - for line in TREE.lines() { - let line = line.trim().trim_start_matches("[mac] ").trim_start_matches("[!mac] "); - if line.is_empty() || line == "---" || line.starts_with('@') { - continue; + let mut japanese_keys = BTreeSet::new(); + let mut chinese_keys = BTreeSet::new(); + let mut traditional_keys = BTreeSet::new(); + for (catalog, unique) in [ + (JAPANESE, &mut japanese_keys), + (SIMPLIFIED_CHINESE, &mut chinese_keys), + (TRADITIONAL_CHINESE, &mut traditional_keys), + ] { + for (command, en, translated) in catalog { + let key = (command.to_string(), en.to_string()); + assert!(actual.contains(&key), "stale translation: {key:?}"); + assert!(unique.insert(key), "duplicate translation: {command} / {en}"); + assert!(!translated.is_empty()); + } + // All fixed TREE entries are covered; @effects is a generated plug-in catalog, + // whose product/effect names are intentionally left as registered. + for line in TREE.lines() { + let line = line.trim().trim_start_matches("[mac] ").trim_start_matches("[!mac] "); + if line.is_empty() || line == "---" || line.starts_with('@') { + continue; + } + let mut parts = line.split(" | "); + let en = parts.next().unwrap(); + let command = parts.next().and_then(|p| p.split_whitespace().next()).unwrap_or(""); + assert!(unique.contains(&(command.into(), en.into())), "untranslated fixed entry: {line}"); } - let mut parts = line.split(" | "); - let en = parts.next().unwrap(); - let command = parts.next().and_then(|p| p.split_whitespace().next()).unwrap_or(""); - assert!(unique.contains(&(command.into(), en.into())), "untranslated fixed entry: {line}"); } + // Every translated language covers exactly the same entries. + assert_eq!(japanese_keys, chinese_keys, "the languages must translate the same entries"); + assert_eq!(chinese_keys, traditional_keys, "the languages must translate the same entries"); } #[test] @@ -782,6 +2117,16 @@ mod tests { (Some("ja-JP"), "ja"), (Some("ja"), "ja"), (Some("JA_jp.UTF-8"), "ja"), + (Some("zh-CN"), "zh-hans"), + (Some("zh"), "zh-hans"), + (Some("zh_CN.UTF-8"), "zh-hans"), + (Some("zh-Hans-CN"), "zh-hans"), + (Some("zh-SG"), "zh-hans"), + (Some("zh-TW"), "zh-hant"), + (Some("zh-Hant"), "zh-hant"), + (Some("zh-HK"), "zh-hant"), + (Some("zh-Hant-TW"), "zh-hant"), + (Some("zh_MO.UTF-8"), "zh-hant"), (Some("en-US"), "en"), (Some("jv-ID"), "en"), (Some("de-DE"), "en"), @@ -792,8 +2137,116 @@ mod tests { let mut app = EffectcraftApp::new(effectcraft_engine::Session::default()); assert_eq!(app.session.prefs.general.language, "system", "the default"); assert_eq!(japanese(&app), system_language() == "ja"); + assert_eq!(simplified(&app), system_language() == "zh-hans"); + assert_eq!(traditional(&app), system_language() == "zh-hant"); app.session.execute("prefs.set", json!({"key":"general.language", "value":"ja"})).unwrap(); assert!(japanese(&app)); + app.session.execute("prefs.set", json!({"key":"general.language", "value":"zh-hans"})).unwrap(); + assert!(simplified(&app)); + assert!(!traditional(&app)); + assert!(!japanese(&app)); + app.session.execute("prefs.set", json!({"key":"general.language", "value":"zh-hant"})).unwrap(); + assert!(traditional(&app)); + assert!(!simplified(&app)); + assert!(!japanese(&app)); + } + + #[test] + fn every_chinese_entry_keeps_the_english_shape() { + for (code, catalog) in [("zh-hans", SIMPLIFIED_CHINESE), ("zh-hant", TRADITIONAL_CHINESE)] { + for (command, en, translated) in catalog { + assert_eq!(en.contains("..."), translated.contains("..."), "{code} {command} / {en}: {translated}"); + let brackets = |s: &str| s.chars().filter(|c| *c == '(' || *c == ')').count(); + assert_eq!(brackets(en), brackets(translated), "{code} {command} / {en}: {translated}"); + assert!(!translated.contains(" "), "{code} {command} / {en}: {translated}"); + } + } + } + + #[test] + fn zh_hans_translates_labels_computed_titles_and_keeps_names_verbatim() { + let mut app = EffectcraftApp::new(effectcraft_engine::Session::default()); + app.session.execute("prefs.set", json!({"key":"general.language", "value":"zh-hans"})).unwrap(); + assert_eq!(language(&app), "zh-hans"); + assert!(simplified(&app)); + assert!(!traditional(&app)); + assert!(!japanese(&app)); + // Fixed menu rows come from the catalog. + assert_eq!(label(&app, "", "Composition"), "合成"); + assert_eq!(label(&app, "", "Effect"), "效果"); + assert_eq!(label(&app, "comp.new", "New Composition..."), "新建合成..."); + assert_eq!(label(&app, "layer.newText", "Text"), "文本"); + // Untranslated keys and dynamic labels stay verbatim. + assert_eq!(label(&app, "unknown.command", "Text"), "Text"); + assert_eq!( + entry(&app, &MenuEntry { label: "Undo".into(), command: "edit.undo".into(), params: json!({}), shortcut: None }, "Undo Comp1".into()), + "无可撤销的操作" + ); + assert_eq!( + entry( + &app, + &MenuEntry { label: "Layer".into(), command: "window.panel".into(), params: json!({"panel":"layer"}), shortcut: None }, + "Layer: File".into() + ), + "图层: File" + ); + // The submenu titles that name the current workspace / view. + assert_eq!( + submenu(&app, "Assign Shortcut to Workspace", "Assign Shortcut to “Default” Workspace".into()), + "为工作区“Default”指定快捷键" + ); + assert_eq!(submenu(&app, "Assign Shortcut to 3D View", "Assign Shortcut to “Top”".into()), "为 3D 视图“Top”指定快捷键"); + // The menu tree carries the same commands and shortcuts with the Chinese labels. + let zh = crate::native_menu::build(&app); + assert!(zh.items().iter().any(|i| i.command == "comp.new" && i.label == "新建合成...")); + assert!(zh.items().iter().any(|i| i.command == "layer.newText" && i.label == "文本")); + assert!(zh.items().iter().any(|i| i.command == "keys.easyEase" && i.label == "缓动")); + // A dynamic filename is never translated. + app.session.prefs.push_recent("/tmp/File.ecproj"); + assert!(crate::native_menu::build(&app).items().iter().any(|i| i.command == "file.openRecent" && i.label == "File.ecproj")); + } + + #[test] + fn zh_hant_translates_labels_computed_titles_and_keeps_names_verbatim() { + let mut app = EffectcraftApp::new(effectcraft_engine::Session::default()); + app.session.execute("prefs.set", json!({"key":"general.language", "value":"zh-hant"})).unwrap(); + assert_eq!(language(&app), "zh-hant"); + assert!(traditional(&app)); + assert!(!simplified(&app)); + assert!(!japanese(&app)); + // Fixed menu rows come from the catalog. + assert_eq!(label(&app, "", "Composition"), "合成"); + assert_eq!(label(&app, "", "Effect"), "效果"); + assert_eq!(label(&app, "comp.new", "New Composition..."), "新增合成..."); + assert_eq!(label(&app, "layer.newText", "Text"), "文字"); + // Untranslated keys and dynamic labels stay verbatim. + assert_eq!(label(&app, "unknown.command", "Text"), "Text"); + assert_eq!( + entry(&app, &MenuEntry { label: "Undo".into(), command: "edit.undo".into(), params: json!({}), shortcut: None }, "Undo Comp1".into()), + "沒有可復原的操作" + ); + assert_eq!( + entry( + &app, + &MenuEntry { label: "Layer".into(), command: "window.panel".into(), params: json!({"panel":"layer"}), shortcut: None }, + "Layer: File".into() + ), + "圖層: File" + ); + // The submenu titles that name the current workspace / view. + assert_eq!( + submenu(&app, "Assign Shortcut to Workspace", "Assign Shortcut to “Default” Workspace".into()), + "為工作區“Default”指定快速鍵" + ); + assert_eq!(submenu(&app, "Assign Shortcut to 3D View", "Assign Shortcut to “Top”".into()), "為 3D 檢視“Top”指定快速鍵"); + // The menu tree carries the same commands and shortcuts with the Traditional labels. + let zh = crate::native_menu::build(&app); + assert!(zh.items().iter().any(|i| i.command == "comp.new" && i.label == "新增合成...")); + assert!(zh.items().iter().any(|i| i.command == "layer.newText" && i.label == "文字")); + assert!(zh.items().iter().any(|i| i.command == "keys.easyEase" && i.label == "緩動")); + // A dynamic filename is never translated. + app.session.prefs.push_recent("/tmp/File.ecproj"); + assert!(crate::native_menu::build(&app).items().iter().any(|i| i.command == "file.openRecent" && i.label == "File.ecproj")); } #[test] diff --git a/crates/ui-egui/src/native_menu.rs b/crates/ui-egui/src/native_menu.rs index f7332aa5..97863924 100644 --- a/crates/ui-egui/src/native_menu.rs +++ b/crates/ui-egui/src/native_menu.rs @@ -184,7 +184,16 @@ pub fn build(app: &EffectcraftApp) -> NativeMenu { if role == Role::Hide && !services_added { out.push(NativeNode::Predefined { role: Role::Services, - label: if crate::i18n::japanese(app) { "サービス" } else { "Services" }.into(), + label: if crate::i18n::japanese(app) { + "サービス" + } else if crate::i18n::simplified(app) { + "服务" + } else if crate::i18n::traditional(app) { + "服務" + } else { + "Services" + } + .into(), command: String::new(), }); out.push(NativeNode::Separator); diff --git a/docs/preferences.md b/docs/preferences.md index 2ee65553..a51ac97d 100644 --- a/docs/preferences.md +++ b/docs/preferences.md @@ -29,7 +29,7 @@ Commands (CLI, MCP, control channel): ### Settings that change behaviour -- `general.language`: interface language (`system` / `en` / `ja`), Settings ▸ General ▸ Language; menu labels change immediately. `system` (Match System, the default) follows the operating system's interface language where EffectCraft has a translation and is English otherwise; the browser build stays in English with it. Native Japanese UI uses installed system fonts; the web host must supply a Japanese font. +- `general.language`: interface language (`system` / `en` / `ja` / `zh-hans` / `zh-hant`), Settings ▸ General ▸ Language; menu labels change immediately. `system` (Match System, the default) follows the operating system's interface language where EffectCraft has a translation and is English otherwise: a Simplified Chinese locale (`zh`, `zh-CN`, `zh_CN.UTF-8`, `zh-Hans-CN`, `zh-SG`) selects `zh-hans`, a Traditional one (`zh-TW`, `zh-HK`, `zh-Hant`, `zh_MO`) selects `zh-hant`; the browser build stays in English with it. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. - `general.undoLevels`: Levels of Undo - `general.pathPointSize`: Path Point and Handle Size - `general.recentItems`: Recent Projects Shown