|
| 1 | +--- |
| 2 | +"@objectstack/spec": patch |
| 3 | +--- |
| 4 | + |
| 5 | +docs(spec,i18n): `GET /i18n/locales` stops declaring `label` a display name |
| 6 | + |
| 7 | +`GetLocalesResponseSchema` described each locale descriptor's `label` as |
| 8 | +"Display name of the locale", and no producer has ever written one. The sole |
| 9 | +producer is `toLocaleDescriptors` (`system/i18n-resolver.ts`) — deliberately |
| 10 | +shared by the runtime dispatcher's `/i18n` domain and `service-i18n`'s |
| 11 | +autonomous route, so there is no second implementation to diverge — and it sets |
| 12 | +`label` to the code. `GET /api/v1/i18n/locales` answers `{ code: 'th', label: |
| 13 | +'th' }`, never `{ code: 'th', label: 'ไทย' }`. Declared not enforced (ADR-0049), |
| 14 | +one field wide, and the describe is what carries the claim into the generated |
| 15 | +JSON Schema, the OpenAPI surface and the SDK type — so a client that trusts it |
| 16 | +renders locale codes at users and only finds out by looking. objectui#4039 hit |
| 17 | +exactly that and routed around the field: the console's language menu reads |
| 18 | +`code` alone off this body and names locales from its own built-in table plus |
| 19 | +`Intl.DisplayNames`. |
| 20 | + |
| 21 | +Patch, and describe-only. The measurement behind that: **no consumer anywhere |
| 22 | +reads `label`**. In this repo every read of the body takes `code` or |
| 23 | +`isDefault` (`http-dispatcher.test.ts`, `domain-handler-registry.test.ts`, |
| 24 | +`i18n-success-envelope.conformance.test.ts`); the one wire fixture that spells |
| 25 | +`label` sets it to the code and asserts only the array length. In objectui the |
| 26 | +one real consumer, `apps/console/src/loadLocales.ts`, reads `entry?.code` and |
| 27 | +documents in its header that the descriptor's label is not a display name. With |
| 28 | +nothing consuming the field, the honest declaration is the whole fix: the |
| 29 | +runtime behaviour is unchanged, and only the field's documented meaning moves. |
| 30 | + |
| 31 | +So the declaration now states the convention it ships — `label` equals `code`; |
| 32 | +naming a locale for a UI is the client's job, where `Intl.DisplayNames` already |
| 33 | +lives and where the choice of *which* language to name it in belongs. The two |
| 34 | +alternatives are deliberately not taken here: serving real display names is a |
| 35 | +capability addition with no measured pull (CLDR data on the server for |
| 36 | +something every client can compute), and retiring the field is a heavier |
| 37 | +response-contract action. Both stay open on #7634. |
| 38 | + |
| 39 | +`toLocaleDescriptors`' output and the declaration are now pinned against each |
| 40 | +other in `i18n-resolver.test.ts`, on both sides — a producer that starts |
| 41 | +inventing display names and a describe that starts promising them each turn it |
| 42 | +red separately. |
0 commit comments