react-cheminfo 0.25.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 (416) 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/ui/EcosystemButton.d.ts +1 -1
  98. package/lib/ecosystem/ui/EcosystemButton.d.ts.map +1 -1
  99. package/lib/ecosystem/ui/EcosystemButton.js +4 -2
  100. package/lib/ecosystem/ui/EcosystemButton.js.map +1 -1
  101. package/lib/ecosystem/ui/EcosystemLinks.d.ts +1 -1
  102. package/lib/ecosystem/ui/EcosystemLinks.d.ts.map +1 -1
  103. package/lib/ecosystem/ui/EcosystemLinks.js +5 -2
  104. package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
  105. package/lib/ecosystem/ui/EcosystemMenu.d.ts.map +1 -1
  106. package/lib/ecosystem/ui/EcosystemMenu.js +3 -1
  107. package/lib/ecosystem/ui/EcosystemMenu.js.map +1 -1
  108. package/lib/ecosystem/ui/SiteGroupSection.d.ts.map +1 -1
  109. package/lib/ecosystem/ui/SiteGroupSection.js +3 -1
  110. package/lib/ecosystem/ui/SiteGroupSection.js.map +1 -1
  111. package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
  112. package/lib/ecosystem/ui/SiteTile.js +3 -1
  113. package/lib/ecosystem/ui/SiteTile.js.map +1 -1
  114. package/lib/error/ui/ErrorFallback.d.ts +2 -2
  115. package/lib/error/ui/ErrorFallback.d.ts.map +1 -1
  116. package/lib/error/ui/ErrorFallback.js +4 -2
  117. package/lib/error/ui/ErrorFallback.js.map +1 -1
  118. package/lib/help/ui/HelpBody.d.ts.map +1 -1
  119. package/lib/help/ui/HelpBody.js +3 -1
  120. package/lib/help/ui/HelpBody.js.map +1 -1
  121. package/lib/help/ui/HelpIcon.d.ts +2 -1
  122. package/lib/help/ui/HelpIcon.d.ts.map +1 -1
  123. package/lib/help/ui/HelpIcon.js +4 -2
  124. package/lib/help/ui/HelpIcon.js.map +1 -1
  125. package/lib/help/ui/HelpToolbarButton.d.ts.map +1 -1
  126. package/lib/help/ui/HelpToolbarButton.js +3 -1
  127. package/lib/help/ui/HelpToolbarButton.js.map +1 -1
  128. package/lib/help/ui/helpName.d.ts +5 -1
  129. package/lib/help/ui/helpName.d.ts.map +1 -1
  130. package/lib/help/ui/helpName.js +4 -2
  131. package/lib/help/ui/helpName.js.map +1 -1
  132. package/lib/i18n/core/chromeCatalog.d.ts +21 -0
  133. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -0
  134. package/lib/i18n/core/chromeCatalog.js +29 -0
  135. package/lib/i18n/core/chromeCatalog.js.map +1 -0
  136. package/lib/i18n/core/index.d.ts +12 -0
  137. package/lib/i18n/core/index.d.ts.map +1 -0
  138. package/lib/i18n/core/index.js +6 -0
  139. package/lib/i18n/core/index.js.map +1 -0
  140. package/lib/i18n/core/languages.d.ts +32 -0
  141. package/lib/i18n/core/languages.d.ts.map +1 -0
  142. package/lib/i18n/core/languages.js +41 -0
  143. package/lib/i18n/core/languages.js.map +1 -0
  144. package/lib/i18n/core/messageCatalog.d.ts +113 -0
  145. package/lib/i18n/core/messageCatalog.d.ts.map +1 -0
  146. package/lib/i18n/core/messageCatalog.js +135 -0
  147. package/lib/i18n/core/messageCatalog.js.map +1 -0
  148. package/lib/i18n/core/messageValues.d.ts +3 -0
  149. package/lib/i18n/core/messageValues.d.ts.map +1 -0
  150. package/lib/i18n/core/messageValues.js +2 -0
  151. package/lib/i18n/core/messageValues.js.map +1 -0
  152. package/lib/i18n/core/session.d.ts +51 -0
  153. package/lib/i18n/core/session.d.ts.map +1 -0
  154. package/lib/i18n/core/session.js +64 -0
  155. package/lib/i18n/core/session.js.map +1 -0
  156. package/lib/i18n/core/translateSetup.d.ts +28 -0
  157. package/lib/i18n/core/translateSetup.d.ts.map +1 -0
  158. package/lib/i18n/core/translateSetup.js +30 -0
  159. package/lib/i18n/core/translateSetup.js.map +1 -0
  160. package/lib/i18n/ui/LanguageSelect.d.ts +37 -0
  161. package/lib/i18n/ui/LanguageSelect.d.ts.map +1 -0
  162. package/lib/i18n/ui/LanguageSelect.js +27 -0
  163. package/lib/i18n/ui/LanguageSelect.js.map +1 -0
  164. package/lib/i18n/ui/index.d.ts +6 -0
  165. package/lib/i18n/ui/index.d.ts.map +1 -0
  166. package/lib/i18n/ui/index.js +4 -0
  167. package/lib/i18n/ui/index.js.map +1 -0
  168. package/lib/i18n/ui/useLanguage.d.ts +23 -0
  169. package/lib/i18n/ui/useLanguage.d.ts.map +1 -0
  170. package/lib/i18n/ui/useLanguage.js +36 -0
  171. package/lib/i18n/ui/useLanguage.js.map +1 -0
  172. package/lib/i18n/ui/useT.d.ts +47 -0
  173. package/lib/i18n/ui/useT.d.ts.map +1 -0
  174. package/lib/i18n/ui/useT.js +51 -0
  175. package/lib/i18n/ui/useT.js.map +1 -0
  176. package/lib/locales/de.json +442 -0
  177. package/lib/locales/en.json +442 -0
  178. package/lib/locales/es.json +442 -0
  179. package/lib/locales/fr.json +442 -0
  180. package/lib/molecule3d/core/gestures.d.ts +10 -0
  181. package/lib/molecule3d/core/gestures.d.ts.map +1 -1
  182. package/lib/molecule3d/core/gestures.js +39 -7
  183. package/lib/molecule3d/core/gestures.js.map +1 -1
  184. package/lib/molecule3d/ui/Molecule3DExport.d.ts.map +1 -1
  185. package/lib/molecule3d/ui/Molecule3DExport.js +3 -1
  186. package/lib/molecule3d/ui/Molecule3DExport.js.map +1 -1
  187. package/lib/molecule3d/ui/Molecule3DHelp.d.ts.map +1 -1
  188. package/lib/molecule3d/ui/Molecule3DHelp.js +7 -2
  189. package/lib/molecule3d/ui/Molecule3DHelp.js.map +1 -1
  190. package/lib/molecule3d/ui/Molecule3DOptions.d.ts.map +1 -1
  191. package/lib/molecule3d/ui/Molecule3DOptions.js +9 -9
  192. package/lib/molecule3d/ui/Molecule3DOptions.js.map +1 -1
  193. package/lib/molecule3d/ui/Molecule3DSurfaceColors.d.ts.map +1 -1
  194. package/lib/molecule3d/ui/Molecule3DSurfaceColors.js +8 -8
  195. package/lib/molecule3d/ui/Molecule3DSurfaceColors.js.map +1 -1
  196. package/lib/molecule3d/ui/Molecule3DToolbar.d.ts.map +1 -1
  197. package/lib/molecule3d/ui/Molecule3DToolbar.js +15 -10
  198. package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
  199. package/lib/molecule3d/ui/MoleculeViewer3D.d.ts.map +1 -1
  200. package/lib/molecule3d/ui/MoleculeViewer3D.js +6 -3
  201. package/lib/molecule3d/ui/MoleculeViewer3D.js.map +1 -1
  202. package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts.map +1 -1
  203. package/lib/orbital/ui/AtomicOrbitalCanvas.js +3 -1
  204. package/lib/orbital/ui/AtomicOrbitalCanvas.js.map +1 -1
  205. package/lib/orbital/ui/AtomicOrbitalControls.d.ts.map +1 -1
  206. package/lib/orbital/ui/AtomicOrbitalControls.js +12 -15
  207. package/lib/orbital/ui/AtomicOrbitalControls.js.map +1 -1
  208. package/lib/orbital/ui/AtomicOrbitalViewer.d.ts.map +1 -1
  209. package/lib/orbital/ui/AtomicOrbitalViewer.js +6 -3
  210. package/lib/orbital/ui/AtomicOrbitalViewer.js.map +1 -1
  211. package/lib/orbital/ui/capability.d.ts +4 -0
  212. package/lib/orbital/ui/capability.d.ts.map +1 -1
  213. package/lib/orbital/ui/capability.js +4 -0
  214. package/lib/orbital/ui/capability.js.map +1 -1
  215. package/lib/overlay/ui/OverlayBar.d.ts +1 -1
  216. package/lib/overlay/ui/OverlayBar.d.ts.map +1 -1
  217. package/lib/overlay/ui/OverlayBar.js +6 -3
  218. package/lib/overlay/ui/OverlayBar.js.map +1 -1
  219. package/lib/overlay/ui/OverlayInfo.d.ts +1 -1
  220. package/lib/overlay/ui/OverlayInfo.d.ts.map +1 -1
  221. package/lib/overlay/ui/OverlayInfo.js +5 -2
  222. package/lib/overlay/ui/OverlayInfo.js.map +1 -1
  223. package/lib/overlay/ui/OverlayPanel.d.ts +9 -2
  224. package/lib/overlay/ui/OverlayPanel.d.ts.map +1 -1
  225. package/lib/overlay/ui/OverlayPanel.js +5 -11
  226. package/lib/overlay/ui/OverlayPanel.js.map +1 -1
  227. package/lib/overlay/ui/OverlayReadout.d.ts.map +1 -1
  228. package/lib/overlay/ui/OverlayReadout.js +3 -1
  229. package/lib/overlay/ui/OverlayReadout.js.map +1 -1
  230. package/lib/pedagogy/ui/ExerciseActions.d.ts +1 -1
  231. package/lib/pedagogy/ui/ExerciseActions.d.ts.map +1 -1
  232. package/lib/pedagogy/ui/ExerciseActions.js +9 -2
  233. package/lib/pedagogy/ui/ExerciseActions.js.map +1 -1
  234. package/lib/pedagogy/ui/ExerciseProgressHeader.d.ts +1 -1
  235. package/lib/pedagogy/ui/ExerciseProgressHeader.d.ts.map +1 -1
  236. package/lib/pedagogy/ui/ExerciseProgressHeader.js +9 -5
  237. package/lib/pedagogy/ui/ExerciseProgressHeader.js.map +1 -1
  238. package/lib/pedagogy/ui/GlossaryIndex.d.ts +1 -1
  239. package/lib/pedagogy/ui/GlossaryIndex.d.ts.map +1 -1
  240. package/lib/pedagogy/ui/GlossaryIndex.js +6 -8
  241. package/lib/pedagogy/ui/GlossaryIndex.js.map +1 -1
  242. package/lib/pedagogy/ui/HintLadder.d.ts +2 -2
  243. package/lib/pedagogy/ui/HintLadder.d.ts.map +1 -1
  244. package/lib/pedagogy/ui/HintLadder.js +8 -2
  245. package/lib/pedagogy/ui/HintLadder.js.map +1 -1
  246. package/lib/pedagogy/ui/SyntaxTooltip.d.ts +4 -4
  247. package/lib/pedagogy/ui/SyntaxTooltip.d.ts.map +1 -1
  248. package/lib/pedagogy/ui/SyntaxTooltip.js +4 -2
  249. package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
  250. package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
  251. package/lib/pedagogy/ui/TutorialStepStrip.js +7 -2
  252. package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
  253. package/lib/periodic/ui/CategoryLegend.d.ts.map +1 -1
  254. package/lib/periodic/ui/CategoryLegend.js +3 -1
  255. package/lib/periodic/ui/CategoryLegend.js.map +1 -1
  256. package/lib/periodic/ui/ElementCell.d.ts.map +1 -1
  257. package/lib/periodic/ui/ElementCell.js +7 -1
  258. package/lib/periodic/ui/ElementCell.js.map +1 -1
  259. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  260. package/lib/periodic/ui/PeriodicTable.js +3 -1
  261. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  262. package/lib/periodic/ui/PeriodicTableChrome.d.ts.map +1 -1
  263. package/lib/periodic/ui/PeriodicTableChrome.js +4 -2
  264. package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -1
  265. package/lib/share/ui/ShareButton.d.ts +2 -2
  266. package/lib/share/ui/ShareButton.d.ts.map +1 -1
  267. package/lib/share/ui/ShareButton.js +5 -2
  268. package/lib/share/ui/ShareButton.js.map +1 -1
  269. package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
  270. package/lib/share/ui/ShareConfigOptions.js +4 -2
  271. package/lib/share/ui/ShareConfigOptions.js.map +1 -1
  272. package/lib/share/ui/ShareDialog.d.ts.map +1 -1
  273. package/lib/share/ui/ShareDialog.js +3 -1
  274. package/lib/share/ui/ShareDialog.js.map +1 -1
  275. package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
  276. package/lib/share/ui/ShareDialogContent.js +10 -1
  277. package/lib/share/ui/ShareDialogContent.js.map +1 -1
  278. package/lib/share/ui/SharePresetTabs.d.ts.map +1 -1
  279. package/lib/share/ui/SharePresetTabs.js +3 -1
  280. package/lib/share/ui/SharePresetTabs.js.map +1 -1
  281. package/lib/slides/ui/BackToSlides.d.ts.map +1 -1
  282. package/lib/slides/ui/BackToSlides.js +4 -2
  283. package/lib/slides/ui/BackToSlides.js.map +1 -1
  284. package/lib/slides/ui/EmbedSlide.d.ts.map +1 -1
  285. package/lib/slides/ui/EmbedSlide.js +3 -1
  286. package/lib/slides/ui/EmbedSlide.js.map +1 -1
  287. package/lib/slides/ui/Slide.d.ts.map +1 -1
  288. package/lib/slides/ui/Slide.js +3 -1
  289. package/lib/slides/ui/Slide.js.map +1 -1
  290. package/lib/slides/ui/SlideshowBar.d.ts.map +1 -1
  291. package/lib/slides/ui/SlideshowBar.js +5 -3
  292. package/lib/slides/ui/SlideshowBar.js.map +1 -1
  293. package/lib/slides/ui/TalkList.d.ts +1 -1
  294. package/lib/slides/ui/TalkList.d.ts.map +1 -1
  295. package/lib/slides/ui/TalkList.js +4 -2
  296. package/lib/slides/ui/TalkList.js.map +1 -1
  297. package/lib/structure/core/editorGuide.d.ts +14 -0
  298. package/lib/structure/core/editorGuide.d.ts.map +1 -1
  299. package/lib/structure/core/editorGuide.js +117 -19
  300. package/lib/structure/core/editorGuide.js.map +1 -1
  301. package/lib/structure/core/editorToolbar.d.ts +3 -1
  302. package/lib/structure/core/editorToolbar.d.ts.map +1 -1
  303. package/lib/structure/core/editorToolbar.js +44 -23
  304. package/lib/structure/core/editorToolbar.js.map +1 -1
  305. package/lib/structure/ui/EditorHelpButton.d.ts.map +1 -1
  306. package/lib/structure/ui/EditorHelpButton.js +3 -2
  307. package/lib/structure/ui/EditorHelpButton.js.map +1 -1
  308. package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
  309. package/lib/structure/ui/StructureEditor.js +3 -1
  310. package/lib/structure/ui/StructureEditor.js.map +1 -1
  311. package/lib/structure/ui/StructureEditorHelp.d.ts.map +1 -1
  312. package/lib/structure/ui/StructureEditorHelp.js +12 -3
  313. package/lib/structure/ui/StructureEditorHelp.js.map +1 -1
  314. package/lib/structure/ui/ToolbarTooltip.d.ts.map +1 -1
  315. package/lib/structure/ui/ToolbarTooltip.js +5 -3
  316. package/lib/structure/ui/ToolbarTooltip.js.map +1 -1
  317. package/lib/ui.d.ts +1 -0
  318. package/lib/ui.d.ts.map +1 -1
  319. package/lib/ui.js +1 -0
  320. package/lib/ui.js.map +1 -1
  321. package/package.json +4 -2
  322. package/src/about/ui/AboutBuild.tsx +23 -16
  323. package/src/about/ui/AboutCitations.tsx +3 -1
  324. package/src/about/ui/AboutPage.tsx +38 -12
  325. package/src/about/ui/AboutProvidedBy.tsx +13 -3
  326. package/src/capsule/ui/Capsule.tsx +48 -0
  327. package/src/capsule/ui/CapsuleFilter.tsx +38 -114
  328. package/src/capsule/ui/capsuleFilterCapsules.tsx +110 -0
  329. package/src/chart/ui/ChartTrackingLayer.tsx +4 -2
  330. package/src/chrome/ui/SiteHeader.tsx +5 -3
  331. package/src/citation/ui/CitationMenu.tsx +9 -5
  332. package/src/citation/ui/CiteButton.tsx +4 -2
  333. package/src/citation/ui/CopyFormatEntries.tsx +3 -1
  334. package/src/citation/ui/WorkEntry.tsx +5 -3
  335. package/src/citation/ui/entries.tsx +9 -2
  336. package/src/citation/ui/useCopyFeedback.ts +11 -4
  337. package/src/clipboard/ui/ClickToCopy.tsx +15 -5
  338. package/src/clipboard/ui/CopyButton.tsx +14 -10
  339. package/src/color/ui/ColorScaleEditor.tsx +17 -15
  340. package/src/color/ui/ColorScaleEntry.tsx +7 -3
  341. package/src/color/ui/ColorScaleLegend.tsx +7 -1
  342. package/src/color/ui/ColorScaleSelect.tsx +12 -6
  343. package/src/confirm/ui/ConfirmButton.tsx +9 -11
  344. package/src/core.ts +1 -0
  345. package/src/credits/ui/CreditsList.tsx +5 -1
  346. package/src/delimited/ui/DelimitedTextDialog.tsx +10 -10
  347. package/src/delimited/ui/DelimitedTextPanel.tsx +19 -12
  348. package/src/download/ui/FigureDownload.tsx +7 -5
  349. package/src/download/ui/FigureDownloadPanel.tsx +31 -25
  350. package/src/ecosystem/ui/EcosystemButton.tsx +5 -3
  351. package/src/ecosystem/ui/EcosystemLinks.tsx +10 -10
  352. package/src/ecosystem/ui/EcosystemMenu.tsx +3 -1
  353. package/src/ecosystem/ui/SiteGroupSection.tsx +6 -2
  354. package/src/ecosystem/ui/SiteTile.tsx +6 -2
  355. package/src/error/ui/ErrorFallback.tsx +13 -12
  356. package/src/help/ui/HelpBody.tsx +4 -2
  357. package/src/help/ui/HelpIcon.tsx +6 -3
  358. package/src/help/ui/HelpToolbarButton.tsx +4 -1
  359. package/src/help/ui/helpName.ts +10 -2
  360. package/src/i18n/core/chromeCatalog.ts +35 -0
  361. package/src/i18n/core/index.ts +26 -0
  362. package/src/i18n/core/languages.ts +46 -0
  363. package/src/i18n/core/messageCatalog.ts +202 -0
  364. package/src/i18n/core/messageValues.ts +2 -0
  365. package/src/i18n/core/session.ts +82 -0
  366. package/src/i18n/core/translateSetup.ts +47 -0
  367. package/src/i18n/ui/LanguageSelect.tsx +72 -0
  368. package/src/i18n/ui/index.ts +9 -0
  369. package/src/i18n/ui/useLanguage.ts +48 -0
  370. package/src/i18n/ui/useT.ts +90 -0
  371. package/src/locales/de.json +442 -0
  372. package/src/locales/en.json +442 -0
  373. package/src/locales/es.json +442 -0
  374. package/src/locales/fr.json +442 -0
  375. package/src/molecule3d/core/gestures.ts +44 -7
  376. package/src/molecule3d/ui/Molecule3DExport.tsx +3 -1
  377. package/src/molecule3d/ui/Molecule3DHelp.tsx +17 -6
  378. package/src/molecule3d/ui/Molecule3DOptions.tsx +13 -13
  379. package/src/molecule3d/ui/Molecule3DSurfaceColors.tsx +16 -13
  380. package/src/molecule3d/ui/Molecule3DToolbar.tsx +29 -18
  381. package/src/molecule3d/ui/MoleculeViewer3D.tsx +13 -8
  382. package/src/orbital/ui/AtomicOrbitalCanvas.tsx +3 -1
  383. package/src/orbital/ui/AtomicOrbitalControls.tsx +15 -20
  384. package/src/orbital/ui/AtomicOrbitalViewer.tsx +13 -13
  385. package/src/orbital/ui/capability.ts +10 -0
  386. package/src/overlay/ui/OverlayBar.tsx +7 -4
  387. package/src/overlay/ui/OverlayInfo.tsx +6 -3
  388. package/src/overlay/ui/OverlayPanel.tsx +10 -7
  389. package/src/overlay/ui/OverlayReadout.tsx +3 -1
  390. package/src/pedagogy/ui/ExerciseActions.tsx +16 -6
  391. package/src/pedagogy/ui/ExerciseProgressHeader.tsx +13 -11
  392. package/src/pedagogy/ui/GlossaryIndex.tsx +11 -12
  393. package/src/pedagogy/ui/HintLadder.tsx +15 -12
  394. package/src/pedagogy/ui/SyntaxTooltip.tsx +9 -7
  395. package/src/pedagogy/ui/TutorialStepStrip.tsx +8 -3
  396. package/src/periodic/ui/CategoryLegend.tsx +6 -1
  397. package/src/periodic/ui/ElementCell.tsx +7 -1
  398. package/src/periodic/ui/PeriodicTable.tsx +3 -1
  399. package/src/periodic/ui/PeriodicTableChrome.tsx +4 -2
  400. package/src/share/ui/ShareButton.tsx +8 -5
  401. package/src/share/ui/ShareConfigOptions.tsx +6 -7
  402. package/src/share/ui/ShareDialog.tsx +3 -1
  403. package/src/share/ui/ShareDialogContent.tsx +20 -10
  404. package/src/share/ui/SharePresetTabs.tsx +3 -1
  405. package/src/slides/ui/BackToSlides.tsx +4 -2
  406. package/src/slides/ui/EmbedSlide.tsx +3 -3
  407. package/src/slides/ui/Slide.tsx +3 -1
  408. package/src/slides/ui/SlideshowBar.tsx +12 -4
  409. package/src/slides/ui/TalkList.tsx +8 -10
  410. package/src/structure/core/editorGuide.ts +126 -19
  411. package/src/structure/core/editorToolbar.ts +52 -24
  412. package/src/structure/ui/EditorHelpButton.tsx +9 -4
  413. package/src/structure/ui/StructureEditor.tsx +7 -1
  414. package/src/structure/ui/StructureEditorHelp.tsx +34 -11
  415. package/src/structure/ui/ToolbarTooltip.tsx +8 -4
  416. package/src/ui.ts +1 -0
