fix: 翻译失效后能自愈 — 不再「一次失效就整场翻不出来」 - #3
Merged
Merged
Conversation
用户反馈:经常突然不能翻译,必须去 系统设置 → 语言与地区 → 翻译语言 重新下载 语言包才恢复。 代码里有个明确的缺陷能解释这个症状:TranslationSession 在 warmUp 里建一次就一直用, 而 translate 是 `try? await s.translate(...)` —— 错误被整个吞掉、失效的 session 原样留着。于是一旦它失效,**这一场剩下的每一句都翻不出来**,只能靠用户去系统设置 折腾一圈再重开字幕。 改法:失败后丢掉旧 session、重建一次再试。真的是语言包没了(重建也失败),才退避 30s 并置 needsLanguagePackReinstall 供 UI 给可操作提示。退避逻辑抽成 TranslationRetryGate 值类型,不接 Apple 框架就能单测(+5 条,守「别每句都重建」这条不变量:边界到点即放行、 成功立刻解封、反复失败不叠加封锁)。 顺带两处: - CaptionEngine 暖机循环里的 `break` 改成「只报一次错但每条轨都试」。老写法下第一条轨 暖机失败会连累第二条轨压根不暖机,即使它本可以正常翻译。 - translate 对空串早退,免得因为空输入翻失败而白白重建一次 session。⚠️ **未验证根因**:我无法复现「session 失效」这件事本身,它多半在 Apple 的翻译资源 管理里。本次改的是「失效后能自愈」而不是「不再失效」—— 如果重下语言包的频率没降, 说明根因不是 session 失效,得另查。 swift build && swift test:193 tests,0 failures。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR improves the resiliency of the app’s English→Chinese translation pipeline by making TranslationService self-heal when the underlying TranslationSession becomes invalid, and by preventing repeated expensive session rebuilds via a cooldown gate.
Changes:
- Add
TranslationRetryGate+ tests to enforce retry cooldown invariants. - Update
TranslationService.translateto rebuild the translation session once on failure and back off for 30s on repeated failures, exposing a UI hint flag for missing language packs. - Adjust
CaptionEnginewarm-up loop to avoidbreak, so each track attempts warm-up while only reporting the “install language pack” error once.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| Tests/LiveSubtitleTests/TranslationRetryGateTests.swift | Adds unit tests covering retry gate cooldown behavior and boundaries. |
| Sources/LiveSubtitle/Translation/TranslationService.swift | Implements session rebuild-on-failure, cooldown gating, and a UI hint flag for missing language packs. |
| Sources/LiveSubtitle/Pipeline/CaptionEngine.swift | Changes warm-up loop to try all tracks while rate-limiting the user-facing error message. |
Suppressed comments (2)
Sources/LiveSubtitle/Translation/TranslationService.swift:72
translateSerially在旧 session 翻译成功时直接return out,但不会解除之前的 cooldown,也不会清掉needsLanguagePackReinstall。这会导致“已经恢复可翻译”后 UI 仍可能提示重装语言包,且后续真需要重建时还可能被旧 cooldown 拦住。
if let s = session, let out = try? await s.translate(en).targetText {
return out
}
Sources/LiveSubtitle/Translation/TranslationService.swift:87
makeSession()成功但fresh.translate(...)失败时,当前不会清掉needsLanguagePackReinstall。如果之前因为缺包置过该标记,之后即使语言包已装好(能成功prepareTranslation)但翻译仍失败,UI 也可能持续提示“去重下语言包”。建议在新 session 构建成功后就先清掉该标记。
session = fresh
gate.clear()
guard let out = try? await fresh.translate(en).targetText else {
// 新 session 也翻不动:不是"失效"能解释的,同样退避,别每句都重建。
gate.block(now: now)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
40
to
44
| func warmUp() async throws { | ||
| let s = TranslationSession(installedSource: Locale.Language(identifier: "en"), | ||
| target: Locale.Language(identifier: "zh-Hans")) | ||
| do { | ||
| try await s.prepareTranslation() | ||
| session = try await Self.makeSession() | ||
| } catch { | ||
| throw TranslateError.notInstalled |
Comment on lines
+94
to
+98
| /// UI 取走提示后清零,免得同一条提示反复弹。 | ||
| func consumeReinstallHint() -> Bool { | ||
| defer { needsLanguagePackReinstall = false } | ||
| return needsLanguagePackReinstall | ||
| } |
Comment on lines
+67
to
+68
| // 空串没有翻译的必要,更不该因为它翻失败就去重建 session | ||
| guard !en.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return nil } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
症状(用户反馈)
经常突然不能翻译,必须去 系统设置 → 语言与地区 → 翻译语言 重新下载语言包才恢复。
代码里能解释这个症状的缺陷
TranslationSession在warmUp()里建一次就一直用,而translate是:于是一旦 session 失效,这一场剩下的每一句都翻不出来 —— 没有任何恢复路径,
只能靠用户去系统设置折腾一圈再重开字幕。
改法
needsLanguagePackReinstall供 UI 给可操作提示。TranslationRetryGate值类型,不接 Apple 框架就能单测(+5 条):边界到点即放行、一次成功立刻解封、反复失败不叠加封锁。守的是「别每句话都去重建 session」。
CaptionEngine暖机循环里的break→ 「只报一次错但每条轨都试」。老写法下第一条轨暖机失败会连累第二条轨压根不暖机,即使它本可以正常翻译。
translate对空串早退,免得因为空输入翻失败而白白重建一次 session。复现不了「session 失效」这件事本身,它多半在 Apple 的翻译资源管理里。
本次改的是「失效后能自愈」,不是「不再失效」 —— 若重下语言包的频率没降,
说明根因不在 session 上,得另查。
193 tests,0 failures。