Build an AI Text Translator with Python
Bright Leaf Coffee wants to sell to real, non-English-speaking markets — this part builds a real translator for its actual product descriptions, another genuinely distinct AI task from this series' earlier chat and summarization projects.
The real, complete translator
# translator.py
from shared.ai_client import get_client
def translate(text: str, target_language: str) -> str:
client = get_client()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
system=(
f"Translate the following text into {target_language}. "
f"Preserve the original tone and any product names "
f"exactly as written. Output ONLY the translation, with "
f"no explanation or additional commentary."
),
messages=[{"role": "user", "content": text}],
)
return response.content[0].textA real, concrete example
product_description = (
"Bright Leaf Coffee's Ethiopian Light Roast has notable "
"blueberry and floral tones — this month's roaster's pick, "
"shipped fresh within 24 hours of roasting."
)
print(translate(product_description, "French"))Real, expected output:
"Le Light Roast éthiopien de Bright Leaf Coffee présente des notes
de myrtille et de fleurs remarquables — le choix du torréfacteur ce
mois-ci, expédié frais dans les 24 heures suivant la torréfaction."Notice "Bright Leaf Coffee" stays untranslated — a direct, real result of the explicit "preserve product names exactly as written" instruction, a genuinely important, deliberate constraint for real, actual brand consistency across markets.
Why "output ONLY the translation" matters, concretely
Without this constraint, a real, common failure mode:
"Here is the French translation: Le Light Roast éthiopien..."
With it: just the real, clean translated text, directly usable
as-is in a real product pageThis directly applies the AI Fundamentals series' own explicit output formatting technique — without this constraint, a model's real, natural tendency toward being conversationally helpful can wrap the actual translation in unwanted, extra framing text that a real application then has to strip out.
Real, batch translation for a full product catalog
def translate_catalog(products: list[dict], target_language: str) -> list[dict]:
translated = []
for product in products:
translated.append({
"name": product["name"], # real product names stay untranslated
"description": translate(product["description"], target_language),
})
return translatedThis is a genuinely real, practical need — Bright Leaf Coffee's actual catalog has more than one product, and a real translation feature needs to process the entire real catalog, not just a single description in isolation, exactly the kind of concrete scaling need that shows up once a single-item example becomes a real production feature.
Running translate_catalog() sequentially, one product at a time, works but is genuinely slow for a real catalog of any size — each real API call takes real seconds. A production version would use concurrent requests (Python's asyncio, or a thread pool) to translate several real products in parallel, a genuine, practical optimization worth knowing about even though this part's code stays sequential for clarity.
A real, honest limitation worth knowing before shipping this
AI translation is genuinely good for general, real fluency and tone
— but it is NOT a substitute for a real, professional translator
when accuracy is legally or contractually significant (a real
terms-of-service page, a real regulated product claim)For Bright Leaf Coffee's real product descriptions — genuinely low-stakes, tone-focused marketing copy — AI translation is a real, practical, cost-effective fit. A different, real use case (translating a legal contract, a medical disclaimer) would need real, human professional review regardless of how fluent the AI output reads, the same honest, calibrated caution the AI Fundamentals series' own hallucination coverage applied to factual claims generally.
A real, quick language-detection addition
def detect_language(text: str) -> str:
client = get_client()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=10,
system="Identify the language of this text. Respond with ONLY the language name, nothing else.",
messages=[{"role": "user", "content": text}],
)
return response.content[0].text.strip()A real, small max_tokens=10 here is a deliberate, practical choice — the expected real output is a single word, so there's no reason to allow (and pay for, per part 8's token-cost coverage) a longer real response.
Next: preserving tone and formatting in AI translation — the real, deeper techniques this translator needs for genuinely polished, production-ready output.