Skip to content

Managing 80+ Google Play locales from the terminal

Google Play supports more than 80 store-listing locales — from af (Afrikaans) to zu (Zulu), including regional variants like es-419 (Latin American Spanish), pt-BR (Brazilian Portuguese), and zh-TW (Traditional Chinese). Setting them all up in the Play Console web UI means clicking through a language dropdown once per locale, per app, and re-doing it for every listing change.

gplay turns that into a scriptable batch job. Here’s the full toolkit.

Terminal window
gplay listings locales

Returns the full list Google Play accepts, as JSON:

[
{ "code": "af", "name": "Afrikaans" },
{ "code": "am", "name": "Amharic" },
{ "code": "ar", "name": "Arabic" },
{ "code": "az-AZ", "name": "Azerbaijani" },
...
{ "code": "zh-TW", "name": "Chinese (Traditional)" },
{ "code": "zu", "name": "Zulu" }
]

Or as a table:

Terminal window
gplay listings locales --output table

Validate a code before you use it (avoid typos wasting a Play API round-trip):

Terminal window
gplay listings locales --validate ar-XB
# → error: unknown locale 'ar-XB'. Did you mean 'ar'?

Which locales does your app currently have listings for?

Terminal window
gplay listings list --package com.example.app --output table

Diff against the full supported set to find gaps:

Terminal window
CURRENT=$(gplay listings list --package com.example.app | jq -r '.[].language' | sort)
SUPPORTED=$(gplay listings locales | jq -r '.[].code' | sort)
comm -23 <(echo "$SUPPORTED") <(echo "$CURRENT")

That tells you exactly which of the 80+ locales you’re missing.

Terminal window
gplay listings get \
--package com.example.app \
--locale de-DE

Returns title, short description, full description, video URL. Perfect for pulling translations into a review tool.

The --listings-dir flag reads Fastlane-format metadata:

metadata/
├── en-US/
│ ├── title.txt
│ ├── short_description.txt
│ ├── full_description.txt
│ └── changelogs/default.txt
├── fr-FR/
│ └── ...
├── de-DE/
├── es-ES/
├── ja-JP/
├── ko/
├── pt-BR/
└── zh-TW/

Push them all in one shot:

Terminal window
gplay listings push \
--package com.example.app \
--listings-dir ./metadata

Every locale that has a directory gets its listing created or updated inside a single edit session — atomic commit.

--dry-run intercepts the write and shows you the payload:

Terminal window
gplay listings push \
--package com.example.app \
--listings-dir ./metadata \
--dry-run

You see exactly what will be sent to Google, per locale, without touching production.

Release notes shipped alongside a track update. YAML format:

release-notes.yaml
en-US: "New Pro features and bug fixes"
en-GB: "New Pro features and bug fixes"
fr-FR: "Nouvelles fonctionnalités Pro et corrections de bugs"
de-DE: "Neue Pro-Funktionen und Fehlerbehebungen"
es-ES: "Nuevas funciones Pro y correcciones de errores"
es-419: "Nuevas funciones Pro y correcciones de errores"
pt-BR: "Novas funcionalidades Pro e correções de bugs"
ja-JP: "新しいProの機能とバグ修正"
ko: "새로운 Pro 기능 및 버그 수정"
zh-TW: "新 Pro 功能與錯誤修正"
zh-CN: "新 Pro 功能与错误修复"
ar: "ميزات Pro الجديدة وإصلاحات الأخطاء"

Apply on release:

Terminal window
gplay release \
--package com.example.app \
--track internal \
--bundle app-release.aab \
--release-notes-file release-notes.yaml

Or generate the whole file from git history in your default locale, then translate:

Terminal window
gplay release-notes generate --since v4.1.0 --output release-notes.yaml

If you pass a plain string as --release-notes, gplay auto-assigns it to en-US. Explicit is better — but this shortcut is handy for internal builds.

Google will reject a release if:

  • Any locale has an empty title.
  • Full description exceeds 4,000 characters.
  • Short description exceeds 80 characters.
  • A locale exists in your listings but not in the supported set (typo, stale data).

Preflight:

Terminal window
gplay listings validate \
--package com.example.app \
--listings-dir ./metadata

Combine gplay with your AI agent for the tedious parts. Prompt:

Pull the en-US listing and full description for com.example.app. Translate the short and full descriptions into French, German, Spanish (both es-ES and es-419), Portuguese (both pt-BR and pt-PT), Japanese, Korean, Chinese (both zh-CN and zh-TW), and Arabic. Preserve technical terms (product names, feature names). Write each to metadata/<locale>/short_description.txt and full_description.txt. When done, dry-run gplay listings push so I can review.

Chains: gplay listings get --locale en-US → LLM translations to files → gplay listings push --dry-run. You review, then run without --dry-run.

Every one of the 12 supported agents — Claude Code, Cursor, Codex, Gemini CLI, Aider, Cline, Windsurf, Continue, GitHub Copilot CLI, Amazon Q Developer, OpenClaw, Hermes Agent — can do this. Install the metadata-sync skill and they’ll know the file layout by default.

Localized listings often need localized screenshots (screenshots with translated in-image text). gplay listings push --screenshots-dir reads the same Fastlane-format tree:

screenshots/
├── en-US/
│ └── phoneScreenshots/
│ ├── 1.png
│ ├── 2.png
│ └── ...
├── fr-FR/
│ └── phoneScreenshots/
│ └── ...

Or use --skip-screenshots if you only want to update text.

Terminal window
brew install tamtom/tap/gplay
gplay setup --auto
gplay listings locales --output table
gplay listings list --package com.example.app --output table

Full listings reference at /reference/listings/. If you’re maintaining a large locale matrix, install the metadata-sync skill and let your AI agent drive the day-to-day translation-review-push cycle.