Writing · August 27, 2026

The translation cost $1.26. Reading it cost a day.

A measured pilot drafted 2,648 Spanish strings in eleven minutes for $1.26. The expensive part is the working day of native-speaker review per language.

Two figures side by side on a dark card: $1.26 in green for 2,566 machine suggestions in eleven minutes, and 1 day in white for native-speaker review per language.
The two halves of the same language: what the machine charged, and what reading it costs.

TL;DR. Self-hosted Weblate plus Claude Haiku 4.5, about $70 a month. A measured Spanish pilot: 2,648 empty strings, 2,566 review-ready suggestions, eleven minutes, $1.26 of inference. The expensive line is not on the bill: it is about a working day of native-speaker review per language. It is also what the senior DevOps job looks like now: deploying AI capability onto rails you already own.

Two things happened, and they are not the same thing

The first was a pilot I measured. Every empty Spanish string, 2,648 of them, through the engine in one batch: 2,566 review-ready suggestions, eleven minutes, $1.26 of inference. About $0.0005 per string. Placeholders ({}, {0}, {name}) came back byte for byte, brand names untranslated. Roughly 3% fell below the quality threshold and stay empty for a human: the correct failure mode.

The second was the one that shipped, and I did not run it. A teammate picked a different language, ran its 877 remaining strings through the same pipeline unprompted, and accepted the whole batch through the API at about three accepts per second. It went from 79% to 99.1% and reached main five days later through an ordinary pull request.

The batch I measured is still sitting in review. The batch that reached users was accepted faster than anyone could read it. That is the finding.

Hours saved: honestly, none. Nobody was hand-translating thousands of strings; most languages had sat near 40% for as long as fallback-to-English held. The pipeline made a thing possible that was not happening: no new vendor, no new hire, just a senior DevOps engineer deployed forward, putting AI where the users already were.

The constraint that picked the model

Translator edits reviews AWS · ~$70/mo · $1.26/language Weblate Claude Haiku via Bedrock accepted translation branch after human Accept
The whole machine: a translator in Weblate, Claude Haiku 4.5 behind Bedrock, and only accepted strings reach the translation branch.

Nobody asked me for a model evaluation. The ask, implicitly, was the newer shape of this job: an engineer who already knows the infrastructure, deployed forward to put an AI capability inside it, secure and priced, without opening a new door.

Billing and access control had to stay inside the cloud account, with no separate AI vendor account, so the model comes from Bedrock. Weblate’s Anthropic engine only speaks the plain Anthropic Messages API with an x-api-key header, and Bedrock’s Mantle endpoint speaks the same shape, so ten lines of nginx injected at container start bridged the two. No custom image, no registry, no build step.

Then the chain paid off in a way I did not plan. That endpoint has its own model catalog, separate from the regular Bedrock list, and it carried exactly one Claude: Haiku 4.5. Every friendly dropdown name 404’d, including the vendor’s own. The fix was asking the endpoint what it actually serves.

So the cheapest tier was not a choice, and it was sufficient: UI strings are short, domain-constrained, heavily templated. A good persona and style prompt got native-quality drafts out of the cheap model, quality score 90 on real domain strings. A billing constraint picked the model and the measurement vindicated it. Start with the cheapest component and iterate up from measured results.

The two gates

The design is short enough to say out loud: the AI drafts, humans gate, git ships.

Gate one is inside Weblate. The engine only ever produces suggestions; translation state, stats, and files are untouched until somebody clicks Accept on that string. Weblate’s own 30-plus automatic checks (placeholders, punctuation, plurals) run on top, independent of the model.

Gate two is a pull request. Accepted strings commit to a dedicated translation branch, and reaching the product takes the same PR to main as any other change, with the engine’s name in the author field: visible in git history, not laundered through a human committer.

Gate two held. Gate one is a convention, not an enforcement, and a script walked through it. The teammate did nothing wrong; the spot-checks read as native and the language is live. But if a review gate matters, it needs permissions behind it, not a default nobody is obliged to respect. I wrote that into the known-gaps doc instead of claiming a control I did not have. The fence, not the model, is where the engineering time went.

Same shape as the OpenClaw leash: the model is the engine, the constraint around it is the product.

The bill

Item$/month
Fargate task, ARM64, 1 vCPU / 4 GB (app + cache + AI proxy)34.04
Application Load Balancer (endpoint and login gate)17.43
RDS Postgres db.t4g.micro + 20 GB gp314.00
Secrets Manager, KMS key, CloudWatch logs~4.50
EFS (under 1 GB)< 0.50
Claude Haiku 4.5 inference (ceiling; measured to date: $1.26 total)5.00
Total~$75 during backfills, ~$70 steady state

Rates came from the AWS Pricing API, not from memory. The inference row is a ceiling, labeled that way on purpose: everything the engine ever spent across the build and pilot was $1.26. Cost Explorer lags a day or two; the real-time usage metrics namespace in CloudWatch is how you measure a pilot the same hour you run it. Same instinct as reading the rate-limit headers off your own wrist instead of trusting a billing page.

The load balancer is a quarter of the bill and exists mostly to host the login gate: the app holds a git write token and has no SSO, so every non-API request passes a Cognito email allowlist at the listener before it reaches the container. That one listener action is what made internet-facing acceptable at all.

Enabling the capability was the easy half. Keeping it secure and inside the budget is why an infrastructure engineer wired it, and not a chatbot pilot on a corporate card.

Bottom line

The adoption signal was the best thing that happened here, and it is also the gate failure. Same teammate, same afternoon. They ran a language through the pipeline without being asked, took it through a normal PR, and then extended the prompt configuration themselves with per-locale register and typography rules I had not written. Infrastructure works when other people start driving it without asking. It also means the first person to drive it did the thing the design was relying on them not to do.

There used to be a person in this gap: the coordinator who sat between translators and the repo, closer to the users than any of us. This pipeline quietly absorbed that manual translation.

What replaced that manual translation is not a model. It is an engineer standing the rails up inside the budget and handing over the keys.

Eleven minutes and $1.26 to draft a language. About a working day of native-speaker attention to read one. Twelve languages of drafting is roughly $15, once, and roughly twelve working days of reading.

The machine half got cheap enough to stop being a decision. The human half did not move, and it is the half that decides whether any of this is trustworthy. A day of reading is expensive enough that under pressure someone will find the button that skips it. The thing worth designing carefully was never the model or the bill. It was the gate, and I shipped mine as a convention.