From eb6476516809c72dfa30827a6f50b02872f50eab Mon Sep 17 00:00:00 2001 From: zitann2020 Date: Sat, 31 Oct 2026 03:33:39 +0900 Subject: [PATCH] i18n(ja): the 3D views take After Effects' names, and the comp says which camera Co-Authored-By: DeepSeek V4.1 Flash --- crates/ui-egui/src/i18n.rs | 20 +++++++++--------- crates/ui-egui/src/i18n/ui.rs | 1 + crates/ui-egui/src/panels/viewer.rs | 25 +++++++++++++++++++++-- crates/ui-egui/src/panels/viewer/tests.rs | 11 ++++++++++ crates/ui-egui/src/panels/viewer/view.rs | 4 ++-- crates/ui-egui/src/panels/viewer_tools.rs | 4 ++-- 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 9eed465e4..3ab7a9082 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -2254,16 +2254,16 @@ const JAPANESE: &[(&str, &str, &str)] = &[ ("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"), + ("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", "選択したレイヤーを見る"), diff --git a/crates/ui-egui/src/i18n/ui.rs b/crates/ui-egui/src/i18n/ui.rs index ed4378271..20112eb44 100644 --- a/crates/ui-egui/src/i18n/ui.rs +++ b/crates/ui-egui/src/i18n/ui.rs @@ -191,6 +191,7 @@ const JAPANESE: &[(&str, &str)] = &[ ("About...", "情報..."), ("Active", "使用中"), ("Active Camera", "アクティブカメラ"), + ("Active Camera ({})", "アクティブカメラ({})"), ("Alpha", "アルファ"), ("Adapt Feature On Every Frame", "フレームごとに特徴を更新"), ("Adaptive Sample Limit:", "適応サンプル数の上限:"), diff --git a/crates/ui-egui/src/panels/viewer.rs b/crates/ui-egui/src/panels/viewer.rs index e3660bac1..bb7b2d075 100644 --- a/crates/ui-egui/src/panels/viewer.rs +++ b/crates/ui-egui/src/panels/viewer.rs @@ -18,6 +18,27 @@ use crate::state::Tool; use crate::theme::Tokens; use crate::{EffectcraftApp, widgets}; +/// A 3D view's name in the interface's language: the View menu's row for its `view.3d.*` command, +/// else the panel catalog, else the English source. The menu's rows carry After Effects' words — +/// フロントビュー rather than フロント — so the viewer's dropdown and the comp's view label read +/// the same names as View ▸ Switch 3D View. +pub(crate) fn view3d_label(v: View3D) -> &'static str { + let id = match v { + View3D::ActiveCamera => "view.3d.activeCamera", + View3D::Default => "view.3d.default", + View3D::Front => "view.3d.front", + View3D::Left => "view.3d.left", + View3D::Top => "view.3d.top", + View3D::Back => "view.3d.back", + View3D::Right => "view.3d.right", + View3D::Bottom => "view.3d.bottom", + View3D::Custom1 => "view.3d.custom1", + View3D::Custom2 => "view.3d.custom2", + View3D::Custom3 => "view.3d.custom3", + }; + crate::i18n::command_label(id, v.label()) +} + /// Viewer mapping published each frame (for the control channel and other panels). #[derive(Clone, Copy, Debug)] pub struct ViewerMap { @@ -756,8 +777,8 @@ fn phase_rigs(app: &mut EffectcraftApp, ui: &mut egui::Ui, ectx: &EvalCtx, v: &m draw_rigs(app, &painter, &map, ectx, &selected, cam_state(ectx), through_active, None); let view = app.session.state.views3d.get(&cid).map(|v| v.current).unwrap_or_default(); let label = match (view, comp.active_camera(time)) { - (View3D::ActiveCamera, Some(c)) => format!("Active Camera ({})", c.name), - (v, _) => v.label().to_string(), + (View3D::ActiveCamera, Some(c)) => crate::i18n::tr_args("Active Camera ({})", &[&c.name]), + (v, _) => view3d_label(v).to_string(), }; painter.text(area.left_top() + vec2(12.0, 10.0), Align2::LEFT_TOP, label, Tokens::ui(12.0), t.text_dim); } diff --git a/crates/ui-egui/src/panels/viewer/tests.rs b/crates/ui-egui/src/panels/viewer/tests.rs index f9d3ef2f4..0e11611d1 100644 --- a/crates/ui-egui/src/panels/viewer/tests.rs +++ b/crates/ui-egui/src/panels/viewer/tests.rs @@ -151,3 +151,14 @@ fn edge_pan_speed_moves_toward_the_edge() { let corner = edge_pan_speed(area, pos2(950.0, 700.0)); assert!(corner.x < 0.0 && corner.y < 0.0, "{corner:?}"); } + +/// Every 3D view names its own `view.3d.*` command: a typo in that mapping would fall back to the +/// English label silently, which is what the viewer showed before (#2691). +#[test] +fn every_3d_view_finds_its_japanese_row() { + crate::i18n::ui::set_current("ja"); + for v in View3D::ALL { + assert_ne!(view3d_label(*v), v.label(), "{v:?} has no Japanese row"); + } + crate::i18n::ui::set_current("en"); +} diff --git a/crates/ui-egui/src/panels/viewer/view.rs b/crates/ui-egui/src/panels/viewer/view.rs index 59e3e513d..baa335e44 100644 --- a/crates/ui-egui/src/panels/viewer/view.rs +++ b/crates/ui-egui/src/panels/viewer/view.rs @@ -124,7 +124,7 @@ fn pane_selector(app: &mut EffectcraftApp, ui: &mut egui::Ui, pane: usize, area: let t = app.tokens; let r = Rect::from_min_size(area.min + vec2(6.0, 6.0), vec2(124.0, 20.0)); let pid = egui::Id::unique(("viewer-pane-view", pane)); - let response = widgets::dropdown(ui, r, crate::i18n::tr(current.label()), &t, pid); + let response = widgets::dropdown(ui, r, super::view3d_label(current), &t, pid); if response.clicked() { let open = widgets::popup_is_open(ui, pid); ui.data_mut(|d| d.insert_temp(pid.with("open"), !open)); @@ -137,7 +137,7 @@ fn pane_selector(app: &mut EffectcraftApp, ui: &mut egui::Ui, pane: usize, area: ui.set_min_width(124.0); let mut chosen = None; for (k, v) in View3D::ALL.iter().enumerate() { - let item = ui.selectable_label(*v == current, crate::i18n::tr(v.label())); + let item = ui.selectable_label(*v == current, super::view3d_label(*v)); app.auto.add(&format!("viewer.view.{pane}.typeItem.{k}"), item.rect, v.label()); if item.clicked() { chosen = Some(*v); diff --git a/crates/ui-egui/src/panels/viewer_tools.rs b/crates/ui-egui/src/panels/viewer_tools.rs index 3429f5404..ff323ffe1 100644 --- a/crates/ui-egui/src/panels/viewer_tools.rs +++ b/crates/ui-egui/src/panels/viewer_tools.rs @@ -895,13 +895,13 @@ fn bottom_bar_contents(app: &mut EffectcraftApp, ui: &mut egui::Ui, bar: Rect, z let cid = app.session.active_comp_id(); let cur = cid.and_then(|c| app.session.state.views3d.get(&c)).map(|v| v.current).unwrap_or_default(); let r = Rect::from_min_size(pos2(x, cy - 10.0), vec2(118.0, 20.0)); - let response = widgets::dropdown(ui, r, cur.label(), &t, egui::Id::unique("vw-cam")); + let response = widgets::dropdown(ui, r, crate::panels::viewer::view3d_label(cur), &t, egui::Id::unique("vw-cam")); if response.clicked() { toggle_popup(ui, "vw-cam-pop"); } app.auto.add_response("viewer.view3d", &response, "3D View"); use effectcraft_engine::render::three_d::View3D; - let items: Vec<(String, bool)> = View3D::ALL.iter().map(|v| (v.label().to_string(), *v == cur)).collect(); + let items: Vec<(String, bool)> = View3D::ALL.iter().map(|v| (crate::panels::viewer::view3d_label(*v).to_string(), *v == cur)).collect(); if let Some(i) = popup(app, ui, "vw-cam-pop", r, &items, "view3dItem") { let _ = app.session.execute("view.set3DView", json!({"view": View3D::ALL[i].id()})); }