skills/gplay-subscription-localization/SKILL.md
Bulk-localize subscription display names, descriptions, and offer tags across all Google Play locales using gplay. Use when you want to fill in subscription metadata for every language without clicking through Play Console manually.
npx skillsauth add tamtom/gplay-cli-skills gplay-subscription-localizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill to bulk-create or bulk-update localized display names, descriptions, and benefits for subscriptions across all Google Play supported locales. This eliminates the tedious manual process of editing each language in Play Console.
gplay auth login or GPLAY_SERVICE_ACCOUNT env var).--package or GPLAY_PACKAGE).gplay subscriptions create first).These are the locales supported by Google Play for subscription listings:
af, am, ar, hy-AM, az-AZ, eu-ES, be, bn-BD, bg, my-MM, ca,
zh-HK, zh-CN, zh-TW, hr, cs-CZ, da-DK, nl-NL, en-AU, en-CA,
en-GB, en-IN, en-SG, en-US, en-ZA, et, fil, fi-FI, fr-CA,
fr-FR, gl-ES, ka-GE, de-DE, el-GR, gu, he-IL, hi-IN, hu-HU,
is-IS, id, it-IT, ja-JP, kn-IN, kk, km-KH, ko-KR, ky-KG,
lo-LA, lv, lt, mk-MK, ms, ms-MY, ml-IN, mr-IN, mn-MN, ne-NP,
no-NO, fa, pl-PL, pt-BR, pt-PT, pa, ro, rm, ru-RU, sr, si-LK,
sk, sl, es-419, es-ES, es-US, sw, sv-SE, ta-IN, te-IN, th,
tr-TR, uk, ur, vi, zu
Verify which locales your app already supports:
EDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id')
gplay listings list --package com.example.app --edit $EDIT_ID --output table
Google Play subscriptions have a hierarchical structure:
Listings are set at the subscription level and apply to all base plans under it.
gplay subscriptions list --package com.example.app --paginate --output table
gplay subscriptions get \
--package com.example.app \
--product-id premium_monthly \
--output json --pretty
The response includes a listings object keyed by locale:
{
"productId": "premium_monthly",
"listings": {
"en-US": {
"title": "Premium Monthly",
"benefits": ["Unlimited access", "No ads"],
"description": "Get premium access to all features"
}
}
}
Create a JSON file with listings for all target locales:
subscription-listings.json:
{
"listings": {
"en-US": {
"title": "Premium Monthly",
"benefits": ["Unlimited access", "No ads", "Priority support"],
"description": "Get premium access to all features every month."
},
"de-DE": {
"title": "Premium Monatlich",
"benefits": ["Unbegrenzter Zugang", "Keine Werbung", "Prioritäts-Support"],
"description": "Erhalten Sie jeden Monat Premium-Zugang zu allen Funktionen."
},
"fr-FR": {
"title": "Premium Mensuel",
"benefits": ["Accès illimité", "Sans publicité", "Support prioritaire"],
"description": "Accédez à toutes les fonctionnalités premium chaque mois."
},
"es-ES": {
"title": "Premium Mensual",
"benefits": ["Acceso ilimitado", "Sin anuncios", "Soporte prioritario"],
"description": "Obtén acceso premium a todas las funciones cada mes."
},
"ja-JP": {
"title": "プレミアム月額",
"benefits": ["無制限アクセス", "広告なし", "優先サポート"],
"description": "毎月すべての機能にプレミアムアクセスできます。"
},
"ko-KR": {
"title": "프리미엄 월간",
"benefits": ["무제한 액세스", "광고 없음", "우선 지원"],
"description": "매달 모든 기능에 프리미엄 액세스를 받으세요."
},
"pt-BR": {
"title": "Premium Mensal",
"benefits": ["Acesso ilimitado", "Sem anúncios", "Suporte prioritário"],
"description": "Tenha acesso premium a todos os recursos todos os meses."
},
"zh-CN": {
"title": "高级月度订阅",
"benefits": ["无限访问", "无广告", "优先支持"],
"description": "每月获得所有功能的高级访问权限。"
}
}
}
gplay subscriptions update \
--package com.example.app \
--product-id premium_monthly \
--json @subscription-listings.json \
--update-mask listings
The --update-mask listings ensures only the listings field is modified, leaving base plans and other configuration untouched.
gplay subscriptions get \
--package com.example.app \
--product-id premium_monthly \
--output json --pretty
Check that all locales appear in the listings object.
gplay subscriptions get \
--package com.example.app \
--product-id premium_monthly \
--output json --pretty > subscription-export.json
Use jq to isolate the listings:
jq '.listings' subscription-export.json > listings-to-translate.json
Send listings-to-translate.json to your translation service or team. The structure is simple key-value pairs per locale.
After receiving translations, build the update JSON:
jq -n --slurpfile translations translated-listings.json \
'{ listings: $translations[0] }' > subscription-update.json
gplay subscriptions update \
--package com.example.app \
--product-id premium_monthly \
--json @subscription-update.json \
--update-mask listings
#!/bin/bash
# bulk-localize-subscriptions.sh
PACKAGE="com.example.app"
LISTINGS_FILE="subscription-listings.json"
# Get all subscription product IDs
PRODUCT_IDS=$(gplay subscriptions list \
--package "$PACKAGE" \
--paginate | jq -r '.[].productId')
for PRODUCT_ID in $PRODUCT_IDS; do
echo "Updating listings for: $PRODUCT_ID"
gplay subscriptions update \
--package "$PACKAGE" \
--product-id "$PRODUCT_ID" \
--json "@$LISTINGS_FILE" \
--update-mask listings
echo "Done: $PRODUCT_ID"
done
echo "All subscriptions updated."
For subscriptions with different display names, use per-product JSON files:
for PRODUCT_ID in $PRODUCT_IDS; do
LISTINGS_FILE="listings/${PRODUCT_ID}.json"
if [ -f "$LISTINGS_FILE" ]; then
gplay subscriptions update \
--package "$PACKAGE" \
--product-id "$PRODUCT_ID" \
--json "@$LISTINGS_FILE" \
--update-mask listings
else
echo "Warning: No listings file for $PRODUCT_ID, skipping."
fi
done
When creating a new subscription with localized listings and base plans in one call:
gplay subscriptions create \
--package com.example.app \
--product-id premium_yearly \
--json @full-subscription.json
full-subscription.json:
{
"productId": "premium_yearly",
"listings": {
"en-US": {
"title": "Premium Yearly",
"benefits": ["Unlimited access", "No ads", "2 months free"],
"description": "Save with annual premium access."
},
"de-DE": {
"title": "Premium Jährlich",
"benefits": ["Unbegrenzter Zugang", "Keine Werbung", "2 Monate gratis"],
"description": "Sparen Sie mit jährlichem Premium-Zugang."
},
"fr-FR": {
"title": "Premium Annuel",
"benefits": ["Accès illimité", "Sans publicité", "2 mois offerts"],
"description": "Économisez avec l'accès premium annuel."
},
"ja-JP": {
"title": "プレミアム年間",
"benefits": ["無制限アクセス", "広告なし", "2ヶ月無料"],
"description": "年間プレミアムアクセスでお得に。"
}
},
"basePlans": [
{
"basePlanId": "yearly",
"state": "ACTIVE",
"autoRenewingBasePlanType": {
"billingPeriodDuration": "P1Y",
"gracePeriodDuration": "P7D",
"resubscribeState": "RESUBSCRIBE_STATE_ACTIVE",
"prorationMode": "CHARGE_ON_NEXT_BILLING_DATE"
},
"regionalConfigs": [
{
"regionCode": "US",
"price": {
"currencyCode": "USD",
"units": "49",
"nanos": 990000000
}
}
]
}
]
}
Offers support localized offerTags which can be used for display in your app:
gplay offers update \
--package com.example.app \
--product-id premium_monthly \
--base-plan-id monthly \
--offer-id free_trial_7d \
--json @offer-update.json
offer-update.json:
{
"offerTags": [
{"tag": "free-trial"},
{"tag": "7-days"}
]
}
Note: Offer tags are not locale-specific in the Google Play API. They are developer-defined identifiers used for filtering in your app. Localize the user-facing text for offer tags in your app code, not in Play Console.
Check which locales your app already has store listings for:
EDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id')
gplay listings list --package com.example.app --edit $EDIT_ID --output table
This lists all locales with store listings. Your subscription listings should cover at least these same locales.
To see the full list of locales a specific listing supports:
gplay listings list --package com.example.app --edit $EDIT_ID \
| jq -r '.[].language'
Copy and customize this template for quick localization:
{
"listings": {
"en-US": { "title": "TITLE_EN", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_EN" },
"de-DE": { "title": "TITLE_DE", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_DE" },
"fr-FR": { "title": "TITLE_FR", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_FR" },
"es-ES": { "title": "TITLE_ES", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_ES" },
"it-IT": { "title": "TITLE_IT", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_IT" },
"ja-JP": { "title": "TITLE_JA", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_JA" },
"ko-KR": { "title": "TITLE_KO", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_KO" },
"pt-BR": { "title": "TITLE_PT_BR", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_PT_BR" },
"ru-RU": { "title": "TITLE_RU", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_RU" },
"zh-CN": { "title": "TITLE_ZH_CN", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_ZH_CN" },
"zh-TW": { "title": "TITLE_ZH_TW", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_ZH_TW" },
"ar": { "title": "TITLE_AR", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_AR" },
"hi-IN": { "title": "TITLE_HI", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_HI" },
"tr-TR": { "title": "TITLE_TR", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_TR" },
"pl-PL": { "title": "TITLE_PL", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_PL" },
"nl-NL": { "title": "TITLE_NL", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_NL" },
"sv-SE": { "title": "TITLE_SV", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_SV" },
"th": { "title": "TITLE_TH", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_TH" },
"vi": { "title": "TITLE_VI", "benefits": ["BENEFIT_1", "BENEFIT_2"], "description": "DESC_VI" }
}
}
--update-mask listings when updating only localized metadata to avoid overwriting base plans or pricing.--output table for verification steps so the user can visually confirm.--help before running commands.update call sets all locales at once.--update-mask flag is critical: without it, an update call may overwrite base plans and pricing.--paginate on list commands to ensure all subscriptions are returned.--pretty when inspecting JSON output for human readability.--help to verify flags for the exact command.development
App vitals monitoring for crashes, ANRs, performance metrics, and errors via gplay vitals commands. Use when asked to check app stability, crash rates, ANR rates, or performance data from Google Play Console.
development
User and grant management for Google Play Console via gplay users and gplay grants commands. Use when asked to manage developer account users, permissions, or app-level access grants.
development
Beta testing groups and tester management for Google Play closed testing tracks. Use when managing testers and beta groups.
development
Pre-submission validation for Google Play releases covering metadata, screenshots, bundle integrity, data safety, and policy compliance. Use when preparing a release to avoid rejections and catch issues before submitting.