@airalogy/aimd-renderer 2.6.0 → 2.8.0

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 (41) hide show
  1. package/README.md +38 -0
  2. package/README.zh-CN.md +38 -0
  3. package/dist/aimd-renderer.css +1 -1
  4. package/dist/common/assetUrls.d.ts +8 -0
  5. package/dist/common/assetUrls.d.ts.map +1 -0
  6. package/dist/common/citationNumbering.d.ts +11 -0
  7. package/dist/common/citationNumbering.d.ts.map +1 -0
  8. package/dist/common/criticMarkup.d.ts +10 -0
  9. package/dist/common/criticMarkup.d.ts.map +1 -0
  10. package/dist/common/processor.d.ts +2 -0
  11. package/dist/common/processor.d.ts.map +1 -1
  12. package/dist/html/index.d.ts +1 -0
  13. package/dist/html/index.d.ts.map +1 -1
  14. package/dist/html.js +1 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +80 -73
  18. package/dist/locales.d.ts +3 -0
  19. package/dist/locales.d.ts.map +1 -1
  20. package/dist/{processor-CHbNEcN8.js → processor-C_zN3-hL.js} +3454 -2534
  21. package/dist/readonly-record-renderer-G9xOkOFe.js +711 -0
  22. package/dist/vue/index.d.ts +2 -0
  23. package/dist/vue/index.d.ts.map +1 -1
  24. package/dist/vue/readonly-record-renderer.d.ts +42 -0
  25. package/dist/vue/readonly-record-renderer.d.ts.map +1 -0
  26. package/dist/vue/vue-renderer.d.ts +7 -1
  27. package/dist/vue/vue-renderer.d.ts.map +1 -1
  28. package/dist/vue.js +20 -13
  29. package/package.json +2 -2
  30. package/src/__tests__/renderer.test.ts +536 -1
  31. package/src/common/assetUrls.ts +22 -0
  32. package/src/common/citationNumbering.ts +265 -0
  33. package/src/common/criticMarkup.ts +97 -0
  34. package/src/common/processor.ts +206 -25
  35. package/src/html/index.ts +4 -0
  36. package/src/index.ts +23 -0
  37. package/src/locales.ts +9 -0
  38. package/src/styles/katex.css +213 -0
  39. package/src/vue/index.ts +22 -0
  40. package/src/vue/readonly-record-renderer.ts +747 -0
  41. package/src/vue/vue-renderer.ts +183 -9
@@ -1,10 +1,12 @@
1
1
  import type { Element, Properties, Root as HastRoot, Text as HastText } from "hast"
2
2
  import type { VFile } from "vfile"
3
3
  import type { VNode } from "vue"
