feat(translation): add post-ASR translation mode for cloud engine
Adds an opt-in translation pipeline that reuses the existing PolishingService + LLMClient + AppGroupStore chain. Translation is implemented as a new PolishMode (.translate(targetLocaleId:)); all existing call sites are unchanged. Settings: - New TranslationPickerRow in the language tab (Toggle + 10-locale picker: en/zh-Hans/zh-Hant/ja/ko/fr/de/es/ru/pt), persisted to the App Group so the keyboard extension can read it during live dictation. - 5 new strings per language (en + zh-Hans). Keyboard: - New TranslationChip on the top bar to the right of LocaleChip; same Menu pattern, lets users toggle or quickly switch target language without leaving the keyboard. - PolishingService dispatches .translate with a parameterised prompt (en/zh variants selected by provider id); PolishingService.error gains a translationNotAvailable case so local-engine users get a clear inline warning when the toggle is on but cloud is off. - 6 new strings per language (en + zh-Hans) for the chip + banner. Local engine policy: - Translation is cloud-only by design (local engine stays ASR-only to honour the no-roundtrip promise). Chip shows a 'cloud required' state and raw transcript still inserts on failure — no data loss. Build: - OSGKeyboardShared adds TranslationLanguage enum (10 locales) and TranslationPrompt factory. - 4 new files, 9 modified. xcodebuild scheme=OSGKeyboard config=Debug destination=iPhone 17 Simulator: BUILD SUCCEEDED (0 warning, 0 error). Also pins DEVELOPMENT_TEAM in project.yml for TestFlight uploads (3 targets; Team X329MZU23S).
This commit is contained in:
@@ -35,6 +35,12 @@ public struct AppGroupPersistor {
|
||||
state.mode = .polish
|
||||
state.engineMode = store.engineMode
|
||||
state.localASRBackend = store.localASRBackend
|
||||
// v0.2.1: translation toggle + target locale. Read once at
|
||||
// hydration; `refreshRuntimeFlags` keeps them in sync while the
|
||||
// keyboard stays open so a Settings change shows up without a
|
||||
// re-present cycle.
|
||||
state.translationEnabled = store.translationEnabled
|
||||
state.translationTargetLocaleId = store.translationTargetLocaleId
|
||||
// v0.2.0: iOS `SpeechAnalyzer` is always ready; mirror that
|
||||
// into the State flags so downstream consumers see the same
|
||||
// shape they did when the previous Qwen3 stack reported "ready".
|
||||
@@ -75,6 +81,11 @@ public struct AppGroupPersistor {
|
||||
let store = AppGroupStore()
|
||||
state.engineMode = store.engineMode
|
||||
state.localASRBackend = store.localASRBackend
|
||||
// v0.2.1: keep translation state in sync with the host app so the
|
||||
// chip on the keyboard reflects the latest value without a re-
|
||||
// present cycle.
|
||||
state.translationEnabled = store.translationEnabled
|
||||
state.translationTargetLocaleId = store.translationTargetLocaleId
|
||||
// v0.2.0: iOS `SpeechAnalyzer` is always ready. Keep these
|
||||
// toggles here so the keyboard UI doesn't flicker if the host
|
||||
// app briefly clears them while refactoring.
|
||||
@@ -105,4 +116,17 @@ public struct AppGroupPersistor {
|
||||
guard AppGroup.isAvailable else { return }
|
||||
AppGroupStore().setLocalASRBackend(localASRBackend)
|
||||
}
|
||||
|
||||
/// v0.2.1: persist translation toggle. Wired through the
|
||||
/// `KeyboardViewController.setTranslation` action hook.
|
||||
public func persist(translationEnabled: Bool) {
|
||||
guard AppGroup.isAvailable else { return }
|
||||
AppGroupStore().setTranslationEnabled(translationEnabled)
|
||||
}
|
||||
|
||||
/// v0.2.1: persist translation target locale id (e.g. `"en"`).
|
||||
public func persist(translationTargetLocaleId: String) {
|
||||
guard AppGroup.isAvailable else { return }
|
||||
AppGroupStore().setTranslationTargetLocaleId(translationTargetLocaleId)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user