Translation memory is one of those tools that works intuitively at small scale and starts behaving in unexpected ways once you pass a certain threshold. When we expanded from three to twelve locales during our early-access program, the TM behavior we had calibrated for three languages stopped holding in ways that were not immediately obvious.
This is what we observed, and what we would do differently if we were sizing from scratch for twelve languages.
The Linear Assumption Does Not Hold
The intuitive model is: TM size scales linearly with language count. Three languages, store three translations per string. Twelve languages, store twelve. Memory usage goes up by a factor of four, match rates stay roughly constant, TM lookup latency increases modestly. That model holds for the storage dimension but breaks on every other dimension.
The first place it breaks is deduplication logic. At three languages, TM deduplication is straightforward. You match source text, normalize whitespace and punctuation, apply a similarity threshold (typically 75-85% for fuzzy matches), and return candidates. At twelve languages, the same deduplication logic is running independently for each locale, and the interaction effects start to accumulate.
Specifically: strings that are legitimate fuzzy matches in one language pair are false matches in another. "Submit" in German matches "Senden" -- a clean TM match. The same "Submit" key in Japanese does not have the same fuzzy-match space because the morphological relationship between Japanese UI strings is different from European language pairs. A 75% threshold calibrated for European languages will generate false-positive TM matches in CJK locales and too-conservative false negatives in closely-related language pairs like Norwegian and Danish.
Per-Locale Match Thresholds
The most impactful change we made was moving from a single global match threshold to per-locale thresholds. This is not a novel idea -- enterprise TMS platforms support it -- but it is rarely configured in practice because it requires actually knowing what threshold makes sense per language family.
The rough calibration we settled on:
- European alphabetic languages (DE, FR, ES, IT, PT, NL, PL): 75-80% fuzzy match threshold works well. These languages have enough morphological regularity that fuzzy matching is productive.
- CJK (ZH, JA, KO): 90%+ threshold for fuzzy matching, with strong preference for exact matches. Fuzzy matching below 90% in CJK produces more rework than it saves because character-level similarity does not correlate with semantic similarity the way it does in European languages.
- Arabic and Hebrew: treat similarly to European languages for threshold, but flag all TM matches for human review when the string contains numbers, dates, or units -- RTL rendering interacts with these in ways that require human judgment.
Storage Architecture and Lookup Latency
At three languages, TM lookup latency is rarely a bottleneck. At twelve, it can become one if the TM is stored as a flat file or a single-table database without appropriate indexing. The math: a product with 8,000 source strings, twelve languages, and an average of 1.5 TM candidates per string lookup is 144,000 candidate comparisons per full TM pass. If a TM pass is triggered on every PR, that number needs to resolve in seconds, not minutes.
The practical threshold we found: once you exceed approximately 50,000 total TM entries (source + translations across all locales), flat-file TM storage noticeably slows CI-integrated TM lookups. Moving TM storage to a properly indexed database with source-text hash as the lookup key and per-locale partitioning brings lookup times back to sub-second for this scale.
TM Divergence Across Languages
A subtler problem: TM divergence. As a product evolves, some locales accumulate approved translations faster than others. The German TM may have high coverage for UI strings because the German team reviews translations quickly. The Thai TM may lag because reviews happen less frequently. The TM coverage divergence means your match rates are not uniform -- and your estimates for "how much new translation work does this sprint add" will be wrong if you average across locales.
Track TM coverage and match rates per locale, not as an aggregate. When you see a locale consistently below 60% match rate on new strings, that is a signal that the TM for that locale needs attention -- either because the base coverage is low or because the match threshold is miscalibrated.
The 47-String Problem We Overlooked
Before we added TM integration to our own workflow, we shipped the same 47 strings -- error messages, empty-state copy, and form validation text -- across three different product areas without TM matching them. The strings were slightly different in each context ("No results found." vs. "No matches found." vs. "Nothing here yet.") but semantically equivalent, and translators handled all three independently across twelve languages.
That was 141 translation units (47 strings x 3 variants x 12 languages, minus matches that TM would have caught automatically) that a properly configured TM with semantic deduplication would have reduced to roughly 47 with variant reviews. At typical per-unit translation costs, the waste was significant. More important, the three variants produced three slightly different translations per locale, which created a subtle UX inconsistency that the localization team spent time reconciling later.
The lesson: TM is not only about cost -- it is about consistency. At twelve languages, inconsistency compounds because a variant in one language may not be visible until a user switches locales. Semantic deduplication at the source level, before strings enter the translation queue, is worth the setup time.
What to Instrument
If you are scaling to twelve or more languages, the metrics worth tracking on a per-locale basis are:
- TM match rate (exact + fuzzy) -- measures TM health and calibration quality
- Translator re-touch rate -- strings translated, then re-queued because source changed before review completed
- Coverage lag -- time from source string change to approved translation in each locale
- False-positive match rate -- matches that translators rejected and had to re-translate
The last one is the most revealing. A high false-positive match rate tells you the threshold is too permissive for that locale. A low match rate across the board suggests either a new product with thin TM history (normal for early stages) or a source string authoring style that varies too much for effective TM matching (the 47-string problem in a different form).
Scale your TM infrastructure ahead of your language count, not alongside it. The cost of recalibrating a misconfigured TM after it has been running at scale for six months is significantly higher than getting the thresholds right before you add the eighth language.