@softure-ai/blog 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +21 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/messages/en.d.ts +2 -0
  7. package/dist/messages/en.d.ts.map +1 -1
  8. package/dist/messages/en.js +2 -0
  9. package/dist/messages/en.js.map +1 -1
  10. package/dist/messages/index.d.ts +2 -0
  11. package/dist/messages/index.d.ts.map +1 -1
  12. package/dist/messages/pl.d.ts +2 -0
  13. package/dist/messages/pl.d.ts.map +1 -1
  14. package/dist/messages/pl.js +2 -0
  15. package/dist/messages/pl.js.map +1 -1
  16. package/dist/next/context.d.ts.map +1 -1
  17. package/dist/next/context.js +1 -0
  18. package/dist/next/context.js.map +1 -1
  19. package/dist/next/discovery.js +2 -2
  20. package/dist/next/discovery.js.map +1 -1
  21. package/dist/next/json-ld.d.ts.map +1 -1
  22. package/dist/next/json-ld.js +11 -3
  23. package/dist/next/json-ld.js.map +1 -1
  24. package/dist/next/metadata.d.ts +1 -1
  25. package/dist/next/metadata.d.ts.map +1 -1
  26. package/dist/next/metadata.js +8 -6
  27. package/dist/next/metadata.js.map +1 -1
  28. package/dist/next/pages.js +1 -1
  29. package/dist/next/pages.js.map +1 -1
  30. package/dist/options.d.ts +30 -0
  31. package/dist/options.d.ts.map +1 -1
  32. package/dist/options.js +35 -0
  33. package/dist/options.js.map +1 -1
  34. package/dist/pages/index.d.ts +2 -2
  35. package/dist/pages/index.d.ts.map +1 -1
  36. package/dist/pages/index.js +2 -2
  37. package/dist/pages/index.js.map +1 -1
  38. package/dist/pages/json-ld.d.ts +11 -0
  39. package/dist/pages/json-ld.d.ts.map +1 -1
  40. package/dist/pages/json-ld.js +14 -7
  41. package/dist/pages/json-ld.js.map +1 -1
  42. package/dist/pages/listing.d.ts +9 -3
  43. package/dist/pages/listing.d.ts.map +1 -1
  44. package/dist/pages/listing.js +7 -5
  45. package/dist/pages/listing.js.map +1 -1
  46. package/dist/server/index.d.ts +1 -1
  47. package/dist/server/index.d.ts.map +1 -1
  48. package/dist/server/index.js +1 -1
  49. package/dist/server/index.js.map +1 -1
  50. package/dist/server/options.d.ts +9 -1
  51. package/dist/server/options.d.ts.map +1 -1
  52. package/dist/server/options.js +6 -0
  53. package/dist/server/options.js.map +1 -1
  54. package/dist/ui/blog-listing.js +2 -2
  55. package/dist/ui/blog-listing.js.map +1 -1
  56. package/dist/ui/page-context.d.ts +2 -0
  57. package/dist/ui/page-context.d.ts.map +1 -1
  58. package/module.json +1 -1
  59. package/package.json +1 -1
  60. package/src/index.ts +1 -1
  61. package/src/messages/en.ts +2 -0
  62. package/src/messages/pl.ts +2 -0
  63. package/src/next/context.ts +1 -0
  64. package/src/next/discovery.ts +2 -2
  65. package/src/next/json-ld.ts +11 -3
  66. package/src/next/metadata.ts +9 -7
  67. package/src/next/pages.tsx +1 -1
  68. package/src/options.ts +42 -0
  69. package/src/pages/index.ts +3 -1
  70. package/src/pages/json-ld.ts +29 -8
  71. package/src/pages/listing.ts +18 -5
  72. package/src/server/index.ts +1 -1
  73. package/src/server/options.ts +14 -1
  74. package/src/ui/blog-listing.tsx +2 -2
  75. package/src/ui/page-context.ts +2 -0
@@ -1,7 +1,7 @@
1
1
  export { findArticlesLinkingTerm, renderPageBody, type RenderPageBodyOptions } from "./body.js";
2
2
  export { formatDay, getArticleDates, getDayInZone, type ArticleDates } from "./dates.js";
3
- export { getArticleImageUrl, getArticleJsonLd, getGlossaryJsonLd, getTermJsonLd, serializeJsonLd, type JsonLdContext } from "./json-ld.js";
4
- export { getArticleCrumbs, getClusterAnchor, getClusterLabel, getTermCrumbs, groupByCluster, sortTerms, splitClusterLead, type ClusterGroup, type Crumb, type CrumbLabels, } from "./listing.js";
3
+ export { DEFAULT_JSON_LD_IDS, getArticleImageUrl, getArticleJsonLd, getGlossaryJsonLd, getTermJsonLd, serializeJsonLd, type JsonLdContext, type JsonLdIds } from "./json-ld.js";
4
+ export { DEFAULT_CLUSTER_ANCHOR_PREFIX, getArticleCrumbs, getClusterAnchor, getClusterLabel, getTermCrumbs, groupByCluster, sortTerms, splitClusterLead, type ArticleCrumbOptions, type ClusterGroup, type Crumb, type CrumbLabels, } from "./listing.js";
5
5
  export { getArticlePath, getReservedSlugs, getTermPath, getTextPath, matchBlogPath, normalizeRoute, type BlogPathKind, type BlogPathMatch, type BlogRoutes, } from "./paths.js";
