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