4
+ import type { AimdAssetUrlResolver } from "./assetUrls"
4
5
  import type {
5
6
  AimdFieldType,
6
7
  AimdNode,
7
8
  AimdQuizNode,
9
+ AimdReferenceEntry,
8
10
  AimdStepNode,
9
11
  ProcessorOptions,
10
12
  RenderContext,
@@ -13,6 +15,7 @@ import type { ExtractedAimdFields } from "@airalogy/aimd-core/types"
13
15
  import type { AimdRendererI18nOptions } from "../locales"
14
16
  import type { VueRendererOptions } from "../vue/vue-renderer"
15
17
  import { resolveQuizPreviewOptions } from "./quiz-preview"
18
+ import { resolveAimdAssetUrl } from "./assetUrls"
16
19
 
17
20
  // ---------------------------------------------------------------------------
18
21
  // Sub-module imports
@@ -21,6 +24,8 @@ import { resolveQuizPreviewOptions } from "./quiz-preview"
21
24
  import { remarkInsertVisibleAssigners, remarkStripAssignerCodeBlocks } from "./assignerVisibility"
22
25
  import { highlightVisibleAssigners } from "./assignerHighlighting"
23
26
  import { annotateStepReferenceSequence } from "./annotateStepReferences"
27
+ import { annotateCitationReferenceLabels, moveReferenceSectionsToEnd } from "./citationNumbering"
28
+ import { criticMarkupHandlers } from "./criticMarkup"
24
29
  import { buildFigureChildren, assignFigureSequenceNumbers } from "./figureNumbering"
25
30
 
26
31
  // ---------------------------------------------------------------------------
@@ -51,6 +56,7 @@ export type AimdHtmlNodeRenderer = (
51
56
  export interface AimdRendererOptions extends ProcessorOptions, AimdRendererI18nOptions {
52
57
  assignerVisibility?: AimdAssignerVisibility
53
58
  aimdElementRenderers?: Partial<Record<AimdFieldType, AimdHtmlNodeRenderer>>
59
+ resolveAssetUrl?: AimdAssetUrlResolver
54
60
  groupStepBodies?: boolean
55
61
  groupCheckBodies?: boolean
56
62
  blockVarTypes?: string[]
@@ -511,7 +517,13 @@ import remarkParse from "remark-parse"
511
517
  import remarkRehype from "remark-rehype"
512
518
  import { unified } from "unified"
513
519
 
514
- import { protectAimdInlineTemplates, remarkAimd } from "@airalogy/aimd-core/parser"
520
+ import {
521
+ CRITIC_MARKUP_SUBSTITUTIONS_DATA_KEY,
522
+ protectAimdInlineTemplates,
523
+ protectCriticMarkupSubstitutions,
524
+ remarkAimd,
525
+ remarkCriticMarkup,
526
+ } from "@airalogy/aimd-core/parser"
515
527
  import {
516
528
  formatAimdExampleValue,
517
529
  formatAimdExamples,
@@ -550,6 +562,7 @@ const EMPTY_EXTRACTED_FIELDS: ExtractedAimdFields = {
550
562
  ref_fig: [],
551
563
  cite: [],
552
564
  fig: [],
565
+ refs: [],
553
566
  }
554
567
 
555
568
  async function ensureMathStylesLoaded(mathEnabled: boolean | undefined): Promise<void> {
@@ -567,14 +580,16 @@ async function ensureMathStylesLoaded(mathEnabled: boolean | undefined): Promise
567
580
 
568
581
  function createAimdParseInput(content: string) {
569
582
  const { content: protectedContent, templates } = protectAimdInlineTemplates(content)
583
+ const { content: criticProtectedContent, substitutions } = protectCriticMarkupSubstitutions(protectedContent)
570
584
  const file: VFile = {
571
585
  data: {
572
586
  aimdInlineTemplates: templates,
587
+ [CRITIC_MARKUP_SUBSTITUTIONS_DATA_KEY]: substitutions,
573
588
  },
574
589
  } as unknown as VFile
575
590
 
576
591
  return {
577
- content: protectedContent,
592
+ content: criticProtectedContent,
578
593
  file,
579
594
  }
580
595
  }
@@ -593,6 +608,7 @@ function createEmptyExtractedFields(): ExtractedAimdFields {
593
608
  ref_fig: [...(EMPTY_EXTRACTED_FIELDS.ref_fig || [])],
594
609
  cite: [...(EMPTY_EXTRACTED_FIELDS.cite || [])],
595
610
  fig: [...(EMPTY_EXTRACTED_FIELDS.fig || [])],
611
+ refs: [...(EMPTY_EXTRACTED_FIELDS.refs || [])],
596
612
  }
597
613
  }
598
614
 
@@ -798,6 +814,94 @@ function buildScaleBandChildren(quizNode: AimdQuizNode): Array<Element | HastTex
798
814
  } as Element]
799
815
  }
800
816
 
817
+ function getReferenceContainer(entry: AimdReferenceEntry): string | undefined {
818
+ return entry.journal || entry.booktitle || entry.publisher
819
+ }
820
+
821
+ function createReferenceTextChildren(entry: AimdReferenceEntry): Array<Element | HastText> {
822
+ const children: Array<Element | HastText> = []
823
+ const pushText = (value: string | undefined, suffix = "") => {
824
+ const normalized = value?.trim()
825
+ if (!normalized) {
826
+ return
827
+ }
828
+ if (children.length > 0) {
829
+ children.push(createTextNode(" "))
830
+ }
831
+ children.push(createTextNode(`${normalized}${suffix}`))
832
+ }
833
+
834
+ pushText(entry.author)
835
+ pushText(entry.year ? `(${entry.year})` : undefined)
836
+ pushText(entry.title, entry.title && !/[.!?]$/.test(entry.title) ? "." : "")
837
+ pushText(getReferenceContainer(entry), ".")
838
+
839
+ if (entry.doi) {
840
+ if (children.length > 0) {
841
+ children.push(createTextNode(" "))
842
+ }
843
+ const doiHref = entry.doi.startsWith("http")
844
+ ? entry.doi
845
+ : `https://doi.org/${entry.doi}`
846
+ children.push({
847
+ type: "element",
848
+ tagName: "a",
849
+ properties: {
850
+ className: ["aimd-refs__doi"],
851
+ href: doiHref,
852
+ },
853
+ children: [createTextNode(`doi:${entry.doi}`)],
854
+ } as Element)
855
+ }
856
+ else if (entry.url) {
857
+ if (children.length > 0) {
858
+ children.push(createTextNode(" "))
859
+ }
860
+ children.push({
861
+ type: "element",
862
+ tagName: "a",
863
+ properties: {
864
+ className: ["aimd-refs__url"],
865
+ href: entry.url,
866
+ },
867
+ children: [createTextNode(entry.url)],
868
+ } as Element)
869
+ }
870
+
871
+ if (children.length === 0) {
872
+ children.push(createTextNode(entry.id))
873
+ }
874
+
875
+ return children
876
+ }
877
+
878
+ function buildReferencesChildren(entries: AimdReferenceEntry[], title: string): Array<Element | HastText> {
879
+ return [
880
+ {
881
+ type: "element",
882
+ tagName: "div",
883
+ properties: { className: ["aimd-refs__title"] },
884
+ children: [createTextNode(title)],
885
+ } as Element,
886
+ {
887
+ type: "element",
888
+ tagName: "ol",
889
+ properties: { className: ["aimd-refs__list"] },
890
+ children: entries.map(entry => ({
891
+ type: "element",
892
+ tagName: "li",
893
+ properties: {
894
+ id: `ref-${entry.id}`,
895
+ className: ["aimd-refs__item"],
896
+ "data-aimd-ref-id": entry.id,
897
+ "data-aimd-ref-type": entry.entry_type,
898
+ },
899
+ children: createReferenceTextChildren(entry),
900
+ } as Element)),
901
+ } as Element,
902
+ ]
903
+ }
904
+
801
905
  function createTextNode(value: string): HastText {
802
906
  return { type: "text", value }
803
907
  }
@@ -985,6 +1089,16 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
985
1089
  nodeData.sequence = figNode.sequence
986
1090
  }
