@morphemecms/cms 0.11.0 → 0.13.0-next-20261106203613

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 (186) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/astro.mjs +2 -1
  3. package/defaults/blockTexts.ts +9 -9
  4. package/defaults/collections.ts +257 -257
  5. package/defaults/colors.ts +74 -74
  6. package/defaults/company.ts +9 -9
  7. package/defaults/editor.ts +65 -65
  8. package/defaults/i18n/da-DK/blockTexts.ts +12 -0
  9. package/defaults/i18n/da-DK/collections.ts +220 -0
  10. package/defaults/i18n/da-DK/colors.ts +102 -0
  11. package/defaults/i18n/da-DK/company.ts +7 -0
  12. package/defaults/i18n/da-DK/editor.ts +13 -0
  13. package/defaults/i18n/da-DK/index.ts +31 -0
  14. package/defaults/i18n/da-DK/internalLinks.ts +12 -0
  15. package/defaults/i18n/da-DK/opens.ts +7 -0
  16. package/defaults/i18n/da-DK/popup.ts +9 -0
  17. package/defaults/i18n/da-DK/privacy.ts +38 -0
  18. package/defaults/i18n/da-DK/rules.ts +56 -0
  19. package/defaults/i18n/da-DK/sitedata.ts +8 -0
  20. package/defaults/i18n/da-DK/standard.ts +8 -0
  21. package/defaults/i18n/da-DK/standardPages.ts +17 -0
  22. package/defaults/internalLinks.ts +8 -8
  23. package/defaults/opens.ts +2 -2
  24. package/defaults/popup.tsx +7 -7
  25. package/defaults/privacy.ts +37 -37
  26. package/defaults/rules.ts +68 -66
  27. package/defaults/schema.ts +1 -1
  28. package/defaults/sitedata.ts +4 -4
  29. package/defaults/standard.ts +9 -6
  30. package/defaults/standardPages.ts +14 -14
  31. package/defaults/texts.ts +7 -510
  32. package/lib/appId.d.mts +1 -0
  33. package/lib/appId.mjs +6 -0
  34. package/lib/appRoute.d.mts +2 -2
  35. package/lib/appRoute.mjs +3 -3
  36. package/lib/appRoute.test.mjs +8 -8
  37. package/lib/apps.mjs +13 -3
  38. package/lib/apps.test.mjs +10 -1
  39. package/lib/contracts.d.mts +3 -2
  40. package/lib/contracts.mjs +3 -2
  41. package/lib/folderChanges.d.mts +29 -0
  42. package/lib/folderChanges.mjs +34 -0
  43. package/lib/licenses.mjs +2 -2
  44. package/lib/licenses.owner.test.mjs +9 -0
  45. package/lib/menu.mjs +4 -4
  46. package/lib/menu.test.mjs +101 -101
  47. package/lib/scheduled.mjs +1 -1
  48. package/lib/section-ranges.d.mts +1 -1
  49. package/lib/section-ranges.mjs +8 -14
  50. package/lib/section-ranges.test.mjs +26 -5
  51. package/lib/storeEntries.d.mts +3 -1
  52. package/lib/storeEntries.mjs +22 -8
  53. package/lib/storeEntries.test.mjs +59 -7
  54. package/lib/text-sections.d.mts +11 -1
  55. package/lib/text-sections.mjs +18 -8
  56. package/lib/text-sections.test.mjs +34 -1
  57. package/lib/translate.d.mts +11 -0
  58. package/lib/translate.mjs +13 -1
  59. package/lib/translate.test.mjs +23 -2
  60. package/lib/video-id.d.mts +6 -2
  61. package/lib/video-id.mjs +5 -1
  62. package/lib/video.d.mts +6 -2
  63. package/lib/video.mjs +5 -1
  64. package/lib/without-h1.d.mts +1 -0
  65. package/lib/without-h1.mjs +19 -4
  66. package/lib/without-h1.test.mjs +30 -1
  67. package/package.json +3 -2
  68. package/scripts/app-screenshots.mjs +9 -8
  69. package/scripts/check-content.mjs +12 -2
  70. package/scripts/check-language.mjs +0 -1
  71. package/scripts/check-site-types.mjs +26 -0
  72. package/scripts/editor-screens.mjs +3 -3
  73. package/scripts/site-types.mjs +14 -0
  74. package/scripts/site-types.test.mjs +21 -0
  75. package/site/activeTheme.test.mjs +52 -0
  76. package/site/appSelf.d.mts +2 -0
  77. package/site/appSelf.mjs +23 -0
  78. package/site/appSelf.test.mjs +35 -0
  79. package/site/content.ts +5 -2
  80. package/site/defineSite.mjs +2 -2
  81. package/site/schema.ts +3 -3
  82. package/site/siteModules.mjs +2 -1
  83. package/site/theme.mjs +19 -8
  84. package/src/Advanced.tsx +2 -2
  85. package/src/App.tsx +79 -78
  86. package/src/AppAdds.tsx +1 -1
  87. package/src/AppList.tsx +39 -24
  88. package/src/BlockDialog.tsx +39 -18
  89. package/src/BlockParts.tsx +6 -6
  90. package/src/BlockSettings.tsx +2 -2
  91. package/src/BrandForm.tsx +2 -2
  92. package/src/Colors.tsx +6 -6
  93. package/src/CompanyForm.tsx +1 -1
  94. package/src/Consents.tsx +3 -3
  95. package/src/CreateFab.tsx +8 -0
  96. package/src/DataForm.tsx +10 -20
  97. package/src/Deleted.tsx +3 -3
  98. package/src/EditorFooter.tsx +2 -2
  99. package/src/EntryForm.tsx +3 -3
  100. package/src/FooterSettings.tsx +2 -2
  101. package/src/FormFrame.tsx +4 -3
  102. package/src/HeaderSettings.tsx +3 -3
  103. package/src/Keywords.tsx +5 -5
  104. package/src/Library.tsx +75 -82
  105. package/src/Licenses.tsx +8 -8
  106. package/src/ListFab.tsx +13 -0
  107. package/src/MainDrawerParts.tsx +3 -3
  108. package/src/MainMenu.tsx +1 -1
  109. package/src/MarkdownEditor.tsx +88 -47
  110. package/src/Media.tsx +11 -20
  111. package/src/MediaTags.tsx +2 -2
  112. package/src/Notifications.tsx +2 -2
  113. package/src/Parts.tsx +17 -17
  114. package/src/Redirects.tsx +14 -22
  115. package/src/Screen.tsx +16 -6
  116. package/src/SeoScores.tsx +6 -6
  117. package/src/SideColumn.tsx +2 -2
  118. package/src/StartFab.tsx +6 -8
  119. package/src/ThemeStore.tsx +37 -16
  120. package/src/Tokens.tsx +2 -2
  121. package/src/apps.ts +7 -8
  122. package/src/checkSite.ts +86 -20
  123. package/src/drawerYield.d.mts +3 -0
  124. package/src/drawerYield.mjs +10 -0
  125. package/src/drawerYield.test.mjs +22 -0
  126. package/src/editor.css +59 -38
  127. package/src/examples.ts +1 -1
  128. package/src/fabScreens.test.mjs +28 -0
  129. package/src/fabScreens.ts +16 -0
  130. package/src/i18n/da-DK/library.ts +2 -2
  131. package/src/i18n/da-DK/text.ts +1 -1
  132. package/src/i18n/en-US/apps.ts +1 -1
  133. package/src/i18n/en-US/common.ts +8 -8
  134. package/src/i18n/en-US/library.ts +5 -5
  135. package/src/i18n/en-US/parts.ts +3 -3
  136. package/src/i18n/en-US/text.ts +1 -1
  137. package/src/i18n/index.ts +4 -8
  138. package/src/images.ts +2 -2
  139. package/src/legacyMove.test.mjs +137 -0
  140. package/src/legacyMove.ts +131 -0
  141. package/src/licenseData.ts +3 -3
  142. package/src/markdown.mjs +10 -7
  143. package/src/markdown.test.mjs +16 -2
  144. package/src/menuChildren.ts +5 -5
  145. package/src/menuOpen.ts +20 -4
  146. package/src/movedRoutes.d.mts +8 -1
  147. package/src/movedRoutes.mjs +102 -21
  148. package/src/movedRoutes.test.mjs +128 -6
  149. package/src/nav.ts +1 -1
  150. package/src/notificationData.ts +1 -1
  151. package/src/pageH1Panel.d.mts +4 -0
  152. package/src/pageH1Panel.mjs +31 -0
  153. package/src/pageH1Panel.test.mjs +56 -0
  154. package/src/pagePreview.tsx +22 -12
  155. package/src/schema.ts +2 -2
  156. package/src/sectionFrame.ts +3 -3
  157. package/src/sectionState.d.mts +3 -3
  158. package/src/sectionState.mjs +6 -6
  159. package/src/sectionState.test.mjs +14 -2
  160. package/src/sheetPlacement.d.mts +6 -4
  161. package/src/sheetPlacement.mjs +15 -10
  162. package/src/sheetPlacement.test.mjs +16 -9
  163. package/src/sidePanel.ts +38 -0
  164. package/src/site.ts +37 -13
  165. package/src/standard/accordion/index.tsx +1 -1
  166. package/src/standard/accordion/shared.ts +1 -1
  167. package/src/standard/buttons/index.tsx +1 -1
  168. package/src/standard/cards/index.tsx +1 -1
  169. package/src/standard/cards/shared.ts +1 -1
  170. package/src/standard/cookies/index.tsx +1 -1
  171. package/src/standard/posts/index.tsx +1 -1
  172. package/src/standard/testimonials/index.tsx +1 -1
  173. package/src/standard/testimonials/list.ts +1 -1
  174. package/src/store.ts +36 -31
  175. package/src/tagUses.d.mts +1 -1
  176. package/src/tagUses.mjs +2 -2
  177. package/src/tagUses.test.mjs +1 -1
  178. package/src/topBarSlot.tsx +7 -15
  179. package/src/ui.tsx +33 -22
  180. package/src/virtual.d.ts +6 -0
  181. package/starter/package.json +1 -1
  182. package/theme/components/PageHeading.astro +22 -0
  183. package/theme/layouts/Base.astro +2 -2
  184. package/theme/layouts/PageLayout.astro +37 -20
  185. package/theme/styles/global.css +2 -1
  186. package/theme/styles/ui.css +40 -10
