When we were designing the Tonguesage sync engine, the first decision we had to make was the unit of synchronization. Files or strings? The answer seems obvious from a modern software standpoint, but the localization industry has defaulted to file-sync for a long time, and that default has consequences worth unpacking.
How File Sync Works
File sync is exactly what it sounds like. Your translation management system maintains a copy of each locale file. When you want translations updated, you export the file (or a set of files), upload it to the TMS, translators work through it, you download the translated file, and you merge it back into your repo.
For a product with stable copy -- say, a marketing site that rarely changes -- file sync is fine. The files don't change much, the export/import cycle is infrequent, and the overhead is manageable.
For a product in active development, file sync breaks down immediately. Here is why.
The Category Error in File Sync
A locale file is not like other source assets. A PNG, a compiled stylesheet, a PDF -- these assets change as discrete wholes. You version them, you deploy new versions, the old version is superseded. When you sync a PNG, syncing the file is the right model because the file is the unit of change.
A locale file is not a whole unit. It is a container for hundreds or thousands of independent string entries, each of which has its own change history, its own translation state, and its own relationship to the code that renders it. When two strings in the same file change, those changes may come from two different features on two different branches by two different engineers. Treating them as one atomic change -- because they happen to live in the same file -- is a category error.
File sync compounds this problem. When you export a locale file for translation, you export all of it: the strings that changed, and the strings that didn't. The TMS has to figure out which strings already have valid translations and which need attention. Different TMS implementations handle this with varying degrees of accuracy. Some flag everything as untranslated if the file hash changed. Some do string-level comparison but miss strings where the key changed without the English text changing. Some require the translator to manually review the whole file regardless.
The result is translators doing more work than necessary, and some changed strings still slipping through because file-level diffing is inherently approximate.
String Sync: The Right Unit of Synchronization
String sync starts at a different level. Instead of tracking files, it tracks individual string entries: the key, the source text, the hash of the source text, and the translation state per locale.
When a commit is pushed, the sync engine parses the locale files and computes a diff against the last known state -- not at the file level, but at the string level. It identifies exactly which strings are new, which have changed source text, and which are unchanged. Unchanged strings with existing translations are untouched. Only the delta enters the translation queue.
This has several concrete consequences:
- Translators see only what actually changed. A 3,000-string file where 12 strings changed produces a 12-item translation job, not a 3,000-item re-review.
- Translation memory matches are applied automatically to unchanged strings, so the TM isn't doing redundant lookup work.
- Branch isolation is natural. Each branch has its own string diff. Two branches touching the same file produce separate translation queues tied to their respective changes -- no collision.
- Stale translation detection is exact. If string key `checkout.confirm.cta` has source text "Confirm purchase" and that changes to "Confirm order," the sync engine knows that locale translations of "Confirm purchase" are now stale, regardless of file-level freshness.
What File Sync Gets Right
File sync is not without merit. It is conceptually simple and maps naturally to the mental model of "I have these files, I need them translated." For teams with a slow-moving codebase and a well-established manual workflow, file sync is adequate.
File sync also has broad TMS support. Almost every TMS on the market supports file import/export. String-level sync requires either a TMS that has a proper API for individual string management or a sync layer (like Tonguesage) that handles the string-level tracking and only pushes translation tasks to the TMS.
The Practical Difference at Scale
The distinction becomes most visible when you look at what happens to translation rework rates. Under file sync, translators frequently re-touch strings they have already translated because the file was re-exported after a different string changed -- bringing the old translated strings back into the queue as apparent changes. Under string sync, a string that has not changed does not enter the queue, period. The translator's workload is strictly the delta.
It also affects translation memory hit rates. String sync means your TM is queried at the exact string level, so matches are applied precisely and your TM grows with accurate change history. File sync at best approximates this; at worst, it bypasses the TM entirely for strings that a file-level diff marks as "potentially changed."
When we built the Tonguesage sync engine around the string as the fundamental unit, this was not an optimization -- it was a correctness requirement. The alternative was building a system that would inevitably produce the same sprint gaps and translator re-touch cycles that motivated the product in the first place. Treating locale files like any other asset is how you end up with a German checkout that is two sprints behind.