Features
Eight chapters, and the first one is why people switch.
Mergua is a translation management platform for teams shipping web apps — and the only one that treats a locale file the way you already treat code: on a branch, reviewed, merged.
Branches
A shared pool of keys is fine until two features touch the same screen. Then a rename on one branch breaks the other team's build, and the only fix is to stop translating until the merge lands. Mergua's branches remove that trade-off.
A graph of the branch checkout-redesign leaving the main branch, gaining 12 keys, then translations in de, fr, es, then a review, before merging back into main.
The diff comes before the merge
Added, changed and removed keys, per locale, listed the way a code review lists them. Nothing lands on main that you have not seen.
Protected branches
A protected branch cannot be renamed or deleted, and a merge cannot tidy it away afterwards. The merge target is protected for you, and cannot lose it while it is the target.
main is a default, not a rule
Point a project at develop and every merge goes there instead. A single merge can also target another open branch, for the release branch that is not ready for main yet.
Sync in, whenever you like
A branch that has been open for a week can pull the target's newer translations in at any point — from main, or from another branch. Where both sides changed the same value, the sync says how many and asks you to settle them before the merge.
Branch-scoped downloads
Add ?branch= to any export and your review deployment gets that branch's translations, not production's.
Named however you like
Mergua does not read your Git remote. The sync script passes the branch it is running on, which is why they line up in practice.
Translation editor
Three views over the same keys, because reviewing 400 strings and writing one careful sentence are not the same job. Panel for depth, inline for context, table for bulk. The source language stays on screen in all three.
Status per key — draft, translated, reviewed — as a dot in the key tree, so you can see where a locale stands without opening it. Arrow keys walk the list, Enter drops into the field, and a value saves itself half a second after you stop typing — so a long locale is a rhythm rather than a scroll. Translation memory suggests what you wrote for a near-identical key last month.
The other two views, and the filter that makes a locale finishable
Inline — for context
Every key of the language under the next, the source beside the field you type in, grouped by file. Writing a whole screen in one pass, where the string before matters.
Table — for bulk
Every language side by side, one row per key, editable in the cell. The key column and the header stay put while you scroll either way.
Missing — for what is left
One filter narrows all three views to the keys with no value yet. The arrow keys walk that list, so the rest of a locale is a sequence rather than a search.
AI translation
Machine translation fails on i18n for one reason: a key arrives with no sentence around it. Mergua sends the keys either side of it, so short strings land in the right sense. Translate one key or a whole locale, then review what came back.
AI output is never auto-approved — it lands unreviewed and waits for a human to sign it off. Placeholders like{count}survive the round trip, and a validator says so if they don't. Gold is reserved for AI across the whole product, so you always know what a machine wrote.
context sent with the key
- cart.summary.title
- Your cart
- cart.summary.open
- Ouvrir
- cart.summary.items
- {count} items
Because its neighbours are about a cart, open comes back as the verb, not the adjective.
Team & review
Invite a freelance translator without handing them the project. Roles restrict what someone can reach, reviewers approve or reject per key, and the discussion sits on the key it is about rather than in a thread nobody can find later.
Invitations go out by email and expire — no shared login. A rejected translation says why, and goes back to the person who wrote it. One page for what is waiting on you, across every project — branches to review, and your own work that came back. A review request and a mention also reach you by email, and one switch turns those off. Every change is in the history with a name and a timestamp.
checkout.pay.label
Payer maintenant
checkout.pay.spinner
Traitement en cours…
Sofia — the button is 90 px wide, this will clip. Shorter?
The two emails it sends, and the switch that stops them
There is no notification centre and no unread count to work through: the queue is where you look, and an email is a shortcut back to it. Two occasions get one — somebody asking you to review a branch, and somebody naming you in a comment — and both are one message per person per window rather than one per event.
Sent for review
Asking for a review mails everyone in the organization who could answer it, minus you. It names the project, the branch and how many changes are waiting, and lands on the queue rather than on one key. Withdrawing the request sends nothing, and asking twice sends nothing the second time.
Named in a comment
Mentions collect for five minutes and travel together, so being named four times in one editing session is one email. The window opens with the first mention and is never pushed back by the next, and a mention you have already read in the app before it closes stays out of the mail. The comment itself does not travel — the thread is where the words stay.
Off without signing in
One switch covers both, in your settings or straight from the link at the foot of either email, which does not ask you to log in first. Account email is untouched: verifying an address and resetting a password arrive whatever the switch says. What you lose is the nudge, not the work — every request and every mention still stands in the queue.
Multiple JSON files per language
Transloco, i18next and vue-i18n all split a locale across files — common.json, errors.json, one per area — so a screen loads only the strings it needs. Mergua keeps that split the whole way through: the files go in as they are, one editor works across them, and they come back in the same shape. A project says once, in its settings, whether it holds one file per language or several.
(The CLI and the API call one of these files a namespace.)
In your repo
common.json148 keys
errors.json36 keys
checkout.json72 keys
Every language carries the same set of files, and the import takes all of them in one pass.
In the editor
- checkout.summary.title checkout
- nav.title common
The badge is the file a key belongs to, so title in checkout is never taken for title in common.
Upload them all at once
Pick the whole folder. The import previews each file on its own — new keys, conflicts, and what it will leave alone — before anything lands, and a file that should carry a different name gets it corrected right there.
One editor, filtered by file
The key tree, the inline view and the table all take the same file filter, and every key carries the file it belongs to. Turn the filter off and you are back to the whole project.
Download one file, or all of them
Choose a file and you get that file. Choose all of them and the ZIP is laid out {locale}/{file}.json — the shape your loader already reads, with nothing to unpack by hand.
Rename and merge, without losing keys
A rename changes the file a key sits in and nothing else — the translations and the history come with it. A merge asks, per clashing key, which version survives, and records the answer in that key's history.
Pipeline sync
One shell script, fetched by curl, no package added to your project. It reads the locale files already in your repo, pushes keys Mergua has not seen, pulls finished translations back, and notices when a branch was merged.
GitLab, GitHub and Gitea — the branch name comes from the CI variable each one already sets. Or skip the script: the REST API is project-scoped, branch-aware, and returns nested or flat JSON.
$ curl -sSL api.mergua.com/v1/mergua.sh | sh
• branch checkout-redesign (from CI_COMMIT_REF_NAME)
• scanned src/assets/i18n/en.json — 412 keys
↑ pushed 12 new, 0 changed
# merge detected — keys promoted to main
Formats & validation
Import what you have, export what your build needs. These four are the whole list, both JSON layouts round-trip, and placeholders are checked everywhere a value arrives — in the editor while someone is still there to fix them, in the import preview before a file lands, on a CI push, and on whatever the AI hands back.
The fourth one leaves. XLIFF 2.0 is what a translation agency and its tools speak, so a language goes out as one document and comes back as one — and what stays in your repository is still JSON.
- JSON
- JSON · flat
- ARB
- XLIFF 2.0
Placeholder validation
Single and double braces, printf (%1$s), i18next references ($t(key)) and ICU plurals. If the source has {count} and the translation doesn't — or renamed it — you hear about it here, not in a runtime error.
Placeholder missing
cart.summary.items · fr · expected {count}
Progress per locale
The bar changes colour as a locale fills up, so “are we ready to ship French?” is a glance, not a query.
- de100%
- fr82%
- es44%
Webhooks
The chapter above is your pipeline calling Mergua. This is Mergua calling your pipeline: one HTTPS POST to a URL of yours when a project's translations change or a branch is merged. The build starts on the change rather than on a schedule, and nothing has to poll to find out.
A branch filter, and it starts at main — a release pipeline hears about main, not about every keystroke on somebody's feature branch. An import of four hundred keys is one delivery, not four hundred — changes are grouped per language and file over a short window before it fires. Every delivery is signed with a secret only your endpoint and Mergua hold, and the body says what moved instead of carrying the text — the pull that runs next fetches the files.
X-Mergua-Event: translations.changed
X-Mergua-Signature: sha256=4f1c9b2e…
{
"branch": "main",
"locale": "de",
"counts": { "added": 12, "updated": 3, "deleted": 0 }
}This page is the tour. The docs are the manual.
Already using Mergua and looking for the exact behaviour of a setting? /docs/features covers the same ground field by field.
Try it on one branch.
The free tier is enough to run a real feature through the whole loop.
Create your account