Unity gives you three ways to get your String Tables out, and the one you choose decides the shape of the whole job. Not the quality, not the cost: the shape. One route hands you a single file with a column per language. Another hands you one file per language. Picking the wrong one for how you work is how a two-hour job becomes a fortnight.
This is a guide to all three, what is actually inside each export, and how to run the translation without hand-editing a single row.
The three routes out of a String Table Collection
Unity’s Localization package exports String Table Collections to CSV, XLIFF and Google Sheets. That is the whole menu, and all three land on file formats AI Glot reads natively, so none of them needs a conversion step.
They are not interchangeable, though, and this is the part worth two minutes:
- One file for every language
- One column per locale, side by side
- One job fills all of them
- Easy to eyeball in a spreadsheet
- Matches on Key or Id at import
- One file per target language
- Each file is one source and one target
- Ten languages is ten files
- What a translation vendor usually asks for
- Version 1.2 or 2.0, your choice
CSV keeps your languages together. A table can hold as many columns as you like, so a single file carries English, French, Japanese and everything else at once, and one translation job can fill every empty column in one pass.
XLIFF splits them apart. An XLIFF file pairs one source with one target by design, so Unity writes a separate file per language and appends the language code to the name: a collection called MyGame exports as MyGame-ru for Russian, MyGame-ja for Japanese. That is not a limitation of Unity, it is what the format is. Unity supports both XLIFF 1.2 and 2.0, and AI Glot reads both.
Google Sheets is the CSV shape with a sync button. Push your collection to a sheet, pull it back when it is filled. If you already work that way, export the sheet to CSV or XLSX and the job is identical to the CSV route.
So the honest recommendation: choose CSV unless something downstream demands XLIFF. Ten languages in one file is one job to run, one plan to read and one file to re-import.
What is actually inside the CSV export
Open it once and the whole workflow stops being mysterious. A basic export has a Key column, an Id column, and one column per locale named after the language and its code, like English(en) and French(fr). Export with comments and you also get a Shared Comments column plus a per-locale one such as French(fr) Comments.
Key,Id,English(en),French(fr)MENU_BTN_START,4102,Start game,MENU_BTN_START,4102,Start game,CommencerHUD_AMMO_LEFT,4103,{0} rounds left,HUD_AMMO_LEFT,4103,{0} rounds left,{0} balles restantesNPC_SMITH_GREET,4104,Need something forged?,NPC_SMITH_GREET,4104,Need something forged?,Une pièce à forger ?Two columns in there decide whether your import works at all.
Key and Id are the join. Unity matches rows on them when you re-import, and it uses the column header names to find them. A translated Key does not fail loudly: the row simply stops matching, and one string silently reverts to its fallback in every language. Say plainly which columns to translate and which to leave, and this cannot happen.
The comment columns are context, not content. If your team writes notes for translators in Shared Comments, those notes are useful to read and wrong to translate. Name them.
The thing that breaks, and it is not the timing
Unity’s Smart Strings are the real hazard in a game’s String Table, and they are invisible to anything translating word by word.
A Smart String carries logic inside the text. An empty placeholder is {}. A named one gives a translator context, like {PlayerName}. Plurals follow the Unicode CLDR rules through a formatter, so a single entry can read {0:plural:is 1 item|are {} items}. They nest, too: {User.Address:{Street}, {City}}.
A translator who does not know the syntax reorders the braces, translates the word plural, or helpfully turns {PlayerName} into {NomDuJoueur}. Each of those is a runtime break rather than a typo, and you find it when a player screenshots it.
This belongs in the string-level instruction, and getting that distinction right is the single most useful thing in this article.
- Decides WHICH text is translated
- Read once, against the file
- "Fill the empty French column"
- "Leave Key, Id and the comments alone"
- Decides HOW each line is written
- Applied as every single string is written
- "Keep every {curly-brace} placeholder exactly as written"
- "Keep UI labels under 20 characters"
Put a placeholder rule in the plan and it does nothing useful. Put a column rule in the string-level slot and it does nothing at all, silently, because there is no file in view at that point. Both failures are quiet, which is why they are worth thirty seconds.
While you are there, the other genuinely game-specific rule: a button that fits in English overflows in German. Translated text commonly runs 15 to 30% longer, and a string-level instruction can ask for a ceiling, so the line is written to fit rather than trimmed afterwards. Say it once, for the entries that live in a fixed-width UI.
Running it, route one: the browser
Upload the CSV at the CSV translator or in the app, then describe the job in one sentence. Something like this, and it is deliberately unglamorous:
The source is the English(en) column. Fill the empty French(fr), German(de)
and Japanese(ja) columns. Leave Key, Id, English(en) and every Comments
column exactly as they are.
You get a plan back before anything is spent: the columns it found, the scope, the word count and the cost. If it misread your file, correct it in a sentence and it plans again. Everything up to approval is free, so a wrong reading costs you nothing but the time to retype a clause.
Then download one CSV, same columns, same Key and Id, and re-import it in Unity.
Running it, route two: your agent does the whole loop
If you work with Claude, Cursor, Copilot or any agent that can run commands in your project, it can do all of this without you opening a browser, and it can put the results back where Unity expects them.
Install and sign in once:
npm install --global @ai-glot/cli
aiglot auth login
- 1ExportString Tables to CSVIn Unity
- 2CreateOne job, all localesFree
- 3Read the planColumns, words, costFree
- 4ApproveYour decision, and the only spendSpends credits
- 5Write backInto the repo, ready to importAgent
Here is a prompt you can hand to your agent. It is written to be pasted, and the parts that matter are explained underneath.
Our Unity String Table export is at Assets/Localization/Export/MyGame.csv.
Columns: Key, Id, English(en), and empty columns for French(fr), German(de)
and Japanese(ja).
Use the aiglot CLI to translate it. Run `aiglot batches create --help` and
`aiglot batches approve --help` first so you use the real flags.
Plan instruction: the source is English(en); fill only the empty French(fr),
German(de) and Japanese(ja) cells; leave Key, Id, English(en) and any
Comments column untouched.
Approval instructions: keep every curly-brace placeholder exactly as written,
including plural formatters and nested ones; never translate a placeholder
name; keep entries whose Key starts with MENU_ or HUD_ under 20 characters.
Use the lite quality tier. Show me the plan and the total cost BEFORE you
approve anything, then wait for me to confirm.
After I confirm, poll until it reaches a terminal status, download the result
over the original path, and tell me the row count so I can re-import in Unity.
It tells the agent to read the help first. An agent that guesses flag names fails on the first call and then invents a reason why.
It separates the two instruction kinds explicitly, which is the whole point of the section above. Written this way, the agent puts each in the right place instead of merging them into one blob that half works.
It stops before the spend. aiglot batches approve is the only command that costs credits. Everything before it is free and repeatable, so an agent looping over your locales unattended cannot surprise you with a bill. That property is what makes handing this to an agent reasonable rather than reckless.
It ends with a number to check. Asking for the row count gives you a one-second sanity test before you re-import.
For reference, the sequence it lands on:
# 1. Create the job. Free. Returns a plan and an id.
id=$(aiglot batches create Assets/Localization/Export/MyGame.csv \
--instruction "The source is English(en). Fill only the empty French(fr), German(de) and Japanese(ja) cells. Leave Key, Id, English(en) and Comments columns unchanged." \
--json | jq -r '.data.id')
# 2. Read the plan for free, and only then commit.
aiglot batches get "$id" --json | jq '.data.plan'
# 3. The only step that spends credits.
aiglot batches approve "$id" --quality lite \
--instructions "Keep every curly-brace placeholder exactly as written. Never translate a placeholder name. Keep MENU_ and HUD_ entries under 20 characters."
# 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
# 5. Back into the project.
[ "$status" = "completed" ] && \
aiglot batches download "$id" --output Assets/Localization/Export/MyGame.csv
There is also an MCP server, aiglot mcp, if your agent prefers tools to a shell. Start with the CLI: it works in a script, it works in CI, and you can read exactly what ran.
If you went the XLIFF route
One file per language means one job per language, and that is fine until it is ten. Two ways to handle it.
Put them in one ZIP. Up to 200 files and 20 MB, with 4 MB per file. Every XLIFF in the archive has to be the same version, 1.2 or 2.0, but they are allowed to have different target languages, which is exactly the shape Unity’s export produces. One job, one instruction, one glossary applied across the set.
Or loop with the CLI, the way the prompt above does, one batch per file. More jobs, but each plan is separately reviewable, which some teams prefer for a first run. Either way the files come back as XLIFF in the version they arrived in, with the source segments untouched and only the targets filled.
The part that decides quality: your own vocabulary
Everything above is plumbing. The reason a translated game reads well or badly is whether your terms hold.
Put the words that must not drift into a workspace glossary once: character names, item and spell names, faction names, the house translation of a recurring line. It belongs to the workspace rather than to one job, so it applies to every String Table you send afterwards, including the export you make in six months when the game has grown by four thousand entries. That is what makes file number twenty agree with file number one.
Have your agent draft it. The glossary is reachable over MCP, with tools to list, read and edit terms, so the same agent that just read your String Tables can pull out the proper nouns and invented words that recur, hand you the list, and write the approved ones into the workspace before the first translation runs. A glossary nobody fills in protects nothing, and for a game with a thousand invented terms, filling one in by hand is the task that gets postponed indefinitely.
This is where a general machine translator struggles, and the reason is mechanical rather than a matter of taste. Its glossary substitutes a term wherever it matches, without reconsidering the sentence around it. A glossary here is carried in as meaning while the line is written, so a name inflects into the grammar instead of being dropped into the middle of it.
The honest scope of this
Do not run your opening hour through this and ship it. The first thirty minutes of a game, the store page and anything a player is likely to quote are writing, and writing deserves a person. That is a few hundred words carrying most of your reputational risk, so paying a native expert for it is cheap in absolute terms and obviously worth it.
The other nine thousand entries are a different job, and this is the split worth internalising: volume and importance are not correlated. Menu labels, tooltips, item descriptions, quest logs, achievement text, error strings: that is where the hours actually go, and it is miserable by hand and unremarkable in one pass. Run the bulk here, then pick your own ceiling: push it straight into the build, or add professional review on your two biggest markets, or on the quest text only, and leave the rest as it comes back. None of those is a repair of a bad first pass, and all of them spend your reviewer’s time on language instead of on spreadsheets.
If you want to see it on a real file before committing to a pipeline, the CSV translator takes an export without an account. The wider picture is in our guide to translating a video game, and the game localization page covers the formats beyond Unity if your studio ships on more than one engine.
Unity’s export behaviour described here comes from the Localization package documentation for version 1.5: the CSV column layout, the Key and Id matching, the comment columns, XLIFF 1.2 and 2.0 support, and the per-language XLIFF naming. Check your own package version if your export looks different, and the file limits quoted are the ones in force when this was written.