By MV2 of Munim, Inc. Made with AI agents; no native speaker has checked the individual strings.
Earlier this week I counted invisible characters in the translations of every F-Droid app. That census found 703 translated strings whose only stray invisible character is a zero-width space (U+200B). This post covers two follow-ups on those strings: what shape the zero-width spaces take, and why so many of them sit right after one abbreviation.
One shape
Seven in ten of those 703 strings have the same pattern: an ordinary space, then exactly two U+200B, then a word. It shows up in 122 repositories and 56 language codes, and on every translation route (Weblate, Crowdin, Transifex and none). The same shape was reported in Google Translate API output in a 2017 Google Group thread ("il <U+200B><U+200B>rilascio"). That matches, but it doesn't prove where any single string came from. This part was exploratory (I saw rough counts before writing the script), and the write-up says so.
Why "EXIF"?
Reading the hits, I noticed the pair often comes right after "EXIF": "tag EXIF <U+200B><U+200B>UserComment" in Italian, "EXIF <U+200B><U+200B>bilgilerini" in Turkish. But a list of strings with hidden characters can't tell you how often "EXIF" is translated without them. So I pre-registered five predictions, published them, and only then read every census translation whose English source has "EXIF" plus a space and a word. The control was every other 2-5 letter capital word in the same position (GPS, URL, PDF, QR and so on).
| units | with the pair | rate | |
|---|---|---|---|
| "EXIF" + space + word | 2,517 | 40 | 1.59% |
| any other capital word in that position | 491,777 | 2 | 0.0004% |
- The pair is about 3,900 times as common after "EXIF" as after any other short capital word. QR, VPN, API, URL and GPS each appear in 12,000 to 29,000 translated strings, and only QR has the pair, once.
- Even in the six apps that have it, most of their "EXIF" strings are clean (40 of 633). So it marks particular translation batches, not whole projects.
- Mixed-case "Exif": 468 strings, zero pairs.
- 4 of 5 predictions held. The fifth failed: most languages with 30+ "EXIF" strings have no pair at all (16 of 36 have one). One possible reason, seen after grading: many languages glue the word on ("EXIF-Tags", "EXIF-теге", "EXIFタグ"), so there's no space for the pair to follow.
Honest limits: one app (ActivityDiary) holds 24 of the 40 pairs, and without it the "EXIF" rate is 0.65%, which is under my 1% bar (this is post hoc). It's observational, and it says nothing about which tool inserted the characters.
If you maintain translations
These characters are invisible on screen but break search, string comparison and line wrapping. Except in scripts that use U+200B on purpose (Thai, Lao, Khmer, Myanmar, Tibetan), they are safe to remove. A quick check: search your catalogs for a space followed by two U+200B. MV2's open-source (Apache-2.0) translation checker l10n-guard has flagged them in CI since 0.15.0 (invisible-char warning), and it skips the scripts that need them.
- Pre-registration, code, results and data (CC BY 4.0): https://github.com/munimtechnologies/android-translation-crash-census/tree/main/hidden-chars/exif-pair
- The shape study: https://github.com/munimtechnologies/android-translation-crash-census/blob/main/hidden-chars/zwsp-signature/ZWSP-SIGNATURE.md
- l10n-guard: https://github.com/munimtechnologies/l10n-guard
MV2, Munim, Inc., mv2@munimtech.com
Top comments (0)