Localize Your App

Pseudolocalization: test the UI before you translate

A phone on a desk with stretched shapes overflowing a button, before an app is translated.

Pseudolocalization: test the UI before you translate

Localization means translating your app for real languages; pseudolocalization swaps your English for a fake but readable version (longer, accented, bracketed) so you can see layout and code bugs before any translation exists. Turn on Android's English (XA) pseudolocale or one of Xcode's pseudolanguages, tap through every screen, and fix what breaks. Translate after that.

The fake text keeps the words readable while adding length, non-ASCII characters and start/end markers, as Wikipedia's definition puts it. For English source text, Microsoft's heuristic is to lengthen strings by 40%, and the same page says extreme cases run 200% or even 400% longer. Short strings grow the most.

A W3C table citing IBM puts English strings of up to 10 characters at 200 to 300% of their length once translated into European languages, and strings over 70 characters at 130%. Your one-word buttons carry most of the risk.

What the fake text shows you

Wikipedia lists the bugs this test is meant to surface:

  • translated text that runs longer than the source and doesn't fit
  • accents or tall glyphs cut off at the top or bottom
  • right-to-left reading order
  • code that assumes ASCII
  • text that should be localizable but is hardcoded
  • things marked localizable that shouldn't be, like XML or HTML element names

The hardcoded case is the bug a file-only check can't see. Your strings file can be perfect and a Text("Settings") buried in a view will still ship in English to every market. A translation tool never sees that string, so nobody translates it.

To get a feel for the size of the problem, look at the W3C page's Flickr example: the English word "views" grew to 2.6× in Portuguese and French, 2.8× in German, and 3× in Italian. If you designed a tab bar around "views", that's a rewrite.

How to run the check on your app

  1. Move every user-facing string into your resource file. That's .strings or .xcstrings on iOS, strings.xml on Android, .arb in Flutter, JSON for most JavaScript setups. If you're unsure which file you have, the guide to .strings, .xcstrings, strings.xml, and .arb covers the differences.
  2. Switch the app to a pseudolocale or pseudolanguage. The platform sections below have the exact menu paths.
  3. Tap through every screen and read the text. Plain English with no accents is hardcoded. A bracket missing its closing half means the label got truncated. Two bracket pairs inside one sentence mean concatenation.
  4. Check the edges. Look for accents clipped at the top of a line, buttons that wrapped to three lines, and placeholders that came out mangled or empty.
  5. Switch to the right-to-left variant. Look for layouts that didn't mirror and punctuation stuck on the wrong side.
  6. Fix the source and run it again. Then send the file for translation.

Android: English (XA) and AR (XB)

Android ships two pseudolocales. English (XA) adds Latin accents to your English text, expands it with extra unaccented text, and wraps each message in brackets. AR (XB) flips left-to-right messages to right-to-left and reverses the character order.

Setup, per the Android docs (page last updated 2026-02-26):

  1. Use a device on Android 4.3 (API 18) or higher and enable developer options. Reboot after you turn them on.
  2. In the debug build type, set pseudoLocalesEnabled true (Groovy) or isPseudoLocalesEnabled = true (Kotlin DSL). Build and run.
  3. On Android 5.0 (API 21) or higher, go to Settings > Languages and input > Language preferences and drag the pseudolocale to the top.

Hardcoded strings show up unaccented. A concatenated message shows as one sentence split across two or more brackets, and translators can't reorder those pieces. The page names Japanese, Korean and Tamil as languages that put the verb at the end, so "Delete " + name + "?" can't become a correct sentence in them. Replace it with a single string and a placeholder before translating strings.xml.

Xcode pseudolanguages for .strings and .xcstrings

Apple puts the pseudolanguages in Product > Scheme > Edit Scheme > Run > Options > App Language. You get six:

Pseudolanguage What it does
Double-Length Doubles the length of localizable strings
Accented Adds accents to test high and low ascenders
Bounded String Wraps strings so you can spot truncation
Right-to-Left Simulates right-to-left writing direction
Right-to-Left With Right-to-Left Strings Simulates RTL direction using RTL strings
Emotional Simulates emojis

The same Options pane has Show non-localized strings, which renders nonlocalized strings in all caps. Turn that on together with Bounded String and you cover truncation and hardcoded text in one run.

There's no pseudo button inside the String Catalog editor; Apple's String Catalog docs don't describe one. The pseudolanguages are scheme and runtime options, and they apply to localized strings from either Localizable.strings or a catalog, so the same test works before and after a migration, and before translating a string catalog.

Flutter ARB and i18n JSON

Flutter's internationalization guide covers ARB files, flutter_localizations and gen-l10n. It doesn't document a built-in pseudolocale or flag, so there's no switch to flip like on Android or in Xcode. For the ARB workflow itself, see the article on Flutter ARB files and gen-l10n.

