A lightweight macOS menu bar application that translates text on-the-fly using the Google Gemini API. Press a global hotkey, confirm the captured text, and the translated result is pasted right back into your active application — no window switching required.
| Feature | Description |
|---|---|
| Global Hotkey | Ctrl + Cmd + T triggers translation from any application |
| AI-Powered Translation | Uses Google Gemini Flash for fast, accurate translations |
| Smart Text Capture | Attempts the Accessibility API first, falls back to clipboard-based Select All → Copy macro |
| Confirmation Dialogs | Shows captured text for review before translating, and the result before pasting |
| Multi-Language Support | English, Spanish, French, German, Chinese, Japanese, Russian + Auto-detect |
| Menu Bar Integration | Lives in the macOS menu bar — no Dock icon, no main window |
| Persistent Preferences | Remembers source/target language and enabled state across launches |
| File Logging | All operations logged to ~/translator.log for debugging |
on-fly-translator/
├── Sources/
│ ├── main.swift # App entry point — creates NSApplication
│ ├── AppDelegate.swift # Menu bar UI, language selection, permission prompts
│ ├── InputMonitor.swift # Carbon hotkey registration, text capture macro
│ ├── GoogleGeminiService.swift # Gemini REST API client
│ └── Logger.swift # Singleton file logger
├── Tests/
│ ├── GoogleGeminiServiceTests.swift
│ ├── InputMonitorTests.swift
│ └── LoggerTests.swift
├── Info.plist # App bundle metadata (LSUIElement = true)
├── Package.swift # Swift Package Manager manifest
├── build.sh # Compiles and code-signs the .app bundle
├── test.sh # Compiles and runs unit tests
├── automated_setup.sh # Guides permission setup via Terminal
└── .env.example # Template for API key environment variable
graph LR
A[User presses Ctrl+Cmd+T] --> B[InputMonitor]
B -->|Accessibility API| C{Text captured?}
B -->|Clipboard fallback| C
C -->|Yes| D[AppDelegate shows confirmation]
D -->|Confirmed| E[GoogleGeminiService]
E -->|Translation| F[AppDelegate shows result]
F -->|Paste| G[Cmd+V into active app]
C -->|No| H[Log error]
| Component | Responsibility |
|---|---|
AppDelegate |
Menu bar setup, language settings UI, permission checks, translation dialog flow |
InputMonitor |
Registers Ctrl+Cmd+T via the Carbon EventHotKey API, captures text via the Accessibility API or clipboard macro, coordinates paste-back |
GoogleGeminiService |
Builds and sends requests to the Gemini generateContent endpoint, parses JSON responses |
Logger |
Thread-safe singleton that appends timestamped messages to ~/translator.log |
- macOS 13 (Ventura) or later
- Swift 5.9+ (ships with Xcode 15+)
- Google Gemini API Key — get one here
- Accessibility + Input Monitoring permissions (the app prompts you on first launch)
git clone https://github.com/mavrovde/on-fly-translator.git
cd on-fly-translatorChoose one of the following methods:
cp .env.example .env
# Edit .env and replace YOUR_API_KEY_HERE with your actual key
export GEMINI_API_KEY=your_actual_keyAfter launching the app, copy your API key to the clipboard and click "Paste API Key from Clipboard" in the menu bar dropdown.
./build.shThis will:
- Compile all Swift source files with optimizations (
-O) - Create the app bundle at
build/on-fly-translator.app - Copy
Info.plistinto the bundle - Ad-hoc code-sign the bundle for stable identity
The app requires two macOS permissions:
| Permission | Why |
|---|---|
| Input Monitoring | To listen for the global Ctrl+Cmd+T hotkey |
| Accessibility | To read selected text and simulate Cmd+C / Cmd+V keystrokes |
Automated setup (guided Terminal wizard):
./automated_setup.shThis script resets existing permissions, opens System Settings to the correct pane, reveals the app in Finder for drag-and-drop, and then launches the app once you confirm.
Manual setup:
- Open System Settings → Privacy & Security → Input Monitoring
- Add and enable
on-fly-translator.app - Open System Settings → Privacy & Security → Accessibility
- Add and enable
on-fly-translator.app - Launch the app:
open build/on-fly-translator.app
open build/on-fly-translator.appLook for the 💬 speech bubble icon in your menu bar.
- Select text in any application (or leave it — the macro will Select All)
- Press
Ctrl + Cmd + T - A dialog appears showing the captured text → click "Translate"
- A second dialog shows the translation → click "Paste"
- The translated text is pasted into the original application ✅
Tip
A glass sound 🔔 plays on successful paste. An error sound plays if translation fails.
| Menu Item | Action |
|---|---|
| Source: <language> | Choose the input language (or Auto-detect) |
| Target: <language> | Choose the output language |
| Enable Translation | Toggle the hotkey on/off (Ctrl+Cmd+T) |
| Paste API Key from Clipboard | Save the Gemini API key from your clipboard |
| Get API Key… | Opens the Google AI Studio API key page |
| Check Permissions | Re-checks Accessibility permissions and starts the input monitor |
| Quit | Exits the application (Cmd+Q) |
./test.shThe test script compiles GoogleGeminiService.swift, Logger.swift, and the test files into a standalone test binary, then executes it. Test coverage includes:
GoogleGeminiServiceTests— request body construction, missing API key errorInputMonitorTests— initialization state, hotkey handlingLoggerTests— singleton identity, file write verification
While build.sh uses swiftc directly for simplicity, SPM is also configured:
swift build # Debug build
swift build -c release # Optimized release build
swift test # Run tests via SPMNote
SPM builds output to .build/ while the build.sh script outputs to build/on-fly-translator.app.
| File | Purpose |
|---|---|
Package.swift |
SPM manifest — targets macOS 13+, defines executable and test targets |
Info.plist |
Bundle ID: com.user.on-fly-translator, LSUIElement: true (no Dock icon) |
.gitignore |
Ignores build/, .build/, Xcode artifacts, logs, and .env |
The GoogleGeminiService resolves the API key in this order:
- Environment variable
GEMINI_API_KEY - UserDefaults key
GeminiAPIKey(set via the menu bar "Paste API Key" option)
All events are logged to ~/translator.log with ISO 8601 timestamps:
[2026-02-17T00:00:00Z] Carbon Hotkey Registered Successfully.
[2026-02-17T00:00:05Z] Carbon Hotkey Detected! Triggering macro...
[2026-02-17T00:00:05Z] Captured Text via AX: Hello world...
[2026-02-17T00:00:06Z] Translation success: Hallo Welt
[2026-02-17T00:00:07Z] Pasted translation.
| Problem | Solution |
|---|---|
| Hotkey not responding | Check that Input Monitoring is enabled in System Settings. Try "Check Permissions" from the menu. |
| "Clipboard empty" in logs | Grant Accessibility permission — the app needs it to simulate Cmd+C. |
| "API Error" or "No API Key" | Verify your Gemini API key is set (env var or menu). Check network connectivity. |
| App not visible | Look for the speech bubble icon in the menu bar. The app has no Dock icon by design (LSUIElement: true). |
| Translation pastes into wrong app | Ensure you don't click other windows between confirming and pasting. The app hides itself to restore focus. |
| Permission prompt not appearing | Run ./automated_setup.sh to reset and re-configure permissions. |
tail -f ~/translator.log- No data collection — text is sent directly to the Google Gemini API and not stored anywhere except the local log file.
- API key stored locally — saved in macOS
UserDefaults(per-user, not shared). - Ad-hoc code signing — the build script signs the bundle with an ad-hoc identity for stable permission grants across rebuilds.
- No network calls unless a translation is explicitly triggered by the user.
This project is provided as-is for personal use.
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-improvement) - Make your changes and add tests
- Run
./test.shto verify - Commit and push
- Open a Pull Request