Diogo·Heleno
← Writing

How My AI Translation Engine Runs, Day to Day

/17 min read/llmtranslationengineering

After the last article, a person whose opinion I take seriously, another owner in this industry, sent me a string of questions, and one of them asked whether a system like the one I am building is easy to use, and easy to maintain.

It is a good question, because it is easy to get lost in building tools, and to forget that a tool is only worth building if the people it was made for actually use it.

As good as my engine might be, the honest truth is that if it does not serve my project managers, it is useless, because they will not use it. If it makes their day harder, slower or more cumbersome, they will quietly drop it and fall back to the routines they already know.

So to them, in a nutshell, the system is as easy as it can be, because they barely touch it. They put the files they need translated into a folder, wait a few minutes, and get them back in memoQ, translated and ready to use.

And for the translators it is easier still, because they never touch the engine either. They open the same memoQ they have always opened, on the same kind of job they have always done, and the only difference is that the file is no longer empty: the translation is already there, waiting to be reviewed instead of written from scratch. It is the same tool and the same craft, with not one new thing to learn.

How a job runs

Here is what happens to an ordinary job, from start to finish.

A project manager receives files from a client and puts them in the folder where that project lives. If memoQ accepts the file as it is, then it is ready to go.

Of course, it is not always that simple. Some files need preparing first. An Excel has to be loaded into memoQ to pick out the few sheets or cells that matter, and a PowerPoint might need cleaning up because every segment is 99% tags. An XML file might need a special filter so that it imports as text and not as a wall of HTML. But that is the day-to-day life of a project manager, and in those cases they prepare the file in memoQ first, export it as MQXLZ, and feed that to the engine instead.

I will mention memoQ a lot, because it is the CAT tool we use. Other CAT tools would work too, I simply have not tried them, because I do not use them. If that is you, if you are on a different tool, give me a shout, I just need a chance to test the engine against its formats. And in any case, any half-decent CAT tool will export to a universal format like XLIFF, which the engine handles as well.

Once the project is prepared, the only thing left for the PM to do is to drop the files into a specific folder, with the language pair in the folder name. If it is an English to French job, they put it in a folder called EN-FR. If no locale is given, the engine assumes a default: for us, EN means EN-GB, FR means FR-FR, PT means PT-PT. Those defaults can change, and a specific locale can be set instead, FR-CA, for example.

A file explorer window showing a folder named "PT-EN" with four source documents inside
The whole of a project manager's interaction with the engine: the files go into a folder named for the language pair, and that is it. File names redacted by policy.

And that is the whole of it, from their side. The system watches the folder, and when new files arrive it does the rest on its own.

It creates the project in memoQ, and imports the client's glossary if there is one. It pre-translates everything against our translation memory, which we have built and corrected over more than twenty years, and the segments that come back as exact matches, the ones already translated and approved in past work, the 100% and 101% matches from specific users, it locks, so that nobody has to read them again. Everything else, the genuinely new text, it sends to the engine.

The engine translates that new text and scores how far it trusts each segment. It writes the translation, the scores and any comments back into the file, locks the repetitions, so that no one has to translate the same line twice, or a hundred times, and then loads the file back into the CAT tool.

So when the reviser opens the job, the translation is already there, segment by segment, with the engine's own doubts marked on it, ready to be reviewed.

A memoQ grid with the target column already filled, a quality score and a comment on several rows, and two rows locked, with all source and target text blurred
What the reviser opens is already translated, each segment carrying the engine's score and the comments where it was unsure. Source and target text redacted by policy.
Stage of an ordinary jobWho or what does it
Receive the source filesThe project manager, into the project folder
Set the project up in the CAT toolThe system
Import the client glossary, if there is oneThe system
Pre-translate against the translation memoryThe system
Lock the matches the team already trustsThe system
Translate the new text and score each segmentThe engine
Lock the repetitionsThe engine
Write the file back into the CAT toolThe system
Review the result, line by lineThe human linguist

So when I say it is easy to use, this is what I mean. The project manager works with a folder, the linguist works in the CAT tool they already know, and neither of them had to learn the engine at all. The tools did not change. What changed is the time, because the linguist now opens a file that is already translated and reviews it, instead of translating it from nothing, and a translator's time is the one resource an LSP cannot make more of.

There are smaller gains too. The PMs no longer have to create the memoQ project themselves, which is never hard but always costs a couple of minutes, nor import the files, at least not for the straightforward formats, which is around 90% of the work. A few minutes saved per project adds up to an hour a day on the busy days.

