Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 190ecd5880 | |||
| b3f26469c8 | |||
| d5c53c7dd4 | |||
| f43ac2e4eb | |||
| ea5dd5bc0e | |||
| 86427fa2b7 | |||
| 3959c3657c | |||
| 191f8abbcc | |||
| d91f8bb6e1 | |||
| d612f9b26b | |||
| 042be17cfa | |||
| d00f4fa695 |
+14
-5
@@ -8,14 +8,19 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.10.0] - 2026-03-05
|
||||
### Changed
|
||||
|
||||
- ♿️(frontend) Caption text size setting for accessibility #1062
|
||||
- ♿️(frontend) sync html lang attribute with i18n for screen readers #1111
|
||||
- ♿️(frontend) improve MoreLink a11y and UX on home page #1112
|
||||
- ♿(frontend) improve chat toast a11y for screen readers #1109
|
||||
- ♿(frontend) improve ui and qria labels for help article links #1108
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🩹(frontend) remove incorrect reference to ProConnect on the prejoin #1080
|
||||
- ✨(frontend) add Ctrl+Shift+/ to open shortcuts settings #1050
|
||||
- ♿(frontend) announce selected state to screen readers #1081
|
||||
- 💄(frontend) truncate long names with ellipsis in reaction overlay #1099
|
||||
- 🐛(frontend) fix hand icon and queue position aligment and position #1119
|
||||
|
||||
## [1.10.0] - 2026-03-05
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -30,6 +35,10 @@ and this project adheres to
|
||||
- 💄(frontend) truncate pinned participant name with ellipsis on overflow #1056
|
||||
- ♿(frontend) prevent focus ring clipping on invite dialog #1078
|
||||
- ♿(frontend) dynamic tab title when connected to meeting #1060
|
||||
- 🩹(frontend) remove incorrect reference to ProConnect on the prejoin #1080
|
||||
- ✨(frontend) add Ctrl+Shift+/ to open shortcuts settings #1050
|
||||
- ♿(frontend) announce selected state to screen readers #1081
|
||||
- 💄(frontend) truncate long names with ellipsis in reaction overlay #1099
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ docker_build(
|
||||
'localhost:5001/meet-backend:latest',
|
||||
context='..',
|
||||
dockerfile='../Dockerfile',
|
||||
build_args={'DOCKER_USER': '1001:127'},
|
||||
only=['./src/backend', './src/mail', './docker'],
|
||||
target = 'backend-production',
|
||||
live_update=[
|
||||
@@ -34,7 +33,6 @@ clean_old_images('localhost:5001/meet-backend')
|
||||
docker_build(
|
||||
'localhost:5001/meet-frontend-dinum:latest',
|
||||
context='..',
|
||||
build_args={'DOCKER_USER': '1001:127'},
|
||||
dockerfile='../docker/dinum-frontend/Dockerfile',
|
||||
only=['./src/frontend', './docker', './.dockerignore'],
|
||||
target = 'frontend-production',
|
||||
@@ -59,7 +57,6 @@ clean_old_images('localhost:5001/meet-frontend-generic')
|
||||
docker_build(
|
||||
'localhost:5001/meet-summary:latest',
|
||||
context='../src/summary',
|
||||
build_args={'DOCKER_USER': '1001:127'},
|
||||
dockerfile='../src/summary/Dockerfile',
|
||||
only=['.'],
|
||||
target = 'production',
|
||||
@@ -72,7 +69,6 @@ clean_old_images('localhost:5001/meet-summary')
|
||||
docker_build(
|
||||
'localhost:5001/meet-agents:latest',
|
||||
context='../src/agents',
|
||||
build_args={'DOCKER_USER': '1001:127'},
|
||||
dockerfile='../src/agents/Dockerfile',
|
||||
only=['.'],
|
||||
target = 'production',
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Suspense } from 'react'
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
||||
import { QueryClientProvider } from '@tanstack/react-query'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLang, useTitle } from 'hoofd'
|
||||
import { useTitle } from 'hoofd'
|
||||
import { Switch, Route } from 'wouter'
|
||||
import { I18nProvider } from 'react-aria-components'
|
||||
import { Layout } from './layout/Layout'
|
||||
@@ -17,7 +17,6 @@ import { useIsSdkContext } from '@/features/sdk/hooks/useIsSdkContext'
|
||||
|
||||
function App() {
|
||||
const { i18n } = useTranslation()
|
||||
useLang(i18n.language)
|
||||
useTitle(import.meta.env.VITE_APP_TITLE ?? '')
|
||||
|
||||
const isSDKContext = useIsSdkContext()
|
||||
|
||||
@@ -2,23 +2,25 @@ import { A, Text } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
|
||||
const appTitle = import.meta.env.VITE_APP_TITLE ?? 'LaSuite Meet'
|
||||
|
||||
export const MoreLink = () => {
|
||||
const { t } = useTranslation('home')
|
||||
const { data } = useConfig()
|
||||
|
||||
if (!data?.manifest_link) return
|
||||
if (!data?.manifest_link) return null
|
||||
|
||||
return (
|
||||
<Text as={'p'} variant={'sm'} style={{ padding: '1rem 0' }}>
|
||||
<Text as="p" variant="sm" style={{ padding: '1rem 0' }}>
|
||||
<A
|
||||
href={data?.manifest_link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label={t('moreLinkLabel')}
|
||||
externalIcon
|
||||
aria-label={t('moreLinkLabel', { appTitle })}
|
||||
>
|
||||
{t('moreLink')}
|
||||
</A>{' '}
|
||||
{t('moreAbout', { appTitle: `${import.meta.env.VITE_APP_TITLE}` })}
|
||||
{t('moreLink')} {t('moreAbout', { appTitle })}
|
||||
</A>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -258,23 +258,10 @@ export const Home = () => {
|
||||
</DialogTrigger>
|
||||
</div>
|
||||
<Separator />
|
||||
<div
|
||||
className={css({
|
||||
display: { base: 'none', lg: 'inline' },
|
||||
})}
|
||||
>
|
||||
<MoreLink />
|
||||
</div>
|
||||
<MoreLink />
|
||||
</LeftColumn>
|
||||
<RightColumn>
|
||||
<IntroSlider />
|
||||
<div
|
||||
className={css({
|
||||
display: { base: 'inline', lg: 'none' },
|
||||
})}
|
||||
>
|
||||
<MoreLink />
|
||||
</div>
|
||||
</RightColumn>
|
||||
</Columns>
|
||||
<LaterMeetingDialog
|
||||
|
||||
@@ -18,10 +18,15 @@ import {
|
||||
ANIMATION_DURATION,
|
||||
ReactionPortals,
|
||||
} from '@/features/rooms/livekit/components/ReactionPortal'
|
||||
import { layoutStore } from '@/stores/layout'
|
||||
import { PanelId } from '@/features/rooms/livekit/hooks/useSidePanel'
|
||||
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
|
||||
|
||||
export const MainNotificationToast = () => {
|
||||
const room = useRoomContext()
|
||||
const { triggerNotificationSound } = useNotificationSound()
|
||||
const { t } = useTranslation('notifications')
|
||||
const announce = useScreenReaderAnnounce()
|
||||
|
||||
const [reactions, setReactions] = useState<Reaction[]>([])
|
||||
const instanceIdRef = useRef(0)
|
||||
@@ -41,12 +46,21 @@ export const MainNotificationToast = () => {
|
||||
},
|
||||
{ timeout: NotificationDuration.MESSAGE }
|
||||
)
|
||||
if (layoutStore.activePanelId !== PanelId.CHAT) {
|
||||
announce(
|
||||
t('chatMessageReceived', {
|
||||
name: participant.name || t('defaultName'),
|
||||
message: chatMessage.message,
|
||||
}),
|
||||
'polite'
|
||||
)
|
||||
}
|
||||
}
|
||||
room.on(RoomEvent.ChatMessage, handleChatMessage)
|
||||
return () => {
|
||||
room.off(RoomEvent.ChatMessage, handleChatMessage)
|
||||
}
|
||||
}, [room, triggerNotificationSound])
|
||||
}, [room, triggerNotificationSound, announce, t])
|
||||
|
||||
const handleEmoji = (emoji: string, participant: Participant) => {
|
||||
if (!emoji || !Object.values(Emoji).includes(emoji as Emoji)) return
|
||||
|
||||
@@ -79,11 +79,20 @@ export const NoAccessView = ({
|
||||
})}
|
||||
>
|
||||
{t(`${i18nKey}.body`)}
|
||||
<br />
|
||||
{helpArticle && (
|
||||
<A href={helpArticle} target="_blank">
|
||||
{t(`${i18nKey}.linkMore`)}
|
||||
</A>
|
||||
<>
|
||||
{' '}
|
||||
<A
|
||||
href={helpArticle}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
externalIcon
|
||||
color="note"
|
||||
aria-label={t(`${i18nKey}.linkAriaLabel`)}
|
||||
>
|
||||
{t(`${i18nKey}.linkMore`)}
|
||||
</A>
|
||||
</>
|
||||
)}
|
||||
</Text>
|
||||
</VStack>
|
||||
|
||||
@@ -151,12 +151,16 @@ export const ScreenRecordingSidePanel = () => {
|
||||
</H>
|
||||
<Text variant="body" fullWidth>
|
||||
{recordingMaxDuration
|
||||
? t('body', {
|
||||
max_duration: recordingMaxDuration,
|
||||
})
|
||||
? t('body', { max_duration: recordingMaxDuration })
|
||||
: t('bodyWithoutMaxDuration')}{' '}
|
||||
{data?.support?.help_article_recording && (
|
||||
<A href={data.support.help_article_recording} target="_blank">
|
||||
<A
|
||||
href={data.support.help_article_recording}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
externalIcon
|
||||
aria-label={t('linkAriaLabel')}
|
||||
>
|
||||
{t('linkMore')}
|
||||
</A>
|
||||
)}
|
||||
|
||||
@@ -187,12 +187,16 @@ export const TranscriptSidePanel = () => {
|
||||
</H>
|
||||
<Text variant="body" fullWidth>
|
||||
{recordingMaxDuration
|
||||
? t('body', {
|
||||
max_duration: recordingMaxDuration,
|
||||
})
|
||||
? t('body', { max_duration: recordingMaxDuration })
|
||||
: t('bodyWithoutMaxDuration')}{' '}
|
||||
{data?.support?.help_article_transcript && (
|
||||
<A href={data.support.help_article_transcript} target="_blank">
|
||||
<A
|
||||
href={data.support.help_article_transcript}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
externalIcon
|
||||
aria-label={t('linkAriaLabel')}
|
||||
>
|
||||
{t('linkMore')}
|
||||
</A>
|
||||
)}
|
||||
@@ -208,6 +212,7 @@ export const TranscriptSidePanel = () => {
|
||||
href={data.transcription_destination}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
externalIcon
|
||||
>
|
||||
{data.transcription_destination.replace('https://', '')}
|
||||
</A>
|
||||
|
||||
@@ -183,7 +183,13 @@ export const ParticipantTile: (
|
||||
}}
|
||||
>
|
||||
{isHandRaised && !isScreenShare && (
|
||||
<span>
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.1rem',
|
||||
}}
|
||||
>
|
||||
<span>{positionInQueue}</span>
|
||||
<RiHand
|
||||
color="black"
|
||||
|
||||
@@ -148,17 +148,22 @@ export const Tools = () => {
|
||||
className={css({
|
||||
textStyle: 'sm',
|
||||
paddingX: '0.75rem',
|
||||
paddingTop: '0.25rem',
|
||||
marginBottom: '1rem',
|
||||
})}
|
||||
>
|
||||
{t('body')}{' '}
|
||||
{data?.support?.help_article_more_tools && (
|
||||
<>
|
||||
<A href={data?.support?.help_article_more_tools} target="_blank">
|
||||
{t('moreLink')}
|
||||
</A>
|
||||
.
|
||||
</>
|
||||
<A
|
||||
href={data.support.help_article_more_tools}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
externalIcon
|
||||
color="note"
|
||||
aria-label={t('linkAriaLabel')}
|
||||
>
|
||||
{t('moreLink')}
|
||||
</A>
|
||||
)}
|
||||
</Text>
|
||||
{isTranscriptEnabled && (
|
||||
|
||||
@@ -151,7 +151,12 @@ export function Chat({ ...props }: ChatProps) {
|
||||
minHeight={0}
|
||||
overflowY="scroll"
|
||||
>
|
||||
<ul className="lk-list lk-chat-messages" ref={ulRef}>
|
||||
<ul
|
||||
className="lk-list lk-chat-messages"
|
||||
ref={ulRef}
|
||||
role="log"
|
||||
aria-relevant="additions"
|
||||
>
|
||||
{renderedMessages}
|
||||
</ul>
|
||||
</Div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { css } from '@/styled-system/css'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { accessibilityStore } from '@/stores/accessibility'
|
||||
import { CaptionsSettings } from '@/features/subtitle/component/CaptionsSettings'
|
||||
|
||||
export type AccessibilityTabProps = Pick<TabPanelProps, 'id'>
|
||||
|
||||
@@ -32,6 +33,7 @@ export const AccessibilityTab = ({ id }: AccessibilityTabProps) => {
|
||||
wrapperProps={{ noMargin: true, fullWidth: true }}
|
||||
/>
|
||||
</li>
|
||||
<CaptionsSettings />
|
||||
</ul>
|
||||
</TabPanel>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Field, H } from '@/primitives'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import {
|
||||
accessibilityStore,
|
||||
type CaptionTextSize,
|
||||
CAPTION_TEXT_SIZE_OPTIONS,
|
||||
} from '@/stores/accessibility'
|
||||
|
||||
export const CaptionsSettings = () => {
|
||||
const { t } = useTranslation('settings', {
|
||||
keyPrefix: 'accessibility.captions',
|
||||
})
|
||||
const snap = useSnapshot(accessibilityStore)
|
||||
|
||||
const captionTextSizeItems = useMemo(
|
||||
() =>
|
||||
CAPTION_TEXT_SIZE_OPTIONS.map((size) => ({
|
||||
value: size,
|
||||
label: t(`textSize.options.${size}`),
|
||||
})),
|
||||
[t]
|
||||
)
|
||||
|
||||
return (
|
||||
<li>
|
||||
<H
|
||||
lvl={3}
|
||||
className={css({
|
||||
marginBottom: '0.5rem',
|
||||
})}
|
||||
>
|
||||
{t('heading')}
|
||||
</H>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('textSize.label')}
|
||||
items={captionTextSizeItems}
|
||||
selectedKey={snap.captionTextSize}
|
||||
onSelectionChange={(key) => {
|
||||
accessibilityStore.captionTextSize = key as CaptionTextSize
|
||||
}}
|
||||
wrapperProps={{ noMargin: true, fullWidth: true }}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -8,6 +8,25 @@ import { useRoomContext } from '@livekit/components-react'
|
||||
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
||||
import { getParticipantName } from '@/features/rooms/utils/getParticipantName'
|
||||
import { Participant, RoomEvent } from 'livekit-client'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import {
|
||||
accessibilityStore,
|
||||
CAPTION_TEXT_SIZE_OPTIONS,
|
||||
type CaptionTextSize,
|
||||
} from '@/stores/accessibility'
|
||||
|
||||
const FONT_SIZE_CONFIG: Record<
|
||||
CaptionTextSize,
|
||||
{ fontSize: string; lineHeight: string }
|
||||
> = {
|
||||
small: { fontSize: '0.875rem', lineHeight: '1.2rem' },
|
||||
medium: { fontSize: '1.5rem', lineHeight: '1.7rem' },
|
||||
large: { fontSize: '2.25rem', lineHeight: '2.5rem' },
|
||||
}
|
||||
|
||||
const CAPTION_FONT_SIZES = Object.fromEntries(
|
||||
CAPTION_TEXT_SIZE_OPTIONS.map((size) => [size, FONT_SIZE_CONFIG[size]])
|
||||
) as Record<CaptionTextSize, { fontSize: string; lineHeight: string }>
|
||||
|
||||
export interface TranscriptionSegment {
|
||||
id: string
|
||||
@@ -73,8 +92,10 @@ const useTranscriptionState = () => {
|
||||
}
|
||||
|
||||
const Transcription = ({ row }: { row: TranscriptionRow }) => {
|
||||
const { captionTextSize } = useSnapshot(accessibilityStore)
|
||||
const participantColor = getParticipantColor(row.participant)
|
||||
const participantName = getParticipantName(row.participant)
|
||||
const { fontSize, lineHeight } = CAPTION_FONT_SIZES[captionTextSize]
|
||||
|
||||
const getDisplayText = (row: TranscriptionRow): string => {
|
||||
return row.segments
|
||||
@@ -116,10 +137,9 @@ const Transcription = ({ row }: { row: TranscriptionRow }) => {
|
||||
</Text>
|
||||
<p
|
||||
className={css({
|
||||
fontSize: '1.5rem',
|
||||
lineHeight: '1.7rem',
|
||||
fontWeight: '400',
|
||||
})}
|
||||
style={{ fontSize, lineHeight }}
|
||||
>
|
||||
{displayText}
|
||||
</p>
|
||||
@@ -198,7 +218,6 @@ export const Subtitles = () => {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return rows
|
||||
}, [transcriptionSegments])
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import resourcesToBackend from 'i18next-resources-to-backend'
|
||||
import { initReactI18next } from 'react-i18next'
|
||||
import LanguageDetector from 'i18next-browser-languagedetector'
|
||||
const i18nDefaultNamespace = 'global'
|
||||
const fallbackLng = 'fr'
|
||||
|
||||
i18n.setDefaultNamespace(i18nDefaultNamespace)
|
||||
i18n
|
||||
@@ -15,7 +16,7 @@ i18n
|
||||
.use(LanguageDetector)
|
||||
.init({
|
||||
supportedLngs: ['en', 'fr', 'nl', 'de'],
|
||||
fallbackLng: 'fr',
|
||||
fallbackLng,
|
||||
ns: i18nDefaultNamespace,
|
||||
detection: {
|
||||
order: ['localStorage', 'navigator'],
|
||||
@@ -24,3 +25,10 @@ i18n
|
||||
escapeValue: false,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
document.documentElement.setAttribute('lang', i18n.language || fallbackLng)
|
||||
})
|
||||
|
||||
i18n.on('languageChanged', (lang) => {
|
||||
document.documentElement.setAttribute('lang', lang)
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"joinMeetingTipContent": "Sie können einem Meeting beitreten, indem Sie den vollständigen Link in die Adressleiste Ihres Browsers einfügen.",
|
||||
"joinMeetingTipHeading": "Wussten Sie schon?",
|
||||
"loginToCreateMeeting": "Melden Sie sich an, um ein Meeting zu erstellen",
|
||||
"moreLinkLabel": "Mehr erfahren – neues Tab",
|
||||
"moreLinkLabel": "Mehr erfahren über {{appTitle}} – neues Tab",
|
||||
"moreLink": "Mehr erfahren",
|
||||
"moreAbout": "über {{appTitle}}",
|
||||
"createMenu": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"muted": "{{name}} hat dein Mikrofon stummgeschaltet. Kein Teilnehmer kann dich hören.",
|
||||
"openChat": "Chat öffnen",
|
||||
"chatMessageReceived": "{{name}} sagt: {{message}}",
|
||||
"lowerHand": {
|
||||
"auto": "Es scheint, dass du angefangen hast zu sprechen, daher wird deine Hand gesenkt.",
|
||||
"dismiss": "Hand oben lassen"
|
||||
|
||||
@@ -322,11 +322,13 @@
|
||||
"closeButton": "{{content}} ausblenden"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "Die Nachrichten sind nur für Teilnehmer zum Zeitpunkt des Sendens sichtbar. Alle Nachrichten werden am Ende des Anrufs gelöscht."
|
||||
"disclaimer": "Die Nachrichten sind nur für Teilnehmer zum Zeitpunkt des Sendens sichtbar. Alle Nachrichten werden am Ende des Anrufs gelöscht.",
|
||||
"messagesLog": "Chat-Nachrichten"
|
||||
},
|
||||
"moreTools": {
|
||||
"body": "Greifen Sie auf weitere Tools zu, um Ihre Meetings zu verbessern.",
|
||||
"moreLink": "Mehr erfahren",
|
||||
"linkAriaLabel": "Dokumentation zu den Tools öffnen - öffnet in neuem Fenster",
|
||||
"moreLink": "Dokumentation öffnen",
|
||||
"tools": {
|
||||
"transcript": {
|
||||
"title": "Transkribieren",
|
||||
@@ -370,11 +372,13 @@
|
||||
"starting": "Wird gestartet…",
|
||||
"anotherModeStarted": "Eine Aufnahme läuft. <br/> Wechseln Sie das Menü und stoppen Sie sie."
|
||||
},
|
||||
"linkMore": "Mehr erfahren",
|
||||
"linkMore": "Dokumentation öffnen",
|
||||
"linkAriaLabel": "Dokumentation zur Transkription öffnen - öffnet in neuem Fenster",
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Zugriff eingeschränkt",
|
||||
"body": "Aus Sicherheitsgründen kann nur der Ersteller oder ein Administrator des Meetings eine Transkription (Beta) starten.",
|
||||
"linkMore": "Mehr erfahren",
|
||||
"linkMore": "Dokumentation öffnen",
|
||||
"linkAriaLabel": "Dokumentation zum Transkriptionszugang öffnen - öffnet in neuem Fenster",
|
||||
"dividerLabel": "ODER",
|
||||
"login": {
|
||||
"heading": "Anmeldung erforderlich",
|
||||
@@ -389,7 +393,8 @@
|
||||
"premium": {
|
||||
"heading": "Premium-Funktion",
|
||||
"body": "Diese Funktion ist öffentlichen Bediensteten vorbehalten. Wenn Ihre E-Mail-Adresse nicht autorisiert ist, kontaktieren Sie bitte den Support, um Zugriff zu erhalten.",
|
||||
"linkMore": "Mehr erfahren",
|
||||
"linkMore": "Dokumentation öffnen",
|
||||
"linkAriaLabel": "Dokumentation zum Premium-Zugang öffnen - öffnet in neuem Fenster",
|
||||
"dividerLabel": "ODER",
|
||||
"login": {
|
||||
"heading": "Anmeldung erforderlich",
|
||||
@@ -406,7 +411,8 @@
|
||||
"heading": "Diesen Anruf für später aufzeichnen",
|
||||
"body": "Zeichnen Sie bis zu {{max_duration}} des Meetings auf.",
|
||||
"bodyWithoutMaxDuration": "Zeichnen Sie Ihr Meeting unbegrenzt auf.",
|
||||
"linkMore": "Mehr erfahren",
|
||||
"linkMore": "Dokumentation öffnen",
|
||||
"linkAriaLabel": "Dokumentation zur Aufzeichnung öffnen - öffnet in neuem Fenster",
|
||||
"details": {
|
||||
"receiver": "Die Aufzeichnung wird an den Organisator und die Mitorganisatoren gesendet.",
|
||||
"destination": "Diese Aufzeichnung wird vorübergehend auf unseren Servern gespeichert",
|
||||
@@ -424,7 +430,8 @@
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Zugriff eingeschränkt",
|
||||
"body": "Aus Sicherheitsgründen kann nur der Ersteller oder ein Administrator des Meetings eine Videoaufnahme (Beta) starten.",
|
||||
"linkMore": "Mehr erfahren",
|
||||
"linkMore": "Dokumentation öffnen",
|
||||
"linkAriaLabel": "Dokumentation zum Aufzeichnungszugang öffnen - öffnet in neuem Fenster",
|
||||
"dividerLabel": "ODER",
|
||||
"login": {
|
||||
"heading": "Anmeldung erforderlich",
|
||||
|
||||
@@ -116,6 +116,17 @@
|
||||
"accessibility": {
|
||||
"announceReactions": {
|
||||
"label": "Reaktionen vorlesen"
|
||||
},
|
||||
"captions": {
|
||||
"heading": "Untertitel",
|
||||
"textSize": {
|
||||
"label": "Untertitel-Schriftgröße",
|
||||
"options": {
|
||||
"small": "Klein",
|
||||
"medium": "Mittel",
|
||||
"large": "Groß"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"joinMeetingTipContent": "You can join a meeting by pasting its full link in the browser's address bar.",
|
||||
"joinMeetingTipHeading": "Did you know?",
|
||||
"loginToCreateMeeting": "Login to create a meeting",
|
||||
"moreLinkLabel": "Learn more - new tab",
|
||||
"moreLinkLabel": "Learn more about {{appTitle}} - new tab",
|
||||
"moreLink": "Learn more",
|
||||
"moreAbout": "about {{appTitle}}",
|
||||
"createMenu": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"muted": "{{name}} has muted your microphone. No participant can hear you.",
|
||||
"openChat": "Open chat",
|
||||
"chatMessageReceived": "{{name}} says: {{message}}",
|
||||
"lowerHand": {
|
||||
"auto": "It seems you have started speaking, so your hand will be lowered.",
|
||||
"dismiss": "Keep hand raised"
|
||||
|
||||
@@ -322,11 +322,13 @@
|
||||
"closeButton": "Hide {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "The messages are visible to participants only at the time they are sent. All messages are deleted at the end of the call."
|
||||
"disclaimer": "The messages are visible to participants only at the time they are sent. All messages are deleted at the end of the call.",
|
||||
"messagesLog": "Chat messages"
|
||||
},
|
||||
"moreTools": {
|
||||
"body": "Access more tools to enhance your meetings.",
|
||||
"moreLink": "Learn more",
|
||||
"linkAriaLabel": "Open documentation about tools - opens in new window",
|
||||
"moreLink": "Open documentation",
|
||||
"tools": {
|
||||
"transcript": {
|
||||
"title": "Transcribe",
|
||||
@@ -370,11 +372,13 @@
|
||||
"starting": "Starting…",
|
||||
"anotherModeStarted": "Screen recording is running. Switch panels and stop it."
|
||||
},
|
||||
"linkMore": "Learn more",
|
||||
"linkMore": "Open documentation",
|
||||
"linkAriaLabel": "Open documentation about transcription - opens in new window",
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Restricted Access",
|
||||
"body": "For security reasons, only the meeting creator or an admin can start a transcription (beta).",
|
||||
"linkMore": "Learn more",
|
||||
"linkMore": "Open documentation",
|
||||
"linkAriaLabel": "Open documentation about transcription access - opens in new window",
|
||||
"dividerLabel": "OR",
|
||||
"login": {
|
||||
"heading": "Login Required",
|
||||
@@ -389,7 +393,8 @@
|
||||
"premium": {
|
||||
"heading": "Premium feature",
|
||||
"body": "This feature is reserved for public agents. If your email address is not authorized, please contact support to get access.",
|
||||
"linkMore": "Learn more",
|
||||
"linkMore": "Open documentation",
|
||||
"linkAriaLabel": "Open documentation about premium access - opens in new window",
|
||||
"dividerLabel": "OR",
|
||||
"login": {
|
||||
"heading": "You are not logged in!",
|
||||
@@ -406,7 +411,8 @@
|
||||
"heading": "Record this call for later",
|
||||
"body": "Record up to {{max_duration}} of meeting.",
|
||||
"bodyWithoutMaxDuration": "Record your meeting without limit.",
|
||||
"linkMore": "Learn more",
|
||||
"linkMore": "Open documentation",
|
||||
"linkAriaLabel": "Open documentation about recording - opens in new window",
|
||||
"details": {
|
||||
"receiver": "The recording will be sent to the host and co-hosts.",
|
||||
"destination": "This recording will be temporarily stored on our servers",
|
||||
@@ -424,7 +430,8 @@
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Restricted Access",
|
||||
"body": "For security reasons, only the meeting creator or an admin can start a recording (beta).",
|
||||
"linkMore": "Learn more",
|
||||
"linkMore": "Open documentation",
|
||||
"linkAriaLabel": "Open documentation about recording access - opens in new window",
|
||||
"dividerLabel": "OR",
|
||||
"login": {
|
||||
"heading": "Login Required",
|
||||
|
||||
@@ -116,6 +116,17 @@
|
||||
"accessibility": {
|
||||
"announceReactions": {
|
||||
"label": "Announce reactions aloud"
|
||||
},
|
||||
"captions": {
|
||||
"heading": "Captions",
|
||||
"textSize": {
|
||||
"label": "Caption text size",
|
||||
"options": {
|
||||
"small": "Small",
|
||||
"medium": "Medium",
|
||||
"large": "Large"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"joinMeetingTipContent": "Vous pouvez rejoindre une réunion en copiant directement son lien complet dans la barre d'adresse du navigateur.",
|
||||
"joinMeetingTipHeading": "Astuce",
|
||||
"loginToCreateMeeting": "Connectez-vous pour créer une réunion",
|
||||
"moreLinkLabel": "En savoir plus - nouvelle fenêtre",
|
||||
"moreLinkLabel": "En savoir plus sur {{appTitle}} - nouvelle fenêtre",
|
||||
"moreLink": "En savoir plus",
|
||||
"moreAbout": "sur {{appTitle}}",
|
||||
"createMenu": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"muted": "{{name}} a coupé votre micro. Aucun participant ne peut l'entendre.",
|
||||
"openChat": "Ouvrir le chat",
|
||||
"chatMessageReceived": "{{name}} dit : {{message}}",
|
||||
"lowerHand": {
|
||||
"auto": "Il semblerait que vous ayez pris la parole, donc la main va être baissée.",
|
||||
"dismiss": "Laisser la main levée"
|
||||
|
||||
@@ -322,11 +322,13 @@
|
||||
"closeButton": "Masquer {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "Les messages sont visibles par les participants uniquement au moment de\nleur envoi. Tous les messages sont supprimés à la fin de l'appel."
|
||||
"disclaimer": "Les messages sont visibles par les participants uniquement au moment de\nleur envoi. Tous les messages sont supprimés à la fin de l'appel.",
|
||||
"messagesLog": "Messages du chat"
|
||||
},
|
||||
"moreTools": {
|
||||
"body": "Accèder à d'avantage d'outils pour améliorer vos réunions.",
|
||||
"moreLink": "En savoir plus",
|
||||
"body": "Accéder à davantage d'outils pour améliorer vos réunions.",
|
||||
"linkAriaLabel": "Ouvrir la documentation sur les outils - ouvre dans une nouvelle fenêtre",
|
||||
"moreLink": "Ouvrir la documentation",
|
||||
"tools": {
|
||||
"transcript": {
|
||||
"title": "Transcrire",
|
||||
@@ -370,11 +372,13 @@
|
||||
"starting": "Démarrage…",
|
||||
"anotherModeStarted": "Un enregistrement est en cours. <br/> Changez de menu et arrêtez le."
|
||||
},
|
||||
"linkMore": "En savoir plus",
|
||||
"linkMore": "Ouvrir la documentation",
|
||||
"linkAriaLabel": "Ouvrir la documentation sur la transcription - ouvre dans une nouvelle fenêtre",
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Accès restreint",
|
||||
"body": "Pour des raisons de sécurité, seul le créateur ou un administrateur de la réunion peut lancer une transcription (beta).",
|
||||
"linkMore": "En savoir plus",
|
||||
"linkMore": "Ouvrir la documentation",
|
||||
"linkAriaLabel": "Ouvrir la documentation sur l'accès à la transcription - ouvre dans une nouvelle fenêtre",
|
||||
"dividerLabel": "OU",
|
||||
"login": {
|
||||
"heading": "Connexion requise",
|
||||
@@ -389,7 +393,7 @@
|
||||
"premium": {
|
||||
"heading": "Fonctionnalité premium",
|
||||
"body": "Cette fonctionnalité est réservée aux agents publics. Si votre adresse email n’est pas autorisée, contactez le support pour obtenir l'accès.",
|
||||
"linkMore": "En savoir plus",
|
||||
"linkMore": "Ouvrir la documentation",
|
||||
"dividerLabel": "OU",
|
||||
"login": {
|
||||
"heading": "Vous n'êtes pas connecté !",
|
||||
@@ -399,14 +403,16 @@
|
||||
"heading": "Demander à l'organisateur",
|
||||
"body": "L'hôte recevra une notification et pourra démarrer la transcription pour vous.",
|
||||
"buttonLabel": "Demander"
|
||||
}
|
||||
},
|
||||
"linkAriaLabel": "Ouvrir la documentation sur l'accès premium - ouvre dans une nouvelle fenêtre"
|
||||
}
|
||||
},
|
||||
"screenRecording": {
|
||||
"heading": "Enregistrez cet appel pour plus tard",
|
||||
"body": "Enregistrez jusqu'à {{max_duration}} de réunion.",
|
||||
"bodyWithoutMaxDuration": "Enregistrez votre réunion sans limite.",
|
||||
"linkMore": "En savoir plus",
|
||||
"linkMore": "Ouvrir la documentation",
|
||||
"linkAriaLabel": "Ouvrir la documentation sur l'enregistrement - ouvre dans une nouvelle fenêtre",
|
||||
"details": {
|
||||
"receiver": "L'enregistrement sera envoyé à l'organisateur et aux coorganisateurs.",
|
||||
"destination": "Cet enregistrement sera conservé temporairement sur nos serveurs",
|
||||
@@ -424,7 +430,8 @@
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Accès restreint",
|
||||
"body": "Pour des raisons de sécurité, seul le créateur ou un administrateur de la réunion peut lancer un enregistrement (beta).",
|
||||
"linkMore": "En savoir plus",
|
||||
"linkMore": "Ouvrir la documentation",
|
||||
"linkAriaLabel": "Ouvrir la documentation sur l'accès à l'enregistrement - ouvre dans une nouvelle fenêtre",
|
||||
"dividerLabel": "OU",
|
||||
"login": {
|
||||
"heading": "Connexion requise",
|
||||
|
||||
@@ -116,6 +116,17 @@
|
||||
"accessibility": {
|
||||
"announceReactions": {
|
||||
"label": "Vocaliser les réactions"
|
||||
},
|
||||
"captions": {
|
||||
"heading": "Sous-titres",
|
||||
"textSize": {
|
||||
"label": "Taille du texte des sous-titres",
|
||||
"options": {
|
||||
"small": "Petit",
|
||||
"medium": "Moyen",
|
||||
"large": "Grand"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"joinMeetingTipContent": "U kunt deelnemen aan een vergadering door de volledige link in de adresbalk van de browser te plakken.",
|
||||
"joinMeetingTipHeading": "Wist u dat?",
|
||||
"loginToCreateMeeting": "Log in om een vergadering te maken",
|
||||
"moreLinkLabel": "Meer informatie - nieuw tabblad",
|
||||
"moreLinkLabel": "Meer informatie over {{appTitle}} - nieuw tabblad",
|
||||
"moreLink": "Meer informatie",
|
||||
"moreAbout": "over {{appTitle}}",
|
||||
"createMenu": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"muted": "{{name}} heeft uw microfoon gedempt. Deelnemers kunnen u niet horen.",
|
||||
"openChat": "Open chat",
|
||||
"chatMessageReceived": "{{name}} zegt: {{message}}",
|
||||
"lowerHand": {
|
||||
"auto": "Het lijkt erop dat u bent begonnen te spreken, dus we laten uw hand zakken.",
|
||||
"dismiss": "Houdt uw hand opgestoken"
|
||||
|
||||
@@ -322,11 +322,13 @@
|
||||
"closeButton": "Verberg {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "De berichten zijn alleen voor de deelnemers zichtbaar op het moment dat ze worden verzonden. Alle berichten worden verwijderd aan het einde van het gesprek."
|
||||
"disclaimer": "De berichten zijn alleen voor de deelnemers zichtbaar op het moment dat ze worden verzonden. Alle berichten worden verwijderd aan het einde van het gesprek.",
|
||||
"messagesLog": "Chatberichten"
|
||||
},
|
||||
"moreTools": {
|
||||
"body": "Je krijgt toegang tot meer tools om je vergaderingen te verbeteren.",
|
||||
"moreLink": "Lees meer",
|
||||
"linkAriaLabel": "Documentatie over tools openen - opent in nieuw venster",
|
||||
"moreLink": "Documentatie openen",
|
||||
"tools": {
|
||||
"transcript": {
|
||||
"title": "Transcriberen",
|
||||
@@ -370,11 +372,13 @@
|
||||
"starting": "Wordt gestart…",
|
||||
"anotherModeStarted": "Er loopt een opname. <br/> Ga naar het menu en stop deze."
|
||||
},
|
||||
"linkMore": "Meer informatie",
|
||||
"linkMore": "Documentatie openen",
|
||||
"linkAriaLabel": "Documentatie over transcriptie openen - opent in nieuw venster",
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Toegang beperkt",
|
||||
"body": "Om veiligheidsredenen kan alleen de maker of een beheerder van de vergadering een transcriptie starten (beta).",
|
||||
"linkMore": "Meer informatie",
|
||||
"linkMore": "Documentatie openen",
|
||||
"linkAriaLabel": "Documentatie over transcriptietoegang openen - opent in nieuw venster",
|
||||
"dividerLabel": "OF",
|
||||
"login": {
|
||||
"heading": "Inloggen vereist",
|
||||
@@ -389,7 +393,8 @@
|
||||
"premium": {
|
||||
"heading": "Premiumfunctie",
|
||||
"body": "Deze functie is voorbehouden aan openbare medewerkers. Als uw e-mailadres niet is toegestaan, neem dan contact op met de support om toegang te krijgen.",
|
||||
"linkMore": "Meer informatie",
|
||||
"linkMore": "Documentatie openen",
|
||||
"linkAriaLabel": "Documentatie over premiumtoegang openen - opent in nieuw venster",
|
||||
"dividerLabel": "OF",
|
||||
"login": {
|
||||
"heading": "Inloggen vereist",
|
||||
@@ -406,7 +411,8 @@
|
||||
"heading": "Neem dit gesprek op voor later",
|
||||
"body": "Neem tot {{max_duration}} van de vergadering op.",
|
||||
"bodyWithoutMaxDuration": "Neem je vergadering onbeperkt op.",
|
||||
"linkMore": "Meer informatie",
|
||||
"linkMore": "Documentatie openen",
|
||||
"linkAriaLabel": "Documentatie over opname openen - opent in nieuw venster",
|
||||
"details": {
|
||||
"receiver": "De opname wordt verzonden naar de organisator en co-organisatoren.",
|
||||
"destination": "Deze opname wordt tijdelijk op onze servers bewaard",
|
||||
@@ -424,7 +430,8 @@
|
||||
"notAdminOrOwner": {
|
||||
"heading": "Toegang beperkt",
|
||||
"body": "Om veiligheidsredenen kan alleen de maker of een beheerder van de vergadering een opname starten (beta).",
|
||||
"linkMore": "Meer informatie",
|
||||
"linkMore": "Documentatie openen",
|
||||
"linkAriaLabel": "Documentatie over opnametoegang openen - opent in nieuw venster",
|
||||
"dividerLabel": "OF",
|
||||
"login": {
|
||||
"heading": "Inloggen vereist",
|
||||
|
||||
@@ -113,12 +113,29 @@
|
||||
"label": "Taal"
|
||||
},
|
||||
"settingsButtonLabel": "Instellingen",
|
||||
"accessibility": {
|
||||
"announceReactions": {
|
||||
"label": "Reacties hardop aankondigen"
|
||||
},
|
||||
"captions": {
|
||||
"heading": "Ondertitels",
|
||||
"textSize": {
|
||||
"label": "Ondertiteltekstgrootte",
|
||||
"options": {
|
||||
"small": "Klein",
|
||||
"medium": "Gemiddeld",
|
||||
"large": "Groot"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
"account": "Profiel",
|
||||
"audio": "Audio",
|
||||
"video": "Video",
|
||||
"general": "Algemeen",
|
||||
"notifications": "Meldingen",
|
||||
"accessibility": "Toegankelijkheid",
|
||||
"transcription": "Transcriptie",
|
||||
"shortcuts": "Sneltoetsen"
|
||||
}
|
||||
|
||||
@@ -2,12 +2,22 @@ import { proxy, subscribe } from 'valtio'
|
||||
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
||||
import { deserializeToProxyMap } from '@/utils/valtio'
|
||||
|
||||
export type CaptionTextSize = 'small' | 'medium' | 'large'
|
||||
|
||||
export const CAPTION_TEXT_SIZE_OPTIONS: CaptionTextSize[] = [
|
||||
'small',
|
||||
'medium',
|
||||
'large',
|
||||
]
|
||||
|
||||
type AccessibilityState = {
|
||||
announceReactions: boolean
|
||||
captionTextSize: CaptionTextSize
|
||||
}
|
||||
|
||||
const DEFAULT_STATE: AccessibilityState = {
|
||||
announceReactions: false,
|
||||
captionTextSize: 'medium',
|
||||
}
|
||||
|
||||
function getAccessibilityState(): AccessibilityState {
|
||||
@@ -15,6 +25,10 @@ function getAccessibilityState(): AccessibilityState {
|
||||
const stored = localStorage.getItem(STORAGE_KEYS.ACCESSIBILITY)
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored)
|
||||
const validCaptionSizes = CAPTION_TEXT_SIZE_OPTIONS
|
||||
const captionTextSize = validCaptionSizes.includes(parsed.captionTextSize)
|
||||
? parsed.captionTextSize
|
||||
: DEFAULT_STATE.captionTextSize
|
||||
return {
|
||||
...DEFAULT_STATE,
|
||||
...parsed,
|
||||
@@ -22,6 +36,7 @@ function getAccessibilityState(): AccessibilityState {
|
||||
typeof parsed.announceReactions === 'boolean'
|
||||
? parsed.announceReactions
|
||||
: DEFAULT_STATE.announceReactions,
|
||||
captionTextSize,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user