react-cheminfo 0.24.0 → 0.26.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 (432) hide show
  1. package/README.md +73 -2
  2. package/bin/check-messages.mjs +229 -0
  3. package/lib/about/ui/AboutBuild.d.ts.map +1 -1
  4. package/lib/about/ui/AboutBuild.js +15 -4
  5. package/lib/about/ui/AboutBuild.js.map +1 -1
  6. package/lib/about/ui/AboutCitations.d.ts.map +1 -1
  7. package/lib/about/ui/AboutCitations.js +3 -1
  8. package/lib/about/ui/AboutCitations.js.map +1 -1
  9. package/lib/about/ui/AboutPage.d.ts.map +1 -1
  10. package/lib/about/ui/AboutPage.js +9 -1
  11. package/lib/about/ui/AboutPage.js.map +1 -1
  12. package/lib/about/ui/AboutProvidedBy.d.ts.map +1 -1
  13. package/lib/about/ui/AboutProvidedBy.js +8 -3
  14. package/lib/about/ui/AboutProvidedBy.js.map +1 -1
  15. package/lib/capsule/ui/Capsule.d.ts +30 -0
  16. package/lib/capsule/ui/Capsule.d.ts.map +1 -0
  17. package/lib/capsule/ui/Capsule.js +12 -0
  18. package/lib/capsule/ui/Capsule.js.map +1 -0
  19. package/lib/capsule/ui/CapsuleFilter.d.ts +19 -3
  20. package/lib/capsule/ui/CapsuleFilter.d.ts.map +1 -1
  21. package/lib/capsule/ui/CapsuleFilter.js +14 -44
  22. package/lib/capsule/ui/CapsuleFilter.js.map +1 -1
  23. package/lib/capsule/ui/capsuleFilterCapsules.d.ts +15 -0
  24. package/lib/capsule/ui/capsuleFilterCapsules.d.ts.map +1 -0
  25. package/lib/capsule/ui/capsuleFilterCapsules.js +47 -0
  26. package/lib/capsule/ui/capsuleFilterCapsules.js.map +1 -0
  27. package/lib/chart/ui/ChartTrackingLayer.d.ts.map +1 -1
  28. package/lib/chart/ui/ChartTrackingLayer.js +4 -2
  29. package/lib/chart/ui/ChartTrackingLayer.js.map +1 -1
  30. package/lib/chrome/ui/SiteHeader.d.ts +1 -1
  31. package/lib/chrome/ui/SiteHeader.d.ts.map +1 -1
  32. package/lib/chrome/ui/SiteHeader.js +4 -2
  33. package/lib/chrome/ui/SiteHeader.js.map +1 -1
  34. package/lib/citation/ui/CitationMenu.d.ts +1 -1
  35. package/lib/citation/ui/CitationMenu.d.ts.map +1 -1
  36. package/lib/citation/ui/CitationMenu.js +7 -3
  37. package/lib/citation/ui/CitationMenu.js.map +1 -1
  38. package/lib/citation/ui/CiteButton.d.ts +1 -1
  39. package/lib/citation/ui/CiteButton.d.ts.map +1 -1
  40. package/lib/citation/ui/CiteButton.js +3 -1
  41. package/lib/citation/ui/CiteButton.js.map +1 -1
  42. package/lib/citation/ui/CopyFormatEntries.d.ts.map +1 -1
  43. package/lib/citation/ui/CopyFormatEntries.js +3 -1
  44. package/lib/citation/ui/CopyFormatEntries.js.map +1 -1
  45. package/lib/citation/ui/WorkEntry.d.ts.map +1 -1
  46. package/lib/citation/ui/WorkEntry.js +3 -1
  47. package/lib/citation/ui/WorkEntry.js.map +1 -1
  48. package/lib/citation/ui/entries.d.ts.map +1 -1
  49. package/lib/citation/ui/entries.js +8 -2
  50. package/lib/citation/ui/entries.js.map +1 -1
  51. package/lib/citation/ui/useCopyFeedback.d.ts.map +1 -1
  52. package/lib/citation/ui/useCopyFeedback.js +9 -4
  53. package/lib/citation/ui/useCopyFeedback.js.map +1 -1
  54. package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
  55. package/lib/clipboard/ui/ClickToCopy.js +12 -6
  56. package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
  57. package/lib/clipboard/ui/CopyButton.d.ts +3 -3
  58. package/lib/clipboard/ui/CopyButton.d.ts.map +1 -1
  59. package/lib/clipboard/ui/CopyButton.js +7 -4
  60. package/lib/clipboard/ui/CopyButton.js.map +1 -1
  61. package/lib/color/ui/ColorScaleEditor.d.ts.map +1 -1
  62. package/lib/color/ui/ColorScaleEditor.js +15 -10
  63. package/lib/color/ui/ColorScaleEditor.js.map +1 -1
  64. package/lib/color/ui/ColorScaleEntry.d.ts.map +1 -1
  65. package/lib/color/ui/ColorScaleEntry.js +4 -2
  66. package/lib/color/ui/ColorScaleEntry.js.map +1 -1
  67. package/lib/color/ui/ColorScaleLegend.d.ts.map +1 -1
  68. package/lib/color/ui/ColorScaleLegend.js +7 -1
  69. package/lib/color/ui/ColorScaleLegend.js.map +1 -1
  70. package/lib/color/ui/ColorScaleSelect.d.ts.map +1 -1
  71. package/lib/color/ui/ColorScaleSelect.js +8 -4
  72. package/lib/color/ui/ColorScaleSelect.js.map +1 -1
  73. package/lib/confirm/ui/ConfirmButton.d.ts +2 -2
  74. package/lib/confirm/ui/ConfirmButton.d.ts.map +1 -1
  75. package/lib/confirm/ui/ConfirmButton.js +4 -2
  76. package/lib/confirm/ui/ConfirmButton.js.map +1 -1
  77. package/lib/core.d.ts +1 -0
  78. package/lib/core.d.ts.map +1 -1
  79. package/lib/core.js +1 -0
  80. package/lib/core.js.map +1 -1
  81. package/lib/credits/ui/CreditsList.d.ts.map +1 -1
  82. package/lib/credits/ui/CreditsList.js +3 -1
  83. package/lib/credits/ui/CreditsList.js.map +1 -1
  84. package/lib/delimited/ui/DelimitedTextDialog.d.ts.map +1 -1
  85. package/lib/delimited/ui/DelimitedTextDialog.js +5 -2
  86. package/lib/delimited/ui/DelimitedTextDialog.js.map +1 -1
  87. package/lib/delimited/ui/DelimitedTextPanel.d.ts.map +1 -1
  88. package/lib/delimited/ui/DelimitedTextPanel.js +8 -8
  89. package/lib/delimited/ui/DelimitedTextPanel.js.map +1 -1
  90. package/lib/download/ui/FigureDownload.d.ts +2 -2
  91. package/lib/download/ui/FigureDownload.d.ts.map +1 -1
  92. package/lib/download/ui/FigureDownload.js +4 -2
  93. package/lib/download/ui/FigureDownload.js.map +1 -1
  94. package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
  95. package/lib/download/ui/FigureDownloadPanel.js +24 -18
  96. package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
  97. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  98. package/lib/ecosystem/core/sites.js +4 -2
  99. package/lib/ecosystem/core/sites.js.map +1 -1
  100. package/lib/ecosystem/ui/EcosystemButton.d.ts +1 -1
  101. package/lib/ecosystem/ui/EcosystemButton.d.ts.map +1 -1
  102. package/lib/ecosystem/ui/EcosystemButton.js +4 -2
  103. package/lib/ecosystem/ui/EcosystemButton.js.map +1 -1
  104. package/lib/ecosystem/ui/EcosystemLinks.d.ts +1 -1
  105. package/lib/ecosystem/ui/EcosystemLinks.d.ts.map +1 -1
  106. package/lib/ecosystem/ui/EcosystemLinks.js +5 -2
  107. package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
  108. package/lib/ecosystem/ui/EcosystemMenu.d.ts.map +1 -1
  109. package/lib/ecosystem/ui/EcosystemMenu.js +3 -1
  110. package/lib/ecosystem/ui/EcosystemMenu.js.map +1 -1
  111. package/lib/ecosystem/ui/SiteGroupSection.d.ts.map +1 -1
  112. package/lib/ecosystem/ui/SiteGroupSection.js +3 -1
  113. package/lib/ecosystem/ui/SiteGroupSection.js.map +1 -1
  114. package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
  115. package/lib/ecosystem/ui/SiteTile.js +3 -1
  116. package/lib/ecosystem/ui/SiteTile.js.map +1 -1
  117. package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
  118. package/lib/ecosystem/ui/glyphs.js +6 -5
  119. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  120. package/lib/error/ui/ErrorFallback.d.ts +2 -2
  121. package/lib/error/ui/ErrorFallback.d.ts.map +1 -1
  122. package/lib/error/ui/ErrorFallback.js +4 -2
  123. package/lib/error/ui/ErrorFallback.js.map +1 -1
  124. package/lib/help/ui/HelpBody.d.ts.map +1 -1
  125. package/lib/help/ui/HelpBody.js +3 -1
  126. package/lib/help/ui/HelpBody.js.map +1 -1
  127. package/lib/help/ui/HelpIcon.d.ts +2 -1
  128. package/lib/help/ui/HelpIcon.d.ts.map +1 -1
  129. package/lib/help/ui/HelpIcon.js +4 -2
  130. package/lib/help/ui/HelpIcon.js.map +1 -1
  131. package/lib/help/ui/HelpToolbarButton.d.ts.map +1 -1
  132. package/lib/help/ui/HelpToolbarButton.js +3 -1
  133. package/lib/help/ui/HelpToolbarButton.js.map +1 -1
  134. package/lib/help/ui/helpName.d.ts +5 -1
  135. package/lib/help/ui/helpName.d.ts.map +1 -1
  136. package/lib/help/ui/helpName.js +4 -2
  137. package/lib/help/ui/helpName.js.map +1 -1
  138. package/lib/i18n/core/chromeCatalog.d.ts +21 -0
  139. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -0
  140. package/lib/i18n/core/chromeCatalog.js +29 -0
  141. package/lib/i18n/core/chromeCatalog.js.map +1 -0
  142. package/lib/i18n/core/index.d.ts +12 -0
  143. package/lib/i18n/core/index.d.ts.map +1 -0
  144. package/lib/i18n/core/index.js +6 -0
  145. package/lib/i18n/core/index.js.map +1 -0
  146. package/lib/i18n/core/languages.d.ts +32 -0
  147. package/lib/i18n/core/languages.d.ts.map +1 -0
  148. package/lib/i18n/core/languages.js +41 -0
  149. package/lib/i18n/core/languages.js.map +1 -0
  150. package/lib/i18n/core/messageCatalog.d.ts +113 -0
  151. package/lib/i18n/core/messageCatalog.d.ts.map +1 -0
  152. package/lib/i18n/core/messageCatalog.js +135 -0
  153. package/lib/i18n/core/messageCatalog.js.map +1 -0
  154. package/lib/i18n/core/messageValues.d.ts +3 -0
  155. package/lib/i18n/core/messageValues.d.ts.map +1 -0
  156. package/lib/i18n/core/messageValues.js +2 -0
  157. package/lib/i18n/core/messageValues.js.map +1 -0
  158. package/lib/i18n/core/session.d.ts +51 -0
  159. package/lib/i18n/core/session.d.ts.map +1 -0
  160. package/lib/i18n/core/session.js +64 -0
  161. package/lib/i18n/core/session.js.map +1 -0
  162. package/lib/i18n/core/translateSetup.d.ts +28 -0
  163. package/lib/i18n/core/translateSetup.d.ts.map +1 -0
  164. package/lib/i18n/core/translateSetup.js +30 -0
  165. package/lib/i18n/core/translateSetup.js.map +1 -0
  166. package/lib/i18n/ui/LanguageSelect.d.ts +37 -0
  167. package/lib/i18n/ui/LanguageSelect.d.ts.map +1 -0
  168. package/lib/i18n/ui/LanguageSelect.js +27 -0
  169. package/lib/i18n/ui/LanguageSelect.js.map +1 -0
  170. package/lib/i18n/ui/index.d.ts +6 -0
  171. package/lib/i18n/ui/index.d.ts.map +1 -0
  172. package/lib/i18n/ui/index.js +4 -0
  173. package/lib/i18n/ui/index.js.map +1 -0
  174. package/lib/i18n/ui/useLanguage.d.ts +23 -0
  175. package/lib/i18n/ui/useLanguage.d.ts.map +1 -0
  176. package/lib/i18n/ui/useLanguage.js +36 -0
  177. package/lib/i18n/ui/useLanguage.js.map +1 -0
  178. package/lib/i18n/ui/useT.d.ts +47 -0
  179. package/lib/i18n/ui/useT.d.ts.map +1 -0
  180. package/lib/i18n/ui/useT.js +51 -0
  181. package/lib/i18n/ui/useT.js.map +1 -0
  182. package/lib/locales/de.json +442 -0
  183. package/lib/locales/en.json +442 -0
  184. package/lib/locales/es.json +442 -0
  185. package/lib/locales/fr.json +442 -0
  186. package/lib/molecule3d/core/gestures.d.ts +10 -0
  187. package/lib/molecule3d/core/gestures.d.ts.map +1 -1
  188. package/lib/molecule3d/core/gestures.js +39 -7
  189. package/lib/molecule3d/core/gestures.js.map +1 -1
  190. package/lib/molecule3d/ui/Molecule3DExport.d.ts.map +1 -1
  191. package/lib/molecule3d/ui/Molecule3DExport.js +3 -1
  192. package/lib/molecule3d/ui/Molecule3DExport.js.map +1 -1
  193. package/lib/molecule3d/ui/Molecule3DHelp.d.ts.map +1 -1
  194. package/lib/molecule3d/ui/Molecule3DHelp.js +7 -2
  195. package/lib/molecule3d/ui/Molecule3DHelp.js.map +1 -1
  196. package/lib/molecule3d/ui/Molecule3DOptions.d.ts.map +1 -1
  197. package/lib/molecule3d/ui/Molecule3DOptions.js +9 -9
  198. package/lib/molecule3d/ui/Molecule3DOptions.js.map +1 -1
  199. package/lib/molecule3d/ui/Molecule3DSurfaceColors.d.ts.map +1 -1
  200. package/lib/molecule3d/ui/Molecule3DSurfaceColors.js +8 -8
  201. package/lib/molecule3d/ui/Molecule3DSurfaceColors.js.map +1 -1
  202. package/lib/molecule3d/ui/Molecule3DToolbar.d.ts.map +1 -1
  203. package/lib/molecule3d/ui/Molecule3DToolbar.js +15 -10
  204. package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
  205. package/lib/molecule3d/ui/MoleculeViewer3D.d.ts.map +1 -1
  206. package/lib/molecule3d/ui/MoleculeViewer3D.js +6 -3
  207. package/lib/molecule3d/ui/MoleculeViewer3D.js.map +1 -1
  208. package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts.map +1 -1
  209. package/lib/orbital/ui/AtomicOrbitalCanvas.js +3 -1
  210. package/lib/orbital/ui/AtomicOrbitalCanvas.js.map +1 -1
  211. package/lib/orbital/ui/AtomicOrbitalControls.d.ts.map +1 -1
  212. package/lib/orbital/ui/AtomicOrbitalControls.js +12 -15
  213. package/lib/orbital/ui/AtomicOrbitalControls.js.map +1 -1
  214. package/lib/orbital/ui/AtomicOrbitalViewer.d.ts.map +1 -1
  215. package/lib/orbital/ui/AtomicOrbitalViewer.js +6 -3
  216. package/lib/orbital/ui/AtomicOrbitalViewer.js.map +1 -1
  217. package/lib/orbital/ui/capability.d.ts +4 -0
  218. package/lib/orbital/ui/capability.d.ts.map +1 -1
  219. package/lib/orbital/ui/capability.js +4 -0
  220. package/lib/orbital/ui/capability.js.map +1 -1
  221. package/lib/overlay/ui/OverlayBar.d.ts +1 -1
  222. package/lib/overlay/ui/OverlayBar.d.ts.map +1 -1
  223. package/lib/overlay/ui/OverlayBar.js +6 -3
  224. package/lib/overlay/ui/OverlayBar.js.map +1 -1
  225. package/lib/overlay/ui/OverlayInfo.d.ts +1 -1
  226. package/lib/overlay/ui/OverlayInfo.d.ts.map +1 -1
  227. package/lib/overlay/ui/OverlayInfo.js +5 -2
  228. package/lib/overlay/ui/OverlayInfo.js.map +1 -1
  229. package/lib/overlay/ui/OverlayPanel.d.ts +9 -2
  230. package/lib/overlay/ui/OverlayPanel.d.ts.map +1 -1
  231. package/lib/overlay/ui/OverlayPanel.js +5 -11
  232. package/lib/overlay/ui/OverlayPanel.js.map +1 -1
  233. package/lib/overlay/ui/OverlayReadout.d.ts.map +1 -1
  234. package/lib/overlay/ui/OverlayReadout.js +3 -1
  235. package/lib/overlay/ui/OverlayReadout.js.map +1 -1
  236. package/lib/pedagogy/ui/ExerciseActions.d.ts +1 -1
  237. package/lib/pedagogy/ui/ExerciseActions.d.ts.map +1 -1
  238. package/lib/pedagogy/ui/ExerciseActions.js +9 -2
  239. package/lib/pedagogy/ui/ExerciseActions.js.map +1 -1
  240. package/lib/pedagogy/ui/ExerciseProgressHeader.d.ts +1 -1
  241. package/lib/pedagogy/ui/ExerciseProgressHeader.d.ts.map +1 -1
  242. package/lib/pedagogy/ui/ExerciseProgressHeader.js +9 -5
  243. package/lib/pedagogy/ui/ExerciseProgressHeader.js.map +1 -1
  244. package/lib/pedagogy/ui/GlossaryIndex.d.ts +1 -1
  245. package/lib/pedagogy/ui/GlossaryIndex.d.ts.map +1 -1
  246. package/lib/pedagogy/ui/GlossaryIndex.js +6 -8
  247. package/lib/pedagogy/ui/GlossaryIndex.js.map +1 -1
  248. package/lib/pedagogy/ui/HintLadder.d.ts +2 -2
  249. package/lib/pedagogy/ui/HintLadder.d.ts.map +1 -1
  250. package/lib/pedagogy/ui/HintLadder.js +8 -2
  251. package/lib/pedagogy/ui/HintLadder.js.map +1 -1
  252. package/lib/pedagogy/ui/SyntaxTooltip.d.ts +4 -4
  253. package/lib/pedagogy/ui/SyntaxTooltip.d.ts.map +1 -1
  254. package/lib/pedagogy/ui/SyntaxTooltip.js +4 -2
  255. package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
  256. package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
  257. package/lib/pedagogy/ui/TutorialStepStrip.js +7 -2
  258. package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
  259. package/lib/periodic/ui/CategoryLegend.d.ts.map +1 -1
  260. package/lib/periodic/ui/CategoryLegend.js +3 -1
  261. package/lib/periodic/ui/CategoryLegend.js.map +1 -1
  262. package/lib/periodic/ui/ElementCell.d.ts.map +1 -1
  263. package/lib/periodic/ui/ElementCell.js +7 -1
  264. package/lib/periodic/ui/ElementCell.js.map +1 -1
  265. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  266. package/lib/periodic/ui/PeriodicTable.js +3 -1
  267. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  268. package/lib/periodic/ui/PeriodicTableChrome.d.ts.map +1 -1
  269. package/lib/periodic/ui/PeriodicTableChrome.js +4 -2
  270. package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -1
  271. package/lib/share/ui/ShareButton.d.ts +2 -2
  272. package/lib/share/ui/ShareButton.d.ts.map +1 -1
  273. package/lib/share/ui/ShareButton.js +5 -2
  274. package/lib/share/ui/ShareButton.js.map +1 -1
  275. package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
  276. package/lib/share/ui/ShareConfigOptions.js +4 -2
  277. package/lib/share/ui/ShareConfigOptions.js.map +1 -1
  278. package/lib/share/ui/ShareDialog.d.ts.map +1 -1
  279. package/lib/share/ui/ShareDialog.js +3 -1
  280. package/lib/share/ui/ShareDialog.js.map +1 -1
  281. package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
  282. package/lib/share/ui/ShareDialogContent.js +10 -1
  283. package/lib/share/ui/ShareDialogContent.js.map +1 -1
  284. package/lib/share/ui/SharePresetTabs.d.ts.map +1 -1
  285. package/lib/share/ui/SharePresetTabs.js +3 -1
  286. package/lib/share/ui/SharePresetTabs.js.map +1 -1
  287. package/lib/slides/ui/BackToSlides.d.ts.map +1 -1
  288. package/lib/slides/ui/BackToSlides.js +4 -2
  289. package/lib/slides/ui/BackToSlides.js.map +1 -1
  290. package/lib/slides/ui/EmbedSlide.d.ts.map +1 -1
  291. package/lib/slides/ui/EmbedSlide.js +3 -1
  292. package/lib/slides/ui/EmbedSlide.js.map +1 -1
  293. package/lib/slides/ui/Slide.d.ts.map +1 -1
  294. package/lib/slides/ui/Slide.js +3 -1
  295. package/lib/slides/ui/Slide.js.map +1 -1
  296. package/lib/slides/ui/SlideshowBar.d.ts.map +1 -1
  297. package/lib/slides/ui/SlideshowBar.js +5 -3
  298. package/lib/slides/ui/SlideshowBar.js.map +1 -1
  299. package/lib/slides/ui/TalkList.d.ts +1 -1
  300. package/lib/slides/ui/TalkList.d.ts.map +1 -1
  301. package/lib/slides/ui/TalkList.js +4 -2
  302. package/lib/slides/ui/TalkList.js.map +1 -1
  303. package/lib/structure/core/editorGuide.d.ts +14 -0
  304. package/lib/structure/core/editorGuide.d.ts.map +1 -1
  305. package/lib/structure/core/editorGuide.js +117 -19
  306. package/lib/structure/core/editorGuide.js.map +1 -1
  307. package/lib/structure/core/editorToolbar.d.ts +3 -1
  308. package/lib/structure/core/editorToolbar.d.ts.map +1 -1
  309. package/lib/structure/core/editorToolbar.js +44 -23
  310. package/lib/structure/core/editorToolbar.js.map +1 -1
  311. package/lib/structure/ui/EditorHelpButton.d.ts.map +1 -1
  312. package/lib/structure/ui/EditorHelpButton.js +3 -2
  313. package/lib/structure/ui/EditorHelpButton.js.map +1 -1
  314. package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
  315. package/lib/structure/ui/StructureEditor.js +3 -1
  316. package/lib/structure/ui/StructureEditor.js.map +1 -1
  317. package/lib/structure/ui/StructureEditorHelp.d.ts.map +1 -1
  318. package/lib/structure/ui/StructureEditorHelp.js +12 -3
  319. package/lib/structure/ui/StructureEditorHelp.js.map +1 -1
  320. package/lib/structure/ui/ToolbarTooltip.d.ts.map +1 -1
  321. package/lib/structure/ui/ToolbarTooltip.js +5 -3
  322. package/lib/structure/ui/ToolbarTooltip.js.map +1 -1
  323. package/lib/translate/core/index.d.ts +1 -1
  324. package/lib/translate/core/index.d.ts.map +1 -1
  325. package/lib/translate/core/start.d.ts +35 -2
  326. package/lib/translate/core/start.d.ts.map +1 -1
  327. package/lib/translate/core/start.js +23 -4
  328. package/lib/translate/core/start.js.map +1 -1
  329. package/lib/ui.d.ts +1 -0
  330. package/lib/ui.d.ts.map +1 -1
  331. package/lib/ui.js +1 -0
  332. package/lib/ui.js.map +1 -1
  333. package/package.json +4 -2
  334. package/src/about/ui/AboutBuild.tsx +23 -16
  335. package/src/about/ui/AboutCitations.tsx +3 -1
  336. package/src/about/ui/AboutPage.tsx +38 -12
  337. package/src/about/ui/AboutProvidedBy.tsx +13 -3
  338. package/src/capsule/ui/Capsule.tsx +48 -0
  339. package/src/capsule/ui/CapsuleFilter.tsx +38 -114
  340. package/src/capsule/ui/capsuleFilterCapsules.tsx +110 -0
  341. package/src/chart/ui/ChartTrackingLayer.tsx +4 -2
  342. package/src/chrome/ui/SiteHeader.tsx +5 -3
  343. package/src/citation/ui/CitationMenu.tsx +9 -5
  344. package/src/citation/ui/CiteButton.tsx +4 -2
  345. package/src/citation/ui/CopyFormatEntries.tsx +3 -1
  346. package/src/citation/ui/WorkEntry.tsx +5 -3
  347. package/src/citation/ui/entries.tsx +9 -2
  348. package/src/citation/ui/useCopyFeedback.ts +11 -4
  349. package/src/clipboard/ui/ClickToCopy.tsx +15 -5
  350. package/src/clipboard/ui/CopyButton.tsx +14 -10
  351. package/src/color/ui/ColorScaleEditor.tsx +17 -15
  352. package/src/color/ui/ColorScaleEntry.tsx +7 -3
  353. package/src/color/ui/ColorScaleLegend.tsx +7 -1
  354. package/src/color/ui/ColorScaleSelect.tsx +12 -6
  355. package/src/confirm/ui/ConfirmButton.tsx +9 -11
  356. package/src/core.ts +1 -0
  357. package/src/credits/ui/CreditsList.tsx +5 -1
  358. package/src/delimited/ui/DelimitedTextDialog.tsx +10 -10
  359. package/src/delimited/ui/DelimitedTextPanel.tsx +19 -12
  360. package/src/download/ui/FigureDownload.tsx +7 -5
  361. package/src/download/ui/FigureDownloadPanel.tsx +31 -25
  362. package/src/ecosystem/core/sites.ts +4 -2
  363. package/src/ecosystem/ui/EcosystemButton.tsx +5 -3
  364. package/src/ecosystem/ui/EcosystemLinks.tsx +10 -10
  365. package/src/ecosystem/ui/EcosystemMenu.tsx +3 -1
  366. package/src/ecosystem/ui/SiteGroupSection.tsx +6 -2
  367. package/src/ecosystem/ui/SiteTile.tsx +6 -2
  368. package/src/ecosystem/ui/glyphs.tsx +16 -22
  369. package/src/error/ui/ErrorFallback.tsx +13 -12
  370. package/src/help/ui/HelpBody.tsx +4 -2
  371. package/src/help/ui/HelpIcon.tsx +6 -3
  372. package/src/help/ui/HelpToolbarButton.tsx +4 -1
  373. package/src/help/ui/helpName.ts +10 -2
  374. package/src/i18n/core/chromeCatalog.ts +35 -0
  375. package/src/i18n/core/index.ts +26 -0
  376. package/src/i18n/core/languages.ts +46 -0
  377. package/src/i18n/core/messageCatalog.ts +202 -0
  378. package/src/i18n/core/messageValues.ts +2 -0
  379. package/src/i18n/core/session.ts +82 -0
  380. package/src/i18n/core/translateSetup.ts +47 -0
  381. package/src/i18n/ui/LanguageSelect.tsx +72 -0
  382. package/src/i18n/ui/index.ts +9 -0
  383. package/src/i18n/ui/useLanguage.ts +48 -0
  384. package/src/i18n/ui/useT.ts +90 -0
  385. package/src/locales/de.json +442 -0
  386. package/src/locales/en.json +442 -0
  387. package/src/locales/es.json +442 -0
  388. package/src/locales/fr.json +442 -0
  389. package/src/molecule3d/core/gestures.ts +44 -7
  390. package/src/molecule3d/ui/Molecule3DExport.tsx +3 -1
  391. package/src/molecule3d/ui/Molecule3DHelp.tsx +17 -6
  392. package/src/molecule3d/ui/Molecule3DOptions.tsx +13 -13
  393. package/src/molecule3d/ui/Molecule3DSurfaceColors.tsx +16 -13
  394. package/src/molecule3d/ui/Molecule3DToolbar.tsx +29 -18
  395. package/src/molecule3d/ui/MoleculeViewer3D.tsx +13 -8
  396. package/src/orbital/ui/AtomicOrbitalCanvas.tsx +3 -1
  397. package/src/orbital/ui/AtomicOrbitalControls.tsx +15 -20
  398. package/src/orbital/ui/AtomicOrbitalViewer.tsx +13 -13
  399. package/src/orbital/ui/capability.ts +10 -0
  400. package/src/overlay/ui/OverlayBar.tsx +7 -4
  401. package/src/overlay/ui/OverlayInfo.tsx +6 -3
  402. package/src/overlay/ui/OverlayPanel.tsx +10 -7
  403. package/src/overlay/ui/OverlayReadout.tsx +3 -1
  404. package/src/pedagogy/ui/ExerciseActions.tsx +16 -6
  405. package/src/pedagogy/ui/ExerciseProgressHeader.tsx +13 -11
  406. package/src/pedagogy/ui/GlossaryIndex.tsx +11 -12
  407. package/src/pedagogy/ui/HintLadder.tsx +15 -12
  408. package/src/pedagogy/ui/SyntaxTooltip.tsx +9 -7
  409. package/src/pedagogy/ui/TutorialStepStrip.tsx +8 -3
  410. package/src/periodic/ui/CategoryLegend.tsx +6 -1
  411. package/src/periodic/ui/ElementCell.tsx +7 -1
  412. package/src/periodic/ui/PeriodicTable.tsx +3 -1
  413. package/src/periodic/ui/PeriodicTableChrome.tsx +4 -2
  414. package/src/share/ui/ShareButton.tsx +8 -5
  415. package/src/share/ui/ShareConfigOptions.tsx +6 -7
  416. package/src/share/ui/ShareDialog.tsx +3 -1
  417. package/src/share/ui/ShareDialogContent.tsx +20 -10
  418. package/src/share/ui/SharePresetTabs.tsx +3 -1
  419. package/src/slides/ui/BackToSlides.tsx +4 -2
  420. package/src/slides/ui/EmbedSlide.tsx +3 -3
  421. package/src/slides/ui/Slide.tsx +3 -1
  422. package/src/slides/ui/SlideshowBar.tsx +12 -4
  423. package/src/slides/ui/TalkList.tsx +8 -10
  424. package/src/structure/core/editorGuide.ts +126 -19
  425. package/src/structure/core/editorToolbar.ts +52 -24
  426. package/src/structure/ui/EditorHelpButton.tsx +9 -4
  427. package/src/structure/ui/StructureEditor.tsx +7 -1
  428. package/src/structure/ui/StructureEditorHelp.tsx +34 -11
  429. package/src/structure/ui/ToolbarTooltip.tsx +8 -4
  430. package/src/translate/core/index.ts +1 -1
  431. package/src/translate/core/start.ts +65 -3
  432. package/src/ui.ts +1 -0
