Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,9 @@ Two things it deliberately does not own:
Works with any OpenAI Chat Completions-compatible API, plus Anthropic's native
Messages API:
- OpenAI, Anthropic, Google Gemini, DeepSeek, OpenRouter, Ollama, LM Studio
- Request format: `{model, messages, temperature, max_tokens}`
- Request format: `{model, messages, max_tokens}` plus whatever per-model
parameters `shared/api-compat.js` decides (see the rules below —
`temperature` is only sent where the model still honours it)
- Response: `{choices[0].message.content}`, or `{content[0].text}` for Anthropic

**All of it lives in `shared/api-compat.js`** — the provider catalog, every
Expand Down
36 changes: 18 additions & 18 deletions background/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const languageNames = {

// Math placeholder rule - always appended to prompts (cannot be overridden by custom prompts)
const MATH_PLACEHOLDER_RULE = `
IMPORTANT: Keep placeholders like {{1}}, {{2}} etc. exactly as they are - do not translate, modify, or add line breaks around them.`;
Placeholders such as {{1}}, {{2}} stand for formulas the page renders itself. Keep each one exactly as written, in place, with no line breaks added around it.`;

// Single word/phrase prompt template (no math placeholder rule)
const SINGLE_WORD_PROMPT = `You are a bilingual dictionary. Translate the given word or short phrase to {targetLang}.
Expand All @@ -102,27 +102,27 @@ Return JSON only with keys "translation" and "phonetic".
// Default prompt template
const DEFAULT_PROMPT = `You are a professional translator. Translate the given text to {targetLang}.
Rules:
1. Provide ONLY the translation, no explanations or notes
1. Reply with the translation only, no explanations or notes
2. Maintain the original formatting (line breaks, punctuation)
3. Keep technical terms, brand names, and proper nouns in their original form when appropriate
4. If the text is already in the target language, return it EXACTLY as is (no paraphrasing or reordering)
4. If the text is already in the target language, return it unchanged (no paraphrasing or reordering)
5. Translate naturally, not literally`;

// Default batch prompt template
const DEFAULT_BATCH_PROMPT = `You are a professional translator. Translate the given numbered texts to {targetLang}.
Rules:
1. Return translations in the SAME numbered format: [1] translation1 [2] translation2 etc.
1. Return translations in the same numbered format: [1] translation1 [2] translation2 etc.
2. Keep the numbering system exactly as given
3. Maintain original formatting within each translation
4. Keep technical terms, brand names, and proper nouns in their original form when appropriate
5. If a text is already in the target language, return it EXACTLY as is (no paraphrasing or reordering)
5. If a text is already in the target language, return it unchanged (no paraphrasing or reordering)
6. Translate naturally, not literally`;

// Batch output rules appended when using custom prompts
const BATCH_OUTPUT_RULES = `BATCH FORMAT RULES:
1. Return translations in the SAME numbered format: [1] translation1 [2] translation2 etc.
1. Return translations in the same numbered format: [1] translation1 [2] translation2 etc.
2. Keep the numbering system exactly as given
3. Output ONLY the translations, nothing else`;
3. Output the translations and nothing else`;

// Get browser language and map to supported language
function getBrowserLanguage() {
Expand Down Expand Up @@ -1818,27 +1818,27 @@ async function translateBatchWithAI(texts, targetLang, settings) {
// Fast batch prompt template
const FAST_BATCH_PROMPT = `You are a professional translator. Translate multiple text segments to {targetLang}.

CRITICAL RULES:
The segments are parsed by a program, so the output format is a contract:
1. Input segments are separated by "{delimiter}"
2. Output translations MUST be separated by "{delimiter}" in the EXACT same order
3. Output ONLY the translations, nothing else
2. Output translations separated by "{delimiter}", in the same order
3. Output the translations and nothing else
4. Keep technical terms, brand names, proper nouns in original form
5. If already in target language, return EXACTLY as is (no paraphrasing or reordering)
6. MUST have exactly the same number of output segments as input
7. Preserve placeholders and inline tags EXACTLY: keep {{1}}-style placeholders unchanged, and keep paired tags like <a1>...</a1> or <strong2>...</strong2> with the same names and numbers, wrapping the translated text they originally wrapped. Never invent, drop, or renumber tags.
5. If a segment is already in the target language, return it unchanged (no paraphrasing or reordering)
6. The number of output segments equals the number of input segments; an empty segment stays empty
7. Preserve placeholders and inline tags: keep {{1}}-style placeholders unchanged, and keep paired tags like <a1>...</a1> or <strong2>...</strong2> with the same names and numbers, wrapping the translated text they originally wrapped. Do not invent, drop, or renumber tags.

Example:
Example (target language shown as Chinese):
Input: Hello{delimiter}Read <a1>the docs</a1> first{delimiter}Thank you
Output: 你好{delimiter}请先阅读<a1>文档</a1>{delimiter}谢谢`;

// Fast batch output rules appended when using custom prompts
function getFastBatchOutputRules(delimiter) {
return `BATCH FORMAT RULES:
1. Input segments are separated by "${delimiter}"
2. Output translations MUST be separated by "${delimiter}" in the EXACT same order
3. Output ONLY the translations, nothing else
4. MUST have exactly the same number of output segments as input
5. Preserve placeholders and inline tags EXACTLY: keep {{1}}-style placeholders unchanged, and keep paired tags like <a1>...</a1> with the same names and numbers, wrapping the translated text they originally wrapped. Never invent, drop, or renumber tags.`;
2. Output translations separated by "${delimiter}", in the same order
3. Output the translations and nothing else
4. The number of output segments equals the number of input segments; an empty segment stays empty
5. Preserve placeholders and inline tags: keep {{1}}-style placeholders unchanged, and keep paired tags like <a1>...</a1> with the same names and numbers, wrapping the translated text they originally wrapped. Do not invent, drop, or renumber tags.`;
}

