@shotlingo/locale-fallback
v0.1.0
Published
Resolve any BCP-47 locale tag to the nearest one App Store Connect or Google Play Console actually supports, with the full fallback chain. Zero dependencies, no network calls.
Maintainers
Readme
@shotlingo/locale-fallback
Resolve any BCP-47 locale tag to the nearest one App Store Connect or Google Play Console actually supports, with the full fallback chain. Zero dependencies, no network calls.
Locale ↔ locale code mapping (no fallback logic): @shotlingo/locale-codes Full interactive reference: shotlingo.com/tools/app-store-locale-codes
Why this matters
A device or OS can report a locale neither store lists as a metadata locale — es-AR, en-NZ, pt-AO, or Google Play's own legacy subtags iw/in for Hebrew/Indonesian. Upload that tag as-is, or key a screenshot set on it directly, and you get nothing: no listing locale, no matching localized asset. This resolves it to a locale the store will actually accept, and exposes the chain it fell back through so you can log or test what happened instead of guessing.
Install
npm install @shotlingo/locale-fallbackUsage
import { resolveLocale, fallbackChain, supportedLocales, isSupportedLocale } from '@shotlingo/locale-fallback';
resolveLocale('en-NZ', 'appStore');
// => 'en-US' (not a listing locale; falls back to base language)
resolveLocale('iw-IL', 'appStore');
// => 'he' (Play's own legacy Hebrew subtag, normalized before matching)
resolveLocale('zh-Hant-HK', 'appStore');
// => 'zh-Hant' (language+script truncation, not the first zh-* entry)
fallbackChain('es-AR', 'appStore');
// => ['es-ES', 'en-US'] — what it tried, in order
isSupportedLocale('en-NZ', 'appStore');
// => false — exact match only, no fallback applied
supportedLocales('play').length;
// => 40API
resolveLocale(requested: string, store: 'appStore' | 'play'): string— the single best-matching locale code.fallbackChain(requested: string, store): string[]— every code tried, in order, deduplicated.[0]is whatresolveLocalereturns.supportedLocales(store): string[]— every locale code this table lists for that store.isSupportedLocale(requested: string, store): boolean— exact match only (case-insensitive), no fallback.LOCALES: LocaleEntry[]— the underlying 40-language table ({ language, appStoreCode, googlePlayCode }).DEFAULT_LOCALE: Record<Store, string>—{ appStore: 'en-US', play: 'en-US' }, the last resort in every chain.
Lookup order: exact match on the tag as given → exact match after normalizing legacy subtags (iw→he, in→id) → the normalized tag truncated to language+script/region → base language only → the store default. This is a language-level lookup, not a full RFC 4647 algorithm with script/region weighting — for the 40 languages this table covers, that's the difference that actually changes which screenshot set or listing locale gets picked.
License
MIT