987
1091
 
1092
+ // Add refs-specific fields
1093
+ if (node.fieldType === "refs") {
1094
+ nodeData.entries = (node as any).entries
1095
+ }
1096
+
1097
+ // Add cite-specific fields
1098
+ if (node.fieldType === "cite") {
1099
+ nodeData.refs = (node as any).refs
1100
+ }
1101
+
988
1102
  // Add step-specific fields
989
1103
  if (node.fieldType === "step") {
990
1104
  const stepNode = node as AimdStepNode
@@ -1017,12 +1131,13 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
1017
1131
  const isCite = fieldType === "cite"
1018
1132
  const isQuiz = fieldType === "quiz"
1019
1133
  const isFig = fieldType === "fig"
1134
+ const isRefs = fieldType === "refs"
1020
1135
  const baseClass = isRef
1021
1136
  ? "aimd-ref"
1022
- : (isCite ? "aimd-cite" : (isFig ? "aimd-figure" : "aimd-field"))
1137
+ : (isCite ? "aimd-cite" : (isFig ? "aimd-figure" : (isRefs ? "aimd-refs" : "aimd-field")))
1023
1138
  const modifierClass = isRef
1024
1139
  ? `aimd-ref--${fieldType === "ref_step" ? "step" : (fieldType === "ref_var" ? "var" : "fig")}`
1025
- : (isCite ? "" : (isFig ? "" : `aimd-field--${typeClass}`))
1140
+ : (isCite ? "" : (isFig || isRefs ? "" : `aimd-field--${typeClass}`))
1026
1141
 
1027
1142
  // Generate children based on field type
1028
1143
  const children: (Element | HastText)[] = []
@@ -1082,27 +1197,66 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
1082
1197
  }
1083
1198
  }