@@ -3,6 +3,7 @@ import type { CSSProperties, ReactElement, ReactNode } from 'react';
3
3
  import { CreditsList } from '../../credits/ui/CreditsList.tsx';
4
4
  import { Wordmark } from '../../ecosystem/ui/Wordmark.tsx';
5
5
  import { SiteMark } from '../../ecosystem/ui/marks.tsx';
6
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
7
  import type { AboutContent } from '../core/about.ts';
7
8
  import { resolveAbout } from '../core/about.ts';
8
9
 
@@ -58,6 +59,7 @@ export interface AboutPageProps {
58
59
  */
59
60
  export function AboutPage(props: AboutPageProps): ReactElement {
60
61
  const { content, className, children, logo, mark } = props;
62
+ const t = useChromeT();
61
63
  const about = resolveAbout(content);
62
64
  const site = about.site;
63
65
 
@@ -76,7 +78,9 @@ export function AboutPage(props: AboutPageProps): ReactElement {
76
78
  <h1 style={logo === undefined ? NAME_STYLE : LOGO_NAME_STYLE}>
77
79
  {logo ?? <Wordmark site={site} size={26} />}
78
80
  </h1>
79
- <p style={TAGLINE_STYLE}>{site.tagline}</p>
81
+ <p style={TAGLINE_STYLE}>
82
+ {t.or(`site.${site.id}.tagline`, site.tagline)}
83
+ </p>
80
84
  <p style={WHAT_STYLE}>{about.what}</p>
81
85
  </div>
82
86
  <AboutVersion
@@ -87,12 +91,15 @@ export function AboutPage(props: AboutPageProps): ReactElement {
87
91
  </header>
88
92
 
89
93
  {about.people.length === 0 && about.providedBy.length === 0 ? null : (
90
- <AboutSection title="Provided by" className="about-provided-by">
94
+ <AboutSection
95
+ title={t('about.providedBy')}
96
+ className="about-provided-by"
97
+ >
91
98
  <AboutProvidedBy people={about.people} providers={about.providedBy} />
92
99
  </AboutSection>
93
100
  )}
94
101
 
95
- <AboutSection title="What you can do here" className="about-can">
102
+ <AboutSection title={t('about.whatYouCanDo')} className="about-can">
96
103
  <ul style={CAN_LIST_STYLE}>
97
104
  {about.can.map((line) => (
98
105
  <li key={line}>{line}</li>
@@ -115,12 +122,12 @@ export function AboutPage(props: AboutPageProps): ReactElement {
115
122
 
116
123
  {children}
117
124
 
118
- <AboutSection title="Built on" className="about-credits">
125
+ <AboutSection title={t('about.builtOn')} className="about-credits">
119
126
  <CreditsList entries={about.credits} />
120
127
  </AboutSection>
121
128
 
122
129
  {about.cite.length === 0 ? null : (
123
- <AboutSection title="How to cite" className="about-cite">
130
+ <AboutSection title={t('about.howToCite')} className="about-cite">
124
131
  <AboutCitations works={about.cite} />
125
132
  </AboutSection>
126
133
  )}
@@ -131,11 +138,16 @@ export function AboutPage(props: AboutPageProps): ReactElement {
131
138
  The version stays in the hero, unlinked, so a report still names a build.
132
139
  */}
133
140
  {!about.publicRepository ? null : (
134
- <AboutSection title="Licence and source" className="about-licence">
141
+ <AboutSection
142
+ title={t('about.licenceAndSource')}
143
+ className="about-licence"
144
+ >
135
145
  <p style={FIRST_PARAGRAPH_STYLE}>
136
- {about.license}, © cheminfo. Use it in a course, fork it, or lift a
137
- piece of it into something else. The sources are at{' '}
138
- <ExternalLink href={about.repository} />.
146
+ {around(
147
+ t('about.licence', { license: about.license }),
148
+ 'sources',
149
+ <ExternalLink key="sources" href={about.repository} />,
150
+ )}
139
151
  </p>
140
152
  {about.build === undefined ? null : (
141
153
  <AboutBuild build={about.build} repository={about.repository} />
@@ -148,10 +160,13 @@ export function AboutPage(props: AboutPageProps): ReactElement {
148
160
  the tracker of a private repository answers 404 to every visitor.
149
161
  */}
150
162
  {about.issues === undefined ? null : (
151
- <AboutSection title="Found a problem?" className="about-issues">
163
+ <AboutSection title={t('about.foundAProblem')} className="about-issues">
152
164
  <p style={FIRST_PARAGRAPH_STYLE}>
153
- Tell us: a report naming what you typed and what came back is the
154
- fastest fix there is. <ExternalLink href={about.issues} />.
165
+ {around(
166
+ t('about.reportIt'),
167
+ 'tracker',
168
+ <ExternalLink key="tracker" href={about.issues} />,
169
+ )}
155
170
  </p>
156
171
  </AboutSection>
157
172
  )}
@@ -159,6 +174,17 @@ export function AboutPage(props: AboutPageProps): ReactElement {
159
174
  );
160
175
  }
161
176
 
177
+ // A link sits inside a sentence whose word order is the translator's, so the
178
+ // message names where it goes with a placeholder and is split there.
179
+ function around(
180
+ message: string,
181
+ placeholder: string,
182
+ link: ReactNode,
183
+ ): ReactNode[] {
184
+ const [before = '', after = ''] = message.split(`{${placeholder}}`);
185
+ return [before, link, after];
186
+ }
187
+
162
188
  function ExternalLink(props: { href: string }): ReactElement {
163
189
  const { href } = props;
164
190
 
@@ -1,5 +1,8 @@
1
1
  import type { CSSProperties, ReactElement } from 'react';
2
2
 
3
+ import type { ChromeKey } from '../../i18n/core/chromeCatalog.ts';
4
+ import type { Translate } from '../../i18n/ui/useT.ts';
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
3
6
  import type { AboutPerson } from '../core/about.ts';
4
7
  import type { ProviderEntry } from '../core/providers.ts';
5
8
 
@@ -19,6 +22,7 @@ export interface AboutProvidedByProps {
19
22
  */
20
23
  export function AboutProvidedBy(props: AboutProvidedByProps): ReactElement {
21
24
  const { people, providers } = props;
25
+ const t = useChromeT();
22
26
  const withRoles = people.filter((person) => person.role !== undefined);
23
27
 
24
28
  return (
@@ -42,7 +46,7 @@ export function AboutProvidedBy(props: AboutProvidedByProps): ReactElement {
42
46
  }
43
47
  >
44
48
  {people.length === 0 ? null : (
45
- <p style={NAMES_STYLE}>{joinNames(people)}</p>
49
+ <p style={NAMES_STYLE}>{joinNames(people, t)}</p>
46
50
  )}
47
51
  {providers.map((provider) => (
48
52
  <p key={provider.id} style={INSTITUTION_STYLE}>
@@ -65,10 +69,16 @@ export function AboutProvidedBy(props: AboutProvidedByProps): ReactElement {
65
69
  );
66
70
  }
67
71
 
68
- function joinNames(people: readonly AboutPerson[]): string {
72
+ function joinNames(
73
+ people: readonly AboutPerson[],
74
+ t: Translate<ChromeKey>,
75
+ ): string {
69
76
  const names = people.map((person) => person.name);
70
77
  if (names.length < 2) return names.join('');
71
- return `${names.slice(0, -1).join(', ')} and ${names.at(-1)}`;
78
+ return t('about.nameList', {
79
+ names: names.slice(0, -1).join(', '),
80
+ last: names.at(-1) ?? '',
81
+ });
72
82
  }
73
83
 
74
84
  function ProviderLogo(props: { provider: ProviderEntry }): ReactElement {
@@ -0,0 +1,48 @@
1
+ /**
2
+ * One capsule of a filter row: an interactive tag that keeps its semantic
3
+ * colour whether or not it is selected, the filled shape being what encodes
4
+ * the selection.
5
+ */
6
+
7
+ import type { Intent } from '@blueprintjs/core';
8
+ import { Tag } from '@blueprintjs/core';
9
+ import type { ReactElement } from 'react';
10
+
11
+ /** What one capsule needs. */
12
+ export interface CapsuleProps {
13
+ /** What the capsule reads, count included. */
14
+ text: string;
15
+ /** Whether it is filled. */
16
+ selected: boolean;
17
+ /**
18
+ * Colour of the capsule, which says what the outcome means.
19
+ * @default undefined — the capsule takes no intent
20
+ */
21
+ intent?: Intent;
22
+ /** What the pointer is told, or `undefined` for no title at all. */
23
+ title: string | undefined;
24
+ /** Called when the capsule is picked. */
25
+ onClick: () => void;
26
+ }
27
+
28
+ /**
29
+ * One capsule.
30
+ * @param props - See {@link CapsuleProps}.
31
+ * @returns The tag.
32
+ */
33
+ export function Capsule(props: CapsuleProps): ReactElement {
34
+ const { text, selected, intent, title, onClick } = props;
35
+ return (
36
+ <Tag
37
+ interactive
38
+ round
39
+ minimal={!selected}
40
+ intent={intent}
41
+ aria-pressed={selected}
42
+ htmlTitle={title}
43
+ onClick={onClick}
44
+ >
45
+ {text}
46
+ </Tag>
47
+ );
48
+ }
@@ -1,9 +1,11 @@
1
1
  import type { Intent } from '@blueprintjs/core';
2
- import { Tag } from '@blueprintjs/core';
3
- import type { CSSProperties, ReactElement } from 'react';
2
+ import type { CSSProperties, ReactElement, ReactNode } from 'react';
4
3
 
5
- import { formatInteger } from '../../format/core/numbers.ts';
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
5
  import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
6
+ import { TOKEN } from '../../tokens/core/familyTokens.ts';
7
+
8
+ import { capsuleFilterCapsules } from './capsuleFilterCapsules.tsx';
7
9
 
8
10
  /** One capsule of a {@link CapsuleFilter} row. */
9
11
  export interface CapsuleOption<TValue extends string = string> {
@@ -43,6 +45,13 @@ export interface CapsuleAllOption {
43
45
  * @default undefined
44
46
  */
45
47
  title?: string;
48
+ /**
49
+ * Whether the capsule is filled, for a row that reads its selection back
50
+ * from a richer state: a pick no capsule can spell leaves `values` empty
51
+ * without meaning every row is kept.
52
+ * @default undefined — filled while no capsule is selected
53
+ */
54
+ selected?: boolean;
46
55
  }
47
56
 
48
57
  /** What every row of filter capsules needs, whatever it selects. */
@@ -51,7 +60,7 @@ export interface CapsuleFilterBaseProps<TValue extends string = string> {
51
60
  options: ReadonlyArray<CapsuleOption<TValue>>;
52
61
  /**
53
62
  * What the group is called, for a screen reader reaching the row.
54
- * @default 'Filter'
63
+ * @default the chrome's own word for it, in the language of the page
55
64
  */
56
65
  label?: string;
57
66
  /**
@@ -64,6 +73,14 @@ export interface CapsuleFilterBaseProps<TValue extends string = string> {
64
73
  * @default undefined
65
74
  */
66
75
  className?: string;
76
+ /**
77
+ * What the row reads back, drawn muted after the last capsule: the selection
78
+ * the capsules cannot spell on their own, or how else it is made. It wraps
79
+ * with them rather than sitting on a line of its own, so the one place a
80
+ * selection is made is the one place it is read.
81
+ * @default undefined — the row is capsules alone
82
+ */
83
+ note?: ReactNode;
67
84
  }
68
85
 
69
86
  /** A row where exactly one capsule is selected. */
@@ -109,136 +126,43 @@ export type CapsuleFilterProps<TValue extends string = string> =
109
126
  * Every capsule keeps its semantic colour whether or not it is selected, so
110
127
  * what a status means stays learnable — the filled shape is what encodes the
111
128
  * selection. Each is a real interactive tag, so the row is reachable by tab and
112
- * a capsule answers to Enter and Space.
129
+ * a capsule answers to Enter and Space. A `note` rides at the end of the row,
130
+ * which is where a selection finer than the capsules can spell is read back.
113
131
  * @param props - See {@link CapsuleFilterProps}.
114
132
  * @returns The capsule row.
115
133
  */
116
134
  export function CapsuleFilter<TValue extends string = string>(
117
135
  props: CapsuleFilterProps<TValue>,
118
136
  ): ReactElement {
119
- const capsules =
120
- props.multiple === true ? multipleCapsules(props) : singleCapsules(props);
121
- const { label = 'Filter', className } = props;
137
+ const { label, className, note } = props;
138
+ const t = useChromeT();
122
139
 
123
140
  return (
124
141
  <div
125
142
  role="group"
126
- aria-label={label}
143
+ aria-label={label ?? t('capsule.filter')}
127
144
  className={joinClassNames('capsule-filter', className)}
128
145
  style={ROW_STYLE}
129
146
  >
130
- {capsules}
147
+ {capsuleFilterCapsules(props)}
148
+ {note === undefined ? null : (
149
+ <span className="capsule-filter__note" style={NOTE_STYLE}>
150
+ {note}
151
+ </span>
152
+ )}
131
153
  </div>
132
154
  );
133
155
  }
134
156
 
135
- function singleCapsules<TValue extends string>(
136
- props: SingleCapsuleFilterProps<TValue>,
137
- ): ReactElement[] {
138
- const { options, value, onChange, formatCount = formatInteger } = props;
139
- const capsules: ReactElement[] = [];
140
- for (const option of options) {
141
- capsules.push(
142
- <Capsule
143
- key={`option:${option.value}`}
144
- text={capsuleText(option, formatCount)}
145
- selected={option.value === value}
146
- intent={option.intent}
147
- title={option.title}
148
- onClick={() => onChange(option.value)}
149
- />,
150
- );
151
- }
152
- return capsules;
153
- }
154
-
155
- function multipleCapsules<TValue extends string>(
156
- props: MultipleCapsuleFilterProps<TValue>,
157
- ): ReactElement[] {
158
- const {
159
- options,
160
- values,
161
- onChange,
162
- allOption,
163
- formatCount = formatInteger,
164
- } = props;
165
- const capsules: ReactElement[] = [];
166
- if (allOption !== undefined) {
167
- capsules.push(
168
- <Capsule
169
- key="all"
170
- text={capsuleText(allOption, formatCount)}
171
- selected={values.length === 0}
172
- title={allOption.title}
173
- onClick={() => onChange([])}
174
- />,
175
- );
176
- }
177
- for (const option of options) {
178
- capsules.push(
179
- <Capsule
180
- key={`option:${option.value}`}
181
- text={capsuleText(option, formatCount)}
182
- selected={values.includes(option.value)}
183
- intent={option.intent}
184
- title={option.title}
185
- onClick={() => onChange(toggled(options, values, option.value))}
186
- />,
187
- );
188
- }
189
- return capsules;
190
- }
191
-
192
- interface CapsuleProps {
193
- text: string;
194
- selected: boolean;
195
- intent?: Intent;
196
- title: string | undefined;
197
- onClick: () => void;
198
- }
199
-
200
- function Capsule(props: CapsuleProps): ReactElement {
201
- const { text, selected, intent, title, onClick } = props;
202
- return (
203
- <Tag
204
- interactive
205
- round
206
- minimal={!selected}
207
- intent={intent}
208
- aria-pressed={selected}
209
- htmlTitle={title}
210
- onClick={onClick}
211
- >
212
- {text}
213
- </Tag>
214
- );
215
- }
216
-
217
- function capsuleText(
218
- capsule: { label: string; count?: number },
219
- formatCount: (count: number) => string,
220
- ): string {
221
- return capsule.count === undefined
222
- ? capsule.label
223
- : `${capsule.label} (${formatCount(capsule.count)})`;
224
- }
225
-
226
- function toggled<TValue extends string>(
227
- options: ReadonlyArray<CapsuleOption<TValue>>,
228
- values: readonly TValue[],
229
- flipped: TValue,
230
- ): TValue[] {
231
- const next: TValue[] = [];
232
- for (const option of options) {
233
- const kept = values.includes(option.value);
234
- if (option.value === flipped ? !kept : kept) next.push(option.value);
235
- }
236
- return next;
237
- }
238
-
239
157
  const ROW_STYLE = {
240
158
  display: 'flex',
241
159
  flexWrap: 'wrap',
242
160
  alignItems: 'center',
243
161
  gap: 6,
244
162
  } as const satisfies CSSProperties;
163
+
164
+ const NOTE_STYLE = {
165
+ marginLeft: 2,
166
+ color: TOKEN.textMuted,
167
+ fontSize: '0.75rem',
168
+ } as const satisfies CSSProperties;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The capsules of a filter row, and nothing around them.
3
+ *
4
+ * They are a plain function of the row's props; the row itself reads the
5
+ * language of the page, which only a render can do, so the two are separate.
6
+ */
7
+
8
+ import type { ReactElement } from 'react';
9
+
10
+ import { formatInteger } from '../../format/core/numbers.ts';
11
+
12
+ import { Capsule } from './Capsule.tsx';
13
+ import type {
14
+ CapsuleFilterProps,
15
+ CapsuleOption,
16
+ MultipleCapsuleFilterProps,
17
+ SingleCapsuleFilterProps,
18
+ } from './CapsuleFilter.tsx';
19
+
20
+ /**
21
+ * The capsules a row draws, in order.
22
+ * @param props - See `CapsuleFilterProps`.
23
+ * @returns The capsules.
24
+ */
25
+ export function capsuleFilterCapsules<TValue extends string = string>(
26
+ props: CapsuleFilterProps<TValue>,
27
+ ): ReactElement[] {
28
+ return props.multiple === true
29
+ ? multipleCapsules(props)
30
+ : singleCapsules(props);
31
+ }
32
+
33
+ function singleCapsules<TValue extends string>(
34
+ props: SingleCapsuleFilterProps<TValue>,
35
+ ): ReactElement[] {
36
+ const { options, value, onChange, formatCount = formatInteger } = props;
37
+ const capsules: ReactElement[] = [];
38
+ for (const option of options) {
39
+ capsules.push(
40
+ <Capsule
41
+ key={`option:${option.value}`}
42
+ text={capsuleText(option, formatCount)}
43
+ selected={option.value === value}
44
+ intent={option.intent}
45
+ title={option.title}
46
+ onClick={() => onChange(option.value)}
47
+ />,
48
+ );
49
+ }
50
+ return capsules;
51
+ }
52
+
53
+ function multipleCapsules<TValue extends string>(
54
+ props: MultipleCapsuleFilterProps<TValue>,
55
+ ): ReactElement[] {
56
+ const {
57
+ options,
58
+ values,
59
+ onChange,
60
+ allOption,
61
+ formatCount = formatInteger,
62
+ } = props;
63
+ const capsules: ReactElement[] = [];
64
+ if (allOption !== undefined) {
65
+ capsules.push(
66
+ <Capsule
67
+ key="all"
68
+ text={capsuleText(allOption, formatCount)}
69
+ selected={allOption.selected ?? values.length === 0}
70
+ title={allOption.title}
71
+ onClick={() => onChange([])}
72
+ />,
73
+ );
74
+ }
75
+ for (const option of options) {
76
+ capsules.push(
77
+ <Capsule
78
+ key={`option:${option.value}`}
79
+ text={capsuleText(option, formatCount)}
80
+ selected={values.includes(option.value)}
81
+ intent={option.intent}
82
+ title={option.title}
83
+ onClick={() => onChange(toggled(options, values, option.value))}
84
+ />,
85
+ );
86
+ }
87
+ return capsules;
88
+ }
89
+
90
+ function capsuleText(
91
+ capsule: { label: string; count?: number },
92
+ formatCount: (count: number) => string,
93
+ ): string {
94
+ return capsule.count === undefined
95
+ ? capsule.label
96
+ : `${capsule.label} (${formatCount(capsule.count)})`;
97
+ }
98
+
99
+ function toggled<TValue extends string>(
100
+ options: ReadonlyArray<CapsuleOption<TValue>>,
101
+ values: readonly TValue[],
102
+ flipped: TValue,
103
+ ): TValue[] {
104
+ const next: TValue[] = [];
105
+ for (const option of options) {
106
+ const kept = values.includes(option.value);
107
+ if (option.value === flipped ? !kept : kept) next.push(option.value);
108
+ }
109
+ return next;
110
+ }
@@ -8,6 +8,7 @@
8
8
  import type { CSSProperties, MouseEvent, ReactElement } from 'react';
9
9
  import { useRef } from 'react';
10
10
 
11
+ import { useChromeT } from '../../i18n/ui/useT.ts';
11
12
  import type { ChartAxisScale } from '../core/chartAxisScale.ts';
12
13
  import type { ChartBand } from '../core/chartBand.ts';
13
14
  import { chartBandCenter, chartBandIndexAt } from '../core/chartBand.ts';
@@ -64,6 +65,7 @@ export function ChartTrackingLayer(
64
65
  ): ReactElement {
65
66
  const { plot, band, y, categories, series, index, onTrack, onSelect } = props;
66
67
  const { slotAxis, title } = props;
68
+ const t = useChromeT();
67
69
  const entered = useRef<number | null>(null);
68
70
  const slot = index ?? -1;
69
71
  const tracked = slot >= 0 && slot < band.count;
@@ -137,8 +139,8 @@ export function ChartTrackingLayer(
137
139
  role="button"
138
140
  aria-label={
139
141
  tracked
140
- ? `Measurement ${categories[slot]}`
141
- : (title ?? 'Measurements')
142
+ ? t('chart.measurement', { name: categories[slot] ?? '' })
143
+ : (title ?? t('chart.measurements'))
142
144
  }
143
145
  onPointerDown={move}
144
146
  onPointerMove={move}
@@ -5,6 +5,7 @@ import { siteById } from '../../ecosystem/core/lookup.ts';
5
5
  import type { SiteId, SiteRecord } from '../../ecosystem/core/sites.ts';
6
6
  import { Wordmark } from '../../ecosystem/ui/Wordmark.tsx';
7
7
  import { SiteMark } from '../../ecosystem/ui/marks.tsx';
8
+ import { useChromeT } from '../../i18n/ui/useT.ts';
8
9
 
9
10
  import { NavLink } from './NavLink.tsx';
10
11
  import { NavMenuButton } from './NavMenuButton.tsx';
@@ -86,7 +87,7 @@ export interface SiteHeaderProps {
86
87
  /**
87
88
  * What the menu the pages fold into on a phone is called, for the pointer
88
89
  * and a screen reader.
89
- * @default 'Pages'
90
+ * @default the chrome's own word for it, in the language of the page
90
91
  */
91
92
  pagesLabel?: string;
92
93
  }
@@ -118,8 +119,9 @@ export function SiteHeader(props: SiteHeaderProps): ReactElement | null {
118
119
  onHome,
119
120
  markSize = 28,
120
121
  width = 'page',
121
- pagesLabel = 'Pages',
122
+ pagesLabel,
122
123
  } = props;
124
+ const t = useChromeT();
123
125
 
124
126
  if (embedded) return null;
125
127
 
@@ -158,7 +160,7 @@ export function SiteHeader(props: SiteHeaderProps): ReactElement | null {
158
160
  {nav.length > 1 ? (
159
161
  <div className="app-header-nav-menu">
160
162
  <NavMenuButton
161
- label={pagesLabel}
163
+ label={pagesLabel ?? t('chrome.pages')}
162
164
  icon="menu"
163
165
  compact
164
166
  items={nav}
@@ -2,6 +2,7 @@ import { Menu, MenuDivider, MenuItem } from '@blueprintjs/core';
2
2
  import { SvgLogoDoi } from 'cheminfo-font';
3
3
  import type { CSSProperties, ReactElement } from 'react';
4
4
 
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
6
  import { CITATION_DOWNLOADS } from '../core/formats.ts';
6
7
  import type { Reference } from '../core/reference.ts';
7
8
  import { doiUrl } from '../core/reference.ts';
@@ -31,7 +32,7 @@ export interface CitedWorksProps {
31
32
  /**
32
33
  * The line heading the menu, saying which of the works a reader is expected
33
34
  * to cite.
34
- * @default 'Please cite both works', or 'Please cite every work' past two
35
+ * @default the chrome's own line, in the language of the page
35
36
  */
36
37
  guidance?: string;
37
38
  }
@@ -69,6 +70,7 @@ export function CitationMenu(props: CitationMenuProps): ReactElement {
69
70
  */
70
71
  function OneWorkMenu(props: CitedReferenceProps): ReactElement {
71
72
  const { reference } = props;
73
+ const t = useChromeT();
72
74
  const feedback = useCopyFeedback();
73
75
  const references = [reference];
74
76
 
@@ -82,7 +84,7 @@ function OneWorkMenu(props: CitedReferenceProps): ReactElement {
82
84
  target="_blank"
83
85
  rel="noreferrer"
84
86
  />
85
- <MenuDivider title="Copy the reference as" />
87
+ <MenuDivider title={t('cite.copyReferenceAs')} />
86
88
  <CopyFormatEntries references={references} feedback={feedback} />
87
89
  <ImportSection references={references} />
88
90
  </Menu>
@@ -97,6 +99,7 @@ function OneWorkMenu(props: CitedReferenceProps): ReactElement {
97
99
  */
98
100
  function WorkSetMenu(props: CitedWorksProps): ReactElement {
99
101
  const { works, guidance } = props;
102
+ const t = useChromeT();
100
103
  const feedback = useCopyFeedback();
101
104
  const references = citedReferences(works);
102
105
  const both = works.length === 2;
@@ -106,14 +109,14 @@ function WorkSetMenu(props: CitedWorksProps): ReactElement {
106
109
  <MenuDivider
107
110
  title={
108
111
  guidance ??
109
- (both ? 'Please cite both works' : 'Please cite every work')
112
+ (both ? t('cite.pleaseCiteBoth') : t('cite.pleaseCiteEvery'))
110
113
  }
111
114
  />
112
115
  {works.map((work) => (
113
116
  <WorkEntry key={work.reference.doi} work={work} feedback={feedback} />
114
117
  ))}
115
118
  <MenuDivider
116
- title={both ? 'Copy both references as' : 'Copy every reference as'}
119
+ title={both ? t('cite.copyBothAs') : t('cite.copyEveryAs')}
117
120
  />
118
121
  <CopyFormatEntries references={references} feedback={feedback} />
119
122
  <ImportSection references={references} />
@@ -132,9 +135,10 @@ function ImportSection(props: {
132
135
  references: readonly Reference[];
133
136
  }): ReactElement {
134
137
  const { references } = props;
138
+ const t = useChromeT();
135
139
  return (
136
140
  <>
137
- <MenuDivider title="Import into a reference manager" />
141
+ <MenuDivider title={t('cite.importIntoManager')} />
138
142
  {CITATION_DOWNLOADS.map((download) => (
139
143
  <DownloadEntry
140
144
  key={download.format}
@@ -1,5 +1,6 @@
1
1
  import type { ReactElement } from 'react';
2
2
 
3
+ import { useChromeT } from '../../i18n/ui/useT.ts';
3
4
  import type { HeaderButtonProps } from '../../shared/ui/MenuButton.tsx';
4
5
  import { MenuButton } from '../../shared/ui/MenuButton.tsx';
5
6
 
@@ -10,7 +11,7 @@ interface CiteButtonBaseProps extends HeaderButtonProps {
10
11
  /**
11
12
  * Text of the button. In a compact bar it is not written, but it stays what
12
13
  * the pointer and a screen reader are told.
13
- * @default 'Cite'
14
+ * @default the chrome's own word for it, in the language of the page
14
15
  */
15
16
  label?: string;
16
17
  }
@@ -33,7 +34,8 @@ export type CiteButtonProps = CiteOneWorkProps | CiteWorksProps;
33
34
  * @returns The button and its menu.
34
35
  */
35
36
  export function CiteButton(props: CiteButtonProps): ReactElement {
36
- const label = props.label ?? 'Cite';
37
+ const t = useChromeT();
38
+ const label = props.label ?? t('cite.button');
37
39
 
38
40
  return (
39
41
  <MenuButton