« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content/dependencies
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies')
-rw-r--r--src/content/dependencies/generateAlbumGalleryStatsLine.js2
-rw-r--r--src/content/dependencies/generateAlbumInfoPage.js14
-rw-r--r--src/content/dependencies/generateAlbumNavAccent.js8
-rw-r--r--src/content/dependencies/generateAlbumReleaseInfo.js7
-rw-r--r--src/content/dependencies/generateAlbumSecondaryNav.js7
-rw-r--r--src/content/dependencies/generateAlbumSidebarTrackSection.js55
-rw-r--r--src/content/dependencies/generateAlbumTrackList.js4
-rw-r--r--src/content/dependencies/generateAlbumTrackListItem.js2
-rw-r--r--src/content/dependencies/generateArtTagGalleryPage.js3
-rw-r--r--src/content/dependencies/generateArtistGalleryPage.js3
-rw-r--r--src/content/dependencies/generateArtistGroupContributionsInfo.js19
-rw-r--r--src/content/dependencies/generateArtistInfoPageChunk.js4
-rw-r--r--src/content/dependencies/generateArtistInfoPageChunkItem.js4
-rw-r--r--src/content/dependencies/generateCommentaryEntry.js6
-rw-r--r--src/content/dependencies/generateContentHeading.js36
-rw-r--r--src/content/dependencies/generateCoverCarousel.js15
-rw-r--r--src/content/dependencies/generateDatetimestampTemplate.js29
-rw-r--r--src/content/dependencies/generateFlashActSidebar.js43
-rw-r--r--src/content/dependencies/generateFlashIndexPage.js30
-rw-r--r--src/content/dependencies/generateGroupGalleryPage.js32
-rw-r--r--src/content/dependencies/generateGroupInfoPage.js6
-rw-r--r--src/content/dependencies/generateGroupSecondaryNav.js6
-rw-r--r--src/content/dependencies/generateGroupSidebarCategoryDetails.js17
-rw-r--r--src/content/dependencies/generateListAllAdditionalFilesChunk.js14
-rw-r--r--src/content/dependencies/generateListingIndexList.js33
-rw-r--r--src/content/dependencies/generateListingPage.js10
-rw-r--r--src/content/dependencies/generateNewsEntryReadAnotherLinks.js16
-rw-r--r--src/content/dependencies/generatePageLayout.js339
-rw-r--r--src/content/dependencies/generateSecondaryNav.js12
-rw-r--r--src/content/dependencies/generateStickyHeadingContainer.js18
-rw-r--r--src/content/dependencies/generateTrackInfoPage.js13
-rw-r--r--src/content/dependencies/generateTrackReleaseInfo.js58
-rw-r--r--src/content/dependencies/generateWikiHomeContentRow.js23
-rw-r--r--src/content/dependencies/generateWikiHomeNewsBox.js32
-rw-r--r--src/content/dependencies/image.js88
-rw-r--r--src/content/dependencies/linkContribution.js70
-rw-r--r--src/content/dependencies/linkExternal.js14
-rw-r--r--src/content/dependencies/linkExternalAsIcon.js8
-rw-r--r--src/content/dependencies/linkListing.js3
-rw-r--r--src/content/dependencies/listAllAdditionalFilesTemplate.js5
-rw-r--r--src/content/dependencies/transformContent.js9
41 files changed, 586 insertions, 531 deletions
diff --git a/src/content/dependencies/generateAlbumGalleryStatsLine.js b/src/content/dependencies/generateAlbumGalleryStatsLine.js
index 08c0abeb..75bffb36 100644
--- a/src/content/dependencies/generateAlbumGalleryStatsLine.js
+++ b/src/content/dependencies/generateAlbumGalleryStatsLine.js
@@ -33,6 +33,6 @@ export default {
 
     return (
       html.tag('p', {class: 'quick-info'},
-        language.formatString(parts.join('.'), options)));
+        language.formatString(...parts, options)));
   },
 };