6
6
  export { buildGonePage, createCachedBlogPathDecider, decideBlogPath, type BlogPathDecision, type BlogPathLookup, type CachedDeciderOptions, type GonePageCopy, type GonePageLink, type GonePageOptions, type GonePageRenderInput, } from "./redirects.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3I,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAChL,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC"}
@@ -2,8 +2,8 @@
2
2
  // 301/410 decisions. The components (`../ui/`) and the Next adapter (`../next/`) render what it returns.
3
3
  export { findArticlesLinkingTerm, renderPageBody } from "./body.js";
4
4
  export { formatDay, getArticleDates, getDayInZone } from "./dates.js";
5
- export { getArticleImageUrl, getArticleJsonLd, getGlossaryJsonLd, getTermJsonLd, serializeJsonLd } from "./json-ld.js";
6
- export { getArticleCrumbs, getClusterAnchor, getClusterLabel, getTermCrumbs, groupByCluster, sortTerms, splitClusterLead, } from "./listing.js";
5
+ export { DEFAULT_JSON_LD_IDS, getArticleImageUrl, getArticleJsonLd, getGlossaryJsonLd, getTermJsonLd, serializeJsonLd } from "./json-ld.js";
6
+ export { DEFAULT_CLUSTER_ANCHOR_PREFIX, getArticleCrumbs, getClusterAnchor, getClusterLabel, getTermCrumbs, groupByCluster, sortTerms, splitClusterLead, } from "./listing.js";
7
7
  export { getArticlePath, getReservedSlugs, getTermPath, getTextPath, matchBlogPath, normalizeRoute, } from "./paths.js";
8
8
  export { buildGonePage, createCachedBlogPathDecider, decideBlogPath, } from "./redirects.js";
9
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,yGAAyG;AACzG,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAA8B,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAqB,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAsB,MAAM,cAAc,CAAC;AAC3I,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,cAAc,EACd,SAAS,EACT,gBAAgB,GAIjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,GAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,cAAc,GAQf,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,yGAAyG;AACzG,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAA8B,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAqB,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAsC,MAAM,cAAc,CAAC;AAChL,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,cAAc,EACd,SAAS,EACT,gBAAgB,GAKjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,GAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,cAAc,GAQf,MAAM,gBAAgB,CAAC"}
@@ -7,10 +7,21 @@ export interface JsonLdContext {
7
7
  readonly urls: SiteUrls;
8
8
  readonly routes: BlogRoutes;
9
9
  readonly locale: Locale;
10
+ /** The BCP-47 tag written as `inLanguage` (`getBlogLocaleTags`); `locale` when left out. */
11
+ readonly language?: string;
12
+ /** The `@id` fragments; `article`, `term` and `glossary` when left out. */
13
+ readonly ids?: JsonLdIds;
10
14
  readonly timezone: string;
11
15
  /** The brand as author and publisher; `null` leaves them out. */
12
16
  readonly brand: string | null;
13
17
  }
18
+ /** The fragments after `#` in the nodes' `@id`s. */
19
+ export interface JsonLdIds {
20
+ readonly article: string;
21
+ readonly term: string;
22
+ readonly glossary: string;
23
+ }
24
+ export declare const DEFAULT_JSON_LD_IDS: JsonLdIds;
14
25
  type JsonLd = Record<string, unknown>;
15
26
  /** JSON for a `<script type="application/ld+json">`: no text in it can close the tag. */
16
27
  export declare function serializeJsonLd(data: unknown): string;
@@ -1 +1 @@
1
- {"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/pages/json-ld.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAA+B,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC5B,mHAAmH;IACnH,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtC,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAErD;AAeD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG,MAAM,CAE1H;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CA4B3G;AAMD,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAkB5H;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAWlH"}
1
+ {"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/pages/json-ld.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAA+B,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC5B,mHAAmH;IACnH,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,oDAAoD;AACpD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,mBAAmB,EAAE,SAAsE,CAAC;AAEzG,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAUtC,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAErD;AAeD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG,MAAM,CAE1H;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CA4B3G;AAMD,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAkB5H;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAWlH"}
@@ -1,5 +1,12 @@
1
1
  import { getArticleDates } from "./dates.js";
2
2
  import { getArticlePath, getTermPath } from "./paths.js";
3
+ export const DEFAULT_JSON_LD_IDS = { article: "article", term: "term", glossary: "glossary" };
4
+ function getIds(ctx) {
5
+ return ctx.ids ?? DEFAULT_JSON_LD_IDS;
6
+ }
7
+ function getLanguage(ctx) {
8
+ return ctx.language ?? ctx.locale;
9
+ }
3
10
  /** JSON for a `<script type="application/ld+json">`: no text in it can close the tag. */