@@ -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
@@ -1,6 +1,7 @@
1
1
  import { MenuItem } from '@blueprintjs/core';
2
2
  import type { ReactElement } from 'react';
3
3
 
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
4
5
  import { CITATION_FORMATS } from '../core/formats.ts';
5
6
  import type { Reference } from '../core/reference.ts';
6
7
  import { CITATION_STYLES } from '../core/segments.ts';
@@ -39,6 +40,7 @@ export function CopyFormatEntries(
39
40
  props: CopyFormatEntriesProps,
40
41
  ): ReactElement[] {
41
42
  const { references, feedback, keyPrefix = '', styled = true } = props;
43
+ const t = useChromeT();
42
44
 
43
45
  return CITATION_FORMATS.map((format) => {
44
46
  if (!styled || !format.styled) {
@@ -60,7 +62,7 @@ export function CopyFormatEntries(
60
62
  <MenuItem
61
63
  key={format.id}
62
64
  icon="clipboard"
63
- text={format.label}
65
+ text={t.or(`cite.format.${format.id}`, format.label)}
64
66
  label={format.hint}
65
67
  >
66
68
  {CITATION_STYLES.map((style) => {
@@ -2,6 +2,7 @@ import { 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 { doiUrl } from '../core/reference.ts';
7
8
  import type { CitedWork } from '../core/works.ts';
@@ -38,6 +39,7 @@ export interface WorkEntryProps {
38
39
  */
39
40
  export function WorkEntry(props: WorkEntryProps): ReactElement {
40
41
  const { work, feedback } = props;
42
+ const t = useChromeT();
41
43
  const { reference, what, note } = work;
42
44
  const references = [reference];
43
45
 
@@ -54,20 +56,20 @@ export function WorkEntry(props: WorkEntryProps): ReactElement {
54
56
  >
55
57
  <MenuItem
56
58
  icon={<SvgLogoDoi style={DOI_ICON_STYLE} />}
57
- text="Open the article"
59
+ text={t('cite.openArticle')}
58
60
  label={reference.doi}
59
61
  href={doiUrl(reference)}
60
62
  target="_blank"
61
63
  rel="noreferrer"
62
64
  />
63
- <MenuDivider title="Copy this reference as" />
65
+ <MenuDivider title={t('cite.copyThisAs')} />
64
66
  <CopyFormatEntries
65
67
  references={references}
66
68
  feedback={feedback}
67
69
  keyPrefix={`${reference.doi}:`}
68
70
  styled={false}
69
71
  />
70
- <MenuDivider title="Import this reference" />
72
+ <MenuDivider title={t('cite.importThis')} />
71
73
  {CITATION_DOWNLOADS.map((download) => (
72
74
  <DownloadEntry
73
75
  key={download.format}
@@ -2,6 +2,7 @@ import type { IconName, Intent } from '@blueprintjs/core';
2
2
  import { MenuItem, Tooltip } from '@blueprintjs/core';
3
3
  import type { CSSProperties, ReactElement } from 'react';
4
4
 
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
6
  import { downloadCitations } from '../core/download.ts';
6
7
  import type { CitationDownload, CitationFormat } from '../core/formats.ts';
7
8
  import type { Reference } from '../core/reference.ts';
@@ -49,7 +50,12 @@ export interface CopyEntryProps {
49
50
  */
50
51
  export function CopyEntry(props: CopyEntryProps): ReactElement {
51
52
  const { references, format, style, state, onCopy } = props;
53
+ const t = useChromeT();
52
54
  const entry = style ?? format;
55
+ const label =
56
+ style === undefined
57
+ ? t.or(`cite.format.${format.id}`, format.label)
58
+ : style.label;
53
59
 
54
60
  return (
55
61
  <PreviewTooltip references={references} format={format.id} style={style}>
@@ -59,7 +65,7 @@ export function CopyEntry(props: CopyEntryProps): ReactElement {
59
65
  style={ENTRY_STYLE}
60
66
  icon={state?.icon ?? 'clipboard'}
61
67
  intent={state?.intent}
62
- text={entry.label}
68
+ text={label}
63
69
  labelElement={
64
70
  // The hint of a style entry is a list of journals, in italic.
65
71
  style !== undefined && state === null ? (
@@ -90,6 +96,7 @@ export interface DownloadEntryProps {
90
96
  */
91
97
  export function DownloadEntry(props: DownloadEntryProps): ReactElement {
92
98
  const { references, download } = props;
99
+ const t = useChromeT();
93
100
  return (
94
101
  <PreviewTooltip references={references} format={download.format}>
95
102
  {(targetProps) => (
@@ -97,7 +104,7 @@ export function DownloadEntry(props: DownloadEntryProps): ReactElement {
97
104
  {...targetProps}
98
105
  style={ENTRY_STYLE}
99
106
  icon="download"
100
- text={download.label}
107
+ text={t.or(`cite.download.${download.format}`, download.label)}
101
108
  labelElement={download.hint}
102
109
  onClick={() => {
103
110
  downloadCitations(references, download);
@@ -1,5 +1,8 @@
1
1
  import { useEffect, useRef, useState } 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 { copyCitations } from '../core/clipboard.ts';
4
7
  import type { CitationFormatId } from '../core/formats.ts';
5
8
  import type { Reference } from '../core/reference.ts';
@@ -31,6 +34,7 @@ export interface CopyFeedback {
31
34
  * @returns The copy action, and the feedback of the entry that used it.
32
35
  */
33
36
  export function useCopyFeedback(): CopyFeedback {
37
+ const t = useChromeT();
34
38
  const [copied, setCopied] = useState<string | null>(null);
35
39
  const [hasFailed, setHasFailed] = useState(false);
36
40
  const timeout = useRef<number | null>(null);
@@ -52,7 +56,7 @@ export function useCopyFeedback(): CopyFeedback {
52
56
  }
53
57
 
54
58
  return {
55
- stateOf: (key) => (copied === key ? feedback(hasFailed) : null),
59
+ stateOf: (key) => (copied === key ? feedback(hasFailed, t) : null),
56
60
  copy: (key, references, format, style) => {
57
61
  copyCitations(references, format, style).then(
58
62
  () => {
@@ -68,9 +72,12 @@ export function useCopyFeedback(): CopyFeedback {
68
72
  };
69
73
  }
70
74
 
71
- function feedback(failed: boolean): CopyState {
75
+ // The label rides at the right of a menu row, where the format's own hint
76
+ // otherwise sits — `LaTeX`, `Word, Docs, email` — so it is written in that
77
+ // register rather than as the word a copy button shows on its own.
78
+ function feedback(failed: boolean, t: Translate<ChromeKey>): CopyState {
72
79
  if (failed) {
73
- return { icon: 'cross', intent: 'danger', label: 'copy failed' };
80
+ return { icon: 'cross', intent: 'danger', label: t('cite.copyFailed') };
74
81
  }
75
- return { icon: 'tick', intent: 'success', label: 'copied' };
82
+ return { icon: 'tick', intent: 'success', label: t('cite.copied') };
76
83
  }
@@ -8,6 +8,9 @@ import type {
8
8
  } from 'react';
9
9
 
10
10
  import { onActivateKey } from '../../hooks/ui/activationKey.ts';
11
+ import type { ChromeKey } from '../../i18n/core/chromeCatalog.ts';
12
+ import type { Translate } from '../../i18n/ui/useT.ts';
13
+ import { useChromeT } from '../../i18n/ui/useT.ts';
11
14
  import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
12
15
  import type { ClipboardContent } from '../core/writeToClipboard.ts';
13
16
  import { writeToClipboard } from '../core/writeToClipboard.ts';
@@ -104,6 +107,7 @@ export function ClickToCopy(props: ClickToCopyProps): ReactElement {
104
107
  className,
105
108
  style,
106
109
  } = props;
110
+ const t = useChromeT();
107
111
  const { copied, failed, copy } = useCopyToClipboard();
108
112
 
109
113
  if (disabled) {
@@ -136,7 +140,7 @@ export function ClickToCopy(props: ClickToCopyProps): ReactElement {
136
140
  style={style}
137
141
  role={focusable && !CELLS.has(Element) ? 'button' : undefined}
138
142
  tabIndex={focusable ? 0 : undefined}
139
- title={title ?? copyTitle(value, label)}
143
+ title={title ?? copyTitle(value, label, t)}
140
144
  data-copy={outcome}
141
145
  onClick={activate}
142
146
  onKeyDown={onActivateKey<KeyboardEvent<HTMLElement>>(activate)}
@@ -157,9 +161,9 @@ export function ClickToCopy(props: ClickToCopyProps): ReactElement {
157
161
  ) : null}
158
162
  <span className="click-to-copy__status" role="status">
159
163
  {outcome === 'copied'
160
- ? 'Copied'
164
+ ? t('clipboard.copied')
161
165
  : outcome === 'failed'
162
- ? 'Copy failed'
166
+ ? t('clipboard.failed')
163
167
  : null}
164
168
  </span>
165
169
  </Element>
@@ -182,10 +186,16 @@ function isOnNestedControl(
182
186
  function copyTitle(
183
187
  value: ClickToCopyProps['value'],
184
188
  label: string | undefined,
189
+ t: Translate<ChromeKey>,
185
190
  ): string {
186
- const what = label === undefined ? 'Copy' : `Copy the ${label}`;
191
+ const what =
192
+ label === undefined
193
+ ? t('clipboard.copy')
194
+ : t('clipboard.copyThe', { what: label });
187
195
  if (typeof value === 'function') return what;
188
196
  const text = typeof value === 'string' ? value : value.text;
189
197
  if (text === '' || text.length > TITLE_VALUE_MAX) return what;
190
- return label === undefined ? `Copy ${text}` : `${what} (${text})`;
198
+ return label === undefined
199
+ ? t('clipboard.copyValue', { value: text })
200
+ : `${what} (${text})`;
191
201
  }