1084
1199
  else if (isCite) {
1085
- // Citation: [refs]
1200
+ // Citation: compact reference markers; details are attached during citation annotation.
1086
1201
  const refs = "refs" in node ? (node as any).refs : [id]
1202
+ children.push(createTextNode("["))
1203
+ refs.forEach((ref: string, index: number) => {
1204
+ if (index > 0) {
1205
+ children.push(createTextNode(", "))
1206
+ }
1207
+ children.push({
1208
+ type: "element",
1209
+ tagName: "span",
1210
+ properties: {
1211
+ className: ["aimd-cite__ref"],
1212
+ role: "doc-noteref",
1213
+ tabIndex: 0,
1214
+ title: ref,
1215
+ "data-aimd-ref-id": ref,
1216
+ "data-aimd-ref-summary": ref,
1217
+ },
1218
+ children: [
1219
+ {
1220
+ type: "element",
1221
+ tagName: "span",
1222
+ properties: { className: ["aimd-cite__label"] },
1223
+ children: [createTextNode(ref)],
1224
+ } as Element,
1225
+ {
1226
+ type: "element",
1227
+ tagName: "span",
1228
+ properties: {
1229
+ className: ["aimd-cite__popover"],
1230
+ role: "tooltip",
1231
+ },
1232
+ children: [createTextNode(ref)],
1233
+ } as Element,
1234
+ ],
1235
+ } as Element)
1236
+ })
1237
+ children.push(createTextNode("]"))
1238
+ }
1239
+ else if (isRefs) {
1240
+ const entries = Array.isArray((node as any).entries) ? (node as any).entries : []
1087
1241
  children.push({
1088
1242
  type: "element",
1089
- tagName: "span",
1090
- properties: { className: ["aimd-cite__refs"] },
1091
- children: [{ type: "text", value: `[${refs.join(", ")}]` }],
1243
+ tagName: "div",
1244
+ properties: { className: ["aimd-refs__content"] },
1245
+ children: buildReferencesChildren(entries, messages.references.title),
1092
1246
  } as Element)
1093
1247
  }
