{notifications.map((notification) => {
const isRead = notification.displayAsRead || readIds.includes(notification.id)
+ const isDeleting = deletingIds.includes(notification.id)
return (
{getTranslatedNotification(notification, t)}
@@ -122,6 +137,7 @@ export const NotificationsSection = ({ notificationRepository }: NotificationsSe
}}
aria-label={t('notifications.dismiss')}
data-testid={`dismiss-notification-${notification.id}`}
+ disabled={isDeleting}
/>
)
diff --git a/src/sections/layout/Layout.tsx b/src/sections/layout/Layout.tsx
index 5833d63cc..8fc1d3f07 100644
--- a/src/sections/layout/Layout.tsx
+++ b/src/sections/layout/Layout.tsx
@@ -1,17 +1,25 @@
import DOMPurify from 'dompurify'
import { Outlet } from 'react-router-dom'
import { Container } from '@iqss/dataverse-design-system'
+import { useTranslation } from 'react-i18next'
import styles from './Layout.module.scss'
import { FooterFactory } from './footer/FooterFactory'
import TopBarProgressIndicator from './topbar-progress-indicator/TopbarProgressIndicator'
import { HeaderFactory } from './header/HeaderFactory'
import { HistoryTrackerProvider } from '@/router/HistoryTrackerProvider'
import { requireAppConfig } from '@/config'
+import type { AppConfig } from '@/config'
export function Layout() {
- const { bannerMessage } = requireAppConfig()
- const sanitizedBannerMessage = bannerMessage
- ? DOMPurify.sanitize(bannerMessage, { USE_PROFILES: { html: true } })
+ const { i18n } = useTranslation()
+ const { bannerMessage, defaultLanguage } = requireAppConfig()
+ const localizedBannerMessage = getLocalizedBannerMessage(
+ bannerMessage,
+ i18n.resolvedLanguage ?? i18n.language,
+ defaultLanguage
+ )
+ const sanitizedBannerMessage = localizedBannerMessage
+ ? DOMPurify.sanitize(localizedBannerMessage, { USE_PROFILES: { html: true } })
: null
return (
@@ -34,3 +42,29 @@ export function Layout() {
)
}
+
+function getLocalizedBannerMessage(
+ bannerMessage: AppConfig['bannerMessage'],
+ selectedLanguage: string | undefined,
+ defaultLanguage: string
+): string | undefined {
+ if (!bannerMessage || typeof bannerMessage === 'string') return bannerMessage
+
+ const normalizedMessages = Object.fromEntries(
+ Object.entries(bannerMessage).map(([language, message]) => [language.toLowerCase(), message])
+ )
+ const selectedLanguageCode = selectedLanguage?.toLowerCase()
+ const defaultLanguageCode = defaultLanguage.toLowerCase()
+ const candidateLanguages = [
+ selectedLanguageCode,
+ selectedLanguageCode?.split('-')[0],
+ defaultLanguageCode,
+ defaultLanguageCode.split('-')[0]
+ ].filter((language): language is string => Boolean(language))
+
+ for (const language of candidateLanguages) {
+ if (normalizedMessages[language]) return normalizedMessages[language]
+ }
+
+ return Object.values(bannerMessage)[0]
+}
diff --git a/tests/component/sections/layout/Layout.spec.tsx b/tests/component/sections/layout/Layout.spec.tsx
index 591349ef5..75196c568 100644
--- a/tests/component/sections/layout/Layout.spec.tsx
+++ b/tests/component/sections/layout/Layout.spec.tsx
@@ -4,6 +4,7 @@ import { FooterMother } from './footer/FooterMother'
import { Layout } from '../../../../src/sections/layout/Layout'
import { applyTestAppConfig } from '../../../support/bootstrapAppConfig'
import type { AppConfig } from '@/config'
+import i18next from '@/i18n'
describe('Layout', () => {
const sandbox: SinonSandbox = createSandbox()
@@ -17,6 +18,8 @@ describe('Layout', () => {
sandbox.restore()
Cypress.env('bannerMessage', defaultBannerMessageEnv)
applyTestAppConfig()
+ cy.clearAllLocalStorage()
+ cy.wrap(i18next.changeLanguage('en'))
})
it('renders the header', () => {
@@ -60,4 +63,41 @@ describe('Layout', () => {
cy.get('script').should('not.exist')
})
})
+
+ it('renders the banner message for the selected header language', () => {
+ Cypress.env('bannerMessage', {
+ en: 'English
banner',
+ es: 'Banner en español
moderno'
+ })
+ applyTestAppConfig()
+
+ cy.customMount(
)
+
+ cy.findByRole('alert').within(() => {
+ cy.findByText('English', { exact: false }).should('exist')
+ cy.findByText('Banner en español', { exact: false }).should('not.exist')
+ })
+
+ cy.findByRole('button', { name: 'Toggle navigation' }).click()
+ cy.get('#language-switcher-dropdown').click()
+ cy.findByText('Español').click()
+
+ cy.findByRole('alert').within(() => {
+ cy.findByText('Banner en español', { exact: false }).should('exist')
+ cy.get('strong').should('contain.text', 'moderno')
+ cy.findByText('English', { exact: false }).should('not.exist')
+ })
+ })
+
+ it('falls back to the default language banner when the selected language is not configured', () => {
+ Cypress.env('bannerMessage', {
+ en: 'Default language banner'
+ })
+ applyTestAppConfig()
+
+ cy.wrap(i18next.changeLanguage('es'))
+ cy.customMount(
)
+
+ cy.findByRole('alert').should('contain.text', 'Default language banner')
+ })
})