The gist
One piece of content, five markets, one price. An article about the cost of living in Cuenca, Ecuador, is written in English. A few minutes later, and for pennies, it exists in Spanish for the local market and in Portuguese for investors from Brazil, with SEO metadata for each language. Not a word-for-word translation but real localization: the right terms, cultural references people recognize, the right tone.
The same skills work for everyday translation too: a reply to a Spanish-speaking customer, a note to relatives abroad, a letter from a landlord or a school that you need to understand. One thing stays a human job: official documents that need a certified translation (more on that below).
Key concepts
- DeepL API: a specialized translator that's strong in European languages, including Spanish and Portuguese; many people find its translations more natural than those of general-purpose translators, so compare them on your own texts
- DeepL MCP: the official DeepL integration for Claude Code, so translation becomes part of your workflow instead of a separate step (MCP is the standard way to plug outside services into Claude Code)
- i18n pipeline (i18n is developer shorthand for "internationalization"): an automated chain: source content → machine translation → cultural adaptation → SEO metadata
- Glossary / term base: a list of terms that must never be translated, or must always be translated one specific way
- Cultural adaptation: replacing idioms, examples and cultural references with ones the target audience understands
- Locale-specific metadata: a title, description and keywords for each language and market
- DeepL vs Claude directly: when the first is cheaper and when the second is more accurate, and how to do the math
Theory
Comparing the tools: DeepL vs Google Translate vs Claude directly
| DeepL API | Google Translate | Claude (direct) | |
|---|---|---|---|
| Speed | Very fast | Very fast | Slower |
| Price | per DeepL's plans, with a free tier | per Google Cloud pricing | per token, depends on the model |
| Term glossary | ✅ built in | ✅ available | ⚠️ through the prompt |
| Cultural adaptation | ❌ | ❌ | ✅ does it on request |
| Keeps HTML markup | ✅ | ✅ | ⚠️ needs a prompt |
| MCP integration | ✅ official | ⚠️ check the documentation | ✅ native |
| Languages | English, Spanish and other major languages | a huge number, including rare ones | all the major ones |
Translation quality isn't in the table: we have no independent test, and the result depends on the language pair and the topic. Compare the tools on your own texts. Current prices and versions: What's current.
Bottom line: DeepL for bulk translation of structured content (product listings, email templates, documents). Claude for cultural adaptation, creative writing and specialized material. Google Translate as a backup for rare languages.
No code needed: everyday translation in a regular chat
Most everyday translation doesn't need a pipeline. Open Claude in your browser, paste the text and add a short prompt. It works for a reply to a customer, a message to family, or a letter you need to understand.
Translate this message into Spanish for [who it's for: a customer in Texas, my aunt in Mexico]. Keep the tone [warm and polite / businesslike], use plain everyday Spanish, and keep names, dates, addresses and prices exactly as they are. After the translation, list any phrases that could be read two ways. Here's the text: [paste the text]
If you don't speak the target language, ask Claude to translate its own result back into English so you can check the meaning. For anything that really matters (money, health, a contract), have someone who speaks the language read it before you send it.
The rest of this lesson is for people who already use Claude Code and want to translate a lot of content on a schedule.
DeepL MCP: translation inside Claude Code
This is where the builders' part starts: you need Claude Code and a terminal. DeepL has an official MCP server (the deepl-mcp-server package; it needs Node.js 18 or newer). Translation becomes part of your workflow, and you don't have to switch between tabs.
Setup in .mcp.json:
{
"mcpServers": {
"deepl": {
"command": "npx",
"args": ["-y", "deepl-mcp-server"],
"env": {
"DEEPL_API_KEY": "${DEEPL_API_KEY}"
}
}
}
}The key itself doesn't go in the file: Claude Code replaces ${DEEPL_API_KEY} with the value of the environment variable, which you set in the terminal before starting Claude Code (the command is in the Practice section).
Once it's connected, Claude uses DeepL within the same session:
Translate the article into Spanish with DeepL, then adapt it for readers in Ecuador.
Claude calls DeepL for the translation, then handles the adaptation itself, without breaking your workflow.
The i18n pipeline: from one text to five markets
How the pipeline flows:
[Source content, EN]
↓
[DeepL API: fast machine translation with a glossary]
↓
[Claude Sonnet: cultural adaptation and tone]
↓
[Claude Haiku: SEO metadata for each market]
↓
[Files: article.en.md / article.es.md / article.pt.md]
[Metadata: article.es.meta.json / article.pt.meta.json]The full Python code for the pipeline:
import anthropic
import deepl
import json
import os
from pathlib import Path
deepl_client = deepl.Translator(os.environ["DEEPL_API_KEY"])
claude_client = anthropic.Anthropic()
# Glossary: terms that are NOT translated, or are translated one fixed way
GLOSSARY_TERMS = {
"ES": {
"Acme Realty": "Acme Realty", # brand: never translate
"Acme AI": "Acme AI", # service name: never translate
"apartment": "departamento", # in Ecuador people say "departamento"
"real estate agency": "inmobiliaria", # the standard local term
},
"PT-BR": {
"Acme Realty": "Acme Realty",
"Acme AI": "Acme AI",
}
}
MARKET_CONTEXT = {
"ecuador": (
"Latin American market, Ecuador. "
"Audience: local home buyers and expats who live in Ecuador. "
"Formal but friendly tone. "
"Emphasis on stability and long-term investment. "
"Ecuador uses the US dollar, which is an important selling point."
),
"brazil": (
"Brazilian market. Audience: entrepreneurs and investors. "
"Direct, concrete tone. Emphasis on ROI and numbers. "
"Avoid excess emotion: facts only."
),
"spain": (
"Spanish market. A more formal tone than in Latin America. "
"Use the Spanish of Spain (not Latin American Spanish). "
"Audience: educated city dwellers."
),
}
def create_deepl_glossary(source_lang: str, target_lang: str) -> str | None:
"""Create a DeepL glossary to protect your terms."""
terms = GLOSSARY_TERMS.get(target_lang, {})
if not terms:
return None
try:
glossary = deepl_client.create_glossary(
name=f"acme-{source_lang}-{target_lang}-{hash(str(terms)) % 10000}",
source_lang=source_lang,
target_lang=target_lang,
entries=terms
)
return glossary.glossary_id
except deepl.DeepLException:
return None # DeepL didn't create the glossary (for example, it doesn't support this language pair): continue without it
def translate_with_deepl(text: str, target_lang: str,
source_lang: str = "EN",
glossary_id: str = None) -> str:
"""Fast machine translation that keeps the formatting."""
result = deepl_client.translate_text(
text,
source_lang=source_lang,
target_lang=target_lang,
glossary=glossary_id,
preserve_formatting=True,
tag_handling="html" # keep HTML tags in the text
)
return result.text
def adapt_culturally(translated_text: str, target_lang: str,
target_market: str, content_type: str = "marketing") -> str:
"""
Claude adapts the translation for the culture.
It doesn't translate again: it makes the text sound natural and replaces
idioms and cultural references that don't fit.
"""
context = MARKET_CONTEXT.get(target_market, "International audience.")
prompt = f"""You are an expert in adapting content for the {target_market} market.
TASK: Adapt the text for the target audience.
Do NOT translate it again: it has already been machine-translated.
Make it sound more natural, replace idioms that don't fit,
and adapt the examples and cultural references.
MARKET CONTEXT: {context}
CONTENT TYPE: {content_type}
STRICT RULES:
- Do NOT change the brands "Acme Realty" and "Acme AI"
- Do NOT change numbers or statistics
- Do NOT change the key points, only how they are presented
- Output language: {target_lang}
TEXT TO ADAPT:
{translated_text}
Return ONLY the adapted text, with no explanations."""
message = claude_client.messages.create(
model="claude-sonnet-5-5", # current models: see the What's current page
max_tokens=16000, # generous on purpose: the model's "thinking" counts toward this limit
messages=[{"role": "user", "content": prompt}]
)
# The reply may contain "thinking" blocks: keep only the text
return "".join(block.text for block in message.content if block.type == "text")
def generate_seo_metadata(content: str, target_lang: str,
target_market: str) -> dict:
"""
Claude Haiku generates SEO metadata for the local market.
It's cheaper than Sonnet and good enough for a structured task.
"""
prompt = f"""Based on this content, generate SEO metadata for the {target_market} market.
CONTENT (first 1,500 characters):
{content[:1500]}
Return JSON:
{{
"title": "up to 60 characters, with the keyword",
"meta_description": "up to 155 characters",
"h1": "the main page heading",
"keywords": ["word1", "word2", "word3", "word4", "word5"],
"og_title": "for Open Graph (up to 70 characters)",
"og_description": "for Open Graph (up to 200 characters)"
}}
Language: {target_lang}
Take into account what people in the {target_market} market actually search for.
Return ONLY the JSON, nothing else."""
message = claude_client.messages.create(
model="claude-haiku-4-5", # check that the model is still available in the API
max_tokens=512,
messages=[{"role": "user", "content": prompt}]
)
text = "".join(block.text for block in message.content if block.type == "text")
try:
return json.loads(text)
except json.JSONDecodeError:
return {"raw": text}
def run_translation_pipeline(source_file: Path, source_lang: str,
targets: list[dict]) -> dict:
"""
The full pipeline: translates one file into several languages.
The targets parameter is a list of dictionaries:
[
{"lang": "ES", "market": "ecuador", "output": "article.es.md"},
{"lang": "PT-BR", "market": "brazil", "output": "article.pt.md"},
]
"""
source_text = source_file.read_text(encoding="utf-8")
results = {}
for target in targets:
lang = target["lang"]
market = target["market"]
output_path = Path(target.get("output", f"output.{lang.lower()}.md"))
print(f" → {lang} for {market}...")
# 1. Glossary
glossary_id = create_deepl_glossary(source_lang, lang)
# 2. Machine translation
raw_translation = translate_with_deepl(
source_text,
target_lang=lang,
source_lang=source_lang,
glossary_id=glossary_id
)
# 3. Cultural adaptation
adapted = adapt_culturally(
raw_translation,
target_lang=lang,
target_market=market,
content_type="real_estate_marketing"
)
# 4. SEO metadata
seo_meta = generate_seo_metadata(adapted, lang, market)
# 5. Save the files (the DeepL translation before adaptation too: it's handy to compare with the result)
output_path.write_text(adapted, encoding="utf-8")
output_path.with_suffix(".deepl.md").write_text(raw_translation, encoding="utf-8")
meta_path = output_path.with_suffix(".meta.json")
meta_path.write_text(
json.dumps(seo_meta, ensure_ascii=False, indent=2),
encoding="utf-8"
)
results[lang] = {
"content": str(output_path),
"meta": str(meta_path),
"chars": len(source_text),
"market": market
}
print(f" ✅ {lang} done: {output_path}")
return results
# Example usage
if __name__ == "__main__":
results = run_translation_pipeline(
source_file=Path("article-en.md"),
source_lang="EN",
targets=[
{"lang": "ES", "market": "ecuador", "output": "article-es.md"},
{"lang": "PT-BR", "market": "brazil", "output": "article-pt.md"},
]
)
print("\n📊 Results:")
for lang, info in results.items():
print(f" {lang}: {info['content']} + {info['meta']}")The glossary: your brand's immune system against bad translations
Categories of terms for your glossary:
| Category | Examples | Rule |
|---|---|---|
| Brands | Acme Realty, Acme AI | Never translate |
| Legal | fideicomiso, plusvalía, promesa de compraventa | Use the local market's term |
| Technical | API, MCP, dashboard, ROI | Leave as is, or add a translation in parentheses |
| Product | "apartment" = "departamento" (Ecuador) | Depends on the country |
| Marketing | The brand's slogan | Translate by hand ahead of time |
A cultural adaptation example: you can see the difference
Original (EN):
"Putting your money into an apartment is as safe as keeping it in an FDIC-insured savings account."
After DeepL (ES):
"Invertir dinero en un apartamento es tan seguro como tenerlo en una cuenta de ahorros asegurada por la FDIC."
The problem: a reader in Latin America has no idea what the FDIC is (it's the US agency that insures bank deposits).
After Claude (cultural adaptation, Ecuador):
"Invertir en un departamento en Cuenca es tan sólido como tener dólares en el Banco del Pacífico, sin riesgo de devaluación."
The swap: the unfamiliar FDIC → the familiar Banco del Pacífico. Local relevance added: Ecuador uses the US dollar, so there's no devaluation risk, which is an important argument for this market.
⚠️ This example shows how translation adapts references, not how to write a real ad. Real estate is not risk-free, and comparing it to an insured bank deposit can count as a misleading investment claim in many countries. In real copy, describe the property and leave out safety promises.
A practical case: Acme Realty, EN → ES → PT
What goes through the pipeline:
- Blog articles: about 5 a month, roughly 1,500 words (10,000 characters) each
- Property listings: descriptions of apartments and houses in 3 languages
- Email newsletters: a weekly digest in 3 languages
- Page metadata: title, description and keywords for each language
- WhatsApp and text message templates: welcome and follow-up messages
Monthly cost (articles only):
- Volume: about 100,000 characters (5 articles × 2 target languages × 10,000 characters)
- DeepL (first-pass translation): you pay according to DeepL's plans; at this volume, compare the free tier with the paid plans on DeepL's pricing page
- Claude (adaptation): per token. The code in this lesson adapts the whole text; to spend less, adapt only the pages that matter
- Total: usually far less than paying a freelancer to translate everything from scratch. Rates depend on the market and the language, so run the numbers for yourself.
Current prices and versions: What's current.
When DeepL is cheaper than Claude, and when it's the other way around
| Scenario | Recommendation | Relative cost |
|---|---|---|
| Bulk product descriptions (over 50K characters a month) | DeepL + Claude to adapt the pages that matter | low |
| Marketing copy | Claude directly | per Claude token |
| Legal documents | DeepL + review by a professional | higher: needs an expert's review |
| Technical texts with specialized terms | DeepL with a glossary | low to medium |
| Creative content, blog posts | Claude directly | per Claude token |
Rule of thumb: standard structured text → DeepL. Text that has to sound like a person wrote it → Claude.
⚠️ Official documents stay a human job. Immigration paperwork, court filings, birth and marriage certificates, diplomas and transcripts usually need a certified translation: a human translator signs a statement that the translation is complete and accurate. Use AI to understand what a document says or to prepare questions for your translator, not to produce the version you submit. The agency, court or school that asks for the translation sets the rules, so check its requirements first. And before you paste a document with Social Security, passport or bank account numbers into any online tool, black those numbers out.
Practice
No code. Translate one real message with the prompt from the "No code needed" section, ask Claude to translate the result back into English and check the meaning. You're done when the back-translation says what you meant and you've fixed the phrases Claude flagged as ambiguous. Steps 1-4 below are for builders: they need Claude Code and a terminal.
Step 1: Get a DeepL API key and set up the MCP (5 min)
- Sign up at deepl.com/pro-api: there's a free tier to start with (see DeepL's site for the volume and terms)
- Copy your API key: it's in your DeepL account, in the keys section (deepl.com/your-account/keys)
- Add the server to
.mcp.json(see the code in the Theory section) - Set the key as an environment variable in the terminal you start Claude Code from:
export DEEPL_API_KEY="your-key"(in Windows PowerShell:$env:DEEPL_API_KEY="your-key"). Don't put the key itself in.mcp.json - Restart Claude Code, approve the deepl server when Claude Code asks, and ask: "translate 'Hello, world' into Spanish with DeepL"
Success check: Claude uses the DeepL MCP and returns a translation.
Step 2: Build a glossary for your project (5 min)
pip install deepl anthropicSave the pipeline code from the Theory section as translation_pipeline.py. Write your terms down in glossary.json; it's your working list:
{
"brand_names": ["Acme Realty", "Acme AI"],
"do_not_translate": ["API", "MCP", "dashboard", "ROI", "CRM"],
"market_specific": {
"ecuador_es": {
"apartment": "departamento",
"real estate": "bienes raíces"
}
}
}Then move the terms into the GLOSSARY_TERMS dictionary in the script: the create_deepl_glossary() function reads them from there. You'll check it in the next step: your brand name must not change in the translation.
Step 3: Run the pipeline on a real text (10 min)
- Take any article or property description (at least 500 words) and save it next to the script as
test-article.en.md - Set your Anthropic key in the same terminal:
export ANTHROPIC_API_KEY="...". Then save the code below asrun_test.pyand run it withpython run_test.py:
from pathlib import Path
from translation_pipeline import run_translation_pipeline
results = run_translation_pipeline(
source_file=Path("test-article.en.md"),
source_lang="EN",
targets=[
{"lang": "ES", "market": "ecuador", "output": "test-article-es.md"},
]
)- Compare three versions: the original, the DeepL translation (
test-article-es.deepl.md) and the text after Claude's adaptation (test-article-es.md) - Notice what the cultural adaptation changed
Step 4: SEO metadata for each language (5 min)
Open the test-article-es.meta.json file from the previous step. Check:
- Title: up to 60 characters, with the keyword?
- Meta description: up to 155 characters?
- Keywords: what local people actually search for, not a word-for-word translation?
If something's off, adjust the prompt in generate_seo_metadata().
Tools and resources
- DeepL API: strong translation for European languages, including Spanish and Portuguese, with a free tier
- DeepL MCP: the official integration for Claude Code
- python-deepl: the official Python SDK
- Google Cloud Translation: a huge number of languages, good for rare ones
- Claude Sonnet: cultural adaptation and creative content
- Crowdin: team translation work and translation memory, pricing on the site
- Lokalise: i18n for SaaS products, pricing on the site
- i18next: i18n for JavaScript/React apps, free
Recommended stack for a small business: DeepL's free tier → a paid plan as your volume grows + Claude for adaptation + the Python script from this lesson.
Key takeaways
Machine translation translates words. Claude translates meaning. DeepL does it fast and cheap as step one; Claude makes it sound natural as step two.
A glossary is your brand's immune system in translation. One wrong translation of a product name or a legal term can cost you the trust of a whole market.
Tokens and a DeepL plan instead of paying a freelancer for every translation isn't just a saving; it's a different way of working. Still show anything important to someone who speaks the language.
Official documents are the exception: when an agency or a court asks for a certified translation, a human translator does it.
Next lesson
→ AI image generators: the start of the module on images, video and music: which image generator to pick for which job
Optional, in the library: AI in messaging apps: Slack, Microsoft Teams, WhatsApp and more. Smart bots that answer customer questions, send deal notifications and manage access to private group chats.
The mark stays in this browser only and is never sent anywhere. My progress