From ba1fa36e66ba008af6da7edff1d4033ed283b770 Mon Sep 17 00:00:00 2001 From: Felix Perron-Brault Date: Wed, 5 Jun 2024 11:21:42 -0400 Subject: [PATCH 1/3] add alt text field on atomic-result-image https://coveord.atlassian.net/browse/KIT-3243 --- .../src/lib/stencil-generated/components.ts | 4 +-- packages/atomic/src/components.d.ts | 8 ++++++ .../atomic-result-image.tsx | 28 ++++++++++++++++++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts b/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts index 21f348cd36f..dd7cc6fe25c 100644 --- a/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts +++ b/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts @@ -1226,14 +1226,14 @@ export declare interface AtomicResultIcon extends Components.AtomicResultIcon {} @ProxyCmp({ - inputs: ['fallback', 'field'] + inputs: ['fallback', 'field', 'imageAltField'] }) @Component({ selector: 'atomic-result-image', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['fallback', 'field'], + inputs: ['fallback', 'field', 'imageAltField'], }) export class AtomicResultImage { protected el: HTMLElement; diff --git a/packages/atomic/src/components.d.ts b/packages/atomic/src/components.d.ts index fd9be0da422..edffdedc8fd 100644 --- a/packages/atomic/src/components.d.ts +++ b/packages/atomic/src/components.d.ts @@ -2547,6 +2547,10 @@ export namespace Components { * The result field which the component should use. This will look for the field in the Result object first, then in the Result.raw object. It is important to include the necessary field in the `atomic-search-interface` component. */ "field": string; + /** + * The result field that contains the alt text for the image. This will look for the field in the Result object first, then in the Result.raw object If the field is not specified, or does not contain a valid value, the alt text will be set to "Image for {productName}". + */ + "imageAltField"?: string; } /** * The `atomic-result-link` component automatically transforms a search result title into a clickable link that points to the original item. @@ -7842,6 +7846,10 @@ declare namespace LocalJSX { * The result field which the component should use. This will look for the field in the Result object first, then in the Result.raw object. It is important to include the necessary field in the `atomic-search-interface` component. */ "field": string; + /** + * The result field that contains the alt text for the image. This will look for the field in the Result object first, then in the Result.raw object If the field is not specified, or does not contain a valid value, the alt text will be set to "Image for {productName}". + */ + "imageAltField"?: string; } /** * The `atomic-result-link` component automatically transforms a search result title into a clickable link that points to the original item. diff --git a/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx b/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx index 0dfc5b6e39a..6976327a9b8 100644 --- a/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx +++ b/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx @@ -27,6 +27,13 @@ export class AtomicResultImage implements InitializableComponent { */ @Prop({reflect: true}) field!: string; + /** + * The result field that contains the alt text for the image. This will look for the field in the Result object first, then in the Result.raw object + * + * If the field is not specified, or does not contain a valid value, the alt text will be set to "Image for {productName}". + */ + @Prop({reflect: true}) imageAltField?: string; + /** * An optional fallback image URL that will be used in case the specified image field is not available or encounters an error. */ @@ -42,6 +49,25 @@ export class AtomicResultImage implements InitializableComponent { return Array.isArray(value) ? value[0] : value; } + private get altText() { + if (this.imageAltField) { + const value = ResultTemplatesHelpers.getResultProperty( + this.result, + this.field + ); + + if (Array.isArray(value)) { + return value[0]; + } + + if (value !== null) { + return value; + } + } + + return `Image for ${this.result.title}`; + } + private logWarning(message: string) { this.bindings.engine.logger.warn(message, this.host); } @@ -87,7 +113,7 @@ export class AtomicResultImage implements InitializableComponent { return ( {`${this.field} this.handleImageError()} loading="lazy" From 661356f85b5771c129adce9fb593b788d8304466 Mon Sep 17 00:00:00 2001 From: Felix Perron-Brault Date: Fri, 7 Jun 2024 10:34:42 -0400 Subject: [PATCH 2/3] localize default alt text https://coveord.atlassian.net/browse/KIT-3243 --- .../atomic-product-image.tsx | 4 +- .../atomic-result-image.tsx | 10 ++- packages/atomic/src/locales.json | 77 +++++++++++++------ 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx index 76dad827127..2c67683ed15 100644 --- a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx +++ b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx @@ -141,10 +141,10 @@ export class AtomicProductImage implements InitializableComponent { } else if (typeof validImagesAlt === 'string') { altText = validImagesAlt; } else { - altText = this.bindings.i18n.t('image-alt-fallback', { + altText = this.bindings.i18n.t('image-alt-fallback-multiple', { count: index + 1, max: validImages?.length, - productName: this.product.ec_name, + itemName: this.product.ec_name, }); } diff --git a/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx b/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx index 6976327a9b8..81ed1996d5f 100644 --- a/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx +++ b/packages/atomic/src/components/search/result-template-components/atomic-result-image/atomic-result-image.tsx @@ -49,23 +49,25 @@ export class AtomicResultImage implements InitializableComponent { return Array.isArray(value) ? value[0] : value; } - private get altText() { + private get altText(): string { if (this.imageAltField) { const value = ResultTemplatesHelpers.getResultProperty( this.result, this.field ); - if (Array.isArray(value)) { + if (Array.isArray(value) && typeof value[0] === 'string') { return value[0]; } - if (value !== null) { + if (typeof value === 'string') { return value; } } - return `Image for ${this.result.title}`; + return this.bindings.i18n.t('image-alt-fallback', { + itemName: this.result.title, + }); } private logWarning(message: string) { diff --git a/packages/atomic/src/locales.json b/packages/atomic/src/locales.json index 9b8704b61d8..0628fd5ea76 100644 --- a/packages/atomic/src/locales.json +++ b/packages/atomic/src/locales.json @@ -7426,32 +7426,59 @@ "zh-CN": "可用于:", "zh-TW": "可用於:" }, + "image-alt-fallback-multiple": { + "en": "Image {{count}} out of {{max}} for {{itemName}}", + "fr": "Image {{count}} sur {{max}} pour {{itemName}}", + "cs": "Obrázek {{count}} z {{max}} pro {{itemName}}", + "da": "Billede {{count}} ud af {{max}} for {{itemName}}", + "de": "Bild {{count}} von {{max}} für {{itemName}}", + "el": "Εικόνα {{count}} από {{max}} για {{itemName}}", + "es": "Imagen {{count}} de {{max}} para {{itemName}}", + "fi": "Kuva {{count}} / {{max}} tuotteelle {{itemName}}", + "hu": "Kép {{count}} a {{max}}-ból a(z) {{itemName}} termékhez", + "id": "Gambar {{count}} dari {{max}} untuk {{itemName}}", + "it": "Immagine {{count}} su {{max}} per {{itemName}}", + "ja": "{{max}}のうちのイメージ{{count}}、{{itemName}}", + "ko": "{{max}}개 중 이미지 {{count}} for {{itemName}}", + "nl": "Afbeelding {{count}} van {{max}} voor {{itemName}}", + "no": "Bilde {{count}} av {{max}} for {{itemName}}", + "pl": "Obraz {{count}} z {{max}} dla {{itemName}}", + "pt": "Imagem {{count}} de {{max}} para {{itemName}}", + "pt-BR": "Imagem {{count}} de {{max}} para {{itemName}}", + "ru": "Изображение {{count}} из {{max}} для {{itemName}}", + "sv": "Bild {{count}} av {{max}} för {{itemName}}", + "th": "รูปภาพ {{count}} จาก {{max}} สำหรับ {{itemName}}", + "tr": "{{max}} üzerinden Resim {{count}} için {{itemName}}", + "zh": "第{{count}}张图片,共{{max}}张,适用于{{itemName}}", + "zh-CN": "第{{count}}张图片,共{{max}}张,适用于{{itemName}}", + "zh-TW": "第{{count}}張圖片,共{{max}}張,適用於{{itemName}}" + }, "image-alt-fallback": { - "en": "Image {{count}} out of {{max}} for {{productName}}", - "fr": "Image {{count}} sur {{max}} pour {{productName}}", - "cs": "Obrázek {{count}} z {{max}} pro {{productName}}", - "da": "Billede {{count}} ud af {{max}} for {{productName}}", - "de": "Bild {{count}} von {{max}} für {{productName}}", - "el": "Εικόνα {{count}} από {{max}} για {{productName}}", - "es": "Imagen {{count}} de {{max}} para {{productName}}", - "fi": "Kuva {{count}} / {{max}} tuotteelle {{productName}}", - "hu": "Kép {{count}} a {{max}}-ból a(z) {{productName}} termékhez", - "id": "Gambar {{count}} dari {{max}} untuk {{productName}}", - "it": "Immagine {{count}} su {{max}} per {{productName}}", - "ja": "{{max}}のうちのイメージ{{count}}、{{productName}}", - "ko": "{{max}}개 중 이미지 {{count}} for {{productName}}", - "nl": "Afbeelding {{count}} van {{max}} voor {{productName}}", - "no": "Bilde {{count}} av {{max}} for {{productName}}", - "pl": "Obraz {{count}} z {{max}} dla {{productName}}", - "pt": "Imagem {{count}} de {{max}} para {{productName}}", - "pt-BR": "Imagem {{count}} de {{max}} para {{productName}}", - "ru": "Изображение {{count}} из {{max}} для {{productName}}", - "sv": "Bild {{count}} av {{max}} för {{productName}}", - "th": "รูปภาพ {{count}} จาก {{max}} สำหรับ {{productName}}", - "tr": "{{max}} üzerinden Resim {{count}} için {{productName}}", - "zh": "第{{count}}张图片,共{{max}}张,适用于{{productName}}", - "zh-CN": "第{{count}}张图片,共{{max}}张,适用于{{productName}}", - "zh-TW": "第{{count}}張圖片,共{{max}}張,適用於{{productName}}" + "en": "Image for {{itemName}}", + "fr": "Image pour {{itemName}}", + "cs": "Obrázek pro {{itemName}}", + "da": "Billede for {{itemName}}", + "de": "Bild für {{itemName}}", + "el": "Εικόνα για {{itemName}}", + "es": "Imagen para {{itemName}}", + "fi": "Kuva tuotteelle {{itemName}}", + "hu": "Kép a(z) {{itemName}} termékhez", + "id": "Gambar untuk {{itemName}}", + "it": "Immagine per {{itemName}}", + "ja": "{{itemName}}の画像", + "ko": "{{itemName}}의 이미지", + "nl": "Afbeelding voor {{itemName}}", + "no": "Bilde for {{itemName}}", + "pl": "Obraz dla {{itemName}}", + "pt": "Imagem para {{itemName}}", + "pt-BR": "Imagem para {{itemName}}", + "ru": "Изображение для {{itemName}}", + "sv": "Bild för {{itemName}}", + "th": "รูปภาพสำหรับ {{itemName}}", + "tr": "{{itemName}} için resim", + "zh": "{{itemName}}的图片", + "zh-CN": "{{itemName}}的图片", + "zh-TW": "{{itemName}}的圖片" }, "image-not-found-alt": { "en": "No image available.", From fdbeacd4dfb83b6484a88bc63ec248942e6631e1 Mon Sep 17 00:00:00 2001 From: Felix Perron-Brault Date: Fri, 7 Jun 2024 14:57:03 -0400 Subject: [PATCH 3/3] rename attribute https://coveord.atlassian.net/browse/KIT-3243 --- packages/atomic/src/components.d.ts | 4 ++-- .../atomic-product-image.tsx | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/atomic/src/components.d.ts b/packages/atomic/src/components.d.ts index edffdedc8fd..e1e8f898cc2 100644 --- a/packages/atomic/src/components.d.ts +++ b/packages/atomic/src/components.d.ts @@ -1890,7 +1890,7 @@ export namespace Components { /** * The product field that contains the alt text for the images. This will look for the field in the product object first, then in the product.additionalFields object. The field can be a string or an array of strings. If the value of the field is a string, it will be used as the alt text for all the images. If the value of the field is an array of strings, the alt text will be used in the order of the images. If the field is not specified, or does not contain a valid value, the alt text will be set to "Image {index} out of {totalImages} for {productName}". */ - "imagesAltField"?: string; + "imageAltField"?: string; /** * Navigates to the specified image index. * @param index - The index of the image to navigate to. @@ -7238,7 +7238,7 @@ declare namespace LocalJSX { /** * The product field that contains the alt text for the images. This will look for the field in the product object first, then in the product.additionalFields object. The field can be a string or an array of strings. If the value of the field is a string, it will be used as the alt text for all the images. If the value of the field is an array of strings, the alt text will be used in the order of the images. If the field is not specified, or does not contain a valid value, the alt text will be set to "Image {index} out of {totalImages} for {productName}". */ - "imagesAltField"?: string; + "imageAltField"?: string; } interface AtomicProductLink { /** diff --git a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx index 2c67683ed15..774f8310859 100644 --- a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx +++ b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/atomic-product-image.tsx @@ -48,7 +48,7 @@ export class AtomicProductImage implements InitializableComponent { * * If the field is not specified, or does not contain a valid value, the alt text will be set to "Image {index} out of {totalImages} for {productName}". */ - @Prop({reflect: true}) imagesAltField?: string; + @Prop({reflect: true}) imageAltField?: string; /** * An fallback image URL that will be used in case the specified image is not available or an error is encountered. @@ -128,7 +128,7 @@ export class AtomicProductImage implements InitializableComponent { (image) => typeof image === 'string' ); - const validImagesAlt = this.imagesAlt; + const validImageAlt = this.imageAlt; this.images = validImages.map((url, index) => { const finalUrl = this.useFallback ? this.fallback : url; @@ -136,10 +136,10 @@ export class AtomicProductImage implements InitializableComponent { this.validateUrl(finalUrl); let altText; - if (Array.isArray(validImagesAlt) && validImagesAlt[index]) { - altText = validImagesAlt[index]; - } else if (typeof validImagesAlt === 'string') { - altText = validImagesAlt; + if (Array.isArray(validImageAlt) && validImageAlt[index]) { + altText = validImageAlt[index]; + } else if (typeof validImageAlt === 'string') { + altText = validImageAlt; } else { altText = this.bindings.i18n.t('image-alt-fallback-multiple', { count: index + 1, @@ -164,11 +164,11 @@ export class AtomicProductImage implements InitializableComponent { return Array.isArray(value) ? value : [value]; } - private get imagesAlt() { - if (this.imagesAltField) { + private get imageAlt() { + if (this.imageAltField) { const value = ProductTemplatesHelpers.getProductProperty( this.product, - this.imagesAltField + this.imageAltField ); if (Array.isArray(value)) {