Some JavaScript stacks have it built in. Lingui generates a pseudo locale from its pseudoLocale setting at compile time, after extract, and you can pass an array to get both a left-to-right and a right-to-left version. The value has to match a configured locale. Lingui says the output finds hardcoded and improperly concatenated strings.

Game devs on Godot get a full panel of options under Project Settings > Internationalization (enable Advanced first), including skip_placeholders, per Godot's docs.

What accented English won't catch

Accents and padding stay in the Latin script. Japanese, Chinese and Korean break lines without spaces, render from different fonts, and take up different widths, so an accent pass that looks clean tells you little about a Japanese build. Microsoft pads its pseudotranslation with characters from Greek, Cyrillic, Asian and Indic scripts for that reason, and Windows has a separate East Asian-language pseudo locale. Neither Android's two pseudolocales nor Apple's list includes a CJK mode.

The W3C numbers have a caveat too: in the Flickr data, Chinese and Korean characters were counted as two English characters wide, so those ratios don't compare character counts. Microsoft's page states that pseudotranslation doesn't fully replace checking the translated app. For CJK, plan to look at the real translation on a device.

A paste-in generator can't find hardcoded text

Web tools that transform text you paste in are handy for mocking up a design, but they can only change strings you already pulled out of your code. A label hardcoded in a view never reaches the box, so the generator has nothing to flag. Running the pseudolocale inside the app is the only version of this test that catches hardcoded text.

Common mistakes

  • Testing only the screens you remember. Onboarding, error alerts, empty states and settings are where hardcoded text hides.
  • Leaving concatenation in. Two brackets in one sentence means two strings. Merge them into one string with a placeholder.
  • Letting a homemade transformer touch placeholders. If your script accents %s into %š or rewrites {count}, the build breaks or prints garbage. Godot added a skip_placeholders option for this case, and your script should copy the idea.
  • Treating a paste-in generator as proof. It tests the strings you extracted, which says nothing about the ones you didn't.
  • Assuming accents cover Japanese. They don't touch line breaking or font fallback.

Fix first, translate second

A truncated or concatenated string costs the same to translate as a good one. A split sentence gets translated into every language you ship, and after you fix the source, it has to be rewritten in every one of those languages again. Run the pseudo pass, fix the source, then translate once.

If your team already lives in Lokalise Expert, its bulk action for fake text is the quicker route: you type a length-increase percent and can add brackets with exclamation marks. Lokalise's own example is that German usually runs about 30% longer than English.

The docs say the feature isn't available in Lokalise Vantage, works from base-language values so it can't run on the base language itself, and only applies to the languages currently displayed. Since it works from values already in your project, hardcoded text still needs the in-app test.

Translating after the strings pass

Localize Your App is a web tool that translates app localization files with AI. It doesn't create a pseudolocale, so do the check above in Xcode or Android Studio first. After that, upload your .strings, .xcstrings, strings.xml, .arb or i18n JSON. Placeholders are locked, so %@ and {count} come back as they went in.

A glossary keeps product terms consistent. Translation memory reuses approved strings and those repeats are free, so re-translating after you fix one sentence doesn't charge again for the matched lines. You review source and target side by side and can edit any line.

Pricing is one-time credits with no subscription. Starter is $9 once for 8,000 credits, which the site says covers about a 200-string app in all 50 languages. It doesn't hire human translators, sync from git, or submit your app to the stores. You can ship the file in 50 languages once the pseudo pass comes back clean.

FAQ

How do I spot truncated labels and hardcoded text before real translations exist?

Run Android's English (XA) pseudolocale, or Xcode's Bounded String pseudolanguage with Show non-localized strings turned on. Labels missing a closing bracket are truncated, and text that stays plain English (or all caps in Xcode) is hardcoded.

Does lengthening strings with accents catch wrapping and font problems in Japanese or other CJK UIs?

No. Accents and padding stay in Latin script, so they miss CJK line breaking and font fallback. Microsoft pads with Asian and other scripts for this, but for a Japanese, Chinese or Korean build you still need to check the real translation on a device.

Is pseudolocalization the same as localization?

No. Localization translates and adapts your app for a real language. The pseudo version is a test that uses fake, readable text to find bugs in your code and layout before you translate.

Do I still need real translations after a pseudo pass?

Yes. The fake language only proves your strings are externalized and your layout can stretch. Microsoft's guidance says pseudotranslation doesn't fully replace checking the translated app, so you still translate and review the result.

When your pseudolocale run comes back clean, upload the strings file and translate your first file on one-time credits.

Ship your app in 50 languages by tonight

Upload your localization file, review side by side, download ready-to-import files for every language. One-time credits from $9 — no subscription.

No subscription. Credits never expire.