Locale merge conflicts are one of those problems that seem like they should be rare but are not. In a team doing active feature development across multiple branches, two engineers touching locale files in the same week is not unusual. And when both branches target the same locale file, the merge conflict that results is genuinely difficult to resolve correctly.
The difficulty is not technical -- git can show you the conflicting lines. The difficulty is semantic. You are looking at two versions of a string translation, one from each branch, and you cannot always tell which one is correct without knowing the context of each feature and what the translator intended in each case.
How Branch-Level Locale Conflicts Happen
The classic scenario:
Engineer A is working on a checkout redesign in `feature/checkout-v2`. She updates the English source string for `checkout.confirm.cta` from "Confirm purchase" to "Place order." The translator assigned to her branch updates `de.json` accordingly: "Bestellung aufgeben."
Simultaneously, Engineer B is working on a payment method update in `feature/payment-methods`. He updates the same key's English string to "Complete payment." His translator updates `de.json`: "Zahlung abschliessen."
Both branches are now carrying a modified `de.json` with different values for the same key. When either branch merges to main, the other branch has a conflict on `de.json` at that key. One translation will win and one will lose. If the merge is done carelessly -- which it often is, because locale files look like boring data files -- the wrong one wins, and a confusing German string ships that references a UI flow neither branch originally described.
Why Standard Merge Conflict Resolution Fails for Locale Files
The default workflow for resolving a merge conflict is: look at the three-way diff (base, ours, theirs), pick the version that is correct, commit. For code, the developer has enough context to make that call. For a locale file, the developer almost certainly does not.
The developer resolving the conflict may not speak German. Even if they do, they may not know whether "Zahlung abschliessen" or "Bestellung aufgeben" is the right phrase in context of the final merged feature, which may have changed during the conflict resolution. And even if they can evaluate the German, they have the same conflict in French, Japanese, Spanish, and Arabic sitting in queue behind it.
The common outcomes are bad: accept one version without evaluating it (introduces a potentially wrong string), create a manual merge of the two translations that a professional translator would never write, or defer the resolution by putting the key back to the base-branch value and marking the translation as needing re-queue (kicking the problem down the road).
The Architectural Fix: Branch-Isolated Locale State
The right fix is not better conflict resolution -- it is preventing the structural condition that creates locale conflicts in the first place. That means treating locale files as branch-isolated artifacts, not shared files that multiple feature branches modify concurrently.
In a branch-isolated model:
- Each feature branch has its own locale diff -- a record of which keys changed on that branch relative to the base branch, and what translations were produced for those changes.
- Locale files in the repository are not modified directly by feature branches during development. Instead, branches carry locale diffs.
- When a branch merges, the locale diff is applied to the main locale file. If two branches both carry changes for the same key, the merge system knows this and routes the conflict to a translator review rather than a developer resolution.
This model is different from the standard git workflow. It requires either a translation sync system that manages locale diffs separately from git file state, or a disciplined convention where feature branches do not commit changes to locale files directly but instead queue them through a central translation management layer.
Practical Mitigation Without Full Branch Isolation
If you are not in a position to change the fundamental architecture, there are mitigations that reduce the frequency and severity of locale merge conflicts:
Lock Locale Files to One Feature at a Time
Establish a convention that only one feature branch at a time is allowed to include locale file changes. Feature branches that need translations queue the translation task separately; translations are merged to a dedicated `translations` branch or directly to main after review, not bundled into the feature branch. This eliminates the structural condition for most conflicts at the cost of some translation workflow coordination.
Use a Locale-Merge-Only CI Step
Add a CI step that runs before merge to check whether the source locale file in the PR intersects with open changes on any other in-flight branch. If intersection is detected, block the merge until the conflict is resolved with translator input. This is a warning system, not a structural fix, but it prevents silent conflict resolution that introduces wrong strings.
Never Resolve Locale Conflicts Without Translator Review
This is a workflow rule that should be written down and enforced in your PR process: when a merge conflict involves a locale file, it requires a translator review before resolution, not a developer judgment call. Mark the conflict in the PR as needing localization review and route it to the translator who handled the affected strings.
The Cost of Getting This Wrong
Locale merge conflicts that resolve to the wrong string are silent bugs. They do not fail tests. They do not produce error messages. They ship to production with a string that is contextually wrong, and they surface only when a user who speaks the language in question encounters the inconsistency and either files a ticket or, more commonly, just loses trust in the product.
For consumer products with significant non-English user bases, localization quality is a retention signal. Getting the German checkout wrong is not a minor cosmetic issue -- it tells the German user that the product was not made for them. Branch-level locale isolation is the engineering solution that makes that class of error preventable rather than merely correctable.