Supervertaler - AI Agent Documentation
This is the single source of truth for AI coding assistants working on this project. Last Updated: February 23, 2026 | Version: v1.9.313
⚡ QUICK START FOR AI AGENTS
IMPORTANT: If you're continuing from a previous session or ran out of context:
- Skip to the end of this file - The most recent development context is in the "🔄 Recent Development History" section (search for the latest date)
- Current version: v1.9.313 - SDLPPX multi-file views, locked segment toggle, memoQ submenu
- Read only what you need - The Project Overview and Architecture sections are reference material; the dated history entries contain the actual working context
Quick Navigation:
- Latest context: See CHANGELOG.md for v1.9.311-313 (Trados SDLXLIFF/SDLPPX improvements)
- Module list: Search for
## 🔌 Complete Module List - Architecture: Search for
## 🏗️ Architecture Patterns - Common pitfalls: Search for
## ⚠️ Common Pitfalls
🎯 Project Overview
Supervertaler is a professional desktop translation application built with Python and PyQt6. It serves as a companion tool for translators, integrating AI-powered translation with traditional CAT (Computer-Assisted Translation) tool workflows.
| Property | Value |
|---|---|
| Name | Supervertaler |
| Version | v1.9.313 (February 2026) |
| Framework | PyQt6 (Qt for Python) |
| Language | Python 3.10+ |
| Platform | Windows (primary), Linux compatible |
| Repository | https://github.com/michaelbeijer/Supervertaler |
| Website | https://supervertaler.com |
| Main File | Supervertaler.py (~56,000+ lines) |
| Modules | 85+ specialized modules in modules/ directory |
Key Capabilities
- Multi-LLM AI Translation: OpenAI GPT-4, Anthropic Claude, Google Gemini, Local Ollama, Custom OpenAI-Compatible API (Volcengine/Doubao, Tongyi/Qwen, DeepSeek, etc.)
- CAT Tool Integration: Trados SDLPPX/SDLRPX, memoQ XLIFF/DOCX/RTF, Phrase/Memsource DOCX, CafeTran DOCX, Déjà Vu X3 RTF
- Translation Memory: Fuzzy matching TM with TMX import/export + Supermemory (ChromaDB vector search)
- Terminology Management: SQLite-based termbases with priority highlighting and automatic extraction
- Document Handling: DOCX, bilingual DOCX, PDF (via OCR), simple TXT, Markdown (MD), Multi-file folder import
- Quality Assurance: Spellcheck, tag validation, consistency checking
- Superlookup: Unified concordance hub with TM, Termbase, Supermemory, MT, and Web Resources
- Batteries Included: Default install includes all major features and dependencies, except heavy optional components (Supermemory + offline Local Whisper)
📦 Installation (Simplified)
Supervertaler uses a batteries-included core install: pip install supervertaler pulls in everything needed for the major features, while keeping heavy optional components out of the default install.
Note: Offline dictation via Local Whisper is optional because it pulls in very large dependencies (PyTorch). The default/recommended voice path uses the OpenAI Whisper API.
Legacy note: older “extras” (e.g. supervertaler[all]) are still accepted for backward compatibility, but they no longer change what gets installed.
Installation Options
| Command | Notes |
|---|---|
pip install supervertaler |
Recommended core install (excludes heavy optional Local Whisper) |
pip install supervertaler[local-whisper] |
Adds offline Local Whisper (heavy; pulls PyTorch) |
pip install supervertaler[all] |
Legacy alias (no-op; kept for compatibility) |
Feature Modules
| Module | Included by default | Size | Description |
|---|---|---|---|
| Supervoice | ✅ | ~150 MB | Voice dictation & commands (OpenAI Whisper API recommended) |
| Web Browser | ✅ | ~100 MB | Built-in browser for Superlookup |
| PDF Rescue | ✅ | ~30 MB | PDF text extraction/OCR |
| MT Providers | ✅ | ~30 MB | DeepL, Amazon Translate |
| Hunspell | ✅ | ~20 MB | Advanced spellcheck |
| AutoFingers | ✅ (Windows) | ~10 MB | Windows automation |
Settings → Features Tab
Users can enable/disable features in Settings → 📦 Features.
Feature Manager Module
The modules/feature_manager.py provides:
FeatureManagerclass for checking feature availabilityFEATURE_MODULESdict defining all optional featureslazy_import_*()functions for conditional importscheck_feature(id)quick availability check
🪟 Windows EXE Releases (CORE + FULL)
Supervertaler Windows releases are published as two separate ZIP assets on the same GitHub Release:
- CORE (recommended for most users)
- Smaller download
- Does not bundle the heavy ML stack (Supermemory + offline Local Whisper)
- FULL ("batteries included")
- Larger download
- Bundles Supermemory + offline Local Whisper (PyTorch / sentence-transformers / ChromaDB)
Key Rule (PyInstaller one-folder builds)
The EXE must be run from the extracted distribution folder. Do not separate Supervertaler.exe from _internal/.
If users see an error like missing python312.dll, they are almost always:
- running the wrong EXE (from an intermediate build folder), or
- moving the EXE away from
_internal/.
How to Build (recommended)
Use the automated build script:
# Build BOTH core + full and create both ZIP assets
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1
# Build only core
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1 -CoreOnly
# Build only full
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1 -FullOnly
# Clean build venvs + rebuild (keeps dist/ so multi-flavor builds can coexist)
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows_release.ps1 -Clean
What it does:
- Uses two isolated build environments:
.venv-build-coreand.venv-build-full - Runs PyInstaller with the corresponding spec:
Supervertaler.core.spec→dist\Supervertaler-core\...Supervertaler.full.spec→dist\Supervertaler-full\...
- Zips each output using
create_release_zip.pyand writes aREADME_FIRST.txtinto each dist folder.
Output Files
After a successful run, you should have:
dist\Supervertaler-v<version>-Windows-CORE.zipdist\Supervertaler-v<version>-Windows-FULL.zip
GitHub Release Posting
Attach both ZIP files to the same GitHub Release tag.
VS Code Tasks
There are build tasks wired up in .vscode/tasks.json:
- "Build Windows EXE (core)"
- "Build Windows EXE (full)"
- "Build Windows EXE (core + full)"
📁 Project Structure
Supervertaler/
├── Supervertaler.py # Main application (~56,000+ lines)
├── modules/ # 85+ specialized modules
│ ├── feature_manager.py # Modular feature management (NEW)
│ ├── llm_clients.py # OpenAI, Anthropic, Google Gemini, Ollama
│ ├── translation_memory.py # TM matching and storage
│ ├── termbase_manager.py # Terminology management
│ ├── docx_handler.py # DOCX import/export
│ ├── sdlppx_handler.py # Trados Studio packages
│ ├── phrase_docx_handler.py# Phrase/Memsource bilingual
│ ├── cafetran_docx_handler.py # CafeTran bilingual
│ ├── supermemory.py # Vector-indexed semantic TM (ChromaDB)
│ ├── spellcheck_manager.py # Spellcheck with pyspellchecker/Hunspell
│ ├── prompt_library.py # AI prompt management
│ └── ... # See module list below
├── user_data/ # User content (gitignored)
│ ├── prompts/ # .svprompt files
│ ├── termbases/ # .db termbase files
│ ├── translation_memories/ # .db TM files
│ ├── dictionaries/ # Custom spellcheck words
│ └── supermemory/ # ChromaDB vector database
├── assets/ # Icons, images
├── docs/ # Documentation site
├── beijerterm/ # 🔗 GIT SUBMODULE - Beijerterm glossary website
├── tests/ # Test files
└── legacy_versions/ # Historical Tkinter version
🔗 Beijerterm Website Submodule (IMPORTANT FOR AI AGENTS)
The beijerterm/ folder is a Git submodule - a separate repository embedded inside Supervertaler.
What is a Submodule?
- It's a pointer to a specific commit in another repository
- Regular
git clonedoes NOT download submodule contents (saves ~15 MB) - The submodule has its own
.gitand tracksmichaelbeijer/beijertermseparately
Two Separate Projects
| Project | Location | Purpose |
|---|---|---|
| Supervertaler | Root folder | PyQt6 translation app |
| Beijerterm | beijerterm/ subfolder |
Static glossary website (beijerterm.com) |
Note: The "Superlookup" name refers to the in-app lookup panel inside Supervertaler - don't confuse it with the Beijerterm website!
Working with the Submodule
To make changes to Beijerterm website:
cd beijerterm/
# Edit files...
git add .
git commit -m "your message"
git push origin main # Pushes to michaelbeijer/beijerterm
Then update the parent reference:
cd .. # Back to Supervertaler root
git add beijerterm # Stage the new submodule commit pointer
git commit -m "chore: Update beijerterm submodule"
git push origin main # Pushes to michaelbeijer/Supervertaler
⚠️ Common Pitfalls
Commits in submodule aren't automatically tracked - After committing inside
beijerterm/, you must also commit in the parent repo to update the pointer.Changelogs are separate - Beijerterm website changes go in
beijerterm/CHANGELOG.md, Supervertaler changes go inCHANGELOG.mdat root.Features in the wrong repo - The "Superlookup" panel inside Supervertaler.py is part of Supervertaler, not the Beijerterm website. Don't confuse them!
Building the website - Run
python scripts/build_site.pyfrom insidebeijerterm/, not from root.
🔧 Key Technical Details
Main Application (Supervertaler.py)
The main file is a large monolithic PyQt6 application. Key sections:
| Line Range | Purpose |
|---|---|
| 1-700 | Imports, constants, Project dataclass |
| 700-2000 | Custom widgets (grid editors, checkboxes) |
| 2000-4500 | MainWindow initialization, UI setup |
| 4500-8000 | Menu actions, file operations |
| 8000-12000 | Settings dialogs |
| 12000-18000 | Grid operations, navigation |
| 18000-25000 | Import/Export handlers |
| 25000-32000 | AI translation, batch operations |
Key Classes
@dataclass
class Project:
segments: List[Segment]
source_lang: str
target_lang: str
original_docx_path: Optional[str] = None
memoq_source_path: Optional[str] = None
sdlppx_source_path: Optional[str] = None
phrase_source_path: Optional[str] = None
original_txt_path: Optional[str] = None
# ... 20+ fields total
@dataclass
class Segment:
source: str
target: str = ""
status: str = "Not Started"
notes: str = ""
segment_type: str = "text"
# ... additional fields
File Extensions
| Extension | Purpose |
|---|---|
.svproj |
Supervertaler project files (JSON) |
.svprompt |
Prompt files (JSON) |
.svntl |
Non-translatables lists (JSON) |
🔌 Complete Module List
AI & LLM (modules/)
llm_clients.py- OpenAI, Anthropic Claude, Google Gemini, Ollama, Custom OpenAI-Compatible API integrationmodel_version_checker.py- Auto-detect new LLM models from providersmodel_update_dialog.py- UI for selecting new modelsprompt_library.py- Prompt management and favoritesprompt_assistant.py- AI-powered prompt generationunified_prompt_library.py- Unified prompt systemunified_prompt_manager_qt.py- Prompt manager UIvoice_dictation.py- Whisper-based voice inputvoice_commands.py- Talon-style voice command system (NEW)ai_actions.py- AI action system for prompt libraryai_attachment_manager.py- File attachment persistenceai_file_viewer_dialog.py- File viewing dialog
Translation Memory & Terminology
translation_memory.py- Fuzzy matching TM systemsupermemory.py- ChromaDB vector semantic search (2100+ lines)termbase_manager.py- SQLite-based terminologyterm_extractor.py- Automatic term extractiontermbase_entry_editor.py- Term editing UItermbase_import_export.py- TMX/TBX import/exporttm_manager_qt.py- TM management UItm_metadata_manager.py- TM metadata handlingtm_editor_dialog.py- TM editing dialogtmx_editor.py/tmx_editor_qt.py- TMX file editingtmx_generator.py- TMX file generation
File Handlers
docx_handler.py- Standard DOCX import/exportsdlppx_handler.py- Trados Studio SDLPPX/SDLRPX packages (767+ lines)phrase_docx_handler.py- Phrase/Memsource bilingual DOCXcafetran_docx_handler.py- CafeTran bilingual DOCXtrados_docx_handler.py- Trados bilingual review DOCXdejavurtf_handler.py- Déjà Vu X3 bilingual RTF (NEW in v1.9.91)mqxliff_handler.py- memoQ XLIFF filessimple_segmenter.py- Text segmentation
Spellcheck & QA
spellcheck_manager.py- Dual-backend spellcheck (pyspellchecker + Hunspell)non_translatables_manager.py- Non-translatable term managementtag_cleaner.py- CAT tool tag removaltag_manager.py- Tag handling
UI Components
ribbon_widget.py- Ribbon-style toolbartranslation_results_panel.py- Match display paneltermview_widget.py- Inline term displaysuperlookup.py- Unified lookup windowsuperbrowser.py- Multi-chat AI browserquick_access_sidebar.py- Quick access panelkeyboard_shortcuts_widget.py- Shortcut managementproject_home_panel.py- Project home UI
Utilities
database_manager.py- SQLite database operationsdatabase_migrations.py- Database schema migrationsconfig_manager.py- Settings managementfile_dialog_helper.py- File dialog utilitiesfind_replace.py- Find and replace functionalityshortcut_manager.py- Keyboard shortcut handlingtheme_manager.py- UI theme managementstatuses.py- Segment status definitions
Specialized Tools
pdf_rescue_Qt.py- AI OCR for PDF extractionimage_extractor.py- Extract images from DOCXfigure_context_manager.py- Image context for AIdocument_analyzer.py- Document analysisencoding_repair.py/encoding_repair_Qt.py- Fix encoding issuesautofingers_engine.py- memoQ AutoFingers automationtracked_changes.py- Track changes analysissupercleaner.py/supercleaner_ui.py- Text cleaning
Benchmarking
llm_leaderboard.py- LLM quality benchmarkingsuperbench_ui.py- Benchmark UIlocal_llm_setup.py- Ollama setup wizard
🏗️ Architecture Patterns
UI Pattern
- PyQt6 with custom styled widgets
- Consistent styling:
- Checkboxes:
CheckmarkCheckBox(Standard),PinkCheckmarkCheckBox(Project),BlueCheckmarkCheckBox(Global) - Radio Buttons:
CheckmarkRadioButton(Standard Green)
- Checkboxes:
- Tag-based text formatting (
<b>,<i>,<u>,<li-o>,<li-b>) - Grid-based segment editor with source (read-only) and target (editable) columns
Data Flow
- Import file → Parse to segments → Display in grid
- User translates/edits → Status updates → Grid refreshes
- Export → Reconstruct original format with translations
Settings Storage
settings/settings.json- Unified configuration withapi_keys,general,ui, andfeaturessectionssettings/- Satellite files:themes.json,shortcuts.json,recent_projects.json,find_replace_history.json,superlookup_history.json,voice_commands.json,model_version_cache.json- Legacy settings files are one-time migrated on startup and renamed to
.migrated .svprojfiles - Per-project settings
📝 Development Guidelines
When Editing Supervertaler.py
- The file is large (~38K+ lines) - use line ranges when reading
- Search for method names with
grep_searchbefore editing - Follow existing patterns for new features
__version__auto-reads frompyproject.toml(dev) orimportlib.metadata(pip) — no manual update needed- To bump version: edit
pyproject.toml,CHANGELOG.md, anddocs/index.html(see Version Bump Checklist below)
When Adding New Modules
- Create in
modules/directory - Add import in main file where needed
- Follow existing module patterns (docstrings, type hints)
Documentation Updates
Always update these files after changes:
AGENTS.md- Add dated entry to development historyCHANGELOG.md- Add version entryREADME.md- Update version badge if needed
Commit Messages
Use semantic prefixes:
feat:- New featurefix:- Bug fixdocs:- Documentationrefactor:- Code restructuringstyle:- Formatting
⚠️ Common Pitfalls
ElementTree namespaces - Always use namespace dict when working with SDLXLIFF:
NAMESPACES = {'sdl': 'http://sdl.com/FileTypes/SdlXliff/1.0'} element.find('.//sdl:seg', NAMESPACES)Grid widget access - Use
table.cellWidget()for QTextEdit,table.item()for QTableWidgetItemFile paths - Store absolute paths, use
os.path.exists()before accessingStatus updates - Remember to update both internal data and grid display
Signal blocking - When setting text programmatically, use
blockSignals(True/False)to prevent cascading eventsQt event queue - Be aware that
setPlainText()queues events even when signals are blockedHidden widget styling - Qt may not apply stylesheets to hidden widgets. If theme colors aren't appearing, apply styles when the widget becomes visible, not just at creation time
Race conditions & timing - When debugging UI issues, consider whether the problem might be timing-related:
- Widgets created before theme manager is initialized
- Styles applied while widgets are hidden
- Signals firing before handlers are connected
- Use
QTimer.singleShot()for deferred initialization when needed
📋 Planned Features & Refactoring
🔑 Inline API Key Editing in Settings UI (Completed in v1.9.240)
Status: Completed and released in v1.9.240
Users can now manage API keys directly in Settings > AI Settings with password-masked QLineEdit fields and show/hide toggles. Keys are read from and written to unified settings storage.
🔧 Configuration File Consolidation (Completed in v1.9.240)
Status: Completed and released in v1.9.240
Configuration was consolidated into settings/settings.json with four top-level sections:
api_keysgeneraluifeatures
The following files were also relocated under settings/: themes.json, shortcuts.json, recent_projects.json, find_replace_history.json, superlookup_history.json, voice_commands.json, and model_version_cache.json.
A one-time startup migration converts legacy files and renames originals to .migrated.
� Future Investigation: TMX Tag Export Format
Issue discovered December 22, 2025: Our TMX Editor stores formatting tags (like <b>, <i>) as escaped text (<b>) in the <seg> element. This is valid XML but may not be the optimal approach.
Three approaches exist:
| Approach | Example in TMX file | Pros | Cons |
|---|---|---|---|
| Escaped text | <seg><b>text</b></seg> |
Simple, valid XML | Tags treated as plain text, lost semantic meaning |
| TMX inline elements | <seg><bpt i="1" type="bold"><b></bpt>text<ept i="1"></b></ept></seg> |
TMX 1.4 compliant, preserves tag semantics | More complex to implement |
| Raw XML (invalid) | <seg><b>text</b></seg> |
Human readable | Invalid XML unless DTD defines <b> |
What other tools do:
- memoQ: Uses TMX inline elements (
<bpt>,<ept>) for proper tag preservation - Trados Studio: Similar, uses inline elements with type attributes
- OmegaT: Generally uses escaped text for simplicity
- Many web tools: Just escape everything
Recommendation for future: Consider implementing proper TMX inline elements (<bpt>, <ept>, <ph>) when exporting. This would:
- Maintain compatibility with professional CAT tools
- Preserve tag type information (bold, italic, etc.)
- Allow round-tripping without tag loss
Files to modify: modules/tmx_editor.py - TmxParser.save_file() method
�💡 Problem-Solving Tips for AI Agents
When stuck on a difficult bug, consider these approaches:
Think about timing: Is this a race condition? Are things happening in the wrong order?
- Widget creation vs. theme application timing
- Signal connections vs. signal emissions
- Hidden vs. visible widget state changes
Think outside the box: The obvious solution may not work
- If stylesheets aren't applying, try QPalette as an alternative
- If a method isn't being called, check if the widget is even visible
- If changes aren't reflected, check if there's caching involved
Add debug output: When behavior is mysterious, add logging to trace execution flow
- Print method entry/exit with timestamps
- Log parameter values and state
- Write to a debug file if console output is too fast
Question assumptions: What do you THINK is happening vs. what is ACTUALLY happening?
- The code might be running but not having the expected effect
- A different code path might be executing
- Something else might be overriding your changes
🧪 Testing
Running Tests
pytest tests/
Manual Testing Checklist
- Import DOCX, translate segment, export
- Save/load .svproj project
- TM matching works
- Termbase highlighting works
- AI translation (if API keys configured)
- Spellcheck toggles correctly
- SDLPPX import/export round-trip
🔑 API Keys
Unified Settings Storage (v1.9.240+):
API keys are stored in settings/settings.json under the api_keys section.
| Platform | Default Data Folder | API Key Storage |
|---|---|---|
| All Users (default) | ~/Supervertaler/ |
settings/settings.json → api_keys |
| Windows (default) | C:\Users\Username\Supervertaler\ |
settings\settings.json → api_keys |
| Development | user_data_private\ (git-ignored) |
settings\settings.json → api_keys |
Backward compatibility:
- Legacy
api_keys.txtremains supported as a fallback input path. - New writes persist to
settings/settings.json.
Supported keys:
openai,claude,google,gemini,custom_openai,deepl,google_translate,ollama_endpoint
Notes:
googleandgeminiare aliases.custom_openaiis for OpenAI-compatible endpoints; endpoint/model are configured in Settings > AI Settings.ollama_endpointcan override the default (http://localhost:11434).
🔄 Recent Development History
February 8, 2026 - Unified Settings + Inline API Key Editing (v1.9.240)
✨ Feature Summary
Completed the unified settings migration and inline API key editing workflow.
Status: Implementation complete, version 1.9.240 released to PyPI
Highlights:
- Consolidated core settings into
settings/settings.jsonwithapi_keys,general,ui, andfeaturessections - Added password-masked API key fields with show/hide toggles in Settings > AI Settings
- Implemented one-time startup migration that renames legacy files to
.migrated - Moved satellite settings/history files into the
settings/subfolder - Removed dead code for deprecated settings paths
February 7, 2026 - Custom OpenAI-Compatible API Provider (v1.9.236)
✨ Feature Summary
Added a generic "Custom (OpenAI-Compatible API)" provider that enables any OpenAI SDK-compatible endpoint — Volcengine (ByteDance Doubao), Alibaba Tongyi (Qwen), DeepSeek, Mistral, Groq, and more. This addresses GitHub issue #155 requesting Chinese AI services that handle Chinese translation better.
Status: Implementation complete, version 1.9.236 released to PyPI
Issue Addressed:
- GitHub #155 - Feature request for Volcengine (Doubao) and Tongyi (Qwen) support
Approach:
Rather than adding each Chinese AI provider individually, implemented a single custom_openai provider that reuses _call_openai() with a user-specified base_url. Users configure: endpoint URL, API key (in api_keys.txt as custom_openai = <key>), and model name (free-text input since model names vary by provider).
Files Modified:
modules/llm_clients.py:- Added
base_url: Optional[str] = Noneparameter to__init__ translate()routes"custom_openai"to_call_openai()(same as"openai")_call_openai()passesbase_urltoOpenAI()constructor when setDEFAULT_MODELSincludes"custom_openai": "custom-model"load_api_keys()includes"custom_openai": ""in defaults- API key validation skipped for
custom_openai(some endpoints don't need one)
- Added
Supervertaler.py— Settings UI:- Added
custom_radio = CustomRadioButton("🔌 Custom (OpenAI-Compatible API)")in_create_ai_settings_tab() - Added
custom_endpoint_input(QLineEdit for URL) andcustom_model_input(QLineEdit for model name) - Added
custom_enable_cb = CheckmarkCheckBox("Enable Custom (OpenAI-Compatible)") - Save handler (
_save_ai_settings_from_ui()) savescustom_openai_model,custom_openai_endpoint load_llm_settings()includescustom_openai_modelandcustom_openai_endpointdefaultsload_provider_enabled_states()includesllm_custom_openai: True
- Added
Supervertaler.py— Helper method:- Added
create_llm_client(provider, model, api_keys, settings)method that handlesbase_urllogic in one place - Used at ~12
LLMClient()instantiation points to avoid duplicating custom_openai logic PreTranslationWorkeracceptsbase_urlparameter for batch translation
- Added
modules/quicktrans.py:- Added
("Custom", "CUS", "custom_openai", "mtql_custom_openai")tollm_defs _call_llm_translation()handles base_url for custom_openai, reads endpoint from parent_app settings
- Added
user_data_private/api_keys.example.txt: Addedcustom_openaisection with example endpoints
LLM Provider Architecture (5 providers total):
openai— OpenAI GPT modelsclaude— Anthropic Claude modelsgemini— Google Gemini modelsollama— Local Ollama models (no API key needed)custom_openai— Any OpenAI-compatible endpoint (reuses_call_openai()with custombase_url)
Settings stored in settings/settings.json (ui section):
llm_settings.provider— active provider namellm_settings.custom_openai_model— model name or endpoint IDllm_settings.custom_openai_endpoint— base URL (e.g.,https://ark.cn-beijing.volces.com/api/v3/)provider_enabled_states.llm_custom_openai— enabled toggle
February 7, 2026 - Version Display Fix for pip Users (v1.9.235)
🐛 Bug Fix
Fixed _read_version() which caused all pip-installed users to see version 1.9.227 regardless of the actual installed version. The function only tried pyproject.toml (which isn't included in pip wheels) and had a hardcoded fallback. Now uses a two-step approach:
- Try
pyproject.tomlviatomllib(works in dev/source checkout) - Try
importlib.metadata.version("supervertaler")(works after pip install) - Fallback to
"0.0.0"instead of a misleading real version number
February 7, 2026 - Multi-file Export & Batch Fixes (v1.9.232-234)
✨ Features:
- Multi-file export "Original Format" option (v1.9.234): Exports each file back to its source format (
.txt,.md, or.docx), useful for mixed-format projects - Saved Views (v1.9.232): Named views that filter the grid to selected files, persisted in project file
- File boundary separators (v1.9.232): Blue separator lines between files in multi-file projects
- Markdown in multi-file import (v1.9.232):
.mdfiles recognized alongside.docxand.txt - Tabbed Project Info dialog (v1.9.232): Overview and File Progress tabs merged into one dialog
🐛 Bug Fixes:
- Batch pre-translation SQLite thread error (v1.9.233): Worker thread was calling main thread's SQLite connection for AI-inject glossary terms. Terms now pre-fetched on main thread and passed to worker.
February 7, 2026 - memoQ RTF Fixes & UI Improvements (v1.9.228-231)
🐛 Bug Fixes:
- memoQ RTF Unicode/formatting loss (v1.9.231): Unicode escapes and RTF character control words were stripped by the generic cleanup regex. All Unicode escapes, hex escapes, and named character control words now decoded before the generic strip.
- memoQ RTF combined formatting (v1.9.231): Segments with bold+underline lost all formatting. Replaced pair-matching regex with direct marker-to-tag conversion.
- memoQ RTF missing import options dialog (v1.9.231): RTF import now shows the same formatting options dialog as DOCX import.
- TM Read/Write settings persistence (v1.9.228): Stale global TM activations could override project-specific settings on restart. Project-specific settings now always take priority.
🎨 UI Improvements:
- Settings panel reorganized (v1.9.227): AI Translation Preferences section reorganized with sub-headings
- Version auto-read from pyproject.toml (v1.9.227):
__version__no longer needs manual updates
February 6, 2026 - WYSIWYG Fix & Import Language Memory (v1.9.224-226)
🐛 Bug Fixes:
- WYSIWYG/Tags toggle corrupted target text (v1.9.225, #142): View mode toggle permanently destroyed whitespace/indentation. Fixed with
white-space: pre-wrapCSS and_suppress_target_change_handlersguard. - Import dialogs ignored saved language pair (v1.9.226, #143): Text/Markdown and multi-file import dialogs always defaulted to English → Dutch. Now all three import dialogs share language memory via
general_settings.json.
February 6, 2026 - memoQ Bilingual RTF Support (v1.9.223)
✨ Feature Summary
Added full import/export support for memoQ bilingual RTF files, addressing GitHub issue #145. This enables users with older memoQ versions (or those who prefer RTF format) to use the same bilingual table workflow as DOCX.
Status: Implementation complete, version 1.9.223 released
Issue Addressed:
- GitHub #145 - Feature request for memoQ RTF bilingual file support
Implementation Details:
The memoQ RTF bilingual format uses the identical 5-column table structure as memoQ DOCX:
- Column 1: Segment ID (number + GUID)
- Column 2: Source text (with formatting)
- Column 3: Target text
- Column 4: Comments
- Column 5: Status ("Not started", "Edited", "Confirmed", etc.)
New Module - modules/memoqrtf_handler.py:
class MemoQRTFHandler:
"""Handler for memoQ bilingual RTF files."""
def load(self, file_path: str) -> bool:
"""Load and parse memoQ bilingual RTF."""
def save(self, output_path: str) -> bool:
"""Save RTF with updated translations."""
def get_source_texts(self) -> List[str]:
"""Get source segments for translation."""
Key Features:
- Parses RTF table structure using
\celland\rowmarkers - Handles RTF formatting codes (
\bbold,\iitalic,\ulunderline) - Decodes Unicode escapes (
\uNNNN?) and hex character codes ('XX) - Preserves RTF structure for clean round-trip export
- Auto-detects source/target languages from header row
Menu Integration:
- Import: File → Import → memoQ Bilingual Table (RTF)...
- Export: File → Export → memoQ Bilingual Table - Translated (RTF)...
Files Modified:
modules/memoqrtf_handler.py(NEW):MemoQRTFHandlerclass for parsing/saving memoQ RTFMemoQSegmentdataclass for segment representation- RTF escape/decode utilities
- Language detection from header row
Supervertaler.py:- Added menu actions for memoQ RTF import/export (lines ~8165, ~8226)
- Added
import_memoq_rtf()method (lines ~27679-27805) - Added
export_memoq_rtf()method (lines ~28407-28515) - Stores
memoq_rtf_source_pathin project for persistence
Technical Notes:
- RTF parsing uses regex to find cell content between
\cellmarkers - Unicode handling:
\uc0\uNNNNand\uNNNN?patterns - Negative Unicode values converted per RTF spec:
code + 65536 - Target cell replacement done in reverse order to preserve positions
February 5, 2026 - Custom Tooltips & Clean Slate Project Imports (v1.9.222)
✨ Feature Summary
Fixed black tooltip rendering issue on certain systems by implementing custom tooltip widgets. Also clarified and restored the "clean slate" behavior for new project imports.
Status: Implementation complete, version 1.9.219 released
Issues Addressed:
- Black tooltip rectangles when hovering over status icons (PyQt6/Qt tooltip rendering issue)
- GitHub #140 investigation ongoing (TM not readable after re-import on macOS)
Custom Tooltip Implementation:
Qt's built-in QToolTip rendered as black rectangles on some systems due to platform-specific styling issues. Solution: bypass Qt's tooltip system entirely with custom QLabel popup widgets.
Key Code - Custom Tooltip Widget (Supervertaler.py):
def _get_custom_tooltip(self):
"""Get or create the custom tooltip label widget."""
if not hasattr(self, '_custom_tooltip') or self._custom_tooltip is None:
self._custom_tooltip = QLabel()
self._custom_tooltip.setWindowFlags(
Qt.WindowType.ToolTip | Qt.WindowType.FramelessWindowHint
)
self._custom_tooltip.setStyleSheet("""
QLabel {
background-color: #f5f5f5;
color: #333333;
border: 1px solid #d0d0d0;
padding: 4px 8px;
font-size: 12px;
}
""")
self._custom_tooltip.hide()
return self._custom_tooltip
Event Filter for Status Icons:
- Intercepts
QEvent.Type.ToolTipevents on status icon labels - Shows custom tooltip popup instead of Qt's default
- Hides popup on
QEvent.Type.Leave
Clean Slate Project Imports (Design Clarification):
The _deactivate_all_resources_for_new_project() function ensures new projects start with a clean slate:
- Design Intent: When importing a new document, NO TMs or glossaries should be pre-selected
- User Workflow: Import document → Select only needed TMs/glossaries → Work with relevant resources
- This prevents resource "pollution" from previous projects carrying over
Files Modified:
Supervertaler.py:- Added
_get_custom_tooltip()method for creating styled tooltip widgets - Added
_show_status_tooltip()and_hide_status_tooltip()methods - Event filter on status icon labels to intercept tooltip events
- Confirmed
_deactivate_all_resources_for_new_project()deactivates resources (clean slate)
- Added
modules/theme_manager.py:- Added QToolTip styling in stylesheet (#f5f5f5 background, #333333 text)
- Added QPalette tooltip colors as fallback for Qt versions that ignore stylesheet
Tooltip Color Choice:
- Background:
#f5f5f5(light gray) - professional, readable in all themes - Text:
#333333(dark gray) - high contrast - Border:
#d0d0d0- subtle definition
GitHub #140 Investigation Notes:
Bug report indicates TM not readable after re-importing document on macOS:
- Checkbox appeared checked but TM wasn't being searched
- Workaround: Uncheck, restart, recheck
- Hypothesis: When re-importing creates a new project_id, the TM activation records from the old project_id don't apply
- Awaiting clarification from bug reporter on exact workflow
February 1, 2026 - Dark Mode Refinements & UI Improvements
✨ Feature Summary
Improved dark mode text visibility and fixed TM navigation arrows that were invisible or rendering incorrectly across light and dark themes.
Status: Implementation complete, version 1.9.184 released
Files Modified:
Supervertaler.py- Multiple UI improvements:- TermView source text color: Changed to #FFFFFF in dark mode for better contrast (lines 175, 456)
- HTML tag colors: Light pink (#FFB6C1) in dark mode for
<b>,</b>tags (lines 1403-1413, 2733-2743) - Navigation arrows: Implemented ClickableArrow class with Unicode symbols (◀ ▶) and theme-aware colors (lines 29674-29733)
- Table header font: Reduced from
font_size + 1tofont_sizefor better proportions (line 30834) - Theme refresh: Added arrow color updates in
refresh_theme_colors()(lines 43993-43999)
modules/unified_prompt_manager_qt.py- Fixed Issue #112:- Prompt edits now immediately reflected in Prompt Library and Preview Combined
- Cache refresh for both active primary and attached prompts (lines 2377-2384)
build_windows_release.ps1- Added Start Menu shortcut scripts to release packages (lines 111-116)create_release_zip.py- Added shortcut creation instructions to README (lines 28-31)
Key Code Locations:
ClickableArrow Class (Supervertaler.py:29684-29705):
class ClickableArrow(QLabel):
clicked = pyqtSignal()
def __init__(self, arrow_symbol, parent=None):
self.arrow_symbol = arrow_symbol
super().__init__("", parent)
self.setCursor(Qt.CursorShape.PointingHandCursor)
def set_color(self, color):
"""Update arrow color for current theme"""
self.setStyleSheet(f"""
QLabel {{
color: {color};
background: transparent;
border: none;
font-size: 11px;
font-weight: bold;
}}
""")
self.setText(self.arrow_symbol)
Theme Color Logic:
- Dark mode: White arrows (#FFFFFF), light pink tags (#FFB6C1)
- Light mode: Dark gray arrows (#333333), standard tag colors
Development Notes:
- Initially tried PNG arrow images but they rendered fuzzy
- Attempted Unicode angle brackets (❮ ❯) but font support was inconsistent
- Final solution: Unicode triangle symbols (◀ ▶) render crisply on all systems
- Arrow visibility issues were caused by arrows being created at startup before theme was applied
- Solution: ClickableArrow class with
set_color()method called during theme refresh
PowerShell Scripts Created:
create_start_menu_shortcut.ps1- For end users (Supervertaler.exe)create_dev_start_menu_shortcut.ps1- For developers (run.cmd)
Related Issues:
- Fixed #112: Prompt editing bug where saved prompts weren't updating in UI
January 30-31, 2026 - Total Recall Architecture & Build System Unification
✨ Feature Summary
Implemented CafeTran-inspired "Total Recall" architecture for instant grid navigation. Instead of querying giant TMs on every segment click, relevant segments are extracted into lightweight in-memory structures on project load.
Status: Implementation complete, ready for testing
Files Created:
modules/project_tm.py- In-memory TM for instant lookupsmodules/extract_tm.py- Persistent TM extraction to .svtm files
Files Modified:
Supervertaler.py(~938 lines changed)modules/database_manager.py- Reduced candidate limitbuild_windows_release.ps1- Unified build system
Implementation 1: In-Memory Termbase Index (Quick Win)
On project load, buil
…(truncated)