// Fast batch translation with delimiter
Expand Down
12 changes: 6 additions & 6 deletions i18n/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,25 +311,25 @@ const I18N_MESSAGES = {
presetApplied: 'Preset applied',
promptStandard: `You are a professional translator. Translate the given text to {targetLang}.
Rules:
1. Provide ONLY the translation, no explanations or notes
1. Reply with the translation only, no explanations or notes
2. Maintain the original formatting (line breaks, punctuation)
3. Keep technical terms, brand names, and proper nouns in their original form when appropriate
4. If the text is already in the target language, return it EXACTLY as is (no paraphrasing or reordering)
4. If the text is already in the target language, return it unchanged (no paraphrasing or reordering)
5. Translate naturally, not literally`,
promptLiteral: `You are a precise translator. Translate the given text to {targetLang}.
Rules:
1. Provide ONLY the translation, no explanations
1. Reply with the translation only, no explanations
2. Translate as literally as possible while maintaining grammatical correctness
3. Preserve the original sentence structure when possible
4. Keep all technical terms, names, and proper nouns unchanged
5. If the text is already in the target language, return it EXACTLY as is (no paraphrasing or reordering)`,
5. If the text is already in the target language, return it unchanged (no paraphrasing or reordering)`,
promptCreative: `You are a creative translator and language artist. Translate the given text to {targetLang}.
Rules:
1. Provide ONLY the translation, no explanations
1. Reply with the translation only, no explanations
2. Prioritize natural, fluent expression in the target language
3. Adapt idioms and cultural references to equivalent expressions in the target culture
4. Maintain the tone and emotion of the original text
5. If the text is already in the target language, return it EXACTLY as is (no paraphrasing or reordering)`,
5. If the text is already in the target language, return it unchanged (no paraphrasing or reordering)`,

// Popup
translateCurrentPage: 'Translate Page',
Expand Down
2 changes: 1 addition & 1 deletion shared/api-compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@
name: 'Anthropic Claude',
endpoint: 'https://api.anthropic.com/v1/messages',
// Native Anthropic API accepts version aliases (no date suffix); aliases
// avoid stale/incorrect dates. claude-opus-4-1 is omitted: it retires
// avoid stale/incorrect dates. claude-opus-4-1 is omitted: it retired on
// 2026-08-05.
models: ['claude-opus-5', 'claude-sonnet-5', 'claude-fable-5', 'claude-haiku-4-5', 'claude-opus-4-8', 'claude-opus-4-7', 'claude-sonnet-4-6', 'claude-opus-4-5', 'claude-sonnet-4-5'],
defaultModel: 'claude-sonnet-5'
Expand Down
4 changes: 2 additions & 2 deletions shared/ocr.js
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,10 @@
// translation is step 2, and it does not happen here (see the file header).
const OCR_SYSTEM_PROMPT = `You are an OCR engine. The user sends one image.
Do both of the following:
1. Extract ALL human-readable text from the image, preserving reading order and line breaks.
1. Extract all human-readable text from the image, preserving reading order and line breaks.
2. Detect the language the extracted text is written in.

Return ONLY a JSON object with exactly these keys:
Return a JSON object, and nothing else, with exactly these keys:
{"text": "<extracted text, verbatim>", "language": "<BCP 47 code such as en, ja, zh-Hans>"}

Rules:
Expand Down
2 changes: 1 addition & 1 deletion test/unit/api-compat.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ test('catalog defaults point at a model in their own list', () => {
test('catalog lists no retired models', () => {
// Append here as vendors retire ids, so they cannot be reintroduced.
const retired = [
'claude-opus-4-1', // retires 2026-08-05
'claude-opus-4-1', // retired 2026-08-05
'anthropic/claude-opus-4.1',
'gemini-2.0-flash', // shut down 2026-06-01
'gemini-2.0-flash-lite',
Expand Down