diff --git a/frontend/src/assets/error_images.json b/frontend/src/assets/error_images.json
index e8ed239a5d1..f7d323810e6 100644
--- a/frontend/src/assets/error_images.json
+++ b/frontend/src/assets/error_images.json
@@ -10,7 +10,9 @@
"creator": "The British Library",
"license": "cc0",
"license_version": "1.0",
- "license_url": "https://creativecommons.org/publicdomain/zero/1.0/"
+ "license_url": "https://creativecommons.org/publicdomain/zero/1.0/",
+ "frontendMediaType": "image",
+ "attribution": "\"Depressed musician vintage drawing\" by The British Library is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/?ref=openverse."
}
},
{
@@ -23,7 +25,9 @@
"creator": "Edward Lagarde, American, 19th century",
"license": "cc0",
"license_version": "1.0",
- "license_url": "https://creativecommons.org/publicdomain/zero/1.0/"
+ "license_url": "https://creativecommons.org/publicdomain/zero/1.0/",
+ "frontendMediaType": "image",
+ "attribution": "\"Depressed musician vintage drawing\" by The British Library is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/?ref=openverse."
}
}
]
diff --git a/frontend/src/components/VErrorSection/VErrorImage.vue b/frontend/src/components/VErrorSection/VErrorImage.vue
index 3f09a47b7fc..97c3c5f8c87 100644
--- a/frontend/src/components/VErrorSection/VErrorImage.vue
+++ b/frontend/src/components/VErrorSection/VErrorImage.vue
@@ -23,7 +23,6 @@ import imageInfo from "~/assets/error_images.json"
interface ErrorImage extends AttributableMedia {
src: string
alt: string
- attribution?: string
}
/**
@@ -54,6 +53,7 @@ export default defineComponent({
alt: `errorImages.${image.id}`,
license: image.license as License,
license_version: image.license_version as LicenseVersion,
+ frontendMediaType: "image",
}
errorImage.attribution = getAttribution(errorImage, i18n)
return [errorItem.error, errorImage]
diff --git a/frontend/src/components/VMediaInfo/VCopyLicense.vue b/frontend/src/components/VMediaInfo/VCopyLicense.vue
index 66be71afd3a..9654029dde6 100644
--- a/frontend/src/components/VMediaInfo/VCopyLicense.vue
+++ b/frontend/src/components/VMediaInfo/VCopyLicense.vue
@@ -39,6 +39,18 @@
>
{{ getAttributionMarkup({ isPlaintext: true }) }}
+
+ {{ getAttributionMarkup({ isXml: true }) }}
+
@@ -55,7 +67,7 @@ import VTabs from "~/components/VTabs/VTabs.vue"
import VTab from "~/components/VTabs/VTab.vue"
import VLicenseTabPanel from "~/components/VMediaInfo/VLicenseTabPanel.vue"
-const tabs = ["rich", "html", "plain"] as const
+const tabs = ["rich", "html", "plain", "xml"] as const
export default defineComponent({
name: "VCopyLicense",
diff --git a/frontend/src/components/VMediaInfo/VLicenseTabPanel.vue b/frontend/src/components/VMediaInfo/VLicenseTabPanel.vue
index fd4a9771e2d..852fcdc7b62 100644
--- a/frontend/src/components/VMediaInfo/VLicenseTabPanel.vue
+++ b/frontend/src/components/VMediaInfo/VLicenseTabPanel.vue
@@ -36,7 +36,7 @@ export default defineComponent({
* The kind of attribution shown in the tab.
*/
tab: {
- type: String as PropType<"rich" | "html" | "plain">,
+ type: String as PropType<"rich" | "html" | "plain" | "xml">,
required: true,
},
/**
diff --git a/frontend/src/locales/scripts/en.json5 b/frontend/src/locales/scripts/en.json5
index 488b9ddc03f..523ad30ffad 100644
--- a/frontend/src/locales/scripts/en.json5
+++ b/frontend/src/locales/scripts/en.json5
@@ -801,6 +801,7 @@
plain: "Plain text",
copyText: "Copy text",
copied: "Copied!",
+ xml: "XML",
},
attribution: "This image was marked with a {link} license:",
},
diff --git a/frontend/src/types/analytics.ts b/frontend/src/types/analytics.ts
index b44a82e33be..0ba673a1e2e 100644
--- a/frontend/src/types/analytics.ts
+++ b/frontend/src/types/analytics.ts
@@ -145,7 +145,7 @@ export type Events = {
/** The unique ID of the media */
id: string
/** The format of the copied attribution */
- format: "plain" | "rich" | "html"
+ format: "plain" | "rich" | "html" | "xml"
/** The media type being searched */
mediaType: MediaType
}
diff --git a/frontend/src/utils/attribution-html.ts b/frontend/src/utils/attribution-html.ts
index 106d3b67b61..a6169c46f8c 100644
--- a/frontend/src/utils/attribution-html.ts
+++ b/frontend/src/utils/attribution-html.ts
@@ -124,6 +124,21 @@ const licenseElementImg = (licenseElement: LicenseElement): string => {
const extLink = (href: string, text: string) =>
h("a", { target: "_blank", rel: "noopener noreferrer", href }, [text])
+/**
+ * Generate a Dublin Core conforming XML attribution snippet.
+ *
+ * @param mediaItem - the media item being attributed
+ * @returns the XML markup of the attribution
+ */
+const xmlAttribution = (mediaItem: Record) =>
+ `
+ ${mediaItem.creator}
+ ${mediaItem.title}
+ ${mediaItem.attribution}
+ ${mediaItem.foreign_landing_url}
+ ${mediaItem.type}
+`
+
/* Interfaces */
/**
@@ -139,6 +154,8 @@ export type AttributableMedia = Pick<
| "license"
| "license_version"
| "license_url"
+ | "frontendMediaType"
+ | "attribution"
>
/**
@@ -148,6 +165,7 @@ export type AttributableMedia = Pick<
export interface AttributionOptions {
includeIcons?: boolean
isPlaintext?: boolean
+ isXml?: boolean
}
/* Actual util */
@@ -163,15 +181,20 @@ export interface AttributionOptions {
export const getAttribution = (
mediaItem: AttributableMedia,
i18n: VueI18n | null = null,
- { includeIcons, isPlaintext }: AttributionOptions = {
+ { includeIcons, isPlaintext, isXml }: AttributionOptions = {
isPlaintext: false,
includeIcons: true,
+ isXml: false,
}
): string => {
if (!mediaItem) {
return ""
}
+ if (isXml) {
+ isPlaintext = true
+ }
+
const isPd = isPublicDomain(mediaItem.license)
const i18nBase = "mediaDetails.reuse.credit"
@@ -248,7 +271,18 @@ export const getAttribution = (
.replace(/\s{2}/g, " ")
.trim()
- return isPlaintext
- ? attribution
- : h("p", { class: "attribution" }, [attribution])
+ if (isXml) {
+ const { frontendMediaType, ...restMediaItem } = mediaItem
+
+ const xmlAttributionParts = {
+ ...restMediaItem,
+ type: frontendMediaType === "audio" ? "Sound" : "StillImage",
+ }
+
+ return xmlAttribution(xmlAttributionParts)
+ } else if (isPlaintext) {
+ return attribution
+ } else {
+ return h("p", { class: "attribution" }, [attribution])
+ }
}
diff --git a/frontend/test/locales/ar.json b/frontend/test/locales/ar.json
index 6754a03ed51..6d7019f0533 100644
--- a/frontend/test/locales/ar.json
+++ b/frontend/test/locales/ar.json
@@ -556,7 +556,8 @@
"html": "لغة البرمجة",
"plain": "نص عادي",
"copyText": "نسخ النص",
- "copied": "نسخ!"
+ "copied": "نسخ!",
+ "xml": "XML"
},
"attribution": "تم تمييز هذه الصورة بترخيص {link}:"
},
diff --git a/frontend/test/locales/es.json b/frontend/test/locales/es.json
index ff74ea4f36e..4d19820458f 100644
--- a/frontend/test/locales/es.json
+++ b/frontend/test/locales/es.json
@@ -556,7 +556,8 @@
"html": "HTML",
"plain": "Texto sin formato",
"copyText": "Copiar el texto",
- "copied": "¡Copiado!"
+ "copied": "¡Copiado!",
+ "xml": "XML"
},
"attribution": "Esta imagen se ha marcado con una licencia {link}:"
},
diff --git a/frontend/test/storybook/visual-regression/v-media-reuse.spec.ts b/frontend/test/storybook/visual-regression/v-media-reuse.spec.ts
index 2837507e238..2d00abf125d 100644
--- a/frontend/test/storybook/visual-regression/v-media-reuse.spec.ts
+++ b/frontend/test/storybook/visual-regression/v-media-reuse.spec.ts
@@ -10,6 +10,7 @@ const tabs = [
{ id: "rich", name: "Rich Text" },
{ id: "html", name: "HTML" },
{ id: "plain", name: "Plain text" },
+ { id: "xml", name: "XML" },
]
const defaultUrl = "/iframe.html?id=components-vmediainfo-vmediareuse--default"
const pageUrl = (dir: (typeof languageDirections)[number]) =>
diff --git a/frontend/test/unit/specs/components/ImageDetails/v-copy-license.spec.js b/frontend/test/unit/specs/components/ImageDetails/v-copy-license.spec.js
index 329fb802b6e..d20f4a3f181 100644
--- a/frontend/test/unit/specs/components/ImageDetails/v-copy-license.spec.js
+++ b/frontend/test/unit/specs/components/ImageDetails/v-copy-license.spec.js
@@ -31,6 +31,6 @@ describe("VCopyLicense", () => {
it("should contain the correct contents", () => {
const { queryAllByText } = render(VCopyLicense, options)
- expect(queryAllByText(/Copy text/i)).toHaveLength(3)
+ expect(queryAllByText(/Copy text/i)).toHaveLength(4)
})
})
diff --git a/frontend/test/unit/specs/utils/attribution-html.spec.ts b/frontend/test/unit/specs/utils/attribution-html.spec.ts
index 62cded6bc44..50e5ef68e6e 100644
--- a/frontend/test/unit/specs/utils/attribution-html.spec.ts
+++ b/frontend/test/unit/specs/utils/attribution-html.spec.ts
@@ -18,6 +18,9 @@ const mediaItem: AttributableMedia = {
license: "pdm",
license_version: "1.0",
license_url: "https://license/url",
+ frontendMediaType: "image",
+ attribution:
+ '"Title" by Creator is marked with Public Domain Mark 1.0 . To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/?ref=openverse.',
}
describe("getAttribution", () => {