diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/content/dependencies/generateAbsoluteDatetimestamp.js | 41 | ||||
-rw-r--r-- | src/content/dependencies/generateColorStyleRules.js | 7 | ||||
-rw-r--r-- | src/content/dependencies/generateColorStyleVariables.js | 51 | ||||
-rw-r--r-- | src/content/dependencies/generateDatetimestampTemplate.js | 28 | ||||
-rw-r--r-- | src/content/dependencies/generateGroupInfoPage.js | 112 | ||||
-rw-r--r-- | src/content/dependencies/generateRelativeDatetimestamp.js | 58 | ||||
-rw-r--r-- | src/content/dependencies/generateTrackInfoPage.js | 70 | ||||
-rw-r--r-- | src/data/things/language.js | 108 | ||||
-rw-r--r-- | src/static/client3.js | 53 | ||||
-rw-r--r-- | src/static/site6.css | 67 | ||||
-rw-r--r-- | src/strings-default.yaml | 71 |
11 files changed, 580 insertions, 86 deletions
diff --git a/src/content/dependencies/generateAbsoluteDatetimestamp.js b/src/content/dependencies/generateAbsoluteDatetimestamp.js new file mode 100644 index 00000000..63acecf2 --- /dev/null +++ b/src/content/dependencies/generateAbsoluteDatetimestamp.js @@ -0,0 +1,41 @@ +export default { + contentDependencies: ['generateDatetimestampTemplate'], + extraDependencies: ['html', 'language'], + + data: (date) => + ({date}), + + relations: (relation) => + ({template: relation('generateDatetimestampTemplate')}), + + slots: { + style: { + validate: v => v.is('full', 'year'), + default: 'full', + }, + + // Only has an effect for 'year' style. + tooltip: { + type: 'boolean', + default: false, + }, + }, + + generate: (data, relations, slots, {language}) => + relations.template.slots({ + mainContent: + (slots.style === 'full' + ? language.formatDate(data.date) + : slots.style === 'year' + ? data.date.getFullYear().toString() + : null), + + tooltipContent: + slots.tooltip && + slots.style === 'year' && + language.formatDate(data.date), + + datetime: + data.date.toISOString(), + }), +}; diff --git a/src/content/dependencies/generateColorStyleRules.js b/src/content/dependencies/generateColorStyleRules.js index 1b316a3c..3f1d0130 100644 --- a/src/content/dependencies/generateColorStyleRules.js +++ b/src/content/dependencies/generateColorStyleRules.js @@ -18,9 +18,12 @@ export default { `:root {`, ...( relations.variables - .slot('color', slots.color) + .slots({ + color: slots.color, + context: 'page-root', + mode: 'property-list', + }) .content - .split(';') .map(line => line + ';')), `}`, ].join('\n'); diff --git a/src/content/dependencies/generateColorStyleVariables.js b/src/content/dependencies/generateColorStyleVariables.js index f30d786b..7cd04bd1 100644 --- a/src/content/dependencies/generateColorStyleVariables.js +++ b/src/content/dependencies/generateColorStyleVariables.js @@ -2,7 +2,23 @@ export default { extraDependencies: ['html', 'getColors'], slots: { - color: {validate: v => v.isColor}, + color: { + validate: v => v.isColor, + }, + + context: { + validate: v => v.is( + 'any-content', + 'page-root', + 'primary-only'), + + default: 'any-content', + }, + + mode: { + validate: v => v.is('style', 'property-list'), + default: 'style', + }, }, generate(slots, {getColors}) { @@ -18,7 +34,7 @@ export default { shadow, } = getColors(slots.color); - return [ + let anyContent = [ `--primary-color: ${primary}`, `--dark-color: ${dark}`, `--dim-color: ${dim}`, @@ -26,6 +42,35 @@ export default { `--bg-color: ${bg}`, `--bg-black-color: ${bgBlack}`, `--shadow-color: ${shadow}`, - ].join('; '); + ]; + + let selectedProperties; + + switch (slots.context) { + case 'any-content': + selectedProperties = anyContent; + break; + + case 'page-root': + selectedProperties = [ + ...anyContent, + `--page-primary-color: ${primary}`, + ]; + break; + + case 'primary-only': + selectedProperties = [ + `--primary-color: ${primary}`, + ]; + break; + } + + switch (slots.mode) { + case 'style': + return selectedProperties.join('; '); + + case 'property-list': + return selectedProperties; + } }, }; diff --git a/src/content/dependencies/generateDatetimestampTemplate.js b/src/content/dependencies/generateDatetimestampTemplate.js new file mode 100644 index 00000000..bfba647f --- /dev/null +++ b/src/content/dependencies/generateDatetimestampTemplate.js @@ -0,0 +1,28 @@ +export default { + extraDependencies: ['html'], + + slots: { + mainContent: {type: 'html'}, + tooltipContent: {type: 'html'}, + datetime: {type: 'string'}, + }, + + generate: (slots, {html}) => + html.tag('span', { + [html.joinChildren]: '', + + class: [ + 'datetimestamp', + slots.tooltipContent && '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/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js index 05df33fb..0e5d645b 100644 --- a/src/content/dependencies/generateGroupInfoPage.js +++ b/src/content/dependencies/generateGroupInfoPage.js @@ -1,7 +1,9 @@ -import {empty} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ + 'generateAbsoluteDatetimestamp', + 'generateColorStyleVariables', 'generateContentHeading', 'generateGroupNavLinks', 'generateGroupSecondaryNav', @@ -62,18 +64,27 @@ export default { sec.albums.galleryLink = relation('linkGroupGallery', group); - sec.albums.entries = - group.albums.map(album => { - const links = {}; - links.albumLink = relation('linkAlbum', album); + sec.albums.colorVariables = + group.albums + .map(() => relation('generateColorStyleVariables')); - const otherGroup = album.groups.find(g => g !== group); - if (otherGroup) { - links.groupLink = relation('linkGroup', otherGroup); - } + sec.albums.albumLinks = + group.albums + .map(album => relation('linkAlbum', album)); - return links; - }); + sec.albums.groupLinks = + group.albums + .map(album => album.groups.find(g => g !== group)) + .map(group => + (group + ? relation('linkGroup', group) + : null)); + + sec.albums.datetimestamps = + group.albums.map(album => + (album.date + ? relation('generateAbsoluteDatetimestamp', album.date) + : null)); } return relations; @@ -85,11 +96,8 @@ export default { data.name = group.name; data.color = group.color; - if (!empty(group.albums)) { - data.albumYears = - group.albums - .map(album => album.date?.getFullYear()); - } + data.albumColors = + group.albums.map(album => album.color); return data; }, @@ -133,34 +141,50 @@ export default { })), html.tag('ul', - sec.albums.entries.map(({albumLink, groupLink}, index) => { - // All these strings are really jank, and should probably - // be implemented with the same 'const parts = [], opts = {}' - // form used elsewhere... - const year = data.albumYears[index]; - const item = - (year - ? language.$('groupInfoPage.albumList.item', { - year, - album: albumLink, - }) - : language.$('groupInfoPage.albumList.item.withoutYear', { - album: albumLink, - })); - - return html.tag('li', - (groupLink - ? language.$('groupInfoPage.albumList.item.withAccent', { - item, - accent: - html.tag('span', {class: 'other-group-accent'}, - language.$('groupInfoPage.albumList.item.otherGroupAccent', { - group: - groupLink.slot('color', false), - })), - }) - : item)); - })), + stitchArrays({ + albumLink: sec.albums.albumLinks, + groupLink: sec.albums.groupLinks, + datetimestamp: sec.albums.datetimestamps, + colorVariables: sec.albums.colorVariables, + albumColor: data.albumColors, + }).map(({ + albumLink, + groupLink, + datetimestamp, + colorVariables, + albumColor, + }) => { + const prefix = 'groupInfoPage.albumList.item'; + const parts = [prefix]; + const options = {}; + + options.album = + albumLink.slot('color', false); + + if (datetimestamp) { + parts.push('withYear'); + options.yearAccent = + language.$(prefix, 'yearAccent', { + year: + datetimestamp.slots({style: 'year', tooltip: true}), + }); + } + + if (groupLink) { + parts.push('withOtherGroup'); + options.otherGroupAccent = + html.tag('span', {class: 'other-group-accent'}, + language.$(prefix, 'otherGroupAccent', { + group: + groupLink.slot('color', false), + })); + } + + return ( + html.tag('li', + {style: colorVariables.slot('color', albumColor).content}, + language.$(...parts, options))); + })), ], ], diff --git a/src/content/dependencies/generateRelativeDatetimestamp.js b/src/content/dependencies/generateRelativeDatetimestamp.js new file mode 100644 index 00000000..bbe33188 --- /dev/null +++ b/src/content/dependencies/generateRelativeDatetimestamp.js @@ -0,0 +1,58 @@ +export default { + contentDependencies: [ + 'generateAbsoluteDatetimestamp', + 'generateDatetimestampTemplate', + ], + + extraDependencies: ['html', 'language'], + + data: (currentDate, referenceDate) => + (currentDate.getTime() === referenceDate.getTime() + ? {equal: true, date: currentDate} + : {equal: false, currentDate, referenceDate}), + + relations: (relation, currentDate) => + ({template: relation('generateDatetimestampTemplate'), + fallback: relation('generateAbsoluteDatetimestamp', currentDate)}), + + slots: { + style: { + validate: v => v.is('full', 'year'), + default: 'full', + }, + + tooltip: { + type: 'boolean', + default: false, + }, + }, + + generate(data, relations, slots, {language}) { + if (data.comparison === 'equal') { + return relations.fallback.slots({ + style: slots.style, + tooltip: slots.tooltip, + }); + } + + return relations.template.slots({ + mainContent: + (slots.style === 'full' + ? language.formatDate(data.currentDate) + : slots.style === 'year' + ? data.currentDate.getFullYear().toString() + : null), + + tooltipContent: + slots.tooltip && + language.formatRelativeDate(data.currentDate, data.referenceDate, { + considerRoundingDays: true, + approximate: true, + absolute: slots.style === 'year', + }), + + datetime: + data.currentDate.toISOString(), + }); + }, +}; diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index d8908ade..041f6bbc 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -1,20 +1,23 @@ -import {empty} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; import {sortAlbumsTracksChronologically, sortFlashesChronologically} from '#wiki-data'; import getChronologyRelations from '../util/getChronologyRelations.js'; export default { contentDependencies: [ + 'generateAbsoluteDatetimestamp', 'generateAdditionalFilesShortcut', 'generateAlbumAdditionalFilesList', 'generateAlbumNavAccent', 'generateAlbumSidebar', 'generateAlbumStyleRules', 'generateChronologyLinks', + 'generateColorStyleVariables', 'generateCommentarySection', 'generateContentHeading', 'generateContributionList', 'generatePageLayout', + 'generateRelativeDatetimestamp', 'generateTrackAdditionalNamesBox', 'generateTrackCoverArtwork', 'generateTrackList', @@ -139,6 +142,29 @@ export default { otherReleases.heading = relation('generateContentHeading'); + otherReleases.colorVariables = + track.otherReleases + .map(() => relation('generateColorStyleVariables')); + + otherReleases.trackLinks = + track.otherReleases + .map(track => relation('linkTrack', track)); + + otherReleases.albumLinks = + track.otherReleases + .map(track => relation('linkAlbum', track.album)); + + otherReleases.datetimestamps = + track.otherReleases.map(track2 => + (track2.date + ? (track.date + ? relation('generateRelativeDatetimestamp', + track2.date, + track.date) + : relation('generateAbsoluteDatetimestamp', + track2.date)) + : null)); + otherReleases.items = track.otherReleases.map(track => ({ trackLink: relation('linkTrack', track), @@ -289,6 +315,9 @@ export default { hasTrackNumbers: track.album.hasTrackNumbers, trackNumber: track.album.tracks.indexOf(track) + 1, + otherReleaseColors: + track.otherReleases.map(track => track.color), + numAdditionalFiles: track.additionalFiles.length, }; }, @@ -355,12 +384,39 @@ export default { }), html.tag('ul', - sec.otherReleases.items.map(({trackLink, albumLink}) => - html.tag('li', - language.$('releaseInfo.alsoReleasedAs.item', { - track: trackLink, - album: albumLink, - })))), + stitchArrays({ + trackLink: sec.otherReleases.trackLinks, + albumLink: sec.otherReleases.albumLinks, + datetimestamp: sec.otherReleases.datetimestamps, + colorVariables: sec.otherReleases.colorVariables, + color: data.otherReleaseColors, + }).map(({ + trackLink, + albumLink, + datetimestamp, + colorVariables, + color, + }) => { + const parts = ['releaseInfo.alsoReleasedAs.item']; + const options = {}; + + options.track = trackLink.slot('color', false); + options.album = albumLink; + + if (datetimestamp) { + parts.push('withYear'); + options.year = + datetimestamp.slots({ + style: 'year', + tooltip: true, + }); + } + + return ( + html.tag('li', + {style: colorVariables.slot('color', color).content}, + language.$(...parts, options))); + })), ], sec.contributors && [ diff --git a/src/data/things/language.js b/src/data/things/language.js index d8af9620..80a34575 100644 --- a/src/data/things/language.js +++ b/src/data/things/language.js @@ -1,3 +1,5 @@ +import { Temporal, toTemporalInstant } from '@js-temporal/polyfill'; + import {isLanguageCode} from '#validators'; import {Tag} from '#html'; @@ -284,6 +286,108 @@ export class Language extends Thing { return this.intl_date.formatRange(startDate, endDate); } + formatDateDuration({ + years: numYears = 0, + months: numMonths = 0, + days: numDays = 0, + approximate = false, + }) { + let basis; + + const years = this.countYears(numYears, {unit: true}); + const months = this.countMonths(numMonths, {unit: true}); + const days = this.countDays(numDays, {unit: true}); + + if (numYears && numMonths && numDays) + basis = this.formatString('count.dateDuration.yearsMonthsDays', {years, months, days}); + else if (numYears && numMonths) + basis = this.formatString('count.dateDuration.yearsMonths', {years, months}); + else if (numYears && numDays) + basis = this.formatString('count.dateDuration.yearsDays', {years, days}); + else if (numYears) + basis = this.formatString('count.dateDuration.years', {years}); + else if (numMonths && numDays) + basis = this.formatString('count.dateDuration.monthsDays', {months, days}); + else if (numMonths) + basis = this.formatzString('count.dateDuration.months', {months}); + else if (numDays) + basis = this.formatString('count.dateDuration.days', {days}); + else + return this.formatString('count.dateDuration.zero'); + + if (approximate) { + return this.formatString('count.dateDuration.approximate', { + duration: basis, + }); + } else { + return basis; + } + } + + formatRelativeDate(currentDate, referenceDate, { + considerRoundingDays = false, + approximate = true, + absolute = true, + } = {}) { + const currentInstant = toTemporalInstant.apply(currentDate); + const referenceInstant = toTemporalInstant.apply(referenceDate); + + const comparison = + Temporal.Instant.compare(currentInstant, referenceInstant); + + if (comparison === 0) { + return this.formatString('count.dateDuration.same'); + } + + const currentTDZ = currentInstant.toZonedDateTimeISO('Etc/UTC'); + const referenceTDZ = referenceInstant.toZonedDateTimeISO('Etc/UTC'); + + const earlierTDZ = (comparison === -1 ? currentTDZ : referenceTDZ); + const laterTDZ = (comparison === 1 ? currentTDZ : referenceTDZ); + + const {years, months, days} = + laterTDZ.since(earlierTDZ, { + largestUnit: 'year', + smallestUnit: + (considerRoundingDays + ? (laterTDZ.since(earlierTDZ, { + largestUnit: 'year', + smallestUnit: 'day', + }).years + ? 'month' + : 'day') + : 'day'), + roundingMode: 'halfCeil', + }); + + const duration = + this.formatDateDuration({ + years, months, days, + approximate: false, + }); + + const relative = + this.formatString( + 'count.dateDuration', + (approximate && (years || months || days) + ? (comparison === -1 + ? 'approximateEarlier' + : 'approximateLater') + : (comparison === -1 + ? 'earlier' + : 'later')), + {duration}); + + if (absolute) { + return this.formatString('count.dateDuration.relativeAbsolute', { + relative, + absolute: this.formatDate(currentDate), + }); + } else { + return relative; + } + } + formatDuration(secTotal, {approximate = false, unit = false} = {}) { if (secTotal === 0) { return this.formatString('count.duration.missing'); @@ -442,7 +546,11 @@ Object.assign(Language.prototype, { countCommentaryEntries: countHelper('commentaryEntries', 'entries'), countContributions: countHelper('contributions'), countCoverArts: countHelper('coverArts'), + countDays: countHelper('days'), + countMonths: countHelper('months'), countTimesReferenced: countHelper('timesReferenced'), countTimesUsed: countHelper('timesUsed'), countTracks: countHelper('tracks'), + countWeeks: countHelper('weeks'), + countYears: countHelper('years'), }); diff --git a/src/static/client3.js b/src/static/client3.js index 1e64ebe1..ce057712 100644 --- a/src/static/client3.js +++ b/src/static/client3.js @@ -1981,8 +1981,8 @@ for (const info of groupContributionsTableInfo) { // Artist link icon tooltips ------------------------------ const externalIconTooltipInfo = clientInfo.externalIconTooltipInfo = { - hoverableLinks: null, - iconContainers: null, + hoverables: null, + tooltips: null, }; function getExternalIconTooltipReferences() { @@ -1991,21 +1991,19 @@ function getExternalIconTooltipReferences() { const spans = Array.from(document.querySelectorAll('span.contribution.has-tooltip')); - info.hoverableLinks = - spans - .map(span => span.querySelector('a')); + info.hoverables = + spans.map(span => span.querySelector('a')); - info.iconContainers = - spans - .map(span => span.querySelector('span.icons-tooltip')); + info.tooltips = + spans.map(span => span.querySelector('span.icons-tooltip')); } function addExternalIconTooltipPageListeners() { const info = externalIconTooltipInfo; for (const {hoverable, tooltip} of stitchArrays({ - hoverable: info.hoverableLinks, - tooltip: info.iconContainers, + hoverable: info.hoverables, + tooltip: info.tooltips, })) { registerTooltipElement(tooltip); registerTooltipHoverableElement(hoverable, tooltip); @@ -2015,6 +2013,41 @@ function addExternalIconTooltipPageListeners() { clientSteps.getPageReferences.push(getExternalIconTooltipReferences); clientSteps.addPageListeners.push(addExternalIconTooltipPageListeners); +// Datetimestamp tooltips --------------------------------- + +const datetimestampTooltipInfo = clientInfo.datetimestampTooltipInfo = { + hoverables: null, + tooltips: null, +}; + +function getDatestampTooltipReferences() { + const info = datetimestampTooltipInfo; + + const spans = + Array.from(document.querySelectorAll('span.datetimestamp.has-tooltip')); + + info.hoverables = + spans.map(span => span.querySelector('time')); + + info.tooltips = + spans.map(span => span.querySelector('span.datetimestamp-tooltip')); +} + +function addDatestampTooltipPageListeners() { + const info = datetimestampTooltipInfo; + + for (const {hoverable, tooltip} of stitchArrays({ + hoverable: info.hoverables, + tooltip: info.tooltips, + })) { + registerTooltipElement(tooltip); + registerTooltipHoverableElement(hoverable, tooltip); + } +} + +clientSteps.getPageReferences.push(getDatestampTooltipReferences); +clientSteps.addPageListeners.push(addDatestampTooltipPageListeners); + // Sticky commentary sidebar ------------------------------ const albumCommentarySidebarInfo = clientInfo.albumCommentarySidebarInfo = { diff --git a/src/static/site6.css b/src/static/site6.css index 892458d6..b2130222 100644 --- a/src/static/site6.css +++ b/src/static/site6.css @@ -473,37 +473,55 @@ a:not([href]):hover { white-space: nowrap; } -.contribution { +.contribution.has-tooltip, +.datetimestamp.has-tooltip { position: relative; } -.contribution.has-tooltip > a { +.contribution.has-tooltip > a, +.datetimestamp.has-tooltip > time { text-decoration: underline; text-decoration-style: dotted; } -.contribution.has-tooltip > a:hover, -.contribution.has-tooltip > a.has-visible-tooltip { - text-decoration-style: wavy !important; +.datetimestamp.has-tooltip > time { + cursor: default; } -.icons { - font-style: normal; - white-space: nowrap; +.contribution.has-tooltip > a:hover, +.contribution.has-tooltip > a.has-visible-tooltip, +.datetimestamp.has-tooltip > time:hover, +.datetimestamp.has-tooltip > time.has-visible-tooltip { + text-decoration-style: wavy !important; } -.icons-tooltip { +.icons-tooltip, +.datetimestamp-tooltip { position: absolute; z-index: 3; left: -34px; top: calc(1em + 1px); - padding: 3px 6px 6px 6px; display: none; } -.icons-tooltip-content { +.icons-tooltip { + padding: 3px 6px 6px 6px; + left: -34px; +} + +.datetimestamp-tooltip { + padding: 3px 4px 2px 2px; + left: -10px; +} + +li:not(:first-child:last-child) .datetimestamp-tooltip { + left: 14px; +} + +.icons-tooltip-content, +.datetimestamp-tooltip-content { display: block; - padding: 6px 2px 2px 2px; + background: var(--bg-black-color); border: 1px dotted var(--primary-color); border-radius: 6px; @@ -514,16 +532,31 @@ a:not([href]):hover { backdrop-filter: brightness(1.5) saturate(1.4) blur(4px); - -webkit-user-select: none; - user-select: none; - box-shadow: 0 3px 4px 4px #000000aa, 0 -2px 4px -2px var(--primary-color) inset; +} + +.icons-tooltip-content { + padding: 6px 2px 2px 2px; + + -webkit-user-select: none; + user-select: none; cursor: default; } +.datetimestamp-tooltip-content { + padding: 5px 6px; + white-space: nowrap; + font-size: 0.9em; +} + +.icons { + font-style: normal; + white-space: nowrap; +} + .icons a:hover { filter: brightness(1.4); } @@ -574,6 +607,10 @@ a:not([href]):hover { white-space: nowrap; } +.other-group-accent a { + color: var(--page-primary-color); +} + .content-columns { columns: 2; } diff --git a/src/strings-default.yaml b/src/strings-default.yaml index 53763dcc..c15a8f5d 100644 --- a/src/strings-default.yaml +++ b/src/strings-default.yaml @@ -129,6 +129,16 @@ count: many: "" other: "{DAYS} days" + months: + _: "{MONTHS}" + withUnit: + zero: "" + one: "{MONTHS} month" + two: "" + few: "" + many: "" + other: "{MONTHS} months" + timesReferenced: _: "{TIMES_REFERENCED}" withUnit: @@ -149,6 +159,16 @@ count: many: "" other: "used {TIMES_USED} times" + weeks: + _: "{WEEKS}" + withUnit: + zero: "" + one: "{WEEKS} week" + two: "" + few: "" + many: "" + other: "{WEEKS} weeks" + words: _: "{WORDS}" thousand: "{WORDS}k" @@ -160,6 +180,16 @@ count: many: "" other: "{WORDS} words" + years: + _: "{YEARS}" + withUnit: + zero: "" + one: "{YEARS} year" + two: "" + few: "" + many: "" + other: "{YEARS} years" + # Numerical things that aren't exactly counting, per se duration: @@ -172,6 +202,24 @@ count: _: "{MINUTES}:{SECONDS}" withUnit: "{MINUTES}:{SECONDS} minutes" + dateDuration: + earlier: "{DURATION} earlier" + later: "{DURATION} later" + same: "on the same date" + zero: "at most one day" + approximate: "about {DURATION}" + approximateEarlier: "about {DURATION} earlier" + approximateLater: "about {DURATION} later" + relativeAbsolute: "{ABSOLUTE}; {RELATIVE}" + + years: "{YEARS}" + months: "{MONTHS}" + days: "{DAYS}" + yearsMonthsDays: "{YEARS}, {MONTHS}, {DAYS}" + yearsMonths: "{YEARS}, {MONTHS}" + yearsDays: "{YEARS}, {DAYS}" + monthsDays: "{MONTHS}, {DAYS}" + fileSize: terabytes: "{TERABYTES} TB" gigabytes: "{GIGABYTES} GB" @@ -220,7 +268,10 @@ releaseInfo: alsoReleasedAs: _: "Also released as:" - item: "{TRACK} (on {ALBUM})" + + item: + _: "{TRACK} ({ALBUM})" + withYear: "({YEAR}) {TRACK} ({ALBUM})" tracksReferenced: "Tracks that {TRACK} references:" tracksThatReference: "Tracks that reference {TRACK}:" @@ -1027,10 +1078,20 @@ groupInfoPage: title: "Albums" item: - _: "({YEAR}) {ALBUM}" - withoutYear: "{ALBUM}" - withAccent: "{ITEM} {ACCENT}" - otherGroupAccent: "(from {GROUP})" + _: >- + {ALBUM} + + withYear: >- + {YEAR_ACCENT} {ALBUM} + + withOtherGroup: >- + {ALBUM} {OTHER_GROUP_ACCENT} + + withYear.withOtherGroup: >- + {YEAR_ACCENT} {ALBUM} {OTHER_GROUP_ACCENT} + + yearAccent: "({YEAR})" + otherGroupAccent: "(from {GROUP})" # # groupGalleryPage: |