There is also the work a good PM does by hand before a job goes out. They will lock the 100% and 101% matches, lock the most common repetitions, sometimes even fix and lock the 95%-and-up matches when they are easy enough to be sure of.

The reason? Our MT grids usually pay only 10% on these matches and repetitions, and 10% adds up over time. But we all know that some of those savings are pennies to the dollar, and it makes no sense to spend ten minutes to save a couple of them. That is exactly why it is so useful to have the machine do it instead. It might save only 2% or 3% of a project, but it does it fast enough that the PM never has to think about it, and it does it on every job, so that the pennies to the dollar turn into dollars of their own over time.

I will write a whole article on what the engine saves my team, in time and in money, before long.

What maintaining it actually means

Maintaining it is the other half of my peer's question, and the honest answer is that it runs on its own most of the time, and then, like all production software, it breaks.

The most common cause is a provider having a bad few seconds, or minutes, or hours. That is what the safety net is for: there are several providers in the pool, so that when one goes down its work simply moves to another, and a monitor watches for it and warns me when it happens, because the cause might be a passing outage, or a model that has been discontinued, or a credit card that the bank has stopped honouring.

Other times it is a deployment that restarts something at the wrong moment and brings the rest down with it, or a client file in an old format that slipped past the PM, so that memoQ hands the engine an XLIFF with more tags and gibberish in it than text to translate.

And these services run in the cloud, on real machines in real data centres somewhere in the EU, and those break too.

I cannot stop any of that, I cannot control every provider at every step, so I do not try. What I build for instead is simpler: when something breaks, it has to tell me that it broke, and it has to break in a way I can see and reproduce, so that I can put a guard in place and stop it from happening again.

And although I run a 9-to-5 LSP, my team does not. They are translators all over the world, working to their own hours and their own preferences, so an engine that breaks on a Saturday afternoon does not let me off the hook, because someone, somewhere, may be trying to start a translation at exactly that moment.

As I have said before, I am not a developer. I understand code and systems, but only broadly, I can read pseudocode and that is about as far as it goes. So the AI writes the code, and it helps me plan and put up the scaffolding, but I decide what it builds and how it builds it.

Maintaining the engine, then, is not really a coding job that I happen to do, it is a job of judgement. Most days it comes down to deciding what is worth fixing, whether a change is safe to put in front of a client, and what the system should do in the moments it is not sure of itself. The code is written to my instructions by a machine that never tires of a rewrite. The deciding, and the answering for it when something goes wrong, is the part that is mine.

One real case shows what that looks like. A job had run almost to the end. The engine had translated the files and finished the work, and then the very last step, loading the result back into the CAT tool, hit a transient error, a provider answering badly for a few seconds during a deployment, and the job stopped. The file had still gone into memoQ, though, and the PM was told the job was done. But there was nothing in it!

A PM worth their salt always opens a project before sending it to the team, so they caught it at once, and they were dismayed, because this was a 450,000-word job that had taken the engine hours to run, and it was now five in the afternoon, which meant the work would not reach the team until the next day.

But this kind of thing had happened before, and small hiccups are exactly why we built a cache into the system. The recovery run was just a quick pre-translate, and within a few minutes the job was whole again and on its way to the team.

And I do not treat an incident as closed while anything about it is still unknown, so I had the system go back over every other job from that window and check for the same near-miss. One had come close, in a different way, and was already safe. The rest were clean.

Underneath it all, the philosophy is short. Every step can be run again without doing its damage twice, which is what makes recovering a half-finished job a calm thing rather than a frightening one. The system stops and tells me instead of guessing, because a job that stops and warns me is one I can still save, while a job that guesses is one the client finds for me. And it keeps a record of everything it did, so that when something breaks I never have to wonder what happened, only decide what to change.

That is what it takes to keep it running. The other half of the story is how it is built.

How it is put together

The system is two pieces that talk to each other, and I kept them apart on purpose, partly because I built them in different orders.

One piece is a small orchestrator, a Python service whose only job is to watch and to sequence: it notices new work, works out which step comes next, and asks for that step to be done. That was the last thing I made.

The other piece is the engine itself, where all the memoQ work and all the translation already live, and which offers each stage of a job as something the orchestrator can ask for over an internal HTTP call. That was the first thing I built, because it was the part I needed to be sure was perfect.

So the orchestrator never touches memoQ directly, it asks the engine to, and that is how I build everything, in small steps, so that whatever I make is a flow of small, named steps rather than one long script that either runs to the end or does not.