diff --git a/src/content/dependencies/generateAlbumInfoPage.js b/src/content/dependencies/generateAlbumInfoPage.js
index 90a120ca..cb7355f3 100644
--- a/src/content/dependencies/generateAlbumInfoPage.js
+++ b/src/content/dependencies/generateAlbumInfoPage.js
@@ -171,10 +171,9 @@ export default {
           relations.releaseInfo,
 
           html.tag('p',
-            {
-              [html.onlyIfContent]: true,
-              [html.joinChildren]: html.tag('br'),
-            },
+            {[html.onlyIfContent]: true},
+            {[html.joinChildren]: html.tag('br')},
+
             [
               sec.extra.additionalFilesShortcut,
 
@@ -206,10 +205,9 @@ export default {
           relations.trackList,
 
           html.tag('p',
-            {
-              [html.onlyIfContent]: true,
-              [html.joinChildren]: '<br>',
-            },
+            {[html.onlyIfContent]: true},
+            {[html.joinChildren]: html.tag('br')},
+
             [
               data.dateAddedToWiki &&
                 language.$('releaseInfo.addedToWiki', {
diff --git a/src/content/dependencies/generateAlbumNavAccent.js b/src/content/dependencies/generateAlbumNavAccent.js
index 01c88bf7..121af439 100644
--- a/src/content/dependencies/generateAlbumNavAccent.js
+++ b/src/content/dependencies/generateAlbumNavAccent.js
@@ -90,11 +90,9 @@ export default {
       slots.showTrackNavigation &&
       data.hasMultipleTracks &&
         html.tag('a',
-          {
-            href: '#',
-            'data-random': 'track-in-sidebar',
-            id: 'random-button',
-          },
+          {id: 'random-button'},
+          {href: '#', 'data-random': 'track-in-sidebar'},
+
           (data.isTrackPage
             ? language.$('trackPage.nav.random')
             : language.$('albumPage.nav.randomTrack')));
diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js
index dd5baab9..cb3aaa75 100644
--- a/src/content/dependencies/generateAlbumReleaseInfo.js
+++ b/src/content/dependencies/generateAlbumReleaseInfo.js
@@ -52,10 +52,9 @@ export default {
   generate(data, relations, {html, language}) {
     return html.tags([
       html.tag('p',
-        {
-          [html.onlyIfContent]: true,
-          [html.joinChildren]: html.tag('br'),
-        },
+        {[html.onlyIfContent]: true},
+        {[html.joinChildren]: html.tag('br')},
+
         [
           relations.artistContributionsLine
             .slots({stringKey: 'releaseInfo.by'}),
diff --git a/src/content/dependencies/generateAlbumSecondaryNav.js b/src/content/dependencies/generateAlbumSecondaryNav.js
index 8cf36fa4..bbf98875 100644
--- a/src/content/dependencies/generateAlbumSecondaryNav.js
+++ b/src/content/dependencies/generateAlbumSecondaryNav.js
@@ -129,11 +129,16 @@ export default {
 
             return (
               html.tag('span',
-                {style: colorVariables.slot('color', groupColor).content},
+                {style:
+                  colorVariables
+                    .slot('color', groupColor)
+                    .content},
+
                 [
                   language.$('albumSidebar.groupBox.title', {
                     group: groupLink.slot('color', false),
                   }),
+
                   `(${language.formatUnitList(previousNextPart)})`,
                 ]));
           }),
diff --git a/src/content/dependencies/generateAlbumSidebarTrackSection.js b/src/content/dependencies/generateAlbumSidebarTrackSection.js
index d3cd37f0..589bd900 100644
--- a/src/content/dependencies/generateAlbumSidebarTrackSection.js
+++ b/src/content/dependencies/generateAlbumSidebarTrackSection.js
@@ -70,17 +70,14 @@ export default {
     const trackListItems =
       relations.trackLinks.map((trackLink, index) =>
         html.tag('li',
-          {
-            class: [
-              data.includesCurrentTrack &&
-              index === data.currentTrackIndex &&
-                'current',
-
-              slots.mode === 'commentary' &&
-              data.tracksAreMissingCommentary[index] &&
-                'no-commentary',
-            ],
-          },
+          data.includesCurrentTrack &&
+          index === data.currentTrackIndex &&
+            {class: 'current'},
+
+          slots.mode === 'commentary' &&
+          data.tracksAreMissingCommentary[index] &&
+            {class: 'no-commentary'},
+
           language.$('albumSidebar.trackList.item', {
             track:
               (slots.mode === 'commentary' && data.tracksAreMissingCommentary[index]
@@ -96,24 +93,24 @@ export default {
           })));
 
     return html.tag('details',
-      {
-        class: data.includesCurrentTrack && 'current',
-
-        open: (
-          // Allow forcing open via a template slot.
-          // This isn't exactly janky, but the rest of this function
-          // kind of is when you contextualize it in a template...
-          slots.open ||
-
-          // Leave sidebar track sections collapsed on album info page,
-          // since there's already a view of the full track listing
-          // in the main content area.
-          data.isTrackPage &&
-
-          // Only expand the track section which includes the track
-          // currently being viewed by default.
-          data.includesCurrentTrack),
-      },
+      data.includesCurrentTrack &&
+        {class: 'current'},
+
+      {open:
+        // Allow forcing open via a template slot.
+        // This isn't exactly janky, but the rest of this function
+        // kind of is when you contextualize it in a template...
+        slots.open ||
+
+        // Leave sidebar track sections collapsed on album info page,
+        // since there's already a view of the full track listing
+        // in the main content area.
+        data.isTrackPage &&
+
+        // Only expand the track section which includes the track
+        // currently being viewed by default.
+        data.includesCurrentTrack},
+
       [
         html.tag('summary', {style},
           html.tag('span',
diff --git a/src/content/dependencies/generateAlbumTrackList.js b/src/content/dependencies/generateAlbumTrackList.js
index 2732aaa4..40cbb14d 100644
--- a/src/content/dependencies/generateAlbumTrackList.js
+++ b/src/content/dependencies/generateAlbumTrackList.js
@@ -123,7 +123,9 @@ export default {
 
               html.tag('dd',
                 html.tag(listTag,
-                  data.hasTrackNumbers ? {start: info.startIndex + 1} : {},
+                  data.hasTrackNumbers &&
+                    {start: info.startIndex + 1},
+
                   items)),
             ]));
 
diff --git a/src/content/dependencies/generateAlbumTrackListItem.js b/src/content/dependencies/generateAlbumTrackListItem.js
index f92712f9..4cfa5cb0 100644
--- a/src/content/dependencies/generateAlbumTrackListItem.js
+++ b/src/content/dependencies/generateAlbumTrackListItem.js
@@ -71,6 +71,6 @@ export default {
     }
 
     return html.tag('li', {style},
-      language.formatString(parts.join('.'), options));
+      language.formatString(...parts, options));
   },
 };
diff --git a/src/content/dependencies/generateArtTagGalleryPage.js b/src/content/dependencies/generateArtTagGalleryPage.js
index e28b54cb..5557d1e2 100644
--- a/src/content/dependencies/generateArtTagGalleryPage.js
+++ b/src/content/dependencies/generateArtTagGalleryPage.js
@@ -91,8 +91,7 @@ export default {
 
         mainClasses: ['top-index'],
         mainContent: [
-          html.tag('p',
-            {class: 'quick-info'},
+          html.tag('p', {class: 'quick-info'},
             language.$('tagPage.infoLine', {
               coverArts: language.countCoverArts(data.numArtworks, {
                 unit: true,
diff --git a/src/content/dependencies/generateArtistGalleryPage.js b/src/content/dependencies/generateArtistGalleryPage.js
index 99e2fcbf..39be9d91 100644
--- a/src/content/dependencies/generateArtistGalleryPage.js
+++ b/src/content/dependencies/generateArtistGalleryPage.js
@@ -83,8 +83,7 @@ export default {
 
         mainClasses: ['top-index'],
         mainContent: [
-          html.tag('p',
-            {class: 'quick-info'},
+          html.tag('p', {class: 'quick-info'},
             language.$('artistGalleryPage.infoLine', {
               coverArts: language.countCoverArts(data.numArtworks, {
                 unit: true,
diff --git a/src/content/dependencies/generateArtistGroupContributionsInfo.js b/src/content/dependencies/generateArtistGroupContributionsInfo.js
index 1aa5dce6..fc82072c 100644
--- a/src/content/dependencies/generateArtistGroupContributionsInfo.js
+++ b/src/content/dependencies/generateArtistGroupContributionsInfo.js
@@ -162,7 +162,9 @@ export default {
           ? language.$('artistPage.groupContributions.title.withSortButton', {
               title: slots.title,
               sort:
-                html.tag('a', {href: '#', class: 'group-contributions-sort-button'},
+                html.tag('a', {class: 'group-contributions-sort-button'},
+                  {href: '#'},
+
                   (slots.sort === 'count'
                     ? language.$('artistPage.groupContributions.title.sorting.count')
                     : language.$('artistPage.groupContributions.title.sorting.duration'))),
@@ -170,12 +172,17 @@ export default {
           : slots.title)),
 
       html.tag('dd', {class: topLevelClasses},
-        html.tag('ul', {class: 'group-contributions-table', role: 'list'},
+        html.tag('ul', {class: 'group-contributions-table'},
+          {role: 'list'},
+
           (slots.sort === 'count'
             ? stitchArrays({
                 group: relations.groupLinksSortedByCount,
                 count: getCounts(data.groupCountsSortedByCount),
-                duration: getDurations(data.groupDurationsSortedByCount, data.groupDurationsApproximateSortedByCount),
+                duration:
+                  getDurations(
+                    data.groupDurationsSortedByCount,
+                    data.groupDurationsApproximateSortedByCount),
               }).map(({group, count, duration}) =>
                 html.tag('li',
                   html.tag('div', {class: 'group-contributions-row'}, [
@@ -187,10 +194,14 @@ export default {
                         ? language.$('artistPage.groupContributions.item.countDurationAccent', {count, duration})
                         : language.$('artistPage.groupContributions.item.countAccent', {count}))),
                   ])))
+
             : stitchArrays({
                 group: relations.groupLinksSortedByDuration,
                 count: getCounts(data.groupCountsSortedByDuration),
-                duration: getDurations(data.groupDurationsSortedByDuration, data.groupDurationsApproximateSortedByCount),
+                duration:
+                  getDurations(
+                    data.groupDurationsSortedByDuration,
+                    data.groupDurationsApproximateSortedByCount),
               }).map(({group, count, duration}) =>
                 html.tag('li',
                   html.tag('div', {class: 'group-contributions-row'}, [
diff --git a/src/content/dependencies/generateArtistInfoPageChunk.js b/src/content/dependencies/generateArtistInfoPageChunk.js
index 2b4523d1..d4c71c32 100644
--- a/src/content/dependencies/generateArtistInfoPageChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageChunk.js
@@ -43,7 +43,7 @@ export default {
               });
           }
 
-          accentedLink = language.formatString(parts.join('.'), options);
+          accentedLink = language.formatString(...parts, options);
           break;
         }
 
@@ -65,7 +65,7 @@ export default {
             options.date = language.formatDate(slots.dateRangeStart ?? slots.date);
           }
 
-          accentedLink = language.formatString(parts.join('.'), options);
+          accentedLink = language.formatString(...parts, options);
           break;
         }
       }
diff --git a/src/content/dependencies/generateArtistInfoPageChunkItem.js b/src/content/dependencies/generateArtistInfoPageChunkItem.js
index 9f99513d..de31d30e 100644
--- a/src/content/dependencies/generateArtistInfoPageChunkItem.js
+++ b/src/content/dependencies/generateArtistInfoPageChunkItem.js
@@ -39,12 +39,12 @@ export default {
         break accent;
       }
 
-      accentedContent = language.formatString(parts.join('.'), options);
+      accentedContent = language.formatString(...parts, options);
     }
 
     return (
       html.tag('li',
-        {class: slots.rerelease && 'rerelease'},
+        slots.rerelease && {class: 'rerelease'},
         accentedContent));
   },
 };
diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js
index 0b2b2558..b4f24686 100644
--- a/src/content/dependencies/generateCommentaryEntry.js
+++ b/src/content/dependencies/generateCommentaryEntry.js
@@ -89,10 +89,12 @@ export default {
         : null);
 
     return html.tags([
-      html.tag('p', {class: 'commentary-entry-heading', style},
+      html.tag('p', {class: 'commentary-entry-heading'},
+        {style},
         language.$(...titleParts, titleOptions)),
 
-      html.tag('blockquote', {class: 'commentary-entry-body', style},
+      html.tag('blockquote', {class: 'commentary-entry-body'},
+        {style},
         relations.bodyContent.slot('mode', 'multiline')),
     ]);
   },
diff --git a/src/content/dependencies/generateContentHeading.js b/src/content/dependencies/generateContentHeading.js
index 0343409c..57bacbe5 100644
--- a/src/content/dependencies/generateContentHeading.js
+++ b/src/content/dependencies/generateContentHeading.js
@@ -16,26 +16,24 @@ export default {
     tag: {type: 'string', default: 'p'},
   },
 
-  generate(relations, slots, {html}) {
-    return html.tag(slots.tag,
-      {
-        class: 'content-heading',
-        id: slots.id,
-        tabindex: '0',
-
-        style:
-          slots.color &&
-            relations.colorVariables
-              .slot('color', slots.color)
-              .content,
-      }, [
-        html.tag('span',
-          {[html.onlyIfContent]: true, class: 'content-heading-main-title'},
+  generate: (relations, slots, {html}) =>
+    html.tag(slots.tag, {class: 'content-heading'},
+      {id: slots.id},
+      {tabindex: '0'},
+
+      slots.color &&
+        {style:
+          relations.colorVariables
+            .slot('color', slots.color)
+            .content},
+
+      [
+        html.tag('span', {class: 'content-heading-main-title'},
+          {[html.onlyIfContent]: true},
           slots.title),
 
-        html.tag('span',
-          {[html.onlyIfContent]: true, class: 'content-heading-accent'},
+        html.tag('span', {class: 'content-heading-accent'},
+          {[html.onlyIfContent]: true},
           slots.accent),
-      ]);
-  }
+      ]),
 }
diff --git a/src/content/dependencies/generateCoverCarousel.js b/src/content/dependencies/generateCoverCarousel.js
index 4919041f..49cb4300 100644
--- a/src/content/dependencies/generateCoverCarousel.js
+++ b/src/content/dependencies/generateCoverCarousel.js
@@ -33,15 +33,14 @@ export default {
     const layout = getCarouselLayoutForNumberOfItems(stitched.length);
 
     return html.tags([
-      html.tag('div',
-        {
-          class: 'carousel-container',
-          'data-carousel-rows': layout.rows,
-          'data-carousel-columns': layout.columns,
-        },
+      html.tag('div', {class: 'carousel-container'},
+        {'data-carousel-rows': layout.rows},
+        {'data-carousel-columns': layout.columns},
+
         repeat(3, [
-          html.tag('div',
-            {class: 'carousel-grid', 'aria-hidden': 'true'},
+          html.tag('div', {class: 'carousel-grid'},
+            {'aria-hidden': 'true'},
+
             stitched.map(({image, link}, index) =>
               html.tag('div', {class: 'carousel-item'},
                 link.slots({
diff --git a/src/content/dependencies/generateDatetimestampTemplate.js b/src/content/dependencies/generateDatetimestampTemplate.js
index bfba647f..d2648d67 100644
--- a/src/content/dependencies/generateDatetimestampTemplate.js
+++ b/src/content/dependencies/generateDatetimestampTemplate.js
@@ -8,21 +8,20 @@ export default {
   },
 
   generate: (slots, {html}) =>
-    html.tag('span', {
-      [html.joinChildren]: '',
-
-      class: [
-        'datetimestamp',
-        slots.tooltipContent && 'has-tooltip',
-      ],
-    }, [
-      html.tag('time',
-        {datetime: slots.datetime},
-        slots.mainContent),
+    html.tag('span', {class: 'datetimestamp'},
+      {[html.joinChildren]: ''},
 
       slots.tooltipContent &&
-        html.tag('span', {class: 'datetimestamp-tooltip'},
-          html.tag('span', {class: 'datetimestamp-tooltip-content'},
-            slots.tooltipContent)),
-    ]),
+        {class: 'has-tooltip'},
+
+      [
+        html.tag('time',
+          {datetime: slots.datetime},
+          slots.mainContent),
+
+        slots.tooltipContent &&
+          html.tag('span', {class: 'datetimestamp-tooltip'},
+            html.tag('span', {class: 'datetimestamp-tooltip-content'},
+              slots.tooltipContent)),
+      ]),
 };
diff --git a/src/content/dependencies/generateFlashActSidebar.js b/src/content/dependencies/generateFlashActSidebar.js
index 29379644..3c631d92 100644
--- a/src/content/dependencies/generateFlashActSidebar.js
+++ b/src/content/dependencies/generateFlashActSidebar.js
@@ -155,7 +155,9 @@ export default {
             relations.currentActFlashLinks
               .map((flashLink, index) =>
                 html.tag('li',
-                  {class: index === data.currentFlashIndex && 'current'},
+                  index === data.currentFlashIndex &&
+                    {class: 'current'},
+
                   flashLink))),
         ]),
     ]);
@@ -168,24 +170,31 @@ export default {
         sideColor: data.sideColors,
         actLinks: relations.sideActLinks,
       }).map(({sideName, sideColor, actLinks}, sideIndex) =>
-          html.tag('details', {
-            class: sideIndex === data.currentSideIndex && 'current',
-            open: data.isFlashActPage && sideIndex === data.currentSideIndex,
-            style: sideColor && `--primary-color: ${getColors(sideColor).primary}`
-          }, [
-            html.tag('summary',
-              html.tag('span', {class: 'group-name'},
-                sideName)),
-
-            html.tag('ul',
-              actLinks.map((actLink, actIndex) =>
-                html.tag('li',
-                  {class:
+          html.tag('details',
+            sideIndex === data.currentSideIndex &&
+              {class: 'current'},
+
+            data.isFlashActPage &&
+            sideIndex === data.currentSideIndex &&
+              {open: true},
+
+            sideColor &&
+              {style: `--primary-color: ${getColors(sideColor).primary}`},
+
+            [
+              html.tag('summary',
+                html.tag('span', {class: 'group-name'},
+                  sideName)),
+
+              html.tag('ul',
+                actLinks.map((actLink, actIndex) =>
+                  html.tag('li',
                     sideIndex === data.currentSideIndex &&
                     actIndex === data.currentActIndex &&
-                      'current'},
-                  actLink))),
-          ])),
+                      {class: 'current'},
+
+                    actLink))),
+            ])),
     ]);
 
     const sideMapBox = {
diff --git a/src/content/dependencies/generateFlashIndexPage.js b/src/content/dependencies/generateFlashIndexPage.js
index 5fc62ab3..621d62aa 100644
--- a/src/content/dependencies/generateFlashIndexPage.js
+++ b/src/content/dependencies/generateFlashIndexPage.js
@@ -96,12 +96,10 @@ export default {
       mainClasses: ['flash-index'],
       mainContent: [
         !empty(data.jumpLinkLabels) && [
-          html.tag('p',
-            {class: 'quick-info'},
+          html.tag('p', {class: 'quick-info'},
             language.$('misc.jumpTo')),
 
-          html.tag('ul',
-            {class: 'quick-info'},
+          html.tag('ul', {class: 'quick-info'},
             stitchArrays({
               colorVariables: relations.jumpLinkColorVariables,
               anchor: data.jumpLinkAnchors,
@@ -109,10 +107,15 @@ export default {
               label: data.jumpLinkLabels,
             }).map(({colorVariables, anchor, color, label}) =>
                 html.tag('li',
-                  html.tag('a', {
-                    href: '#' + anchor,
-                    style: colorVariables.slot('color', color).content,
-                  }, label)))),
+                  html.tag('a',
+                    {href: '#' + anchor},
+
+                    {style:
+                      colorVariables
+                        .slot('color', color)
+                        .content},
+
+                    label)))),
         ],
 
         stitchArrays({
@@ -139,10 +142,13 @@ export default {
             coverGridPaths,
           }, index) => [
             html.tag('h2',
-              {
-                id: anchor,
-                style: colorVariables.slot('color', color).content,
-              },
+              {id: anchor},
+
+              {style:
+                colorVariables
+                  .slot('color', color)
+                  .content},
+
               actLink),
 
             coverGrid.slots({
diff --git a/src/content/dependencies/generateGroupGalleryPage.js b/src/content/dependencies/generateGroupGalleryPage.js
index 259f5dce..490dcf10 100644
--- a/src/content/dependencies/generateGroupGalleryPage.js
+++ b/src/content/dependencies/generateGroupGalleryPage.js
@@ -132,21 +132,25 @@ export default {
                     image.slot('path', path)),
             }),
 
-          html.tag('p',
-            {class: 'quick-info'},
+          html.tag('p', {class: 'quick-info'},
             language.$('groupGalleryPage.infoLine', {
-              tracks: html.tag('b',
-                language.countTracks(data.numTracks, {
-                  unit: true,
-                })),
-              albums: html.tag('b',
-                language.countAlbums(data.numAlbums, {
-                  unit: true,
-                })),
-              time: html.tag('b',
-                language.formatDuration(data.totalDuration, {
-                  unit: true,
-                })),
+              tracks:
+                html.tag('b',
+                  language.countTracks(data.numTracks, {
+                    unit: true,
+                  })),
+
+              albums:
+                html.tag('b',
+                  language.countAlbums(data.numAlbums, {
+                    unit: true,
+                  })),
+
+              time:
+                html.tag('b',
+                  language.formatDuration(data.totalDuration, {
+                    unit: true,
+                  })),
             })),
 
           relations.coverGrid
diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js
index 0e5d645b..8d123c92 100644
--- a/src/content/dependencies/generateGroupInfoPage.js
+++ b/src/content/dependencies/generateGroupInfoPage.js
@@ -182,7 +182,11 @@ export default {
 
                   return (
                     html.tag('li',
-                      {style: colorVariables.slot('color', albumColor).content},
+                      {style:
+                        colorVariables
+                          .slot('color', albumColor)
+                          .content},
+
                       language.$(...parts, options)));
                 })),
           ],
diff --git a/src/content/dependencies/generateGroupSecondaryNav.js b/src/content/dependencies/generateGroupSecondaryNav.js
index e3b28099..43c78a0f 100644
--- a/src/content/dependencies/generateGroupSecondaryNav.js
+++ b/src/content/dependencies/generateGroupSecondaryNav.js
@@ -89,7 +89,11 @@ export default {
         (!relations.previousGroupLink && !relations.nextGroupLink
           ? categoryLink
           : html.tag('span',
-              {style: relations.colorVariables.slot('color', data.categoryColor).content},
+              {style:
+                relations.colorVariables
+                  .slot('color', data.categoryColor)
+                  .content},
+
               [
                 categoryLink.slot('color', false),
                 `(${language.formatUnitList(previousNextPart)})`,
diff --git a/src/content/dependencies/generateGroupSidebarCategoryDetails.js b/src/content/dependencies/generateGroupSidebarCategoryDetails.js
index 709ab211..19c5447c 100644
--- a/src/content/dependencies/generateGroupSidebarCategoryDetails.js
+++ b/src/content/dependencies/generateGroupSidebarCategoryDetails.js
@@ -49,13 +49,16 @@ export default {
 
   generate(data, relations, slots, {html, language}) {
     return html.tag('details',
-      {
-        open: data.isCurrentCategory,
-        class: data.isCurrentCategory && 'current',
-      },
+      data.isCurrentCategory &&
+        {class: 'current', open: true},
+
       [
         html.tag('summary',
-          {style: relations.colorVariables.slot('color', data.color).content},
+          {style:
+            relations.colorVariables
+              .slot('color', data.color)
+              .content},
+
           html.tag('span',
             language.$('groupSidebar.groupList.category', {
               category:
@@ -69,7 +72,9 @@ export default {
             galleryLink: relations.groupGalleryLinks,
           })).map(({infoLink, galleryLink}, index) =>
                 html.tag('li',
-                  {class: index === data.currentGroupIndex && 'current'},
+                  index === data.currentGroupIndex &&
+                    {class: 'current'},
+
                   language.$('groupSidebar.groupList.item', {
                     group:
                       (slots.currentExtra === 'gallery'
diff --git a/src/content/dependencies/generateListAllAdditionalFilesChunk.js b/src/content/dependencies/generateListAllAdditionalFilesChunk.js
index c87c03cc..e31633f4 100644
--- a/src/content/dependencies/generateListAllAdditionalFilesChunk.js
+++ b/src/content/dependencies/generateListAllAdditionalFilesChunk.js
@@ -43,7 +43,7 @@ export default {
                 ? html.tag('li',
                     additionalFileLinks[0].slots({
                       content:
-                        language.$(`listingPage.${slots.stringsKey}.file`, {
+                        language.$('listingPage', slots.stringsKey, 'file', {
                           title: additionalFileTitle,
                         }),
                     }))
@@ -52,11 +52,15 @@ export default {
                     html.tag('details', [
                       html.tag('summary',
                         html.tag('span',
-                          language.$(`listingPage.${slots.stringsKey}.file.withMultipleFiles`, {
+                          language.$('listingPage', slots.stringsKey, 'file.withMultipleFiles', {
                             title:
-                              html.tag('span', {class: 'group-name'}, additionalFileTitle),
+                              html.tag('span', {class: 'group-name'},
+                                additionalFileTitle),
+
                             files:
-                              language.countAdditionalFiles(additionalFileLinks.length, {unit: true}),
+                              language.countAdditionalFiles(
+                                additionalFileLinks.length,
+                                {unit: true}),
                           }))),
 
                       html.tag('ul',
@@ -67,7 +71,7 @@ export default {
                             html.tag('li',
                               additionalFileLink.slots({
                                 content:
-                                  language.$(`listingPage.${slots.stringsKey}.file`, {
+                                  language.$('listingPage', slots.stringsKey, 'file', {
                                     title: additionalFileFile,
                                   }),
                               })))),
diff --git a/src/content/dependencies/generateListingIndexList.js b/src/content/dependencies/generateListingIndexList.js
index 290295b5..ed153652 100644
--- a/src/content/dependencies/generateListingIndexList.js
+++ b/src/content/dependencies/generateListingIndexList.js
@@ -81,16 +81,18 @@ export default {
               listingStringsKey: listingStringsKeys,
             }).map(({listingLink, listingStringsKey}, listingIndex) =>
                 html.tag('li',
-                  {class:
-                    targetIndex === data.currentTargetIndex &&
-                    listingIndex === data.currentListingIndex &&
-                      'current'},
-                  listingLink
-                    .slot('content', language.$(`listingPage.${listingStringsKey}.title.short`))))));
+                  targetIndex === data.currentTargetIndex &&
+                  listingIndex === data.currentListingIndex &&
+                    {class: 'current'},
+
+                  listingLink.slots({
+                    content:
+                      language.$('listingPage', listingStringsKey, 'title.short'),
+                  })))));
 
     const targetTitles =
       data.targetStringsKeys
-        .map(stringsKey => language.$(`listingPage.target.${stringsKey}`));
+        .map(stringsKey => language.$('listingPage.target', stringsKey));
 
     switch (slots.mode) {
       case 'sidebar':
@@ -100,13 +102,13 @@ export default {
             listingLinkList: listingLinkLists,
           }).map(({targetTitle, listingLinkList}, targetIndex) =>
               html.tag('details',
-                {
-                  open: targetIndex === data.currentTargetIndex,
-                  class: targetIndex === data.currentTargetIndex && 'current',
-                },
+                targetIndex === data.currentTargetIndex &&
+                  {class: 'current', open: true},
+
                 [
                   html.tag('summary',
-                    html.tag('span', {class: 'group-name'}, targetTitle)),
+                    html.tag('span', {class: 'group-name'},
+                      targetTitle)),
 
                   listingLinkList,
                 ])));
@@ -118,8 +120,11 @@ export default {
               targetTitle: targetTitles,
               listingLinkList: listingLinkLists,
             }).map(({targetTitle, listingLinkList}) => [
-                html.tag('dt', {class: ['content-heading']}, targetTitle),
-                html.tag('dd', listingLinkList),
+                html.tag('dt', {class: 'content-heading'},
+                  targetTitle),
+
+                html.tag('dd',
+                  listingLinkList),
               ])));
     }
   },
diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js
index 2050d62d..fe65a82d 100644
--- a/src/content/dependencies/generateListingPage.js
+++ b/src/content/dependencies/generateListingPage.js
@@ -167,7 +167,9 @@ export default {
         relations.sameTargetListingLinks &&
           html.tag('p',
             language.$('listingPage.listingsFor', {
-              target: language.$(`listingPage.target.${data.targetStringsKey}`),
+              target:
+                language.$('listingPage.target', data.targetStringsKey),
+
               listings:
                 language.formatUnitList(
                   stitchArrays({
@@ -175,10 +177,12 @@ export default {
                     stringsKey: data.sameTargetListingStringsKeys,
                   }).map(({link, stringsKey}, index) =>
                       html.tag('span',
-                        {class: index === data.sameTargetListingsCurrentIndex && 'current'},
+                        index === data.sameTargetListingsCurrentIndex &&
+                          {class: 'current'},
+
                         link.slots({
                           attributes: {class: 'nowrap'},
-                          content: language.$(`listingPage.${stringsKey}.title.short`),
+                          content: language.$('listingPage', stringsKey, 'title.short'),
                         })))),
             })),
 
diff --git a/src/content/dependencies/generateNewsEntryReadAnotherLinks.js b/src/content/dependencies/generateNewsEntryReadAnotherLinks.js
index 33c5bda0..d978b0e4 100644
--- a/src/content/dependencies/generateNewsEntryReadAnotherLinks.js
+++ b/src/content/dependencies/generateNewsEntryReadAnotherLinks.js
@@ -85,13 +85,13 @@ export default {
     }
 
     return (
-      html.tag('p', {
-        [html.onlyIfContent]: true,
-        [html.joinChildren]: html.tag('br'),
-        class: [
-          'read-another-links',
-          entryLines.length > 1 && 'offset-tooltips',
-        ],
-      }, entryLines));
+      html.tag('p', {class: 'read-another-links'},
+        {[html.onlyIfContent]: true},
+        {[html.joinChildren]: html.tag('br')},
+
+        entryLines.length > 1 &&
+          {class: 'offset-tooltips'},
+
+        entryLines));
   },
 };
diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js
index e4c02fb2..3ed6631c 100644
--- a/src/content/dependencies/generatePageLayout.js
+++ b/src/content/dependencies/generatePageLayout.js
@@ -252,123 +252,114 @@ export default {
     }
 
     const mainHTML =
-      html.tag('main', {
-        id: 'content',
-        class: slots.mainClasses,
-      }, [
-        titleHTML,
-
-        html.tag('div', {
-          [html.onlyIfContent]: true,
-          id: 'cover-art-container',
-        }, slots.cover),
-
-        slots.additionalNames,
-
-        html.tag('div',
-          {
-            [html.onlyIfContent]: true,
-            class: 'main-content-container',
-          },
-          slots.mainContent),
-      ]);
+      html.tag('main', {id: 'content'},
+        {class: slots.mainClasses},
+
+        [
+          titleHTML,
+
+          html.tag('div', {id: 'cover-art-container'},
+            {[html.onlyIfContent]: true},
+            slots.cover),
+
+          slots.additionalNames,
+
+          html.tag('div', {class: 'main-content-container'},
+            {[html.onlyIfContent]: true},
+            slots.mainContent),
+        ]);
 
     const footerHTML =
-      html.tag('footer',
-        {[html.onlyIfContent]: true, id: 'footer'},
+      html.tag('footer', {id: 'footer'},
+        {[html.onlyIfContent]: true},
+
         [
-          html.tag('div',
-            {
-              [html.onlyIfContent]: true,
-              class: 'footer-content',
-            },
+          html.tag('div', {class: 'footer-content'},
+            {[html.onlyIfContent]: true},
             footerContent),
 
           relations.footerLocalizationLinks,
         ]);
 
-    const navHTML = html.tag('nav',
-      {
-        [html.onlyIfContent]: true,
-        id: 'header',
-        class: [
-          !empty(slots.navLinks) && 'nav-has-main-links',
-          !html.isBlank(slots.navContent) && 'nav-has-content',
-          !html.isBlank(slots.navBottomRowContent) && 'nav-has-bottom-row',
-        ],
-      },
-      [
-        html.tag('div',
-          {
-            [html.onlyIfContent]: true,
-            class: [
-              'nav-main-links',
-              'nav-links-' + slots.navLinkStyle,
-            ],
-          },
-          slots.navLinks
-            ?.filter(Boolean)
-            ?.map((cur, i) => {
-              let content;
-
-              if (cur.html) {
-                content = cur.html;
-              } else {
-                let title;
-                let href;
-
-                switch (cur.auto) {
-                  case 'home':
-                    title = data.wikiName;
-                    href = to('localized.home');
-                    break;
-                  case 'current':
-                    title = slots.title;
-                    href = '';
-                    break;
-                  case null:
-                  case undefined:
-                    title = cur.title;
-                    href = to(...cur.path);
-                    break;
-                }
+    const navHTML =
+      html.tag('nav', {id: 'header'},
+        {[html.onlyIfContent]: true},
 
-                content = html.tag('a',
-                  {href},
-                  title);
-              }
+        !empty(slots.navLinks) &&
+          {class: 'nav-has-main-links'},
 
-              let className;
+        !html.isBlank(slots.navContent) &&
+          {class: 'nav-has-content'},
 
-              if (
-                cur.current ||
-                cur.auto === 'current' ||
-                (slots.navLinkStyle === 'hierarchical' &&
-                  i === slots.navLinks.length - 1)
-              ) {
-                className = 'current';
-              }
+        !html.isBlank(slots.navBottomRowContent) &&
+          {class: 'nav-has-bottom-row'},
 
-              return html.tag('span',
-                {class: className},
-                [
-                  html.tag('span',
-                    {class: 'nav-link-content'},
-                    content),
+        [
+          html.tag('div', {class: 'nav-main-links'},
+            {[html.onlyIfContent]: true},
+            {class: 'nav-links-' + slots.navLinkStyle},
+
+            slots.navLinks
+              ?.filter(Boolean)
+              ?.map((cur, i) => {
+                let content;
+
+                if (cur.html) {
+                  content = cur.html;
+                } else {
+                  let title;
+                  let href;
+
+                  switch (cur.auto) {
+                    case 'home':
+                      title = data.wikiName;
+                      href = to('localized.home');
+                      break;
+                    case 'current':
+                      title = slots.title;
+                      href = '';
+                      break;
+                    case null:
+                    case undefined:
+                      title = cur.title;
+                      href = to(...cur.path);
+                      break;
+                  }
+
+                  content =
+                    html.tag('a', {href}, title);
+                }
+
+                return (
                   html.tag('span',
-                    {[html.onlyIfContent]: true, class: 'nav-link-accent'},
-                    cur.accent),
-                ]);
-            })),
+                    cur.current &&
+                      {class: 'current'},
+
+                    cur.auto === 'current' &&
+                      {class: 'current'},
 
-        html.tag('div',
-          {[html.onlyIfContent]: true, class: 'nav-bottom-row'},
-          slots.navBottomRowContent),
+                    slots.navLinkStyle === 'hierarchical' &&
+                    i === slots.navLinks.length - 1 &&
+                      {class: 'current'},
 
-        html.tag('div',
-          {[html.onlyIfContent]: true, class: 'nav-content'},
-          slots.navContent),
-      ])
+                    [
+                      html.tag('span', {class: 'nav-link-content'},
+                        content),
+
+                      html.tag('span', {class: 'nav-link-accent'},
+                        {[html.onlyIfContent]: true},
+                        cur.accent),
+                    ]));
+              })),
+
+          html.tag('div', {class: 'nav-bottom-row'},
+            {[html.onlyIfContent]: true},
+            slots.navBottomRowContent),
+
+          html.tag('div', {class: 'nav-content'},
+            {[html.onlyIfContent]: true},
+            slots.navContent),
+        ]);
 
     const generateSidebarHTML = (side, id) => {
       const content = slots[side + 'Content'];
@@ -390,24 +381,28 @@ export default {
           multiple
             .filter(Boolean)
             .map(box =>
-              html.tag('div', {
-                [html.onlyIfContent]: true,
-                class: ['sidebar', box.class],
-              }, box.content));
+              html.tag('div', {class: 'sidebar'},
+                {[html.onlyIfContent]: true},
+                {class: box.class},
+                box.content));
       }
 
       if (html.isBlank(sidebarContent)) {
         return html.blank();
       }
 
-      return html.tag('div',
-        {id, class: [
-          'sidebar-column',
-          wide && 'wide',
-          !collapse && 'no-hide',
-          stickyMode !== 'static' && `sticky-${stickyMode}`,
-          ...sidebarClasses,
-        ]},
+      return html.tag('div', {class: 'sidebar-column'},
+        {id, class: sidebarClasses},
+
+        wide &&
+          {class: 'wide'},
+
+        !collapse &&
+          {class: 'no-hide'},
+
+        stickyMode !== 'static' &&
+          {class: `sticky-${stickyMode}`},
+
         sidebarContent);
     }
 
@@ -435,7 +430,7 @@ export default {
           html.tag('span', {class: 'skipper'},
             html.tag('a',
               {href: `#${id}`},
-              language.$(`misc.skippers.${string}`))));
+              language.$('misc.skippers', string))));
 
     const skippersHTML =
       mainHTML &&
@@ -464,8 +459,8 @@ export default {
               {condition: footerHTML, id: 'footer', string: 'footer'},
             ])),
 
-          html.tag('div',
-            {[html.onlyIfContent]: true, class: 'skipper-list'},
+          html.tag('div', {class: 'skipper-list'},
+            {[html.onlyIfContent]: true},
             processSkippers([
               {id: 'tracks', string: 'tracks'},
               {id: 'art', string: 'artworks'},
@@ -500,20 +495,26 @@ export default {
 
           html.tag('div', {id: 'image-overlay-action-content-with-size'}, [
             language.$('releaseInfo.viewOriginalFile.withSize', {
-              link: html.tag('a', {class: 'image-overlay-view-original'},
-                language.$('releaseInfo.viewOriginalFile.link')),
-              size: html.tag('span',
-                {[html.joinChildren]: ''},
-                [
-                  html.tag('span', {id: 'image-overlay-file-size-kilobytes'},
-                    language.$('count.fileSize.kilobytes', {
-                      kilobytes: html.tag('span', {class: 'image-overlay-file-size-count'}),
-                    })),
-                  html.tag('span', {id: 'image-overlay-file-size-megabytes'},
-                    language.$('count.fileSize.megabytes', {
-                      megabytes: html.tag('span', {class: 'image-overlay-file-size-count'}),
-                    })),
-                ]),
+              link:
+                html.tag('a', {class: 'image-overlay-view-original'},
+                  language.$('releaseInfo.viewOriginalFile.link')),
+
+              size:
+                html.tag('span',
+                  {[html.joinChildren]: ''},
+                  [
+                    html.tag('span', {id: 'image-overlay-file-size-kilobytes'},
+                      language.$('count.fileSize.kilobytes', {
+                        kilobytes:
+                          html.tag('span', {class: 'image-overlay-file-size-count'}),
+                      })),
+
+                    html.tag('span', {id: 'image-overlay-file-size-megabytes'},
+                      language.$('count.fileSize.megabytes', {
+                        megabytes:
+                          html.tag('span', {class: 'image-overlay-file-size-count'}),
+                      })),
+                  ]),
             }),
 
             html.tag('span', {id: 'image-overlay-file-size-warning'},
@@ -524,42 +525,45 @@ export default {
 
     const layoutHTML = [
       navHTML,
-      slots.bannerPosition === 'top' && slots.banner,
+
+      slots.bannerPosition === 'top' &&
+        slots.banner,
+
       slots.secondaryNav,
-      html.tag('div',
-        {
-          class: [
-            'layout-columns',
-            !collapseSidebars && 'vertical-when-thin',
-          ],
-        },
+
+      html.tag('div', {class: 'layout-columns'},
+        !collapseSidebars &&
+          {class: 'vertical-when-thin'},
+
         [
           sidebarLeftHTML,
           mainHTML,
           sidebarRightHTML,
         ]),
-      slots.bannerPosition === 'bottom' && slots.banner,
+
+      slots.bannerPosition === 'bottom' &&
+        slots.banner,
+
       footerHTML,
     ];
 
     const pageHTML = html.tags([
       `<!DOCTYPE html>`,
       html.tag('html',
-        {
-          lang: language.intlCode,
-          'data-language-code': language.code,
-
-          'data-url-key': 'localized.' + pagePath[0],
-          ...Object.fromEntries(
-            pagePath
-              .slice(1)
-              .map((v, i) => [['data-url-value' + i], v])),
-
-          'data-rebase-localized': to('localized.root'),
-          'data-rebase-shared': to('shared.root'),
-          'data-rebase-media': to('media.root'),
-          'data-rebase-data': to('data.root'),
-        },
+        {lang: language.intlCode},
+        {'data-language-code': language.code},
+
+        {'data-url-key': 'localized.' + pagePath[0]},
+        Object.fromEntries(
+          pagePath
+            .slice(1)
+            .map((v, i) => [['data-url-value' + i], v])),
+
+        {'data-rebase-localized': to('localized.root')},
+        {'data-rebase-shared': to('shared.root')},
+        {'data-rebase-media': to('media.root')},
+        {'data-rebase-data': to('data.root')},
+
         [
           // developersComment,
 
@@ -644,17 +648,20 @@ export default {
 
           html.tag('body',
             [
-              html.tag('div',
-                {
-                  id: 'page-container',
-                  class: [
-                    (hasSidebarLeft || hasSidebarRight) && 'has-one-sidebar',
-                    (hasSidebarLeft && hasSidebarRight) && 'has-two-sidebars',
-                    !(hasSidebarLeft || hasSidebarRight) && 'has-zero-sidebars',
-                    hasSidebarLeft && 'has-sidebar-left',
-                    hasSidebarRight && 'has-sidebar-right',
-                  ],
-                },
+              html.tag('div', {id: 'page-container'},
+                (hasSidebarLeft || hasSidebarRight
+                  ? {class: 'has-one-sidebar'}
+                  : {class: 'has-zero-sidebars'}),
+
+                hasSidebarLeft && hasSidebarRight &&
+                  {class: 'has-two-sidebars'},
+
+                hasSidebarLeft &&
+                  {class: 'has-sidebar-left'},
+
+                hasSidebarRight &&
+                  {class: 'has-sidebar-right'},
+
                 [
                   skippersHTML,
                   layoutHTML,
diff --git a/src/content/dependencies/generateSecondaryNav.js b/src/content/dependencies/generateSecondaryNav.js
index e62016bd..1f965a25 100644
--- a/src/content/dependencies/generateSecondaryNav.js
+++ b/src/content/dependencies/generateSecondaryNav.js
@@ -9,11 +9,9 @@ export default {
     },
   },
 
-  generate(slots, {html}) {
-    return html.tag('nav', {
-      [html.onlyIfContent]: true,
-      id: 'secondary-nav',
-      class: slots.class,
-    }, slots.content);
-  },
+  generate: (slots, {html}) =>
+    html.tag('nav', {id: 'secondary-nav'},
+      {[html.onlyIfContent]: true},
+      {class: slots.class},
+      slots.content),
 };
diff --git a/src/content/dependencies/generateStickyHeadingContainer.js b/src/content/dependencies/generateStickyHeadingContainer.js
index 5ea10765..8eb39e6c 100644
--- a/src/content/dependencies/generateStickyHeadingContainer.js
+++ b/src/content/dependencies/generateStickyHeadingContainer.js
@@ -6,21 +6,16 @@ export default {
     cover: {type: 'html'},
   },
 
-  generate(slots, {html}) {
-    const hasCover = !html.isBlank(slots.cover);
+  generate: (slots, {html}) =>
+    html.tag('div', {class: 'content-sticky-heading-container'},
+      !html.isBlank(slots.cover) &&
+        {class: 'has-cover'},
 
-    return html.tag('div',
-      {
-        class: [
-          'content-sticky-heading-container',
-          hasCover && 'has-cover',
-        ],
-      },
       [
         html.tag('div', {class: 'content-sticky-heading-row'}, [
           html.tag('h1', slots.title),
 
-          hasCover &&
+          !html.isBlank(slots.cover) &&
             html.tag('div', {class: 'content-sticky-heading-cover-container'},
               html.tag('div', {class: 'content-sticky-heading-cover'},
                 slots.cover.slot('mode', 'thumbnail'))),
@@ -28,6 +23,5 @@ export default {
 
         html.tag('div', {class: 'content-sticky-subheading-row'},
           html.tag('h2', {class: 'content-sticky-subheading'})),
-      ]);
-  },
+      ]),
 };
diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js
index 041f6bbc..b5121386 100644
--- a/src/content/dependencies/generateTrackInfoPage.js
+++ b/src/content/dependencies/generateTrackInfoPage.js
@@ -346,10 +346,9 @@ export default {
           relations.releaseInfo,
 
           html.tag('p',
-            {
-              [html.onlyIfContent]: true,
-              [html.joinChildren]: '<br>',
-            },
+            {[html.onlyIfContent]: true},
+            {[html.joinChildren]: html.tag('br')},
+
             [
               sec.sheetMusicFiles &&
                 language.$('releaseInfo.sheetMusicFiles.shortcut', {
@@ -414,7 +413,11 @@ export default {
 
                   return (
                     html.tag('li',
-                      {style: colorVariables.slot('color', color).content},
+                      {style:
+                        colorVariables
+                          .slot('color', color)
+                          .content},
+
                       language.$(...parts, options)));
                 })),
           ],
diff --git a/src/content/dependencies/generateTrackReleaseInfo.js b/src/content/dependencies/generateTrackReleaseInfo.js
index c347dbce..3bdeaa4f 100644
--- a/src/content/dependencies/generateTrackReleaseInfo.js
+++ b/src/content/dependencies/generateTrackReleaseInfo.js
@@ -46,33 +46,34 @@ export default {
     return data;
   },
 
-  generate(data, relations, {html, language}) {
-    return html.tags([
-      html.tag('p', {
-        [html.onlyIfContent]: true,
-        [html.joinChildren]: html.tag('br'),
-      }, [
-        relations.artistContributionLinks
-          .slots({stringKey: 'releaseInfo.by'}),
-
-        relations.coverArtistContributionsLine
-          ?.slots({stringKey: 'releaseInfo.coverArtBy'}),
-
-        data.date &&
-          language.$('releaseInfo.released', {
-            date: language.formatDate(data.date),
-          }),
-
-        data.coverArtDate &&
-          language.$('releaseInfo.artReleased', {
-            date: language.formatDate(data.coverArtDate),
-          }),
-
-        data.duration &&
-          language.$('releaseInfo.duration', {
-            duration: language.formatDuration(data.duration),
-          }),
-      ]),
+  generate: (data, relations, {html, language}) =>
+    html.tags([
+      html.tag('p',
+        {[html.onlyIfContent]: true},
+        {[html.joinChildren]: html.tag('br')},
+
+        [
+          relations.artistContributionLinks
+            .slots({stringKey: 'releaseInfo.by'}),
+
+          relations.coverArtistContributionsLine
+            ?.slots({stringKey: 'releaseInfo.coverArtBy'}),
+
+          data.date &&
+            language.$('releaseInfo.released', {
+              date: language.formatDate(data.date),
+            }),
+
+          data.coverArtDate &&
+            language.$('releaseInfo.artReleased', {
+              date: language.formatDate(data.coverArtDate),
+            }),
+
+          data.duration &&
+            language.$('releaseInfo.duration', {
+              duration: language.formatDuration(data.duration),
+            }),
+        ]),
 
       html.tag('p',
         (relations.externalLinks
@@ -85,6 +86,5 @@ export default {
           : language.$('releaseInfo.listenOn.noLinks', {
               name: html.tag('i', data.name),
             }))),
-    ]);
-  },
+    ]),
 };
diff --git a/src/content/dependencies/generateWikiHomeContentRow.js b/src/content/dependencies/generateWikiHomeContentRow.js
index 5b1df99e..c8354fea 100644
--- a/src/content/dependencies/generateWikiHomeContentRow.js
+++ b/src/content/dependencies/generateWikiHomeContentRow.js
@@ -20,16 +20,15 @@ export default {
     content: {type: 'html'},
   },
 
-  generate(data, relations, slots, {html}) {
-    return (
-      html.tag('section',
-        {
-          class: 'row',
-          style: relations.colorVariables.slot('color', data.color).content,
-        },
-        [
-          html.tag('h2', data.name),
-          slots.content,
-        ]));
-  },
+  generate: (data, relations, slots, {html}) =>
+    html.tag('section', {class: 'row'},
+      {style:
+        relations.colorVariables
+          .slot('color', data.color)
+          .content},
+
+      [
+        html.tag('h2', data.name),
+        slots.content,
+      ]),
 };
diff --git a/src/content/dependencies/generateWikiHomeNewsBox.js b/src/content/dependencies/generateWikiHomeNewsBox.js
index 0d8303f1..f592ab99 100644
--- a/src/content/dependencies/generateWikiHomeNewsBox.js
+++ b/src/content/dependencies/generateWikiHomeNewsBox.js
@@ -57,23 +57,25 @@ export default {
             mainLink,
             readMoreLink,
           }, index) =>
-          html.tag('article',
-            {class: ['news-entry', index === 0 && 'first-news-entry']},
-            [
-              html.tag('h2', [
-                html.tag('time', language.formatDate(date)),
-                mainLink,
-              ]),
+            html.tag('article', {class: 'news-entry'},
+              index === 0 &&
+                {class: 'first-news-entry'},
 
-              content.slot('thumb', 'medium'),
+              [
+                html.tag('h2', [
+                  html.tag('time', language.formatDate(date)),
+                  mainLink,
+                ]),
 
-              html.tag('p',
-                {[html.onlyIfContent]: true},
-                readMoreLink
-                  ?.slots({
-                    content: language.$('homepage.news.entry.viewRest'),
-                  })),
-            ])),
+                content.slot('thumb', 'medium'),
+
+                html.tag('p',
+                  {[html.onlyIfContent]: true},
+                  readMoreLink
+                    ?.slots({
+                      content: language.$('homepage.news.entry.viewRest'),
+                    })),
+              ])),
       ],
     };
   },
diff --git a/src/content/dependencies/image.js b/src/content/dependencies/image.js
index 3c78abe3..91bae43c 100644
--- a/src/content/dependencies/image.js
+++ b/src/content/dependencies/image.js
@@ -141,7 +141,7 @@ export default {
       return prepare(
         html.tag('div', {class: 'image-text-area'},
           (html.isBlank(slots.missingSourceContent)
-            ? language.$(`misc.missingImage`)
+            ? language.$('misc.missingImage')
             : slots.missingSourceContent)));
     }
 
@@ -231,39 +231,44 @@ export default {
 
     const nonlazyHTML =
       originalSrc &&
-        prepare(
-          html.tag('img', {
-            ...imgAttributes,
-            src: thumbSrc ?? originalSrc,
-          }));
+        prepareVisible(
+          html.tag('img',
+            imgAttributes,
+            {src: thumbSrc ?? originalSrc}));
 
     if (slots.lazy) {
       return html.tags([
         html.tag('noscript', nonlazyHTML),
-        prepare(
-          html.tag('img',
-            {
-              ...imgAttributes,
-              class: 'lazy',
-              'data-original': thumbSrc ?? originalSrc,
-            }),
+        prepareHidden(
+          html.tag('img', {class: 'lazy'},
+            imgAttributes,
+            {'data-original': thumbSrc ?? originalSrc}),
           true),
       ]);
     }
 
     return nonlazyHTML;
 
-    function prepare(content, hide = false) {
+    function prepareVisible(content) {
+      return prepare(content, false);
+    }
+
+    function prepareHidden(content) {
+      return prepare(content, true);
+    }
+
+    function prepare(content, hide) {
       let wrapped = content;
 
       wrapped =
-        html.tag('div', {
-          class: ['image-container', !originalSrc && 'placeholder-image'],
-          style: styleOnContainer,
-        }, [
+        html.tag('div', {class: 'image-container'},
+          {style: styleOnContainer},
+
+          !originalSrc &&
+            {style: 'placeholder-image'},
+
           html.tag('div', {class: 'image-inner-area'},
-            wrapped),
-        ]);
+            wrapped));
 
       if (willReveal) {
         wrapped =
@@ -277,38 +282,29 @@ export default {
 
       if (willSquare) {
         wrapped =
-          html.tag('div',
-            {
-              class: [
-                'square',
-                hide && !willLink && 'js-hide'
-              ],
-            },
+          html.tag('div', {class: 'square'},
+            hide && !willLink &&
+              {class: 'js-hide'},
 
             html.tag('div', {class: 'square-content'},
               wrapped));
       }
 
       if (willLink) {
-        wrapped = html.tag('a',
-          {
-            id: idOnLink,
-
-            class: [
-              'box',
-              'image-link',
-              hide && 'js-hide',
-              classOnLink,
-            ],
-
-            style: styleOnLink,
-
-            href:
-              (typeof slots.link === 'string'
-                ? slots.link
-                : originalSrc),
-          },
-          wrapped);
+        wrapped =
+          html.tag('a', {class: ['box', 'image-link']},
+            {id: idOnLink},
+            {class: classOnLink},
+            {style: styleOnLink},
+
+            hide &&
+              {class: 'js-hide'},
+
+            (typeof slots.link === 'string'
+              ? {href: slots.link}
+              : {href: originalSrc}),
+
+            wrapped);
       }
 
       return wrapped;
diff --git a/src/content/dependencies/linkContribution.js b/src/content/dependencies/linkContribution.js
index 790afa4f..578ae039 100644
--- a/src/content/dependencies/linkContribution.js
+++ b/src/content/dependencies/linkContribution.js
@@ -51,57 +51,55 @@ export default {
     if (hasExternalIcons && slots.iconMode === 'inline') {
       parts.push('withExternalLinks');
       options.links =
-        html.tag('span',
-          {
-            [html.noEdgeWhitespace]: true,
-            class: ['icons', 'icons-inline'],
-          },
+        html.tag('span', {class: ['icons', 'icons-inline']},
+          {[html.noEdgeWhitespace]: true},
+
           language.formatUnitList(
             relations.artistIcons
               .slice(0, 4)
-              .map(icon => icon.slot('context', 'artist'))));
+              .map(icon =>
+                icon.slot({
+                  context: 'artist',
+                }))));
     }
 
-    let content = language.formatString(parts.join('.'), options);
+    let content = language.formatString(...parts, options);
 
     if (hasExternalIcons && slots.iconMode === 'tooltip') {
       content = [
         content,
-        html.tag('span',
-          {
-            [html.noEdgeWhitespace]: true,
-            class: ['icons', 'icons-tooltip'],
-            inert: true,
-          },
-          html.tag('span',
-            {
-              [html.noEdgeWhitespace]: true,
-              [html.joinChildren]: '',
-              class: 'icons-tooltip-content',
-            },
+        html.tag('span', {class: ['icons', 'icons-tooltip']},
+          {[html.noEdgeWhitespace]: true},
+          {inert: true},
+
+          html.tag('span', {class: 'icons-tooltip-content'},
+            {[html.noEdgeWhitespace]: true},
+            {[html.joinChildren]: ''},
+
             relations.artistIcons
-              .map(icon => icon.slots({context: 'artist', withText: true})))),
+              .map(icon =>
+                icon.slots({
+                  context: 'artist',
+                  withText: true,
+                })))),
       ];
     }
 
     if (hasContribution || hasExternalIcons) {
       content =
-        html.tag('span', {
-          [html.noEdgeWhitespace]: true,
-          [html.joinChildren]: '',
-
-          class: [
-            'contribution',
-
-            hasExternalIcons &&
-            slots.iconMode === 'tooltip' &&
-              'has-tooltip',
-
-            parts.length > 1 &&
-            slots.preventWrapping &&
-              'nowrap',
-          ],
-        }, content);
+        html.tag('span', {class: 'contribution'},
+          {[html.noEdgeWhitespace]: true},
+          {[html.joinChildren]: ''},
+
+          hasExternalIcons &&
+          slots.iconMode === 'tooltip' &&
+            {class: 'has-tooltip'},
+
+          parts.length > 1 &&
+          slots.preventWrapping &&
+            {class: 'nowrap'},
+
+          content);
     }
 
     return content;
diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js
index 70e1ccff..16990023 100644
--- a/src/content/dependencies/linkExternal.js
+++ b/src/content/dependencies/linkExternal.js
@@ -27,14 +27,12 @@ export default {
 
   generate: (data, slots, {html, language}) =>
     html.tag('a',
-      {
-        href: data.url,
-        class: 'nowrap',
-        target:
-          (slots.tab === 'separate'
-            ? '_blank'
-            : null),
-      },
+      {class: 'nowrap'},
+      {href: data.url},
+
+      slots.tab === 'separate' &&
+        {target: '_blank'},
+
       language.formatExternalLink(data.url, {
         style: slots.style,
         context: slots.context,
diff --git a/src/content/dependencies/linkExternalAsIcon.js b/src/content/dependencies/linkExternalAsIcon.js
index 357c835c..3eb355a9 100644
--- a/src/content/dependencies/linkExternalAsIcon.js
+++ b/src/content/dependencies/linkExternalAsIcon.js
@@ -25,8 +25,12 @@ export default {
     const compactText = format('compact');
     const iconId = format('icon-id');
 
-    return html.tag('a',
-      {href: data.url, class: ['icon', slots.withText && 'has-text']},
+    return html.tag('a', {class: 'icon'},
+      {href: data.url},
+
+      slots.withText &&
+        {class: 'has-text'},
+
       [
         html.tag('svg', [
           !slots.withText &&
diff --git a/src/content/dependencies/linkListing.js b/src/content/dependencies/linkListing.js
index 2fc516bc..ac66919a 100644
--- a/src/content/dependencies/linkListing.js
+++ b/src/content/dependencies/linkListing.js
@@ -10,5 +10,6 @@ export default {
 
   generate: (data, relations, {language}) =>
     relations.link
-      .slot('content', language.$(`listingPage.${data.stringsKey}.title`)),
+      .slot('content',
+        language.$('listingPage', data.stringsKey, 'title')),
 };
diff --git a/src/content/dependencies/listAllAdditionalFilesTemplate.js b/src/content/dependencies/listAllAdditionalFilesTemplate.js
index 1b81e24b..627fdab4 100644
--- a/src/content/dependencies/listAllAdditionalFilesTemplate.js
+++ b/src/content/dependencies/listAllAdditionalFilesTemplate.js
@@ -173,10 +173,13 @@ export default {
 
             html.tag('dl', [
               albumChunk.slots({
-                title: language.$(`listingPage.${slots.stringsKey}.albumFiles`),
+                title:
+                  language.$('listingPage', slots.stringsKey, 'albumFiles'),
+
                 additionalFileTitles: albumAdditionalFileTitles,
                 additionalFileLinks: albumAdditionalFileLinks,
                 additionalFileFiles: albumAdditionalFileFiles,
+
                 stringsKey: slots.stringsKey,
               }),
 
diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js
index d42cce92..151c2c2e 100644
--- a/src/content/dependencies/transformContent.js
+++ b/src/content/dependencies/transformContent.js
@@ -369,10 +369,11 @@ export default {
                 type: 'image',
                 inline: true,
                 data:
-                  html.tag('img', {
-                    src, width, height,
-                    class: pixelate && 'pixelate',
-                  }),
+                  html.tag('img',
+                    {src, width, height},
+
+                    pixelate &&
+                      {class: 'pixelate'}),
               };
             }