diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bf6bec4..c51eb36 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,7 +3,7 @@ ## Validation - [ ] `swift build` passes -- [ ] English and Simplified Chinese UI were checked +- [ ] English, Japanese, and Simplified Chinese UI were checked - [ ] User-facing copy is concise and has no truncation ellipsis - [ ] Documentation and changelog are updated when needed - [ ] I considered the README, download guidance, privacy, and release-note impact @@ -14,6 +14,6 @@ ## Release note - + ## Screenshots or recordings diff --git a/.github/release.yml b/.github/release.yml index 8466453..9ee4a2a 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,15 +1,15 @@ changelog: categories: - - title: ✨ New features / 新功能 + - title: ✨ New features / 新機能 / 新功能 labels: - enhancement - - title: 🐛 Fixes / 修复 + - title: 🐛 Fixes / 修正 / 修复 labels: - bug - - title: ♿ Accessibility / 无障碍 + - title: ♿ Accessibility / アクセシビリティ / 无障碍 labels: - accessibility - - title: 📚 Documentation / 文档 + - title: 📚 Documentation / ドキュメント / 文档 labels: - documentation exclude: diff --git a/AppResources/Info.plist b/AppResources/Info.plist index d783c94..75e3718 100644 --- a/AppResources/Info.plist +++ b/AppResources/Info.plist @@ -12,7 +12,7 @@ CFBundleShortVersionString1.1.2 CFBundleVersion5 CFBundleLocalizations - enzh-Hans + enjazh-Hans LSMinimumSystemVersion13.0 ATSApplicationFontsPathFonts NSHighResolutionCapable diff --git a/AppResources/ja.lproj/Localizable.strings b/AppResources/ja.lproj/Localizable.strings new file mode 100644 index 0000000..2b8dca7 --- /dev/null +++ b/AppResources/ja.lproj/Localizable.strings @@ -0,0 +1,328 @@ +/* MP4Flow Japanese interface. Keys are the Simplified Chinese source strings. */ +"Language" = "言語"; +"常用选择" = "よく使う項目"; +"更多选择" = "その他の項目"; +"智能转换(推荐)" = "スマート変換(おすすめ)"; +"智能增强放大(macOS 27+)" = "スマート高画質拡大(macOS 27+)"; +"清晰又省空间" = "高画質・省容量"; +"尽量保留原画" = "高画質を優先"; +"所有设备都能播放" = "幅広い端末で再生"; +"节省更多空间" = "さらに容量を節約"; +"最稳妥转换(较慢)" = "確実に変換(低速)"; +"只换成 MP4(最快)" = "MP4に変換のみ(最速)"; +"自动选择,能不压就不压。" = "可能な限り再エンコードせずに自動選択します。"; +"支持 1280×1080 以下视频,最高 2 倍。" = "1280 × 1080以下の動画に対応。最大2倍。"; +"清晰省空间,适合大文件。" = "画質と容量のバランスがよく、大きなファイルに向いています。"; +"保留更多细节,文件更大。" = "より多くのディテールを保持します。出力ファイルは大きくなります。"; +"旧设备和电视也能播放。" = "古い端末やテレビでも再生しやすい形式です。"; +"文件更小,旧设备可能不支持。" = "ファイルは小さくなりますが、古い端末では再生できない場合があります。"; +"转换失败时使用,速度较慢。" = "ほかの変換に失敗したときに使います。処理速度は遅くなります。"; +"只换MP4,不压缩画面。" = "映像を圧縮せず、MP4コンテナに変換します。"; +"文件更小" = "小さい"; +"清晰刚好" = "バランス"; +"画质更好" = "高画質"; +"文件更小,细节会少一点。" = "ファイルを小さくします。ディテールは少し減ります。"; +"画面和大小都合适。" = "画質とファイルサイズのバランスが取れています。"; +"保留更多细节,文件更大,速度更慢。" = "より多くのディテールを保持します。ファイルは大きく、処理は遅くなります。"; +"保持原画" = "元のサイズ"; +"转1080P" = "1080pに変換"; +"转720P" = "720pに変換"; +"转576P" = "576pに変換"; +"转480P" = "480pに変換"; +"保持原画尺寸。" = "元の解像度を保ちます。"; +"输出1080P,放大不增细节。" = "1080pで出力します。拡大してもディテールは増えません。"; +"输出720P,节省空间。" = "720pで出力し、容量を節約します。"; +"输出576P,适合宽屏。" = "576pで出力します。一般的なワイド画面に適しています。"; +"输出480P,最省空间。" = "480pで出力し、最も容量を節約します。"; +"等待中" = "待機中"; +"转换中" = "変換中"; +"正在合并" = "結合中"; +"已完成" = "完了"; +"失败" = "失敗"; +"已取消" = "キャンセル済み"; +"正在编码(无法读取总时长)" = "エンコード中(総再生時間を取得できません)"; +"正在编码" = "エンコード中"; +"等待合并" = "結合待ち"; +"正在无损合并" = "再エンコードせずに結合中"; +"已停止;可重新排队。" = "停止しました。もう一度キューに追加できます。"; +"顺时针 90°" = "右に90°回転"; +"逆时针 90°" = "左に90°回転"; +"旋转 180°" = "180°回転"; +"兼容合并" = "互換結合"; +"无损合并" = "ロスレス結合"; +"已处理 %d/%d" = "%d/%d件を処理済み"; +"当前方式已设定画质。" = "この変換モードでは画質があらかじめ設定されています。"; +"只换格式,不压缩画面。" = "コンテナ形式のみを変更し、映像は圧縮しません。"; +"添加视频" = "動画を追加"; +"选择输出位置" = "出力先フォルダを選択"; +"正在检查 %d 个片段是否可无损合并" = "%d個のクリップをロスレス結合できるか確認中"; +"正在兼容合并 %d 个片段(重新编码)" = "%d個のクリップを互換結合中(再エンコード)"; +"正在停止转换" = "変換を停止中"; +"无法创建合并清单:%@" = "結合リストを作成できませんでした:%@"; +"无损合并不支持文件名中的换行符。" = "ロスレス結合では、改行を含むファイル名は使用できません。"; +"已无损合并 %d 个片段:%@" = "%d個のクリップをロスレス結合しました:%@"; +"无法无损合并:%@" = "ロスレス結合できません:%@"; +"合并已取消。" = "結合をキャンセルしました。"; +"%@未完成" = "%@ は完了しませんでした"; +"%@完成" = "%@ が完了しました"; +"片段参数不同,可使用兼容合并。" = "クリップの設定が異なります。互換結合を使用してください。"; +"FFmpeg 合并失败。" = "FFmpegでの結合に失敗しました。"; +"无法启动 FFmpeg:%@" = "FFmpegを起動できませんでした:%@"; +"兼容合并失败:存在无法读取的视频流。" = "互換結合に失敗しました。読み取れない映像ストリームがあります。"; +"正在兼容合并 %d 个片段 · 统一为 %@" = "%d個のクリップを互換結合中・%@に統一"; +"已兼容合并 %d 个片段(统一为 %@):%@" = "%d個のクリップを互換結合しました(%@に統一):%@"; +"兼容合并失败:%@" = "互換結合に失敗しました:%@"; +"兼容合并已取消。" = "互換結合をキャンセルしました。"; +"FFmpeg 兼容合并失败。" = "FFmpegでの互換結合に失敗しました。"; +"转换已取消;可重新排队未完成项目。" = "変換をキャンセルしました。未完了の項目をもう一度キューに追加できます。"; +"转换完成" = "変換が完了しました"; +"队列处理结束,%d 项失败。" = "キューの処理が終了しました。%d件失敗しました。"; +"未检测到视频流,文件可能损坏或只是音频文件。" = "映像ストリームが見つかりません。ファイルが破損しているか、音声のみの可能性があります。"; +"硬件处理失败,正在使用兼容方式重试" = "ハードウェア処理に失敗しました。互換モードで再試行します。"; +"硬件编码不可用,正在使用兼容编码重试" = "ハードウェアエンコードを利用できません。互換エンコードで再試行します。"; +"智能增强放大暂不支持裁切或旋转。" = "スマート高画質拡大では、現在クロップと回転を使用できません。"; +"当前视频不支持智能增强放大。" = "この動画はスマート高画質拡大に対応していません。"; +"智能增强放大至 %@" = "%@までスマート高画質拡大"; +"智能增强放大需要 macOS 27 或更高版本。" = "スマート高画質拡大にはmacOS 27以降が必要です。"; +"智能增强放大失败:%@" = "スマート高画質拡大に失敗しました:%@"; +"此 Mac 不支持智能增强放大。" = "このMacはスマート高画質拡大に対応していません。"; +"无法读取用于智能增强的视频。" = "スマート高画質拡大用の動画を読み取れませんでした。"; +"无法写入智能增强输出文件。" = "スマート高画質拡大の出力ファイルを書き込めませんでした。"; +"无法准备智能增强的视频帧。" = "スマート高画質拡大用の映像フレームを準備できませんでした。"; +"无法调整智能增强输出尺寸。" = "スマート高画質拡大の出力サイズを調整できませんでした。"; +"编码器未响应。" = "エンコーダが応答しません。"; +"智能增强处理超时。" = "スマート高画質拡大がタイムアウトしました。"; +"整理输出文件超时。" = "出力ファイルの仕上げがタイムアウトしました。"; +"智能增强不支持裁切或旋转" = "スマート高画質拡大ではクロップまたは回転を使用できません"; +"请先使用普通转换,再剪辑或裁切。" = "先に通常の変換を行ってから、トリミングまたはクロップしてください。"; +"智能增强处理超时" = "スマート高画質拡大がタイムアウトしました"; +"请降低目标分辨率后重试。" = "目標解像度を下げてから再試行してください。"; +"需要 macOS 27 或更高版本" = "macOS 27以降が必要です"; +"请改用「智能转换」。" = "「スマート変換」を使用してください。"; +"此视频暂不支持智能增强" = "この動画は現在スマート高画質拡大に対応していません"; +"请使用「智能转换」先转换为新文件,然后添加新文件重试。" = "先に「スマート変換」で新しいファイルを作成し、そのファイルを追加して再試行してください。"; +"未检测到可用视频流" = "使用できる映像ストリームが見つかりません"; +"请确认文件可播放,或重新导出后再试。" = "ファイルを再生できるか確認するか、再書き出ししてから試してください。"; +"转换未完成" = "変換が完了しませんでした"; +"请重试;仍失败请使用「最稳妥转换」。" = "再試行してください。引き続き失敗する場合は「確実に変換」を使用してください。"; +"无法保存输出文件:%@" = "出力ファイルを保存できませんでした:%@"; +"FFmpeg 转换失败。" = "FFmpegでの変換に失敗しました。"; +"智能预设必须在探测后解析为具体编码路径" = "スマート変換は解析後に具体的なエンコード方法へ決定される必要があります。"; +"保留源码率 %.1f Mbps%@" = "元のビットレート %.1f Mbps%@ を維持"; +"不重新编码" = "再エンコードなし"; +"智能增强放大(实验性)" = "スマート高画質拡大(実験的機能)"; +"自动放大" = "自動拡大"; +"自动选择支持倍率。" = "対応する倍率を自動的に選択します。"; +"添加视频后显示可选分辨率。" = "動画を追加すると選択可能な解像度が表示されます。"; +"最高增强 2 倍。" = "最大2倍まで高画質拡大します。"; +"目标码率 %.1f Mbps" = "目標ビットレート %.1f Mbps"; +"硬件编码不可用。请改用“兼容优先:H.264 MP4(软件)”。" = "ハードウェアエンコードを利用できません。「互換性優先:H.264 MP4(ソフトウェア)」を使用してください。"; +"无法读取源文件或写入输出位置,请检查文件与权限。" = "元ファイルを読み取れないか、出力先に書き込めません。ファイルとアクセス権を確認してください。"; +"该流无法直接封装为 MP4,请改用 H.264 或 HEVC 转码。" = "このストリームは直接MP4に格納できません。H.264またはHEVCで変換してください。"; +"FFmpeg 转换失败(退出码 %d)。" = "FFmpegでの変換に失敗しました(終了コード%d)。"; +"片段时间轴或流参数不兼容。请先使用相同预设转换为 MP4 后再合并。" = "クリップのタイムラインまたはストリーム設定に互換性がありません。同じプリセットでMP4へ変換してから結合してください。"; +"无法读取片段或写入输出位置,请检查文件与权限。" = "クリップを読み取れないか、出力先に書き込めません。ファイルとアクセス権を確認してください。"; +"FFmpeg 合并失败(退出码 %d)。" = "FFmpegでの結合に失敗しました(終了コード%d)。"; +"需要安装 FFmpeg" = "FFmpegのインストールが必要です"; +"复制安装命令" = "インストールコマンドをコピー"; +"打开 Homebrew 官网" = "Homebrewを開く"; +"稍后再说" = "あとで"; +"检查更新" = "アップデート"; +"知道了" = "OK"; +"无法无损合并" = "ロスレス結合できません"; +"合并完成" = "結合が完了しました"; +"在访达中显示" = "Finderで表示"; +"兼容合并,需重新编码" = "互換結合には再エンコードが必要です"; +"取消" = "キャンセル"; +"开始兼容合并" = "互換結合を開始"; +"视频转 MP4" = "動画をMP4に変換"; +"本地处理,保护隐私" = "ローカル処理でプライバシーを保護"; +"转换预设" = "変換プリセット"; +"画质大小" = "画質とサイズ"; +"分辨率" = "解像度"; +"输出位置" = "出力先"; +"默认输出至源文件夹" = "元ファイルのフォルダに出力"; +"已选择自定义输出文件夹" = "カスタム出力フォルダを選択済み"; +"需要安装 FFmpeg?" = "FFmpegのインストールが必要ですか?"; +"复制" = "コピー"; +"查看安装步骤" = "インストール手順を見る"; +"转换队列(%d)" = "変換キュー(%d)"; +"拖入视频文件" = "動画ファイルをここにドロップ"; +"支持 AVI、WMV、MKV、RMVB 及常见视频格式" = "AVI、WMV、MKV、RMVBなどの一般的な動画形式に対応"; +"清空列表" = "リストを消去"; +"清理已完成(%d)" = "完了済みを消去(%d)"; +"重排失败项" = "失敗項目を再追加"; +"合并(%d)" = "結合(%d)"; +"取消任务" = "タスクをキャンセル"; +"开始转换" = "変換を開始"; +"正在检查片段兼容性" = "クリップの互換性を確認中"; +"正在%@ %d 个片段 · %d%%" = "%@:%d個のクリップ・%d%%"; +"准备就绪" = "準備完了"; +"已添加 %d 个视频" = "%d本の動画を追加しました"; +"处理中" = "処理中"; +"正在转换 · %d%% · %@" = "変換中・%d%%・%@"; +"正在转换 · %d%%" = "変換中・%d%%"; +"正在转换 · %@" = "変換中・%@"; +"正在%@ · %d%%" = "%@・%d%%"; +"配置选项" = "設定オプション"; +"原视频所在文件夹" = "元動画のあるフォルダ"; +"当前:%@" = "現在:%@"; +"选择其他文件夹" = "別のフォルダを選択"; +"准备输出 MP4" = "MP4出力の準備完了"; +"正在读取视频信息" = "動画情報を読み込み中"; +"剪辑" = "トリミング"; +"裁切画面" = "画面をクロップ"; +"打开文件夹" = "フォルダを開く"; +"从队列移除" = "キューから削除"; +"待" = "待機:"; +"待%@" = "%@を待機中"; +"%@ 视频" = "%@の動画"; +"裁切" = "クロップ"; +"旋转" = "回転"; +"裁切为 %@" = "%@にクロップ"; +"旋转视频" = "動画を回転"; +"取消旋转" = "回転を解除"; +"保留范围" = "残す範囲"; +"原始时长 %@" = "元の長さ %@"; +"起始" = "開始"; +"至" = "〜"; +"结束" = "終了"; +"后退 5 帧" = "5フレーム戻る"; +"前进 5 帧" = "5フレーム進む"; +"保留 %@" = "%@を残す"; +"保留" = "残す"; +"正在加载视频预览" = "動画プレビューを読み込み中"; +"确认剪辑" = "トリミングを確定"; +"无法读取视频信息,请确认文件可播放。" = "動画情報を読み取れません。ファイルを再生できるか確認してください。"; +"原始" = "元のまま"; +"裁切参数" = "クロップ設定"; +"宽高比" = "アスペクト比"; +"裁切比例" = "クロップ比率"; +"位置和尺寸(像素)" = "位置とサイズ(px)"; +"视频尺寸:%d × %d" = "動画サイズ:%d × %d"; +"时长:%@" = "長さ:%@"; +"宽" = "幅"; +"高" = "高さ"; +"可手动输入裁切区域" = "クロップ範囲を手動で入力できます"; +"正在加载裁切预览" = "クロッププレビューを読み込み中"; +"确认裁切" = "クロップを確定"; +"无法读取视频尺寸,请确认文件可播放。" = "動画サイズを読み取れません。ファイルを再生できるか確認してください。"; +"裁切区域,可拖动移动或调整四角" = "クロップ範囲。ドラッグで移動、四隅でサイズ変更できます。"; +"调整裁切区域" = "クロップ範囲を調整"; +"剪辑范围" = "トリミング範囲"; +"W" = "幅"; +"H" = "高"; +"当前版本为 v%@。正式发布更新源配置完成后,MP4Flow 会在这里提示可用的新版本。" = "現在のバージョンはv%@です。正式なアップデート配信を設定すると、新しいバージョンをここでお知らせします。"; +"检查更新,当前版本 v%@" = "アップデートを確認。現在のバージョン:v%@"; +"MP4Flow 依赖本机的 FFmpeg 进行转码,但尚未检测到它。\n\n1. 打开「终端」\n2. 若尚未安装 Homebrew,请在官网完成安装\n3. 粘贴并执行:brew install ffmpeg\n4. 安装结束后,完全退出并重新打开 MP4Flow。" = "MP4Flowは動画の変換にローカルのFFmpegを使用しますが、見つかりませんでした。\n\n1. 「ターミナル」を開きます\n2. Homebrewが未インストールの場合は、公式サイトからインストールします\n3. 次を貼り付けて実行します:brew install ffmpeg\n4. 完了後、MP4Flowを完全に終了して開き直します。"; +"中文" = "中国語"; +"检测到片段的分辨率、帧率或音频参数不同,无法安全无损拼接。继续后将以队列中最大分辨率为目标尺寸:较小视频等比例放大;比例不同则居中补边,不会拉伸画面。输出统一编码为 H.264 + AAC MP4。" = "クリップの解像度、フレームレート、または音声設定が異なるため、安全にロスレス結合できません。続行すると、キュー内で最大の解像度を目標サイズにします。小さい動画は比率を保って拡大し、比率が異なる動画には中央揃えで余白を追加するため、映像は引き伸ばされません。出力はH.264 + AAC MP4に統一されます。"; +"关于 MP4Flow" = "MP4Flowについて"; +"MP4Flow 使用帮助" = "MP4Flowヘルプ"; +"发现新版本 v%@" = "新しいバージョン v%@ が見つかりました"; +"检查更新…" = "アップデートを確認…"; +"在 GitHub 查看项目" = "GitHubでプロジェクトを見る"; +"反馈问题或建议" = "問題または提案を送る"; +"免费开源的本地视频转换工具" = "無料・オープンソースのローカル動画変換ツール"; +"开发者:" = "開発者:"; +"下载更新" = "アップデートをダウンロード"; +"本地处理,不上传视频或使用数据。" = "ローカルで処理します。動画や利用データはアップロードしません。"; +"三步完成本地视频转换。" = "3ステップでローカル動画変換。"; +"点击「添加视频」或将文件拖入窗口。" = "「動画を追加」をクリックするか、ファイルをウインドウにドロップします。"; +"选择转换方式" = "変換方法を選択"; +"选择预设、画质、分辨率与输出位置。" = "プリセット、画質、解像度、出力先を選択します。"; +"确认队列后点击「开始转换」,完成后可在访达中打开文件。" = "キューを確認して「変換を開始」をクリックします。完了後はFinderでファイルを開けます。"; +"遇到问题?" = "お困りですか?"; +"请确认已安装 FFmpeg;智能增强需要 Apple 芯片与 macOS 27+。不支持的素材可先用「智能转换」生成新文件后重试。" = "FFmpegがインストールされていることを確認してください。スマート高画質拡大にはAppleシリコンとmacOS 27以降が必要です。対応していない素材は、先に「スマート変換」で新しいファイルを作成してから再試行してください。"; +"所有转换均在本机完成。更新检查只读取 GitHub 公开版本信息,不上传视频或使用数据。" = "すべての変換はこのMacで完結します。アップデート確認ではGitHubの公開リリース情報のみを読み取り、動画や利用データはアップロードしません。"; +"发现新版本 v%@,可前往 GitHub 下载。" = "v%@を利用できます。GitHubからダウンロードできます。"; +"MP4Flow 已是最新版本(v%@)。" = "MP4Flowは最新です(v%@)。"; +"暂时无法检查更新。请确认网络连接,或稍后重试。" = "アップデートを確認できませんでした。ネットワーク接続を確認して、あとでもう一度試してください。"; +"正在检查更新…" = "アップデートを確認中…"; +"更新设置" = "アップデート設定"; +"自动检查更新" = "アップデートを自動確認"; +"更新不会自动下载或安装。" = "アップデートが自動でダウンロードまたはインストールされることはありません。"; +"首次启动不联网;从第二次启动起,每天最多检查一次 GitHub 公开发布信息。" = "初回起動時は通信しません。2回目以降は、GitHubの公開リリース情報を1日最大1回確認します。"; +"自动检查已关闭。你仍可随时通过“帮助 > 检查更新”手动检查。" = "自動確認はオフです。「ヘルプ > アップデートを確認」からいつでも手動で確認できます。"; +"更新检查只读取 GitHub 公开发布信息,不上传视频或使用数据。" = "アップデート確認ではGitHubの公開リリース情報のみを読み取り、動画や利用データはアップロードしません。"; +"可在 GitHub Release 查看更新说明并下载。" = "GitHub Releasesで更新内容を確認し、ダウンロードできます。"; +"查看更新与下载" = "更新を表示"; +"暂不提醒此版本" = "このバージョンを非表示"; +"MIT License" = "MITライセンス"; +"FFmpeg 长时间无进度,已安全停止。" = "FFmpegの進行が長時間止まったため、安全に停止しました。"; +"仅保留第一路视频和第一路音频。" = "最初の映像トラックと音声トラックのみを保持します。"; +"容器元数据和章节将被移除。" = "コンテナメタデータとチャプターは削除されます。"; +"无法保存输出文件" = "出力ファイルを保存できませんでした"; +"无法读取此视频的媒体数据" = "この動画のメディアデータを読み取れませんでした"; +"无法验证输出文件" = "出力ファイルを検証できませんでした"; +"未检测到 ffprobe,请安装完整的 FFmpeg 后重试。" = "ffprobeが見つかりません。完全なFFmpegパッケージをインストールしてから再試行してください。"; +"未检测到音频流。" = "音声ストリームが見つかりません。"; +"检测到 %d 条字幕;当前输出不会保留字幕。" = "%d個の字幕トラックを検出しました。現在の出力では字幕は保持されません。"; +"检测到 %d 路音频;其余音轨不会写入输出。" = "%d個の音声トラックを検出しました。最初のトラック以外は出力に書き込まれません。"; +"检测到 HDR;视频流将直接封装,完成后仍建议核对播放效果。" = "HDRを検出しました。映像ストリームは直接再格納されます。完了後に再生結果を確認してください。"; +"检测到 HDR;转码后请核对色彩与动态范围。" = "HDRを検出しました。変換後に色とダイナミックレンジを確認してください。"; +"正在停止转换并清理临时文件" = "変換を停止し、一時ファイルを消去中"; +"正在兼容转码" = "互換モードで変換中"; +"正在快速直封装" = "再エンコードせずに高速再格納中"; +"正在检测素材" = "素材を解析中"; +"正在硬件转码" = "ハードウェア変換中"; +"正在验证输出" = "出力を検証中"; +"没有读取或写入文件的权限" = "ファイルを読み書きする権限がありません"; +"硬件编码不可用" = "ハードウェアエンコードを利用できません"; +"请使用「最稳妥转换」重试。" = "「確実に変換」で再試行してください。"; +"请安装 FFmpeg 和 ffprobe 后重试。" = "FFmpegとffprobeをインストールしてから再試行してください。"; +"请检查文件和输出文件夹权限后重试。" = "ファイルと出力先フォルダのアクセス権を確認してから再試行してください。"; +"请检查磁盘空间后重试。" = "ディスクの空き容量を確認してから再試行してください。"; +"请检查输出文件夹权限和可用空间后重试。" = "出力先フォルダのアクセス権と空き容量を確認してから再試行してください。"; +"请确认文件可播放,或使用「智能转换」生成新文件后重试。" = "ファイルを再生できるか確認するか、「スマート変換」で新しいファイルを作成してから再試行してください。"; +"请确认视频可播放、磁盘可用后重试;仍失败请使用「最稳妥转换」。" = "動画を再生でき、ディスクを使用できることを確認してから再試行してください。引き続き失敗する場合は「確実に変換」を使用してください。"; +"请释放空间或选择其他输出位置后重试。" = "空き容量を確保するか、別の出力先を選択してから再試行してください。"; +"转换长时间无进度,已安全停止" = "変換の進行が長時間止まったため、安全に停止しました"; +"转换长时间无进度,正在安全停止" = "変換が停止しています。安全に停止中です"; +"输出文件为空或未写完整" = "出力ファイルが空か、不完全です"; +"输出文件缺少视频流" = "出力ファイルに映像ストリームがありません"; +"输出磁盘空间不足" = "出力先ディスクの空き容量が不足しています"; +"环境体检" = "環境チェック"; +"检查本机转换依赖、硬件编码与输出位置。" = "ローカルの変換ツール、ハードウェアエンコード、出力先を確認します。"; +"检查本机转换依赖与硬件编码;输出位置在添加视频后检查。" = "ローカルの変換ツールとハードウェアエンコードを確認します。出力先は動画追加後に確認します。"; +"重新检查" = "再確認"; +"正在检查…" = "確認中…"; +"正在检查转换环境…" = "変換環境を確認中…"; +"需要安装 FFmpeg" = "FFmpegをインストールする必要があります"; +"FFprobe 不可用" = "FFprobeを利用できません"; +"输出位置不可写" = "出力先フォルダに書き込めません"; +"添加视频后检查输出位置。" = "動画追加後に出力先を確認します。"; +"可用空间较少" = "空き容量が少なくなっています"; +"将使用软件编码" = "ソフトウェアエンコードを使用します"; +"FFmpeg %@ 已就绪" = "FFmpeg %@ は準備完了です"; +"转换环境已就绪" = "変換環境の準備ができました"; +"转换环境需要注意" = "変換環境の確認が必要です"; +"转换环境需要处理" = "変換環境の対応が必要です"; +"未检测到可用的 FFmpeg;请安装后重新检查。" = "使用できるFFmpegが見つかりません。インストールしてから再確認してください。"; +"FFprobe 不可用;请重新安装 FFmpeg。" = "FFprobeを利用できません。FFmpegを再インストールしてください。"; +"输出位置不可写;请选择可写文件夹或检查权限。" = "出力先フォルダに書き込めません。書き込み可能なフォルダを選ぶか、アクセス権を確認してください。"; +"添加视频后会检查原视频所在文件夹。" = "動画追加後に元動画のフォルダを確認します。"; +"输出位置可写,但可用空间较少。" = "出力先フォルダには書き込めますが、空き容量が少なくなっています。"; +"硬件编码不可用;将使用软件编码。" = "ハードウェアエンコードを利用できません。ソフトウェアエンコードを使用します。"; +"FFmpeg %@ · 输出位置可写" = "FFmpeg %@・出力先フォルダは書き込み可能"; +"请在终端执行 brew install ffmpeg,然后重新检查。" = "ターミナルで brew install ffmpeg を実行してから、もう一度確認してください。"; +"请重新安装 FFmpeg:brew reinstall ffmpeg。" = "FFmpegを再インストールしてください:brew reinstall ffmpeg。"; +"将使用软件编码;速度可能较慢。" = "ソフトウェアエンコードを使用します。処理速度は遅くなる場合があります。"; +"请选择可写的文件夹或检查磁盘权限。" = "書き込み可能なフォルダを選ぶか、ディスクのアクセス権を確認してください。"; +"可用空间较少;建议至少保留 1 GB。" = "空き容量が少なくなっています。少なくとも1 GBの空きを確保することをおすすめします。"; +"处理策略" = "処理ポリシー"; +"默认输出第一路视频和音频,并移除容器元数据和章节;开始转换时会检测多音轨、字幕和 HDR,并在队列中提示。" = "MP4Flowは最初の映像トラックと音声トラックを出力し、コンテナメタデータとチャプターを削除します。変換開始時に複数音声、字幕、HDRを検出し、キューに通知を表示します。"; +"默认仅输出第一路视频和音频,并移除容器元数据和章节。开始转换时会检测多音轨、字幕和 HDR,并在队列中提示。" = "デフォルトでは最初の映像トラックと音声トラックのみを出力し、コンテナメタデータとチャプターを削除します。変換開始時に複数音声、字幕、HDRを検出し、キューに通知を表示します。"; +"%@ · %d%%" = "%@・%d%%"; +"%@ · %@" = "%@・%@"; +"正在转换" = "変換中"; +"完成" = "完了"; +"未找到" = "見つかりません"; +"版本:%@ · %@" = "バージョン:%@・%@"; +"路径:%@" = "パス:%@"; +"未检测到可用的 FFmpeg VideoToolbox 编码器。" = "使用可能なFFmpeg VideoToolboxエンコーダが見つかりません。"; +"可用硬件编码:%@。" = "使用可能なハードウェアエンコード:%@。"; +"将输出到原视频所在文件夹;添加视频后检查。" = "元動画のあるフォルダに出力します。動画追加後に確認します。"; +"已检查 %d 个文件夹;无法写入:%@" = "%d個のフォルダを確認しました。書き込めません:%@"; +"已检查 %d 个输出文件夹,可写。" = "%d個の出力先フォルダを確認しました。書き込み可能です。"; +"可用空间:%@" = "空き容量:%@"; diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b5c4f0..5e6616c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## Unreleased + +### English + +- Added a complete Japanese experience: app language selection and system-language detection, bundled Japanese resources, a Japanese website view, Japanese documentation, and Japanese release-note coverage. + +### 日本語 + +- 日本語での利用体験を追加しました。アプリの言語選択とシステム言語の検出、日本語リソースの同梱、日本語の公式サイト、日本語ドキュメント、日本語のリリースノートを含みます。 + +### 中文 + +- 新增完整日文支持:应用语言选择与系统语言识别、日文资源随应用打包、官网日文页面、日文文档与日文版本说明。 + ## 1.1.2 — 2026-10-15 ### English @@ -8,6 +22,12 @@ - Added update-check regression coverage for semantic versions, trusted release URLs, draft/prerelease filtering, daily backoff, HTTP failures, and timeouts. Updates remain a user-approved visit to the GitHub Release page; they are never downloaded or installed automatically. - Standardised interface symbols on the bundled Tabler Icons Outline set and refined shared controls for a more consistent macOS experience. +### 日本語 + +- 更新通知を改善しました。初回起動時はネットワークに接続せず、自動確認は永続化されて1日1回までに制限され、設定から無効にもできます。新しいリリースがある場合は閉じられるアプリ内バナーを表示し、手動確認では更新あり、最新、失敗を一貫して知らせます。 +- セマンティックバージョン、信頼できるリリース URL、ドラフト/プレリリースの除外、日次の間隔制御、HTTP 失敗、タイムアウトを対象に更新確認の回帰テストを追加しました。更新は GitHub Releases をユーザーが承認して開く方式であり、自動ダウンロードや自動インストールは行いません。 +- 同梱の Tabler Icons Outline セットにインターフェース記号を統一し、共通コントロールを整えて macOS らしい一貫性を高めました。 + ### 中文 - 完善更新提醒:首次启动不联网,自动检查会持久化并限制为每天最多一次,也可在“设置”中关闭。发现新版本时显示可隐藏的应用内提示;手动检查会一致地反馈有更新、已是最新或检查失败。 @@ -23,6 +43,13 @@ - Makes media handling explicit before conversion: MP4Flow reports multi-audio, subtitle, and HDR handling instead of silently implying they were preserved. Added a reproducible 28-case synthetic media regression gate. - Refined the Environment Check layout, original icon system, centered checking state, and compact action buttons. +### 日本語 + +- ローカルの FFmpeg、ffprobe、利用可能な VideoToolbox ハードウェアエンコーダを表示する「環境チェック」を追加しました。出力先の確認は動画の追加またはカスタム出力先の選択後まで遅らせ、起動時の静かさと応答性を保ちます。 +- 変換の状態で、素材の検査、直接再格納、ハードウェアエンコード、ソフトウェア互換エンコード、出力検証を明示するようにしました。進行停止のタイムアウト、安全なキャンセル後の清掃、出力検証、よくある失敗の回復案内を追加しました。 +- 変換前に複数音声、字幕、HDR の扱いを明示し、保持されたと誤解させる表示をしないようにしました。再現可能な28件の合成メディア回帰ゲートも追加しました。 +- 環境チェックのレイアウト、独自アイコンシステム、中央揃えの確認状態、コンパクトな操作ボタンを改善しました。 + ### 中文 - 新增“环境体检”:检查本机 FFmpeg、ffprobe 与可用的 VideoToolbox 硬件编码器。输出位置仅在添加视频或选择自定义目录后检查,启动界面更安静、响应更快。 @@ -38,6 +65,12 @@ - Resolution choices now adapt to the source. Audio/video writing is concurrent, and encoder, frame-processing, and finalisation timeouts prevent an export from waiting indefinitely. - Added a real GitHub update check, a linked About panel, a focused Help window, and clear recovery guidance. Update checks read public release metadata only and never upload videos or usage data. +### 日本語 + +- Appleシリコンかつ macOS 27 以降向けに、実験的な「スマート高画質拡大」を追加しました。対応する元解像度と目標解像度の組み合わせでは、システムの VideoToolbox 機能により最大2倍まで拡大できます。 +- 解像度の選択肢を元動画に応じて変化させました。音声と映像の同時書き込みに加え、エンコーダ、フレーム処理、終了処理のタイムアウトにより、書き出しが無期限に待機するのを防ぎます。 +- 実際の GitHub 更新確認、リンク付きの「情報」パネル、操作に集中したヘルプ画面、明確な復旧案内を追加しました。更新確認は公開リリース情報のみを読み取り、動画や利用データをアップロードしません。 + ### 中文 - 新增实验性「智能增强放大(macOS 27+)」:在 Apple 芯片 Mac 上调用系统 VideoToolbox 能力,符合条件的源视频最高可放大 2 倍。 @@ -46,12 +79,28 @@ ## 1.0.1 — 2026-09-23 +### English + - Added `−5` and `+5` trim controls for frame-accurate navigation while selecting a clip range. - Widened trim time fields so start and end timecodes remain fully visible. - Improved frame stepping by using the source frame rate, cancelling stale preview seeks, and clearly disabling controls at range boundaries. +### 日本語 + +- クリップ範囲を選ぶ際のフレーム単位の移動のため、トリミング操作に `−5` と `+5` を追加しました。 +- 開始と終了のタイムコードが最後まで見えるよう、トリミングの時刻フィールドを広げました。 +- 元動画のフレームレートを使い、古いプレビューシークを取り消し、範囲の端では操作を明確に無効化することで、フレーム移動を改善しました。 + +### 中文 + +- 剪辑范围选择中新增 `−5` 与 `+5` 帧操作,帮助更精确地定位画面。 +- 加宽剪辑时间栏,确保起止时间码完整显示。 +- 使用源视频帧率、取消过期预览跳转,并在范围边界清晰禁用控件,优化逐帧定位。 + ## 1.0.0 — 2026-09-22 +### English + - Added English and Simplified Chinese application language support. - Added a reproducible DMG installer workflow with a Finder installation layout. - Added open-source documentation, privacy, security, attribution, and contribution guidance. @@ -59,6 +108,24 @@ - Hardened lossless merge with line-break filename rejection and atomic temporary output publishing. - Added a release checklist covering FFmpeg trust boundaries, privacy disclosures, asset provenance, signing, notarization, and GitHub release hygiene. +### 日本語 + +- 英語と簡体字中国語のアプリ言語サポートを追加しました。 +- Finder でのインストール配置を含む、再現可能な DMG インストーラのワークフローを追加しました。 +- オープンソース向けのドキュメント、プライバシー、セキュリティ、帰属表示、貢献ガイドを追加しました。 +- キュー、変換、結合、エラーの文言を、簡潔で分かりやすい表現に改善しました。 +- 改行を含むファイル名を拒否し、原子的な一時出力公開を使うことで、ロスレス結合を強化しました。 +- FFmpeg の信頼境界、プライバシー開示、アセットの出所、署名、公証、GitHub リリースの運用を確認するリリースチェックリストを追加しました。 + +### 中文 + +- 新增中英文应用语言支持。 +- 新增可重复执行的 DMG 安装包流程与 Finder 安装布局。 +- 新增开源文档、隐私、安全、署名与贡献说明。 +- 优化队列、转换、合并与报错文案,使其更简洁易懂。 +- 拒绝含换行符的文件名,并使用原子临时输出发布,增强无损合并的可靠性。 +- 新增发布检查清单,覆盖 FFmpeg 信任边界、隐私披露、资产来源、签名、公证和 GitHub 发布规范。 + ## Earlier versions Earlier development changes are intentionally not retroactively reconstructed. Future release notes follow the Keep a Changelog style. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4356e86..4355c9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,9 +3,9 @@ Thank you for improving MP4Flow. 1. Discuss substantial changes in an issue before implementation. -2. Keep both English and Simplified Chinese user-facing text clear, short, and consistent. Do not machine-translate codec jargon literally. +2. Keep English, Japanese, and Simplified Chinese user-facing text clear, short, and consistent. Do not machine-translate codec jargon literally. 3. Build with `swift build` and run `./Scripts/build-app.sh` before a pull request. 4. Do not add telemetry, network calls, or bundled FFmpeg binaries without explicit discussion. 5. Keep changes focused and document user-visible behaviour in `CHANGELOG.md`. -For UI work, test both app languages and narrow windows. For conversion changes, include a sample command or a repeatable description using non-private media. +For UI work, test all three app languages and narrow windows. For conversion changes, include a sample command or a repeatable description using non-private media. diff --git a/NOTICE.ja.md b/NOTICE.ja.md new file mode 100644 index 0000000..c1b4629 --- /dev/null +++ b/NOTICE.ja.md @@ -0,0 +1,19 @@ +# 表示と帰属 + +## FFmpeg + +MP4Flow は、ユーザーが用意した FFmpeg インストールを呼び出します。FFmpeg はこのリポジトリに同梱、ダウンロード、再配布されません。ユーザーがインストールする FFmpeg ビルドのライセンスは、ビルド方法により LGPL、GPL、またはその他の組み合わせになる場合があります。MP4Flow の MIT ライセンスは FFmpeg をライセンスするものではありません。インストールする FFmpeg ビルドに付属する利用条件と表示を確認してください。 + +## Noto Sans SC + +同梱の Noto Sans SC フォントファイルは、SIL Open Font License 1.1 の下で配布されています。完全なライセンス本文は [AppResources/OFL.txt](AppResources/OFL.txt) にあります。同梱アートワークとデモアセットの表示は [AppResources/ASSET_NOTICES.md](AppResources/ASSET_NOTICES.md) を参照してください。 + +## Tabler Icons Outline + +MP4Flow は、MIT License の下で提供される [`tabler/tabler-icons` v3.49.0](https://github.com/tabler/tabler-icons/tree/v3.49.0) の Tabler Icons Outline SVG から、選択した一部を使用しています。同梱するソースファイルと完全な帰属表示は [AppResources/ASSET_NOTICES.md](AppResources/ASSET_NOTICES.md) にあります。 + +## メディアの権利とブランド + +MP4Flow を使ってメディアを変換、編集、結合、保存、共有するために必要な権利および許諾は、あなたの責任で確認してください。MP4Flow は、第三者の動画、音声、字幕、商標、その他のコンテンツに関する権利を付与しません。 + +Apple、macOS、Homebrew、FFmpeg、GitHub などの名称は、各所有者の商標である場合があります。ここでの使用は説明目的のみであり、提携、後援、承認を意味するものではありません。 diff --git a/PRIVACY.ja.md b/PRIVACY.ja.md new file mode 100644 index 0000000..3bb65fd --- /dev/null +++ b/PRIVACY.ja.md @@ -0,0 +1,33 @@ +# プライバシー + +MP4Flow は、実行している Mac 上でメディアを処理するように設計されています。この文書は、このリポジトリで公開するオープンソースアプリの動作を説明するものであり、macOS、ブラウザ、Homebrew、または別途インストールした FFmpeg ビルドの動作を説明するものではありません。 + +## MP4Flow が扱うデータ + +- アプリは、追加または選択した動画ファイルとフォルダを読み取ります。キューの表示と変換に必要な範囲で、メモリ内のサムネイルを作成し、メディアのプロパティを読み取ることがあります。 +- macOS のユーザーデフォルトには、選択した表示言語のみを保存します。キュー、動画のパス、変換設定、診断情報、アカウント情報、メディアライブラリは保存しません。 +- 変換、解析、トリミング、クロップ、回転、結合は、ローカルの `ffmpeg` と `ffprobe` 実行ファイルを通じて行います。このアプリのリリースには、テレメトリ、分析、広告 SDK、メディアアップロードのコードは含まれません。 + +## 更新確認 + +- MP4Flow は、最新の安定版を確認するために `https://api.github.com/repos/ixiehao/MP4Flow/releases/latest` へアクセスできます。このリクエストには固定の MP4Flow User-Agent と、GitHub およびネットワーク接続で通常扱われるネットワークメタデータだけが含まれます。動画の内容、ファイルパス、変換設定、アカウント情報、利用データは含まれません。 +- 自動確認は初期状態で有効ですが、初回起動時はオフラインです。以降の起動では、MP4Flow は最大で1日1回だけ確認し、一時的な失敗時は1時間待機します。**設定** で自動確認を無効にしても、いつでも **ヘルプ > アップデートを確認** を利用できます。 +- 更新が見つかった場合も、選択したときに公開 GitHub リリースページを開くだけです。MP4Flow が自動で更新をダウンロード、インストール、実行することはありません。 + +## ローカルに作成されるファイル + +- 出力は初期設定では元ファイルの隣に、または選択したフォルダに書き込まれます。MP4Flow が元ファイルを削除または上書きすることはありません。 +- 処理中の出力は、意図した結果の隣に UUID 名の隠し `.partial.mp4` ファイルとして作成され、FFmpeg が成功した後にのみ最終位置へ移動します。通常の失敗またはキャンセル後には、アプリが削除を試みます。クラッシュ、強制終了、電源断、ストレージエラーでは一時ファイルが残ることがあります。変換が実行中でないことを確認してから安全に削除できます。 +- ロスレス結合では、システムの一時ディレクトリに UUID 名のマニフェストを短時間作成します。そこには選択した元ファイルのパスが入り、結合後に削除されます。強制終了時は macOS が一時ディレクトリを清掃するまで残ることがあります。 + +## メタデータとローカルツール + +MP4Flow は、生成する出力にコンテナレベルのメタデータやチャプターをコピーしないよう FFmpeg に指示します。コーデックに必要なストリーム情報や、別途インストールした FFmpeg ビルドが追加するデータは残ることがあるため、機密情報を消去する用途では出力を確認してください。クロップ、トリミング、変換は、人物や場所を特定し得る映像、音声、字幕、その他の内容が消えることを保証しません。 + +MP4Flow は、ユーザーが用意した FFmpeg を `/opt/homebrew/bin`、`/usr/local/bin`、`/opt/local/bin`、`/usr/bin` だけで探します。この実行ファイルのダウンロード、同梱、検証、更新は行いません。信頼できる提供元から FFmpeg を導入し、そのビルド固有のプライバシー、セキュリティ、ライセンス情報を確認してください。 + +**Homebrew を開く** を選択すると、既定のブラウザで `https://brew.sh/ja/` を開きます。これは明示的なブラウザ操作であり、そのリクエストやブラウザが扱うデータは MP4Flow のローカル処理の範囲外です。 + +## あなたが選べること + +非公開のメディアは、適切な macOS 権限を設定したフォルダに保管してください。出力を共有する前に、表示内容、音声、字幕、ファイル名、メタデータを確認してください。今後のリリースで、ここに記載した公開リリース確認を超えるデータ収集やネットワーク機能を追加する場合は、そのリリース前にこのポリシーを更新します。 diff --git a/README.ja.md b/README.ja.md new file mode 100644 index 0000000..285fe92 --- /dev/null +++ b/README.ja.md @@ -0,0 +1,108 @@ +# MP4Flow + +> **MP4 への変換を、とても簡単にする、無料・オープンソースのネイティブ macOS 動画変換アプリ。** + +[![最新リリース](https://img.shields.io/github/v/release/ixiehao/MP4Flow?display_name=tag&sort=semver&label=release)](https://github.com/ixiehao/MP4Flow/releases/latest) +[![macOS 13+](https://img.shields.io/badge/macOS-13%2B-000000?logo=apple&logoColor=white)](https://github.com/ixiehao/MP4Flow/releases/latest) +[![ライセンス](https://img.shields.io/github/license/ixiehao/MP4Flow)](LICENSE) +[![GitHub stars](https://img.shields.io/github/stars/ixiehao/MP4Flow?style=flat)](https://github.com/ixiehao/MP4Flow/stargazers) + +[MP4Flow をダウンロード](https://github.com/ixiehao/MP4Flow/releases/latest) · [公式サイト](https://ixiehao.github.io/MP4Flow/?lang=ja) · [English](README.md) · [简体中文](README.zh-CN.md) · [問題を報告](https://github.com/ixiehao/MP4Flow/issues/new/choose) + +MP4Flow は、一般的な動画ファイルを再生しやすい MP4 に変換し、すべての処理を **あなたの Mac 上で** 完結させます。複雑なコーデックの用語を、元の画質を保つ、容量を抑える、互換性を優先する、といった分かりやすい選択肢に置き換えました。トリミング、クロップ、回転、結合にも対応しています。アカウント登録も動画のアップロードも不要で、無料で使えます。 + +MP4 変換に加えて、動画の一部を切り出し、画面をクロップし、向きを回転できます。macOS に馴染む、速く、軽く、無料でオープンソースの動画変換ツールを目指しています。 + +![MP4Flow の機能デモ](docs/assets/mp4flow-demo.gif) + +*動画を追加し、必要なら簡単に編集して、Mac 上で変換します。* + +[ダウンロードとインストール](docs/DOWNLOAD.md) · [インストーラをビルド](docs/INSTALLER-BUILD.md) · [メディア回帰テスト](docs/MEDIA-REGRESSION.md) · [リリースチェックリスト](docs/RELEASE-CHECKLIST.md) · [プライバシー](PRIVACY.ja.md) · [セキュリティ](SECURITY.ja.md) + +## ダウンロードとインストール + +1. [GitHub の最新リリース](https://github.com/ixiehao/MP4Flow/releases/latest)を開き、`.dmg` と対応する `.sha256` ファイルをダウンロードします。 +2. DMG を開き、**MP4Flow** を **Applications** にドラッグします。 +3. FFmpeg と ffprobe を一度インストールしてから、アプリ内の **環境チェック** で準備ができていることを確認します。 + + ```sh + brew install ffmpeg + ``` + +リリースページとこのリポジトリが公式の配布場所です。開く前にダウンロードを確認したい場合は、[チェックサムの手順](docs/DOWNLOAD.md)を参照してください。 + +**対応する Mac:** macOS 13 Ventura 以降、Appleシリコンおよび Intel Mac。ハードウェアアクセラレーションの可否は、Mac と元動画のコーデックにより異なります。 + +## MP4Flow でできること + +| やりたいこと | MP4Flow の方法 | +| --- | --- | +| 動画を MP4 に変換 | スマート変換、H.264 互換、HEVC の容量節約、ソフトウェア互換モードを分かりやすく選べます。 | +| できるだけ速く処理 | MP4 を直接再格納できるときは再エンコードしません。対応するトリミングはストリームコピーを使います。 | +| すばやく編集 | 範囲をトリミング、画面をクロップ、90°/180° 回転、または複数の動画を結合してから書き出せます。 | +| 動画を手元に残す | メディア処理はすべて Mac 上で行います。アカウント、分析、動画アップロードサービスはありません。 | + +## 主な特徴 + +- **日本語、英語、簡体字中国語の UI** — 初回起動時はシステム言語に従い、アプリ内で切り替えられます。 +- **可能な限り高速** — MP4 の直接再格納とストリームコピーによるトリミングで再エンコードを回避。対応する H.264/HEVC の拡大縮小は Apple VideoToolbox を利用します。 +- **分かりやすい変換方法** — スマート変換、明瞭でコンパクト、元の画質を維持、H.264 互換、容量を抑える HEVC、ソフトウェア互換モードを選べます。 +- **解像度の制御** — 元の寸法を保つか、アスペクト比を維持したまま 1080p、720p、576p、480p に変換できます。拡大はキャンバスを大きくするもので、存在しない細部を復元するものではありません。 +- **実験的なスマート高画質拡大** — Appleシリコンかつ macOS 27 以降では、システムが報告する正確な倍率で VideoToolbox の超解像を利用できます。明示的な選択が必要で、クロップや回転との同時使用にはまだ対応していません。初回利用時にシステムモデルのダウンロードが必要な場合があります。 +- **シンプルな編集** — 範囲のトリミング、ドラッグと数値入力によるクロップ、90° または 180° の回転に対応します。 +- **2つの結合方法** — ストリームが一致する場合はロスレス結合、異なる場合は表示比率を引き伸ばさず、最大の元解像度に合わせた互換結合を使えます。 +- **信頼できるバッチ処理** — 進行状況、失敗項目の再試行、キャンセル、安全な一時出力、既存出力の非上書きを備えます。 +- **プライバシーを重視** — 処理は Mac 上にとどまります。出力ではコンテナメタデータとチャプターをコピーしない設定です。機密情報の編集では、共有前に書き出し結果を確認してください。 + +## 動作環境 + +- macOS 13 Ventura 以降 +- [FFmpeg](https://ffmpeg.org/) と `ffprobe` が `/opt/homebrew/bin`、`/usr/local/bin`、`/opt/local/bin`、または `/usr/bin` にインストール済み +- Appleシリコンまたは Intel Mac。ハードウェアアクセラレーションの可否は Mac と元動画のコーデックにより異なります +- **スマート高画質拡大(実験的)**:Appleシリコン、macOS 27 以降、かつ VideoToolbox が対応する元解像度と目標解像度の組み合わせが必要です。システムは初回使用時にモデルをダウンロードすることがあります。モデルは MP4Flow に同梱されず、MP4Flow が動画を開発者や第三者へ送信することもありません。 + +Homebrew で FFmpeg をインストールします。 + +```sh +brew install ffmpeg +``` + +## 使い方 + +1. MP4Flow を開き、動画ファイルを追加するかキューにドラッグします。 +2. 変換方法、画質/容量、解像度、出力先を選びます。 +3. 必要に応じて、待機中の項目でトリミング、クロップ、回転を行います。 +4. **変換を開始** を選択します。完了したファイルは Finder で表示できます。 + +結合するには、編集していない待機中のファイルを少なくとも2つ追加し、**結合** を選びます。ストリームのパラメータが異なる場合は、**互換結合** を選択してください。 + +## ソースからビルド + +```sh +git clone https://github.com/ixiehao/MP4Flow.git +cd MP4Flow +./Scripts/build-app.sh +open MP4Flow.app +``` + +生成されるアプリにはローカル開発用の ad-hoc 署名が付与されます。配布可能な DMG を作成するには、[インストーラ作成手順](docs/INSTALLER-BUILD.md)を参照してください。 + +## メディア回帰テスト + +FFmpeg をインストールした後、リリース前に合成メディアのテストスイートを実行できます。 + +```sh +./Scripts/run-media-regression.sh +``` + +このスクリプトはプロジェクト専用の小さなテスト素材を作成・削除し、H.264、HEVC、可変フレームレート、縦長動画、音声/字幕のバリエーション、回転、HDR シグナル、特殊な寸法、長時間スケジューリング、特殊なファイル名、破損した入力を確認します。公開リリース前には、[メディア回帰ゲート](docs/MEDIA-REGRESSION.md)にある実機テストも完了してください。 + +## 依存関係とライセンス + +- MP4Flow は Swift、SwiftUI、Apple のシステムフレームワークを使用します。 +- FFmpeg は外部の実行時依存関係です。アプリは FFmpeg を同梱、ダウンロード、またはライセンスするものではありません。ライセンスはインストールするビルドによって決まります。 +- スマート高画質拡大は、現在の Mac と macOS が対応するときに Apple のオンデバイス VideoToolbox フレームワークを使用します。利用可否、対応倍率、モデル配信はオペレーティングシステムによって管理されます。 +- 同梱する Noto Sans SC フォントは [SIL Open Font License 1.1](AppResources/OFL.txt) で提供されています。 +- アプリは、インターフェース用に [Tabler Icons Outline](https://github.com/tabler/tabler-icons) SVG の厳選した一部(v3.49.0)を同梱しています。実行時のネットワーク依存はなく、[MIT License](AppResources/ASSET_NOTICES.md)の下でローカル利用しています。 + +帰属表示は [NOTICE.ja.md](NOTICE.ja.md)、データの取り扱いは [PRIVACY.ja.md](PRIVACY.ja.md)、プロジェクトのライセンスは [LICENSE](LICENSE) を参照してください。 diff --git a/README.md b/README.md index 8cbf77a..7d66c37 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![License](https://img.shields.io/github/license/ixiehao/MP4Flow)](LICENSE) [![GitHub stars](https://img.shields.io/github/stars/ixiehao/MP4Flow?style=flat)](https://github.com/ixiehao/MP4Flow/stargazers) -[Download MP4Flow](https://github.com/ixiehao/MP4Flow/releases/latest) · [Website](https://ixiehao.github.io/MP4Flow/) · [中文说明](README.zh-CN.md) · [Report a problem](https://github.com/ixiehao/MP4Flow/issues/new/choose) +[Download MP4Flow](https://github.com/ixiehao/MP4Flow/releases/latest) · [Website](https://ixiehao.github.io/MP4Flow/) · [日本語](README.ja.md) · [中文说明](README.zh-CN.md) · [Report a problem](https://github.com/ixiehao/MP4Flow/issues/new/choose) MP4Flow converts common video files to playable MP4 **on your Mac**. It replaces codec jargon with clear choices: keep the original, save space, use a compatible format, trim, crop, rotate, or merge clips. Your videos are never uploaded, no account is required, and the app is free to use. @@ -44,7 +44,7 @@ The release page and this repository are the official download locations. If you ## Highlights -- **English and Simplified Chinese UI** — follows the system language on first launch and can be changed in the app. +- **English, Japanese, and Simplified Chinese UI** — follows the system language on first launch and can be changed in the app. - **Fast when possible** — direct MP4 remuxing and stream-copy trimming avoid re-encoding; supported H.264/HEVC scaling uses Apple VideoToolbox. - **Clear choices** — Smart Convert, Clear and Compact, Preserve Original Quality, device-compatible H.264, smaller HEVC, and a software fallback. - **Resolution control** — keep original dimensions or convert to 1080p, 720p, 576p, or 480p while preserving aspect ratio. Upscaling enlarges the canvas, not missing detail. diff --git a/README.zh-CN.md b/README.zh-CN.md index dea39ee..612b001 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -7,7 +7,7 @@ [![许可证](https://img.shields.io/github/license/ixiehao/MP4Flow)](LICENSE) [![GitHub stars](https://img.shields.io/github/stars/ixiehao/MP4Flow?style=flat)](https://github.com/ixiehao/MP4Flow/stargazers) -[下载 MP4Flow](https://github.com/ixiehao/MP4Flow/releases/latest) · [官方网站](https://ixiehao.github.io/MP4Flow/) · [English](README.md) · [反馈问题](https://github.com/ixiehao/MP4Flow/issues/new/choose) +[下载 MP4Flow](https://github.com/ixiehao/MP4Flow/releases/latest) · [官方网站](https://ixiehao.github.io/MP4Flow/) · [English](README.md) · [日本語](README.ja.md) · [反馈问题](https://github.com/ixiehao/MP4Flow/issues/new/choose) MP4Flow 将常见视频格式转换为易播放的 MP4,所有处理都在 **你的 Mac 本机** 完成。它把复杂的编码参数换成直观选择:保留原画、节省空间、兼容播放、剪辑、裁切、旋转和合并。无需登录、不会上传视频,且完全免费。 @@ -44,7 +44,7 @@ MP4Flow 将常见视频格式转换为易播放的 MP4,所有处理都在 ** ## 功能特点 -- **中英文界面**:首次启动跟随系统语言,也可在应用顶部手动切换。 +- **中文、英文、日文界面**:首次启动跟随系统语言,也可在应用顶部手动切换。 - **能快则快**:可直接封装 MP4;兼容时剪辑不重新编码;符合条件的 H.264/HEVC 缩放使用 Apple VideoToolbox。 - **好懂的转换选择**:智能转换、清晰又省空间、尽量保留原画、所有设备都能播放、节省更多空间、软件兼容模式。 - **分辨率控制**:保持原画,或转为 1080P、720P、576P、480P,并保持原视频比例。放大只改变尺寸,不能补回不存在的细节。 @@ -103,5 +103,6 @@ open MP4Flow.app - FFmpeg 是外部运行时依赖,应用不会打包、下载或为其授权;其许可证取决于你安装的构建版本。 - 智能增强放大在当前 Mac 与系统支持时调用 Apple VideoToolbox;可用性、支持倍率和模型交付均由操作系统控制。 - 随应用提供的 Noto Sans SC 字体使用 [SIL Open Font License 1.1](AppResources/OFL.txt)。 +- 应用为界面内置了 [Tabler Icons Outline](https://github.com/tabler/tabler-icons) SVG 的精选子集(v3.49.0);图标仅在本机使用、没有运行时网络依赖,并遵循 [MIT License](AppResources/ASSET_NOTICES.md)。 请查看 [NOTICE.md](NOTICE.md)、[PRIVACY.md](PRIVACY.md) 和 [LICENSE](LICENSE)。 diff --git a/SECURITY.ja.md b/SECURITY.ja.md new file mode 100644 index 0000000..3aebcd8 --- /dev/null +++ b/SECURITY.ja.md @@ -0,0 +1,20 @@ +# セキュリティポリシー + +## サポート対象のバージョン + +セキュリティ修正は、`main` ブランチ上の最新リリースに適用します。開発ビルド、未署名の DMG、ad-hoc 署名の DMG はサポート対象の配布成果物ではありません。 + +## 脆弱性の報告 + +悪用可能な脆弱性を公開 Issue で開示しないでください。最初の公開リリース前に、メンテナーは GitHub Private Vulnerability Reporting を有効にし、この文書に Security タブの報告リンクを掲載する必要があります。それまでは、メンテナーと合意した非公開チャネルを使い、影響を受けるバージョン、影響、再現手順、安全な概念実証を含めてください。必要かつ共有する権限がある場合を除き、非公開のメディアを送らないでください。 + +## セキュリティ境界 + +- MP4Flow は、文書化された固定の場所にあるローカルインストール済み `ffmpeg`/`ffprobe` だけを起動します。メディアパスはプロセス引数として渡し、シェルは呼び出しません。実行ファイルそのものはこのリポジトリの信頼境界外です。信頼できる提供元からインストールしてください。 +- 生成する出力は、UUID 名の一時ファイルに最初に書き込まれ、変換または結合が成功した後に最終位置へ移動します。既存の最終出力名を意図的に上書きすることはありません。 +- ロスレス結合では FFmpeg concat マニフェストを使います。このモードでは、ファイル名に改行が含まれる場合、マニフェスト構造を変えられないよう拒否します。 +- アプリはサンドボックス化されておらず、実行するユーザーと同じファイルシステムアクセスを必要とします。信頼できないメディアや信頼できない FFmpeg ビルドには、通常の macOS の注意を払ってください。 + +## リリース要件 + +公開配布の前に、Developer ID Application 証明書でビルドし、ネストしたコードをすべて署名し、DMG を公証し、公証チケットをステープルし、クリーンな Mac で Gatekeeper の動作を確認してください。完全なリリースゲートは [docs/RELEASE-CHECKLIST.md](docs/RELEASE-CHECKLIST.md) を参照してください。 diff --git a/Scripts/build-app.sh b/Scripts/build-app.sh index e40b7b3..13f9505 100755 --- a/Scripts/build-app.sh +++ b/Scripts/build-app.sh @@ -22,7 +22,7 @@ cp AppResources/AppIcon.icns "$APP_PATH/Contents/Resources/AppIcon.icns" cp AppResources/NotoSansSC-Variable.ttf "$APP_PATH/Contents/Resources/Fonts/NotoSansSC-Variable.ttf" cp AppResources/OFL.txt "$APP_PATH/Contents/Resources/Fonts/OFL.txt" cp AppResources/ASSET_NOTICES.md "$APP_PATH/Contents/Resources/ASSET_NOTICES.md" -cp -R AppResources/en.lproj AppResources/zh-Hans.lproj "$APP_PATH/Contents/Resources/" +cp -R AppResources/en.lproj AppResources/ja.lproj AppResources/zh-Hans.lproj "$APP_PATH/Contents/Resources/" # SwiftPM places the curated Tabler Outline SVGs in a resource bundle. Keep it # alongside the executable so AppKit can render the vectors at every scale. for resource_bundle in .build/release/*.bundle; do diff --git a/Scripts/validate-localizations.sh b/Scripts/validate-localizations.sh index 552fecd..19fe34b 100755 --- a/Scripts/validate-localizations.sh +++ b/Scripts/validate-localizations.sh @@ -6,18 +6,35 @@ cd "$PROJECT_DIR" plutil -lint AppResources/Info.plist plutil -lint AppResources/en.lproj/Localizable.strings +plutil -lint AppResources/ja.lproj/Localizable.strings plutil -lint AppResources/zh-Hans.lproj/Localizable.strings missing=0 while IFS= read -r key; do - if ! rg -F --quiet "\"$key\" =" AppResources/en.lproj/Localizable.strings; then - printf 'Missing English localization for dynamic key: %s\n' "$key" >&2 - missing=1 - fi + for language in en ja; do + if ! rg -F --quiet "\"$key\" =" "AppResources/$language.lproj/Localizable.strings"; then + printf 'Missing %s localization for dynamic key: %s\n' "$language" "$key" >&2 + missing=1 + fi + done done < <(rg -o 'L10n\.(text|format)\("[^"]+"' Sources/FastConvert \ | sed -E 's/.*L10n\.(text|format)\("([^"]+)".*/\2/' \ | sort -u) +# Base64 keeps the comparison line-oriented even when an interface key itself +# contains newlines (for example, the FFmpeg installation instructions). +while IFS= read -r encoded_key; do + [[ -n "$encoded_key" ]] || continue + printf 'Missing Japanese localization for interface key: ' >&2 + printf '%s' "$encoded_key" | base64 -D + printf '\n' >&2 + missing=1 +done < <( + comm -23 \ + <(plutil -convert json -o - AppResources/en.lproj/Localizable.strings | jq -r 'keys[] | @base64' | sort) \ + <(plutil -convert json -o - AppResources/ja.lproj/Localizable.strings | jq -r 'keys[] | @base64' | sort) +) + if [[ "$missing" -ne 0 ]]; then exit 1 fi diff --git a/Sources/FastConvert/AppLanguage.swift b/Sources/FastConvert/AppLanguage.swift index b74eb9e..27a5337 100644 --- a/Sources/FastConvert/AppLanguage.swift +++ b/Sources/FastConvert/AppLanguage.swift @@ -1,10 +1,11 @@ import Foundation /// The app language is chosen inside MP4Flow so people can switch between -/// Simplified Chinese and English without changing their macOS language. +/// Simplified Chinese, English, and Japanese without changing their macOS language. enum AppLanguage: String, CaseIterable, Identifiable, Sendable { case chinese = "zh-Hans" case english = "en" + case japanese = "ja" var id: String { rawValue } @@ -12,13 +13,17 @@ enum AppLanguage: String, CaseIterable, Identifiable, Sendable { switch self { case .chinese: "中文" case .english: "English" + case .japanese: "日本語" } } var locale: Locale { Locale(identifier: rawValue) } static var systemDefault: AppLanguage { - Locale.preferredLanguages.first?.lowercased().hasPrefix("zh") == true ? .chinese : .english + let identifier = Locale.preferredLanguages.first?.lowercased() ?? "" + if identifier.hasPrefix("zh") { return .chinese } + if identifier.hasPrefix("ja") { return .japanese } + return .english } private var localizationBundle: Bundle { diff --git a/Sources/FastConvert/FastConvertApp.swift b/Sources/FastConvert/FastConvertApp.swift index 4a3e161..2e6d1f2 100644 --- a/Sources/FastConvert/FastConvertApp.swift +++ b/Sources/FastConvert/FastConvertApp.swift @@ -1183,12 +1183,12 @@ private struct FailurePresentation { let solution: String init(message: String) { - let isSmartEnhance = message.contains("智能增强") || message.localizedCaseInsensitiveContains("smart enhance") + let isSmartEnhance = message.contains("智能增强") || message.contains("スマート高画質拡大") || message.localizedCaseInsensitiveContains("smart enhance") if isSmartEnhance { - if message.contains("裁切") || message.contains("旋转") || message.localizedCaseInsensitiveContains("crop") || message.localizedCaseInsensitiveContains("rotation") { + if message.contains("裁切") || message.contains("旋转") || message.contains("クロップ") || message.contains("回転") || message.localizedCaseInsensitiveContains("crop") || message.localizedCaseInsensitiveContains("rotation") { reason = L10n.text("智能增强不支持裁切或旋转") solution = L10n.text("请先使用普通转换,再剪辑或裁切。") - } else if message.contains("超时") || message.contains("未响应") || message.localizedCaseInsensitiveContains("timed out") || message.localizedCaseInsensitiveContains("did not respond") { + } else if message.contains("超时") || message.contains("未响应") || message.contains("タイムアウト") || message.contains("応答しません") || message.localizedCaseInsensitiveContains("timed out") || message.localizedCaseInsensitiveContains("did not respond") { reason = L10n.text("智能增强处理超时") solution = L10n.text("请降低目标分辨率后重试。") } else if message.contains("macOS 27") { @@ -1198,7 +1198,7 @@ private struct FailurePresentation { reason = L10n.text("此视频暂不支持智能增强") solution = L10n.text("请使用「智能转换」先转换为新文件,然后添加新文件重试。") } - } else if message.contains("未检测到视频流") || message.localizedCaseInsensitiveContains("no video stream") { + } else if message.contains("未检测到视频流") || message.contains("映像ストリームが見つかりません") || message.localizedCaseInsensitiveContains("no video stream") { reason = L10n.text("未检测到可用视频流") solution = L10n.text("请确认文件可播放,或重新导出后再试。") } else { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 473acd1..52e2437 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -5,7 +5,7 @@ MP4Flow is a small native SwiftUI application without a server. - `FastConvertApp.swift` contains the SwiftUI screens, editors, and interaction components. - `ConverterStore.swift` owns the serial queue, FFmpeg process lifecycle, progress parsing, media probing, output naming, and merge logic. - `AppLanguage.swift` resolves the selected language and exposes `L10n` for dynamic strings that SwiftUI cannot localize automatically. -- `AppResources/*.lproj/Localizable.strings` holds English and Simplified Chinese localizations. Chinese source strings are the Chinese fallback; English must include every user-facing key used dynamically. +- `AppResources/*.lproj/Localizable.strings` holds English, Japanese, and Simplified Chinese localizations. Chinese source strings are the Chinese fallback; English and Japanese include every user-facing key used dynamically, and CI verifies their coverage. - `Scripts/build-app.sh` produces an app bundle; `Scripts/package-dmg.sh` creates an installer from an isolated temporary build. The converter uses FFmpeg and ffprobe from the local computer. For supported H.264 and HEVC input without cropping, VideoToolbox keeps decode, scaling, rotation, and encoding in hardware memory. Rotation uses FFmpeg's `transpose_vt` filter when available and falls back to its software filter if a local FFmpeg build cannot run the hardware path. Queue work is serial by design: it avoids competing for CPU, disk I/O, and VideoToolbox resources during long batch operations. diff --git a/docs/DOWNLOAD.md b/docs/DOWNLOAD.md index 603c007..2ed4721 100644 --- a/docs/DOWNLOAD.md +++ b/docs/DOWNLOAD.md @@ -1,4 +1,4 @@ -# Download and install / 下载与安装 +# Download and install / ダウンロードとインストール / 下载与安装 ## English @@ -28,6 +28,34 @@ cat MP4Flow-.dmg.sha256 The two SHA-256 values must match. If they do not, delete the DMG and download it again from the [official Releases page](https://github.com/ixiehao/MP4Flow/releases/latest). +## 日本語 + +### MP4Flow をダウンロード + +1. [GitHub Releases](https://github.com/ixiehao/MP4Flow/releases/latest)から現在の `.dmg` をダウンロードします。同じページに対応する `.sha256` ファイルもあります。 +2. DMG を開き、**MP4Flow** を **Applications** にドラッグします。 +3. アプリが必要とする2つのローカル動画ツールをインストールします。 + + ```sh + brew install ffmpeg + ``` + +4. MP4Flow を開き、**環境チェック** を使います。`ffmpeg` と `ffprobe` の両方が見つかることと、利用可能なハードウェアエンコーダを確認できます。 + +MP4Flow は、Appleシリコンと Intel Mac の macOS 13 Ventura 以降に対応しています。処理はローカルで行われ、動画をアップロードしたりアカウントを要求したりすることはありません。 + +### ダウンロードを確認する(任意) + +リリースをダウンロードした後、ターミナルで次のコマンドを実行します。ファイル名はダウンロードしたバージョンに置き換えてください。 + +```sh +cd ~/Downloads +shasum -a 256 MP4Flow-.dmg +cat MP4Flow-.dmg.sha256 +``` + +2つの SHA-256 値は一致している必要があります。一致しない場合は DMG を削除し、[公式 Releases ページ](https://github.com/ixiehao/MP4Flow/releases/latest)からもう一度ダウンロードしてください。 + ## 中文 ### 下载 MP4Flow diff --git a/docs/GITHUB_METADATA.md b/docs/GITHUB_METADATA.md index 010046c..c06e7ae 100644 --- a/docs/GITHUB_METADATA.md +++ b/docs/GITHUB_METADATA.md @@ -3,19 +3,19 @@ Keep these settings in sync with the repository's **About** panel. They are part of the product's public download path, not optional decoration. -**Description:** `MP4Flow — Free, open-source macOS video converter to MP4. Process locally: convert, trim, crop, rotate, and merge. 不上传视频。` +**Description:** `MP4Flow — Free, open-source macOS video converter to MP4. Process locally: convert, trim, crop, rotate, and merge. No upload. ローカル処理。` **Homepage:** -**Topics:** `macos`, `macos-app`, `apple-silicon`, `swift`, `swiftui`, `ffmpeg`, `video-converter`, `video-transcoder`, `video-editing`, `video-processing`, `mp4`, `h264`, `hevc`, `videotoolbox`, `local-first`, `privacy`, `open-source`, `chinese` +**Topics:** `macos`, `macos-app`, `apple-silicon`, `swift`, `swiftui`, `ffmpeg`, `video-converter`, `video-transcoder`, `video-editing`, `video-processing`, `mp4`, `h264`, `hevc`, `videotoolbox`, `local-first`, `privacy`, `open-source`, `chinese`, `japanese` ## Public project surfaces - Keep the README's first screen focused on the value proposition, latest release, system requirement, and official download path. -- Keep [README.md](../README.md) and [README.zh-CN.md](../README.zh-CN.md) - equivalent in scope. English aids global discovery; Chinese serves the - existing primary user base. +- Keep [README.md](../README.md), [README.ja.md](../README.ja.md), and + [README.zh-CN.md](../README.zh-CN.md) equivalent in scope. English aids + global discovery; Japanese and Chinese serve native-language users. - Link the latest release rather than a versioned DMG in README text. This avoids leaving visitors on a stale installer after the next release. - Attach a `.dmg` and matching `.sha256` file to every stable release. Do not diff --git a/docs/RELEASE-CHECKLIST.md b/docs/RELEASE-CHECKLIST.md index 252487e..ac70215 100644 --- a/docs/RELEASE-CHECKLIST.md +++ b/docs/RELEASE-CHECKLIST.md @@ -7,8 +7,8 @@ Use this checklist for each public MP4Flow release. It is a release gate, not a - [x] Create the canonical GitHub repository and replace the clone URL in both README files. - [ ] Enable GitHub Private Vulnerability Reporting and replace the reporting instruction in [SECURITY.md](../SECURITY.md) with the repository's private reporting link. - [ ] Confirm the repository description, topics, licence, default branch protection, and release notes follow [GITHUB_METADATA.md](GITHUB_METADATA.md). -- [ ] Confirm the repository homepage, bilingual README download links, issue chooser, and social preview still point to the current official project surfaces. -- [ ] Confirm the latest Release has a human-readable title, bilingual user-facing notes, a signed/notarized DMG, and a matching SHA-256 file. +- [ ] Confirm the repository homepage, trilingual README download links, issue chooser, and social preview still point to the current official project surfaces. +- [ ] Confirm the latest Release has a human-readable title, English, Japanese, and Simplified Chinese user-facing notes, a signed/notarized DMG, and a matching SHA-256 file. - [ ] Check that `.gitignore` is effective and that the branch contains no signing certificates, provisioning profiles, private keys, `.env` files, test media, DMGs, or build products. - [ ] Review issues, pull requests, screenshots, and logs for private file paths, personal data, or unlicensed media. @@ -37,7 +37,7 @@ Use this checklist for each public MP4Flow release. It is a release gate, not a - [ ] Re-sign the app and every nested executable with a Developer ID Application certificate. Verify with `codesign --verify --deep --strict --verbose=2 MP4Flow.app`. - [ ] Submit the final DMG for Apple notarization, staple the ticket, then assess it on a clean Mac with `spctl --assess --type open --context context:primary-signature `. - [ ] Generate and publish the SHA-256 file for the exact notarized DMG. Treat a checksum as integrity information, not as a signing substitute. -- [ ] Install the final DMG on a clean Intel Mac and Apple-silicon Mac when both architectures are claimed. Test first launch, Gatekeeper, English, Simplified Chinese, FFmpeg missing, conversion, trim, crop, rotation, and both merge modes. +- [ ] Install the final DMG on a clean Intel Mac and Apple-silicon Mac when both architectures are claimed. Test first launch, Gatekeeper, English, Japanese, Simplified Chinese, FFmpeg missing, conversion, trim, crop, rotation, and both merge modes. ## Release notes and support diff --git a/website/app.js b/website/app.js index 670942a..de1b15c 100644 --- a/website/app.js +++ b/website/app.js @@ -21,7 +21,8 @@ const copy = { footerTagline: "智能转换、剪切、裁切、旋转,全部在 Mac 本地完成。", footerGithub: "GitHub", footerPrivacy: "隐私", footerLicense: "MIT 许可证", pageTitle: "MP4Flow|智能转换、剪切、裁切、旋转的 macOS 视频转 MP4 工具", pageDescription: "MP4Flow:免费开源的原生 macOS 视频转 MP4 工具。智能转换、剪切、裁切、旋转,全部本地完成。", ogTitle: "MP4Flow|智能转换、剪切、裁切、旋转,全部在 Mac 本地完成", ogDescription: "免费开源的原生 macOS 视频转 MP4 工具。极速处理、不上传视频、不用登录。", ogLocale: "zh_CN", socialImageAlt: "MP4Flow 真实软件工作界面,展示在 Mac 本地完成的视频转换", - installEyebrow: "开始转换前", installTitle: "安装 FFmpeg", installIntro: "MP4Flow 使用 FFmpeg 与 ffprobe 读取和转换视频。通过 Homebrew 安装时,两者会一并安装。", installStepOne: "打开「终端」应用。", installStepTwo: "输入以下命令:", installStepThree: "安装完成后,重新打开 MP4Flow。", installHelp: "还没有 Homebrew?请先访问 brew.sh 安装。" + installEyebrow: "开始转换前", installTitle: "安装 FFmpeg", installIntro: "MP4Flow 使用 FFmpeg 与 ffprobe 读取和转换视频。通过 Homebrew 安装时,两者会一并安装。", installStepOne: "打开「终端」应用。", installStepTwo: "输入以下命令:", installStepThree: "安装完成后,重新打开 MP4Flow。", installHelp: "还没有 Homebrew?请先访问 brew.sh 安装。", + homeLabel: "MP4Flow 首页", navLabel: "主导航", languagePickerLabel: "语言选择", featureListLabel: "MP4Flow 核心功能", stageLabel: "MP4Flow 应用演示", closeInstall: "关闭安装说明", privacyURL: "https://github.com/ixiehao/MP4Flow/blob/main/PRIVACY.md" }, en: { navTools: "Four tools", navWorkflow: "How it works", navDownload: "Download", @@ -45,14 +46,44 @@ const copy = { footerTagline: "Smart Convert, trim, crop, and rotate — all on your Mac.", footerGithub: "GitHub", footerPrivacy: "Privacy", footerLicense: "MIT License", pageTitle: "MP4Flow — Smart Convert, Trim, Crop & Rotate Video to MP4 on macOS", pageDescription: "MP4Flow is a free, open-source native macOS video-to-MP4 converter with Smart Convert, trim, crop, rotate, and local processing.", ogTitle: "MP4Flow — Smart Convert, Trim, Crop & Rotate Video on Mac", ogDescription: "A free, open-source native macOS video-to-MP4 app. Fast where possible, processed locally, with no account or upload.", ogLocale: "en_US", socialImageAlt: "MP4Flow's real macOS workspace showing video processed locally", - installEyebrow: "BEFORE YOU CONVERT", installTitle: "Install FFmpeg", installIntro: "MP4Flow uses FFmpeg and ffprobe to read and convert video. Installing with Homebrew adds both tools.", installStepOne: "Open the Terminal app.", installStepTwo: "Run this command:", installStepThree: "When it finishes, reopen MP4Flow.", installHelp: "Need Homebrew first? Install it from brew.sh." + installEyebrow: "BEFORE YOU CONVERT", installTitle: "Install FFmpeg", installIntro: "MP4Flow uses FFmpeg and ffprobe to read and convert video. Installing with Homebrew adds both tools.", installStepOne: "Open the Terminal app.", installStepTwo: "Run this command:", installStepThree: "When it finishes, reopen MP4Flow.", installHelp: "Need Homebrew first? Install it from brew.sh.", + homeLabel: "MP4Flow home", navLabel: "Primary navigation", languagePickerLabel: "Language", featureListLabel: "Core MP4Flow features", stageLabel: "MP4Flow app demonstration", closeInstall: "Close installation guide", privacyURL: "https://github.com/ixiehao/MP4Flow/blob/main/PRIVACY.md" + }, + ja: { + navTools: "4つの機能", navWorkflow: "使い方", navDownload: "ダウンロード", + eyebrow: "MP4FLOW FOR MAC", heroTitle: "MP4へ変換。
もっと簡単に。", + heroIntro: "スマート変換、トリミング、クロップ、回転。よく使う動画処理を、軽くて分かりやすい Mac アプリにまとめました。", + heroToolOne: "スマート変換", heroToolTwo: "トリミング", heroToolThree: "クロップ", heroToolFour: "回転", + download: "無料でダウンロード", exploreTools: "4つの機能を見る", heroSystemNote: "macOS 13+ · AppleシリコンとIntel", installGuide: "FFmpegをインストール", + stageLive: "このMacで処理中", stageStatus: "MP4Flow の作業画面", stageCaption: "実際の MP4Flow の作業画面:動画を追加し、処理方法を選び、この Mac で書き出します。", stageAlt: "MP4Flow がこの Mac 上で動画を変換している実際の画面", + proofOneTitle: "可能な限り高速", proofOneBody: "可能なときは再エンコードせずに直接再格納します。エンコードが必要な場合は、利用できる Apple のハードウェア機能を優先します。", + proofTwoTitle: "Mac ネイティブ", proofTwoBody: "macOS 13+、Appleシリコン、Intel Mac 向けに設計。軽く、作業に集中できるインターフェースです。", + proofThreeTitle: "ローカル処理", proofThreeBody: "アカウント登録もアップロードも不要です。動画の読み込み、処理、書き出しはすべてこの Mac で行います。", + toolsEyebrow: "FOUR TOOLS. ONE CLEAR WORKFLOW.", toolsTitle: "変換だけではない。
4つの基本機能。", toolsIntro: "どの機能も、少ない設定で理解しやすく、すぐ完了できるように設計しています。編集したいときだけ編集し、それ以外は変換するだけです。", + toolOneTitle: "スマート変換", toolOneBody: "適切な MP4 の処理方法を選び、可能なときは直接再格納します。互換性が必要な場合にだけ、ハードウェアまたはソフトウェアでエンコードします。", toolOneDetail: "互換性 · 明瞭 · コンパクト", + toolTwoTitle: "トリミング", toolTwoBody: "範囲を指定し、開始点と終了点を前後に細かく調整して、必要な場面だけを書き出します。", toolTwoDetail: "範囲を正確に選択", + toolThreeTitle: "クロップ", toolThreeBody: "クロップ枠をドラッグするか、位置とサイズを数値で入力します。アスペクト比の選択で一般的な画角も簡単に設定できます。", toolThreeDetail: "ドラッグ · 数値 · アスペクト比", + toolFourTitle: "回転", toolFourBody: "向きが合わない映像を正しい方向に直します。表示比率を保ったまま 90° または 180° 回転できます。", toolFourDetail: "90° / 180° · 引き伸ばさない", + workflowEyebrow: "FROM FILE TO MP4", workflowTitle: "3ステップで動画を処理。", stepOneTitle: "動画を追加", stepOneBody: "ファイルをドロップするか、Finder から素材を選びます。", + stepTwoTitle: "変換または編集", stepTwoBody: "スマート変換を選ぶか、開始前にトリミング、クロップ、回転を行います。", stepThreeTitle: "このMacで書き出し", stepThreeBody: "分かりやすい進行状況を確認し、完了したファイルを Finder で開きます。", + downloadEyebrow: "FREE. OPEN SOURCE. ON YOUR MAC.", downloadTitle: "最初の1本から。
動画処理をもっと簡単に。", downloadBody: "最新版をダウンロード。MP4Flow は無料かつオープンソースで、動画はあなたの Mac にとどまります。", + getLatest: "最新版を入手", viewSource: "ソースコードを見る ↗", downloadNote: "macOS 13+ · FFmpeg と ffprobe が必要 · AppleシリコンとIntel対応", + footerTagline: "スマート変換、トリミング、クロップ、回転。すべて Mac 上で完結します。", footerGithub: "GitHub", footerPrivacy: "プライバシー", footerLicense: "MIT ライセンス", + pageTitle: "MP4Flow|macOSで動画をMP4に変換・トリミング・クロップ・回転", pageDescription: "MP4Flow は、スマート変換、トリミング、クロップ、回転を備えた、無料・オープンソースのネイティブ macOS 動画 MP4 変換アプリです。すべてローカルで処理します。", + ogTitle: "MP4Flow|Macで動画をスマート変換、トリミング、クロップ、回転", ogDescription: "無料・オープンソースのネイティブ macOS 動画 MP4 変換アプリ。可能な限り高速で、アップロードもアカウント登録も不要です。", ogLocale: "ja_JP", socialImageAlt: "Mac上でローカル処理するMP4Flowの実際の作業画面", + installEyebrow: "変換を始める前に", installTitle: "FFmpegをインストール", installIntro: "MP4Flow は動画の読み込みと変換に FFmpeg と ffprobe を使用します。Homebrew でインストールすると、両方のツールが追加されます。", installStepOne: "「ターミナル」アプリを開きます。", installStepTwo: "次のコマンドを実行します:", installStepThree: "完了したら MP4Flow を開き直します。", installHelp: "Homebrew がまだない場合は、brew.sh から先にインストールしてください。", + homeLabel: "MP4Flow ホーム", navLabel: "メインナビゲーション", languagePickerLabel: "言語選択", featureListLabel: "MP4Flow の主な機能", stageLabel: "MP4Flow アプリのデモ", closeInstall: "インストールガイドを閉じる", privacyURL: "https://github.com/ixiehao/MP4Flow/blob/main/PRIVACY.ja.md" } }; -const languageButton = document.querySelector(".language-switch"); -const languageLabel = document.querySelector("#language-label"); +const languageOptions = document.querySelectorAll(".language-option"); const heroAppScreen = document.querySelector("#hero-app-screen"); -let language = navigator.language.toLowerCase().startsWith("zh") ? "zh" : "en"; +const privacyLink = document.querySelector("#privacy-link"); +const requestedLanguage = new URLSearchParams(window.location.search).get("lang"); +const browserLanguage = navigator.language.toLowerCase(); +let language = ["zh", "en", "ja"].includes(requestedLanguage) + ? requestedLanguage + : browserLanguage.startsWith("zh") ? "zh" : browserLanguage.startsWith("ja") ? "ja" : "en"; function setMeta(selector, value) { const meta = document.querySelector(selector); @@ -62,7 +93,7 @@ function setMeta(selector, value) { function applyLanguage(nextLanguage) { language = nextLanguage; const translations = copy[language]; - document.documentElement.lang = language === "zh" ? "zh-CN" : "en"; + document.documentElement.lang = language === "zh" ? "zh-CN" : language; document.title = translations.pageTitle; setMeta('meta[name="description"]', translations.pageDescription); setMeta('meta[property="og:title"]', translations.ogTitle); @@ -72,7 +103,7 @@ function applyLanguage(nextLanguage) { setMeta('meta[name="twitter:title"]', translations.ogTitle); setMeta('meta[name="twitter:description"]', translations.ogDescription); setMeta('meta[name="twitter:image:alt"]', translations.socialImageAlt); - heroAppScreen.src = language === "zh" ? heroAppScreen.dataset.srcZh : heroAppScreen.dataset.srcEn; + heroAppScreen.src = language === "zh" ? heroAppScreen.dataset.srcZh : language === "ja" ? heroAppScreen.dataset.srcJa : heroAppScreen.dataset.srcEn; heroAppScreen.alt = translations.stageAlt; document.querySelectorAll("[data-i18n]").forEach((element) => { element.innerHTML = translations[element.dataset.i18n]; @@ -80,11 +111,22 @@ function applyLanguage(nextLanguage) { document.querySelectorAll("[data-i18n-html]").forEach((element) => { element.innerHTML = translations[element.dataset.i18nHtml]; }); - languageLabel.textContent = language === "zh" ? "EN" : "中文"; - languageButton.setAttribute("aria-label", language === "zh" ? "Switch to English" : "切换到中文"); + document.querySelectorAll("[data-i18n-aria-label]").forEach((element) => { + element.setAttribute("aria-label", translations[element.dataset.i18nAriaLabel]); + }); + privacyLink.href = translations.privacyURL; + languageOptions.forEach((option) => { + const isCurrent = option.dataset.language === language; + option.setAttribute("aria-pressed", String(isCurrent)); + option.tabIndex = isCurrent ? -1 : 0; + }); + const url = new URL(window.location.href); + if (language === "zh") url.searchParams.delete("lang"); + else url.searchParams.set("lang", language); + window.history.replaceState(null, "", `${url.pathname}${url.search}${url.hash}`); } -languageButton.addEventListener("click", () => applyLanguage(language === "zh" ? "en" : "zh")); +languageOptions.forEach((option) => option.addEventListener("click", () => applyLanguage(option.dataset.language))); const installDialog = document.querySelector("#install-dialog"); document.querySelector("#install-guide-trigger").addEventListener("click", () => installDialog.showModal()); document.querySelector("#install-dialog-close").addEventListener("click", () => installDialog.close()); diff --git a/website/assets/mp4flow-working-screen-ja.png b/website/assets/mp4flow-working-screen-ja.png new file mode 100644 index 0000000..6ce1d39 Binary files /dev/null and b/website/assets/mp4flow-working-screen-ja.png differ diff --git a/website/index.html b/website/index.html index d76ef7b..4b7845d 100644 --- a/website/index.html +++ b/website/index.html @@ -8,11 +8,16 @@ + + + + + @@ -29,7 +34,7 @@ MP4Flow|智能转换、剪切、裁切、旋转的 macOS 视频转 MP4 工具 - + + diff --git a/website/styles.css b/website/styles.css index 1020753..02e9a59 100644 --- a/website/styles.css +++ b/website/styles.css @@ -11,7 +11,7 @@ --white: #ffffff; color: var(--ink); background: var(--white); - font-family: Inter, "SF Pro Display", "PingFang SC", "Noto Sans SC", system-ui, -apple-system, BlinkMacSystemFont, sans-serif; + font-family: Inter, "SF Pro Display", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "PingFang SC", "Noto Sans SC", system-ui, -apple-system, BlinkMacSystemFont, sans-serif; font-synthesis: none; } @@ -28,13 +28,16 @@ h1, h2, h3, p { margin-top: 0; } .wordmark-icon { display: block; width: 34px; height: 34px; flex: 0 0 auto; border-radius: 9px; box-shadow: 0 5px 12px rgba(22, 77, 187, .18); } .wordmark-name span { color: var(--blue); } nav { display: flex; align-items: center; gap: 25px; margin-left: auto; } -nav a, .language-switch { color: #52627f; font-size: .88rem; font-weight: 720; } +nav a, .language-picker { color: #52627f; font-size: .88rem; font-weight: 720; } nav a { transition: color .18s ease; } nav a:hover { color: var(--blue); } -.language-switch { min-width: 78px; min-height: 38px; display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 0 12px 0 10px; border: 1px solid #d7e1ef; border-radius: 999px; color: #425574; background: rgba(255, 255, 255, .78); box-shadow: 0 1px 2px rgba(15, 37, 79, .04); cursor: pointer; transition: color .2s ease, border-color .2s ease, box-shadow .2s ease, transform .2s ease; } +.language-picker { min-height: 38px; display: inline-flex; align-items: center; gap: 2px; padding: 3px 4px 3px 8px; border: 1px solid #d7e1ef; border-radius: 999px; color: #425574; background: rgba(255, 255, 255, .82); box-shadow: 0 1px 2px rgba(15, 37, 79, .04); } .language-globe { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; } -.language-switch:hover { border-color: #aac1ee; color: var(--blue); box-shadow: 0 7px 16px rgba(36, 104, 242, .13); transform: translateY(-1px); } -.language-switch:focus-visible, .button:focus-visible, nav a:focus-visible, .install-guide-trigger:focus-visible, .dialog-close:focus-visible { outline: 3px solid rgba(36, 104, 242, .28); outline-offset: 3px; } +.language-picker:focus-within { border-color: #aac1ee; box-shadow: 0 7px 16px rgba(36, 104, 242, .13); } +.language-option { min-width: 29px; height: 30px; padding: 0 6px; border: 0; border-radius: 999px; color: #596a87; background: transparent; cursor: pointer; font: 780 .72rem/1 Inter, "SF Pro Display", "PingFang SC", "Hiragino Sans", system-ui, sans-serif; transition: color .18s ease, background-color .18s ease, box-shadow .18s ease; } +.language-option:hover { color: var(--blue); background: #edf3ff; } +.language-option[aria-pressed="true"] { color: #fff; background: var(--blue); box-shadow: 0 2px 6px rgba(36, 104, 242, .28); cursor: default; } +.language-option:focus-visible, .button:focus-visible, nav a:focus-visible, .install-guide-trigger:focus-visible, .dialog-close:focus-visible { outline: 3px solid rgba(36, 104, 242, .28); outline-offset: 3px; } .hero { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); align-items: center; gap: clamp(42px, 5.5vw, 70px); min-height: 590px; padding: 55px 0 65px; } .hero-copy, .hero-stage, .tools-section > *, .workflow > * { min-width: 0; } @@ -115,8 +118,8 @@ footer { min-height: 105px; display: flex; align-items: center; gap: 23px; borde .tools-section { padding: 76px 0 50px; }.section-heading > p:not(.eyebrow) { max-width: 520px; }.workflow { gap: 40px; padding: 84px 0 78px; }.download-panel { margin-bottom: 62px; } } @media (max-width: 520px) { - .site-header, main, footer { width: calc(100% - 28px); }.site-header { padding-top: max(16px, env(safe-area-inset-top)); }.wordmark { font-size: 1.34rem; }.wordmark-icon { width: 30px; height: 30px; border-radius: 8px; }.language-switch { min-width: 72px; min-height: 34px; }.language-switch .language-globe { width: 15px; height: 15px; } + .site-header, main, footer { width: calc(100% - 28px); }.site-header { padding-top: max(16px, env(safe-area-inset-top)); }.wordmark { font-size: 1.34rem; }.wordmark-icon { width: 30px; height: 30px; border-radius: 8px; }.language-picker { min-height: 34px; padding-left: 6px; }.language-picker .language-globe { width: 15px; height: 15px; }.language-option { min-width: 27px; height: 27px; padding: 0 5px; font-size: .67rem; } nav a { font-size: .76rem; }.hero { gap: 34px; padding: 43px 0 49px; }.eyebrow { margin-bottom: 12px; font-size: .67rem; }.hero-intro { margin-bottom: 20px; font-size: 1rem; }.hero-tools { gap: 6px; }.hero-tools li { padding: 6px 9px; font-size: .71rem; }.hero-actions { align-items: stretch; margin-top: 24px; }.button { width: 100%; }.hero-stage { border-radius: 17px; }.hero-stage-bar { min-height: 36px; padding: 0 12px; font-size: .64rem; }.stage-caption { display: none; } h1 { font-size: clamp(2.36rem, 11.8vw, 3.28rem); letter-spacing: -.058em; } h2 { font-size: clamp(2.18rem, 10vw, 3rem); }.proof-strip { margin-bottom: 55px; border-radius: 15px; }.proof-strip article { padding: 23px 21px; }.proof-strip h2 { font-size: 1.18rem; }.proof-kicker { margin-bottom: 17px; }.tools-section { padding: 60px 0 44px; }.tool-grid { grid-template-columns: 1fr; }.tool-card { min-height: 222px; padding: 23px; }.tool-card h3 { margin-top: 34px; }.tool-card p { margin-bottom: 14px; }.workflow { gap: 32px; padding: 67px 0 60px; }.workflow li { grid-template-columns: 35px minmax(0, 1fr); gap: 12px; padding: 19px 0; }.download-panel { margin: 0 -1px 50px; padding: 60px 22px 56px; border-radius: 18px; }.download-panel h2 { font-size: clamp(2.1rem, 9.5vw, 2.8rem); }.download-note { max-width: 280px; margin-right: auto; margin-left: auto; } footer { min-height: 0; flex-direction: column; align-items: flex-start; gap: 13px; padding: 28px 0 34px; } footer p { max-width: 280px; font-size: .78rem; line-height: 1.6; }.footer-links { width: auto; flex-wrap: wrap; row-gap: 9px; margin-left: 0; }.install-dialog { width: calc(100% - 24px); padding: 22px; }.install-dialog h2 { font-size: 1.85rem; } } -@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; }.button, .tool-card, .language-switch { transition: none; } } +@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; }.button, .tool-card, .language-option { transition: none; } }