@@ -3,7 +3,7 @@
3
3
  // (packages/editor/site/*.ts); keep them in step.
4
4
  // markdown: a folder of .md files (front matter + text): blog posts and pages.
5
5
  // folder: a folder of .json files, one entry per file: categories, promotions (the testimonials are the standard
6
- // block "Udtalelser"'s, packages/editor/src/standard/testimonials/list.ts, an app's lists its own,
6
+ // block "Testimonials"'s, packages/editor/src/standard/testimonials/list.ts, an app's lists its own,
7
7
  // src/apps/<app>/lists.ts).
8
8
  // files: single .json files: the settings (the standard pages …), the footer and the menu.
9
9
  import { AppWindow, ArrowsHorizontal, ColumnsPlusLeft, ColumnsPlusRight, File, SquareHalfBottom } from '@phosphor-icons/react';
@@ -13,32 +13,32 @@ import { config } from '@site/config';
13
13
  import { standardPaths } from '@site/standardPages';
14
14
 
15
15
  // The fields of one button of the action bar (the bottom bar on a phone, ActionBar.astro) and of the button in the header
16
- // ("Headerknap", src/data/header.json): its text, where it leads, and the promotion or page it leads to.
16
+ // ("Header button", src/data/header.json): its text, where it leads, and the promotion or page it leads to.
17
17
  const barButtonLabel: Field = {
18
18
  name: 'label',
19
- label: 'Knaptekst',
19
+ label: 'Button text',
20
20
  type: 'string',
21
21
  max: 30,
22
- hint: 'Hvis feltet er tomt, bruges standardteksten eller sidens navn.',
22
+ hint: "If the field is empty, the standard text or the page's name is used.",
23
23
  };
24
24
 
25
25
  const barButtonTo: Field = {
26
26
  name: 'to',
27
- label: 'Fører til',
27
+ label: 'Leads to',
28
28
  type: 'select',
29
29
  required: true,
30
30
  default: 'booking',
31
31
  options: [
32
- { label: 'Book en tid', value: 'booking' },
33
- { label: 'Ring', value: 'phone' },
34
- { label: 'Åbn promovering', value: 'promotion', onPage: 'promotions' },
35
- { label: 'En side', value: 'page' },
32
+ { label: 'Book an appointment', value: 'booking' },
33
+ { label: 'Call', value: 'phone' },
34
+ { label: 'Open promotion', value: 'promotion', onPage: 'promotions' },
35
+ { label: 'A page', value: 'page' },
36
36
  ],
37
37
  };
38
38
 
