Game localization starts with a file your engine already wrote for you, and the job is to send that file somewhere that reads it as it is. Unity gives you XLIFF or CSV. Unreal gives you PO. Godot gives you either. None of them needs to be reshaped first.
This guide is the long version: what game localization actually involves, why it pays, which file each engine hands you, what you can and cannot ask for depending on the shape of that file, how the platform runs a job today, and how to hand the whole loop to an AI agent so a ten-language pass is one decision instead of forty clicks.
What game localization actually involves
Localization is four separate jobs that people collapse into one word, and knowing which one you are in stops most of the pain.
1. Internationalization, which is code, not language. Your game has to be able to display another language at all: no text baked into a texture, no sentence assembled by string concatenation, a font with the glyphs you need, and layouts that survive a label growing. Every engine has a system for this, and every engine’s system is where the strings end up living.
2. Extraction, which the engine does. Unity collects your text into String Table Collections. Unreal’s Localization Dashboard gathers it into a target and exports it. Godot reads a spreadsheet or a gettext catalogue. The output of this step is the file you are going to translate.
3. Translation, which is the part this article is about. One file in, one file out, in the same format.
4. Re-import and testing. The file goes back where it came from, the game is rebuilt, and somebody reads the German main menu to check nothing overflows.
The only step that has to leave your engine is the third one. Anything that asks you to restructure the file before you can translate it has added a fifth job that nobody needed.
Why localize at all
The case is a market case, not a polish case. A game published in English is discoverable and playable by the people who read English, and the rest of the world is the rest of the world.
CSA Research’s “Can’t Read, Won’t Buy” survey of 8,709 consumers across 29 countries found that 40% of consumers will not buy from websites in another language, and that 76% prefer buying products with information in their own language. That research is about buying online in general rather than about games specifically, which is exactly why it is worth quoting here: the preference is not a gaming quirk, it is how people buy anything.
Three more effects that matter for a game in particular, without a number attached to any of them, because we do not have one worth publishing:
- Store discoverability. A store page in one language is searchable in one language. Titles, descriptions and tags are three screens of text next to forty hours of content.
- Reviews and refunds. A player who cannot read a tutorial writes about the tutorial.
- Reach per unit of work. Your systems, art and audio are already done. Text is the cheapest thing in your project to duplicate.
If your game has a few hundred strings, this is a weekend of careful work either way. Above a few thousand, the difference between a workflow and a habit is the whole project.
Where this sits next to a translation management system
Large studios run their localization through a TMS: memoQ, Phrase, Crowdin, Lokalise and their peers. Those are coordination platforms. They hold the strings, the translation memory, the reviewer seats, the workflow states and the integrations, and for a team of twenty people with vendors attached, that coordination is the product.
If you are one to fifteen people, that is usually not the problem you have. You do not need seats, states and vendor management. You need this build’s exported strings translated well, with your invented vocabulary intact, before the milestone. That is a job, not a platform.
So the honest placement: a TMS is where a large team organises people, and AI Glot is where a file gets translated. Plenty of teams keep their engine’s export as the single source of truth, translate it here, and commit the result, with no third system in the middle at all.
What your engine exports, and what we read
AI Glot reads twelve formats: CSV, Excel, JSON and ARB, YAML, XLIFF, PO, Android XML, iOS .strings, Java .properties, .NET RESX, SRT subtitles, and ZIP archives of any of those. The two formats the game engines actually use, Unreal’s PO and Unity’s XLIFF and CSV, are native. That is the whole point of this section: there is no export-then-convert-then-translate-then-convert-back.
Unity
The Localization package exports String Table Collections three ways, and any of them works here.
XLIFF, in versions 1.2 and 2.0, is the one built for this. Unity’s documentation describes exporting String Table Collections to one or more XLIFF files, editing them in an external tool, and importing them back with the updated translations, which is precisely the round trip. Send it to the XLIFF translator and it comes back with the same units in the same order.
CSV is the other export, and it is more readable if you want to eyeball it. Unity’s CSV carries a Key column with the key you assigned, an Id column with the id Unity assigned, and one column per locale in the String Table. The “CSV with comments” variant adds a comment column per locale, which is context for the translator and must not itself be translated. That distinction is one sentence in your instruction, and it is what the CSV translator page exists for. There is a full walkthrough of both Unity exports, with the exact instruction to write for each.
Google Sheets is the third: the package synchronises a String Table Collection with a sheet. Export that sheet as CSV or XLSX and you are back in the first case.
Unreal Engine
Unreal’s Localization Dashboard is a PO pipeline. Epic’s own documentation, on the localization tools page, recommends “combined with an external translation tool (such as Poedit, OneSky, or XLOC)” for real translation work rather than the built-in editor. AI Glot is that external tool, with the difference that the file does not need a human sitting in front of it.
A PO entry has three parts that matter to you. The context line carries Unreal’s identity for that entry, which is built from its namespace and key. The source is the English text. The translation slot is empty until somebody fills it. Send the file to the PO translator and only that third part changes.
msgctxt "QUEST_TURNIN_MAREN_01"msgid "Bring the sunken lantern back to Maren."msgstr ""msgstr "Rapporte la lanterne engloutie à Maren."That is why msgctxt and msgid are treated as structure rather than as text. Change either one and Unreal either cannot match the entry or treats the translation as stale.
Godot, and the mobile builds
Godot supports both routes. Its documentation says it has an importer that reads CSV files, and that it also supports loading translations written in the gettext .po format. Either file is a file we already read.
If you ship on phones, the store-side and platform-side strings are Android strings.xml and iOS .strings, and both have their own free tool: Android XML and iOS .strings. Cutscene and trailer subtitles are SRT, which is the same workflow as translating YouTube subtitles.
We do not claim to replace Unity, Unreal, Godot or a localization platform. We process what they export.
One column per language, or one file per language
This is the single most useful thing to understand before you write an instruction, because it decides what you are even allowed to ask for.
- CSV and Excel: a column per locale
- JSON and YAML: sibling keys, where the structure provides for them
- You can ask for four languages in one output
- You can ask for only the rows whose target cell is still empty
- PO and XLIFF: each entry has one translation slot
- Android XML, iOS .strings, .properties, RESX, SRT: one value per key
- Four languages is four jobs and four files
- The source is never overwritten; the empty slot is filled
So “translate my game into French, German, Spanish and Japanese” is one job if you are holding a Unity CSV with four locale columns, and four jobs if you are holding four Unreal PO files. Asking a single-language format to hold two languages fails, and it fails at the plan stage rather than silently, which is the right place for it to fail.
Sending a folder of locale files as one archive
A game repository does not hold one localization file. It holds a directory per culture, each with the same file name in it. That whole tree goes in as a single ZIP, which is what the ZIP translator is for.
The limits are worth knowing before you build the archive: up to 200 files, 20 MB for the archive, and 4 MB per file inside it. Larger single files are fine on their own, where the caps are much higher: 60 MB for a CSV, 50 MB for an XLSX, 12 MB for XLIFF, Android XML and RESX, 8 MB for JSON, and 4 MB for PO, YAML, .properties, .strings and SRT.
Every file in the archive must be the same format and share the same shape, and “the same shape” means something specific per format:
- CSV: identical columns, in the same order.
- Android XML, iOS
.strings, Java.properties, RESX: an identical set of keys. A per-culture folder set passes this naturally, because it is generated from one source. - XLIFF: the same version and unit shape. The files may each declare a different language pair, which is why a mixed export of several targets is still one archive.
- PO: any PO files, since a catalogue’s shape is its format.
An archive that fails a shape check is refused with the mismatch named, rather than half-processed.
How a translation actually runs now
There is no column mapping screen and no configuration step. There have not been fixed modes to choose from since August 2026.
- Upload the file your engine exported.
- Say what you need, in plain English. One sentence, or five.
- Read the plan. It shows the languages, the scope it understood, the word count and the cost.
- Correct it if it is wrong. This is free and repeatable.
- Approve. This is the step that spends credits.
- Download one file, in the format you sent.
The instruction is free text and the engine compiles it into verified code, which is why scope sentences that no machine translator can express actually work here: “only the entries whose translation is still empty”, “only the rows where the German column still holds the English text”, “translate the dialogue and the item names, leave the developer comments alone”.
Everything up to step five costs nothing. A plan that misread your file is free to correct, so there is never a reason to guess.
Text that has to fit
A button that fits in English overflows in German. Translated text typically runs 15 to 30% longer, and a UI built to the English width is a UI built to the shortest case.
The wrong fix is to translate first and trim afterwards, which produces abbreviations nobody would choose. The right fix is to say the constraint up front, so the line is written to fit:
Keep every UI label under 28 characters, including spaces. If the natural
translation is longer, choose a shorter phrasing rather than abbreviating.
That belongs in the string-level instructions, passed at approval, because a character ceiling describes something visible inside one string. Ask for it once per file and it is applied while each label is written.
Two things it does not replace. Test the longest strings in the build, because a ceiling on characters is not a measurement of pixels in your font. And keep the ceiling honest: 28 characters for a button, not 28 characters for a quest description, or you will get quest descriptions that read like telegrams.
The two instructions people mix up
This is the one thing in the whole workflow that fails silently, so it is worth thirty seconds.
The plan instruction decides what gets translated. It is read once, against the shape of the whole file, and it is where the target language and the scope belong. “Translate every entry whose translation slot is still empty into German.”
The string-level instructions are applied while each string is written. At that point the engine is looking at one string, so these can only describe what is visible inside it: a character ceiling, a register, a placeholder such as {count} to keep exactly as written, a name to leave alone.
Put a character ceiling in the plan and it does nothing useful. Put “skip the first column” or “only translate the second half of the file” in the string-level slot and it does nothing at all, because there is no file in view at that point. Nothing errors. You simply get output that ignored you.
Names, items and spells that must not drift
Lore is where game translation is different from everything else. A product catalogue has a hundred terms that must stay fixed. A game has a thousand, they are invented, and they recur across thousands of lines and across every update you ship for the next three years.
Put them in a workspace glossary once: character names, place names, item and spell names, the house translation of a recurring phrase, and the names that must not be translated at all. A glossary belongs to one language pair, and it is snapshotted when a plan is made, so a batch already running is never changed under you and the next file gets the current terms.
The plan caps are worth checking against your term list: one glossary with 50 terms on Free, three with 150 on Starter, unlimited glossaries with 500 terms each on Pro.
And you do not have to type that list yourself. The glossary is reachable from the MCP server, with tools to list glossaries, read one, and add, change or replace terms. So an agent that already has your project open can do the tedious half: read your String Tables or your dialogue files, pull out the proper nouns and the invented words that recur, propose them to you as a list, and write the ones you approve into the workspace before any translation runs.
That is worth more than it sounds. A glossary nobody fills in protects nothing, and filling one in by hand for a game with a thousand invented terms is exactly the task that gets postponed forever. Ask your agent to draft it, then edit its list instead of writing one from scratch.
This is also the mechanical reason a general machine translator struggles with a game. Its glossary substitutes a term wherever it matches, so the sentence around the substitution is never reconsidered, and an invented noun with a gender lands in the middle of a French sentence that does not agree with it. Here the glossary is carried in as meaning while the line is written, so the term inflects into the sentence. The same difference applies to using a chat assistant for the job: it is fine for ten strings and it cannot hold one rule reliably at string 18,000.
Let an agent run your game localization loop
This is the part most studios have not caught up with yet. There is a REST API, a command line tool and an MCP server, so a coding agent can run the entire loop without a human opening a browser.
Install it and sign in once:
npm install --global @ai-glot/cli
aiglot auth login
That opens a browser to authorize the machine. On a build server with no browser, aiglot auth login --device gives you the device-code flow, and aiglot auth login --key <key> works in CI.
- 1PrepareCollect the engine exportsYour agent, free
- 2CreateOne batch per fileFree
- 3Read the planScope, words, costFree
- 4ApproveThe only step that spendsYour decision
- 5Write backInto the per-culture pathsYour agent
The prompt to hand your agent
Paste this, changing the paths and the language list. It is written to be given to an agent, not run yourself.
My Unreal project is at ~/dev/starfall. The Localization Dashboard exported
PO files to Content/Localization/Game/<culture>/Game.po, and their msgstr
lines are still empty.
Translate the French, German, Spanish and Japanese files with the aiglot CLI.
Read `aiglot batches create --help` and `aiglot batches approve --help` first
so you use the real flags, and run `aiglot languages` to confirm each language
tag before you start.
A PO file holds one target language, so create ONE batch per culture, four in
total. The source language is English: say so explicitly in every instruction
rather than letting it be inferred.
The plan instruction should translate only the entries whose msgstr is still
empty, and leave msgctxt, msgid and every placeholder or rich-text tag exactly
as written.
At approval, pass this as the string-level instruction: "Keep UI labels under
28 characters. Keep placeholders exactly as written. Do not translate any name
that appears in the glossary."
Show me all four plans, the total word count and the cost BEFORE you approve
anything, then wait for me to confirm.
After I confirm, approve with the lite quality tier, poll until each batch
reaches a terminal status, and download each result next to the original as
Game.translated.po. Do not overwrite the source files. Tell me if any batch
failed.
Four things in that prompt are doing real work, and they are the parts to copy into your own.
It tells the agent to read the help first. An agent guessing flag names fails on the first call and then invents a plausible reason why. Reading the real help, or aiglot help --json for the whole command tree at once, removes that.
It says one batch per culture, out loud. An agent that assumes one job with four targets will write an instruction a PO file cannot honour, and you will spend a plan cycle finding out.
It names the source language. Without it the source is inferred from the content, and that inference is least reliable exactly where it costs most: short UI labels, files with a stray translated line already in them, and text full of invented names.
It puts a stop before the spend. aiglot batches approve is the only command that costs credits. Everything before it is free and repeatable, so asking to see four plans first costs nothing. That property is what makes an unattended agent loop reasonable rather than frightening: an agent that misunderstands you burns plans, not money.
What the agent actually runs
for pair in fr:French de:German es:Spanish ja:Japanese; do
code=${pair%%:*}
lang=${pair#*:}
po=~/dev/starfall/Content/Localization/Game/${code}/Game.po
# 1. Create the batch. Free. Returns the file and its plan.
id=$(aiglot batches create "$po" \
--instruction "The source language is English. Translate into ${lang} only the entries whose msgstr is still empty. Leave msgctxt and msgid exactly as they are, and keep every placeholder and rich-text tag untouched." \
--json | jq -r '.data.id')
# 2. Read the plan, still free.
aiglot batches get "$id" --json | jq '.data.plan'
# 3. Approve. The only step that spends credits.
aiglot batches approve "$id" --quality lite \
--instructions "Keep UI labels under 28 characters. Keep placeholders exactly as written."
# 4. Wait for a TERMINAL status, not for a specific one.
until status=$(aiglot batches get "$id" --json | jq -r '.data.status'); \
[ "$status" = "completed" ] || [ "$status" = "failed" ] || [ "$status" = "cancelled" ]; do
sleep 5
done
[ "$status" = "completed" ] && \
aiglot batches download "$id" --output "${po%.po}.translated.po"
done
One detail there is worth stealing even if you never translate a game. The loop waits for any terminal status rather than watching for completed. A script that waits only for the status it hopes for waits forever on a failure, because a comparison against a value that never arrives is not an error. It is just always false.
If your agent prefers tools to a shell, aiglot mcp bridges to the MCP server. The CLI is the better starting point: it works in a script, it works in CI, and you can read exactly what ran.
The other half: an agent that only prepares the files
Full automation is not the only useful shape, and for a first pass it is often not the right one.
An agent is just as valuable doing the boring half and stopping. Ask it to walk the repository, find every localization file, report which cultures exist and which entries are still untranslated, and assemble a single ZIP with one file per culture. Then you upload that archive yourself, read the plan, approve, and let the agent put the results back in the right paths afterwards. That split keeps the two decisions with the person who should be making them, which language set you are paying for and whether the plan is right, and gives the machine the file handling, which is the part that is genuinely tedious and genuinely error-prone. The game localization solution page walks the same job through the browser if you would rather see it before scripting it.
Where a human still belongs
We are not going to tell you AI translation replaces a game translator, because for a game in particular it does not.
Use it for the bulk. UI strings, item and equipment descriptions, tooltips, achievement names, patch notes, the long tail of barks and flavour text. This is the volume that makes studios postpone localization for a year, and it is unremarkable in one pass.
Put human review on top where it earns its keep. Your opening hour, your key characters’ voices, anything comic, anything that rhymes. A first pass plus a reviewer is a good use of an expert and a bad use of a week spent inside files.
Hire a specialist outright for your store page and your trailer, which are the two texts that decide whether anyone sees the rest.
The reason this split works is that volume and importance are not correlated, and once you see it the budget decision makes itself. Your store page is a few hundred words carrying most of your reputational risk: paying a native expert for it is cheap in absolute terms and obviously worth it. Your nine thousand UI and item strings across eight languages are almost all of the words and none of the same risk, and no budget survives a per-word rate on them.
So run the volume here, then pick your own ceiling. Some studios push the output straight into the build. Others add professional review on their two biggest markets, or on the quest text only, and leave the rest as it comes back. Both are reasonable, and neither is a repair of a bad first pass.
Automation is there so that expert time goes into language instead of file handling. That is the entire pitch, and it is honest.
Start with the file you already have
Export from your engine. Send that file. Read the plan. Nothing is spent until you approve it, so the cost of finding out whether this fits your project is an upload and two minutes.
If you have a Unity String Table, a folder of Unreal PO files, or a spreadsheet of dialogue that has been waiting since your last milestone, that is the input. Sign up to AI Glot and translate one file first, then point an agent at the rest.