top of page

How to Handle Multilingual Text and Dynamic UI Content in Mobile Test Automation

  • Autorenbild: Christian Schiller
    Christian Schiller
  • 15. Sept. 2025
  • 14 Min. Lesezeit

The Multilingual UI Flakiness Problem


Mobile UI tests are notoriously flaky when your app supports multiple languages. A simple change in text – whether switching from English to Korean or even a subtle character difference – can cause automated tests to fail unexpectedly. For example, one engineer found that a hidden newline character in a French welcome message (“Bienvenue…\nmy-app-name!”) caused a previously passing Appium test to break. The app looked correct on-screen, but the UI hierarchy had a sneaky difference that the test didn’t expect. Such brittle text representations often make tests fail even when the user-facing behavior is fine. In fact, many functional tests fail “not because of actual app errors, but due to changes like copy updates… This was already a challenge before considering the added complexities of … multilingual UIs”.


When an app is translated into Korean, Arabic, or any other language, the UI text and layout can change. Different scripts might introduce new fonts, longer words, or right-to-left layouts. Traditional automation scripts that look for exact strings or specific element positions tend to break under these conditions. This leads to high maintenance overhead for QA teams, who must constantly tweak or duplicate tests for each locale. In short, multilingual UIs and dynamic content (like varying text or layouts based on user context) have been a recipe for flaky tests and fragile assertions.


Why Verifying Text Across Languages Is Hard


Several factors make multilingual text validation a tough nut to crack:


  • Localized Strings & Layout: Apps display different text per locale – e.g. an English “Login” vs a Korean “로그인”. If your test expects one language, it will fail on the other. Even if you plan for both, translated text can be longer, causing line breaks or truncation that change the UI structure. Font and script differences (Asian characters, Arabic script, emoji) might not render the same way, sometimes leading to hidden characters or different encodings (like curly vs straight quotes) that confuse strict checks.


  • Brittle Locators: The safest way to find UI elements is by stable identifiers (resource IDs or accessibility IDs) rather than visible text. But not every element has a reliable ID. Many teams fall back to XPath or text-based locators (“find the element with text ‘Submit’”), which will only work in one language unless you write extra logic. Hard-coding assertions for each language leads to duplicate tests or complex conditional code. If a developer changes a single word or punctuation in the UI copy, a text locator or assertion can break the test.


  • Dynamic and Async Content: Modern apps often load content dynamically – for example, a welcome message that includes the user’s name or a daily quiz question that changes text every run. These aren’t static strings you can hard-code into a test. Timing issues also arise: a piece of text might appear after a network call or an animation delay. A test polling for a specific string might give up too early or miss subtle changes (like a loading spinner being replaced with text). Testers often resort to adding waits or retries, which can be hard to get right for every language and screen.


  • Accessibility Gaps: In an ideal world, every piece of UI text would be exposed via accessibility APIs (so automation can read it directly). In reality, some text is baked into images or custom components, especially for things like game score readouts, fancy fonts, or canvas drawings. These won’t show up in the normal UI tree that tools like Appium or Espresso retrieve. When testing a multilingual app, you might encounter certain languages not displaying via the usual getText() methods due to encoding or visibility quirks. It’s frustrating to see “the text is clearly on the emulator screen” yet your script reads an empty value or a placeholder.


Together, these issues make it clear why plain-vanilla automation struggles with multilingual and dynamic UI content. Test authors either limit themselves to language-neutral verifications (e.g. just check an element exists, not that the text is correct) or invest a lot of effort in per-language test logic – which is time-consuming and error-prone.


How Traditional Frameworks Try to Handle It (Pros and Cons)


