We are building a CLI translation utility that detects source language automatically and converts text files into any target language. It helps developers localize documentation, subtitle files, or app copy without managing phrase-based translation services. Because the tool runs on Oxlo.ai, long paragraphs cost the same as short ones, which keeps pricing predictable for document-scale workloads. See https://oxlo.ai/pricing for current plan details.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Instantiate the Oxlo.ai client
Create a new file named translate.py. I start by loading the API key from the environment and instantiating the client exactly as I would for OpenAI, just pointing the base URL at Oxlo.ai.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ["OXLO_API_KEY"],
)
SYSTEM_PROMPT = "You are a helpful assistant."
user_message = "Reply with OK."
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
print(response.choices[0].message.content)
Step 2: Define the system prompt and basic translate function
The system prompt locks the model into translator mode and strips out unwanted commentary. I keep it in a constant so I can tweak tone or terminology in one place.
SYSTEM_PROMPT = """You are a professional translator. Detect the source language automatically. Translate the text into the language requested by the user. Preserve markdown formatting, code blocks, URLs, and proper names. Do not add explanations, preambles, or quotation marks around the output. Return only the translated text."""
Next, a thin wrapper around the chat completions endpoint. I use llama-3.3-70b as the default because it handles general-purpose translation reliably.
def translate(text: str, target_language: str, model: str = "llama-3.3-70b") -> str:
user_message = f"Translate to {target_language}:\n\n{text}"
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
return response.choices[0].message.content.strip()
Step 3: Batch multiple segments in one request
Because Oxlo.ai uses flat per-request pricing, a prompt containing ten paragraphs costs the same as a prompt containing one sentence. I exploit that by batching segments together, which also reduces script runtime. I switch to qwen-3-32b here because it is particularly strong on multilingual reasoning.
def translate_batch(segments: list[str], target_language: str, model: str = "qwen-3-32b") -> list[str]:
numbered = "\n".join(f"[{i + 1}] {seg}" for i, seg in enumerate(segments))
user_message = (
f"Translate each numbered segment below to {target_language}. "
f"Preserve the [N] markers in your response.\n\n{numbered}"
)
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
raw = response.choices[0].message.content
results = []
for line in raw.splitlines():
line = line.strip()
if line.startswith("[") and "]" in line:
results.append(line.split("]", 1)[1].strip())
return results
Step 4: Wire it into a file translator CLI
Most real-world translation tasks involve files, not single strings. The script below splits a text file on double newlines, translates the resulting paragraphs in batch, and writes them to an output file.
import os
import sys
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ["OXLO_API_KEY"],
)
SYSTEM_PROMPT = """You are a professional translator. Detect the source language automatically. Translate the text into the language requested by the user. Preserve markdown formatting, code blocks, URLs, and proper names. Do not add explanations, preambles, or quotation marks around the output. Return only the translated text."""
def translate_batch(segments: list[str], target_language: str, model: str = "qwen-3-32b") -> list[str]:
numbered = "\n".join(f"[{i + 1}] {seg}" for i, seg in enumerate(segments))
user_message = (
f"Translate each numbered segment below to {target_language}. "
f"Preserve the [N] markers in your response.\n\n{numbered}"
)
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
raw = response.choices[0].message.content
results = []
for line in raw.splitlines():
line = line.strip()
if line.startswith("[") and "]" in line:
results.append(line.split("]", 1)[1].strip())
return results
def translate_file(input_path: str, output_path: str, target_language: str):
with open(input_path, "r", encoding="utf-8") as f:
paragraphs = [p.strip() for p in f.read().split("\n\n") if p.strip()]
translations = translate_batch(paragraphs, target_language)
with open(output_path, "w", encoding="utf-8") as f:
for t in translations:
f.write(t + "\n\n")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: python translate.py ")
sys.exit(1)
translate_file(sys.argv[1], sys.argv[2], sys.argv[3])
Run it
Create sample_en.txt with the following content:
Welcome to the application.
To get started, clone the repository and run `npm install`. Make sure you have Node.js 18+ installed.
For questions, open an issue on GitHub or email support@example.com.
Then run the translator:
export OXLO_API_KEY="your_key_here"
python translate.py sample_en.txt sample_es.txt Spanish
After a few seconds, sample_es.txt should contain something like:
Bienvenido a la aplicación.
Para comenzar, clona el repositorio y ejecuta `npm install`. Asegúrate de tener Node.js 18+ instalado.
Para preguntas, abre un issue en GitHub o envía un correo a support@example.com.
Next steps
Add a local SQLite cache keyed by a hash of the input paragraph so you do not burn requests on text that has not changed since the last run. If you are localizing a documentation site, wrap this script in a GitHub Action that triggers on every pull request and commits the translated files back to the repo.