A job built as a sequence of steps is a job you can stop and start again from the exact point where it broke, and that one property is what saves me. If a step fails, it can be run again, and again, and again, until it gets to the end. If it cannot, I can open up that one step, see why, and fix it there, without touching the rest. And if a single step fails, the others around it can often still run, so that the job reaches the end almost intact, instead of stopping dead in the middle of the road with half the trip still ahead of it.

How it watches the folder

The watching is very simple, on purpose. The orchestrator does not sit on the folder waiting for the operating system to announce that a file has appeared. Instead it works on a cycle: every few minutes it checks whether there are new projects in the TMS, and whether there are files sitting in the right folder waiting to be processed, and if there are, it checks memoQ to see whether the matching project already exists, and whether those files are already in it or not. If any of that points to new work, the process begins.

And the few minutes can become no time at all, because if the project manager presses the Update button, the system checks on the spot. Otherwise it waits, and goes looking again on its own every little while.

The memoQ cycle

Once a candidate is confirmed, the engine drives memoQ through the cycle, one step at a time, in order. It creates the project, imports the documents in chunks so that a large file never overloads the whole server, pre-translates everything against the translation memory, and locks the matches the team already trusts, so that those segments never cost a human a second reading. Then it exports the bilingual file, hands the new segments to the engine to translate, writes the translations, the scores and the comments back into that same file, locks the repetitions while leaving the first of each unlocked so it can still be reviewed, and re-imports the whole thing into memoQ.

The re-import knows each document by its own identity, so that if a step has to be run again after a failure, nothing is ever imported twice and nothing is doubled. That is the idempotency I mentioned in the first half, made concrete: a retry after a break is a safe thing to do.

How the project manager knows it is ready

There is one last thing the system has to do, which is to tell the project manager when a job is finished and ready for them to take into memoQ. They can follow each job in a tracking dashboard that shows every run and its state, from detected, to running, to done, so that at any moment they can see exactly where their work stands.

The pre-TM tracking dashboard listing several runs in a table, each with a state such as detected, running or done, and the project identifiers blurred
How a project manager always knows where the work stands: every run and its state, from detected to done. Project identifiers redacted by policy.

And the system also emails the PM when a job finishes, whether it finished cleanly or not, so that the right thing can be done next.

An email notification whose subject line shows a pre-translation job has finished, with addresses and project identifiers blurred
The system does not wait to be asked: it emails when a job is done, and it reaches me directly when one fails. Addresses and identifiers redacted by policy.

When a run fails rather than finishes, it does not wait to be discovered, it reaches me directly, so that I hear about a failure in minutes, not days. And a job whose state you can always see cannot quietly go missing.

The rule that runs underneath all of it

All of this runs on shared ground, and that single fact shapes every rule I have just described. We are not alone in those folders, or on that memoQ server. An older orchestration was there before mine and still runs beside it, and another system reads from the very same folders, at a later step, to hand the documents to the translators who do the work. So my system lives by one rule above all the rest: it never creates, touches or deletes anything that is not its own.

A memoQ project we did not make, we do not open. A pair that belongs to the other system, we do not even show. Ownership is settled by an identity we record the moment we create something, and if that identity does not match, the answer is always to leave it alone.

I learned how much that rule matters by breaking it. At one point I added what looked like sensible housekeeping: at the end of a finished run, the system moved the processed files out of the working folder and into a tidy "done" folder, sorted by date. It was clean, and it was wrong, because the other system, the one that hands work to the translators, reads those exact files from that exact folder at a later step, and by tidying them away I had quietly taken the translators' work out from under them. The fix was to tear it out completely, by the roots, and then to put dozens of files back by hand so that the handoff could happen again. The lesson stayed with me: in a folder you share with someone else, you are a guest, and the safe thing is to touch nothing you did not bring in yourself.

The question underneath the question

None of this, though, answers the question that really sits underneath the one I was asked, which is whether the translations the engine produces are any good. Easy to use, steady to run, honest about its own failures: none of that is the same as good, because a system can be all of those things and still hand the reviser work to correct on every line. Whether mine does that, and by how much, is something I measure rather than assume, and that measurement, how I compare what the engine wrote against what the human shipped, and how that comparison is fed back to make the engine better, is the next article.

So the honest answer is that both things are true at once. It is genuinely easy to use, for the people who use it, and it is real work to maintain, but I do that work, because no one knows my business the way I do. One day I hope to have someone do it for me, but for now, when you are saving a business, it is all hands on deck.

I worked out early that if I was going to keep my own company from being drowned by AI, I would have to start using AI for real, and not just in a chat window. And in the end I am the owner, and I am the one who has to answer for it.

Comments