Quality engineers have developed a few workarounds within traditional frameworks like Appium, Espresso, and XCUITest:


  • Resource IDs & Separate Strings: The recommended practice is to use resource identifiers for elements (so the locator doesn’t change with language) and to externalize expected strings. For example, your test might always find a button by id="login_button", then verify its label by looking up the expected text from a localization file based on the device locale. This avoids hard-coding text in the test. The upside is you can reuse the test logic across languages by injecting different expected values. The downside is the complexity – you need a mechanism to know the app’s current language and map it to the right expected string. Maintaining a dictionary of expected texts for 5, 10, or 180 languages can be cumbersome. And if the UI text changes (copy tweak or new translation), you must update your test data as well.


  • Multiple Test Suites or Parameters: Some teams duplicate their test suites for each target language (running the same scenarios in English, Korean, Spanish, etc.). Others use test parameters to loop through locales. This ensures coverage, but at the cost of multiplied execution time and maintenance. If a flow changes, you now have to update it in many places. It also doesn’t solve the core fragility: each run is still doing strict checks that might break on minor visual differences.


  • Using Accessibility where possible: On Android and iOS, UI frameworks allow developers to set an accessibility label or identifier that is language-agnostic. For example, a “Save” button might have a content-description like "save_button" that stays constant across locales. Where such labels exist, tests can assert e.g. that element.getContentDesc() == "save_button". This is more robust than checking visible text. However, not all UI elements have proper accessibility tags (especially older or third-party components). Also, verifying the actual displayed text is correct (not just that the button is present) still requires checking the text itself at some point.


  • OCR and Image Comparison Hacks: In cases where the text is not easily accessible (like a pop-up message with no ID, or a canvas-rendered string), engineers sometimes turn to image-based methods. A crude approach is taking a screenshot and using an OCR library (like Tesseract) within the test to read the text, then compare it to expected output. This can work across any language that the OCR engine supports, and modern OCR can handle over 100 languages with decent accuracy. In fact, the Appium community introduced an OCR plugin to make this easier. When enabled, it dynamically adds a special OCR context to your test session. In that context, the page source is populated with elements defined by their visible text instead of IDs. You can then find an element via XPath //item[text()="로그인"] regardless of it being an Android or iOS app, because the plugin presents the screen’s text as a searchable XML. The advantage here is obvious: you’re checking exactly what the user sees, and it works for any language or script because it’s just reading pixels. The disadvantage is that it introduces extra overhead and potential false positives if OCR misreads a character. Moreover, not all testing environments support such plugins – for example, cloud device providers didn’t yet support Appium’s OCR plugin at the time of a 2025 report, limiting this technique mostly to local runs.


  • Loose Assertions: Another pragmatic approach in traditional testing is to loosen the assertion criteria. Instead of requiring an exact match to a full sentence, testers assert partial content or use regex. For instance, if the English success message is "Profile updated successfully" and in Korean it’s "프로필이 업데이트되었습니다", one might just check that the word "updated" (or its Korean equivalent "업데이트") appears in the text. This way, as long as the translation contains that keyword, the test passes. This reduces brittleness when translations vary in wording. The trade-off is that it might not catch certain errors (if a translation is wrong but still contains the keyword). It also relies on the tester knowing which keywords to expect in each language, which again complicates test data management.


Each of these approaches attempts to mitigate flakiness, but none are silver bullets. They either increase the complexity of test code or only partially address the problem. It’s a juggling act: either hard-code and risk flakiness, or add layers of abstraction and maintenance to handle multiple languages and dynamic content. This is where new AI-driven solutions are changing the game.


GPT Driver’s AI-Enhanced Solution (OCR + Dynamic Understanding)


GPT Driver takes a different approach by leveraging AI – both computer vision and language models – to simplify multilingual and dynamic UI testing. To answer the original question: Yes, this tool can read on-screen text in any language (English, Korean, or otherwise) exactly as it appears on the emulator or device. In fact, GPT Driver was designed so you can write a test once and run it across iOS or Android in over 180 languages without rewriting assertions. Here’s how it tackles the problem:


  • Screen OCR and Accessibility Fusion: GPT Driver’s engine looks at the app like a human would. It uses OCR to read text from the screen image and also taps into accessibility layers when available. This means whether the text is a standard UI label, a custom-drawn canvas text, or a mix of Latin and Korean characters, the system can capture it. For example, if your app shows a Korean welcome message “환영합니다”, GPT Driver will detect those characters via OCR if they’re not directly accessible. Modern OCR is quite advanced (tools like Tesseract or Google Vision can handle multi-language text out-of-the-box), so GPT Driver can reliably recognize non-Latin scripts, RTL text, etc., on the fly.


  • Natural Language Assertions: Instead of writing code like assert element.text == "Login failed.", testers using GPT Driver write steps in plain language, such as: “Check that the login failed message is displayed to the user.” The AI interprets this intent and determines how to verify it. Importantly, the AI is not limited to an exact hard-coded string unless you want it to be. It will look at the screen’s text (from OCR or the UI tree) and understand if the login-failed message is present. If your app is in English, it might find “Login failed. Please try again.” If it’s in Korean, it might find the equivalent Korean message. As long as the expected meaning or the correct UI element is there, the step passes. This dramatically reduces false failures due to minor text changes or translations. (If you do need an exact match – say to verify a translation is 100% correct – GPT Driver offers an “exact text” assertion mode, but by default it’s a bit forgiving to avoid brittleness.)


  • Adapting to Dynamic Content: AI-driven testing shines when the UI is unpredictable. GPT Driver’s vision + LLM approach allows it to handle conditional or dynamic scenarios in one test flow. For instance, imagine an education app where after a quiz the screen might say either “Great job!” or “5-day streak!” depending on user status. A single GPT Driver step can be written to account for both messages (the AI will look for either outcome). In a traditional script you’d need an if/else or two separate tests, but the AI can reason that both variants mean “the user achieved something”. Similarly, if an element moves or the layout shifts due to longer text in German or Korean, the visual analysis can still locate the button or text by context (e.g. by its label or neighboring elements), not by an absolute XPath. The result is fewer flaky failures when content changes.


  • No More Brittle Locators: Because GPT Driver doesn’t rely solely on fixed element identifiers, it’s inherently more resilient to UI changes. If a developer forgets to assign a stable ID to a new label, the AI can still find it by reading the on-screen text or recognizing a button by its icon and position. This is a form of self-healing – tests continue to work across app versions and language editions, catching real bugs rather than getting tripped up by locator changes. As the makers put it, the visual+LLM approach “handles unexpected screens and UI changes without adjusting tests”. In practice, this means less maintenance: teams using GPT Driver report spending far less time updating tests for copy changes or new translations, because the AI handles those variations automatically.


  • Runs on Emulators and Real Devices: Whether you’re running on a local emulator or a cloud-based real device, GPT Driver can analyze the UI. It connects to a device session (their platform provides hosted simulators/phones) and sees whatever the user would see. So if the question is specifically about reading text on an emulator’s screen, the answer is yes – GPT Driver literally looks at the pixels of the emulator screen and reads any language displayed. It’s not constrained to what the OS’s accessibility API returns (which might miss non-visible text or certain toast messages). This also means it’s well suited for catching visual issues like overlapping characters or truncated text, which pure DOM-based checks might ignore.


