Skip to content

Development

Mohammad Hasan Kaman edited this page Oct 21, 2026 · 1 revision

Development

The project is small, deliberately — two source files and a test suite — but the conventions around them are strict.


The layout

kaman-ai-translator/
├── translator_app_v3.py   # PyQt6 UI & QThread workers (entry point)
│                           #   batch engine, live view, dialogs, themes
├── kaman_core.py          # Qt-free core: config + DPAPI encryption,
│                           #   prompts, chunking, structure analysis,
│                           #   engines (Gemini / OpenAI-compatible),
│                           #   job store, exporters
├── tests/test_v3.py       # 302-check offline test-suite
├── icon.png / icon.ico
├── requirements.txt
├── LICENSE
├── CONTRIBUTING.md
└── README.md

Ten tracked files. The commit history goes back to the v3.0.0 rewrite (b1c004a), and the current head is 3feb372.


The one structural rule

kaman_core.py must not import Qt.

The core holds everything that is worth testing — configuration and encryption, the prompts, chunking, structure analysis, the engines, the job store, the exporters. Keeping it GUI-free is what allows the entire pipeline to be tested headlessly, with no display and no event loop.

The reverse is not true: translator_app_v3.py imports the core freely, and imports PyQt6 heavily. It is the entry point — python translator_app_v3.py starts the application.

If a change needs a GUI, it goes in translator_app_v3.py. If it does not, it goes in kaman_core.py. A pull request that adds a PyQt6 import to the core breaks the test suite's ability to run without a display, and will be sent back.


Running the app from source

git clone https://github.com/Mohammad-Hasan-Kaman/kaman-ai-translator.git
cd kaman-ai-translator
pip install -r requirements.txt
python translator_app_v3.py

Python 3.11+. The dependencies are PyQt6, Pillow, google-genai and pymupdf.


Running the tests

python tests/test_v3.py
# expected: ALL V3 TESTS PASSED  (302 checks)

The suite is fully offline — fake engines, a temporary APPDATA, no network, no API key. See Testing for what it covers and how it is structured.

A contribution is not complete until the suite passes. The rule from CONTRIBUTING.md is explicit: the test suite must pass, and it must pass offline — a test that requires a real API key or a network call is not acceptable, because then it cannot run for anyone else.

The suite exits non-zero on any failure, so it works as a CI gate.


The contribution rules

CONTRIBUTING.md covers three areas.

1 — The offline test requirement

New behaviour comes with a test. The suite must keep passing with no network access and no credentials.

2 — The RTL conventions

The interface is 100% right-to-left Persian, and this is a maintained property, not an accident:

Rule Implementation
Persian numerals fa_number(value) maps ASCII digits to ۰۱۲۳۴۵۶۷۸۹.
Spin-box alignment align_spin_value_right plus _SpinAlignFilter, re-applied on Show, StyleChange, Polish, FontChange and ApplicationPaletteChange — Qt re-lays-out spin boxes on a theme change and loses the alignment otherwise.
Progress direction The percentage label is right-aligned; the progress bar's internal text is hidden because Qt drew it on the left.
Arrow direction "Next" points left (◀), "previous" points right (▶).
Panel order The source panel is added first, so in an RTL layout it lands on the right.
Copy button state Blue when the current page has a translation, grey when it does not.

These are asserted by the test suite — sections K, S, U and V exist to check the geometry of the interface. A change that breaks RTL alignment breaks a test.

3 — The security rules

  • The API key is never to be committed, hard-coded, logged, or included in a release asset.
  • It is entered in the settings dialog and stored encrypted with Windows DPAPI.
  • A contribution that adds a network endpoint, an update checker, or a telemetry call will be rejected — the "no background network activity beyond the provider you configured" property is a promise the README makes, and the test suite and the contribution guide both protect it.

Working on the code

The GUI never blocks. Everything long-running runs on a QThread worker: translation, structure analysis, and exports. A new feature that could take more than a fraction of a second belongs on a worker thread, not on the main thread.

The state is saved per page. JobStore writes the job file atomically after every completed page, guarded by a lock. A new code path that mutates job state should go through the store, not write the file directly.

Cancellation is cooperative. Workers poll a threading.Event between chunks and raise CancelledError; the app never kills a thread. New long operations should follow the same pattern so that ⏸ توقف and ■ لغو keep working.

The config is an allow-list. CONFIG_DEFAULTS defines both the defaults and the set of keys that are read from disk. A new setting must be added there, or it will be silently dropped on load.


The commit history

The history is small and readable, and the messages describe why:

3feb372 chore: remove the unused duplicate icon..ico asset
946bdb2 docs: translate the star section to English and drop the stale icon from the project tree
522e64f Docs: advertise bidirectional EN⇄FA translation in the README tagline
b57a6c2 Docs: fix stale test badge (303) and document encrypt_fallback.log
9734867 Log the reason when DPAPI encryption falls back to base64
7cd883c Show the exact local data folder in Settings with a one-click open button
20ac318 Docs: professional README, CONTRIBUTING and LICENSE for the v3.0.0 release
3466b04 Docs: fix executable build command (verified PyInstaller flags with bundled icon) and list icon.ico
1d7c6fb Add multi-resolution icon.ico for the Windows executable
b1c004a kaman-ai-translator v3.0.0 — complete rewrite

The convention is a conventional-commit prefix (feat:, docs:, chore:, fix:) followed by a description of the effect.


Related pages

Clone this wiki locally