4
11
  export function serializeJsonLd(data) {
5
12
  return JSON.stringify(data).replace(/</g, "\\u003c");
@@ -34,12 +41,12 @@ export function getArticleJsonLd(article, crumbs, ctx) {
34
41
  const graph = [
35
42
  {
36
43
  "@type": "BlogPosting",
37
- "@id": `${url}#article`,
44
+ "@id": `${url}#${getIds(ctx).article}`,
38
45
  mainEntityOfPage: url,
39
46
  url,
40
47
  headline: article.title,
41
48
  description: article.description,
42
- inLanguage: ctx.locale,
49
+ inLanguage: getLanguage(ctx),
43
50
  datePublished: dates.published,
44
51
  dateModified: dates.updated ?? dates.published,
45
52
  ...(brand === null ? {} : { author: brand, publisher: brand }),
@@ -57,7 +64,7 @@ export function getArticleJsonLd(article, crumbs, ctx) {
57
64
  return { "@context": "https://schema.org", "@graph": graph };
58
65
  }
59
66
  function getTermSetReference(ctx, glossaryTitle) {
60
- return { "@type": "DefinedTermSet", "@id": `${ctx.urls.getCanonicalUrl(ctx.routes.glossary)}#glossary`, name: glossaryTitle };
67
+ return { "@type": "DefinedTermSet", "@id": `${ctx.urls.getCanonicalUrl(ctx.routes.glossary)}#${getIds(ctx).glossary}`, name: glossaryTitle };
61
68
  }
62
69
  /** A term: `DefinedTerm` in the glossary's `DefinedTermSet`, and its `BreadcrumbList`. */
63
70
  export function getTermJsonLd(term, crumbs, ctx, glossaryTitle) {
@@ -67,11 +74,11 @@ export function getTermJsonLd(term, crumbs, ctx, glossaryTitle) {
67
74
  "@graph": [
68
75
  {
69
76
  "@type": "DefinedTerm",
70
- "@id": `${url}#term`,
77
+ "@id": `${url}#${getIds(ctx).term}`,
71
78
  url,
72
79
  name: term.title,
73
80
  description: term.description,
74
- inLanguage: ctx.locale,
81
+ inLanguage: getLanguage(ctx),
75
82
  ...(term.termForms.length > 0 ? { alternateName: term.termForms } : {}),
76
83
  inDefinedTermSet: getTermSetReference(ctx, glossaryTitle),
77
84
  },
@@ -85,10 +92,10 @@ export function getGlossaryJsonLd(terms, ctx, glossaryTitle) {
85
92
  "@context": "https://schema.org",
86
93
  ...getTermSetReference(ctx, glossaryTitle),
87
94
  url: ctx.urls.getCanonicalUrl(ctx.routes.glossary),
88
- inLanguage: ctx.locale,
95
+ inLanguage: getLanguage(ctx),
89
96
  hasDefinedTerm: terms.map((term) => {
90
97
  const url = ctx.urls.getCanonicalUrl(getTermPath(ctx.routes, term.slug));
91
- return { "@type": "DefinedTerm", "@id": `${url}#term`, name: term.title, description: term.description, url };
98
+ return { "@type": "DefinedTerm", "@id": `${url}#${getIds(ctx).term}`, name: term.title, description: term.description, url };
92
99
  }),
93
100
  };
94
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"json-ld.js","sourceRoot":"","sources":["../../src/pages/json-ld.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"json-ld.js","sourceRoot":"","sources":["../../src/pages/json-ld.ts"],"names":[],"mappings":"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"}
@@ -13,8 +13,10 @@ export interface ClusterGroup<T> {
13
13
  }
14
14
  /** The display name of a cluster: the app's label in the locale, else the key with spaces and a capital. */
15
15
  export declare function getClusterLabel(cluster: string, labels: Readonly<Record<string, LocalizedText>>, locale: Locale): string;
16
- /** The anchor of a cluster's section on the listing: the target of the article's middle crumb. */
17
- export declare function getClusterAnchor(cluster: string): string;
16
+ /** The cluster anchor prefix when the app sets none (`blog({ anchors: { cluster } })`). */
17
+ export declare const DEFAULT_CLUSTER_ANCHOR_PREFIX = "cluster";
18
+ /** The anchor of a cluster's section on the listing (`<prefix>-<cluster>`): the target of the article's middle crumb. */
19
+ export declare function getClusterAnchor(cluster: string, prefix?: string): string;
18
20
  /** The pillar leads its group; the rest keep their order. Without a pillar there is no lead. */
19
21
  export declare function splitClusterLead<T extends Pick<BlogArticle, "isPillar">>(articles: readonly T[]): {
20
22
  lead: T | null;
@@ -39,8 +41,12 @@ export interface CrumbLabels {
39
41
  readonly glossary: string;
40
42
  readonly cluster: (cluster: string) => string;
41
43
  }
44
+ export interface ArticleCrumbOptions {
45
+ /** The listing's cluster anchor prefix; `cluster` when left out. */
46
+ readonly clusterAnchorPrefix?: string;
47
+ }
42
48
  /** Blog › cluster › title; without a cluster, Blog › title. */
43
- export declare function getArticleCrumbs(article: Pick<BlogArticle, "slug" | "title" | "cluster">, routes: BlogRoutes, labels: CrumbLabels): Crumb[];
49
+ export declare function getArticleCrumbs(article: Pick<BlogArticle, "slug" | "title" | "cluster">, routes: BlogRoutes, labels: CrumbLabels, options?: ArticleCrumbOptions): Crumb[];
44
50
  /** Blog › glossary › term. */
45
51
  export declare function getTermCrumbs(term: Pick<BlogArticle, "slug" | "title">, routes: BlogRoutes, labels: CrumbLabels): Crumb[];
46
52
  //# sourceMappingURL=listing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"listing.d.ts","sourceRoot":"","sources":["../../src/pages/listing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAA+B,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;CAC7B;AAED,4GAA4G;AAC5G,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKxH;AAED,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,EAAE,CAAA;CAAE,CAG/H;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,UAAU,CAAC,EAChF,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EACrC,UAAU,EAAE,MAAM,GACjB,YAAY,CAAC,CAAC,CAAC,EAAE,CAYnB;AAED,qHAAqH;AACrH,wBAAgB,SAAS,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,CAExG;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/C;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,CAO3I;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,CAMzH"}
1
+ {"version":3,"file":"listing.d.ts","sourceRoot":"","sources":["../../src/pages/listing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAA+B,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;CAC7B;AAED,4GAA4G;AAC5G,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKxH;AAED,2FAA2F;AAC3F,eAAO,MAAM,6BAA6B,YAAY,CAAC;AAEvD,yHAAyH;AACzH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAsC,GAAG,MAAM,CAExG;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,EAAE,CAAA;CAAE,CAG/H;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,UAAU,CAAC,EAChF,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EACrC,UAAU,EAAE,MAAM,GACjB,YAAY,CAAC,CAAC,CAAC,EAAE,CAYnB;AAED,qHAAqH;AACrH,wBAAgB,SAAS,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,CAExG;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/C;AAED,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,EACxD,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,mBAAwB,GAChC,KAAK,EAAE,CAOT;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,CAMzH"}
@@ -7,9 +7,11 @@ export function getClusterLabel(cluster, labels, locale) {
7
7
  const words = cluster.replace(/-/g, " ");
8
8
  return words.charAt(0).toUpperCase() + words.slice(1);
9
9
  }
10
- /** The anchor of a cluster's section on the listing: the target of the article's middle crumb. */
11
- export function getClusterAnchor(cluster) {
12
- return `cluster-${cluster}`;
10
+ /** The cluster anchor prefix when the app sets none (`blog({ anchors: { cluster } })`). */
11
+ export const DEFAULT_CLUSTER_ANCHOR_PREFIX = "cluster";
12
+ /** The anchor of a cluster's section on the listing (`<prefix>-<cluster>`): the target of the article's middle crumb. */
13
+ export function getClusterAnchor(cluster, prefix = DEFAULT_CLUSTER_ANCHOR_PREFIX) {
14
+ return `${prefix}-${cluster}`;
13
15
  }
14
16
  /** The pillar leads its group; the rest keep their order. Without a pillar there is no lead. */
15
17
  export function splitClusterLead(articles) {
@@ -38,10 +40,10 @@ export function sortTerms(terms, locale) {
38
40
  return [...terms].sort((a, b) => a.title.localeCompare(b.title, locale));
39
41
  }
40
42
  /** Blog › cluster › title; without a cluster, Blog › title. */
41
- export function getArticleCrumbs(article, routes, labels) {
43
+ export function getArticleCrumbs(article, routes, labels, options = {}) {
42
44
  const crumbs = [{ name: labels.blog, path: routes.index }];
43
45
  if (article.cluster !== null) {
44
- crumbs.push({ name: labels.cluster(article.cluster), path: `${routes.index}#${getClusterAnchor(article.cluster)}` });
46
+ crumbs.push({ name: labels.cluster(article.cluster), path: `${routes.index}#${getClusterAnchor(article.cluster, options.clusterAnchorPrefix)}` });
45
47
  }
46
48
  crumbs.push({ name: article.title, path: getArticlePath(routes, article.slug) });
47
49
  return crumbs;
@@ -1 +1 @@
1
- {"version":3,"file":"listing.js","sourceRoot":"","sources":["../../src/pages/listing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"listing.js","sourceRoot":"","sources":["../../src/pages/listing.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ export { findArticleBySlug, findSlugRedirect, getPublishedArticle, listArticles,
3
3
  export { articleHistorySchema, parseArticleHistory, type ArticleHistory, type ArticleHistoryMap } from "../db/history.js";
4
4
  export { runBlogPublish, type ArticleFile, type BlogPublishRun, type PublishedChange, type PublishGate, type PublishProblem, type RunBlogPublishOptions, } from "../db/publish-run.js";
5
5
  export { checkArticlesTable } from "./health.js";
6
- export { getBlogMessages, getBlogOptions, getBlogRefreshPath, getBlogReservedSlugs, getBlogRoutes, getQualitySettings } from "./options.js";
6
+ export { getBlogLocaleTags, getBlogMessages, getBlogOptions, getBlogRefreshPath, getBlogReservedSlugs, getBlogRoutes, getQualitySettings, type BlogLocaleTags } from "./options.js";
7
7
  export * from "../discovery/index.js";
8
8
  export * from "../pages/index.js";
9
9
  export * from "../quality/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACxI,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1H,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC5I,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACxI,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1H,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa,EAAE,kBAAkB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACpL,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
@@ -6,7 +6,7 @@ export { findArticleBySlug, findSlugRedirect, getPublishedArticle, listArticles,
6
6
  export { articleHistorySchema, parseArticleHistory } from "../db/history.js";
7
7
  export { runBlogPublish, } from "../db/publish-run.js";
8
8
  export { checkArticlesTable } from "./health.js";
9
- export { getBlogMessages, getBlogOptions, getBlogRefreshPath, getBlogReservedSlugs, getBlogRoutes, getQualitySettings } from "./options.js";
9
+ export { getBlogLocaleTags, getBlogMessages, getBlogOptions, getBlogRefreshPath, getBlogReservedSlugs, getBlogRoutes, getQualitySettings } from "./options.js";
10
10
  export * from "../discovery/index.js";
11
11
  export * from "../pages/index.js";
12
12
  export * from "../quality/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,qGAAqG;AACrG,oBAAoB;AACpB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAwD,MAAM,4BAA4B,CAAC;AACxI,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,cAAc,GAIf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAA+C,MAAM,kBAAkB,CAAC;AAC1H,OAAO,EACL,cAAc,GAOf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC5I,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,qGAAqG;AACrG,oBAAoB;AACpB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAwD,MAAM,4BAA4B,CAAC;AACxI,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,cAAc,GAIf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAA+C,MAAM,kBAAkB,CAAC;AAC1H,OAAO,EACL,cAAc,GAOf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa,EAAE,kBAAkB,EAAuB,MAAM,cAAc,CAAC;AACpL,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { type SoftureConfig } from "@softure-ai/core";
2
2
  import type { BlogMessages } from "../messages/index.js";
3
- import type { BlogOptions } from "../options.js";
3
+ import { type BlogOptions } from "../options.js";
4
4
  import { type BlogRoutes } from "../pages/paths.js";
5
5
  import { type QualitySettings } from "../quality/settings.js";
6
6
  export declare function getBlogOptions(config: SoftureConfig): BlogOptions;
@@ -8,6 +8,14 @@ export declare function getBlogOptions(config: SoftureConfig): BlogOptions;
8
8
  export declare function getBlogMessages(config: SoftureConfig): BlogMessages;
9
9
  /** The module's routes with the app's overrides applied, without trailing slashes. */
10
10
  export declare function getBlogRoutes(config: SoftureConfig): BlogRoutes;
11
+ export interface BlogLocaleTags {
12
+ /** BCP-47: JSON-LD `inLanguage` and the feed's `<language>`. */
13
+ readonly bcp47: string;
14
+ /** `og:locale`, `language_TERRITORY`. */
15
+ readonly openGraph: string;
16
+ }
17
+ /** The app locale's language tags: the app's `locales` entry, else the bare code and `en_US` / `pl_PL`. */
18
+ export declare function getBlogLocaleTags(config: SoftureConfig): BlogLocaleTags;
11
19
  /** The path of the cache refresh route (`refreshBlogCache`), outside the pages' routes. */
12
20
  export declare function getBlogRefreshPath(config: SoftureConfig): string;
13
21
  /** The slugs no article may take: the app's `reservedSlugs` and the static pages under the listing. */
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"AACA,OAAO,EAAiD,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAatF,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAGjE;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAGnE;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAS/D;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAKhE;AAED,uGAAuG;AACvG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAGpE;AAED,kGAAkG;AAClG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG,IAAI,CAKhF"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"AACA,OAAO,EAAiD,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAatF,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAGjE;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAGnE;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAS/D;AAED,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,2GAA2G;AAC3G,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CAGvE;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAKhE;AAED,uGAAuG;AACvG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAGpE;AAED,kGAAkG;AAClG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG,IAAI,CAKhF"}
@@ -1,5 +1,6 @@
1
1
  // The blog options, routes and copy of the running app, read from the configuration.
2
2
  import { getModule, getSiteUrls } from "@softure-ai/core";
3
+ import { DEFAULT_OPEN_GRAPH_LOCALES } from "../options.js";
3
4
  import { getReservedSlugs, normalizeRoute } from "../pages/paths.js";
4
5
  import { resolveQualitySettings } from "../quality/settings.js";
5
6
  const MODULE_ID = "blog";
@@ -32,6 +33,11 @@ export function getBlogRoutes(config) {
32
33
  };
33
34
  return { index: read("index"), glossary: read("glossary"), method: read("method"), rss: read("rss") };
34
35
  }
36
+ /** The app locale's language tags: the app's `locales` entry, else the bare code and `en_US` / `pl_PL`. */
37
+ export function getBlogLocaleTags(config) {
38
+ const tags = getBlogOptions(config).locales[config.locale];
39
+ return { bcp47: tags?.bcp47 ?? config.locale, openGraph: tags?.openGraph ?? DEFAULT_OPEN_GRAPH_LOCALES[config.locale] };
40
+ }
35
41
  /** The path of the cache refresh route (`refreshBlogCache`), outside the pages' routes. */
36
42
  export function getBlogRefreshPath(config) {
37
43
  const path = getBlogModule(config).routes.refresh;
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,EAAE,SAAS,EAAE,WAAW,EAA6C,MAAM,kBAAkB,CAAC;AAGrG,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAmB,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAwB,MAAM,wBAAwB,CAAC;AAEtF,MAAM,SAAS,GAAG,MAAM,CAAC;AAEzB,sGAAsG;AACtG,SAAS,aAAa,CAAC,MAAqB;IAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,yFAAyF,CAAC,CAAC;IAC7G,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,kEAAkE;IAClE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,OAAsB,CAAC;AACtD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,MAAqB;IACnD,+EAA+E;IAC/E,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAiB,CAAC;AACvE,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IAC5C,MAAM,IAAI,GAAG,CAAC,IAAsB,EAAU,EAAE;QAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,wFAAwF;QACxF,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,uCAAuC,CAAC,CAAC;QACjH,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;AACxG,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,kBAAkB,CAAC,MAAqB;IACtD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IAClD,sFAAsF;IACtF,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;IACjH,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,oBAAoB,CAAC,MAAqB;IACxD,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,kBAAkB,CAAC,MAAqB;IACtD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/I,OAAO,sBAAsB,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC;AAC/D,CAAC"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"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"}
@@ -21,8 +21,8 @@ function ArticleCard({ article, context, timezone, isLead }) {
21
21
  export function BlogListingView({ context, groups, termCount, timezone, cta }) {
22
22
  const copy = context.messages.pages;
23
23
  return (_jsxs(BlogLayout, { context: context, title: copy.blogTitle, lead: copy.blogDescription, children: [groups.length === 0 ? (_jsx("p", { className: "blog-empty", children: copy.empty })) : (_jsx("div", { className: "blog-groups", children: groups.map((group) => {
24
- const id = group.cluster === null ? undefined : getClusterAnchor(group.cluster);
25
- const headingId = `${id ?? "cluster-other"}-heading`;
24
+ const id = group.cluster === null ? undefined : getClusterAnchor(group.cluster, context.clusterAnchorPrefix);
25
+ const headingId = `${id ?? getClusterAnchor("other", context.clusterAnchorPrefix)}-heading`;
26
26
  return (_jsxs("section", { id: id, "aria-labelledby": headingId, className: "blog-group", children: [_jsx("h2", { id: headingId, className: "blog-group-title", children: group.label }), group.lead === null ? null : _jsx(ArticleCard, { article: group.lead, context: context, timezone: timezone, isLead: true }), group.rest.length === 0 ? null : (_jsx("ul", { className: "blog-cards", children: group.rest.map((article) => (_jsx("li", { children: _jsx(ArticleCard, { article: article, context: context, timezone: timezone, isLead: false }) }, article.id))) }))] }, group.cluster ?? ""));
27
27
  }) })), cta === undefined ? null : _jsx("div", { className: "blog-slot", children: cta }), termCount > 0 ? (_jsxs("p", { className: "blog-glossary-teaser", children: [_jsx("a", { href: context.routes.glossary, children: copy.glossaryLink }), ": ", copy.glossaryTeaser] })) : null, _jsx(BlogFooterNote, { context: context })] }));
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"blog-listing.js","sourceRoot":"","sources":["../../src/ui/blog-listing.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blog-listing.js","sourceRoot":"","sources":["../../src/ui/blog-listing.tsx"],"names":[],"mappings":"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"}
@@ -11,5 +11,7 @@ export interface BlogPageContext {
11
11
  readonly brand: string | null;
12
12
  /** The note under every text in the locale; `null` without one. */
13
13
  readonly disclaimer: string | null;
14
+ /** The listing's cluster anchor prefix (`<prefix>-<cluster>`); `cluster` when left out. */
15
+ readonly clusterAnchorPrefix?: string;
14
16
  }
15
17
  //# sourceMappingURL=page-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-context.d.ts","sourceRoot":"","sources":["../../src/ui/page-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC"}
1
+ {"version":3,"file":"page-context.d.ts","sourceRoot":"","sources":["../../src/ui/page-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,2FAA2F;IAC3F,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC"}
package/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "blog",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "dependsOn": { "seo": "^0.1.0?", "security": "^0.1.0?" },
5
5
  "dbSchema": "blog",
6
6
  "tables": ["articles", "slug_history"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softure-ai/blog",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "SOFTURE AI blog module: articles and glossary terms kept as Markdown files with a strict YAML frontmatter (extendable by the app's own fields), stored in the module's Postgres schema by the softure-blog publish command (dry run by default, all or nothing, content hash, slug history, one pillar per cluster), a server-side Markdown renderer (no raw HTML, safe links, glossary links, block plugins), a text quality gate (softure-blog check, run before every publish) with language rulesets and rule plugins, the blog's pages ready to mount in Next.js (listing, article, glossary, method page, OG image, JSON-LD) with a proxy piece for 301 and 410, an article writing skill (softure-blog skill install) generated from the gate's rules, and discovery: an RSS feed, read next, sitemap entries and an IndexNow submit on publish through the optional @softure-ai/seo, with a rate-limited cache refresh route the publish calls first (through the optional @softure-ai/security).",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -29,7 +29,7 @@ export const BLOG_RATE_LIMIT_BUCKETS = {
29
29
  export const blog = defineModule({
30
30
  manifest: {
31
31
  id: MODULE_ID,
32
- version: "0.1.8",
32
+ version: "0.1.9",
33
33
  // seo is optional: with it the sitemap lists the texts and a publish pings IndexNow. security is
34
34
  // optional too: only the cache refresh route needs it, for its rate limit.
35
35
  dependsOn: { seo: "^0.1.0?", security: "^0.1.0?" },
@@ -47,6 +47,8 @@ export const en = {
47
47
  },
48
48
  glossary: {
49
49
  title: "Glossary",
50
+ /** A glossary term's page title with the brand: `{title}` the term, `{brand}` the site. */
51
+ termTitleWithBrand: "{title} | {brand}",
50
52
  description: "Short definitions of the terms the texts use, each with the day it was checked and its sources.",
51
53
  empty: "The first definitions are on their way.",
52
54
  explainedIn: "Explained in these texts",
@@ -42,6 +42,8 @@ export const pl = {
42
42
  },
43
43
  glossary: {
44
44
  title: "Słownik pojęć",
45
+ /** A glossary term's page title with the brand: `{title}` the term, `{brand}` the site. */
46
+ termTitleWithBrand: "{title} | {brand}",
45
47
  description: "Krótkie definicje pojęć, których używają teksty, każda z datą sprawdzenia i źródłami.",
46
48
  empty: "Pierwsze definicje są w drodze.",
47
49
  explainedIn: "Rozwijamy w tekstach",
@@ -26,5 +26,6 @@ export function getPageContext(config: SoftureConfig): BlogPageContext {
26
26
  methodPath: options.methodPage ? routes.method : null,
27
27
  brand: options.brand?.name ?? null,
28
28
  disclaimer: options.disclaimer === undefined ? null : (options.disclaimer[config.locale] ?? options.disclaimer.en),
29
+ clusterAnchorPrefix: options.anchors.cluster,
29
30
  };
30
31
  }
@@ -7,7 +7,7 @@ import { errorLogLabel, formatMessage, getSiteUrls } from "@softure-ai/core";
7
7
  import { getSoftureConfig } from "@softure-ai/core/next";
8
8
  import { buildBlogRss } from "../discovery/rss.js";
9
9
  import { getClusterLabel } from "../pages/listing.js";
10
- import { getBlogOptions } from "../server/options.js";
10
+ import { getBlogLocaleTags, getBlogOptions } from "../server/options.js";
11
11
  import { getPageContext } from "./context.js";
12
12
  import { getPublishedArticles, getPublishedTerms } from "./data.js";
13
13
 
@@ -34,7 +34,7 @@ export async function serveBlogRss(): Promise<Response> {
34
34
  channel: {
35
35
  title: context.brand === null ? copy.pages.blogTitle : formatMessage(copy.pages.titleWithBrand, { title: copy.pages.blogTitle, brand: context.brand }),
36
36
  description: copy.pages.blogDescription,
37
- language: config.locale,
37
+ language: getBlogLocaleTags(config).bcp47,
38
38
  },
39
39
  getCategory: (text) => (text.kind === "term" ? copy.glossary.title : text.cluster === null ? null : getClusterLabel(text.cluster, clusters, config.locale)),
40
40
  });
@@ -7,7 +7,7 @@ import { getSiteUrls, type SoftureConfig } from "@softure-ai/core";
7
7
  import type { BlogArticle } from "../contract.js";
8
8
  import { getArticleJsonLd, getGlossaryJsonLd, getTermJsonLd, serializeJsonLd, type JsonLdContext } from "../pages/json-ld.js";
9
9
  import { getArticleCrumbs, getClusterLabel, getTermCrumbs, sortTerms, type CrumbLabels } from "../pages/listing.js";
10
- import { getBlogOptions } from "../server/options.js";
10
+ import { getBlogLocaleTags, getBlogOptions } from "../server/options.js";
11
11
  import type { BlogPageContext } from "../ui/page-context.js";
12
12
  import { getPageContext } from "./context.js";
13
13
 
@@ -22,13 +22,21 @@ export function getCrumbLabels(config: SoftureConfig, context: BlogPageContext =
22
22
  }
23
23
 
24
24
  function getJsonLdContext(config: SoftureConfig, context: BlogPageContext): JsonLdContext {
25
- return { urls: getSiteUrls(config), routes: context.routes, locale: config.locale, timezone: config.timezone, brand: context.brand };
25
+ return {
26
+ urls: getSiteUrls(config),
27
+ routes: context.routes,
28
+ locale: config.locale,
29
+ language: getBlogLocaleTags(config).bcp47,
30
+ ids: getBlogOptions(config).jsonLd.ids,
31
+ timezone: config.timezone,
32
+ brand: context.brand,
33
+ };
26
34
  }
27
35
 
28
36
  /** An article's `BlogPosting`, breadcrumbs and FAQ, serialized. */
29
37
  export function buildArticleJsonLd(config: SoftureConfig, article: BlogArticle): string {
30
38
  const context = getPageContext(config);
31
- const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context));
39
+ const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context), { clusterAnchorPrefix: context.clusterAnchorPrefix });
32
40
  return serializeJsonLd(getArticleJsonLd(article, crumbs, getJsonLdContext(config, context)));
33
41
  }
34
42
 
@@ -16,6 +16,7 @@ import type { Metadata } from "next/types.js";
16
16
  import type { BlogArticle } from "../contract.js";
17
17
  import { getArticleDates } from "../pages/dates.js";
18
18
  import { getArticlePath, getTermPath } from "../pages/paths.js";
19
+ import { getBlogLocaleTags } from "../server/options.js";
19
20
  import type { BlogPageContext } from "../ui/page-context.js";
20
21
  import { getPageContext } from "./context.js";
21
22
 
@@ -24,8 +25,9 @@ export interface ListingMetadataInput {
24
25
  readonly isEmpty: boolean;
25
26
  }
26
27
 
27
- function withBrand(title: string, context: BlogPageContext): string {
28
- return context.brand === null ? title : formatMessage(context.messages.pages.titleWithBrand, { title, brand: context.brand });
28
+ /** `pattern`: the page kind's title message (`pages.titleWithBrand`, or `glossary.termTitleWithBrand` for a term). */
29
+ function withBrand(title: string, context: BlogPageContext, pattern: string = context.messages.pages.titleWithBrand): string {
30
+ return context.brand === null ? title : formatMessage(pattern, { title, brand: context.brand });
29
31
  }
30
32
 
31
33
  /** A page's canonical URL: seo's host and trailing-slash rule when the app lists seo, else on `appOrigin`. */
@@ -48,11 +50,11 @@ function getStaticMetadata(config: SoftureConfig, context: BlogPageContext, page
48
50
  };
49
51
  }
50
52
 
51
- function getTextMetadata(config: SoftureConfig, context: BlogPageContext, text: BlogArticle, path: string, options: { hasFeed?: boolean } = {}): Metadata {
53
+ function getTextMetadata(config: SoftureConfig, context: BlogPageContext, text: BlogArticle, path: string, options: { hasFeed?: boolean; titlePattern?: string } = {}): Metadata {
52
54
  const dates = getArticleDates(text, config.timezone);
53
55
  const url = getCanonicalUrl(config, path);
54
56
  return {
55
- title: withBrand(text.title, context),
57
+ title: withBrand(text.title, context, options.titlePattern),
56
58
  description: text.description,
57
59
  robots: { index: true, follow: true },
58
60
  alternates: { canonical: url, ...(options.hasFeed === true ? { types: getFeedAlternates(config, context) } : {}) },
@@ -61,7 +63,7 @@ function getTextMetadata(config: SoftureConfig, context: BlogPageContext, text:
61
63
  title: text.title,
62
64
  description: text.description,
63
65
  url,
64
- locale: config.locale,
66
+ locale: getBlogLocaleTags(config).openGraph,
65
67
  publishedTime: dates.published,
66
68
  modifiedTime: dates.updated ?? dates.published,
67
69
  ...(context.brand === null ? {} : { siteName: context.brand }),
@@ -89,10 +91,10 @@ export function buildGlossaryIndexMetadata(config: SoftureConfig, { isEmpty }: L
89
91
  return getStaticMetadata(config, context, { title: copy.title, description: copy.description, path: context.routes.glossary, isEmpty });
90
92
  }
91
93
 
92
- /** A glossary term's metadata. The caller checks the text is a published term. */
94
+ /** A glossary term's metadata, titled by `glossary.termTitleWithBrand`. The caller checks the text is a published term. */
93
95
  export function buildTermMetadata(config: SoftureConfig, term: BlogArticle): Metadata {
94
96
  const context = getPageContext(config);
95
- return getTextMetadata(config, context, term, getTermPath(context.routes, term.slug));
97
+ return getTextMetadata(config, context, term, getTermPath(context.routes, term.slug), { titlePattern: context.messages.glossary.termTitleWithBrand });
96
98
  }
97
99
 
98
100
  /** The method page's metadata. */
@@ -108,7 +108,7 @@ export async function BlogArticlePage({ params, cta, afterArticle }: BlogArticle
108
108
  const context = getPageContext(config);
109
109
  const [terms, published] = await Promise.all([getPublishedTerms(config), getPublishedArticles(config)]);
110
110
  const body = renderPageBody<ReactNode>(article, getBodyOptions(config, context, terms));
111
- const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context));
111
+ const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context), { clusterAnchorPrefix: context.clusterAnchorPrefix });
112
112
  const jsonLd = buildArticleJsonLd(config, article);
113
113
  return (
114
114
  <BlogArticleView