From a2dfd6631afb153b182f3729e35b73697c36166a Mon Sep 17 00:00:00 2001 From: Ikki Nishihara Date: Sat, 10 Oct 2026 03:17:21 +0900 Subject: [PATCH] i18n: Japanese for the panels, dialogs and tooltips ui.rs gets a Japanese table with the same 396 rows as the Simplified and Traditional Chinese ones, so Japanese now translates the interface below the menu bar too (it covered the menus only). The shape test keeps the three tables listing the same source strings; a new test checks that Japanese reads its own rows and fills values in order. The existing "no rows yet" check uses Ukrainian instead. ROADMAP.md and docs/preferences.md say which catalogs have panel rows. Co-Authored-By: Claude Sonnet 5.5 --- ROADMAP.md | 1 + crates/ui-egui/src/i18n/ui.rs | 447 +++++++++++++++++++++++++++++++++- docs/preferences.md | 2 +- 3 files changed, 447 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 70935025..6134edb8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,6 @@ # Roadmap +- 2026-10-10: Japanese now translates the interface below the menu bar too: `crates/ui-egui/src/i18n/ui.rs` has a Japanese table with the same 396 rows as the Chinese ones (panels, dialogs, buttons and tooltips; the shape test keeps the three catalogs listing the same source strings). Menus were already Japanese. - 2026-10-09: Settings ▸ General ▸ Language now translates the interface below the menu bar as well: panels, dialogs, buttons and tooltips read their text through `crates/ui-egui/src/i18n/ui.rs`, keyed by the English source string. Simplified and Traditional Chinese are complete (384 strings); Japanese rows can follow in the same file. A test fails when a converted panel gains a hard-coded string, and another keeps the catalog free of unused rows. - 2026-10-08: `effectcraft-cli render --out` resolves a relative path against the working directory, like `--project` (it used the project's folder, which doubled a path that already named it). Render Queue outputs set in a project are unchanged. - 2026-10-08: Long-press a grouped toolbar button to choose its tools, including Horizontal/Vertical Type; releasing the hold keeps the menu open. Existing point/paragraph text creation is unchanged. diff --git a/crates/ui-egui/src/i18n/ui.rs b/crates/ui-egui/src/i18n/ui.rs index 4afb43b1..8a83d97c 100644 --- a/crates/ui-egui/src/i18n/ui.rs +++ b/crates/ui-egui/src/i18n/ui.rs @@ -40,9 +40,11 @@ type Index = HashMap<&'static str, &'static str>; /// The catalog for `language`, indexed by English source (built on first use: panels translate /// hundreds of strings a frame); `None` for English and any language that has no rows yet. fn catalog(language: &str) -> Option<&'static Index> { + static JA: OnceLock = OnceLock::new(); static HANS: OnceLock = OnceLock::new(); static HANT: OnceLock = OnceLock::new(); let (index, rows) = match language { + "ja" => (&JA, JAPANESE), "zh-hans" => (&HANS, SIMPLIFIED_CHINESE), "zh-hant" => (&HANT, TRADITIONAL_CHINESE), _ => return None, @@ -75,6 +77,433 @@ pub(crate) fn tr_args(text: &str, args: &[&dyn Display]) -> String { out } +/// Japanese: the same rows, in the same order, as the Chinese catalogs below (the tests keep the two in step). +const JAPANESE: &[(&str, &str)] = &[ + (" OK ", " OK "), + (" Delete ", " 削除 "), + (" Open Auto-Save ", " 自動保存を開く "), + ("(missing)", "(見つかりません)"), + ("360 View Orientation", "360度ビューの方向"), + ("3:2 Pulldown: {}", "3:2プルダウン:{}"), + ( + "A clean-room, open-source compositor for motion graphics and visual effects: native on macOS, Windows and Linux, and in the browser. Part of the ArtCraft family of creative apps.", + "モーショングラフィックスとビジュアルエフェクト向けの、クリーンルーム方式で開発されたオープンソースのコンポジットソフトウェアです。macOS、Windows、Linuxでネイティブに動作し、ブラウザーでも使えます。ArtCraftクリエイティブアプリファミリーの一員です。", + ), + ("About EffectCraft", "EffectCraftについて"), + ("About...", "情報..."), + ("Active Camera", "アクティブカメラ"), + ("Adapt Feature On Every Frame", "フレームごとに特徴を更新"), + ("Adaptive Sample Limit:", "適応サンプル数の上限:"), + ("Add Animator", "アニメーターを追加"), + ("Add Comment", "コメントを追加"), + ("Add Formatting", "書式を追加"), + ("Add Group", "グループを追加"), + ("Add Mirror", "ミラーを追加"), + ("Add Selected As", "選択項目を次の形式で追加"), + ("Add a comment", "コメントを追加"), + ("Add a shape, fill, stroke or path operation", "シェイプ、塗り、線、またはパス操作を追加"), + ("Add to Composition", "コンポジションに追加"), + ("Add to Favorites", "お気に入りに追加"), + ("Add:", "追加:"), + ("Adjust Exposure (stops)", "露出を調整(段単位)"), + ("Adjust composition duration to the time span of the selected layers", "コンポジションのデュレーションを、選択したレイヤーの時間範囲に合わせる"), + ("Advanced 3D", "アドバンスド3D"), + ("Align Layers to:", "レイヤーの整列基準:"), + ("All six face cameras turn together; the scene is not changed.", "6つの面のカメラがすべて一緒に回転します。シーンは変更されません。"), + ("Anchor:", "アンカー:"), + ("Aperture", "絞り"), + ("Apply Dimensions:", "適用する次元:"), + ("Apply Motion To:", "モーションの適用先:"), + ("Arrange", "重ね順"), + ("Assign", "割り当て"), + ("Auto", "自動"), + ("Auto-saves", "自動保存"), + ("Back", "戻る"), + ("Background Color:", "背景色:"), + ("Blend Mode:", "描画モード:"), + ("Blending Mode", "描画モード"), + ("Blur", "ブラー"), + ("Blur Level", "ブラーレベル"), + ("Browser Storage", "ブラウザーストレージ"), + ("Browse…", "参照…"), + ("Brush Dynamics", "ブラシのダイナミクス"), + ("Caching frames…", "フレームをキャッシュ中…"), + ("Cancel", "キャンセル"), + ("Casts Shadows", "シャドウを落とす"), + ("Change Renderer…", "レンダラーを変更…"), + ( + "Changing a shortcut creates a custom preset; the default stays as it is.", + "ショートカットを変更するとカスタムプリセットが作成されます。初期設定のプリセットはそのまま残ります。", + ), + ("Channel", "チャンネル"), + ("Channel:", "チャンネル:"), + ("Chapter:", "チャプター:"), + ("Choose...", "選択..."), + ("Classic 3D", "クラシック3D"), + ("Clear", "消去"), + ("Clear list", "リストを消去"), + ("Click a key to see its commands.", "キーをクリックすると、割り当てられたコマンドが表示されます。"), + ("Click adds a point (½ height = no change)", "クリックでポイントを追加(高さの½=変化なし)"), + ("Click adds a point; drag one off to remove", "クリックでポイントを追加、外へドラッグで削除"), + ("Click to make this viewer active", "クリックしてこのビューアーをアクティブ化"), + ("Click to reveal the expression in the timeline", "クリックしてタイムラインでエクスプレッションを表示"), + ("Click to show the active composition here", "クリックしてアクティブなコンポジションをここに表示"), + ("Click, then click in the Composition panel", "クリックしてから、コンポジションパネル内をクリック"), + ("Clone Options", "クローンオプション"), + ("Clone Source Overlay:", "クローンソースのオーバーレイ:"), + ("Close", "閉じる"), + ("Close Panel", "パネルを閉じる"), + ("Close tutorial", "チュートリアルを閉じる"), + ("Color", "カラー"), + ("Color Depth: {}", "色深度:{}"), + ("Color:", "カラー:"), + ("Colour map", "カラーマップ"), + ("Columns", "列"), + ("Comment:", "コメント:"), + ("Community", "コミュニティ"), + ("Composition", "コンポジション"), + ("Composition Mini-Flowchart", "コンポジションミニフローチャート"), + ("Composition Name:", "コンポジション名:"), + ("Composition Settings ▸ 3D Renderer", "コンポジション設定 ▸ 3Dレンダラー"), + ("Composition Settings…", "コンポジション設定…"), + ("Composition marker bin: drag a marker to the time ruler", "コンポジションマーカーのビン:マーカーをタイムルーラーへドラッグ"), + ("Cone Angle", "円錐の角度"), + ("Cone Feather", "円錐の境界のぼかし"), + ("Constrain Proportions", "縦横比を固定"), + ("Continuous (Lock Outgoing to Incoming)", "連続(出る速度を入る速度に固定)"), + ("Cue Point", "キューポイント"), + ("Current Render", "現在のレンダリング"), + ("Darker", "暗く"), + ("Default Output:", "既定の出力:"), + ("Default: {}", "初期設定:{}"), + ("Defaults", "初期設定"), + ("Delete", "削除"), + ("Delete Selected Points", "選択したポイントを削除"), + ("Delete selected project items", "選択したプロジェクト項目を削除"), + ("Delete this template", "このテンプレートを削除"), + ("Depth of Field", "被写界深度"), + ("Discord", "Discord"), + ("Distribute Layers:", "レイヤーの分布:"), + ("Don't Recover", "復元しない"), + ("Don't Save", "保存しない"), + ("Double-click a layer to open it in the Layer panel", "レイヤーをダブルクリックしてレイヤーパネルで開く"), + ("Double-click footage in the Project panel to open it here", "プロジェクトパネルのフッテージをダブルクリックしてここで開く"), + ("Double-click to edit the comment", "ダブルクリックしてコメントを編集"), + ("Download", "ダウンロード"), + ( + "Drag properties here from the timeline,\nor use Animation > Add Property to Essential Graphics.", + "タイムラインからここへプロパティをドラッグするか、\n「アニメーション > エッセンシャルグラフィックスにプロパティを追加」を使用してください。", + ), + ("Drag to change", "ドラッグして変更"), + ("Drag to create a guide", "ドラッグしてガイドを作成"), + ("Drag to slip the source", "ドラッグしてソースをスリップ"), + ("Drop Frame", "ドロップフレーム"), + ("Duplicate", "複製"), + ("Duration:", "デュレーション:"), + ("Edit Gradient…", "グラデーションを編集…"), + ("Edit Target: {}", "編集対象:{}"), + ("Edit in the Timeline", "タイムラインで編集"), + ("EffectCraft didn't quit normally last time.", "EffectCraftは前回正常に終了しませんでした。"), + ("Effects & Presets options", "エフェクト&プリセットのオプション"), + ("Effects: {}", "エフェクト:{}"), + ("Empty folder", "空のフォルダー"), + ("Enable Depth of Field", "被写界深度を有効化"), + ("Enable Expression", "エクスプレッションを有効化"), + ("Enhance", "強調"), + ("Essential Properties — {}", "エッセンシャルプロパティ — {}"), + ("Event", "イベント"), + ("Export Template…", "テンプレートを書き出し…"), + ("Export...", "書き出し..."), + ("Expression Language Menu", "エクスプレッション言語メニュー"), + ("Expression pick whip: drag onto a property", "エクスプレッションのピックウィップ:プロパティへドラッグ"), + ("Expression:", "エクスプレッション:"), + ("Eyedropper: click, then click in the Composition panel", "スポイト:クリックしてから、コンポジションパネル内をクリック"), + ("Falloff", "減衰"), + ("Falloff Distance", "減衰距離"), + ("Favorites", "お気に入り"), + ("Field Render: {}", "フィールドレンダリング:{}"), + ("Figures", "数字"), + ("Fill Target", "塗りつぶし対象"), + ("Finished", "完了"), + ("Flowchart: {}", "フローチャート:{}"), + ("Focus Distance", "フォーカス距離"), + ("Follow Feature Rotation and Scale", "特徴の回転とスケールに追従"), + ("Footage: {}", "フッテージ:{}"), + ("Format: {}", "形式:{}"), + ("Frame Aspect Ratio: {}", "フレームアスペクト比:{}"), + ("Frame Blending: {}", "フレームブレンド:{}"), + ("Frame Rate:", "フレームレート:"), + ("Frame Render Time {}ms", "フレームのレンダリング時間 {}ms"), + ("Frame Target:", "フレームターゲット:"), + ("Grab bag", "いろいろ"), + ("Grid", "グリッド"), + ("Guide Layers: {}", "ガイドレイヤー:{}"), + ("Guides", "ガイド"), + ("Height:", "高さ:"), + ("Hide This", "この列を非表示"), + ("Histogram", "ヒストグラム"), + ("Hold In Place", "固定する位置"), + ("Home", "ホーム"), + ("If Confidence is Below", "信頼度が次の値未満の場合"), + ("Import", "読み込み"), + ("Import and Add to Composition", "読み込んでコンポジションに追加"), + ("Import...", "読み込み..."), + ("Imported media", "読み込んだメディア"), + ("Influence:", "影響:"), + ("Install from File…", "ファイルからインストール…"), + ("Intensity", "強度"), + ("Inverted", "反転"), + ("Join the ArtCraft community on Discord", "DiscordでArtCraftコミュニティに参加"), + ("Key: {}", "キー:{}"), + ("LEARN", "学習"), + ("Label", "ラベル"), + ("Label Colors and Names:", "ラベルカラーと名前:"), + ("Label:", "ラベル:"), + ("Latest auto-save: {}", "最新の自動保存:{}"), + ("Layer", "レイヤー"), + ("Layer controls", "レイヤーコントロール"), + ("Layer {}", "レイヤー{}"), + ("Layer:", "レイヤー:"), + ("Layer: {}", "レイヤー:{}"), + ("Learn", "学習"), + ("Leave all attributes in \"{}\"", "すべての属性を「{}」に残す"), + ("Licence: {}", "ライセンス:{}"), + ("Ligatures", "合字"), + ("Light Type", "ライトの種類"), + ("Lighter", "明るく"), + ("Link Selected Property", "選択したプロパティをリンク"), + ("Lock Aspect Ratio to {}", "アスペクト比を{}に固定"), + ("Lock to Zoom", "ズームにロック"), + ("Locked: {} — {}", "ロック済み:{} — {}"), + ("Log:", "ログ:"), + ("Loop (Trace Path)", "ループ(パスをトレース)"), + ("MIT OR Apache-2.0 • Fonts: Inter, JetBrains Mono (OFL)", "MIT OR Apache-2.0 • フォント:Inter、JetBrains Mono (OFL)"), + ("Magnification ratio popup", "拡大率のポップアップ"), + ("Make Comp Size", "コンポジションサイズにする"), + ("Masks", "マスク"), + ("Maximize Panel", "パネルを最大化"), + ("Media Replacement", "メディアの置き換え"), + ("Mesh:", "メッシュ:"), + ("Method Used: {} Average Error: {} pixels", "使用した手法:{} 平均誤差:{}ピクセル"), + ("Models folder: {}", "モデルフォルダー:{}"), + ("Modifiers:", "修飾キー:"), + ("More", "その他"), + ("More ArtCraft apps", "ほかのArtCraftアプリ"), + ("More tutorials", "ほかのチュートリアル"), + ("Motion Blur", "モーションブラー"), + ("Motion Blur: {}", "モーションブラー:{}"), + ("Motion Sketch: drag to record", "モーションスケッチ:ドラッグして記録"), + ("Move Down", "下へ移動"), + ("Move Up", "上へ移動"), + ("Move to Project Root", "プロジェクトのルートへ移動"), + ("Name", "名前"), + ("Name:", "名前:"), + ("Navigation", "ナビゲーション"), + ("New", "新規"), + ("New Comp from Selection", "選択範囲から新規コンポジション"), + ("New Duration:", "新しいデュレーション:"), + ("New composition name:", "新規コンポジション名:"), + ("New from Render Queue item:", "レンダーキュー項目から新規作成:"), + ("New from Template", "テンプレートから新規作成"), + ("Next", "次へ"), + ("Nice work. Pick another tutorial on the Home screen's Learn tab.", "お疲れさまでした。ホーム画面の「学習」タブで別のチュートリアルを選んでください。"), + ( + "No VR environments yet. Create one with Composition ▸ VR ▸ Create VR Environment…", + "VR環境はまだありません。次のメニューで作成してください:コンポジション ▸ VR ▸ VR環境を作成…", + ), + ("No audio layer selected", "オーディオレイヤーが選択されていません"), + ("No background jobs running", "実行中のバックグラウンドジョブはありません"), + ("No composition markers", "コンポジションマーカーはありません"), + ("No contributor data was built into this copy.", "このビルドにはコントリビューターのデータが含まれていません。"), + ("No device list from this host; the system default output is used.", "このホストからはデバイス一覧を取得できないため、システムの既定の出力を使用します。"), + ("No layer selected", "レイヤーが選択されていません"), + ("No matching effects or presets", "一致するエフェクトまたはプリセットはありません"), + ("No model credits were built into this copy.", "このビルドにはモデルのクレジットが含まれていません。"), + ("No nested compositions", "ネストされたコンポジションはありません"), + ("No shortcut", "ショートカットなし"), + ("No unlocked layer selected", "ロックされていないレイヤーが選択されていません"), + ("No video", "ビデオなし"), + ("None", "なし"), + ("Not applied: tick it in the list to add it.", "未適用:リストでチェックを入れると追加されます。"), + ("Not assigned", "未割り当て"), + ("Note: Shadows are only cast from layers with Cast Shadows enabled.", "注意:シャドウは「シャドウを投影」が有効なレイヤーからのみ投影されます。"), + ("Notify", "通知"), + ("OK", "OK"), + ("Offset:", "オフセット:"), + ("On ({}) stop:", "({})で停止したとき:"), + ("One-Node Camera", "1ノードカメラ"), + ("Opacity:", "不透明度:"), + ("Open Composition", "コンポジションを開く"), + ("Open Last Saved Project", "最後に保存したプロジェクトを開く"), + ("Open New Composition", "新規コンポジションを開く"), + ("Open Output", "出力を開く"), + ("Open a composition to build Essential Graphics", "エッセンシャルグラフィックスを作成するには、コンポジションを開いてください"), + ("Open a composition to see its scopes", "コンポジションを開くとスコープが表示されます"), + ("Open a composition to track motion.", "モーションをトラックするには、コンポジションを開いてください。"), + ("Opus Tuning: {}", "Opusチューニング:{}"), + ("Original Duration:", "元のデュレーション:"), + ("Output Cycle: {}", "出力サイクル:{}"), + ("Output To:", "出力先:"), + ("Parameter Name:", "パラメーター名:"), + ("Parent pick whip: drag onto a layer", "親ピックウィップ:レイヤー上にドラッグ"), + ("Pixel Aspect Ratio:", "ピクセルアスペクト比:"), + ("Playing on Video Preview", "ビデオプレビューで再生中"), + ("Post-Render Action: {}", "レンダリング後の処理:{}"), + ("Preserve frame rate when nested or in render queue", "ネスト時またはレンダーキュー内でフレームレートを保持"), + ("Preserve resolution when nested", "ネスト時に解像度を保持"), + ("Preset", "プリセット"), + ("Preset:", "プリセット:"), + ("Presets", "プリセット"), + ("Previous", "前へ"), + ("Primary:", "プライマリ:"), + ("Process Before Match", "マッチ前の処理"), + ("Profile: {}", "プロファイル:{}"), + ( + "Project color depth: click to cycle 8/16/32 bpc, Alt-click for Project Settings", + "プロジェクトの色深度:クリックで8/16/32 bpcを切り替え、Alt+クリックでプロジェクト設定を開く", + ), + ("Project: {}", "プロジェクト:{}"), + ("Projects", "プロジェクト"), + ("Property pick whip: drag onto a property", "プロパティピックウィップ:プロパティ上にドラッグ"), + ("Protected Region", "保護領域"), + ("Proxy Use: {}", "プロキシの使用:{}"), + ("Push All to Comp", "すべてをコンポジションに反映"), + ("Radius", "半径"), + ("Rate Control: {}", "レート制御:{}"), + ("Recent", "最近使用した項目"), + ("Recording", "記録中"), + ("Remove", "削除"), + ("Rename", "名前を変更"), + ("Render: {} ms • UI {} fps{}", "レンダリング:{} ms • UI {} fps{}"), + ("Renderer:", "レンダラー:"), + ("Request Persistent Storage", "永続ストレージを要求"), + ("Reset", "リセット"), + ("Reset Labels", "ラベルをリセット"), + ("Reset Preset", "プリセットをリセット"), + ("Reset to Default", "初期設定にリセット"), + ("Reset to Saved Layout", "保存したレイアウトにリセット"), + ("Resolution/Down Sample Factor Popup", "解像度/ダウンサンプル係数のポップアップ"), + ("Restore Panel Size", "パネルのサイズを元に戻す"), + ("Reverse the order", "順序を逆にする"), + ("Revert All", "すべて元に戻す"), + ("Roman Hanging Punctuation", "欧文句読点のぶら下がり"), + ("Roving:", "ロービング:"), + ("Ruler zero point (drag to move, double-click to reset)", "定規の原点(ドラッグで移動、ダブルクリックでリセット)"), + ("Rulers", "定規"), + ("Run", "実行"), + ("Sample Format: {}", "サンプル形式:{}"), + ("Samples Per Frame:", "フレームあたりのサンプル数:"), + ("Save from #{}", "#{}から保存"), + ("Saved {}", "保存日時:{}"), + ("Script… (⌘/Ctrl+Enter runs)", "スクリプト…(⌘/Ctrl+Enterで実行)"), + ("Search commands or shortcuts", "コマンドまたはショートカットを検索"), + ("Select", "選択"), + ("Select a command to change its shortcut.", "ショートカットを変更するコマンドを選択してください。"), + ("Select a layer to see its effects", "レイヤーを選択するとエフェクトが表示されます"), + ("Select a layer to see its properties", "レイヤーを選択するとプロパティが表示されます"), + ( + "Select a layer with a mask or shape path (or the path property), or Puppet pins.", + "マスクまたはシェイプパスのあるレイヤー(またはパスプロパティ)か、パペットピンを選択してください。", + ), + ("Select a text layer", "テキストレイヤーを選択してください"), + ("Select an item in the Project panel", "プロジェクトパネルで項目を選択してください"), + ("Select animated properties to show them in the Graph Editor", "アニメーションのあるプロパティを選択すると、グラフエディターに表示されます"), + ( + "Select the leader pin, then Shift-click the pins that should trail it (hair, cloth, tails)", + "リーダーピンを選択してから、追従させるピン(髪、布、しっぽなど)をShift+クリック", + ), + ("Set Ground Plane and Origin", "地面と原点を設定"), + ("Set Paint Colors to Black and White (D)", "ペイントカラーを黒と白に設定(D)"), + ("Settings", "設定"), + ("Settings Name:", "設定名:"), + ("Shadow Darkness", "シャドウの暗さ"), + ("Shadow Diffusion", "シャドウの拡散"), + ("Shadows", "シャドウ"), + ("Shape…", "シェイプ…"), + ("Show", "表示"), + ("Show Layer Name", "レイヤー名を表示"), + ("Show Source Name", "ソース名を表示"), + ("Show me", "やり方を見る"), + ("Show:", "表示:"), + ("Shutter Angle:", "シャッター角度:"), + ("Shutter Phase:", "シャッターフェーズ:"), + ("Size", "サイズ"), + ("Skip", "スキップ"), + ("Snapping", "スナップ"), + ("Snapping options", "スナップオプション"), + ("Snapshot", "スナップショット"), + ("Solo Supported Properties", "対応プロパティをソロ表示"), + ("Solo Switches: {}", "ソロスイッチ:{}"), + ("Sort", "並べ替え"), + ("Spacing:", "間隔:"), + ("Spatial Interpolation:", "空間補間法:"), + ("Speed:", "速度:"), + ("Start Timecode:", "開始タイムコード:"), + ("Start: {} Duration: {}", "開始:{} デュレーション:{}"), + ("Step {} of {}: {}", "ステップ{}/{}:{}"), + ("Stop {} at {}°", "ストップ{}:{}°"), + ("Stored in: {}", "保存先:{}"), + ("Stretch", "伸縮"), + ("Stretch Factor:", "伸縮率:"), + ("Stylistic Sets", "スタイルセット"), + ("Subpixel Positioning", "サブピクセル位置決め"), + ("Swap Paint Colors (X)", "ペイントカラーを入れ替え(X)"), + ("System Default", "システムの既定"), + ("Table", "表形式"), + ("Template name", "テンプレート名"), + ("Template: {}\n{}", "テンプレート:{}\n{}"), + ("Temporal Interpolation:", "時間補間法:"), + ("The Media Browser is not available here (use File ▸ Import)", "ここではメディアブラウザーを使用できません(「ファイル ▸ 読み込み」を使ってください)"), + ("The OpenEXR layer shown in red, green, blue and alpha", "赤・緑・青・アルファとして表示するOpenEXRレイヤー"), + ("The render queue is empty.", "レンダーキューは空です。"), + ("This ScriptUI panel has closed", "このScriptUIパネルは閉じられました"), + ("This change will create a new solid for this layer.", "この変更により、このレイヤー用に新しい平面が作成されます。"), + ("Time", "時間"), + ("Time Stretch…", "時間伸縮…"), + ("Time:", "時間:"), + ("Time: {}", "時間:{}"), + ("Title/action safe", "タイトル/アクションセーフ"), + ("Toggle Switches / Modes", "スイッチ/モードを切り替え"), + ("Track Name:", "トラック名:"), + ( + "Trained models are available in the desktop app; the browser uses the classic engine.", + "学習済みモデルはデスクトップアプリで利用できます。ブラウザー版では従来のエンジンを使用します。", + ), + ("Transform", "トランスフォーム"), + ("Transparency grid", "透明グリッド"), + ("Tutorial complete", "チュートリアル完了"), + ("Two-Node Camera", "2ノードカメラ"), + ("Type", "種類"), + ("Type a command or effect…", "コマンドまたはエフェクトを入力…"), + ("URL:", "URL:"), + ("Undock Panel", "パネルのドッキングを解除"), + ("Unlink {}", "{}のリンクを解除"), + ( + "Use this option to place the currently selected layers together into a new intermediate composition.", + "このオプションを使用すると、現在選択しているレイヤーをまとめて新しい中間コンポジションに配置します。", + ), + ("VR Environments", "VR環境"), + ("Value:", "値:"), + ("Variable Font Axes", "可変フォントの軸"), + ("Video Codec: {}", "ビデオコーデック:{}"), + ("View:", "表示:"), + ("Welcome to EffectCraft", "EffectCraftへようこそ"), + ("Width:", "幅:"), + ("You can undo this.", "この操作は取り消せます。"), + ("Your changes will be lost if you don't save them.", "保存しないと、変更内容は失われます。"), + ("Zoom", "ズーム"), + ("built-in", "組み込み"), + ("frames per second", "フレーム/秒"), + ("template name", "テンプレート名"), + ("{} contributors · {} commits", "コントリビューター{}人 · コミット{}件"), + ("{} x {}, {}MB per 8bpc frame", "{} x {}、8bpcフレームあたり{}MB"), + ("{} — coming soon", "{} — 近日対応予定"), + ("{} — double-click to open, {}-click to reveal", "{} — ダブルクリックで開く、{}+クリックで場所を表示"), + ("⌘/Ctrl-drag a pin to record its motion", "⌘/Ctrl+ドラッグでピンの動きを記録"), + ("▣ {}", "▣ {}"), + ("⚠ {} is used by:", "⚠ {}は次のコマンドで使用中:"), +]; + const SIMPLIFIED_CHINESE: &[(&str, &str)] = &[ (" OK ", " 确定 "), (" Delete ", " 删除 "), @@ -991,7 +1420,7 @@ mod tests { const UNITS: &[&str] = &[" px", "%", "·", "s", "ms", "°", "fps", " bpc", " mm", " s", " %", " pixels"]; fn catalogs() -> Vec<(&'static str, &'static str)> { - SIMPLIFIED_CHINESE.iter().copied().chain(TRADITIONAL_CHINESE.iter().copied()).collect() + JAPANESE.iter().copied().chain(SIMPLIFIED_CHINESE.iter().copied()).chain(TRADITIONAL_CHINESE.iter().copied()).collect() } /// A row that translates nothing, repeats a source string, or changes the number of values the @@ -1001,6 +1430,8 @@ mod tests { let hans: Vec<&str> = SIMPLIFIED_CHINESE.iter().map(|(en, _)| *en).collect(); let hant: Vec<&str> = TRADITIONAL_CHINESE.iter().map(|(en, _)| *en).collect(); assert_eq!(hans, hant, "the two Chinese catalogs list different source strings"); + let ja: Vec<&str> = JAPANESE.iter().map(|(en, _)| *en).collect(); + assert_eq!(hans, ja, "the Japanese catalog lists different source strings than the Chinese ones"); let mut sorted = hans.clone(); sorted.sort_unstable(); let listed = sorted.len(); @@ -1019,7 +1450,7 @@ mod tests { fn english_and_unknown_text_pass_through() { set_current("en"); assert_eq!(tr("Composition Name:"), "Composition Name:"); - set_current("ja"); // no rows for Japanese yet + set_current("uk"); // no rows for Ukrainian yet assert_eq!(tr("Composition Name:"), "Composition Name:"); set_current("zh-hans"); assert_eq!(tr("Composition Name:"), "合成名称:"); @@ -1038,6 +1469,18 @@ mod tests { assert_eq!(tr_args("Proxy Use: {}", &[&"Best"]), "Proxy Use: Best"); } + /// Japanese reads its own rows: values fill the placeholders in order, and a name that is not a + /// row (a layer or file name) stays verbatim. + #[test] + fn japanese_rows_translate_the_panels() { + set_current("ja"); + assert_eq!(tr("Composition Name:"), "コンポジション名:"); + assert_eq!(tr("my layer.mp4"), "my layer.mp4"); + assert_eq!(tr_args("Proxy Use: {}", &[&"Best"]), "プロキシの使用:Best"); + assert_eq!(tr_args("Step {} of {}: {}", &[&1, &3, &"Colour"]), "ステップ1/3:Colour"); + set_current("en"); + } + /// Every row is asked for by a converted panel: a leftover row means the panel went back to its /// English literal. #[test] diff --git a/docs/preferences.md b/docs/preferences.md index 9e3d4147..32ed532d 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` / `zh-hans` / `zh-hant` / `uk`), 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`, a Ukrainian one (`uk`, `uk-UA`, `uk_UA.UTF-8`) selects `uk`; the browser build stays in English with it. Choose **Українська** for Ukrainian menus; Ukrainian dialog and panel contents stay in English for now, and Ukrainian uses the bundled UI fonts. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. The same setting picks the CJK fallback for the interface *and* the Han preference of the text engine, so the composition's own text is drawn with the same language's glyph forms (the text engine's preference is process-global); swapping the language reinstalls the fonts, so it applies without a restart. Two catalogs back the text: the menus are keyed by `(command, English label)` (`crates/ui-egui/src/i18n.rs`), and the rest of the interface - panels, dialogs, buttons, tooltips - is keyed by its English source string (`crates/ui-egui/src/i18n/ui.rs`), where a panel writes `tr("Rename")`, or `tr_args("Proxy Use: {}", &[&quality])` when the row carries a value. A row that is missing falls back to English, so a new string shows up untranslated rather than empty; the tests in that module fail on an unused row and on a hard-coded string in a converted panel. +- `general.language`: interface language (`system` / `en` / `ja` / `zh-hans` / `zh-hant` / `uk`), 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`, a Ukrainian one (`uk`, `uk-UA`, `uk_UA.UTF-8`) selects `uk`; the browser build stays in English with it. Choose **Українська** for Ukrainian menus; Ukrainian dialog and panel contents stay in English for now, and Ukrainian uses the bundled UI fonts. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. The same setting picks the CJK fallback for the interface *and* the Han preference of the text engine, so the composition's own text is drawn with the same language's glyph forms (the text engine's preference is process-global); swapping the language reinstalls the fonts, so it applies without a restart. Two catalogs back the text: the menus are keyed by `(command, English label)` (`crates/ui-egui/src/i18n.rs`), and the rest of the interface - panels, dialogs, buttons, tooltips - is keyed by its English source string (`crates/ui-egui/src/i18n/ui.rs`, with rows for Japanese, Simplified Chinese and Traditional Chinese), where a panel writes `tr("Rename")`, or `tr_args("Proxy Use: {}", &[&quality])` when the row carries a value. A row that is missing falls back to English, so a new string shows up untranslated rather than empty; the tests in that module fail on an unused row and on a hard-coded string in a converted panel. - `general.undoLevels`: Levels of Undo - `general.pathPointSize`: Path Point and Handle Size - `general.recentItems`: Recent Projects Shown