If you've ever shipped a multilingual mobile app, you've probably encountered bugs that behave like undefined behavior in C++: everything works perfectly in testing until production reveals edge cases that only surface in specific locales.
Localization bugs follow similar patterns. A missing plural category in Polish, an unescaped ampersand in German, or a mismatched placeholder in Japanese can crash your app or silently fall back to English — often in ways that are impossible to catch during development.
This post covers the input and output validation pipeline we use for iOS, Android, and React Native projects. Think of it as running static analysis and sanitizers over your translation files, because these resources are effectively compiled assets that need the same rigor as your code.
Before any translation work begins, we parse and validate the base-language files. This is essentially precondition checking for resource files.
Duplicate Keys
Duplicate keys violate basic resource management principles. We reject them outright rather than allowing undefined behavior during compilation.
Structural Validation
Between XML (Android), .strings + .stringsdict (iOS), and JSON (React Native), there are countless ways to introduce syntax errors. We validate:
- File structure and encoding
- Escape sequence correctness
- Platform-specific formatting requirements
- Quote integrity and termination
An unescaped ampersand in Android XML or a missing semicolon in iOS strings will break your build. Better to catch these issues early.
Placeholder Safety
Placeholders function like API contracts — if you change the signature, all callers break. We verify that:
- Placeholder counts match expectations
- Order is preserved unless explicitly changed
- Format specifiers are consistent (
%s vs %@ vs {name})
- Plural-specific placeholders maintain consistency
If one locale drops or adds a placeholder, that's not a warning — it's a runtime crash waiting to happen.
Plural Validation: Where Linguistics Gets Complex
Plurals are where most developers discover that natural language operates under different rules than programming languages.
Platforms handle plurals differently:
- Android: Six possible categories (
zero, one, two, few, many, other)
- iOS: ICU rules implemented via
.stringsdict files
- React Native: Varies by i18n library, often messageformat-based
Languages differ even more dramatically.
Example: Polish Plural Logic
Polish demonstrates why plural validation matters. The rules look like they were designed by someone who writes template metaprogramming for entertainment:
one applies to numbers ending in 1, except 11
few applies to numbers ending in 2–4, except 12–14
many covers everything else
other exists because linguistic edge cases are infinite
This translates to logic roughly equivalent to:
if (n % 10 == 1 && n % 100 != 11) {
return one;
} else if (n % 10 >= 2 && n % 10 <= 4 && !(n % 100 >= 12 && n % 100 <= 14)) {
return few;
} else {
return many;
}
This is essentially what ICU implements under the hood.
Why This Matters for Runtime Behavior
If your translation file lacks any required plural category, Polish users will see broken UI or fallback text. Both Android and iOS request specific categories based on the numeric value being displayed — if the translation cannot satisfy that request, your app enters undefined behavior territory.
The validator ensures:
- All required categories exist for each language
- No categories are missing or misspelled
- Placeholders match across all plural forms
- Platform-specific structure (like
.stringsdict nesting) is correct
Polish is dramatic but not unique. Arabic plural rules are even more complex, involving different logic for different numeric ranges.
Output Validation: Verifying Translation Quality
LLMs are useful tools, but they occasionally behave like junior developers who "simplify" your interface by changing %1$s placeholders to %s and deciding JSON doesn't need proper comma placement.
Every translated file gets validated for:
Syntax Correctness
- XML well-formedness
- JSON structural validity
.strings quote and escape integrity
.stringsdict proper nesting and key presence
Each platform requires different escape sequences. LLMs don't inherently understand these requirements, so we enforce platform-specific rules during validation.
Placeholder Consistency
If a translation drops a placeholder, that's an error.
If a translation introduces a new placeholder, that's an error.
There are no "warnings" for placeholder mismatches — only binary pass/fail.
Plural Completeness
If a language requires six plural categories and the translation provides four, we reject the entire file. Plural rules are mandatory, not optional.
Testing Across 80+ Languages
To ensure consistent behavior, we run validation tests across all supported languages, verifying:
- ICU plural rule compliance per language
- Category completeness requirements
- Placeholder consistency across plural forms
- Structural correctness for each platform
- Unicode handling and escape safety
- Platform-specific differences between Android, iOS, and React Native
This approach catches edge cases that would otherwise surface only in production — including languages where "zero" doesn't map to "other," languages where plural categories depend on the final two digits, and languages where negative numbers follow different rules than zero.
Why Validation Prevents Production Issues
Without systematic validation, teams regularly encounter:
%@ vs %s format specifier mismatches causing crashes
- Android builds failing due to unescaped XML content
.stringsdict files silently failing and falling back to English
- i18next rendering object references instead of translated strings
- Plural sets missing required categories for specific languages
- CI failures that work perfectly in development environments
Validation eliminates these issues before they reach devices or production environments.
Conclusion
Localization bugs are subtle, platform-specific, and often catastrophic when they surface in production. By treating translations as compiled resources and validating them with the same rigor applied to source code, we eliminate entire classes of runtime failures.
Proper validation ensures that whether you're targeting English, Polish, Arabic, or any other language, your localized app behaves predictably across all platforms and locales.
Ready to localize your app?
Get started free — no credit card required.
Start Translating →