Skip to content

Resolve consumer locales against shipped translation bundles #490

@jkmassel

Description

@jkmassel

Summary

Consumers currently pass locale to EditorConfiguration as an opaque string, and src/utils/localization.js does a single-level dynamic import. If the tag doesn't match a shipped translations/*.json exactly, the editor silently falls back to English. The supported-locales list lives in bin/prep-translations.js; consumers don't see it, and have no way to ask "what's the closest bundle you actually ship?". This means each client has to mirror that table to do the right thing — and historically hasn't.

Concretely on WP-Android (today): PerAppLocaleManager.getCurrentLocaleLanguageCode() returns Locale.getLanguage() — ISO 639-1 only — so a Brazilian user sends pt (matches), a Chinese user sends zh (no zh-cn/zh-tw match → English), and a user who picked en_GB / nl_BE / pt_BR in the language picker loses their region variant before we ever reach GutenbergKit.

Proposed shape

Move locale resolution into the library so every client gets correct behaviour without re-implementing the table:

1. Platform-native setLocale overloads

// Android
setLocale(locale: Locale)      // new — resolves internally
setLocale(locale: String)      // existing — power-user / tests
// iOS
func setLocale(_ locale: Locale)        // new
func setLocale(_ identifier: String)    // existing

The new overloads call toLanguageTag().lowercased() (or Locale.identifier on iOS) and run the resolution chain before storing the string for serialization. The wire format stays unchanged — only the consumer-facing API gains type safety.

2. Resolution chain

For an input tag xx-yy:

  1. Full tag (xx-yy) — match if shipped
  2. Language-only tag (xx) — match if shipped
  3. Fall back to en

Determined at runtime against the actually-bundled translation files, not a hard-coded list — that way the resolver stays correct when SUPPORTED_LOCALES in bin/prep-translations.js changes without anyone remembering to update a duplicate.

3. JS-side fallback becomes defensive

localization.js's catch-and-warn stays as a defense-in-depth net but should rarely fire in practice once the Android/iOS resolver narrows to a known-shipped tag.

Out of scope

  • Changing the SUPPORTED_LOCALES list itself.
  • Changing the wire format of EditorConfiguration.locale.
  • Pluralization / RTL handling — separate concerns.

Why this matters

Two clients today (WP-Android, WP-iOS) and a third on the way (the GutenbergKit preloader being added in WP-Android #22579, where every preloaded session has to remember to overlay the locale or it ships English regardless of device language). One resolver in the library closes all three at once and any future client by default.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions