From 7d6b072276f28d72f8e1b4a2cbdc90fb5b467bf8 Mon Sep 17 00:00:00 2001 From: Amad Ul Hassan Date: Fri, 5 Jun 2026 13:43:46 +0200 Subject: [PATCH] Accessibility existing issues all (ufal/dspace-angular#139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add lang attributes to description fields Set HTML lang attributes based on metadata language for various description and metadata display elements to improve i18n and accessibility. Updated templates to bind [attr.lang] on spans, links and browse links; metadata-values now passes mdValue.language into render templates; clarin description component now emits per-entry language and value pairs; ClarinItemBoxView stores itemDescriptionLang; SidebarSearchListElement supports descriptionLang with a getDescriptionLang() hook and OrgUnit implementation returns the description language. These changes ensure displayed metadata uses the correct language attribute when available. * Improve accessibility: add ARIA labels & i18n keys Add ARIA attributes and move icon markup to improve screen-reader support across several components. Updated templates to include aria-label on interactive buttons (info, calendar, remove/save/delete/clear actions) and aria-hidden on decorative icons. Adjusted calendar button markup to place the calendar icon inside the button element. Added corresponding i18n keys in many locale JSON5 files so the new labels are translatable (English provided and placeholder entries added across locales; some locales include TODO notes for translation). These changes are focused on accessibility and localization support. * Improve accessibility and semantic headings Replace several presentational heading tags with semantically appropriate heading levels (convert h4/h3/h5/h6 to h2/h3 with existing styling classes) across home, footer and item templates to improve document structure. Add aria-hidden to the hidden repository link and aria-live/aria-atomic to the pagination info for better accessibility. Update footer markup to group links into separate ULs (removing BRs) and adjust SCSS selectors to target both heading elements and .h4 class, plus spacing for stacked lists. Also add TranslateModule.forRoot() to an existing-relation-list-element spec to satisfy translations in tests. * Update cs translations: relation group, license Replace English strings with Czech translations in src/assets/i18n/cs.json5 for the following keys: form.relation-group.save, form.relation-group.delete, form.relation-group.clear, and submission.cc-license.field-info. Improves localization for relation-group actions and the CC license field. * Mark decorative paperclip icon aria-hidden Accessibility tweak: add aria-hidden="true" to the Font Awesome paperclip icon so screen readers ignore the decorative icon. Also replace the non-breaking space inside the tag with a regular space between the icon and the heading text in clarin-files-section.component.html. * Normalize metadata language to BCP 47 for HTML lang attributes PR ufal/dspace-angular#139 binds [attr.lang] straight from the DSpace metadata language field, which is stored as Java-style locales (en_US, cs_CZ) or the wildcard *. None of those are valid BCP 47 / HTML lang values, so assistive technology ignores them and the accessibility improvement is inert for the common stored values. Add a single shared metadataLangToBcp47() helper (*/empty/nullish -> null, "_" -> "-") and a thin dsLang pipe that delegates to it. Route all of PR #139's lang bindings through it: the pipe in the seven templates, the helper directly in the three .ts sites. Declare DsLangPipe in the specs that render the pipe (NO_ERRORS_SCHEMA does not suppress missing pipes), including the shared grid element test factory. Add unit specs for the helper and pipe plus a DOM assertion that en_US renders as lang="en-US". * Translate remaining English strings to Czech in cs.json5 --------- Co-authored-by: Ondřej Košarko Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> (cherry picked from commit cd1c6174bec756970e1240ecdfb1c9006cfe443a) --- .../clarin-navbar-top.component.html | 2 +- ...-search-result-grid-element.component.html | 2 +- ...-search-result-grid-element.component.html | 2 +- ...-search-result-grid-element.component.html | 2 +- ...-search-result-list-element.component.html | 2 +- ...arch-result-list-element.component.spec.ts | 5 ++-- ...t-sidebar-search-list-element.component.ts | 8 +++++ ...-item-metadata-list-element.component.html | 2 +- ...em-metadata-list-element.component.spec.ts | 3 +- src/app/footer/footer.component.html | 12 ++++---- src/app/footer/footer.component.scss | 14 +++++++-- src/app/home-page/home-page.component.html | 14 ++++----- .../clarin-files-section.component.html | 2 +- .../item-delete/item-delete.component.html | 3 +- .../metadata-values.component.html | 17 ++++++----- .../metadata-values.component.spec.ts | 9 ++++++ .../metadata-values.component.ts | 10 +++++++ .../full-file-section.component.html | 4 +-- .../full-file-section.component.spec.ts | 3 +- ...arin-description-item-field.component.html | 4 ++- ...clarin-description-item-field.component.ts | 17 +++++------ .../views-downloads-statistics.component.html | 4 +-- .../access-control-array-form.component.html | 8 +++-- .../clarin-item-box-view.component.html | 2 +- .../clarin-item-box-view.component.ts | 9 +++++- ...sting-relation-list-element.component.html | 1 + ...ng-relation-list-element.component.spec.ts | 2 ++ .../dynamic-relation-group.component.html | 3 ++ ...arch-result-grid-element.component.spec.ts | 3 +- ...sidebar-search-list-element.component.html | 1 + .../sidebar-search-list-element.component.ts | 15 ++++++++++ .../pagination/pagination.component.html | 2 +- src/app/shared/shared.module.ts | 4 ++- src/app/shared/utils/ds-lang.pipe.spec.ts | 25 ++++++++++++++++ src/app/shared/utils/ds-lang.pipe.ts | 24 +++++++++++++++ .../utils/metadata-language.util.spec.ts | 30 +++++++++++++++++++ .../shared/utils/metadata-language.util.ts | 20 +++++++++++++ ...mission-section-cc-licenses.component.html | 3 +- src/assets/i18n/cs.json5 | 9 ++++++ src/assets/i18n/en.json5 | 8 +++++ 40 files changed, 252 insertions(+), 58 deletions(-) create mode 100644 src/app/shared/utils/ds-lang.pipe.spec.ts create mode 100644 src/app/shared/utils/ds-lang.pipe.ts create mode 100644 src/app/shared/utils/metadata-language.util.spec.ts create mode 100644 src/app/shared/utils/metadata-language.util.ts diff --git a/src/app/clarin-navbar-top/clarin-navbar-top.component.html b/src/app/clarin-navbar-top/clarin-navbar-top.component.html index 5b7de122232..1aa30c6ada6 100644 --- a/src/app/clarin-navbar-top/clarin-navbar-top.component.html +++ b/src/app/clarin-navbar-top/clarin-navbar-top.component.html @@ -16,7 +16,7 @@ - +
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html index ebd8c5cb6ba..b7b0ac8e340 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html @@ -31,7 +31,7 @@

- +

diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html index 698a401bba0..3730a78755c 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html @@ -35,7 +35,7 @@

- +

diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html index a5936c0585d..213ea3ea82d 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html @@ -25,7 +25,7 @@

- +

diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html index 8221a3608fa..7d3f0d0926f 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html @@ -31,7 +31,7 @@ + [innerHTML]="firstMetadataValue('dc.description')" [attr.lang]="dso.firstMetadata('dc.description')?.language | dsLang"> diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts index 9609a9582aa..42e3aa372ed 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts @@ -5,6 +5,7 @@ import { of as observableOf } from 'rxjs'; import { OrgUnitSearchResultListElementComponent } from './org-unit-search-result-list-element.component'; import { Item } from '../../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { DsLangPipe } from '../../../../../shared/utils/ds-lang.pipe'; import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service'; @@ -75,7 +76,7 @@ describe('OrgUnitSearchResultListElementComponent', () => { } } )], - declarations: [ OrgUnitSearchResultListElementComponent , TruncatePipe], + declarations: [ OrgUnitSearchResultListElementComponent , TruncatePipe, DsLangPipe], providers: [ { provide: TruncatableService, useValue: {} }, { provide: DSONameService, useClass: DSONameServiceMock }, @@ -145,7 +146,7 @@ describe('OrgUnitSearchResultListElementComponent', () => { } } )], - declarations: [OrgUnitSearchResultListElementComponent, TruncatePipe], + declarations: [OrgUnitSearchResultListElementComponent, TruncatePipe, DsLangPipe], providers: [ {provide: TruncatableService, useValue: {}}, {provide: DSONameService, useClass: DSONameServiceMock}, diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts index 25ff6181b2d..24ff750cabb 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts @@ -5,6 +5,7 @@ import { ItemSearchResult } from '../../../../../shared/object-collection/shared import { Component } from '@angular/core'; import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; import { Item } from '../../../../../core/shared/item.model'; +import { metadataLangToBcp47 } from '../../../../../shared/utils/metadata-language.util'; @listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) @listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement, Context.SideBarSearchModalCurrent) @@ -24,4 +25,11 @@ export class OrgUnitSidebarSearchListElementComponent extends SidebarSearchListE getDescription(): string { return this.firstMetadataValue('dc.description'); } + + /** + * Get the language of the Org Unit description. + */ + getDescriptionLang(): string | null { + return metadataLangToBcp47(this.dso.firstMetadata('dc.description')?.language); + } } diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html index ec4dbd43236..f7eb2692ac0 100644 --- a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html +++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html @@ -1,7 +1,7 @@ - + diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts index 429f2986b94..2099ea96da5 100644 --- a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts @@ -8,6 +8,7 @@ import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-rep import { OrgUnitItemMetadataListElementComponent } from './org-unit-item-metadata-list-element.component'; import { Item } from '../../../../core/shared/item.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; +import { DsLangPipe } from '../../../../shared/utils/ds-lang.pipe'; const description = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.'; const organisation = 'Anonymous'; @@ -24,7 +25,7 @@ describe('OrgUnitItemMetadataListElementComponent', () => { imports:[ NgbModule ], - declarations: [OrgUnitItemMetadataListElementComponent], + declarations: [OrgUnitItemMetadataListElementComponent, DsLangPipe], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(OrgUnitItemMetadataListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } diff --git a/src/app/footer/footer.component.html b/src/app/footer/footer.component.html index 4f77afe7b88..6230ba2e434 100644 --- a/src/app/footer/footer.component.html +++ b/src/app/footer/footer.component.html @@ -2,25 +2,27 @@