In short, GPT Driver’s AI-driven method brings robustness by validating the UI output instead of relying on the internal UI structure. It combines the strength of human-like observation (seeing the screen) with the precision of machines (OCR for exact text when needed). By using natural language, it also lowers the barrier for writing complex test scenarios that span multiple languages or unpredictable content.


Best Practices for Multilingual and Dynamic UI Testing


No matter what tools you use, there are some strategies to keep your mobile tests stable across languages and changing content:


  • Design with Localization in Mind: Ensure your app uses consistent identifiers for elements and externalizes all user-facing text. This makes it easier to write one test that can work in any locale (by switching the app’s language setting). If you have control over development, encourage using accessibility labels and IDs that tests can hook into (e.g. a login_error_message id that stays the same in all languages). This reduces the heavy lifting needed in test scripts.


  • Parametrize or Loop Through Languages: If you’re using a code-based framework, take advantage of test parameters or data-driven testing to run the same scenario in multiple locales. Maintain a mapping of expected text per locale in a config or resource file. This way, you avoid duplicating entire test scripts – the logic is the same, only the checked values change. (For example, have a JSON of expected strings keyed by language, and your test reads the expected value at runtime based on current locale.) It’s extra work up front, but it pays off as your app adds more translations.


  • Leverage Modern Tools (OCR and AI): Don’t shy away from using OCR or AI assistance for tricky text validations. As demonstrated, an OCR step can fetch on-screen text in Korean just as easily as English, and frameworks like Appium now even provide plugins to integrate OCR results into your test flow. AI-based solutions go further by understanding context – consider them for complex flows where UI content isn’t static. Even if you stick with Appium/Espresso, you can incorporate a bit of computer vision: e.g., use an OCR library to verify critical texts (like the presence of a welcome message in whatever language) if direct methods fail. This adds resilience and catches issues (like missing translations) that purely code-based checks might miss.


  • Use Partial Matching Carefully: When verifying dynamic text, sometimes it’s impractical to assert the whole string (which may include random user data or timestamps). In those cases, assert the constant part of the text. For example, if the app shows “Hello, ! You have 3 new messages.”, you might just verify it contains “You have _ new messages.” in the current language. Be cautious: ensure the fragment is unique enough to avoid false positives. In multilingual tests, you might store regex patterns per language if needed (since word order can differ). AI tools can handle this more flexibly by understanding the intent (“there is a greeting with a new messages count”), but if doing it manually, define clear patterns for each locale.


  • Test Extreme Cases in Each Language: Dynamic UI issues often appear at the extremes – e.g., German or Russian translations that are significantly longer and break a layout, or Arabic text that causes an alignment issue. Incorporate these into your automation runs. If possible, as part of CI, run a smoke test in a couple of representative languages (like English for baseline, and one with long text or different script for edge cases). This way you catch layout problems or missing translation strings early. Some teams even automate screenshot comparisons for different locales to spot visual discrepancies. It’s not purely text validation, but it’s valuable for quality when you support many locales.


  • Combine Approaches for Robustness: The best solution often uses multiple techniques. For instance, you might use GPT Driver for end-to-end user-level validation (making sure everything looks correct to the user across languages), and still maintain a smaller set of unit/integration tests that verify specific strings in isolation (ensuring the copy text matches the expected translation exactly). Similarly, you could use Appium’s standard commands for most interactions (fast and stable by ID) and fall back to an AI/OCR-based step only when needed (for a text that doesn’t have a stable ID or is truly dynamic). This hybrid approach can give you both speed and flexibility.


