A lightweight vocabulary learning app with system tray and spaced repetition. Supports Linux desktop (XFCE, GNOME, etc.) and macOS with GTK. You control what you learn. Period.
- System tray: Runs in background with tray icon
- Save phrases: Select text anywhere, press a hotkey, done
- Spaced repetition: SM-2 algorithm for optimal review scheduling
- Auto-translation: Automatic translation via multiple providers
- Multiple translation providers: Google (direct), Google (deep-translator), EasyGoogle, MyMemory
- Stats dashboard: See words learned, streak, reviews today
- Word Browser: View, search, edit and delete all words
- Word of the Day: Daily vocabulary boost with CEFR-level words (A1-C2)
- Autostart: Automatically starts on login
- Multiple languages: Support for 9 target languages
- Custom data directory: Store database anywhere (e.g., Dropbox for sync)
- Cross-platform: Works on Linux and macOS
Located in src/ folder - modern GTK3 interface with system tray.
./setup.shThis will create a virtual environment and install all dependencies:
requests- HTTP librarysqlalchemy- Database ORMdeep-translator- Translation libraryeasygoogletranslate- Alternative translationpytest- Testing frameworkpytest-mock- Mock supportpytest-cov- Coverage reports
Linux (apt): python3-gi, python3-gi-cairo, gir1.2-gtk-3.0, gir1.2-appindicator3-0.1
Linux (pacman): python-gobject, gtk3, libappindicator-gtk3
macOS (Homebrew): gtk+3, pygobject3, adwaita-icon-theme
source venv/bin/activate
python3 src/vocab_gui.pyConfigure in your desktop environment settings (usually Settings → Keyboard → Shortcuts):
| Command | Purpose |
|---|---|
python3 /path/to/src/vocab_cli.py --save |
Save selected text |
python3 /path/to/src/vocab_cli.py --delete |
Delete current word |
python3 /path/to/src/vocab_cli.py --next |
Show next word |
Configure via System Settings → Keyboard → Shortcuts → Services, or use tools like Hammerspoon or Karabiner-Elements. The same CLI commands apply:
| Command | Purpose |
|---|---|
python3 /path/to/src/vocab_cli.py --save |
Save clipboard text |
python3 /path/to/src/vocab_cli.py --delete |
Delete current word |
python3 /path/to/src/vocab_cli.py --next |
Show next word |
- Review interval: How often to show words (30min - 8hours)
- Translation provider: Choose between Google Translate (direct), Google Translate (deep-translator), EasyGoogle Translate, or MyMemory (free)
- Target language: Translation language (Russian, Spanish, French, German, Italian, Portuguese, Japanese, Chinese, Korean)
- Word of the Day: Enable/disable daily word notifications with CEFR level selection (A1-C2)
- Autostart: Automatically starts on system login
- Custom data directory: Store database elsewhere
- Linux default:
~/.local/share/vocab_app/vocab.db - macOS default:
~/Library/Application Support/vocab_app/vocab.db - Can be changed in settings
Words are selected for review using the SM-2 algorithm:
- First review: 1 day interval
- Subsequent reviews:
interval × ease_factor(default 2.5x) - Ease factor: Increases slightly with each quality rating ≥3, decreases if <3 (minimum 1.3)
- Maximum interval: 180 days (≈6 months)
- Sorting: Due date ascending, then by interval (shorter first)
- Make sure
notify-sendis installed:sudo apt install libnotify-bin - Check that desktop notifications are enabled in your system settings
- If tray icon or popup icon doesn't appear, check file permissions on
icons/folder
- Make sure GTK is installed via Homebrew:
brew install gtk+3 pygobject3 - Ensure the venv was created with
--system-site-packages
- Check that notifications are allowed for "Script Editor" in System Settings → Notifications
- GTK StatusIcon may not appear in the macOS menu bar by default. If the tray icon is missing, you can still run the app and interact via notifications and CLI commands.
- The app shows words that are due for review (based on interval)
- Make sure your target language matches the translations you want to review
src/
├── application/ # Service layer (business logic)
│ ├── factory.py # ServiceFactory - creates services with DI
│ ├── export_service.py # CSV export
│ ├── review_service.py # SM-2 spaced repetition
│ ├── word_service.py # Word CRUD operations
│ ├── wotd_service.py # Word of the Day
│ ├── settings_service.py
│ └── service_interfaces.py # Abstract interfaces
│
├── domain/ # Domain layer (pure business rules)
│ ├── entities.py # Word, Language, Stats, etc.
│ └── repositories.py # Abstract repository interfaces
│
├── infrastructure/ # Infrastructure layer (external systems)
│ ├── database_manager.py # DB lifecycle
│ ├── translation.py # Translation API implementations
│ ├── models.py # SQLAlchemy ORM models
│ ├── mappers.py # ORM ↔ Entity mappers
│ └── ...
│
├── repositories/ # Data access implementations
│ ├── word_repository.py
│ ├── settings_repository.py
│ └── sqlite.py # SQLite implementation
│
└── vocab_gui.py # GTK3 GUI entry point
- Dependency Injection: Services receive dependencies via constructor
- Factory Pattern:
ServiceFactorycreates services with proper DI - Repository Pattern: Abstract data access via interfaces
- Facade Pattern:
VocabServiceprovides unified API - Single Responsibility: Each service handles one domain
- Single Responsibility: Each class has one reason to change
- Open/Closed: Extend via interfaces, not modification
- Liskov Substitution: All implementations follow abstract interfaces
- Interface Segregation: Small, focused interfaces
- Dependency Inversion: Depend on abstractions, not implementations
source venv/bin/activate
PYTHONPATH=src pytest src/tests/ -vsrc/tests/
├── conftest.py # Fixtures
├── unit/ # Unit tests
│ ├── test_word_service.py
│ ├── test_review_service.py
│ ├── test_settings_service.py
│ └── test_export_service.py
├── domain/ # Domain entity tests
│ └── test_entities.py
└── integration/ # Integration tests
└── test_repository.py
Tests run automatically on GitHub Actions (see .github/workflows/test.yml).





