How to Build a Claude-Powered Translation Tool
Building a Claude-powered translation tool comes down to three things: a prompt that constrains Claude to translate rather than chat, an API setup that handles streaming and errors cleanly, and a way to preserve formatting and context across long documents. Claude is a strong translation engine because it handles idiom, tone, and domain-specific terminology far better than rule-based systems, but it needs guardrails so it doesn't summarize, explain, or "improve" the source text instead of translating it.
This guide walks through the actual implementation: prompt structure, request handling, streaming for long documents, and how to go from a working prototype to something you can expose as a real product feature. If you want to skip the infrastructure work and get a translation endpoint running in minutes, SubToAPI turns your Claude access into a clean HTTPS API with streaming and usage tracking included.
Why Claude Works Well for Translation
Traditional machine translation (Google Translate, DeepL) is trained specifically for translation and is fast and cheap for generic text. Claude's advantage shows up in three situations:
- Domain-specific content — legal contracts, medical reports, technical documentation where word choice matters and context changes meaning.
- Tone preservation — marketing copy, UX strings, customer support replies where you need to keep a brand voice, not just swap words.
- Structured input — JSON, Markdown, HTML, or code comments where you need the translation to respect formatting instead of flattening it.
If your use case is "translate a product description and keep the HTML tags intact," Claude will outperform a generic MT API because it can reason about structure, not just substitute tokens.
Designing the Translation Prompt
The biggest failure mode when people build Claude translation tools is vague instructions that let the model add commentary, apologize, or explain its choices. Lock this down with a strict system prompt.
You are a professional translation engine. Translate the user's text
from {source_language} to {target_language}.
Rules:
- Output ONLY the translated text. No explanations, no notes, no quotes.
- Preserve all formatting: line breaks, HTML tags, Markdown, placeholders like {name}.
- Keep the same tone and register as the source (formal stays formal, casual stays casual).
- Do not translate proper nouns, brand names, or code identifiers.
- If the source language is ambiguous, detect it automatically.
Keep the user message to just the raw text you want translated — no extra framing. Mixing instructions into the user turn invites the model to respond to the instructions instead of the content.
Handling Auto-Detection
If you don't know the source language ahead of time, don't run a separate detection call — Claude can detect and translate in one pass. Just say "detect the source language automatically" in the system prompt and, if you need it for logging, ask for a one-line JSON header before the translation, then parse it out:
{"detected_language": "fr"}
followed by the translated text on the next line. This avoids a second round trip just to identify the language.
Building the Request
Here's a minimal implementation using SubToAPI's Messages endpoint, which proxies directly to Claude with your existing subscription:
async function translate(text, targetLanguage) {
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-3-5-sonnet-20241022",
max_tokens: 2048,
system: `You are a professional translation engine. Translate to ${targetLanguage}.
Output ONLY the translated text. Preserve formatting and placeholders exactly.`,
messages: [{ role: "user", content: text }],
}),
});
const data = await response.json();
return data.content[0].text;
}
This is enough to ship a basic internal tool. For production use, you'll want streaming and chunking for longer inputs — covered next.
Streaming for Long Documents
Translating a paragraph is fast enough to wait for. Translating a 10-page document is not — users will assume the request hung. Stream the response so the UI can show translated text appearing incrementally, the same way Claude's own chat interface does.
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-3-5-sonnet-20241022",
max_tokens: 4096,
stream: true,
system: "Translate to Spanish. Output only the translation.",
messages: [{ role: "user", content: longDocument }],
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// parse SSE events and append text deltas to your UI
}
See the streaming docs for the exact event format and parsing helpers.
Chunking Strategy for Very Long Inputs
Claude has a large context window, but there are two practical reasons to chunk long documents anyway:
- Consistency checks — if a document exceeds a few thousand words, splitting by section (headings, paragraphs) and translating each chunk separately makes it easier to spot-check quality and retry individual sections if something goes wrong.
- Terminology consistency — for documents with recurring technical terms, pass a short glossary in the system prompt for every chunk so the same term doesn't get translated two different ways across the document.
Glossary (use these exact translations):
- "invoice" → "facture"
- "due date" → "date d'échéance"
Split on natural boundaries (paragraphs, not arbitrary character counts) so you never cut a sentence mid-translation.
Handling Edge Cases
- Mixed-language input: tell Claude explicitly whether to translate everything or only non-target-language segments.
- Placeholders and variables: if your source text includes
{username}or%s, test that Claude leaves them untouched — add an explicit rule and a few examples if it doesn't. - Right-to-left languages: Claude handles Arabic and Hebrew translation correctly, but your frontend needs to apply
dir="rtl"— that's a UI concern, not a model concern. - Rate limits and retries: wrap calls with exponential backoff; translation tools often batch many short requests at once, which is exactly when you'll hit limits fastest.
Going From Prototype to Product
Once the core translation logic works, the remaining work is operational: API key management per customer, usage metering if you're billing by volume, and monitoring token spend. Rather than building that layer yourself, SubToAPI gives you application keys (sub_live_...), per-key usage metadata, and team seats out of the box, so you can focus on the translation UX instead of billing infrastructure. Check the quickstart to get a key running in a few minutes, and pricing if you're evaluating plans for a team.
Questions
Does Claude translate as accurately as DeepL or Google Translate for simple text? For straightforward sentences, dedicated MT engines are often faster and comparably accurate. Claude pulls ahead on idiomatic, domain-specific, or structured content where context and tone matter.
Can Claude translate while preserving HTML or Markdown formatting? Yes, if you explicitly instruct it to preserve tags and formatting in the system prompt. Without that instruction, it may flatten or alter structure, so always test with representative samples first.
How do I keep terminology consistent across a long translated document? Pass a glossary of fixed term translations in the system prompt for every chunk, and split documents on paragraph or section boundaries rather than arbitrary character limits.