@@ -1376,29 +1376,44 @@ describe('translatePage', () => {
13761376 // doc already says. One component, one address — `title` and `subtitle`
13771377 // now follow the same rule."
13781378 //
1379- // This test previously asserted the OPPOSITE (`title` resolving to
1380- // `快速新建`, the id route beating the page-name one). It is inverted, not
1381- // deleted, because the inversion IS the behaviour change the ruling
1382- // records: the id route was live for this component and preferred, and a
1383- // bundle that used it now falls back to the page-name key.
1384- it ( 'reads a region-level `page:header` by page name only, id or no id (batch #58)' , ( ) => {
1385- const doc = {
1386- name : 'sales_home_page' ,
1387- regions : [ {
1388- name : 'header' ,
1389- // `properties` widened to the open bag it is: the overlay adds keys
1390- // the literal does not spell out, and inferring it as `{title}` alone
1391- // would make reading the result a type error.
1392- components : [ {
1393- type : 'page:header' ,
1394- id : 'quick_create' ,
1395- properties : { title : 'Sales Home' } as Record < string , string > ,
1396- } ] ,
1379+ // The ruling has two halves, and one bundle cannot measure both — so two
1380+ // pins. `homeBundle` carries `pages.sales_home_page.label`, and the
1381+ // page-name overlay is applied AFTER the id route and wins for `title`
1382+ // whether or not the id route was read: against that bundle the header's
1383+ // `title` reads `销售看板` on a resolver that still reads the id route.
1384+ // That is a real invariant (precedence when both routes are present) and
1385+ // the first pin names it as exactly that — it is NOT evidence that the id
1386+ // route is closed. The second pin hands the resolver an id-ONLY bundle —
1387+ // no `pages.<name>.label`, no `pages.<name>.title` — so the page-name
1388+ // overlay has nothing to win with and only the id route could move the
1389+ // title. Measured with the gate reverted to `if (addressed)`: the first
1390+ // pin stays green, the second goes red.
1391+ //
1392+ // A region-level `page:header` that carries an id. `properties` is
1393+ // widened to the open bag it is: the overlay adds keys the literal does
1394+ // not spell out, and inferring it as `{title}` alone would make reading
1395+ // the result a type error.
1396+ const regionHeaderWithId = ( ) => ( {
1397+ name : 'sales_home_page' ,
1398+ regions : [ {
1399+ name : 'header' ,
1400+ components : [ {
1401+ type : 'page:header' ,
1402+ id : 'quick_create' ,
1403+ properties : { title : 'Sales Home' } as Record < string , string > ,
13971404 } ] ,
1398- } ;
1399- const out = translatePage ( doc , homeBundle , { locale : 'zh-CN' } ) ;
1400- // `components.quick_create.title` (`快速新建`) is NOT read here — the
1401- // page-name route is, falling back to `pages.<name>.label` for `title`.
1405+ } ] ,
1406+ } ) ;
1407+
1408+ // Previously this asserted the OPPOSITE (`title` resolving to `快速新建`,
1409+ // the id route beating the page-name one). Inverted, not deleted, because
1410+ // the inversion IS the behaviour change the ruling records: the id route
1411+ // was live for this component and preferred, and a bundle that used it
1412+ // now falls back to the page-name key.
1413+ it ( 'prefers the page-name route over the id route for a region-level `page:header` when a bundle carries both (batch #58)' , ( ) => {
1414+ const out = translatePage ( regionHeaderWithId ( ) , homeBundle , { locale : 'zh-CN' } ) ;
1415+ // `components.quick_create.title` (`快速新建`) does not win here — the
1416+ // page-name route does, falling back to `pages.<name>.label` for `title`.
14021417 expect ( out . regions [ 0 ] . components [ 0 ] . properties . title ) . toBe ( '销售看板' ) ;
14031418 expect ( out . regions [ 0 ] . components [ 0 ] . properties . subtitle ) . toBe ( '欢迎回来' ) ;
14041419 // Control: the very same bundle entry still reaches the component that
@@ -1408,6 +1423,40 @@ describe('translatePage', () => {
14081423 . properties . title ) . toBe ( '快速新建' ) ;
14091424 } ) ;
14101425
1426+ it ( 'does not read the id route for a region-level `page:header` — an id-only bundle leaves its authored title alone (batch #58)' , ( ) => {
1427+ // No `pages.<name>.label` / `title` / `subtitle`: the page-name route
1428+ // resolves nothing for this page, so a translated title on the header
1429+ // could only have come from `components.quick_create.title`.
1430+ const idOnly : TranslationBundle = {
1431+ 'zh-CN' : { pages : { sales_home_page : { components : { quick_create : { title : '快速新建' } } } } } ,
1432+ } ;
1433+ const out = translatePage ( regionHeaderWithId ( ) , idOnly , { locale : 'zh-CN' } ) ;
1434+ expect ( out . regions [ 0 ] . components [ 0 ] . properties . title ) . toBe ( 'Sales Home' ) ;
1435+ // Control 1: the same id-only bundle DOES translate the component that
1436+ // owns the id, so the authored title above is the header's id route
1437+ // being closed and not a bundle nothing can resolve.
1438+ expect ( byId ( translatePage ( homePage ( ) , idOnly , { locale : 'zh-CN' } ) , 'quick_create' )
1439+ . properties . title ) . toBe ( '快速新建' ) ;
1440+ // Control 2: a `page:header` NESTED in a container stays id-addressed —
1441+ // the ruling closes the id route at region level only, and the id route
1442+ // is the only one that reaches a nested header.
1443+ const nestedDoc = {
1444+ name : 'sales_home_page' ,
1445+ regions : [ {
1446+ name : 'main' ,
1447+ components : [ {
1448+ type : 'page:card' ,
1449+ id : 'wrapper' ,
1450+ properties : {
1451+ children : [ { type : 'page:header' , id : 'quick_create' , properties : { title : 'Sales Home' } as Record < string , string > } ] ,
1452+ } ,
1453+ } ] ,
1454+ } ] ,
1455+ } ;
1456+ const nested = translatePage ( nestedDoc , idOnly , { locale : 'zh-CN' } ) ;
1457+ expect ( ( nested . regions [ 0 ] . components [ 0 ] . properties . children as any [ ] ) [ 0 ] . properties . title ) . toBe ( '快速新建' ) ;
1458+ } ) ;
1459+
14111460 it ( 'does not mutate the input page' , ( ) => {
14121461 const doc = homePage ( ) ;
14131462 const snapshot = JSON . parse ( JSON . stringify ( doc ) ) ;
0 commit comments