1094
- else if (fieldType === "var") {
1095
- // Variable: type label + id + optional type annotation
1096
- const definition = "definition" in node ? node.definition : undefined
1097
- children.push(
1248
+ else if (fieldType === "var") {
1249
+ // Variable: type label + id + optional type annotation
1250
+ const definition = "definition" in node ? node.definition : undefined
1251
+ children.push(
1098
1252
  {
1099
1253
  type: "element",
1100
1254
  tagName: "span",
1101
- properties: { className: ["aimd-field__scope"] },
1102
- children: [{ type: "text", value: getAimdRendererScopeLabel("var", messages) }],
1103
- } as Element,
1104
- createFieldNameElement(id, definition),
1105
- )
1255
+ properties: { className: ["aimd-field__scope"] },
1256
+ children: [{ type: "text", value: getAimdRendererScopeLabel("var", messages) }],
1257
+ } as Element,
1258
+ createFieldNameElement(id, definition),
1259
+ )
1106
1260
  if (definition?.type) {
1107
1261
  children.push({
1108
1262
  type: "element",
@@ -1349,9 +1503,15 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
1349
1503
  else if (fieldType === "fig") {
1350
1504
  // Figure: delegate to figureNumbering module
1351
1505
  const figNode = node as any
1506
+ const figId = figNode.id || id
1507
+ const figSrc = resolveAimdAssetUrl(figNode.src, options.resolveAssetUrl, {
1508
+ kind: "fig",
1509
+ id: figId,
1510
+ title: figNode.title,
1511
+ })
1352
1512
  children.push(...buildFigureChildren({
1353
- id: figNode.id || id,
1354
- src: figNode.src,
1513
+ id: figId,
1514
+ src: figSrc,
1355
1515
  title: figNode.title,
1356
1516
  legend: figNode.legend,
1357
1517
  sequence: figNode.sequence,
@@ -1383,16 +1543,20 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
1383
1543
  }
1384
1544
  }
1385
1545
 
1386
- // Add reference href
1546
+ // Add internal reference metadata for host-level scrolling.
1387
1547
  if (isRef) {
1548
+ properties.title = id
1549
+ properties.tabIndex = 0
1550
+ properties["data-aimd-ref-target"] = id
1551
+
1388
1552
  if (fieldType === "ref_step") {
1389
- properties.href = `#step-${id}`
1553
+ properties["data-aimd-ref-kind"] = "step"
1390
1554
  }
1391
1555
  else if (fieldType === "ref_var") {
1392
- properties.href = `#var-${id}`
1556
+ properties["data-aimd-ref-kind"] = "var"
1393
1557
  }
1394
1558
  else if (fieldType === "ref_fig") {
1395
- properties.href = `#fig-${id}`
1559
+ properties["data-aimd-ref-kind"] = "fig"
1396
1560
  }
1397
1561
  }
1398
1562
 
@@ -1454,6 +1618,15 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
1454
1618
  properties["data-aimd-fig-src"] = figNode.src
1455
1619
  }
1456
1620
 
1621
+ if (node.fieldType === "cite") {
1622
+ const refs = "refs" in node ? (node as any).refs : [id]
1623
+ properties["data-aimd-refs"] = refs.join(",")
1624
+ }
1625
+
1626
+ if (node.fieldType === "refs") {
1627
+ properties.id = "refs"
1628
+ }
1629
+
1457
1630
  // Add quiz metadata for fallback reconstruction
1458
1631
  if (node.fieldType === "quiz") {
1459
1632
  const quizNode = node as AimdQuizNode
@@ -1465,8 +1638,8 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
1465
1638
  const element: Element = assignAimdNodeData({
1466
1639
  type: "element",
1467
1640
  tagName: isRef
1468
- ? "a"
1469
- : (isFig ? "figure" : ((fieldType === "var_table" || isQuiz || isGroupedStepContainer) ? "div" : "span")),
1641
+ ? "span"
1642
+ : (isFig ? "figure" : (isRefs ? "section" : ((fieldType === "var_table" || isQuiz || isGroupedStepContainer) ? "div" : "span"))),
1470
1643
  properties,
1471
1644
  children,
1472
1645
  }, node)
@@ -1512,6 +1685,7 @@ function createBaseProcessor(options: AimdRendererOptions = {}) {
1512
1685
  // to properly parse multiline AIMD syntax like var_table with subvars
1513
1686
  processor.use(remarkAimd)
1514
1687
  processor.use(remarkStripAssignerCodeBlocks)
1688
+ processor.use(remarkCriticMarkup)
1515
1689
 
1516
1690
  // Single line break to <br> conversion (default enabled for AIMD)
1517
1691
  if (breaks) {
@@ -1534,6 +1708,7 @@ export function createHtmlProcessor(options: AimdRendererOptions = {}) {
1534
1708
  handlers: {
1535
1709
  // Custom handler for AIMD nodes
1536
1710
  aimd: aimdHandler,
1711
+ ...criticMarkupHandlers,
1537
1712
  },
1538
1713
  } as any)
1539
1714
  .use(rehypeRaw)
@@ -1567,6 +1742,7 @@ export async function renderToHtml(
1567
1742
  const fields = getExtractedFields(file)
1568
1743
  annotateStepReferenceSequence(hastTree, fields, options)
1569
1744
  assignFigureSequenceNumbers(hastTree, fields)
1745
+ annotateCitationReferenceLabels(hastTree, fields)
1570
1746
  liftBlockVarElements(hastTree, options.blockVarTypes)
1571
1747
  if (options.groupStepBodies) {
1572
1748
  groupStepBodies(hastTree)
@@ -1575,6 +1751,7 @@ export async function renderToHtml(
1575
1751
  groupCheckBodies(hastTree)
1576
1752
  }
1577
1753
  await highlightVisibleAssigners(hastTree, options)
1754
+ moveReferenceSectionsToEnd(hastTree)
1578
1755
  const html = toHtml(hastTree, { allowDangerousHtml: true })
1579
1756
 
1580
1757
  return { html, fields }
@@ -1597,6 +1774,7 @@ export async function renderToVue(
1597
1774
  const fields = getExtractedFields(file)
1598
1775
  annotateStepReferenceSequence(hastTree, fields, options)
1599
1776
  assignFigureSequenceNumbers(hastTree, fields)
1777
+ annotateCitationReferenceLabels(hastTree, fields)
1600
1778
  liftBlockVarElements(hastTree, options.blockVarTypes)
1601
1779
  if (options.groupStepBodies) {
1602
1780
  groupStepBodies(hastTree)
@@ -1605,6 +1783,7 @@ export async function renderToVue(
1605
1783
  groupCheckBodies(hastTree)
1606
1784
  }
1607
1785
  await highlightVisibleAssigners(hastTree, options)
1786
+ moveReferenceSectionsToEnd(hastTree)
1608
1787
  const nodes = renderToVNodes(hastTree, options)
1609
1788
 
1610
1789
  return { nodes, fields }
@@ -1642,10 +1821,12 @@ export function renderToHtmlSync(
1642
1821
  const fields = getExtractedFields(file)
1643
1822
  annotateStepReferenceSequence(hastTree, fields, options)
1644
1823
  assignFigureSequenceNumbers(hastTree, fields)
1824
+ annotateCitationReferenceLabels(hastTree, fields)
1645
1825
  liftBlockVarElements(hastTree, options.blockVarTypes)
1646
1826
  if (options.groupStepBodies) {
1647
1827
  groupStepBodies(hastTree)
1648
1828
  }
1829
+ moveReferenceSectionsToEnd(hastTree)
1649
1830
  const html = toHtml(hastTree, { allowDangerousHtml: true })
1650
1831
 
1651
1832
  return { html, fields }
package/src/html/index.ts CHANGED
@@ -25,6 +25,10 @@ export type {
25
25
  AimdRendererOptions,
26
26
  RenderResult,
27
27
  } from '../common/processor'
28
+ export type {
29
+ AimdAssetUrlResolver,
30
+ AimdAssetUrlResolveContext,
31
+ } from '../common/assetUrls'
28
32
  export type {
29
33
  AimdRendererI18nOptions,
30
34
  AimdRendererLocale,
package/src/index.ts CHANGED
@@ -23,6 +23,11 @@ export {
23
23
  resolveAimdRendererLocale,
24
24
  } from './locales'
25
25
 
26
+ export type {
27
+ AimdAssetUrlResolver,
28
+ AimdAssetUrlResolveContext,
29
+ } from './common/assetUrls'
30
+
26
31
  export {
27
32
  bubbleMenuEventKey,
28
33
  draftEventKey,
@@ -41,6 +46,24 @@ export {
41
46
  } from './common/unified-token-renderer'
42
47
 
43
48
  // Vue renderer exports
49
+ export {
50
+ AIMD_RECORD_RENDER_SCOPES,
51
+ createReadonlyRecordAimdRenderers,
52
+ createReadonlyRecordElementRenderers,
53
+ createReadonlyRecordRenderContext,
54
+ normalizeRecordRenderValue,
55
+ renderReadonlyRecordToVue,
56
+ type AimdRecordRenderScope,
57
+ type AimdRecordRenderValue,
58
+ type ReadonlyRecordAsset,
59
+ type ReadonlyRecordAssetKind,
60
+ type ReadonlyRecordAssetResolveContext,
61
+ type ReadonlyRecordAssetResolver,
62
+ type ReadonlyRecordMarkdownRenderOptions,
63
+ type ReadonlyRecordRenderContextInput,
64
+ type ReadonlyRecordVueRendererOptions,
65
+ } from './vue/readonly-record-renderer'
66
+
44
67
  export {
45
68
  type AimdComponentRenderer,
46
69
  type AimdRendererContext,
package/src/locales.ts CHANGED
@@ -43,6 +43,9 @@ export interface AimdRendererMessages {
43
43
  reference: (value: string | number) => string
44
44
  captionTitle: (sequence: number, title?: string) => string
45
45
  }
46
+ references: {
47
+ title: string
48
+ }
46
49
  assigner: {
47
50
  clientSummary: string
48
51
  serverSummary: string
@@ -104,6 +107,9 @@ const EN_US_MESSAGES: AimdRendererMessages = {
104
107
  reference: value => `figure ${value}`,
105
108
  captionTitle: (sequence, title) => title ? `figure ${sequence}: ${title}` : `figure ${sequence}`,
106
109
  },
110
+ references: {
111
+ title: "References",
112
+ },
107
113
  assigner: {
108
114
  clientSummary: "Client assigner",
109
115
  serverSummary: "Server assigner",
@@ -141,6 +147,9 @@ const ZH_CN_MESSAGES: AimdRendererMessages = {
141
147
  reference: value => `图 ${value}`,
142
148
  captionTitle: (sequence, title) => title ? `图 ${sequence}:${title}` : `图 ${sequence}`,
143
149
  },
150
+ references: {
151
+ title: "参考文献",
152
+ },
144
153
  assigner: {
145
154
  clientSummary: "前端 assigner",
146
155
  serverSummary: "服务端 assigner",