react-cheminfo 0.25.0 → 0.27.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 (436) hide show
  1. package/README.md +73 -2
  2. package/bin/check-deploy.mjs +14 -4
  3. package/bin/check-messages.mjs +229 -0
  4. package/lib/about/ui/AboutBuild.d.ts.map +1 -1
  5. package/lib/about/ui/AboutBuild.js +15 -4
  6. package/lib/about/ui/AboutBuild.js.map +1 -1
  7. package/lib/about/ui/AboutCitations.d.ts.map +1 -1
  8. package/lib/about/ui/AboutCitations.js +3 -1
  9. package/lib/about/ui/AboutCitations.js.map +1 -1
  10. package/lib/about/ui/AboutPage.d.ts.map +1 -1
  11. package/lib/about/ui/AboutPage.js +9 -1
  12. package/lib/about/ui/AboutPage.js.map +1 -1
  13. package/lib/about/ui/AboutProvidedBy.d.ts.map +1 -1
  14. package/lib/about/ui/AboutProvidedBy.js +8 -3
  15. package/lib/about/ui/AboutProvidedBy.js.map +1 -1
  16. package/lib/capsule/ui/Capsule.d.ts +30 -0
  17. package/lib/capsule/ui/Capsule.d.ts.map +1 -0
  18. package/lib/capsule/ui/Capsule.js +12 -0
  19. package/lib/capsule/ui/Capsule.js.map +1 -0
  20. package/lib/capsule/ui/CapsuleFilter.d.ts +19 -3
  21. package/lib/capsule/ui/CapsuleFilter.d.ts.map +1 -1
  22. package/lib/capsule/ui/CapsuleFilter.js +14 -44
  23. package/lib/capsule/ui/CapsuleFilter.js.map +1 -1
  24. package/lib/capsule/ui/capsuleFilterCapsules.d.ts +15 -0
  25. package/lib/capsule/ui/capsuleFilterCapsules.d.ts.map +1 -0
  26. package/lib/capsule/ui/capsuleFilterCapsules.js +47 -0
  27. package/lib/capsule/ui/capsuleFilterCapsules.js.map +1 -0
  28. package/lib/chart/ui/ChartTrackingLayer.d.ts.map +1 -1
  29. package/lib/chart/ui/ChartTrackingLayer.js +4 -2
  30. package/lib/chart/ui/ChartTrackingLayer.js.map +1 -1
  31. package/lib/chrome/ui/SiteHeader.d.ts +1 -1
  32. package/lib/chrome/ui/SiteHeader.d.ts.map +1 -1
  33. package/lib/chrome/ui/SiteHeader.js +4 -2
  34. package/lib/chrome/ui/SiteHeader.js.map +1 -1
  35. package/lib/citation/ui/CitationMenu.d.ts +1 -1
  36. package/lib/citation/ui/CitationMenu.d.ts.map +1 -1
  37. package/lib/citation/ui/CitationMenu.js +7 -3
  38. package/lib/citation/ui/CitationMenu.js.map +1 -1
  39. package/lib/citation/ui/CiteButton.d.ts +1 -1
  40. package/lib/citation/ui/CiteButton.d.ts.map +1 -1
  41. package/lib/citation/ui/CiteButton.js +3 -1
  42. package/lib/citation/ui/CiteButton.js.map +1 -1
  43. package/lib/citation/ui/CopyFormatEntries.d.ts.map +1 -1
  44. package/lib/citation/ui/CopyFormatEntries.js +3 -1
  45. package/lib/citation/ui/CopyFormatEntries.js.map +1 -1
  46. package/lib/citation/ui/WorkEntry.d.ts.map +1 -1
  47. package/lib/citation/ui/WorkEntry.js +3 -1
  48. package/lib/citation/ui/WorkEntry.js.map +1 -1
  49. package/lib/citation/ui/entries.d.ts.map +1 -1
  50. package/lib/citation/ui/entries.js +8 -2
  51. package/lib/citation/ui/entries.js.map +1 -1
  52. package/lib/citation/ui/useCopyFeedback.d.ts.map +1 -1
  53. package/lib/citation/ui/useCopyFeedback.js +9 -4
  54. package/lib/citation/ui/useCopyFeedback.js.map +1 -1
  55. package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
  56. package/lib/clipboard/ui/ClickToCopy.js +12 -6
  57. package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
  58. package/lib/clipboard/ui/CopyButton.d.ts +3 -3
  59. package/lib/clipboard/ui/CopyButton.d.ts.map +1 -1
  60. package/lib/clipboard/ui/CopyButton.js +7 -4
  61. package/lib/clipboard/ui/CopyButton.js.map +1 -1
  62. package/lib/color/ui/ColorScaleEditor.d.ts.map +1 -1
  63. package/lib/color/ui/ColorScaleEditor.js +15 -10
  64. package/lib/color/ui/ColorScaleEditor.js.map +1 -1
  65. package/lib/color/ui/ColorScaleEntry.d.ts.map +1 -1
  66. package/lib/color/ui/ColorScaleEntry.js +4 -2
  67. package/lib/color/ui/ColorScaleEntry.js.map +1 -1
  68. package/lib/color/ui/ColorScaleLegend.d.ts.map +1 -1
  69. package/lib/color/ui/ColorScaleLegend.js +7 -1
  70. package/lib/color/ui/ColorScaleLegend.js.map +1 -1
  71. package/lib/color/ui/ColorScaleSelect.d.ts.map +1 -1
  72. package/lib/color/ui/ColorScaleSelect.js +8 -4
  73. package/lib/color/ui/ColorScaleSelect.js.map +1 -1
  74. package/lib/confirm/ui/ConfirmButton.d.ts +2 -2
  75. package/lib/confirm/ui/ConfirmButton.d.ts.map +1 -1
  76. package/lib/confirm/ui/ConfirmButton.js +4 -2
  77. package/lib/confirm/ui/ConfirmButton.js.map +1 -1
  78. package/lib/core.d.ts +1 -0
  79. package/lib/core.d.ts.map +1 -1
  80. package/lib/core.js +1 -0
  81. package/lib/core.js.map +1 -1
  82. package/lib/credits/ui/CreditsList.d.ts.map +1 -1
  83. package/lib/credits/ui/CreditsList.js +3 -1
  84. package/lib/credits/ui/CreditsList.js.map +1 -1
  85. package/lib/delimited/ui/DelimitedTextDialog.d.ts.map +1 -1
  86. package/lib/delimited/ui/DelimitedTextDialog.js +5 -2
  87. package/lib/delimited/ui/DelimitedTextDialog.js.map +1 -1
  88. package/lib/delimited/ui/DelimitedTextPanel.d.ts.map +1 -1
  89. package/lib/delimited/ui/DelimitedTextPanel.js +8 -8
  90. package/lib/delimited/ui/DelimitedTextPanel.js.map +1 -1
  91. package/lib/deploy/core/checkDeploy.d.ts +3 -1
  92. package/lib/deploy/core/checkDeploy.d.ts.map +1 -1
  93. package/lib/deploy/core/checkDeploy.js +7 -1
  94. package/lib/deploy/core/checkDeploy.js.map +1 -1
  95. package/lib/deploy/core/index.d.ts +1 -0
  96. package/lib/deploy/core/index.d.ts.map +1 -1
  97. package/lib/deploy/core/index.js +1 -0
  98. package/lib/deploy/core/index.js.map +1 -1
  99. package/lib/deploy/core/pageCache.d.ts +24 -0
  100. package/lib/deploy/core/pageCache.d.ts.map +1 -0
  101. package/lib/deploy/core/pageCache.js +91 -0
  102. package/lib/deploy/core/pageCache.js.map +1 -0
  103. package/lib/deploy/core/types.d.ts +1 -1
  104. package/lib/deploy/core/types.d.ts.map +1 -1
  105. package/lib/deploy/core/types.js.map +1 -1
  106. package/lib/download/ui/FigureDownload.d.ts +2 -2
  107. package/lib/download/ui/FigureDownload.d.ts.map +1 -1
  108. package/lib/download/ui/FigureDownload.js +4 -2
  109. package/lib/download/ui/FigureDownload.js.map +1 -1
  110. package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
  111. package/lib/download/ui/FigureDownloadPanel.js +24 -18
  112. package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
  113. package/lib/ecosystem/ui/EcosystemButton.d.ts +1 -1
  114. package/lib/ecosystem/ui/EcosystemButton.d.ts.map +1 -1
  115. package/lib/ecosystem/ui/EcosystemButton.js +4 -2
  116. package/lib/ecosystem/ui/EcosystemButton.js.map +1 -1
  117. package/lib/ecosystem/ui/EcosystemLinks.d.ts +1 -1
  118. package/lib/ecosystem/ui/EcosystemLinks.d.ts.map +1 -1
  119. package/lib/ecosystem/ui/EcosystemLinks.js +5 -2
  120. package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
  121. package/lib/ecosystem/ui/EcosystemMenu.d.ts.map +1 -1
  122. package/lib/ecosystem/ui/EcosystemMenu.js +3 -1
  123. package/lib/ecosystem/ui/EcosystemMenu.js.map +1 -1
  124. package/lib/ecosystem/ui/SiteGroupSection.d.ts.map +1 -1
  125. package/lib/ecosystem/ui/SiteGroupSection.js +3 -1
  126. package/lib/ecosystem/ui/SiteGroupSection.js.map +1 -1
  127. package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
  128. package/lib/ecosystem/ui/SiteTile.js +3 -1
  129. package/lib/ecosystem/ui/SiteTile.js.map +1 -1
  130. package/lib/error/ui/ErrorFallback.d.ts +2 -2
  131. package/lib/error/ui/ErrorFallback.d.ts.map +1 -1
  132. package/lib/error/ui/ErrorFallback.js +4 -2
  133. package/lib/error/ui/ErrorFallback.js.map +1 -1
  134. package/lib/help/ui/HelpBody.d.ts.map +1 -1
  135. package/lib/help/ui/HelpBody.js +3 -1
  136. package/lib/help/ui/HelpBody.js.map +1 -1
  137. package/lib/help/ui/HelpIcon.d.ts +2 -1
  138. package/lib/help/ui/HelpIcon.d.ts.map +1 -1
  139. package/lib/help/ui/HelpIcon.js +4 -2
  140. package/lib/help/ui/HelpIcon.js.map +1 -1
  141. package/lib/help/ui/HelpToolbarButton.d.ts.map +1 -1
  142. package/lib/help/ui/HelpToolbarButton.js +3 -1
  143. package/lib/help/ui/HelpToolbarButton.js.map +1 -1
  144. package/lib/help/ui/helpName.d.ts +5 -1
  145. package/lib/help/ui/helpName.d.ts.map +1 -1
  146. package/lib/help/ui/helpName.js +4 -2
  147. package/lib/help/ui/helpName.js.map +1 -1
  148. package/lib/i18n/core/chromeCatalog.d.ts +21 -0
  149. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -0
  150. package/lib/i18n/core/chromeCatalog.js +29 -0
  151. package/lib/i18n/core/chromeCatalog.js.map +1 -0
  152. package/lib/i18n/core/index.d.ts +12 -0
  153. package/lib/i18n/core/index.d.ts.map +1 -0
  154. package/lib/i18n/core/index.js +6 -0
  155. package/lib/i18n/core/index.js.map +1 -0
  156. package/lib/i18n/core/languages.d.ts +32 -0
  157. package/lib/i18n/core/languages.d.ts.map +1 -0
  158. package/lib/i18n/core/languages.js +41 -0
  159. package/lib/i18n/core/languages.js.map +1 -0
  160. package/lib/i18n/core/messageCatalog.d.ts +113 -0
  161. package/lib/i18n/core/messageCatalog.d.ts.map +1 -0
  162. package/lib/i18n/core/messageCatalog.js +135 -0
  163. package/lib/i18n/core/messageCatalog.js.map +1 -0
  164. package/lib/i18n/core/messageValues.d.ts +3 -0
  165. package/lib/i18n/core/messageValues.d.ts.map +1 -0
  166. package/lib/i18n/core/messageValues.js +2 -0
  167. package/lib/i18n/core/messageValues.js.map +1 -0
  168. package/lib/i18n/core/session.d.ts +51 -0
  169. package/lib/i18n/core/session.d.ts.map +1 -0
  170. package/lib/i18n/core/session.js +64 -0
  171. package/lib/i18n/core/session.js.map +1 -0
  172. package/lib/i18n/core/translateSetup.d.ts +28 -0
  173. package/lib/i18n/core/translateSetup.d.ts.map +1 -0
  174. package/lib/i18n/core/translateSetup.js +30 -0
  175. package/lib/i18n/core/translateSetup.js.map +1 -0
  176. package/lib/i18n/ui/LanguageSelect.d.ts +37 -0
  177. package/lib/i18n/ui/LanguageSelect.d.ts.map +1 -0
  178. package/lib/i18n/ui/LanguageSelect.js +27 -0
  179. package/lib/i18n/ui/LanguageSelect.js.map +1 -0
  180. package/lib/i18n/ui/index.d.ts +6 -0
  181. package/lib/i18n/ui/index.d.ts.map +1 -0
  182. package/lib/i18n/ui/index.js +4 -0
  183. package/lib/i18n/ui/index.js.map +1 -0
  184. package/lib/i18n/ui/useLanguage.d.ts +23 -0
  185. package/lib/i18n/ui/useLanguage.d.ts.map +1 -0
  186. package/lib/i18n/ui/useLanguage.js +36 -0
  187. package/lib/i18n/ui/useLanguage.js.map +1 -0
  188. package/lib/i18n/ui/useT.d.ts +47 -0
  189. package/lib/i18n/ui/useT.d.ts.map +1 -0
  190. package/lib/i18n/ui/useT.js +51 -0
  191. package/lib/i18n/ui/useT.js.map +1 -0
  192. package/lib/locales/de.json +442 -0
  193. package/lib/locales/en.json +442 -0
  194. package/lib/locales/es.json +442 -0
  195. package/lib/locales/fr.json +442 -0
  196. package/lib/molecule3d/core/gestures.d.ts +10 -0
  197. package/lib/molecule3d/core/gestures.d.ts.map +1 -1
  198. package/lib/molecule3d/core/gestures.js +39 -7
  199. package/lib/molecule3d/core/gestures.js.map +1 -1
  200. package/lib/molecule3d/ui/Molecule3DExport.d.ts.map +1 -1
  201. package/lib/molecule3d/ui/Molecule3DExport.js +3 -1
  202. package/lib/molecule3d/ui/Molecule3DExport.js.map +1 -1
  203. package/lib/molecule3d/ui/Molecule3DHelp.d.ts.map +1 -1
  204. package/lib/molecule3d/ui/Molecule3DHelp.js +7 -2
  205. package/lib/molecule3d/ui/Molecule3DHelp.js.map +1 -1
  206. package/lib/molecule3d/ui/Molecule3DOptions.d.ts.map +1 -1
  207. package/lib/molecule3d/ui/Molecule3DOptions.js +9 -9
  208. package/lib/molecule3d/ui/Molecule3DOptions.js.map +1 -1
  209. package/lib/molecule3d/ui/Molecule3DSurfaceColors.d.ts.map +1 -1
  210. package/lib/molecule3d/ui/Molecule3DSurfaceColors.js +8 -8
  211. package/lib/molecule3d/ui/Molecule3DSurfaceColors.js.map +1 -1
  212. package/lib/molecule3d/ui/Molecule3DToolbar.d.ts.map +1 -1
  213. package/lib/molecule3d/ui/Molecule3DToolbar.js +15 -10
  214. package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
  215. package/lib/molecule3d/ui/MoleculeViewer3D.d.ts.map +1 -1
  216. package/lib/molecule3d/ui/MoleculeViewer3D.js +6 -3
  217. package/lib/molecule3d/ui/MoleculeViewer3D.js.map +1 -1
  218. package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts.map +1 -1
  219. package/lib/orbital/ui/AtomicOrbitalCanvas.js +3 -1
  220. package/lib/orbital/ui/AtomicOrbitalCanvas.js.map +1 -1
  221. package/lib/orbital/ui/AtomicOrbitalControls.d.ts.map +1 -1
  222. package/lib/orbital/ui/AtomicOrbitalControls.js +12 -15
  223. package/lib/orbital/ui/AtomicOrbitalControls.js.map +1 -1
  224. package/lib/orbital/ui/AtomicOrbitalViewer.d.ts.map +1 -1
  225. package/lib/orbital/ui/AtomicOrbitalViewer.js +6 -3
  226. package/lib/orbital/ui/AtomicOrbitalViewer.js.map +1 -1
  227. package/lib/orbital/ui/capability.d.ts +4 -0
  228. package/lib/orbital/ui/capability.d.ts.map +1 -1
  229. package/lib/orbital/ui/capability.js +4 -0
  230. package/lib/orbital/ui/capability.js.map +1 -1
  231. package/lib/overlay/ui/OverlayBar.d.ts +1 -1
  232. package/lib/overlay/ui/OverlayBar.d.ts.map +1 -1
  233. package/lib/overlay/ui/OverlayBar.js +6 -3
  234. package/lib/overlay/ui/OverlayBar.js.map +1 -1
  235. package/lib/overlay/ui/OverlayInfo.d.ts +1 -1
  236. package/lib/overlay/ui/OverlayInfo.d.ts.map +1 -1
  237. package/lib/overlay/ui/OverlayInfo.js +5 -2
  238. package/lib/overlay/ui/OverlayInfo.js.map +1 -1
  239. package/lib/overlay/ui/OverlayPanel.d.ts +9 -2
  240. package/lib/overlay/ui/OverlayPanel.d.ts.map +1 -1
  241. package/lib/overlay/ui/OverlayPanel.js +5 -11
  242. package/lib/overlay/ui/OverlayPanel.js.map +1 -1
  243. package/lib/overlay/ui/OverlayReadout.d.ts.map +1 -1
  244. package/lib/overlay/ui/OverlayReadout.js +3 -1
  245. package/lib/overlay/ui/OverlayReadout.js.map +1 -1
  246. package/lib/pedagogy/ui/ExerciseActions.d.ts +1 -1
  247. package/lib/pedagogy/ui/ExerciseActions.d.ts.map +1 -1
  248. package/lib/pedagogy/ui/ExerciseActions.js +9 -2
  249. package/lib/pedagogy/ui/ExerciseActions.js.map +1 -1
  250. package/lib/pedagogy/ui/ExerciseProgressHeader.d.ts +1 -1
  251. package/lib/pedagogy/ui/ExerciseProgressHeader.d.ts.map +1 -1
  252. package/lib/pedagogy/ui/ExerciseProgressHeader.js +9 -5
  253. package/lib/pedagogy/ui/ExerciseProgressHeader.js.map +1 -1
  254. package/lib/pedagogy/ui/GlossaryIndex.d.ts +1 -1
  255. package/lib/pedagogy/ui/GlossaryIndex.d.ts.map +1 -1
  256. package/lib/pedagogy/ui/GlossaryIndex.js +6 -8
  257. package/lib/pedagogy/ui/GlossaryIndex.js.map +1 -1
  258. package/lib/pedagogy/ui/HintLadder.d.ts +2 -2
  259. package/lib/pedagogy/ui/HintLadder.d.ts.map +1 -1
  260. package/lib/pedagogy/ui/HintLadder.js +8 -2
  261. package/lib/pedagogy/ui/HintLadder.js.map +1 -1
  262. package/lib/pedagogy/ui/SyntaxTooltip.d.ts +4 -4
  263. package/lib/pedagogy/ui/SyntaxTooltip.d.ts.map +1 -1
  264. package/lib/pedagogy/ui/SyntaxTooltip.js +4 -2
  265. package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
  266. package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
  267. package/lib/pedagogy/ui/TutorialStepStrip.js +7 -2
  268. package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
  269. package/lib/periodic/ui/CategoryLegend.d.ts.map +1 -1
  270. package/lib/periodic/ui/CategoryLegend.js +3 -1
  271. package/lib/periodic/ui/CategoryLegend.js.map +1 -1
  272. package/lib/periodic/ui/ElementCell.d.ts.map +1 -1
  273. package/lib/periodic/ui/ElementCell.js +7 -1
  274. package/lib/periodic/ui/ElementCell.js.map +1 -1
  275. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  276. package/lib/periodic/ui/PeriodicTable.js +3 -1
  277. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  278. package/lib/periodic/ui/PeriodicTableChrome.d.ts.map +1 -1
  279. package/lib/periodic/ui/PeriodicTableChrome.js +4 -2
  280. package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -1
  281. package/lib/share/ui/ShareButton.d.ts +2 -2
  282. package/lib/share/ui/ShareButton.d.ts.map +1 -1
  283. package/lib/share/ui/ShareButton.js +5 -2
  284. package/lib/share/ui/ShareButton.js.map +1 -1
  285. package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
  286. package/lib/share/ui/ShareConfigOptions.js +4 -2
  287. package/lib/share/ui/ShareConfigOptions.js.map +1 -1
  288. package/lib/share/ui/ShareDialog.d.ts.map +1 -1
  289. package/lib/share/ui/ShareDialog.js +3 -1
  290. package/lib/share/ui/ShareDialog.js.map +1 -1
  291. package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
  292. package/lib/share/ui/ShareDialogContent.js +10 -1
  293. package/lib/share/ui/ShareDialogContent.js.map +1 -1
  294. package/lib/share/ui/SharePresetTabs.d.ts.map +1 -1
  295. package/lib/share/ui/SharePresetTabs.js +3 -1
  296. package/lib/share/ui/SharePresetTabs.js.map +1 -1
  297. package/lib/slides/ui/BackToSlides.d.ts.map +1 -1
  298. package/lib/slides/ui/BackToSlides.js +4 -2
  299. package/lib/slides/ui/BackToSlides.js.map +1 -1
  300. package/lib/slides/ui/EmbedSlide.d.ts.map +1 -1
  301. package/lib/slides/ui/EmbedSlide.js +3 -1
  302. package/lib/slides/ui/EmbedSlide.js.map +1 -1
  303. package/lib/slides/ui/Slide.d.ts.map +1 -1
  304. package/lib/slides/ui/Slide.js +3 -1
  305. package/lib/slides/ui/Slide.js.map +1 -1
  306. package/lib/slides/ui/SlideshowBar.d.ts.map +1 -1
  307. package/lib/slides/ui/SlideshowBar.js +5 -3
  308. package/lib/slides/ui/SlideshowBar.js.map +1 -1
  309. package/lib/slides/ui/TalkList.d.ts +1 -1
  310. package/lib/slides/ui/TalkList.d.ts.map +1 -1
  311. package/lib/slides/ui/TalkList.js +4 -2
  312. package/lib/slides/ui/TalkList.js.map +1 -1
  313. package/lib/structure/core/editorGuide.d.ts +14 -0
  314. package/lib/structure/core/editorGuide.d.ts.map +1 -1
  315. package/lib/structure/core/editorGuide.js +117 -19
  316. package/lib/structure/core/editorGuide.js.map +1 -1
  317. package/lib/structure/core/editorToolbar.d.ts +3 -1
  318. package/lib/structure/core/editorToolbar.d.ts.map +1 -1
  319. package/lib/structure/core/editorToolbar.js +44 -23
  320. package/lib/structure/core/editorToolbar.js.map +1 -1
  321. package/lib/structure/ui/EditorHelpButton.d.ts.map +1 -1
  322. package/lib/structure/ui/EditorHelpButton.js +3 -2
  323. package/lib/structure/ui/EditorHelpButton.js.map +1 -1
  324. package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
  325. package/lib/structure/ui/StructureEditor.js +3 -1
  326. package/lib/structure/ui/StructureEditor.js.map +1 -1
  327. package/lib/structure/ui/StructureEditorHelp.d.ts.map +1 -1
  328. package/lib/structure/ui/StructureEditorHelp.js +12 -3
  329. package/lib/structure/ui/StructureEditorHelp.js.map +1 -1
  330. package/lib/structure/ui/ToolbarTooltip.d.ts.map +1 -1
  331. package/lib/structure/ui/ToolbarTooltip.js +5 -3
  332. package/lib/structure/ui/ToolbarTooltip.js.map +1 -1
  333. package/lib/ui.d.ts +1 -0
  334. package/lib/ui.d.ts.map +1 -1
  335. package/lib/ui.js +1 -0
  336. package/lib/ui.js.map +1 -1
  337. package/package.json +4 -2
  338. package/src/about/ui/AboutBuild.tsx +23 -16
  339. package/src/about/ui/AboutCitations.tsx +3 -1
  340. package/src/about/ui/AboutPage.tsx +38 -12
  341. package/src/about/ui/AboutProvidedBy.tsx +13 -3
  342. package/src/capsule/ui/Capsule.tsx +48 -0
  343. package/src/capsule/ui/CapsuleFilter.tsx +38 -114
  344. package/src/capsule/ui/capsuleFilterCapsules.tsx +110 -0
  345. package/src/chart/ui/ChartTrackingLayer.tsx +4 -2
  346. package/src/chrome/ui/SiteHeader.tsx +5 -3
  347. package/src/citation/ui/CitationMenu.tsx +9 -5
  348. package/src/citation/ui/CiteButton.tsx +4 -2
  349. package/src/citation/ui/CopyFormatEntries.tsx +3 -1
  350. package/src/citation/ui/WorkEntry.tsx +5 -3
  351. package/src/citation/ui/entries.tsx +9 -2
  352. package/src/citation/ui/useCopyFeedback.ts +11 -4
  353. package/src/clipboard/ui/ClickToCopy.tsx +15 -5
  354. package/src/clipboard/ui/CopyButton.tsx +14 -10
  355. package/src/color/ui/ColorScaleEditor.tsx +17 -15
  356. package/src/color/ui/ColorScaleEntry.tsx +7 -3
  357. package/src/color/ui/ColorScaleLegend.tsx +7 -1
  358. package/src/color/ui/ColorScaleSelect.tsx +12 -6
  359. package/src/confirm/ui/ConfirmButton.tsx +9 -11
  360. package/src/core.ts +1 -0
  361. package/src/credits/ui/CreditsList.tsx +5 -1
  362. package/src/delimited/ui/DelimitedTextDialog.tsx +10 -10
  363. package/src/delimited/ui/DelimitedTextPanel.tsx +19 -12
  364. package/src/deploy/core/checkDeploy.ts +7 -1
  365. package/src/deploy/core/index.ts +1 -0
  366. package/src/deploy/core/pageCache.ts +120 -0
  367. package/src/deploy/core/types.ts +2 -1
  368. package/src/download/ui/FigureDownload.tsx +7 -5
  369. package/src/download/ui/FigureDownloadPanel.tsx +31 -25
  370. package/src/ecosystem/ui/EcosystemButton.tsx +5 -3
  371. package/src/ecosystem/ui/EcosystemLinks.tsx +10 -10
  372. package/src/ecosystem/ui/EcosystemMenu.tsx +3 -1
  373. package/src/ecosystem/ui/SiteGroupSection.tsx +6 -2
  374. package/src/ecosystem/ui/SiteTile.tsx +6 -2
  375. package/src/error/ui/ErrorFallback.tsx +13 -12
  376. package/src/help/ui/HelpBody.tsx +4 -2
  377. package/src/help/ui/HelpIcon.tsx +6 -3
  378. package/src/help/ui/HelpToolbarButton.tsx +4 -1
  379. package/src/help/ui/helpName.ts +10 -2
  380. package/src/i18n/core/chromeCatalog.ts +35 -0
  381. package/src/i18n/core/index.ts +26 -0
  382. package/src/i18n/core/languages.ts +46 -0
  383. package/src/i18n/core/messageCatalog.ts +202 -0
  384. package/src/i18n/core/messageValues.ts +2 -0
  385. package/src/i18n/core/session.ts +82 -0
  386. package/src/i18n/core/translateSetup.ts +47 -0
  387. package/src/i18n/ui/LanguageSelect.tsx +72 -0
  388. package/src/i18n/ui/index.ts +9 -0
  389. package/src/i18n/ui/useLanguage.ts +48 -0
  390. package/src/i18n/ui/useT.ts +90 -0
  391. package/src/locales/de.json +442 -0
  392. package/src/locales/en.json +442 -0
  393. package/src/locales/es.json +442 -0
  394. package/src/locales/fr.json +442 -0
  395. package/src/molecule3d/core/gestures.ts +44 -7
  396. package/src/molecule3d/ui/Molecule3DExport.tsx +3 -1
  397. package/src/molecule3d/ui/Molecule3DHelp.tsx +17 -6
  398. package/src/molecule3d/ui/Molecule3DOptions.tsx +13 -13
  399. package/src/molecule3d/ui/Molecule3DSurfaceColors.tsx +16 -13
  400. package/src/molecule3d/ui/Molecule3DToolbar.tsx +29 -18
  401. package/src/molecule3d/ui/MoleculeViewer3D.tsx +13 -8
  402. package/src/orbital/ui/AtomicOrbitalCanvas.tsx +3 -1
  403. package/src/orbital/ui/AtomicOrbitalControls.tsx +15 -20
  404. package/src/orbital/ui/AtomicOrbitalViewer.tsx +13 -13
  405. package/src/orbital/ui/capability.ts +10 -0
  406. package/src/overlay/ui/OverlayBar.tsx +7 -4
  407. package/src/overlay/ui/OverlayInfo.tsx +6 -3
  408. package/src/overlay/ui/OverlayPanel.tsx +10 -7
  409. package/src/overlay/ui/OverlayReadout.tsx +3 -1
  410. package/src/pedagogy/ui/ExerciseActions.tsx +16 -6
  411. package/src/pedagogy/ui/ExerciseProgressHeader.tsx +13 -11
  412. package/src/pedagogy/ui/GlossaryIndex.tsx +11 -12
  413. package/src/pedagogy/ui/HintLadder.tsx +15 -12
  414. package/src/pedagogy/ui/SyntaxTooltip.tsx +9 -7
  415. package/src/pedagogy/ui/TutorialStepStrip.tsx +8 -3
  416. package/src/periodic/ui/CategoryLegend.tsx +6 -1
  417. package/src/periodic/ui/ElementCell.tsx +7 -1
  418. package/src/periodic/ui/PeriodicTable.tsx +3 -1
  419. package/src/periodic/ui/PeriodicTableChrome.tsx +4 -2
  420. package/src/share/ui/ShareButton.tsx +8 -5
  421. package/src/share/ui/ShareConfigOptions.tsx +6 -7
  422. package/src/share/ui/ShareDialog.tsx +3 -1
  423. package/src/share/ui/ShareDialogContent.tsx +20 -10
  424. package/src/share/ui/SharePresetTabs.tsx +3 -1
  425. package/src/slides/ui/BackToSlides.tsx +4 -2
  426. package/src/slides/ui/EmbedSlide.tsx +3 -3
  427. package/src/slides/ui/Slide.tsx +3 -1
  428. package/src/slides/ui/SlideshowBar.tsx +12 -4
  429. package/src/slides/ui/TalkList.tsx +8 -10
  430. package/src/structure/core/editorGuide.ts +126 -19
  431. package/src/structure/core/editorToolbar.ts +52 -24
  432. package/src/structure/ui/EditorHelpButton.tsx +9 -4
  433. package/src/structure/ui/StructureEditor.tsx +7 -1
  434. package/src/structure/ui/StructureEditorHelp.tsx +34 -11
  435. package/src/structure/ui/ToolbarTooltip.tsx +8 -4
  436. package/src/ui.ts +1 -0
