@@ -23,6 +23,7 @@ import {
2323 type SettingsLiveStatus ,
2424 type SettingsLiveStatusProvider ,
2525 type SettingsWritePredicate ,
26+ type SettingsDisplayOptions ,
2627 SETTINGS_LIVE_STATUS_BANNER_ID ,
2728 type SettingsAuditSink ,
2829 type SettingsContext ,
@@ -1619,6 +1620,7 @@ export class SettingsService {
16191620 async liveStatusOf (
16201621 namespace : string ,
16211622 ctx : SettingsContext = { } ,
1623+ display : SettingsDisplayOptions = { } ,
16221624 ) : Promise < SettingsManifest [ 'specifiers' ] [ number ] | undefined > {
16231625 const provider = this . liveStatusProviders . get ( namespace ) ;
16241626 if ( ! provider ) return undefined ;
@@ -1628,6 +1630,7 @@ export class SettingsService {
16281630 namespace,
16291631 ctx,
16301632 organizationId : async ( ) => organizationReachRowOwner ( await this . organizationReachOf ( ctx ) ) ,
1633+ locale : display . locale ,
16311634 } ) ;
16321635 } catch ( err : any ) {
16331636 this . logger ?. warn ?.(
@@ -2277,11 +2280,15 @@ export class SettingsService {
22772280 * naming each such key (`invalid_value`, `constraint: { scope: 'user' }`):
22782281 * the row it would store names no owner, and the user rung answers only its
22792282 * owner, so no reader would ever see it while the write reported success.
2283+ *
2284+ * `display` picks the language of a write predicate's refusal, and nothing
2285+ * else (see {@link refuseByWritePredicates}).
22802286 */
22812287 async setMany (
22822288 namespace : string ,
22832289 patch : Record < string , unknown > ,
22842290 ctx : SettingsContext = { } ,
2291+ display : SettingsDisplayOptions = { } ,
22852292 ) : Promise < Record < string , ResolvedSettingValue > > {
22862293 // The pre-bind window: refuse rather than resolve against a store nothing
22872294 // will ever read. See `assertEngineBound`.
@@ -2365,7 +2372,7 @@ export class SettingsService {
23652372 // may refuse a change the declarations above accept. After them, so a
23662373 // malformed value is told about its own fault first; before the crypto
23672374 // pass and every write, so a refused batch writes nothing.
2368- await this . refuseByWritePredicates ( reg , namespace , patch , ctx , reach ) ;
2375+ await this . refuseByWritePredicates ( reg , namespace , patch , ctx , reach , display ) ;
23692376
23702377 // #8026 — a declared-encrypted key with nothing able to encrypt it fails
23712378 // the WHOLE batch, here, rather than part-way down the write loop below.
@@ -2579,6 +2586,7 @@ export class SettingsService {
25792586 patch : Record < string , unknown > ,
25802587 ctx : SettingsContext ,
25812588 reach : OrganizationReach | undefined ,
2589+ display : SettingsDisplayOptions ,
25822590 ) : Promise < void > {
25832591 const byKey = this . writePredicates . get ( namespace ) ;
25842592 if ( ! byKey ) return ;
@@ -2591,7 +2599,7 @@ export class SettingsService {
25912599 if ( stableStringify ( next ) === stableStringify ( current ) ) continue ;
25922600 const scope = reg . scopes . get ( key ) ! ;
25932601 const organizationId = scope === 'global' || ! reach ? undefined : organizationReachRowOwner ( reach ) ?? null ;
2594- const refusal = await predicate ( { namespace, key, next, current, organizationId, ctx } ) ;
2602+ const refusal = await predicate ( { namespace, key, next, current, organizationId, ctx, locale : display . locale } ) ;
25952603 if ( ! refusal ) continue ;
25962604 const spec = ( ( reg . manifest . specifiers ?? [ ] ) as Array < Record < string , unknown > > )
25972605 . find ( ( s ) => s . key === key ) ;
0 commit comments