Skip to content

Address part order follows the reader's locale because nothing carries the address's own country #4738

Description

@yinlianghui

Observation recorded while implementing #4028 (PR: claude/issue-4028-addressfield-locale-remainder). Not a regression — #4028 is a strict improvement over the hardcoded US order — this records the limit that fix had to accept, so the next reader re-judges it instead of inheriting it.

What #4028 does

formatAddress(addr, locale) now orders the parts by the reader's display locale (useDisplayLocale()): zh / ja / ko read largest-first, every other locale keeps the small-to-large order. Both callers — AddressField's readonly branch and AddressCellRenderer — pass the same locale, so the two surfaces objectui#4037 unified stay in step.

The limit

An address format is a property of where the mail goes, not of who is reading. A zh console showing a US customer's address renders it largest-first; a US console showing a Chinese address renders it street-first. Both are wrong for the address and right for the reader, and a CRM is exactly where cross-border addresses are normal.

Why the better channel was not taken in #4028

AddressValue (from @objectstack/spec/data) carries countryCode, which would be the correct, unambiguous input for a per-country rule. Measured on main today: AddressField exposes no countryCode input and never writes one — it renders five boxes (street / city / state / postalCode / country) and handleFieldChange only preserves whatever countryCode a producer already stored. So on data this widget produces, that channel is empty, and an address-driven rule would have had nothing to read for the majority of records. The remaining alternative — matching the free-text country string ("中国" / "China" / "PRC" / "美国") — is a name-guessing table with no source of truth behind it.

What a fix would need

  1. A channel that actually carries the country: either a countryCode input/derivation in AddressField, or a producer-side guarantee that stored addresses carry it.
  2. A per-country order rule (CLDR / libaddressinput-shaped) replacing the current language-subtag set in packages/fields/src/widgets/address-format.ts, with the reader's locale kept only as the fallback for an address that states no country.

Note (2) also covers a second real case the current two-profile rule does not: de / fr / es write the postal code before the city ("10115 Berlin"), which today renders as a separate comma group.

The pin that must move if this is taken: orders a US address by the READER, not by the address — the stated limit in packages/fields/src/widgets/__tests__/AddressField.i18n.test.tsx. It was written to make this decision visible rather than silent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions