App Store vs Google Play locale codes, side by side

The two stores use different codes for the same language, and the mismatches are not systematic. Here is the mapping:

Language App Store Connect Google Play Same?
English (US) en-US en-US Yes
English (UK) en-GB en-GB Yes
Spanish (Spain) es-ES es-ES Yes
Spanish (Latin America) es-MX es-419 No
German de-DE de-DE Yes
French fr-FR fr-FR Yes
Italian it it-IT No
Portuguese (Brazil) pt-BR pt-BR Yes
Japanese ja ja-JP No
Korean ko ko-KR No
Dutch nl-NL nl-NL Yes
Swedish sv sv-SE No

Five of twelve differ. There is no rule you can apply: Apple uses a bare language code for Italian, Japanese, Korean and Swedish, but a full language-region code for German, French and Dutch. You cannot derive one store's code from the other's. You look it up.

Important scope note. These twelve are the languages AppSubmit supports, not the languages the stores support. App Store Connect accepts roughly 40 localisations for an app listing and Google Play accepts roughly 80. If your language is not in the table above, the pattern still applies but you need the store's own list, and Apple's bare-code exceptions extend beyond these four.

Why es-MX and es-419 are the interesting pair

es-419 is not a typo and it is not a country. 419 is the UN M.49 region code for Latin America and the Caribbean, so es-419 means "Spanish, Latin American variant" without naming a country. It is the correct BCP 47 way to express the thing.

Apple expresses the same idea as es-MX, Spanish as spoken in Mexico, and uses it as the de facto Latin American Spanish listing. So the two stores disagree not just on syntax but on what the locale is: one is a region-neutral variant, the other is a specific country standing in for a region.

The practical consequence is that this is the one pair you cannot fix with string surgery. Stripping or appending a region gets you from it to it-IT. Nothing gets you from es-MX to es-419 except a lookup table.

What actually breaks

The loud failure. Send it-IT to the App Store Connect API and the request is rejected: the locale is not a recognised value for a version localisation, and the whole metadata push fails with it. Send ja to the Play Developer API and the listing update is rejected the same way. Neither store silently accepts a code it does not know.

That failure is annoying and harmless. You see it, you fix the code, you push again.

The quiet failure is the expensive one. Your codes are all valid, your push succeeds, and the copy lands in a locale nobody in your target market sees.

This happens when tooling assumes en-US is the default. It very often is not. Apple has a primaryLocale on the app and Play has a defaultLanguage on the listing, and either can be en-GB, de-DE or anything else. If a German developer's Play listing defaults to de-DE and your update writes to en-US, everything reports success and the listing that most shoppers load is untouched.

The fix is an explicit fallback order, in this order:

  1. The store's own declared default (Apple primaryLocale, Play defaultLanguage).
  2. Then en-US.
  3. Then any locale starting with en.
  4. Then whatever exists at all.

Hardcoding en-US first is the bug. It is a bug that produces no error message, which is why it survives for months.

Locale codes are not country codes

Two different axes, frequently conflated:

  • Locale controls the language of your listing text: name, subtitle or short description, description, screenshots, release notes.
  • Territory or country controls availability and price: where the app can be bought, at what price, in which storefront it appears.

They use different vocabularies. Territories are two-letter country codes (us, gb, de, jp, br), and the App Store additionally has numeric storefront IDs for some of its search endpoints. Your app can be on sale in 175 territories with two localisations, or in one territory with nine.

Getting this wrong tends to produce the question "why is my Japanese listing not showing in Japan", where the answer is that the listing is localised but the app is not available in the jp territory, or vice versa.

Practical rules for storing and syncing them

Store each store's own code, natively. The temptation is to normalise everything to BCP 47 internally and translate on the way out. It works until you need to reconcile what Apple currently holds against what you think it holds, at which point you are translating in both directions and one of them is lossy. Keep Apple's ja on Apple's rows and Play's ja-JP on Play's rows, and map only at the point where a human picks a language.

Map at the language, not the code. The unit that means something to a user is "Japanese". The codes are two spellings of it. A small table with a label, an Apple code and a Play code is enough, and it is the only place the mismatch has to be known.

Never lowercase or normalise case. en-US is not en-us to either API. This bites when locale codes pass through a URL slug, a filename or a database column with a case-insensitive collation.

Do not assume a language exists on both stores. Play's roughly 80 languages include several Apple does not offer, and there are Apple localisations without a clean Play equivalent. A cross-store tool has to be able to say "this language is Play-only" rather than inventing a code.

AppSubmit stores each store's own locale code on the listing row for exactly this reason, and picks the store's declared default rather than assuming en-US. If you are doing it yourself, the twelve-row table above plus the fallback order is the whole trick.

Last reviewed 2026-08-17. Apple and Google change their rules without notice, so check anything decision-critical against their live documentation.