本仓库是一个本地单用户字幕翻译工具,专注“翻译已有字幕文件”。
This repository is a local single-user subtitle translation tool focused on translating existing subtitle files.
このリポジトリは、既存字幕ファイルの翻訳に特化したローカル単一ユーザー向けツールです。
本 README 按以下顺序提供三种语言说明:
- 中文(本章节)
- English
- 日本語
如果你只想快速用起来,直接看:
这是一个“字幕文件翻译器”,不是“视频处理器”。
项目目标:
- 上传已有字幕文件(例如
.srt、.ass) - 翻译为目标语言(中/英/日)
- 预览结果并导出字幕文件
- 尽可能保留原始结构、时间轴、标签和编码安全
明确不做:
- 不做视频抽轨
- 不做 OCR
- 不做封装解析(mkv/mp4 内嵌字幕提取)
- 不做图片字幕识别
- 本地网页 UI(Streamlit)
- UI 支持三语言切换:
中文 / 日本語 / English - 支持中英日互译,源语言可自动识别
- 多 Provider 翻译通道(官方 API + 无 key 方案)
- 连接测试按钮(先验证 API 再翻译)
- LLM Provider 支持“连接后拉取模型列表”
- 可选术语表(CSV)
- 本地翻译记忆库(SQLite)
- API Key 本地加密保存与自动回填
- 编码安全导出:原编码优先,不可写回自动切
UTF-8 BOM
正式支持(稳定):
SRTASSSSAWebVTT (VTT)
尽力支持(best effort):
MicroDVD (.sub)TMP (.txt)TTML (.ttml)SAMI (.smi/.sami)
明确排除:
- 图片字幕:
PGS/SUP、VobSub (.idx/.sub)等 - 其他非文本字幕
说明:
MicroDVD文件如果缺少 FPS 元信息,工具会明确报错并停止(避免错误时间轴)。
- Python
3.13+ - 包管理与运行:
uv - Web UI:
streamlit - 字幕读写:
pysubs2 - 网络请求:
httpx - LLM 接口:
openaiPython SDK(兼容 OpenAI 风格网关) - Google 无 key 方案:
deep-translator - 编码检测:
charset-normalizer - 本地存储:
sqlite3(翻译记忆)+cryptography(API key 加密)
- Windows 10/11(当前提供了 Windows 一键启动脚本)
- Python 3.13 或更高版本
- 已安装
uv
安装 uv(官方文档):
https://docs.astral.sh/uv/
uv sync --all-groupsCopy-Item .env.example .env你可以在 .env 配置 key,也可以在 UI 里直接填并“加密保存”。
常见最小配置示例(DeepSeek):
DEEPSEEK_API_KEY=你的key
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-chat方式 A(命令行):
uv run streamlit run app.py打开:
http://localhost:8501
你可以不用每次开终端输入命令。
文件:start_subtitle_translator.bat
特点:
- 自动检查
uv - 首次自动
uv sync --all-groups - 若没有
.env则自动从.env.example复制 - 自动打开浏览器
- 保留终端日志窗口,便于排错
文件:start_subtitle_translator_silent.vbs
特点:
- 不弹终端窗口
- 后台启动 Streamlit
- 自动打开浏览器
demo1_qwe/
├─ app.py
├─ .env.example
├─ start_subtitle_translator.bat
├─ start_subtitle_translator_silent.vbs
├─ .streamlit/config.toml
├─ src/subtitle_translator/
│ ├─ ui.py # 页面与交互流程
│ ├─ translator.py # Provider 适配层 + 批量翻译逻辑
│ ├─ subtitle_io.py # 字幕解析/回写/标签保护
│ ├─ encoding.py # 编码识别与换行归一
│ ├─ glossary.py # 术语表解析
│ ├─ memory.py # 翻译记忆 SQLite
│ ├─ secret_store.py # API key 加密存储
│ ├─ config.py # 环境配置与路径
│ └─ models.py # 核心数据结构
└─ .data/
├─ translation_memory.sqlite3
├─ secret_store.enc
└─ secret_store.key
- 左侧先选 UI 语言(中文/日本語/English)
- 在左侧 Provider 区选择翻译通道
- 填 API key(或使用无 key Provider)
- 点击“测试连接”确认可用
- 上传字幕文件
- 选择源语言和目标语言
- (可选)上传术语表 CSV
- 点击“开始翻译”
- 在预览表检查译文
- 下载导出字幕
OpenAIGoogle Gemini (OpenAI-compatible)DeepSeekQwen / DashScope (CN)Qwen / DashScope (Intl)Zhipu GLMCustom OpenAI-compatible
行为说明:
- 先“测试连接”后可拉取实时模型列表
- 也支持手动输入模型名
- Custom 通道必须填写 Base URL
DeepL API
Google Translate (deep-translator, no key)
注意:
- 无 key 通道方便测试,但稳定性和可持续性不如官方 API。
OPENAI_API_KEYOPENAI_BASE_URLOPENAI_MODELGEMINI_API_KEYGEMINI_BASE_URLGEMINI_MODELDEEPSEEK_API_KEYDEEPSEEK_BASE_URLDEEPSEEK_MODELDASHSCOPE_API_KEYDASHSCOPE_BASE_URLDASHSCOPE_MODELDASHSCOPE_INTL_API_KEYDASHSCOPE_INTL_BASE_URLDASHSCOPE_INTL_MODELZHIPU_API_KEYZHIPU_BASE_URLZHIPU_MODELCUSTOM_LLM_API_KEYCUSTOM_LLM_BASE_URLCUSTOM_LLM_MODELDEEPL_API_KEYDEEPL_API_BASE_URL
APP_DB_PATH
翻译记忆数据库路径(默认.data/translation_memory.sqlite3)APP_SECRET_STORE_PATH
加密 API key 数据文件路径(默认.data/secret_store.enc)APP_SECRET_KEY_PATH
加密密钥文件路径(默认.data/secret_store.key)APP_BATCH_SIZE
批量翻译条数(默认20)APP_MAX_FILE_SIZE_MB
单文件大小上限 MB(默认5)APP_REQUEST_TIMEOUT_SECONDS
请求超时秒数(默认60)
文件必须是 CSV,列名固定:
source,target,notes
字幕,subtitle,UI term
姐姐,sister,dialog context规则:
source:源术语target:目标术语notes:可选备注
读取:
- 尝试 BOM
- 编码检测
- 回退策略(保证最大兼容)
写出:
- 优先保持原编码与原换行风格
- 如果译文无法安全写回原编码,自动改为
utf-8-sig(UTF-8 BOM)
标签保护:
- 保留 HTML 标签
- 保留 ASS/SSA 样式控制片段
- 使用占位符机制避免模型破坏控制标记
你在 UI 中可选择“记住 API 密钥(加密保存)”。
实现逻辑:
- 明文不会直接写入配置文件
- 使用
cryptography.fernet加密后写入secret_store.enc - 密钥保存在
secret_store.key
注意事项:
secret_store.enc和secret_store.key需要同时保留- 如果
secret_store.key丢失,历史加密内容无法解密 - 建议将
.data/目录加入备份或按需清理
用途:
- 同句重复时优先复用历史译文,减少请求次数和成本
存储:
APP_DB_PATH对应 SQLite 数据库
行为:
- 精确匹配复用
- 与 provider + model + 语言方向绑定
- 文件名:
原文件名.目标语言代码.原扩展名 - 保持原格式导出(不跨格式转换)
- 保持时间轴、段落顺序与换行风格
- 导出时显示实际编码(便于排查乱码)
- 强制刷新:
Ctrl + F5 - 关闭旧页面后重新打开
http://localhost:8501 - 重启应用
- 先检查 key 是否有效、有余额、未过期
- 检查 Base URL 是否对应当前 provider
- 检查网络是否可达目标 API
- 先点“测试连接”,确认通过后再翻译
- 检查扩展名是否在支持列表
- 图片字幕(
.sup/.idx)不支持
- 先看导出编码提示
- 若播放器不兼容,尝试播放器侧切换编码
- 工具已自动在必要时切
UTF-8 BOM
- 本项目为本地运行,不强制上传到第三方服务器
- 但翻译请求会发送到你选择的 Provider API
- 请遵守字幕内容版权和平台合规要求
- 生产环境建议对
.env与.data做访问控制
- 仅支持文本字幕,不支持图片字幕 OCR
- 大文件翻译速度依赖网络与 Provider 响应
- 无 key 通道稳定性不保证
- 当前主要面向单用户本地使用
安装依赖:
uv sync --all-groups手动启动:
uv run streamlit run app.pyThis README is intentionally arranged in this order:
- Chinese
- English (this section)
- Japanese
If you want a fast path:
- Read 5. Quick Start (5 minutes)
- Use 6. Launch Methods (double-click startup)
- Follow 8. User Workflow
This is a subtitle translator, not a video processing pipeline.
What it does:
- Translates existing subtitle files
- Preserves subtitle structure as much as possible
- Exports translated subtitle files safely
What it does not do:
- No video demux/extraction
- No OCR
- No image subtitle recognition
- Local web UI (Streamlit)
- Trilingual UI:
中文 / 日本語 / English - Translation among Chinese / English / Japanese
- Multiple provider backends (official APIs + no-key options)
- “Test Connection” before translation
- Live model fetch for LLM providers
- Optional glossary CSV
- Local translation memory (SQLite)
- Encrypted API key storage with auto-fill
- Encoding-safe export with UTF-8 BOM fallback
Officially supported:
SRT,ASS,SSA,VTT
Best effort:
MicroDVD (.sub),TMP (.txt),TTML,SAMI
Excluded:
- Image-based subtitles such as
.sup,.idx/.sub(VobSub/PGS-like)
- Python 3.13+
- uv
- Streamlit
- pysubs2
- openai SDK
- httpx
- deep-translator
- charset-normalizer
- sqlite3
- cryptography
Install dependencies:
uv sync --all-groupsCreate .env:
Copy-Item .env.example .envStart app:
uv run streamlit run app.pyOpen:
http://localhost:8501
Visible launcher:
start_subtitle_translator.bat- Opens browser automatically
- Keeps terminal logs visible
Silent launcher:
start_subtitle_translator_silent.vbs- Starts in background
- Opens browser automatically
src/subtitle_translator/ui.py: UI and workflowsrc/subtitle_translator/translator.py: provider adapters and translation servicesrc/subtitle_translator/subtitle_io.py: parsing/export/tag protectionsrc/subtitle_translator/encoding.py: decode/normalize/newline handlingsrc/subtitle_translator/memory.py: translation memorysrc/subtitle_translator/secret_store.py: encrypted API key storagesrc/subtitle_translator/config.py: env and runtime paths
- Select UI language
- Select provider in sidebar
- Enter API key (or use a no-key provider)
- Click Test Connection
- Upload subtitle file
- Select source and target languages
- Optionally upload glossary CSV
- Click Start Translation
- Preview result
- Download output file
LLM providers:
- OpenAI
- Gemini (OpenAI-compatible endpoint)
- DeepSeek
- Qwen DashScope CN/Intl
- Zhipu GLM
- Custom OpenAI-compatible
Machine translation API providers:
- DeepL API
No-key options:
- Google Translate via deep-translator
Provider variables:
OPENAI_API_KEY,OPENAI_BASE_URL,OPENAI_MODELGEMINI_API_KEY,GEMINI_BASE_URL,GEMINI_MODELDEEPSEEK_API_KEY,DEEPSEEK_BASE_URL,DEEPSEEK_MODELDASHSCOPE_API_KEY,DASHSCOPE_BASE_URL,DASHSCOPE_MODELDASHSCOPE_INTL_API_KEY,DASHSCOPE_INTL_BASE_URL,DASHSCOPE_INTL_MODELZHIPU_API_KEY,ZHIPU_BASE_URL,ZHIPU_MODELCUSTOM_LLM_API_KEY,CUSTOM_LLM_BASE_URL,CUSTOM_LLM_MODELDEEPL_API_KEY,DEEPL_API_BASE_URL
App variables:
APP_DB_PATHAPP_SECRET_STORE_PATHAPP_SECRET_KEY_PATHAPP_BATCH_SIZEAPP_MAX_FILE_SIZE_MBAPP_REQUEST_TIMEOUT_SECONDS
Required columns:
source,target,notesExample:
source,target,notes
subtitle,subtitle,UI term
sister,sister,dialog contextRead path:
- BOM + detection + fallback decode
Write path:
- Reuse original encoding/newline if possible
- Fallback to
utf-8-sigwhen original encoding cannot represent translated text
Safety:
- ASS/SSA tags and HTML-like tags are protected by placeholders
- Tag order is validated after translation
When “Remember API key (encrypted)” is enabled:
- Keys are encrypted into
secret_store.enc - Encryption key is stored in
secret_store.key - Auto-fill works on next app start
Important:
- Keep both files together
- Losing
secret_store.keymeans old encrypted values cannot be decrypted
- Stored in SQLite (
APP_DB_PATH) - Exact-match reuse for repeated lines
- Bound to provider/model and language direction
- Output file name pattern:
originalName.targetLang.originalExt - Original subtitle format is preserved
- Timeline/order/newline style are preserved
- Actual output encoding is shown in UI
UI hard to read:
Ctrl+F5hard refresh- Restart app and reopen page
Provider connection fails:
- Verify key validity and quota
- Verify base URL
- Verify network access
Unsupported file:
- Check extension support
- Image subtitle formats are excluded
- App runs locally
- Translation content is still sent to your selected provider API
- Protect
.envand.datain shared environments
- Text subtitles only
- No OCR for image subtitles
- No-key providers may be unstable
- Designed for local single-user scenario
この README は次の順序です。
- 中文
- English
- 日本語(本セクション)
最短手順は以下です。
- 5. クイックスタート
- 6. 起動方法
- 8. 使い方
本ツールは「既存字幕ファイルの翻訳」に特化しています。
対応内容:
- 既存字幕ファイルの翻訳
- 構造・タイムライン・タグの保護
- 安全な文字コードでの書き出し
非対応:
- 動画からの字幕抽出
- OCR
- 画像字幕の認識
- ローカル Web UI(Streamlit)
- UI 言語切替:
中文 / 日本語 / English - 中日英の翻訳
- 複数プロバイダー対応(公式 API / 無 key)
- 接続テスト
- LLM のモデル一覧を接続後に取得
- 用語集 CSV(任意)
- 翻訳メモリ(SQLite)
- API キー暗号化保存と自動入力
- 文字コード安全なエクスポート
正式対応:
SRT,ASS,SSA,VTT
ベストエフォート:
MicroDVD (.sub),TMP (.txt),TTML,SAMI
非対応:
- 画像字幕(
.sup、.idx/.subなど)
- Python 3.13+
- uv
- Streamlit
- pysubs2
- openai SDK
- httpx
- deep-translator
- charset-normalizer
- sqlite3
- cryptography
依存関係インストール:
uv sync --all-groups.env 作成:
Copy-Item .env.example .env起動:
uv run streamlit run app.pyブラウザ:
http://localhost:8501
表示あり(ログ確認向け):
start_subtitle_translator.bat
表示なし(静かに起動):
start_subtitle_translator_silent.vbs
ui.py: UI と操作フローtranslator.py: プロバイダー層と翻訳実行subtitle_io.py: 読み込み・書き出し・タグ保護encoding.py: 文字コード処理memory.py: 翻訳メモリsecret_store.py: API キー暗号化保存config.py: 環境変数とパス
- UI 言語を選択
- サイドバーでプロバイダー選択
- API キー入力(または無 key プロバイダー)
- 接続テスト
- 字幕ファイルをアップロード
- 入力言語・出力言語を選択
- 必要なら用語集 CSV を追加
- 翻訳開始
- プレビュー確認
- ダウンロード
LLM 系:
- OpenAI
- Gemini(OpenAI 互換)
- DeepSeek
- Qwen DashScope(CN/Intl)
- Zhipu GLM
- Custom OpenAI-compatible
翻訳 API 系:
- DeepL API
無 key 系:
- Google Translate(deep-translator)
主な項目:
- 各プロバイダーの
*_API_KEY,*_BASE_URL,*_MODEL APP_DB_PATHAPP_SECRET_STORE_PATHAPP_SECRET_KEY_PATHAPP_BATCH_SIZEAPP_MAX_FILE_SIZE_MBAPP_REQUEST_TIMEOUT_SECONDS
詳細は .env.example を参照してください。
必須カラム:
source,target,notes読み込み:
- BOM/検出/フォールバックでデコード
書き出し:
- 可能なら元の文字コード・改行を維持
- 不可能なら
utf-8-sigへ自動フォールバック
保護:
- ASS/SSA タグや HTML 風タグをプレースホルダーで保護
保存先:
secret_store.encsecret_store.key
注意:
- 2つのファイルをセットで保持してください
secret_store.key紛失時、過去データは復号不可です
- SQLite に保存
- 同文の再翻訳を抑制
- プロバイダー/モデル/言語方向ごとに管理
- ファイル名:
元ファイル名.言語コード.拡張子 - 形式は元字幕形式を維持
- タイムライン・順序・改行を維持
- 実際の出力エンコードを UI に表示
見づらい・表示崩れ:
Ctrl+F5で再読み込み- アプリ再起動
接続エラー:
- API キー
- Base URL
- ネットワーク
対応外ファイル:
- 拡張子を確認
- 画像字幕は非対応
- ローカル実行が前提
- 翻訳時は選択プロバイダーへテキスト送信
.envと.dataの保護を推奨
- テキスト字幕のみ
- 画像字幕 OCR 非対応
- 無 key プロバイダーは不安定な場合あり
- 単一ユーザー向け設計
End of README.