Localizing a mobile app: the moving parts engineers actually deal with
Mobile localization is often described as a translation task, but most of the work that engineers touch is structural: where text lives, how the operating system decides which version to show, and what happens when a layout built for one language meets a string twice as long. Get the structure right and translation becomes a content problem. Get it wrong and every new language is a new set of bugs.
Resource files, one set per language
Both major mobile platforms ask you to keep translatable text out of your source code and inside dedicated resource files, one set per language. A key like welcome_title maps to a string in each language's file, and the app looks up the key at runtime rather than hardcoding text inline. This is the same idea behind gettext-style catalogs on other platforms: the code references a stable identifier, and the actual words live somewhere a translator can open without touching code.
Keeping every string in these files, with no exceptions for 'just one quick label,' is what makes the rest of localization tractable. A string typed directly into a layout file or a source file is invisible to translators and invisible to any tooling that checks completeness.
How the OS actually picks a locale
Both platforms let the user rank an ordered list of preferred languages in the operating system's settings, not just pick one. When your app launches, the OS walks that list and looks for the closest match among the languages you've shipped resources for — first an exact match, then a related fallback, then your default language if nothing matches.
This matters for a common support question: 'why is my app in the wrong language?' The answer is almost always that the OS is doing exactly what it was told, using the user's ranked list, not what the developer assumed was 'their' language. If you ship Portuguese for Brazil but not the base Portuguese file, some devices with a plain Portuguese preference and no regional variant configured may fall through to your default language instead.
Layouts that survive text expansion
Text length varies enormously between languages for the same meaning. A short English label can expand well beyond its original length in some European languages, while some East Asian languages often render the same meaning in visibly fewer characters. A button sized to fit English text exactly will clip or wrap unpredictably once translated.
The practical fix is not to guess a safe pixel width. It's to build layouts that resize to their content — flexible containers instead of fixed widths, buttons that grow with their label, and text that's allowed to wrap onto a second line instead of being clipped. Testing with a deliberately long placeholder string in your default language during development catches most of these issues before a translator ever sees the screen.
- Avoid fixed-width buttons and labels; let them size to content
- Test with an artificially long string, not just the real translation
- Allow line wrapping on labels that can plausibly grow
- Leave room in icon-plus-text rows for the text to widen
In-app text and store listing text are separate jobs
It's easy to assume that once the app itself is translated, the job is done. The store listing — the title, description, screenshots, and keywords shown before anyone downloads the app — is a separate deliverable with its own text, its own character limits, and often its own writer, because it has to persuade rather than instruct.
The two also update on different schedules. In-app strings change with app releases; a store listing can be edited independently and more frequently. Treating them as one translation job usually means the listing gets stale copy or the in-app text inherits marketing tone it doesn't need.
When device language and region don't match
A user's language preference and their region setting are two different values, and they frequently disagree — someone traveling, using an imported device, or simply preferring a different interface language than the language of the content they consume. The region setting typically drives things like date format, currency, and number formatting; the language preference drives which translated strings are shown.
This split means you can end up with, for example, an interface in one language while dates and currency are formatted for a different region entirely. That's not a bug — it's the two settings doing their separate jobs — but it does mean you should format dates, numbers, and currency using the region, and pick your translated strings using the language preference, rather than assuming one setting tells you both.
Where this leaves you
None of this requires exotic tooling: it requires discipline about keeping text out of code, testing layouts against length, and treating the store listing as its own artifact. The apps that handle new languages smoothly are usually the ones where these decisions were made early, not the ones that translated the most carefully after the fact.