@@ -2,6 +2,8 @@ import type { IconName, Intent } from '@blueprintjs/core';
2
2
  import { Button } from '@blueprintjs/core';
3
3
  import type { ReactElement } from 'react';
4
4
 
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
+
5
7
  import {
6
8
  DEFAULT_COPY_RESET_AFTER,
7
9
  useCopyToClipboard,
@@ -24,12 +26,12 @@ export interface CopyButtonProps {
24
26
  label?: string;
25
27
  /**
26
28
  * Text shown while the copy is being confirmed, when there is a label.
27
- * @default 'Copied'
29
+ * @default the chrome's own word for it, in the language of the page
28
30
  */
29
31
  copiedLabel?: string;
30
32
  /**
31
33
  * Text shown while a refused copy is being reported, when there is a label.
32
- * @default 'Copy failed'
34
+ * @default the chrome's own line, in the language of the page
33
35
  */
34
36
  failedLabel?: string;
35
37
  /**
@@ -59,7 +61,7 @@ export interface CopyButtonProps {
59
61
  resetAfter?: number;
60
62
  /**
61
63
  * What the pointer and a screen reader are told.
62
- * @default 'Copy to clipboard'
64
+ * @default the chrome's own line, in the language of the page
63
65
  */
64
66
  title?: string;
65
67
  /**
@@ -79,24 +81,26 @@ export function CopyButton(props: CopyButtonProps): ReactElement {
79
81
  const {
80
82
  content,
81
83
  label,
82
- copiedLabel = 'Copied',
83
- failedLabel = 'Copy failed',
84
+ copiedLabel,
85
+ failedLabel,
84
86
  minimal = false,
85
87
  small = false,
86
88
  icon = 'clipboard',
87
89
  disabled = false,
88
90
  resetAfter = DEFAULT_COPY_RESET_AFTER,
89
- title = 'Copy to clipboard',
91
+ title,
90
92
  className,
91
93
  } = props;
94
+ const t = useChromeT();
92
95
  const { copied, failed, copy } = useCopyToClipboard(resetAfter);
96
+ const hoverTitle = title ?? t('clipboard.copyToClipboard');
93
97
  const look = buttonLook({
94
98
  copied,
95
99
  failed,
96
100
  icon,
97
101
  label,
98
- copiedLabel,
99
- failedLabel,
102
+ copiedLabel: copiedLabel ?? t('clipboard.copied'),
103
+ failedLabel: failedLabel ?? t('clipboard.failed'),
100
104
  });
101
105
 
102
106
  return (
@@ -108,8 +112,8 @@ export function CopyButton(props: CopyButtonProps): ReactElement {
108
112
  intent={look.intent}
109
113
  text={look.text}
110
114
  disabled={disabled}
111
- title={title}
112
- aria-label={label ?? title}
115
+ title={hoverTitle}
116
+ aria-label={label ?? hoverTitle}
113
117
  onClick={() => {
114
118
  void copy(typeof content === 'function' ? content() : content);
115
119
  }}
@@ -2,6 +2,7 @@ import { Button, HTMLSelect } from '@blueprintjs/core';
2
2
  import type { CSSProperties, ReactElement } from 'react';
3
3
 
4
4
  import { formatDecimal } from '../../format/core/numbers.ts';
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
6
  import { normalizeHexColor } from '../core/hex.ts';
6
7
  import type {
7
8
  ColorInterpolation,
@@ -22,14 +23,11 @@ const POSITION_DECIMALS = 2;
22
23
  // hex colour is shown as black until it is picked again.
23
24
  const UNREADABLE_COLOR = '#000000';
24
25
 
25
- /** What each path between two anchors is called. */
26
- const INTERPOLATION_LABELS: Array<{
27
- value: ColorInterpolation;
28
- label: string;
29
- }> = [
30
- { value: 'rgb', label: 'RGB — mix the channels' },
31
- { value: 'hsv', label: 'HSV — turn the short way' },
32
- { value: 'hsv-long', label: 'HSV — turn the long way' },
26
+ /** The paths between two anchors, in the order the picker lists them. */
27
+ const INTERPOLATIONS: readonly ColorInterpolation[] = [
28
+ 'rgb',
29
+ 'hsv',
30
+ 'hsv-long',
33
31
  ];
34
32
 
35
33
  /** What {@link ColorScaleEditor} edits. */
@@ -57,6 +55,7 @@ export interface ColorScaleEditorProps {
57
55
  */
58
56
  export function ColorScaleEditor(props: ColorScaleEditorProps): ReactElement {
59
57
  const { className, value, onChange } = props;
58
+ const t = useChromeT();
60
59
  const stops = value.stops;
61
60
 
62
61
  function write(next: readonly ColorStop[]): void {
@@ -69,7 +68,7 @@ export function ColorScaleEditor(props: ColorScaleEditorProps): ReactElement {
69
68
  scale={value}
70
69
  height={PREVIEW_HEIGHT}
71
70
  samples={PREVIEW_SAMPLES}
72
- label="The scale being edited"
71
+ label={t('color.scaleBeingEdited')}
73
72
  />
74
73
 
75
74
  <div style={ROWS_STYLE}>
@@ -77,7 +76,7 @@ export function ColorScaleEditor(props: ColorScaleEditorProps): ReactElement {
77
76
  <div key={`${String(index)}-${stop.color}`} style={ROW_STYLE}>
78
77
  <input
79
78
  type="color"
80
- aria-label={`Colour of anchor ${String(index + 1)}`}
79
+ aria-label={t('color.anchorColour', { index: index + 1 })}
81
80
  value={normalizeHexColor(stop.color) ?? UNREADABLE_COLOR}
82
81
  style={SWATCH_STYLE}
83
82
  onChange={(event) => {
@@ -86,7 +85,7 @@ export function ColorScaleEditor(props: ColorScaleEditorProps): ReactElement {
86
85
  />
87
86
  <input
88
87
  type="range"
89
- aria-label={`Position of anchor ${String(index + 1)}`}
88
+ aria-label={t('color.anchorPosition', { index: index + 1 })}
90
89
  min={0}
91
90
  max={1}
92
91
  step={POSITION_STEP}
@@ -107,7 +106,7 @@ export function ColorScaleEditor(props: ColorScaleEditorProps): ReactElement {
107
106
  icon="cross"
108
107
  variant="minimal"
109
108
  size="small"
110
- aria-label={`Remove anchor ${String(index + 1)}`}
109
+ aria-label={t('color.removeAnchor', { index: index + 1 })}
111
110
  disabled={stops.length <= MINIMUM_STOPS}
112
111
  onClick={() => {
113
112
  write(stops.filter((_, at) => at !== index));
@@ -121,16 +120,19 @@ export function ColorScaleEditor(props: ColorScaleEditorProps): ReactElement {
121
120
  <Button
122
121
  icon="plus"
123
122
  size="small"
124
- text="Add a colour"
123
+ text={t('color.addColour')}
125
124
  disabled={stops.length >= MAXIMUM_CUSTOM_STOPS}
126
125
  onClick={() => {
127
126
  write(withAddedStop(value));
128
127
  }}
129
128
  />
130
129
  <HTMLSelect
131
- aria-label="Path between two anchors"
130
+ aria-label={t('color.path')}
132
131
  value={value.interpolation}
133
- options={INTERPOLATION_LABELS}
132
+ options={INTERPOLATIONS.map((interpolation) => ({
133
+ value: interpolation,
134
+ label: t(`color.interpolation.${interpolation}`),
135
+ }))}
134
136
  onChange={(event) => {
135
137
  onChange({
136
138
  stops,
@@ -1,6 +1,7 @@
1
1
  import { MenuDivider, MenuItem } from '@blueprintjs/core';
2
2
  import type { CSSProperties, ReactElement } from 'react';
3
3
 
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
4
5
  import { resolveColorScale } from '../core/scaleText.ts';
5
6
  import type { ColorScaleKind } from '../core/scales.ts';
6
7
  import { COLOR_SCALE_KIND_LABELS } from '../core/scales.ts';
@@ -33,14 +34,15 @@ interface ColorScaleEntryProps {
33
34
  */
34
35
  export function ColorScaleEntry(props: ColorScaleEntryProps): ReactElement {
35
36
  const { id, label, kind, description, previous, selected, onChange } = props;
37
+ const t = useChromeT();
36
38
  const entry = (
37
39
  <MenuItem
38
40
  roleStructure="listoption"
39
41
  selected={selected}
40
- htmlTitle={description}
42
+ htmlTitle={t.or(`color.scale.${id}.description`, description)}
41
43
  text={
42
44
  <span style={ITEM_STYLE}>
43
- <span>{label}</span>
45
+ <span>{t.or(`color.scale.${id}.label`, label)}</span>
44
46
  <ColorScaleBar scale={resolveColorScale(id).scale} />
45
47
  </span>
46
48
  }
@@ -52,7 +54,9 @@ export function ColorScaleEntry(props: ColorScaleEntryProps): ReactElement {
52
54
  if (previous === kind) return entry;
53
55
  return (
54
56
  <>
55
- <MenuDivider title={COLOR_SCALE_KIND_LABELS[kind]} />
57
+ <MenuDivider
58
+ title={t.or(`color.kind.${kind}`, COLOR_SCALE_KIND_LABELS[kind])}
59
+ />
56
60
  {entry}
57
61
  </>
58
62
  );
@@ -2,6 +2,7 @@ import type { CSSProperties, ReactElement } from 'react';
2
2
  import { useId } from 'react';
3
3
 
4
4
  import { formatTrimmed } from '../../format/core/numbers.ts';
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
6
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
6
7
  import type { ColorScale } from '../core/interpolate.ts';
7
8
  import { evenScale, sampleScale } from '../core/interpolate.ts';
@@ -66,6 +67,7 @@ export function ColorScaleLegend(props: ColorScaleLegendProps): ReactElement {
66
67
  label = '',
67
68
  formatValue = defaultFormatValue,
68
69
  } = props;
70
+ const t = useChromeT();
69
71
  const gradientId = useId();
70
72
 
71
73
  const stops = gradientStops('stops' in scale ? scale : evenScale(scale));
@@ -81,7 +83,11 @@ export function ColorScaleLegend(props: ColorScaleLegendProps): ReactElement {
81
83
  viewBox={`0 0 ${BAR_WIDTH} ${BAR_HEIGHT}`}
82
84
  preserveAspectRatio="none"
83
85
  role="img"
84
- aria-label={`${label === '' ? 'Colour scale' : label} from ${low} to ${high}`}
86
+ aria-label={t('color.legendLabel', {
87
+ what: label === '' ? t('color.colourScale') : label,
88
+ low,
89
+ high,
90
+ })}
85
91
  >
86
92
  {stops.length === 0 ? null : (
87
93
  <defs>
@@ -8,6 +8,7 @@ import {
8
8
  import type { CSSProperties, ReactElement } from 'react';
9
9
  import { useState } from 'react';
10
10
 
11
+ import { useChromeT } from '../../i18n/ui/useT.ts';
11
12
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
12
13
  import { formatColorScale, resolveColorScale } from '../core/scaleText.ts';
13
14
  import { COLOR_SCALES } from '../core/scales.ts';
@@ -68,6 +69,7 @@ export function ColorScaleSelect(props: ColorScaleSelectProps): ReactElement {
68
69
  allowCustom = true,
69
70
  testId,
70
71
  } = props;
72
+ const t = useChromeT();
71
73
  const [isOpen, setOpen] = useState(false);
72
74
  const [isEditing, setEditing] = useState(false);
73
75
  const resolved = resolveColorScale(value);
@@ -79,14 +81,14 @@ export function ColorScaleSelect(props: ColorScaleSelectProps): ReactElement {
79
81
  icon="chevron-left"
80
82
  variant="minimal"
81
83
  size="small"
82
- text="Scales"
84
+ text={t('color.scales')}
83
85
  onClick={() => {
84
86
  setEditing(false);
85
87
  }}
86
88
  />
87
89
  <Button
88
90
  size="small"
89
- text="Done"
91
+ text={t('color.done')}
90
92
  onClick={() => {
91
93
  setEditing(false);
92
94
  setOpen(false);
@@ -119,8 +121,8 @@ export function ColorScaleSelect(props: ColorScaleSelectProps): ReactElement {
119
121
  <MenuDivider />
120
122
  <MenuItem
121
123
  icon="edit"
122
- text="Custom…"
123
- label={resolved.id === null ? 'in use' : undefined}
124
+ text={t('color.customEllipsis')}
125
+ label={resolved.id === null ? t('color.inUse') : undefined}
124
126
  shouldDismissPopover={false}
125
127
  onClick={() => {
126
128
  setEditing(true);
@@ -150,13 +152,17 @@ export function ColorScaleSelect(props: ColorScaleSelectProps): ReactElement {
150
152
  >
151
153
  <Button
152
154
  alignText="start"
153
- aria-label={label === '' ? 'Colour scale' : label}
155
+ aria-label={label === '' ? t('color.colourScale') : label}
154
156
  data-testid={testId}
155
157
  endIcon="caret-down"
156
158
  fill
157
159
  text={
158
160
  <span style={BUTTON_TEXT_STYLE}>
159
- <span>{resolved.label}</span>
161
+ <span>
162
+ {resolved.id === null
163
+ ? t('color.custom')
164
+ : t.or(`color.scale.${resolved.id}.label`, resolved.label)}
165
+ </span>
160
166
  <ColorScaleBar
161
167
  scale={resolved.scale}
162
168
  style={{ width: BUTTON_BAR_WIDTH }}
@@ -3,6 +3,8 @@ import { Alert, Button } from '@blueprintjs/core';
3
3
  import type { ReactElement, ReactNode } from 'react';
4
4
  import { useState } from 'react';
5
5
 
6
+ import { useChromeT } from '../../i18n/ui/useT.ts';
7
+
6
8
  /** Props of {@link ConfirmButton}: a Blueprint button, and what it asks. */
7
9
  export interface ConfirmButtonProps extends Omit<ButtonProps, 'onClick'> {
8
10
  /**
@@ -14,12 +16,12 @@ export interface ConfirmButtonProps extends Omit<ButtonProps, 'onClick'> {
14
16
  onConfirm: () => void;
15
17
  /**
16
18
  * Text of the button that goes ahead: the verb of what happens, never `OK`.
17
- * @default 'Delete'
19
+ * @default the chrome's own word for it, in the language of the page
18
20
  */
19
21
  confirmLabel?: string;
20
22
  /**
21
23
  * Text of the button that backs out.
22
- * @default 'Cancel'
24
+ * @default the chrome's own word for it, in the language of the page
23
25
  */
24
26
  cancelLabel?: string;
25
27
  }
@@ -35,13 +37,9 @@ export interface ConfirmButtonProps extends Omit<ButtonProps, 'onClick'> {
35
37
  * @returns The button, and the alert it opens.
36
38
  */
37
39
  export function ConfirmButton(props: ConfirmButtonProps): ReactElement {
38
- const {
39
- question,
40
- onConfirm,
41
- confirmLabel = 'Delete',
42
- cancelLabel = 'Cancel',
43
- ...buttonProps
44
- } = props;
40
+ const { question, onConfirm, confirmLabel, cancelLabel, ...buttonProps } =
41
+ props;
42
+ const t = useChromeT();
45
43
  const [asking, setAsking] = useState(false);
46
44
 
47
45
  return (
@@ -58,8 +56,8 @@ export function ConfirmButton(props: ConfirmButtonProps): ReactElement {
58
56
  icon={alertIcon(buttonProps.icon)}
59
57
  canEscapeKeyCancel
60
58
  canOutsideClickCancel
61
- cancelButtonText={cancelLabel}
62
- confirmButtonText={confirmLabel}
59
+ cancelButtonText={cancelLabel ?? t('confirm.cancel')}
60
+ confirmButtonText={confirmLabel ?? t('confirm.delete')}
63
61
  onCancel={() => {
64
62
  setAsking(false);
65
63
  }}
package/src/core.ts CHANGED
@@ -10,6 +10,7 @@ export * from './download/core/index.ts';
10
10
  export * from './ecosystem/core/index.ts';
11
11
  export * from './error/core/index.ts';
12
12
  export * from './format/core/index.ts';
13
+ export * from './i18n/core/index.ts';
13
14
  export * from './language/core/index.ts';
14
15
  export * from './orbital/core/index.ts';
15
16
  export * from './overlay/core/index.ts';
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, ReactElement } from 'react';
2
2
 
3
+ import { useChromeT } from '../../i18n/ui/useT.ts';
3
4
  import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
4
5
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
5
6
  import type { CreditEntry } from '../core/credits.ts';
@@ -32,6 +33,7 @@ export interface CreditsListProps {
32
33
  */
33
34
  export function CreditsList(props: CreditsListProps): ReactElement {
34
35
  const { entries, showLicense = true, className } = props;
36
+ const t = useChromeT();
35
37
 
36
38
  return (
37
39
  <ul
@@ -53,7 +55,9 @@ export function CreditsList(props: CreditsListProps): ReactElement {
53
55
  ) : (
54
56
  ' '
55
57
  )}
56
- <span>{entry.description}</span>
58
+ <span>
59
+ {t.or(`credits.${entry.id}.description`, entry.description)}
60
+ </span>
57
61
  </li>
58
62
  ))}
59
63
  </ul>
@@ -1,6 +1,8 @@
1
1
  import { Button, Dialog, DialogBody, DialogFooter } from '@blueprintjs/core';
2
2
  import type { CSSProperties, ReactElement } from 'react';
3
3
 
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
+
4
6
  import type { DelimitedTextPanelProps } from './DelimitedTextPanel.tsx';
5
7
  import { DelimitedTextPanel } from './DelimitedTextPanel.tsx';
6
8
 
@@ -26,27 +28,25 @@ export interface DelimitedTextDialogProps extends DelimitedTextPanelProps {
26
28
  export function DelimitedTextDialog(
27
29
  props: DelimitedTextDialogProps,
28
30
  ): ReactElement {
29
- const {
30
- isOpen,
31
- onClose,
32
- title = 'Copy the table',
33
- className,
34
- ...panel
35
- } = props;
31
+ const { isOpen, onClose, title, className, ...panel } = props;
32
+ const t = useChromeT();
33
+ const heading = title ?? t('delimited.copyTable');
36
34
 
37
35
  return (
38
36
  <Dialog
39
37
  isOpen={isOpen}
40
38
  onClose={onClose}
41
- title={title}
39
+ title={heading}
42
40
  icon="th"
43
41
  className={className}
44
42
  style={DIALOG_STYLE}
45
43
  >
46
44
  <DialogBody>
47
- <DelimitedTextPanel {...panel} label={panel.label ?? title} />
45
+ <DelimitedTextPanel {...panel} label={panel.label ?? heading} />
48
46
  </DialogBody>
49
- <DialogFooter actions={<Button text="Close" onClick={onClose} />} />
47
+ <DialogFooter
48
+ actions={<Button text={t('delimited.close')} onClick={onClose} />}
49
+ />
50
50
  </Dialog>
51
51
  );
52
52
  }
@@ -6,7 +6,7 @@ import { CopyButton } from '../../clipboard/ui/CopyButton.tsx';
6
6
  import { downloadText } from '../../download/core/downloadText.ts';
7
7
  import { sanitizeFileName } from '../../download/core/sanitizeFileName.ts';
8
8
  import { formatInteger } from '../../format/core/numbers.ts';
9
- import { pluralize } from '../../format/core/words.ts';
9
+ import { useChromeT } from '../../i18n/ui/useT.ts';
10
10
  import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
11
11
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
12
12
  import type { DelimiterId } from '../core/delimiters.ts';
@@ -82,9 +82,10 @@ export function DelimitedTextPanel(
82
82
  fileName = 'table',
83
83
  defaultDelimiter = 'tab',
84
84
  downloadable = true,
85
- label = 'The table, as text',
85
+ label,
86
86
  height = 320,
87
87
  } = props;
88
+ const t = useChromeT();
88
89
  const [delimiterId, setDelimiterId] = useState<string>(defaultDelimiter);
89
90
 
90
91
  const choice = delimiterChoice(delimiterId);
@@ -96,10 +97,16 @@ export function DelimitedTextPanel(
96
97
  return (
97
98
  <div className={joinClassNames('delimited-text', className)}>
98
99
  <Callout intent="primary" compact icon="info-sign">
99
- {description ?? defaultDescription(rows.length)}
100
+ {description ??
101
+ t(
102
+ rows.length === 1
103
+ ? 'delimited.descriptionOne'
104
+ : 'delimited.descriptionMany',
105
+ { count: formatInteger(rows.length) },
106
+ )}
100
107
  </Callout>
101
108
  <div style={CONTROLS_STYLE}>
102
- <span style={LABEL_STYLE}>Separator</span>
109
+ <span style={LABEL_STYLE}>{t('delimited.separator')}</span>
103
110
  <SegmentedControl
104
111
  size="small"
105
112
  options={DELIMITER_CHOICES.map((option) => ({
@@ -113,7 +120,7 @@ export function DelimitedTextPanel(
113
120
  {downloadable ? (
114
121
  <Button
115
122
  icon="download"
116
- text="Save"
123
+ text={t('delimited.save')}
117
124
  size="small"
118
125
  onClick={() =>
119
126
  downloadText(
@@ -124,13 +131,18 @@ export function DelimitedTextPanel(
124
131
  }
125
132
  />
126
133
  ) : null}
127
- <CopyButton content={text} label="Copy" icon="clipboard" small />
134
+ <CopyButton
135
+ content={text}
136
+ label={t('delimited.copy')}
137
+ icon="clipboard"
138
+ small
139
+ />
128
140
  </div>
129
141
  <textarea
130
142
  readOnly
131
143
  value={text}
132
144
  spellCheck={false}
133
- aria-label={label}
145
+ aria-label={label ?? t('delimited.tableAsText')}
134
146
  className={Classes.INPUT}
135
147
  style={{ ...TEXT_STYLE, height }}
136
148
  onFocus={(event) => event.currentTarget.select()}
@@ -139,11 +151,6 @@ export function DelimitedTextPanel(
139
151
  );
140
152
  }
141
153
 
142
- function defaultDescription(rowCount: number): string {
143
- const rows = `${formatInteger(rowCount)} ${pluralize(rowCount, 'row')}`;
144
- return `${rows}, one per line. Copy them, then paste into a spreadsheet.`;
145
- }
146
-
147
154
  const CONTROLS_STYLE = {
148
155
  display: 'flex',
149
156
  flexWrap: 'wrap',
@@ -1,5 +1,6 @@
1
1
  import { readComposeFile } from './composeFile.ts';
2
2
  import { readEnvExample } from './envExample.ts';
3
+ import { readPageCache } from './pageCache.ts';
3
4
  import type { CheckDeployOptions, DeployFile, DeployProblem } from './types.ts';
4
5
  import { DEPLOY_COMPOSE_FILES } from './types.ts';
5
6
 
@@ -12,7 +13,9 @@ import { DEPLOY_COMPOSE_FILES } from './types.ts';
12
13
  * reports it healthy. So a repository has to hand it a selectable tag on every
13
14
  * image we build, an `IMAGE_NAME` that names the package our own workflow
14
15
  * publishes, a compose file that parses on a checkout with no `.env` yet, and a
15
- * health probe to read. Each of those is invisible until a deploy, which is the
16
+ * health probe to read. It also has to hand the browser a page the browser will
17
+ * not keep, or the next deploy leaves returning visitors on a blank one. Each
18
+ * of those is invisible until a deploy, which is the
16
19
  * worst moment to discover it — an `env_file` without `required: false` fails
17
20
  * before a container starts, and an `IMAGE_NAME` off by a suffix pulls a
18
21
  * package that was never published.
@@ -68,6 +71,9 @@ export function findDeployProblems(
68
71
  readEnvExample(envExample, expected, problems);
69
72
  }
70
73
 
74
+ const dockerfile = byPath.get('Dockerfile');
75
+ if (dockerfile !== undefined) readPageCache(dockerfile, byPath, problems);
76
+
71
77
  const gitignore = byPath.get('.gitignore');
72
78
  if (gitignore === undefined || !/^\s*\/?\.deploy\/?\s*$/m.test(gitignore)) {
73
79
  problems.push({
@@ -5,4 +5,5 @@ export type {
5
5
  DeployProblem,
6
6
  DeployProblemKind,
7
7
  } from './types.ts';
8
+ export { NGINX_CONFIG, PAGE_CACHE_CONFIG } from './pageCache.ts';
8
9
  export { DEPLOY_COMPOSE_FILES } from './types.ts';
@@ -0,0 +1,120 @@
1
+ import type { DeployProblem } from './types.ts';
2
+
3
+ /** The page cache policy of a static-web-server site, at the repository root. */
4
+ export const PAGE_CACHE_CONFIG = 'sws.toml';
5
+
6
+ /** The nginx configuration of a site served by nginx. */
7
+ export const NGINX_CONFIG = 'nginx.conf';
8
+
9
+ const NO_CACHE =
10
+ /cache-control[\s:=]+["']?[^"'\n]*(?:no-cache|no-store|max-age=0)/i;
11
+
12
+ /**
13
+ * Report a server that lets a browser keep the page itself.
14
+ *
15
+ * A page names the hashed bundles of the build that wrote it, so a browser
16
+ * still holding a copy from an earlier deploy asks the new image for files it
17
+ * does not have; the request falls through to the page, the browser refuses to
18
+ * run HTML as a module, and the site comes up blank until the copy expires.
19
+ * Nothing on the server can see it and no test can either, because a test
20
+ * always loads a page and its bundles from the same build. So it is read off
21
+ * the server's configuration instead: static-web-server hands pages out with
22
+ * `max-age=86400` of its own, and nginx says nothing and lets the browser
23
+ * guess, so both have to be told. The bundles, named by their content, are the
24
+ * one thing worth keeping.
25
+ * @param dockerfile - The Dockerfile, which says what serves the build.
26
+ * @param byPath - Every file that was read, by repository path.
27
+ * @param problems - Where each problem found is appended.
28
+ */
29
+ export function readPageCache(
30
+ dockerfile: string,
31
+ byPath: ReadonlyMap<string, string>,
32
+ problems: DeployProblem[],
33
+ ): void {
34
+ if (dockerfile.includes('static-web-server')) {
35
+ readStaticWebServer(dockerfile, byPath, problems);
36
+ } else if (/^FROM\s+\S*nginx/im.test(dockerfile)) {
37
+ readNginx(byPath, problems);
38
+ }
39
+ }
40
+
41
+ function readStaticWebServer(
42
+ dockerfile: string,
43
+ byPath: ReadonlyMap<string, string>,
44
+ problems: DeployProblem[],
45
+ ): void {
46
+ const named = /^\s*ENV\s+SERVER_CONFIG_FILE=(?<path>\S+)/m.exec(dockerfile);
47
+ const destination = named?.groups?.path;
48
+ if (destination === undefined) {
49
+ problems.push({
50
+ file: 'Dockerfile',
51
+ line: lineOf(dockerfile, /static-web-server/),
52
+ kind: 'cacheable-page',
53
+ message:
54
+ 'static-web-server keeps every page in the browser for a day, so each deploy blanks the site for anyone who came by before it',
55
+ hint: `COPY ${PAGE_CACHE_CONFIG} /etc/sws.toml and set SERVER_CONFIG_FILE to it`,
56
+ });
57
+ return;
58
+ }
59
+
60
+ const copied = new RegExp(
61
+ String.raw`^\s*COPY\s+(?:--\S+\s+)*${escapeRegExp(PAGE_CACHE_CONFIG)}\s+${escapeRegExp(destination)}\s*$`,
62
+ 'm',
63
+ );
64
+ if (!copied.test(dockerfile)) {
65
+ problems.push({
66
+ file: 'Dockerfile',
67
+ line: lineOf(dockerfile, /^\s*ENV\s+SERVER_CONFIG_FILE=/m),
68
+ kind: 'cacheable-page',
69
+ message: `SERVER_CONFIG_FILE names ${destination}, which nothing puts there`,
70
+ hint: `COPY ${PAGE_CACHE_CONFIG} ${destination}`,
71
+ });
72
+ return;
73
+ }
74
+
75
+ readNoCacheRule(PAGE_CACHE_CONFIG, byPath, problems);
76
+ }
77
+
78
+ function readNginx(
79
+ byPath: ReadonlyMap<string, string>,
80
+ problems: DeployProblem[],
81
+ ): void {
82
+ readNoCacheRule(NGINX_CONFIG, byPath, problems);
83
+ }
84
+
85
+ function readNoCacheRule(
86
+ path: string,
87
+ byPath: ReadonlyMap<string, string>,
88
+ problems: DeployProblem[],
89
+ ): void {
90
+ const text = byPath.get(path);
91
+ if (text === undefined) {
92
+ problems.push({
93
+ file: path,
94
+ line: 0,
95
+ kind: 'cacheable-page',
96
+ message: 'the server has no page cache policy to read',
97
+ hint: `commit ${path} at the repository root, telling the browser to check the page on every visit`,
98
+ });
99
+ return;
100
+ }
101
+ if (!NO_CACHE.test(text)) {
102
+ problems.push({
103
+ file: path,
104
+ line: 0,
105
+ kind: 'cacheable-page',
106
+ message: 'no rule stops a browser from keeping the page between deploys',
107
+ hint: 'give the page Cache-Control: no-cache, and keep the long life for the hashed bundles alone',
108
+ });
109
+ }
110
+ }
111
+
112
+ function lineOf(text: string, pattern: RegExp): number {
113
+ const match = pattern.exec(text);
114
+ if (match === null) return 0;
115
+ return text.slice(0, match.index).split('\n').length;
116
+ }
117
+
118
+ function escapeRegExp(value: string): string {
119
+ return value.replaceAll(/[$()*+.?[\\\]^{|}]/g, String.raw`\$&`);
120
+ }