Status: design proposal (v1). No code written yet. Goal: kill the "I don't know wtf I'm doing" feeling.
The current GUI mirrors the tools (tabs per script). The redesign mirrors the
user's journeys. The engine (tradutor.py, diff_tool.py, merge.py,
glossary_manager.py, wiki_sync.py, scripts/) stays untouched — the new
GUI orchestrates it via subprocess and direct imports.
-
Project-centric, app owns the folder. The user never chooses output paths per run. The app manages one folder per translation project and knows where everything lives. No more scattered
ptBR_final_FINAL2.jsonchaos. -
State-first: every screen answers three questions. Where am I? What just happened? What happens next? The Home dashboard is the anchor; every journey ends by returning Home with a clear new state.
-
Free before paid. Everything free (Pre-Scan, glossary check, fullize, diff, audit, merge) is shown before anything that costs API money. Every paid action shows a cost/scope estimate first and requires one explicit click.
-
One primary action per screen. Engine knobs (workers, batch sizes, save-every) never appear in journeys. They live in Settings, defaulting to "auto".
-
Advanced stays reachable, out of the way. Glossary editing, wiki sync, model profiles: one click deeper, never in the main flow.
-
Never lose work. Resume by default; backups before every merge; the app remembers what has been done (project.json), so re-opening the app = continuing, not starting over.
One folder per translation project. Created by the app, or adopted from existing files (see §3).
RogueTraderPT/ ← the project folder
project.json ← state (tracks exact file paths)
input/
enGB_1.6.1.514.json ← current game dump (versioned name kept)
output/
ptBR_preserved_1.6.1.514.json ← master Preserved track (versioned)
ptBR_full_1.6.1.514.json ← master Full track (versioned)
patches/
2025-09-10_delta.json ← EN→EN delta
2025-09-10_delta_pt.json ← translated delta
audit/
2025-09-12_audit.json ← categorized report
2025-09-12_retry_uuids.json ← failed/identical/suspect UUID list
release/
traducao_FULL_1.6.1.514.zip ← mod-page-ready package
traducao_PRESERVED_1.6.1.514.zip
backups/
2025-09-10_pre-merge_ptBR_full_1.6.1.514.json
Versioned-name convention (locked 2026-07-25): files keep their
version-carrying names (enGB_<ver>.json, ptBR_<track>_<ver>.json) so the
game version is visible at a glance. The app never renames or copies the
user's files — project.json tracks the exact current path of the input and
each track, and every flow resolves paths from there. Renames happen only on
an explicit version bump (Patch Day merges into ptBR_<track>_<new_ver>.json;
the previous version's master is preserved in backups/).
project.json (owned by the app, never edited by hand):
{
"app_version": "2.0",
"game_profile": "rogue_trader",
"game_version": "1.3.2",
"glossary": "glossary.json",
"glossary_stamp": {"terms": 2694, "built_for": "rogue_trader"},
"input": {"file": "input/enGB.json", "original_name": "enGB_1.6.1.514.json", "sha256": "…", "strings": 70412},
"tracks": {
"preserved": {"status": "done", "updated": "2025-09-01", "translated": 52100, "skipped_free": 18312},
"full": {"status": "done", "updated": "2025-09-01"}
},
"last_audit": {"date": "2025-09-12", "failed": 12, "identical": 340, "suspect": 88},
"releases": [{"version": "1.4", "date": "2025-09-13", "track": "full"}]
}This file is what lets the Home screen say "Preserved 100% ✓ · Full 100% ✓ · 12 strings failed last audit" instead of the user remembering.
Filename convention: game dumps and outputs carry the game version in the
filename (enGB_1.6.1.514.json, ptBR_full_1.6.1.514.json). The app copies
the input to the canonical input/enGB.json but records the source filename
in input.original_name and auto-detects game_version from it (editable
from the Home dashboard when detection fails).
For users who already translated (the maintainer included):
"Adopt existing translation" dialog:
- Point at an existing folder or loose files.
- The app detects which files look like EN dumps / preserved / full outputs
(schema sniffing:
{strings: {uuid: {Text}}}+ PT-BR heuristics + preserve-map). - User confirms the mapping → app copies (never moves) them into the
project structure, backfills
project.json, done. - From then on, everything is managed.
The app opens here. Always.
┌──────────────────────────────────────────────────────────┐
│ W40K TRANSLATOR [Settings ⚙] │
│ │
│ INPUT enGB.json ✓ 70,412 strings · game v1.3.2 │
│ TRACKS Preserved ✓ 100% Full ✓ 100% │
│ AUDIT ⚠ 12 failed · 340 identical · 88 suspect │
│ GLOSSARY 2,694 terms · Rogue Trader ✓ │
│ │
│ Fluxo: ① traduzir → ② auditar → ③ publicar │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ ┌────────┐ │
│ │ ① Nova │ │ ② Corrigir &│ │ ③ Final.│ │ ④ Dia │ │
│ │ Tradução │ │ Auditar │ │& Publicar│ │de Patch│ │
│ └─────────────┘ └─────────────┘ └─────────┘ └────────┘ │
│ [ ⑤ Glossário (construção e manutenção) ] │
└──────────────────────────────────────────────────────────┘
Buttons light up / grey out based on state (e.g. ② needs an output; ③ needs a clean-or-confirmed audit — see the audit gate below; ④ needs an output). Greyed-out buttons explain why on hover — that alone removes half the confusion.
Journey order matters (locked 2026-07-25): the canonical flow is ① translate → ② audit & fix → ③ package. A release should ship 100% audited; ④ Patch Day feeds new deltas back into ①→②→③; ⑤ Glossary is its own space (maintenance + auto-build), not a step in the flow.
The primary journey. Preserve-mode is the default and first-class.
- Step 1 — Input. Shows
input/enGB.jsonif present, or "drop your enGB.json here" (with a helper: "find it in …\WH40KRT_Data\StreamingAssets\Localization"). Track choice: ◉ Preserved (recommended — mechanics/wiki names stay EN) / ○ Full only later. - Step 2 — Pre-Flight (free). Runs Pre-Scan + glossary health:
52,100 strings to translate · 18,312 free (skips + exact terms)Glossary coverage: 96% ✓(see §5 for the low-coverage warning)New term candidates: 41 found→ optional review- Cost estimate:
≈ $1.20 on deepseek-v4-flash · ~3.5 h - Model picker (profiles only; no knobs).
- Step 3 — Run. Progress bar + live counters (done/free/failed/ETA/cost so far), Pause and Stop (resume-safe by engine design). On finish: "Preserved track done ✓ — next: audit & fix before publishing" → journey ②.
Where placeholder-mangling ($TERM4$, {mf|him|her} leftovers) gets cleaned.
Runs before every release — see the audit gate in §4.3.
- Run audit (free) → categorized table:
Failed (API errors) · Identical (EN = PT) · Suspect (leaked placeholders, broken tags, gender-tag artifacts). - Each row shows EN vs PT side by side; filter by category; select all/none.
- Retry selected → exports UUID list → engine re-translates only those
(
--retranslate-map) → auto-merge back with backup. - Edit manually for one-off fixes (inline editor, writes through merge path so backups still happen).
- Audit result + timestamp recorded in
project.json.last_audit— this is what the release gate checks.
- Fullize card: "Turn your Preserved translation into 100% PT — FREE, no
API." One button →
output/ptBR_full.json. - Release card: pick track (Preserved / Full), version tag → Export mod
package: zip containing the file already renamed to
enGB.json+ auto-generatedINSTALL.txt(backup original, drop into Localization folder) + optional changelog stub. Built for uploading straight to Nexus. Exported zips follow the user's naming conventiontraducao_<TRACK>_<game_version>.zip(e.g.traducao_FULL_1.6.1.514.zip), using thegame_versionrecorded in project.json. - Audit gate (locked 2026-07-25) — a release ships 100% audited:
- Outputs changed since the last audit (or audit never ran) → export blocked: "Rode a auditoria antes de publicar."
- Last audit has
failed/suspect> 0 → counts shown, export requires an explicit "exportar mesmo assim" confirmation (some flags are false positives, e.g. proper nouns in "identical" — override exists but is never the default path). - Clean audit newer than the outputs → export flows normally.
- Shows the diff vs. the previous release ("312 strings changed since v1.3").
The money-anxiety killer.
- Drop the new
enGB.json(old one is already archived ininput/). - Free diff → "The patch changed 1,240 of 70,412 strings. Translating only the delta ≈ $0.08."
- Run → translate delta → auto-merge into both masters with timestamped backup → both outputs + project.json updated.
- Ends with: "Your translation is current again ✓ — export a new release?"
The glossary is a first-class citizen, not a side tool. For Rogue Trader it is already built (2,694 terms); this space is what keeps it alive for DLCs and future games.
- Term table: search/filter by category, preserve/inline flags, add / edit / remove.
- Wiki seed button (existing live-wiki fetch).
- Glossary auto-build (locked 2026-07-25): the candidate scanner (already
used read-only in Pre-Flight) becomes a builder workflow:
- Scan the current input → ranked list of unknown repeated EN terms.
- User approves / rejects candidates.
- Approved terms get PT translations: typed manually or suggested in batch by the LLM (small, explicit API cost — one batch, not the whole game) with human review before merging.
- Merge into the glossary with the proper category/preserve flags → stamp updated. Pre-Flight links here when it finds candidates ("41 termos novos encontrados — revisar no Glossário").
- Glossary stamp shown everywhere: "built for Rogue Trader · 2,694 terms".
- API keys — keyring storage (keep existing implementation), per provider.
- Model profiles — editable table: model name, workers, batch size per
Pre-Scan tier (short/medium/long), save-every. Saved to
user_profiles.jsonin the project/app config, overridingmodel_profiles.pywithout code edits. New model drops → add a row here. - Defaults — default model, theme, project folder location.
The Pre-Flight step computes coverage = share of translatable strings containing ≥1 known glossary term:
- High coverage → proceed normally.
- Slightly low + many candidates → "New content (DLC?) — review 41 candidate terms before translating?" (journey ⑤ lite, inside the wizard).
- Very low → hard warning: "This input doesn't look like Rogue Trader. This glossary will force wrong terms. Create a new game profile?"
Game profiles (later, not v1): a profile bundles glossary + system prompt +
tag rules. Today tradutor.py's SYSTEM_PROMPT hardcodes W40K/Owlcat; the plan
is to externalize it into the profile so the same engine can serve other
Owlcat-format games (e.g. Dark Heresy-style JSON). v1 only names the profile
in project.json so the migration path exists.
- PySide6 desktop app (familiar, no new runtime; launcher script flow).
- Keyring API-key storage.
- Live-wiki glossary fetch.
- Grimdark theme (optional toggle; readability first).
- Full game-profile editor (only the
rogue_traderprofile; prompt still hardcoded in the engine). - Multi-project window (v1: one project open at a time, switchable).
- Cloud anything.
| Phase | Delivers | Depends on |
|---|---|---|
| P1 ✅ (2026-07-25) | Project scaffold + project.json + Home dashboard + Adopt existing files |
— |
| P2 ✅ (2026-07-25) | ① New Translation wizard w/ Pre-Flight + cost estimate | P1 |
| P3 ✅ (2026-07-25) | Fullize + mod-page zip (release mechanics) | P2 |
| P4 ✅ (2026-07-25) | ② Fix & Audit journey + audit gate on release (reorders flow to ①→②→③) | P2 |
| P5 ✅ (2026-07-25) | ④ Patch Day (delta → translate → auto-merge) | P4 |
| P6 ✅ (2026-07-25) | ⑤ Glossary space (term table + auto-build) + Settings | P1 |
P6 shipped in two drops. ⚙ Settings — SettingsDialog
(Provedores / Modelos / Geral) on the dashboard ⚙ button; user overrides
persist outside repo/projects in %APPDATA%/W40KTranslator/
(user_providers.json + user_profiles.json) via the Qt-free
w40k_settings.py; w40k_preflight resolves models/providers/subprocess
env through the effective layer; model pickers default to the effective
default_model. ⑤ Glossário — GlossaryDialog (Termos / Construir)
over the PROJECT glossary (§9.7): sortable/filterable term table with
add/edit/remove (atomic write + once-per-session backup in backups/),
auto-build (candidate scan → approve/reject → optional single-batch LLM
PT suggestion with human review → dedupe merge with metadata stamp),
offline wiki seed + live MediaWiki single-term fetch; Qt-free logic in
w40k_glossary.py; Pre-Flight candidate hint links to ⑤. No placeholders
remain.
| P7 | Game profiles (prompt externalization; inclui editor de prompt por perfil) | all |
Each phase ships a usable app; P1 alone already kills the folder chaos.
- UI language: PT-BR.
- Theme: keep the grimdark 40k look (dark + gold) as the default.
- App name: W40K Translator (placeholder brand; may change later).
P1 shipped as
w40k_translator.py+w40k_project.py+launch_translator.bat. P2 addedw40k_preflight.py(Qt-free Pre-Flight/credentials/progress-parse layer). P3 addedw40k_release.py(Qt-free fullize/release-zip layer). P4 addedw40k_audit.py(Qt-free audit/retry/merge/gate layer). P5 addedw40k_patch.py(Qt-free patch-diff/delta/merge-hygiene layer). P6 Settings (2026-07-25) addedw40k_settings.py(Qt-free user-override layer overmodel_profiles.py, persisted in%APPDATA%/W40KTranslator/, redirectable viaW40K_CONFIG_DIR) andkey_store_deleteinw40k_preflight.py. P6 bug-fix round (2026-07-25): enginetradutor.py—-wagora defaultNone(explícito é literal; auto-bump só quando omitido/<=0) e cliente OpenAI commax_retries=1(sem retry duplo sob rate-limit);w40k_preflight.pyganhoukey_store_set_ex(diagnóstico do cofre),test_connection(probe /models → fallback chat completions) ewrite_prescan_cache(reuso do Pre-Scan via--prescan-cacheno wizard); builders de audit/patch (w40k_audit._profile_run_flags) passam-w/--save-everydo perfil EFETIVO; falha de gravação no cofre agora gera aviso visível (root cause do relato: pacotekeyringnão estava instalado no Python do usuário). P6 ⑤ Glossário (2026-07-25):w40k_glossary.py(Qt-free: load/save atômico + backup, CRUD com validação, filtro, scan de candidatos com contexto, guess de categoria, merge com dedupe, prompt/parser da sugestão LLM em lote, semente wiki offline viawiki_synce fetch ao vivo MediaWiki portado da GUI antiga) +GlossaryDialog. P6 prep (2026-07-25, no phase row):Project.reconcile()/cleanup_stale()- ReconcileDialog (§9.6); per-project glossary with extended additive
metadata(§9.7) —import_glossary/create_empty_glossary, GlossaryChoiceDialog, project-first glossary resolution inw40k_preflight.resolve_glossary_path; repoglossary.jsongained additive metadata (terms untouched, engine-verified). Versioned-name refactor (2026-07-25, §2/§9.6 revised): registration is in place — the app never copies/renames user files;project.jsontracks exact paths (input.file,tracks.<track>.file) resolved viaProject.track_path()/track_target()across P2–P5 flows; renames only on explicit version bump (rename_files_to_version; Patch Day post-merge, "editar versão" confirm);known_filessha registry prevents re-prompts for replaced/archived dumps.
- ReconcileDialog (§9.6); per-project glossary with extended additive
- Flow order (locked 2026-07-25): ① translate → ② audit & fix → ③ package; release is gated on a clean-or-explicitly-confirmed audit (§4.3).
- Glossary auto-build (locked 2026-07-25): candidate scan → approve → manual or LLM-suggested PT terms → merge; lives in journey ⑤ (§4.5).
- State reconciliation (locked 2026-07-25, revised same day): the app
detects known files dropped by hand into
input//output/and offers to register them intoproject.jsonin place — it never renames or copies the user's files, and once registered a file must never re-trigger the dialog. Tracks and input follow the versioned-name convention (§2). - Per-project glossary (locked 2026-07-25): each project owns its
glossary file (imported from the community RT glossary, from another
project, or empty — never from scratch unless wanted). Glossary JSON
metadatadeclares:name,game,game_version,kind(base_game|mod),mod_name,parent. A mod project imports the RT glossary then adds/removes terms locally (§4.5 auto-build). - Prompt editor (roadmap, P7): game profiles bundle glossary + system prompt + tag rules; the profile's prompt is editable in the app so far-future non-W40K projects reuse the tool without code edits.