By applying these practices, teams can significantly reduce the flakiness associated with multilingual UI testing. The goal is to write tests that are intent-driven (“does the user see the correct error message?”) rather than brittle (“does the screen have this exact 47-character string?”). This shift in mindset, supported by the right tools, leads to more robust automation.


Example: Traditional vs. AI Approach in Action


Consider a scenario of validating an error banner after a failed login attempt, in both English and Korean:


  • Traditional Approach: You write a test that enters a wrong password and then checks for an error label. With Appium/Espresso, this might involve finding an element by its ID (error_text) and calling something like getText() to compare it against the expected error message. If your test is written for English, you expect "Invalid password. Please try again." and assert that matches. Now you want to run the same test on the Korean version of the app. If nothing is changed, the test will still be looking for the English string and will fail – even though the app did show a correct error, just in Korean (“비밀번호가 잘못되었습니다. 다시 시도해주세요.”). To handle this, you’d need to modify the test: maybe parameterize it so that for locale=ko it expects the Korean string. This means your test code has to be aware of languages. Moreover, if the app’s designers tweak the message (say, add an exclamation mark or change wording), the strict string check fails. You’d have to update the expected value in your test data. In short, the traditional test requires maintenance whenever UI copy changes or for each new language added.


  • GPT Driver (AI) Approach: You write a test step in plain language: “After entering an incorrect password, verify that an error message is displayed to the user.” You don’t specify the exact text – you care that the user sees the appropriate error feedback. GPT Driver will perform the login attempt, then look at the screen. It will use OCR and accessibility info to find any error message visible. In an English run, it might see “Invalid password. Please try again.” and understand that this is an error (the wording and maybe the red color or icon clues it in). In a Korean run, it will see the Korean text and similarly recognize it as an error message on the screen. The assertion passes as long as some error is shown as expected. The same test script works for both languages without modification. If the developers change the text copy slightly, the AI is likely to adapt – it’s checking the intent (that a login failure message appears), not doing a byte-for-byte string match. Only if the error message failed to appear at all, or was completely wrong (say it showed a success message instead), would the AI flag it. This approach dramatically cuts down false failures. As one QA lead put it, they no longer worry about “brittle text” breaking their tests every time content changes. They focus on real issues (like if a translation is missing, meaning no error showed up, which the AI would catch).


The above example highlights how an AI-driven tool can reduce test maintenance. The QA team doesn’t need separate scripts for Korean vs English, and they don’t spend time updating expected strings for minor text changes. The test is resilient to dynamic content (imagine the error message contained a variable part, like number of attempts – the AI would still find it). Meanwhile, traditional tests demand explicit handling of each variation.


Key Takeaways


Testing multilingual apps and dynamic UI content has historically been hard, but it’s a challenge worth tackling to ensure a quality user experience for everyone. Traditional frameworks can do it – but with significant effort in managing locators and expected strings across locales, and with risk of flaky failures on small changes.


AI-enhanced solutions like GPT Driver offer a compelling alternative by reading the UI exactly as a user sees it and using intelligent reasoning to decide if the app behavior is correct. This approach greatly reduces false failures caused by language differences or content changes, letting your team trust the test results again. As the industry moves in this direction, we see tools using OCR and vision to bridge the gap between what the app displays and what tests can verify.


For QA leads and senior engineers, the lesson is clear: embrace techniques that make tests more robust to change. Use strong foundations (unique IDs, good localization practices) but augment them with modern tech – whether it’s an OCR plugin, visual assertions, or an AI-driven test platform. By doing so, you can write one set of tests that truly works across all languages and dynamic scenarios, with far less maintenance. The result is higher confidence in your automation suite and faster releases, because your tests focus on catching real bugs instead of being brittle “spell-checkers” for your UI. In summary, yes – it is possible to read and validate text in any language as it appears on screen, and doing so will make your mobile tests more reliable in our multi-language, ever-changing app world.

 
 
bottom of page