System and Translation Prompts
Translation requests are driven by system prompts and translation prompts together: the system prompt files control “how to translate” and “what to output,” while translation prompts supply custom rules, glossary extraction, and AI line-breaking requirements. Use this page when you need to know when a prompt file is read, in what order it is concatenated, where the target_lang placeholder is replaced, and how the result enters an OpenAI/Gemini request.
This guide does not cover prompt-file listing, applying, or CRUD (see Prompt list, apply, and preview), nor the structured editor (see Structured prompt editor and format); AI OCR, AI colorizer, and AI renderer prompts are covered in AI OCR prompt, AI colorizer prompt, and AI renderer prompt. How history pages become messages is covered in Context and Prompts.
When to use it
- Fixed system prompt files:
dict/system_prompt_hq.yaml(base system prompt) anddict/system_prompt_hq_format.yaml(output format). They are loaded fromdict/at runtime by filename stem, are not part of the user prompt list, and have no dedicated desktop editor. - Translation prompts: the custom HQ prompt pointed to by
translator.high_quality_prompt_path(user.yaml/.yml/.jsonfiles underdict/),dict/glossary_extraction_prompt.yaml(glossary-extraction rules), anddict/system_prompt_line_break.yaml(AI line-breaking prompt). - Related config keys:
translator.high_quality_prompt_path,translator.extract_glossary,render.disable_auto_wrap; full parameter documentation is in Translation settings and Typesetting and rendering. - This guide only explains how prompts are loaded, combined, and injected into the OpenAI/Gemini system instruction; it does not cover translator selection, API credentials, or candidate-slot rotation (see Translator selection and API management).
- No real API key, private prompt text, or local absolute path is written on this page. Prompt content is user data; remove it from logs, request exports, and debug directories before sharing.
Plain Translation Prompt File Format
Custom translation prompts use a template file: copy dict/prompt_example.yaml and rename it to your own file (for example dict/my_manga_prompt.yaml), then click “Apply Selected Prompt” on the Prompt Management page or choose it from the “Custom Prompt” dropdown under “Settings → Translation”. The file is YAML and its root must be an object, with this structure:
system_prompt: ""
glossary:
Person:
- original: ""
aliases:
- original: ""
translations:
- text: ""
condition: ""
description: ""
overwrite: false
Location: []
Org: []
Item: []
Skill: []
Creature: []system_prompt: a string for the custom system prompt body; it can be empty. When empty, only the built-in base prompt is used; when filled, this content is prepended before the base prompt.glossary: the terminology table grouped byPerson/Location/Org/Item/Skill/Creature. Every category uses the same shape: top-leveloriginalis the canonical source name,aliasesstores its source-language forms, and each alias owns one or more manually authoredtranslationswith an optionalcondition; an empty array (such asLocation: []) means the category has no entries.- Placeholder:
{{{target_lang}}}in the text is replaced with the target language name at each request construction, see Placeholder replacement.
Desensitized example (structure and placeholder usage only, no real prompt content):
system_prompt: |
You are a manga translation assistant. Make the {{{target_lang}}} translation natural and keep character voice consistent.
glossary:
Person:
- original: "Example Character Name"
aliases:
- original: "Example Character Name"
translations:
- text: "Example Character Translation"
description: "Example character description"
overwrite: true
Location: []
Org:
- original: "Example Organization Name"
aliases:
- original: "Example Organization Name"
translations:
- text: "Example Organization Translation"
overwrite: false
Item: []
Skill: []
Creature: []Use it in Prompt Management
Select and apply a translation prompt in Prompt Management
Open “Prompt Management”. The “Prompt List” shows only user prompt files under dict/ and excludes system prompt stems (system_prompt_hq, system_prompt_hq_format, system_prompt_line_break, glossary_extraction_prompt, ai_ocr_prompt, ai_colorizer_prompt, ai_renderer_prompt). Select a file and click “Apply Selected Prompt”; the app writes dict/<filename> to translator.high_quality_prompt_path and persists it, and the status label shows “Current prompt: {filename}”.
Full list, preview, and editing operations are in Prompt list, apply, and preview; structured editing and save validation are in Structured prompt editor and format.
Enable the related toggles in Settings
- Open “Settings” → “Translation” and enable “Auto Extract Glossary”. This writes
translator.extract_glossary; only when a parseable custom prompt also exists does the request append the glossary-extraction rules and thenew_termsoutput format. - Open “Settings” → “Typesetting” and enable “AI Line Breaking”. This writes
render.disable_auto_wrap; when enabled, the translation request loadsdict/system_prompt_line_break.yamland attachesoriginal_region_countto each region in the user input JSON. - The on-screen name of
translator.high_quality_prompt_pathis “Custom Prompt”. Its dynamic-settings control is implemented indynamic_settings.py(it rescansdict/and excludes system prompts when the dropdown opens); the actual entry point for setting this key is “Apply Selected Prompt” in Prompt Management.
How prompts are loaded
When files are loaded
Before a translation batch starts, _load_and_prepare_prompts() prepares the prompts once:
- If
translator.high_quality_prompt_pathis non-empty, the path is normalized (normalize_server_resource_path), relative paths are joined withBASE_PATH, andload_custom_prompt()parses the file. If the exact path does not exist, it retries with the extension replaced in the order.yaml→.yml→.json; parse failures only log a warning and do not abort translation. - If
render.disable_auto_wrapis true,load_line_break_prompt()loadssystem_prompt_line_breakfromdict/intoctx.line_break_prompt_json; a missing file is also only logged.
The base system prompt, output format, and glossary-extraction prompt are not preloaded: on every request construction (including retries), _build_system_prompt() reads system_prompt_hq and system_prompt_hq_format from dict/ by stem, and glossary mode additionally reads glossary_extraction_prompt. The loader prefers .yaml, then .yml, then .json.
Composition order
_build_system_prompt() concatenates the prompts into a single text block in a fixed order: retry hint (retries only) → AI line-break prompt (optional) → custom HQ prompt (optional) → base system prompt → output format. The custom prompt is recursively flattened into a text block by _flatten_prompt_data(); when glossary extraction is enabled and the custom prompt is valid, the glossary-extraction rules and the extended new_terms output format are appended after the base prompt, with sections separated by \n\n---\n\n.
flowchart LR
R["Retry hint (retries only)"] --> L["AI line-break prompt (optional)"]
L --> C["Custom HQ prompt (optional)"]
C --> S["system_prompt_hq or code fallback"]
S --> G{"extract_glossary and\ncustom prompt valid?"}
G -->|no| O["Standard translations output format"]
G -->|yes| T["Glossary rules + new_terms output format"]
O --> API["OpenAI system message\nor Gemini system_instruction"]
T --> API
API --> U["Current-page JSON user prompt"]
If the base system prompt is missing or empty, the in-code fallback (_HQ_FALLBACK_PROMPT) is used; a missing output-format prompt logs a warning but the request still goes out with weaker format constraints.
Placeholder replacement
Placeholders in prompt files are literal triple-brace markers (for example {{{target_lang}}}), not Python string-format syntax. At each request construction, the runtime replaces the marker with the full target-language name: VALID_LANGUAGES maps language codes to full names (such as CHS → Chinese (Simplified), JPN → Japanese), and unknown codes are kept as-is. Replacement happens only in the in-memory request text; the dict/ files are never rewritten by it.
| Placeholder | Files | Replaced when | Replaced with |
|---|---|---|---|
{{{target_lang}}} | system_prompt_hq, system_prompt_hq_format, custom prompts, glossary_extraction_prompt | Every request construction | Full target-language name |
{{{optional_new_terms_rule}}} | system_prompt_hq_format | Only when extract_glossary=True | Rule text requiring a new_terms key; empty in normal mode |
{{{optional_new_terms_example_suffix}}} | system_prompt_hq_format | Only when extract_glossary=True | The new_terms section in the output JSON example; empty in normal mode |
{{{optional_new_terms_final_instruction}}} | system_prompt_hq_format | Only when extract_glossary=True | The closing instruction to return "new_terms": [] when none found; empty in normal mode |
Path into the OpenAI/Gemini system instruction
The combined system prompt is injected as a single unit; it is never split into multiple system messages per file:
flowchart TD
B["Single text produced by _build_system_prompt"] --> O{"Translator implementation"}
O -->|OpenAI| O1["messages[0] = role=system\ncontent = system prompt"]
O1 --> O2["History user/assistant messages"]
O2 --> O3["Current-page role=user (images in HQ)"]
O -->|Gemini| G1["generation_config.system_instruction\n= system prompt"]
G1 --> G2["contents = history user/model parts"]
G2 --> G3["Current-page user parts"]
- OpenAI (
openai.py,openai_hq.py): the system prompt is placed inmessages[0](role=system), followed by historyuser/assistantmessages from_build_openai_context_messages(), then the current-pageuserrequest; the HQ user message includes image content. - Gemini (
gemini.py,gemini_hq.py): the system prompt is assigned togeneration_config.system_instruction, andcontentsfirst carries historyuser/modelparts from_build_gemini_context_messages(), then the current-pageuserparts. - When glossary mode is enabled and the response contains
new_terms, both OpenAI and Gemini callmerge_glossary_to_file()to merge the new terms back into theglossaryfield of the custom prompt file (YAML or JSON depending on the extension). - Streaming and non-streaming transports use the same system instruction and message construction; with
disable_auto_wrapenabled, each region in the current-page user JSON carriesoriginal_region_countso final rendering can validate the[BR]marker count.
Limitations and notes
- Enabling “Auto Extract Glossary” alone has no effect: the code requires
bool(custom_prompt_json) and extract_glossaryto both be true, i.e. a parseable custom prompt must exist and the toggle must be on. - A missing base system prompt falls back to built-in code text; a missing format or glossary prompt only weakens constraints without crashing; an unparseable custom prompt is skipped and the base prompt is still used.
- Glossary write-back modifies the custom prompt file under
dict/; to keep the runtime from editing files, turn off “Auto Extract Glossary” or use a read-only copy. - System prompt files are excluded from the user prompt list and have no desktop editor; manual edits must keep the YAML/JSON root as an object.
render.disable_auto_wrapaffects both typesetting line wrapping and translation requests (line-break prompt +original_region_count); it is not a pure rendering toggle, and Qt's defaulttruediffers from the core/release defaultfalse.- Prompt text may contain business content and goes verbatim into requests and logs; remove prompt bodies, history text, paths, and credentials before sharing.
