Options Page: Configuring Custom Prompts#
Custom prompts are managed on the options page via dedicated sections for both web page translation and video subtitles translation. The PersonalizedPrompts section allows users to manage prompts for web page translation, while the Custom Subtitle Prompts section (under Video Subtitles settings) provides similar functionality for subtitle translation. Each UI presents a card-based list of all available prompts, with controls for selection, editing, and deletion. Users can add new prompts or edit existing ones using a form presented in a modal sheet. The form requires a prompt name and prompt text, both of which are validated to ensure they are not empty. The default prompt is visually distinguished and cannot be deleted or renamed.
Custom prompts for video subtitles are managed independently from those for web page translation. This allows users to tailor translation instructions specifically for subtitle content, separate from general web page translation prompts. The interaction design, import/export, and selection logic are consistent across both sections.
All user-facing text, including button labels, badges, and dialog messages, is localized using the i18n system, ensuring a consistent experience across supported languages. The UI structure and localization keys are updated to reflect the new export mode and selection logic. The default prompt is always available as a view-only option and is not persisted in user storage.
Improved Interaction Design#
The prompt editing form now features two separate fields: System Prompt and Prompt. Both fields support quick-insert buttons for supported tokens (such as {{input}} and {{targetLang}}). Each button includes a tooltip explaining the token's meaning, making it easier for users to construct prompts correctly and understand how tokens are replaced during translation. These buttons are available when editing or creating a prompt, and are disabled for the default prompt. The tooltips are localized for all supported languages.
- System Prompt: Used to provide high-level translation instructions and context to the LLM. This field is especially important for batch translation and context-aware translation.
- Prompt: Used for the main translation instruction and input text.
Both fields are required for custom prompts. The default prompt provides built-in values for both fields, which are shown as read-only when editing the default prompt.
Prompt Selection and Export Mode#
The prompt list UI now supports two distinct modes:
-
Normal Mode:
- Each prompt card displays its name, a preview of the prompt text, and action buttons for editing and (if not default) deleting the prompt.
- The currently selected prompt is visually indicated with a badge (e.g., "in use").
- Clicking a card selects it as the active prompt for translation. The default prompt is visually distinguished, shown as a view-only card, and cannot be deleted, renamed, or exported. Selection of the default prompt uses a UI-only sentinel ID, but in configuration, the default is represented by
promptId: null.
-
Export Mode:
- Activated by clicking the "Export" button.
- Cards display checkboxes for selecting prompts to export, except for the default prompt, which cannot be selected or exported.
- Users can select multiple custom prompts and then click "Export Selected" to download them as a JSON file.
- A "Cancel" button exits export mode and clears the selection.
- Edit and delete actions are disabled in export mode.
All user-facing text, including button labels, badges, and dialog messages, is localized using the i18n system, ensuring a consistent experience across supported languages. The UI structure and localization keys are updated to reflect the new export mode and selection logic. The default prompt is always available as a view-only option and is not persisted in user storage.
Popup Page: Selecting a Prompt for Translation#
The prompt selection dropdown is available both in the popup page and in the Translation Hub (accessible via the Tools sidebar or options page). The TranslatePromptSelector component provides a dropdown menu listing all configured prompts. Users can select which prompt to use for the current translation session. The selected prompt is stored in the translation configuration and is used for subsequent translation requests. The dropdown and its labels are fully localized. Only providers that support LLM-based translation expose this selector; for other providers, the selector is hidden.
This ensures a consistent prompt selection experience whether translating from the popup or from the Translation Hub interface. All prompt management and selection logic is shared between both entry points.
Importing and Exporting Prompts#
Users can import prompts from a JSON file using the import button on the options page. The import process reads the file, parses the JSON, assigns new UUIDs to each imported prompt, and merges them into the current configuration. If an imported prompt does not include a systemPrompt field (for backward compatibility), it is backfilled with an empty string. Success and error notifications are displayed using toast messages. Exporting prompts works by entering export mode, selecting one or more prompts via checkboxes, and clicking the "Export Selected" button, which downloads a JSON file containing the selected prompts' names, system prompts, and texts. The import/export format is a simple array of objects with name, systemPrompt, and prompt fields.
Example export format:
[
{
"name": "Formal Style",
"systemPrompt": "You are a professional translator. Translate to {{targetLang}} in a formal tone.",
"prompt": "Translate the following text to {{targetLang}} in a formal tone: {{input}}"
},
{
"name": "Conversational",
"systemPrompt": "You are a friendly translator. Translate to {{targetLang}} as if speaking to a friend.",
"prompt": "Translate to {{targetLang}} as if speaking to a friend: {{input}}"
}
]
When importing, any missing systemPrompt field is set to an empty string for compatibility.
Configuration Schema#
Custom prompts are stored in the translation configuration under customPromptsConfig, and in the video subtitles configuration under videoSubtitles.customPromptsConfig. Both use the same schema, defined using zod:
export const translatePromptObjSchema = z.object({
name: z.string(),
id: z.string(),
systemPrompt: z.string(),
prompt: z.string(),
});
export const customPromptsConfigSchema = z.object({
promptId: z.string().nullable(), // currently selected prompt ID (null means default)
patterns: z.array(translatePromptObjSchema), // list of all custom prompts
}).superRefine((data, ctx) => {
if (data.promptId !== null) {
const patternIds = data.patterns.map(p => p.id)
if (!patternIds.includes(data.promptId)) {
ctx.addIssue({
code: 'invalid_value',
values: patternIds,
message: `promptId "${data.promptId}" must be null or match a pattern id`,
path: ['promptId'],
})
}
}
})
Each prompt object contains an id (string, UUID), name (string), systemPrompt (string), and prompt (string). The configuration enforces that all fields are present and non-empty. The default prompt is not stored in the patterns array and is selected by setting promptId to null.
The videoSubtitles config object now includes a customPromptsConfig field, which is managed independently from the main translation prompts. This allows users to define and select different prompts for subtitle translation versus web page translation.
Integration with the Translation Workflow#
When a translation is requested, the system retrieves the currently selected prompt by checking customPromptsConfig.promptId. If promptId is null, the default prompt (defined as a code constant) is used. Otherwise, the system looks up the custom prompt in customPromptsConfig.patterns by ID. If the prompt is not found, it falls back to the default prompt. Each prompt now consists of two fields: systemPrompt and prompt. Both may contain tokens such as {{targetLang}} and {{input}}, which are replaced at runtime with the actual target language and input text. This allows for highly customizable translation instructions sent to the LLM provider.
Example usage in code:
let systemPrompt: string
let prompt: string
if (!promptId) {
systemPrompt = DEFAULT_TRANSLATE_SYSTEM_PROMPT
prompt = DEFAULT_TRANSLATE_PROMPT
} else {
const customPrompt = patterns.find(pattern => pattern.id === promptId)
systemPrompt = customPrompt?.systemPrompt ?? DEFAULT_TRANSLATE_SYSTEM_PROMPT
prompt = customPrompt?.prompt ?? DEFAULT_TRANSLATE_PROMPT
}
const finalSystemPrompt = systemPrompt
.replaceAll('{{targetLang}}', targetLang)
.replaceAll('{{input}}', inputText)
const finalPrompt = prompt
.replaceAll('{{targetLang}}', targetLang)
.replaceAll('{{input}}', inputText)
For LLM-based providers, both the resolved systemPrompt and prompt are included in the translation request and in the hash for cache invalidation when either changes. The translation API now passes both fields to the LLM provider.
Localization Support#
All UI strings related to custom prompts are localized using the i18n system. The English localization file, for example, defines keys for titles, descriptions, button labels, dialog messages, and export mode actions under options.translation.personalizedPrompts and exportPrompt. This ensures that users can manage and select prompts in their preferred language, and that prompt instructions are clearly explained in the UI. The token tooltips and export mode controls are also localized for all supported languages.
Example localization keys:
options:
translation:
personalizedPrompts:
title: Personalized Prompts
description: Customizing different types of Prompts allows you to adjust the Prompt type yourself during translation. A Prompt represents the text that the user sends to the LLM.
addPrompt: Add Prompt
import: Import
export: Export
current: in use
editPrompt:
promptCellInput:
input: Text content to translate
targetLang: Target language
exportPrompt:
exportSelected: Export Selected
cancel: Cancel
# ...
translatePrompt:
title: AI Translation Style
description: Select a Prompt to use during translation. Add or modify custom Prompts on the options page.
This design enables a flexible, user-friendly, and internationalized workflow for managing and applying custom translation prompts in Read Frog, with an improved and intuitive export and selection experience.