Testing Mobile Application Localization
"Register" button in German became "Registrieren" and went outside UIButton bounds — designer didn't account that German averages 35% longer than Russian. Or Arabic RTL text mixed with LTR numbers looks like garbage. This is localization testing classic that English autotests never catch.
Most Common Issues
Hardcoded strings. In Xcode localizedString(forKey:table:bundle:) not called — instead label.text = "Welcome" directly in code. Tool to find: genstrings or SwiftLint rule no_direct_string_use (custom). On Android same — strings in strings.xml vs inline in XML layouts vs concatenation in Kotlin.
Date, number, currency formatting. DateFormatter without explicit locale uses system user locale, but NumberFormatter or just String(format: "%.2f", price) — no. American format 1,234.56 in German locale should be 1.234,56. Such errors don't break UI but look unprofessional.
Text direction (BiDi). In Arabic and Hebrew locale layoutDirection = RTL. Back/forward icons swap places, padding and margin should mirror. On iOS semanticContentAttribute = .forceRightToLeft at view hierarchy level. On Android — android:supportsRtl="true" in manifest and layoutDirection="locale" in layout files. If single custom view draws text through Canvas.drawText without RTL — bug.
Tools and Approach
Pseudolocalization — first and cheapest test. Replace all strings with pseudolocalized version: add accents to letters and lengthen strings 30–40% ([Ñéṁö Ŝţŕïñĝ!!!!!]). This reveals all cut strings and hardcodes before you paid translator.
On iOS — menu item Scheme → Run → Options → App Language: "Pseudolanguage - Accented Latin". On Android — LocaleList.setDefault(Locale("ar")) in Application.onCreate for RTL testing, or pseudo-locale en-XA via adb:
adb shell settings put global locale_overlay en-XA
Screenshot testing by locales. Paparazzi (Android) or SnapshotTesting (iOS) allow running one test with locale set:
@Test fun allLocales() {
for (locale in listOf("en", "de", "ar", "ja", "ru")) {
paparazzi.snapshot(locale = locale) {
RegistrationScreen()
}
}
}
Each run CI generates screenshots — reviewer sees difference visually. Auto-catches cut buttons.
Manual testing with native speaker. No replacement for semantics. Machine translation can give grammatically correct but contextually strange text. "Click here" in Japanese sounds rude — need お進みください. Not automated.
| Check | Tool | When |
|---|---|---|
| Hardcoded strings | SwiftLint / Android Lint | CI on each PR |
| UI cut | Pseudolocalization | During development |
| Screenshots by locales | Paparazzi / SnapshotTesting | CI |
| RTL layout | Device/emulator with Arabic locale | Before release |
| Number and date format | Unit tests with specific locales | During development |
| Translation semantics | Native speaker | Before release |
Process
Audit current locales — how many supported, RTL present. Pseudolocalization setup in Scheme/build config. Add screenshot tests for key screens with locale set. Manual testing of complex languages (Arabic, Japanese, German). Defect list with reproduction.
Timeline — 2–4 days on project with 3–5 locales. RTL locales add 1–2 days if layout not prepared for RTL from start.