39
39
  const barButtonOpen: Field = {
40
40
  name: 'open',
41
- label: 'Promovering',
41
+ label: 'Promotion',
42
42
  type: 'relation',
43
43
  to: 'promotions',
44
44
  onPage: true,
@@ -48,7 +48,7 @@ const barButtonOpen: Field = {
48
48
 
49
49
  const barButtonHref: Field = {
50
50
  name: 'href',
51
- label: 'Side',
51
+ label: 'Page',
52
52
  type: 'relation',
53
53
  to: 'pages',
54
54
  fixed: true,
@@ -57,39 +57,39 @@ const barButtonHref: Field = {
57
57
  };
58
58
 
59
59
  // The page Google should count as the original of a page or a post (rel=canonical); empty is itself.
60
- // Under "Søgemaskiner" with the Google texts (EntryForm.tsx).
60
+ // Under "Search engines" with the Google texts (EntryForm.tsx).
61
61
  const canonical: Field = {
62
62
  name: 'canonical',
63
63
  label: 'Canonical URL',
64
64
  type: 'relation',
65
65
  to: 'pages',
66
66
  fixed: true,
67
- hint: 'Den side, Google skal vise i stedet for denne.',
67
+ hint: 'The page Google should show instead of this one.',
68
68
  };
69
69
 
70
- // Not for search engines: noindex, and not in the sitemap. Under "Søgemaskiner" too.
70
+ // Not for search engines: noindex, and not in the sitemap. Under "Search engines" too.
71
71
  const noindex: Field = {
72
72
  name: 'noindex',
73
- label: 'Skjul for søgemaskiner (noindex)',
73
+ label: 'Hide from search engines (noindex)',
74
74
  type: 'boolean',
75
- hint: 'Siden vises ikke i Google.',
75
+ hint: 'The page is not shown in Google.',
76
76
  };
77
77
 
78
- // The text of the picture at the top of a post (a page has its pictures in its text): "Dekorativt billede" (drawn with alt="", screen readers skip
79
- // it), else its alternative text.
78
+ // The text of the picture at the top of a post (a page has its pictures in its text): "Decorative picture" (drawn with alt="", screen readers skip
79
+ // it), else its alt text.
80
80
  const topImageText: Field[] = [
81
81
  {
82
82
  name: 'imageDecorative',
83
- label: 'Dekorativt billede',
83
+ label: 'Decorative picture',
84
84
  type: 'boolean',
85
- toggle: ['Til', 'Fra'],
86
- hint: 'Skærmlæsere springer billedet over.',
85
+ toggle: ['On', 'Off'],
86
+ hint: 'Screen readers skip the picture.',
87
87
  },
88
- { name: 'imageAlt', label: 'Alternativ tekst', type: 'string', only: { field: 'imageDecorative', is: ['', 'false'] } },
88
+ { name: 'imageAlt', label: 'Alt text', type: 'string', only: { field: 'imageDecorative', is: ['', 'false'] } },
89
89
  ];
90
90
 
91
- // "Status" at the top of a page or post (EntryForm.tsx): Kladde, Skjult, Udgivet or Planlagt, and for
92
- // Planlagt when (packages/editor/lib/status.mjs). Udgivet is no `status` in the file. A post's date follows the time.
91
+ // "Status" at the top of a page or post (EntryForm.tsx): Draft, Hidden, Published or Scheduled, and for
92
+ // Scheduled when (packages/editor/lib/status.mjs). Published is no `status` in the file. A post's date follows the time.
93
93
  const status = (hidden: string): Field[] => [
94
94
  {
95
95
  name: 'status',
@@ -97,96 +97,96 @@ const status = (hidden: string): Field[] => [
97
97
  type: 'select',
98
98
  segments: true,
99
99
  options: [
100
- { value: 'draft', label: 'Kladde', hint: 'Vises ikke på hjemmesiden.' },
101
- { value: 'unlisted', label: 'Skjult', hint: hidden },
102
- { value: '', label: 'Udgivet', hint: 'Vises på hjemmesiden.' },
103
- { value: 'scheduled', label: 'Planlagt', hint: 'Vises på hjemmesiden fra tidspunktet nedenfor.' },
100
+ { value: 'draft', label: 'Draft', hint: 'Not shown on the website.' },
101
+ { value: 'unlisted', label: 'Hidden', hint: hidden },
102
+ { value: '', label: 'Published', hint: 'Shown on the website.' },
103
+ { value: 'scheduled', label: 'Scheduled', hint: 'Shown on the website from the time below.' },
104
104
  ],
105
105
  },
106
106
  {
107
107
  name: 'publishAt',
108
- label: 'Tidspunkt',
108
+ label: 'Time',
109
109
  type: 'datetime',
110
110
  required: true,
111
111
  only: { field: 'status', is: ['scheduled'] },
112
- hint: 'Udgives senest en time efter.',
112
+ hint: 'Published at most an hour after.',
113
113
  },
114
114
  ];
115
115
 
116
- // The Google texts, and the picture when the page is shared, which the editor shows under "Sociale medier" (SHARE_FIELDS
116
+ // The Google texts, and the picture when the page is shared, which the editor shows under "Social media" (SHARE_FIELDS
117
117
  // in packages/editor/src/seo.ts).
118
118
  const seo: Field[] = [
119
119
  {
120
120
  name: 'seoTitle',
121
- label: 'Google-titel',
121
+ label: 'Google title',
122
122
  type: 'string',
123
- hint: 'Højst ca. 60 tegn.',
123
+ hint: 'At most about 60 characters.',
124
124
  max: 70,
125
125
  },
126
126
  {
127
127
  name: 'seoDescription',
128
- label: 'Google-beskrivelse',
128
+ label: 'Google description',
129
129
  type: 'text',
130
- hint: 'Ca. 140-155 tegn.',
130
+ hint: 'About 140-155 characters.',
131
131
  max: 170,
132
132
  },
133
133
  // og:image (Base.astro), cut to 1200 × 630 by packages/editor/scripts/responsive-images.mjs.
134
134
  {
135
135
  name: 'shareImage',
136
- label: 'Billede ved deling',
136
+ label: 'Picture when shared',
137
137
  type: 'image',
138
- hint: 'Vises, når siden deles, fx på Facebook.',
138
+ hint: 'Shown when the page is shared, e.g. on Facebook.',
139
139
  },
140
140
  ];
141
141
 
142
- // The title and description when a page or post is shared (og:title, og:description in Base.astro), under "Sociale
143
- // medier" with the picture.
142
+ // The title and description when a page or post is shared (og:title, og:description in Base.astro), under "Social
143
+ // media" with the picture.
144
144
  const shareTexts: Field[] = [
145
145
  {
146
146
  name: 'shareTitle',
147
- label: 'Titel ved deling',
147
+ label: 'Title when shared',
148
148
  type: 'string',
149
- hint: 'Hvis feltet er tomt, bruges Google-titlen.',
149
+ hint: 'If the field is empty, the Google title is used.',
150
150
  max: 70,
151
151
  },
152
152
  {
153
153
  name: 'shareDescription',
154
- label: 'Beskrivelse ved deling',
154
+ label: 'Description when shared',
155
155
  type: 'text',
156
- hint: 'Hvis feltet er tomt, bruges Google-beskrivelsen.',
156
+ hint: 'If the field is empty, the Google description is used.',
157
157
  max: 170,
158
158
  },
159
159
  ];
160
160
 
161
161
  // The words that link to a page or post from the others (packages/editor/site/autolinks.mjs). Under
162
- // "Søgemaskiner" with the Google texts (EntryForm.tsx).
162
+ // "Search engines" with the Google texts (EntryForm.tsx).
163
163
  const keywords: Field[] = [
164
164
  {
165
165
  name: 'keyword',
166
- label: 'Primært søgeord',
166
+ label: 'Main keyword',
167
167
  type: 'string',
168
168
  chips: 'one',
169
- hint: 'Ordet bliver et link hertil fra andre sider.',
169
+ hint: 'The word becomes a link to here from other pages.',
170
170
  },
171
171
  {
172
172
  name: 'keywords',
173
- label: 'Sekundære søgeord',
173
+ label: 'Other keywords',
174
174
  type: 'string',
175
175
  chips: 'many',
176
- hint: 'Hvert ord bliver et link hertil fra andre sider.',
176
+ hint: 'Each word becomes a link to here from other pages.',
177
177
  },
178
178
  ];
179
179
 
180
- // The business, on "Virksomheden" (CompanyForm.tsx): its name and title, phone, e-mail, address and CVR number
181
- // (src/data/contact.json), shown at the top and bottom of every page and in the blocks that show them ("Kontakt" and
182
- // "Adresse"); and the bank details (src/data/payment.json), shown in "Betaling". The calendar
180
+ // The business, on "Business" (CompanyForm.tsx): its name and title, phone, e-mail, address and CVR number
181
+ // (src/data/contact.json), shown at the top and bottom of every page and in the blocks that show them ("Contact" and
182
+ // "Address"); and the bank details (src/data/payment.json), shown in "Payment". The calendar
183
183
  // is the app Calendly's (morpheme-apps/apps/calendly/).
184
184
  export const contactFields: Field[] = [
185
- { name: 'name', label: 'Navn', type: 'string', required: true },
186
- { name: 'role', label: 'Titel', type: 'string', required: true },
185
+ { name: 'name', label: 'Name', type: 'string', required: true },
186
+ { name: 'role', label: 'Title', type: 'string', required: true },
187
187
  {
188
188
  name: 'phone',
189
- label: 'Telefon',
189
+ label: 'Phone',
190
190
  type: 'string',
191
191
  required: true,
192
192
  digitsInPairs: 8,
@@ -194,41 +194,41 @@ export const contactFields: Field[] = [
194
194
  },
195
195
  {
196
196
  name: 'email',
197
- label: 'E-mail',
197
+ label: 'Email',
198
198
  type: 'string',
199
199
  required: true,
200
200
  pattern: [
201
201
  '^[A-Za-z0-9._%+-]+@[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*\\.[A-Za-z]{2,}$',
202
- 'Skriv en gyldig e-mailadresse',
202
+ 'Write a valid email address',
203
203
  ],
204
204
  },
205
205
  {
206
206
  name: 'street',
207
- label: 'Vej og nummer',
207
+ label: 'Street and number',
208
208
  type: 'string',
209
209
  required: true,
210
210
  },
211
- { name: 'city', label: 'Postnummer og by', type: 'string', required: true },
211
+ { name: 'city', label: 'Postcode and town', type: 'string', required: true },
212
212
  {
213
213
  name: 'cvr',
214
- label: 'CVR-nummer',
214
+ label: 'CVR number',
215
215
  type: 'string',
216
- hint: 'Vises nederst på hver side.',
217
- pattern: ['^\\d{8}$', 'Et CVR-nummer har otte cifre'],
216
+ hint: 'Shown at the bottom of every page.',
217
+ pattern: ['^\\d{8}$', 'A CVR number has eight digits'],
218
218
  },
219
219
  ];
220
220
 
221
- // The social media (src/data/social.json, a part of its own under "Virksomheden", company.ts): the site's profiles, and
221
+ // The social media (src/data/social.json, a part of its own under "Business", company.ts): the site's profiles, and
222
222
  // which share buttons a post shows. A switch that is not in the file is on (company.ts gives the form that default).
223
223
  // A profile address: empty, or one that begins with https://.
224
- const httpsAddress: [string, string] = ['^$|^https://\\S+$', 'Skriv en adresse, der begynder med https://'];
224
+ const httpsAddress: [string, string] = ['^$|^https://\\S+$', 'Write an address that starts with https://'];
225
225
 
226
226
  export const socialFields: Field[] = [
227
227
  {
228
228
  name: 'facebook',
229
229
  label: 'Facebook',
230
230
  type: 'string',
231
- hint: 'Adressen på sitets profil. Vises i Googles data om virksomheden.',
231
+ hint: "The address of the site's profile. Shown in Google's data about the business.",
232
232
  pattern: httpsAddress,
233
233
  },
234
234
  {
@@ -267,94 +267,94 @@ export const socialFields: Field[] = [
267
267
  type: 'string',
268
268
  pattern: httpsAddress,
269
269
  },
270
- { name: 'shareFacebook', label: 'Del på Facebook', type: 'boolean' },
271
- { name: 'shareX', label: 'Del på X', type: 'boolean' },
272
- { name: 'shareLinkedin', label: 'Del på LinkedIn', type: 'boolean' },
273
- { name: 'sharePinterest', label: 'Del på Pinterest', type: 'boolean', hint: 'Vises kun, når indlægget har et billede.' },
274
- { name: 'shareCopyLink', label: 'Kopiér link', type: 'boolean' },
270
+ { name: 'shareFacebook', label: 'Share on Facebook', type: 'boolean' },
271
+ { name: 'shareX', label: 'Share on X', type: 'boolean' },
272
+ { name: 'shareLinkedin', label: 'Share on LinkedIn', type: 'boolean' },
273
+ { name: 'sharePinterest', label: 'Share on Pinterest', type: 'boolean', hint: 'Shown only when the post has a picture.' },
274
+ { name: 'shareCopyLink', label: 'Copy link', type: 'boolean' },
275
275
  ];
276
276
 
277
- // The bank details, a part of its own under "Betaling" (company.ts, src/data/payment.json).
277
+ // The bank details, a part of its own under "Payment" (company.ts, src/data/payment.json).
278
278
  export const bankFields: Field[] = [
279
279
  { name: 'bank', label: 'Bank', type: 'string', required: true },
280
- { name: 'reg', label: 'Reg.nr.', type: 'string', required: true },
281
- { name: 'account', label: 'Kontonummer', type: 'string', required: true },
280
+ { name: 'reg', label: 'Reg. no.', type: 'string', required: true },
281
+ { name: 'account', label: 'Account number', type: 'string', required: true },
282
282
  ];
283
283
 
284
284
  // The standard pages (src/data/standard-pages.json, config.standardPages, packages/editor/defaults/standardPages.ts), each a field that
285
285
  // picks a page, as rows of a list (Part.rows): the front page, shown at / (packages/editor/site/home.ts), the blog page, shown at
286
286
  // /blog/, the page shown for an address that does not exist (packages/editor/site/standardPages.ts) and the contact page under
287
- // "Udseende" › "Standardsider" (appearance in editor.ts), and the privacy policy and the cookie policy under "Privatliv" ›
288
- // "Privatlivssider" (privacy.ts). Different pages, but the cookie policy may be the privacy policy (keptBy in rules.ts).
287
+ // "Appearance" › "Default pages" (appearance in editor.ts), and the privacy policy and the cookie policy under "Privacy" ›
288
+ // "Privacy pages" (privacy.ts). Different pages, but the cookie policy may be the privacy policy (keptBy in rules.ts).
289
289
  const standardPageFields: Field[] = [
290
290
  {
291
291
  name: 'front',
292
- label: 'Forside',
292
+ label: 'Front page',
293
293
  type: 'relation',
294
294
  to: 'standardPages',
295
295
  required: true,
296
- hint: 'Siden vises på forsiden, og dens egen adresse sender videre dertil.',
296
+ hint: 'The page is shown on the front page, and its own address sends on there.',
297
297
  },
298
298
  {
299
299
  name: 'blog',
300
- label: 'Blogside',
300
+ label: 'Blog page',
301
301
  type: 'relation',
302
302
  to: 'standardPages',
303
303
  required: true,
304
- hint: 'Siden vises på /blog/, og dens egen adresse sender videre dertil.',
304
+ hint: 'The page is shown at /blog/, and its own address sends on there.',
305
305
  },
306
306
  {
307
307
  name: 'notFound',
308
- label: '404-side',
308
+ label: '404 page',
309
309
  type: 'relation',
310
310
  to: 'standardPages',
311
311
  required: true,
312
- hint: 'Siden vises, når en adresse ikke findes.',
312
+ hint: 'The page is shown when an address does not exist.',
313
313
  },
314
314
  {
315
315
  name: 'contact',
316
- label: 'Kontaktside',
316
+ label: 'Contact page',
317
317
  type: 'relation',
318
318
  to: 'standardPages',
319
319
  required: true,
320
- hint: 'Linket til vejvisningen går hertil.',
320
+ hint: 'The link to the directions goes here.',
321
321
  },
322
322
  {
323
323
  name: 'privacy',
324
- label: 'Privatlivspolitik',
324
+ label: 'Privacy policy',
325
325
  type: 'relation',
326
326
  to: 'standardPages',
327
327
  required: true,
328
- hint: 'Siden, der fortæller, hvilke oplysninger der gemmes, og hvorfor.',
328
+ hint: 'The page that tells what information is stored, and why.',
329
329
  },
330
330
  {
331
331
  name: 'cookies',
332
- label: 'Cookiepolitik',
332
+ label: 'Cookie policy',
333
333
  type: 'relation',
334
334
  to: 'standardPages',
335
335
  required: true,
336
- hint: 'Cookiebannerets link går hertil; det må være privatlivspolitikken.',
336
+ hint: "The cookie banner's link goes here; it may be the privacy policy.",
337
337
  },
338
338
  ];
339
339
 
340
340
  /** The fields of the standard pages by their keys, in that order. */
341
341
  export const standardPageFieldsOf = (...keys: string[]) => keys.map((key) => standardPageFields.find((f) => f.name === key)!);
342
342
 
343
- /** The "Book en tid" box's own heading and text, in a page's text; empty,
344
- * the shared ones ("Blokke" › "Book en tid", booking.json). */
343
+ /** The "Book an appointment" box's own heading and text, in a page's text; empty,
344
+ * the shared ones ("Blocks" › "Book an appointment", booking.json). */
345
345
  export const bookingTexts: Field[] = [
346
346
  {
347
347
  name: 'heading',
348
- label: 'Overskrift',
348
+ label: 'Heading',
349
349
  type: 'string',
350
- hint: 'Hvis feltet er tomt, bruges standardteksten.',
350
+ hint: 'If empty, the default text is used.',
351
351
  placeholder: (site) => site.booking.heading,
352
352
  },
353
353
  {
354
354
  name: 'text',
355
- label: 'Tekst',
355
+ label: 'Text',
356
356
  type: 'text',
357
- hint: 'Hvis feltet er tomt, bruges standardteksten.',
357
+ hint: 'If empty, the default text is used.',
358
358
  placeholder: (site) => site.booking.text,
359
359
  },
360
360
  ];
@@ -362,64 +362,64 @@ export const bookingTexts: Field[] = [
362
362
  // The icons the owner picks from on the site's own fields (the same as the standard blocks', iconNames in
363
363
  // packages/editor/src/icon.tsx, which draws them).
364
364
  export const icons = [
365
- ['Diplom', 'certificate'],
366
- ['Hjerte', 'heart'],
367
- ['Hånd med hjerte', 'hand-heart'],
368
- ['Tre personer', 'users-three'],
369
- ['To personer', 'users'],
370
- ['Studenterhue', 'graduation-cap'],
371
- ['Håndtryk', 'handshake'],
372
- ['Bog', 'book-open'],
373
- ['Bog med tekst', 'book-open-text'],
374
- ['Medalje', 'medal'],
375
- ['Samtale', 'chats'],
376
- ['Lotusblomst', 'flower-lotus'],
377
- ['Blad', 'leaf'],
378
- ['Pære', 'lightbulb'],
379
- ['Tog', 'train'],
365
+ ['Diploma', 'certificate'],
366
+ ['Heart', 'heart'],
367
+ ['Hand with heart', 'hand-heart'],
368
+ ['Three people', 'users-three'],
369
+ ['Two people', 'users'],
370
+ ['Graduation cap', 'graduation-cap'],
371
+ ['Handshake', 'handshake'],
372
+ ['Book', 'book-open'],
373
+ ['Book with text', 'book-open-text'],
374
+ ['Medal', 'medal'],
375
+ ['Conversation', 'chats'],
376
+ ['Lotus flower', 'flower-lotus'],
377
+ ['Leaf', 'leaf'],
378
+ ['Light bulb', 'lightbulb'],
379
+ ['Train', 'train'],
380
380
  ['Bus', 'bus'],
381
- ['Cykel', 'bicycle'],
382
- ['Bil', 'car'],
383
- ['Dør', 'door-open'],
384
- ['Videokamera', 'video-camera'],
385
- ['Redningskrans', 'lifebuoy'],
386
- ['Telefon', 'phone'],
387
- ['Ur', 'clock'],
388
- ['Kortnål', 'map-pin'],
389
- ['Kaffe', 'coffee'],
390
- ['Kørestol', 'wheelchair'],
391
- ['Info', 'info'],
392
- ['Brev', 'envelope-simple'],
381
+ ['Bicycle', 'bicycle'],
382
+ ['Car', 'car'],
383
+ ['Door', 'door-open'],
384
+ ['Video camera', 'video-camera'],
385
+ ['Lifebuoy', 'lifebuoy'],
386
+ ['Phone', 'phone'],
387
+ ['Clock', 'clock'],
388
+ ['Map pin', 'map-pin'],
389
+ ['Coffee', 'coffee'],
390
+ ['Wheelchair', 'wheelchair'],
391
+ ['Information', 'info'],
392
+ ['Letter', 'envelope-simple'],
393
393
  ].map(([label, value]) => ({ label, value }));
394
394
 
395
395
  // A link in the menu: any page, the front page and the blog too, stored by its address.
396
- const menuHref: Field = { name: 'href', label: 'Side', type: 'relation', to: 'pages', fixed: true, required: true };
396
+ const menuHref: Field = { name: 'href', label: 'Page', type: 'relation', to: 'pages', fixed: true, required: true };
397
397
 
398
398
  export const collections: Collection[] = [
399
399
  {
400
400
  kind: 'markdown',
401
401
  id: 'blog',
402
- create: 'Nyt blogindlæg',
403
- label: 'Blogindlæg',
404
- singular: 'blogindlæg',
402
+ create: 'New blog post',
403
+ label: 'Blog posts',
404
+ singular: 'blog post',
405
405
  folder: 'src/content/blog',
406
406
  deletable: true,
407
407
  fields: [
408
- ...status('Vises ikke på bloggen eller i Google, men kan åbnes på sin adresse.'),
409
- { name: 'title', label: 'Titel', type: 'string', required: true },
410
- { name: 'date', label: 'Dato', type: 'date', required: true },
411
- { name: 'path', label: 'Adresse', type: 'string', address: 'post' },
412
- { name: 'description', label: 'Kort beskrivelse', type: 'text' },
408
+ ...status('Not shown on the blog or in Google, but can be opened at its address.'),
409
+ { name: 'title', label: 'Title', type: 'string', required: true },
410
+ { name: 'date', label: 'Date', type: 'date', required: true },
411
+ { name: 'path', label: 'URL', type: 'string', address: 'post' },
412
+ { name: 'description', label: 'Short description', type: 'text' },
413
413
  {
414
414
  name: 'categories',
415
415
  label: 'Tags',
416
416
  type: 'relation',
417
417
  to: 'categories',
418
418
  multiple: true,
419
- add: 'Tilføj tag',
420
- edit: { to: 'ny/kategorier', text: 'Opret et tag' },
419
+ add: 'Add tag',
420
+ edit: { to: 'new/tags', text: 'Create a tag' },
421
421
  },
422
- { name: 'image', label: 'Billede øverst', type: 'image' },
422
+ { name: 'image', label: 'Picture at the top', type: 'image' },
423
423
  ...topImageText,
424
424
  ...seo,
425
425
  ...shareTexts,
@@ -431,46 +431,46 @@ export const collections: Collection[] = [
431
431
  {
432
432
  kind: 'markdown',
433
433
  id: 'pages',
434
- create: 'Ny side',
435
- label: 'Sider',
436
- singular: 'side',
434
+ create: 'New page',
435
+ label: 'Pages',
436
+ singular: 'page',
437
437
  folder: 'src/content/pages',
438
438
  fields: [
439
- ...status('Vises ikke i Google, men kan åbnes på sin adresse.'),
440
- { name: 'title', label: 'Titel', type: 'string', required: true },
441
- { name: 'path', label: 'Adresse', type: 'string', address: 'page' },
442
- { name: 'description', label: 'Kort beskrivelse', type: 'text' },
439
+ ...status('Not shown in Google, but can be opened at its address.'),
440
+ { name: 'title', label: 'Title', type: 'string', required: true },
441
+ { name: 'path', label: 'URL', type: 'string', address: 'page' },
442
+ { name: 'description', label: 'Short description', type: 'text' },
443
443
  {
444
444
  name: 'categories',
445
445
  label: 'Tags',
446
446
  type: 'relation',
447
447
  to: 'categories',
448
448
  multiple: true,
449
- add: 'Tilføj tag',
450
- edit: { to: 'ny/kategorier', text: 'Opret et tag' },
451
- hint: 'Vises ikke på hjemmesiden.',
449
+ add: 'Add tag',
450
+ edit: { to: 'new/tags', text: 'Create a tag' },
451
+ hint: 'Not shown on the website.',
452
452
  },
453
453
  {
454
454
  name: 'template',
455
- label: 'Skabelon',
455
+ label: 'Template',
456
456
  type: 'select',
457
457
  segments: true,
458
458
  layout: true,
459
459
  // The options the theme in use offers, the first of its list the default (templateFieldOf in src/templateField.ts).
460
460
  offered: 'templates',
461
461
  options: [
462
- { label: 'En kolonne', value: 'single', icon: File },
463
- { label: 'Fuld bredde', value: 'full', icon: ArrowsHorizontal },
464
- { label: 'Sidebjælke til venstre', value: 'sidebar-left', icon: ColumnsPlusLeft },
465
- { label: 'Sidebjælke til højre', value: 'sidebar-right', icon: ColumnsPlusRight },
462
+ { label: 'Single column', value: 'single', icon: File },
463
+ { label: 'Full width', value: 'full', icon: ArrowsHorizontal },
464
+ { label: 'Sidebar left', value: 'sidebar-left', icon: ColumnsPlusLeft },
465
+ { label: 'Sidebar right', value: 'sidebar-right', icon: ColumnsPlusRight },
466
466
  ],
467
- hint: 'Temaet bestemmer, hvilke skabeloner der findes.',
467
+ hint: 'The theme decides which templates there are.',
468
468
  },
469
469
  {
470
470
  name: 'review',
471
- label: 'Til gennemsyn',
471
+ label: 'For review',
472
472
  type: 'text',
473
- hint: 'Vises kun på sider under /ny/.',
473
+ hint: 'Only shown on pages under /ny/.',
474
474
  },
475
475
  ...seo,
476
476
  ...shareTexts,
@@ -479,14 +479,14 @@ export const collections: Collection[] = [
479
479
  noindex,
480
480
  ],
481
481
  blocks: true,
482
- // One "Book en tid" a page (at the very end it goes across the page, PageLayout.astro). A new page
482
+ // One "Book an appointment" a page (at the very end it goes across the page, PageLayout.astro). A new page
483
483
  // starts empty.
484
484
  template: { max: { booking: 1 } },
485
485
  },
486
486
  {
487
487
  kind: 'folder',
488
- id: 'kategorier',
489
- create: 'Nyt tag',
488
+ id: 'tags',
489
+ create: 'New tag',
490
490
  label: 'Tags',
491
491
  singular: 'tag',
492
492
  folder: 'src/data/categories',
@@ -494,29 +494,29 @@ export const collections: Collection[] = [
494
494
  slugFrom: 'name',
495
495
  summary: (d) => String(d.name ?? ''),
496
496
  fields: [
497
- { name: 'name', label: 'Navn', type: 'string', required: true },
497
+ { name: 'name', label: 'Name', type: 'string', required: true },
498
498
  ...seo,
499
499
  {
500
500
  name: 'blogCategory',
501
- label: 'Blogkategori',
501
+ label: 'Blog category',
502
502
  type: 'boolean',
503
- toggle: ['Vis', 'Skjul'],
503
+ toggle: ['Show', 'Hide'],
504
504
  default: true,
505
- hint: 'Vis tagget på bloggen med sin egen side.',
505
+ hint: 'Show the tag on the blog with its own page.',
506
506
  },
507
507
  ],
508
508
  },
509
509
  {
510
- // "Promovering": what is laid over the pages to get visitors to book, call or sign up, in
511
- // src/data/popups/<slug>.json, read by packages/editor/site/popups.ts, on every page or those picked under "Sider".
510
+ // "Promotion": what is laid over the pages to get visitors to book, call or sign up, in
511
+ // src/data/popups/<slug>.json, read by packages/editor/site/popups.ts, on every page or those picked under "Pages".
512
512
  // The pop-ups are shown by packages/editor/theme/components/Popup.astro; a kind an app adds without a part
513
513
  // in the pop-up (src/apps/<app>/popups/View.tsx) shows itself (the app Calendly's booking sheet,
514
514
  // morpheme-apps/apps/calendly/, when a button opens it).
515
515
  kind: 'folder',
516
516
  id: 'popups',
517
- create: 'Ny promovering',
518
- label: 'Promovering',
519
- singular: 'promovering',
517
+ create: 'New promotion',
518
+ label: 'Promotion',
519
+ singular: 'promotion',
520
520
  folder: 'src/data/popups',
521
521
  deletable: true,
522
522
  // A pop-up by its heading; a kind without one by its name (the app's bar), else by the kind's name
@@ -534,8 +534,8 @@ export const collections: Collection[] = [
534
534
  omit: {
535
535
  bookingbar: ['image', 'heading', 'text', 'trigger', 'button'],
536
536
  },
537
- // What a button ("Knapper": "Åbn promovering") can open of one: a pop-up itself, the action bar nothing (opens.ts).
538
- opens: { standard: { label: 'Pop op-vindue' } },
537
+ // What a button ("Buttons": "Open promotion") can open of one: a pop-up itself, the action bar nothing (opens.ts).
538
+ opens: { standard: { label: 'Pop-up' } },
539
539
  // A contact bar (`contactbar`, a kind of its own before it became an action bar) is an action bar with its two
540
540
  // buttons, to call and to its page, without one the contact page (packages/editor/lib/contactBar.ts).
541
541
  upgrade: (data, files) => fromContactBar(data, standardPaths(files.find((f) => f.path === config.standardPages)?.text).contact ?? ''),
@@ -548,49 +548,49 @@ export const collections: Collection[] = [
548
548
  // Without one (those made before there were kinds), it is the standard one.
549
549
  default: 'standard',
550
550
  options: [
551
- { label: 'Pop op-vindue', value: 'standard', icon: AppWindow, hint: 'Med billede, tekst og en knap.' },
551
+ { label: 'Pop-up', value: 'standard', icon: AppWindow, hint: 'With a picture, text and a button.' },
552
552
  {
553
- label: 'Handlingslinje',
553
+ label: 'Action bar',
554
554
  value: 'bookingbar',
555
555
  icon: SquareHalfBottom,
556
- hint: 'Knapper eller tekst nederst på skærmen på en telefon.',
556
+ hint: 'Buttons or text at the bottom of the screen on a phone.',
557
557
  },
558
558
  ],
559
559
  },
560
560
  {
561
561
  name: 'enabled',
562
- label: 'Aktiveret',
562
+ label: 'Activated',
563
563
  type: 'boolean',
564
- toggle: ['Til', 'Fra'],
564
+ toggle: ['On', 'Off'],
565
565
  default: true,
566
566
  },
567
- // At the top of the box, to its edges in 3:2, as on the cards with a picture ("Kort").
568
- { name: 'image', label: 'Billede', type: 'image', hint: 'Vises øverst, skåret til 3:2.' },
569
- { name: 'heading', label: 'Overskrift', type: 'string', required: true, max: 80 },
570
- { name: 'text', label: 'Tekst', type: 'text' },
567
+ // At the top of the box, to its edges in 3:2, as on the cards with a picture ("Cards").
568
+ { name: 'image', label: 'Picture', type: 'image', hint: 'Shown at the top, cropped to 3:2.' },
569
+ { name: 'heading', label: 'Heading', type: 'string', required: true, max: 80 },
570
+ { name: 'text', label: 'Text', type: 'text' },
571
571
  // Where it is shown, for every kind: on every page, on those picked (without `where`, from
572
572
  // before, those picked), or on the blog posts with one of the tags picked and those tags' pages.
573
573
  {
574
574
  name: 'where',
575
- label: 'Vises på',
575
+ label: 'Shown on',
576
576
  type: 'select',
577
577
  default: 'some',
578
578
  options: [
579
- { label: 'Alle sider', value: 'all' },
580
- { label: 'Udvalgte sider', value: 'some' },
581
- { label: 'Blogindlæg med tags', value: 'tags' },
579
+ { label: 'All pages', value: 'all' },
580
+ { label: 'Selected pages', value: 'some' },
581
+ { label: 'Blog posts with tags', value: 'tags' },
582
582
  ],
583
583
  },
584
584
  {
585
585
  name: 'pages',
586
- label: 'Sider',
586
+ label: 'Pages',
587
587
  type: 'relation',
588
588
  to: 'pages',
589
589
  fixed: true,
590
590
  multiple: true,
591
591
  required: true,
592
- add: 'Tilføj side',
593
- hint: 'Vises kun på disse sider.',
592
+ add: 'Add page',
593
+ hint: 'Only shown on these pages.',
594
594
  only: { field: 'where', is: ['some'] },
595
595
  },
596
596
  {
@@ -600,92 +600,92 @@ export const collections: Collection[] = [
600
600
  to: 'categories',
601
601
  multiple: true,
602
602
  required: true,
603
- add: 'Tilføj tag',
604
- hint: 'Vises på blogindlæg med et af disse tags og på taggenes sider.',
603
+ add: 'Add tag',
604
+ hint: "Shown on blog posts with one of these tags and on the tags' pages.",
605
605
  only: { field: 'where', is: ['tags'] },
606
606
  },
607
607
  // When it opens (packages/editor/theme/components/Popup.astro): after `delay`, at `scroll` % down the page, or as the
608
608
  // visitor is about to leave it.
609
609
  {
610
610
  name: 'trigger',
611
- label: 'Vises',
611
+ label: 'Shown',
612
612
  type: 'select',
613
613
  required: true,
614
614
  default: 'time',
615
- hint: 'Hver besøgende ser det, til de lukker det.',
615
+ hint: 'Each visitor sees it until they close it.',
616
616
  options: [
617
- { label: 'Efter en tid', value: 'time' },
618
- { label: 'Når siden er rullet ned', value: 'scroll' },
617
+ { label: 'After a while', value: 'time' },
618
+ { label: 'When the page is scrolled down', value: 'scroll' },
619
619
  {
620
- label: 'Når den besøgende vil forlade siden',
620
+ label: 'When the visitor is about to leave the page',
621
621
  value: 'exit',
622
- hint: 'På en telefon: når den besøgende ruller hurtigt op.',
622
+ hint: 'On a phone: when the visitor scrolls up quickly.',
623
623
  },
624
624
  ],
625
625
  },
626
626
  {
627
627
  name: 'delay',
628
- label: 'Vises efter',
628
+ label: 'Shown after',
629
629
  type: 'select',
630
630
  required: true,
631
631
  default: '5',
632
632
  only: { field: 'trigger', is: ['time'] },
633
633
  options: [
634
- { label: 'Med det samme', value: '0' },
635
- { label: '5 sekunder', value: '5' },
636
- { label: '10 sekunder', value: '10' },
637
- { label: '30 sekunder', value: '30' },
634
+ { label: 'At once', value: '0' },
635
+ { label: '5 seconds', value: '5' },
636
+ { label: '10 seconds', value: '10' },
637
+ { label: '30 seconds', value: '30' },
638
638
  ],
639
639
  },
640
640
  {
641
641
  name: 'scroll',
642
- label: 'Rullet ned',
642
+ label: 'Scrolled down',
643
643
  type: 'select',
644
644
  required: true,
645
645
  default: '25',
646
646
  options: [
647
- { label: '25 % af siden', value: '25' },
648
- { label: '50 % af siden', value: '50' },
649
- { label: '75 % af siden', value: '75' },
650
- { label: 'Hele siden', value: '100' },
647
+ { label: '25% of the page', value: '25' },
648
+ { label: '50% of the page', value: '50' },
649
+ { label: '75% of the page', value: '75' },
650
+ { label: 'The whole page', value: '100' },
651
651
  ],
652
652
  only: { field: 'trigger', is: ['scroll'] },
653
653
  },
654
654
  {
655
655
  name: 'button',
656
- label: 'Knap',
656
+ label: 'Button',
657
657
  type: 'select',
658
658
  required: true,
659
659
  default: 'booking',
660
660
  options: [
661
- { label: 'Book en tid', value: 'booking' },
662
- { label: 'Ring', value: 'phone' },
663
- { label: 'En side', value: 'page' },
661
+ { label: 'Book an appointment', value: 'booking' },
662
+ { label: 'Call', value: 'phone' },
663
+ { label: 'A page', value: 'page' },
664
664
  { label: 'Download PDF', value: 'file' },
665
- { label: 'Ingen knap', value: 'none' },
665
+ { label: 'No button', value: 'none' },
666
666
  ],
667
667
  },
668
668
  {
669
669
  name: 'label',
670
- label: 'Knaptekst',
670
+ label: 'Button text',
671
671
  type: 'string',
672
672
  max: 30,
673
- hint: 'Hvis feltet er tomt, bruges standardteksten.',
673
+ hint: 'If empty, the default text is used.',
674
674
  only: { field: 'button', is: ['booking', 'phone', 'page', 'file'] },
675
675
  },
676
- // A PDF from "Filer" (public/filer/), by its address (/filer/<name>.pdf).
676
+ // A PDF from "Files" (public/filer/), by its address (/filer/<name>.pdf).
677
677
  {
678
678
  name: 'file',
679
679
  label: 'PDF',
680
680
  type: 'relation',
681
681
  to: 'files',
682
682
  required: true,
683
- edit: { to: 'filer', text: 'Upload en PDF' },
683
+ edit: { to: 'files', text: 'Upload a PDF' },
684
684
  only: { field: 'button', is: ['file'] },
685
685
  },
686
686
  {
687
687
  name: 'href',
688
- label: 'Side (knap)',
688
+ label: 'Page (button)',
689
689
  type: 'relation',
690
690
  to: 'pages',
691
691
  fixed: true,
@@ -693,20 +693,20 @@ export const collections: Collection[] = [
693
693
  only: { field: 'button', is: ['page'] },
694
694
  },
695
695
  // The action bar's one or two items, each a button or a text (`type`; without one, a button, as before there were
696
- // texts). The first button is filled, a second with a line. Each button goes where a button of "Knapper" can
696
+ // texts). The first button is filled, a second with a line. Each button goes where a button of "Buttons" can
697
697
  // (Button in packages/editor/src/standard/buttons/fields.ts, the targets of `buttonTargets` in config.ts and a
698
- // page): "Book en tid" (what books on the page, an app's booking sheet, else the booking page), "Ring", "Åbn
699
- // promovering" (one shown on every page: a pop-up, or an app's booking sheet) or a page. A text is a list row of
698
+ // page): "Book an appointment" (what books on the page, an app's booking sheet, else the booking page), "Call", "Open
699
+ // promotion" (one shown on every page: a pop-up, or an app's booking sheet) or a page. A text is a list row of
700
700
  // two lines, its heading over its text, beside the button (ActionBar.astro).
701
701
  {
702
702
  name: 'buttons',
703
- label: 'Knapper og tekst',
704
- singular: 'punkt',
703
+ label: 'Buttons and text',
704
+ singular: 'item',
705
705
  type: 'list',
706
706
  summary: ['label', 'heading'],
707
707
  required: true,
708
708
  maxItems: 2,
709
- hint: 'Højst to punkter.',
709
+ hint: 'At most two items.',
710
710
  default: [{ type: 'button', label: '', to: 'booking' }],
711
711
  only: { field: 'type', is: ['bookingbar'] },
712
712
  fields: [
@@ -717,13 +717,13 @@ export const collections: Collection[] = [
717
717
  segments: true,
718
718
  default: 'button',
719
719
  options: [
720
- { label: 'Knap', value: 'button' },
721
- { label: 'Tekst', value: 'text' },
720
+ { label: 'Button', value: 'button' },
721
+ { label: 'Text', value: 'text' },
722
722
  ],
723
723
  },
724
724
  {
725
725
  name: 'heading',
726
- label: 'Overskrift',
726
+ label: 'Heading',
727
727
  type: 'string',
728
728
  required: true,
729
729
  max: 30,
@@ -731,10 +731,10 @@ export const collections: Collection[] = [
731
731
  },
732
732
  {
733
733
  name: 'text',
734
- label: 'Tekst',
734
+ label: 'Text',
735
735
  type: 'string',
736
736
  max: 40,
737
- hint: 'Står under overskriften.',
737
+ hint: 'Shown under the heading.',
738
738
  only: { field: 'type', is: ['text'] },
739
739
  },
740
740
  { ...barButtonLabel, only: { field: 'type', is: ['button'] } },
@@ -754,18 +754,18 @@ export const collections: Collection[] = [
754
754
  // src/data/footer.json, read by packages/editor/theme/layouts/Base.astro.
755
755
  {
756
756
  file: 'src/data/footer.json',
757
- label: 'Footeren',
757
+ label: 'The footer',
758
758
  view: '/',
759
759
  fields: [
760
- { name: 'text', label: 'Tekst (under navnet)', type: 'text', required: true },
760
+ { name: 'text', label: 'Text (under the name)', type: 'text', required: true },
761
761
  {
762
762
  name: 'contactHeading',
763
- label: 'Overskrift (kontakt)',
763
+ label: 'Heading (contact)',
764
764
  type: 'string',
765
765
  required: true,
766
- edit: { to: 'virksomheden/kontakt', text: 'Rediger telefon, e-mail og adresse' },
766
+ edit: { to: 'company/contact', text: 'Edit phone, email and address' },
767
767
  },
768
- { name: 'linksHeading', label: 'Overskrift (links)', type: 'string', required: true },
768
+ { name: 'linksHeading', label: 'Heading (links)', type: 'string', required: true },
769
769
  {
770
770
  name: 'links',
771
771
  label: 'Links',
@@ -773,7 +773,7 @@ export const collections: Collection[] = [
773
773
  type: 'list',
774
774
  summary: 'label',
775
775
  required: true,
776
- fields: [{ name: 'label', label: 'Tekst', type: 'string', required: true }, menuHref],
776
+ fields: [{ name: 'label', label: 'Text', type: 'string', required: true }, menuHref],
777
777
  },
778
778
  ],
779
779
  },
@@ -782,40 +782,40 @@ export const collections: Collection[] = [
782
782
  {
783
783
  kind: 'files',
784
784
  id: 'menu',
785
- label: 'Hovedmenu',
786
- singular: 'hovedmenu',
785
+ label: 'Main menu',
786
+ singular: 'main menu',
787
787
  files: [
788
788
  // src/data/menu.json, read by packages/editor/site/site.ts (nav, navShown) for the header (Header.astro, MobileMenu.tsx).
789
789
  {
790
790
  file: 'src/data/menu.json',
791
- label: 'Hovedmenuen',
791
+ label: 'The main menu',
792
792
  view: '/',
793
793
  fields: [
794
794
  {
795
795
  name: 'enabled',
796
- label: 'Aktiveret',
796
+ label: 'Activated',
797
797
  type: 'boolean',
798
- toggle: ['Til', 'Fra'],
798
+ toggle: ['On', 'Off'],
799
799
  default: true,
800
- hint: 'Når menuen er fra, har headeren hverken menu eller menuknap.',
800
+ hint: 'When the menu is off, the header has neither menu nor menu button.',
801
801
  },
802
802
  ],
803
803
  root: {
804
804
  name: 'items',
805
- label: 'Menupunkter',
806
- singular: 'menupunkt',
805
+ label: 'Menu items',
806
+ singular: 'menu item',
807
807
  type: 'list',
808
808
  summary: 'label',
809
809
  fields: [
810
- { name: 'label', label: 'Tekst', type: 'string', required: true },
810
+ { name: 'label', label: 'Text', type: 'string', required: true },
811
811
  menuHref,
812
812
  {
813
813
  name: 'children',
814
- label: 'Undermenu',
815
- singular: 'punkt',
814
+ label: 'Submenu',
815
+ singular: 'item',
816
816
  type: 'list',
817
817
  summary: 'label',
818
- fields: [{ name: 'label', label: 'Tekst', type: 'string', required: true }, menuHref],
818
+ fields: [{ name: 'label', label: 'Text', type: 'string', required: true }, menuHref],
819
819
  },
820
820
  ],
821
821
  },
@@ -824,62 +824,62 @@ export const collections: Collection[] = [
824
824
  },
825
825
  {
826
826
  kind: 'files',
827
- id: 'mobilmenu',
828
- label: 'Mobilmenu',
829
- singular: 'mobilmenu',
827
+ id: 'mobile-menu',
828
+ label: 'Mobile menu',
829
+ singular: 'mobile menu',
830
830
  files: [
831
831
  // src/data/mobile-menu.json, read by packages/editor/site/site.ts (mobileNav) for the bar under the header (MobileNav.astro).
832
832
  {
833
833
  file: 'src/data/mobile-menu.json',
834
- label: 'Mobilmenuen',
834
+ label: 'The mobile menu',
835
835
  view: '/',
836
836
  fields: [
837
837
  {
838
838
  name: 'enabled',
839
- label: 'Aktiveret',
839
+ label: 'Activated',
840
840
  type: 'boolean',
841
- toggle: ['Til', 'Fra'],
841
+ toggle: ['On', 'Off'],
842
842
  default: false,
843
- hint: 'Punkterne står på en linje under headeren på en telefon og kan skubbes til siden.',
843
+ hint: 'The items are on a line under the header on a phone and can be swiped sideways.',
844
844
  },
845
845
  ],
846
846
  root: {
847
847
  name: 'items',
848
- label: 'Menupunkter',
849
- singular: 'menupunkt',
848
+ label: 'Menu items',
849
+ singular: 'menu item',
850
850
  type: 'list',
851
851
  summary: 'label',
852
- fields: [{ name: 'label', label: 'Tekst', type: 'string', required: true }, menuHref],
852
+ fields: [{ name: 'label', label: 'Text', type: 'string', required: true }, menuHref],
853
853
  },
854
854
  },
855
855
  ],
856
856
  },
857
857
  {
858
858
  kind: 'files',
859
- id: 'headerknap',
860
- label: 'Headerknap',
861
- singular: 'headerknap',
859
+ id: 'header-button',
860
+ label: 'Header button',
861
+ singular: 'header button',
862
862
  files: [
863
863
  // src/data/header.json, optional (a site without it has no button and the menu button at the start), read by the header
864
864
  // (Header.astro). The button is one of the action bar's (barButtonLabel …).
865
865
  {
866
866
  file: 'src/data/header.json',
867
- label: 'Headeren',
867
+ label: 'The header',
868
868
  view: '/',
869
869
  optional: true,
870
870
  fields: [
871
871
  {
872
872
  name: 'button',
873
- label: 'Handlingsknap',
873
+ label: 'Action button',
874
874
  type: 'object',
875
875
  fields: [
876
876
  {
877
877
  name: 'enabled',
878
- label: 'Aktiveret',
878
+ label: 'Activated',
879
879
  type: 'boolean',
880
- toggle: ['Til', 'Fra'],
880
+ toggle: ['On', 'Off'],
881
881
  default: false,
882
- hint: 'Knappen står i headeren.',
882
+ hint: 'The button is in the header.',
883
883
  },
884
884
  barButtonLabel,
885
885
  barButtonTo,
@@ -889,13 +889,13 @@ export const collections: Collection[] = [
889
889
  },
890
890
  {
891
891
  name: 'menuSide',
892
- label: 'Menuknappens placering',
892
+ label: 'Menu button position',
893
893
  type: 'select',
894
894
  segments: true,
895
895
  default: 'start',
896
896
  options: [
897
- { label: 'Venstre', value: 'start' },
898
- { label: 'Højre', value: 'end' },
897
+ { label: 'Left', value: 'start' },
898
+ { label: 'Right', value: 'end' },
899
899
  ],
900
900
  },
901
901
  ],