transScan is a macOS menu bar translation overlay for reading foreign-language text without leaving your current app.
The app stays out of the Dock, listens for a configurable shortcut, opens a floating NSPanel, reads recently copied text from the clipboard, and translates it with Apple's Translation framework. Select the text you want, copy it, and keep the popup open while each new copy updates the translation.
transScan uses Apple's built-in Translation framework through TranslationSession.
- No OpenAI, Google Translate, DeepL, or custom LLM API is used.
- No API key is required.
- Translation is handled by Apple's system translation engine and language packs on supported macOS versions.
- The app creates the translation session in SwiftUI with
.translationTask(engine.configuration)and passes that session intoTranslationEngine.
The practical tradeoff is that translation quality, language availability, and language-pack behavior are determined by Apple's framework, not by this repository.
The MVP is implemented as a macOS-only SwiftUI/AppKit app.
- Menu bar app with
LSUIElement=YES - Floating always-on-top overlay built with
NSPanel+ SwiftUI - Configurable hotkey stored in
UserDefaults - Accessibility selected-text detection with clipboard fallback
- Source language auto-detect or manual source selection
- Target language picker and source/target swap
- Apple Translation framework session injection through
.translationTask - XCTest coverage for detector, translation engine, and view model behavior
The active work is UI reliability and reading polish: overlay reopen behavior, shortcut display, long text scrolling, and real app verification. See roadmap.md and roadmap.progress.json.
The user should be able to read an article, PDF, or app screen, copy a sentence, press the hotkey, and immediately see a compact translation overlay without switching context.
MVP non-goals:
- Text-to-speech
- Translation history
- Explanation or nuance analysis
- iOS support
- macOS app development environment with Xcode
- Apple Translation framework support on the target macOS version
- Accessibility permission for selected-text detection
The current Xcode project uses generated Info.plist settings, LSUIElement=YES, and bundle id com.finn.transScan.
Open in Xcode:
open transScan.xcodeprojBuild from CLI:
xcodebuild -project transScan.xcodeproj -scheme transScan buildRun tests:
xcodebuild -project transScan.xcodeproj -scheme transScan testThe high-level path is:
transScanApp.swiftstarts aMenuBarExtraandSettingsscene.AppDelegate.swiftregisters global/local key monitors and toggles the overlay.OverlayWindowController.swiftowns the floatingNSPanellifecycle.OverlayContentView.swifthosts the SwiftUI overlay and injects the Translation session with.translationTask.TextDetector.swiftwatches selected text with Accessibility APIs and falls back to clipboard polling.TranslationViewModel.swiftdebounces detected text, tracks translation state, handles language swaps, and coordinates UI updates.TranslationEngine.swiftwraps Apple Translation, language persistence, language-pack preparation, and pending requests while the session is not ready.
Important architecture rule: TranslationEngine cannot create its own TranslationSession. The SwiftUI view layer must create the session through .translationTask(engine.configuration) and pass it back with engine.provideSession(session). If this connection breaks, translation requests can remain pending.
transScan/ macOS app source
transScanApp.swift app entry point
AppDelegate.swift menu bar lifecycle and hotkey monitors
OverlayWindowController.swift NSPanel lifecycle
OverlayContentView.swift overlay host and Translation session injection
TranslationViewModel.swift translation state and UI flow
TranslationEngine.swift Apple Translation wrapper
TextDetector.swift Accessibility and clipboard text detection
SettingsView.swift shortcut/settings UI
transScanTests/ XCTest coverage
docs/ product, architecture, UI, and session notes
roadmap.md human-readable current state and next work
roadmap.progress.json machine-readable handoff tracker
CLAUDE.md agent guardrails and project-specific rules
AGENTS.md Codex-facing repository guidelines
Read these before changing behavior:
- docs/PRD.md: product requirements and MVP boundaries
- docs/ADR.md: architecture decisions
- docs/UI_GUIDE.md: overlay design rules
- roadmap.md: current focus and next actions
- docs/session-logs/: durable session history
If BrainVault notes and repository files conflict, prefer the repository files for code-coupled facts.
This project should be worked on through the app source, repo-local docs, session handoff files, and macOS-specific build/debug support. Use the workflow by task type.
Start by reading:
CLAUDE.mdAGENTS.mdroadmap.md- relevant files under
docs/ - the source and tests for the feature being changed
Then make focused changes and verify with:
xcodebuild -project transScan.xcodeproj -scheme transScan build
xcodebuild -project transScan.xcodeproj -scheme transScan testFor UI behavior, also run the app and visually check the menu bar item, overlay open/close, shortcut label, settings window, and long translation text behavior.
Use /session-end when ending a coding session, preparing handoff, or saving resumable state.
It should update:
CLAUDE.local.mdwith short next-session instructionsroadmap.mdcheckboxesroadmap.progress.jsondocs/session-logs/YYYY-MM-DD.md
Expected verification:
node -e "JSON.parse(require('fs').readFileSync('roadmap.progress.json','utf8')); console.log('roadmap.progress.json OK')"
git check-ignore -v CLAUDE.local.md || true
git status --shortThe short-term handoff file should stay local and gitignored. The long-term record belongs in docs/session-logs/.
Use the build-macos-apps plugin when the task is macOS-specific:
- build or launch the app
- inspect schemes or app bundle behavior
- debug menu bar, window, signing, entitlement, log, or runtime launch issues
- create a stable
script/build_and_run.shentrypoint if repeated build/run work becomes painful
For now the repo uses direct Xcode commands. If app launch/debug becomes frequent, add a project-local run script and wire it into Codex app environment actions.
App tests live in transScanTests/.
Prefer focused XCTest coverage around:
- text normalization and clipboard fallback
- duplicate text suppression
- translation engine language/session behavior
- view model state transitions
- shortcut and settings logic when extracted into testable units
- Keep SwiftUI views view-focused.
- Put AppKit/window/platform lifecycle code in dedicated service-style types.
- Keep the Translation framework session bridge in the view layer.
- Do not let language changes erase the current translation context unless the UX explicitly calls for it.
- For shortcut work, verify both global and local app states. The current implementation uses
NSEventmonitors;Carbon RegisterEventHotKeyis still a possible future hardening path. - For overlay UI changes, check short text, long text, blank lines, scroll behavior, close/reopen, menu bar reopen, and hotkey toggle.
Use Conventional Commit style:
feat(ui): improve overlay reading layout
fix(ui): restore overlay fade-in on reopen
test(translation): cover language swap behavior
For PRs, include:
- short summary
- linked issue or decision note if applicable
- build/test results
- screenshots or screen recordings for UI changes
- notes about Accessibility permission or manual macOS verification
