From 534f939f5aeaffccfe67270fd4b8089e4b7cda77 Mon Sep 17 00:00:00 2001 From: aptmac Date: Thu, 9 Jan 2025 13:57:10 -0500 Subject: [PATCH] feat(i18n): allow setting i18n namespaces via an environment variable (#1527) --- LOCALIZATION.md | 8 +-- src/app/About/About.tsx | 6 +- src/app/About/AboutCryostatModal.tsx | 6 +- src/app/About/AboutDescription.tsx | 4 +- src/app/Agent/AgentLiveProbes.tsx | 4 +- src/app/Agent/AgentProbeTemplates.tsx | 14 ++-- src/app/AppLayout/AppLayout.tsx | 5 +- src/app/AppLayout/ThemeToggle.tsx | 4 +- .../Archives/AllArchivedRecordingsTable.tsx | 4 +- .../AllTargetsArchivedRecordingsTable.tsx | 4 +- src/app/Dashboard/AddCard.tsx | 10 +-- .../AutomatedAnalysisCard.tsx | 14 ++-- .../AutomatedAnalysisCardList.tsx | 20 +++--- .../AutomatedAnalysisConfigDrawer.tsx | 4 +- .../AutomatedAnalysisConfigForm.tsx | 34 ++++----- .../AutomatedAnalysisFilters.tsx | 8 +-- .../ClickableAutomatedAnalysisLabel.tsx | 4 +- .../Filters/AutomatedAnalysisScoreFilter.tsx | 14 ++-- .../Charts/jfr/JFRMetricsChartCard.tsx | 5 +- .../Charts/mbean/MBeanMetricsChartCard.tsx | 4 +- src/app/Dashboard/Dashboard.tsx | 4 +- src/app/Dashboard/DashboardCardActionMenu.tsx | 8 +-- .../Dashboard/DashboardLayoutCreateModal.tsx | 8 +-- .../DashboardLayoutSetAsTemplateModal.tsx | 8 +-- src/app/Dashboard/DashboardLayoutToolbar.tsx | 8 +-- .../Dashboard/Diagnostics/DiagnosticsCard.tsx | 4 +- src/app/Dashboard/ErrorCard.tsx | 4 +- src/app/Dashboard/LayoutTemplateGroup.tsx | 14 ++-- src/app/Dashboard/LayoutTemplatePicker.tsx | 10 +-- .../Dashboard/LayoutTemplateUploadModal.tsx | 16 ++--- src/app/Dashboard/utils.tsx | 6 +- src/app/DateTimePicker/DateTimePicker.tsx | 10 +-- src/app/DateTimePicker/MeridiemPicker.tsx | 8 +-- src/app/DateTimePicker/TimePicker.tsx | 12 ++-- src/app/DateTimePicker/TimezonePicker.tsx | 8 +-- src/app/DateTimePicker/i18n.ts | 4 +- src/app/Events/EventTemplates.tsx | 4 +- src/app/Events/EventTypes.tsx | 4 +- src/app/NotFound/NotFound.tsx | 4 +- src/app/QuickStarts/QuickStartDrawer.tsx | 4 +- .../QuickStarts/QuickStartsCatalogPage.tsx | 4 +- .../RecordingLabelFields.tsx | 4 +- src/app/Recordings/ActiveRecordingsTable.tsx | 6 +- src/app/Recordings/Filters/DatetimeFilter.tsx | 10 +-- src/app/Recordings/Filters/DurationFilter.tsx | 8 +-- .../Filters/RecordingStateFilter.tsx | 4 +- src/app/Recordings/RecordingActions.tsx | 4 +- src/app/Recordings/RecordingFilters.tsx | 12 ++-- src/app/Rules/CreateRule.tsx | 70 +++++++------------ src/app/Rules/RuleDeleteWarningModal.tsx | 12 ++-- src/app/Rules/Rules.tsx | 35 +++++----- src/app/Rules/RulesUploadModal.tsx | 10 +-- .../Credentials/CreateCredentialModal.tsx | 13 ++-- .../Credentials/CredentialTestTable.tsx | 28 ++++---- .../Credentials/MatchedTargetsTable.tsx | 4 +- .../Credentials/StoredCredentials.tsx | 10 +-- src/app/SecurityPanel/ImportCertificate.tsx | 4 +- src/app/SecurityPanel/SecurityPanel.tsx | 4 +- src/app/Settings/Config/AutoRefresh.tsx | 4 +- src/app/Settings/Config/ChartCards.tsx | 6 +- src/app/Settings/Config/DatetimeControl.tsx | 4 +- .../Settings/Config/DeletionDialogControl.tsx | 6 +- src/app/Settings/Config/FeatureLevels.tsx | 4 +- src/app/Settings/Config/Language.tsx | 7 +- .../Settings/Config/NotificationControl.tsx | 6 +- src/app/Settings/Config/Theme.tsx | 4 +- src/app/Settings/Config/WebSocketDebounce.tsx | 6 +- src/app/Settings/Settings.tsx | 7 +- .../Shared/Components/DurationUnitSelect.tsx | 10 +-- src/app/Shared/Components/ErrorBoundary.tsx | 7 +- .../MatchExpressionDisplay.tsx | 8 +-- src/app/Shared/Components/i18n.ts | 6 +- src/app/Shared/i18n.ts | 6 +- src/app/TargetView/TargetContextSelector.tsx | 4 +- src/app/TargetView/TargetSelect.tsx | 4 +- src/app/Topology/Actions/CreateTarget.tsx | 8 +-- .../Topology/Shared/Components/Shortcuts.tsx | 4 +- src/app/Topology/Toolbar/TopologyToolbar.tsx | 4 +- src/i18n/config.ts | 25 +------ src/i18n/i18nextUtil.ts | 35 ++++++++++ src/test/About/About.test.tsx | 2 +- .../AutomatedAnalysisCard.test.tsx | 8 +-- .../AutomatedAnalysisConfigForm.test.tsx | 2 +- .../DateTimePicker/DateTimePicker.test.tsx | 6 +- .../DateTimePicker/MeridiemPicker.test.tsx | 2 +- src/test/DateTimePicker/TimePicker.test.tsx | 28 ++++---- src/test/Recordings/RecordingFilters.test.tsx | 24 +++---- src/test/Settings/FeatureLevels.test.tsx | 8 +-- src/test/Settings/Language.test.tsx | 4 +- webpack.dev.js | 3 +- webpack.prod.js | 3 +- 91 files changed, 410 insertions(+), 421 deletions(-) diff --git a/LOCALIZATION.md b/LOCALIZATION.md index ddc23bdaf..54234b446 100644 --- a/LOCALIZATION.md +++ b/LOCALIZATION.md @@ -4,17 +4,17 @@ Cryostat-web uses [i18next](https://www.i18next.com/) as an internationalization ### Adding a new translation -The current list of language locales supported in Cryostat can be found in `src/i18n/config.ts`. The translations themselves can be found in `locales/{LOCALE_CODE}` +The current list of language locales supported in Cryostat can be found in `src/i18n/i18nextUtil.ts`. The translations themselves can be found in `locales/{LOCALE_CODE}` -To add a new language, add a new entry to the `i18nResources` object in `src/i18n.ts`. The key should be the language locale, and the value should be the translation object containing the corresponding namespace json files in `locales`. +To add a new language, add a new entry to the `i18nResources` object in `src/i18nextUtil.ts`. The key should be the language locale, and the value should be the translation object containing the corresponding namespace json files in `locales`. To add a new localization key for a user-facing string in `cryostat-web`, use the `t` function from `react-i18next`: ```tsx -import { useTranslation } from 'react-i18next'; +import { useCryostatTranslation } from 'react-i18next'; ... export const SomeFC = (props) => { - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); return (
diff --git a/src/app/About/About.tsx b/src/app/About/About.tsx index a42fd7efc..7f8f7e423 100644 --- a/src/app/About/About.tsx +++ b/src/app/About/About.tsx @@ -20,15 +20,15 @@ import { BreadcrumbPage } from '@app/BreadcrumbPage/BreadcrumbPage'; import build from '@app/build.json'; import { ThemeSetting } from '@app/Settings/types'; import { useTheme } from '@app/utils/hooks/useTheme'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Brand, Card, CardBody, CardFooter, CardHeader } from '@patternfly/react-core'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { AboutDescription } from './AboutDescription'; export interface AboutProps {} export const About: React.FC = (_) => { - const { t } = useTranslation('public'); + const { t } = useCryostatTranslation(); const [theme] = useTheme(); const logo = React.useMemo(() => (theme === ThemeSetting.DARK ? cryostatLogoDark : cryostatLogo), [theme]); @@ -42,7 +42,7 @@ export const About: React.FC = (_) => { - {t('CRYOSTAT_TRADEMARK', { ns: 'common' })} + {t('CRYOSTAT_TRADEMARK')} ); diff --git a/src/app/About/AboutCryostatModal.tsx b/src/app/About/AboutCryostatModal.tsx index 7df28ccf4..13bb62e06 100644 --- a/src/app/About/AboutCryostatModal.tsx +++ b/src/app/About/AboutCryostatModal.tsx @@ -17,9 +17,9 @@ import bkgImg from '@app/assets/cryostat_icon_bg.svg'; import cryostatLogo from '@app/assets/cryostat_icon_rgb_reverse.svg'; import build from '@app/build.json'; import { portalRoot } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { AboutModal } from '@patternfly/react-core'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { AboutDescription } from './AboutDescription'; export interface AboutCryostatModalProps { @@ -28,7 +28,7 @@ export interface AboutCryostatModalProps { } export const AboutCryostatModal: React.FC = ({ isOpen, onClose }) => { - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); return ( = ({ isOpen, brandImageAlt="Cryostat Logo" isOpen={isOpen} onClose={onClose} - trademark={t('CRYOSTAT_TRADEMARK', { ns: 'common' })} + trademark={t('CRYOSTAT_TRADEMARK')} backgroundImageSrc={bkgImg} > diff --git a/src/app/About/AboutDescription.tsx b/src/app/About/AboutDescription.tsx index 8e389f4f8..7569bd0ca 100644 --- a/src/app/About/AboutDescription.tsx +++ b/src/app/About/AboutDescription.tsx @@ -19,9 +19,9 @@ import { BuildInfo } from '@app/Shared/Services/api.types'; import { NotificationsContext } from '@app/Shared/Services/Notifications.service'; import { ServiceContext } from '@app/Shared/Services/Services'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Text, TextContent, TextList, TextListItem, TextVariants } from '@patternfly/react-core'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; export const VERSION_REGEX = /^(v?[0-9]+\.[0-9]+\.[0-9]+)(?:-(.+))?$/; @@ -30,7 +30,7 @@ export const AboutDescription: React.FC = () => { const notificationsContext = React.useContext(NotificationsContext); const [cryostatVersion, setCryostatVersion] = React.useState(undefined as string | undefined); const [buildInfo, setBuildInfo] = React.useState({ git: { hash: '' } }); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const addSubscription = useSubscriptions(); React.useEffect(() => { diff --git a/src/app/Agent/AgentLiveProbes.tsx b/src/app/Agent/AgentLiveProbes.tsx index ce5c20be8..16f4537de 100644 --- a/src/app/Agent/AgentLiveProbes.tsx +++ b/src/app/Agent/AgentLiveProbes.tsx @@ -23,6 +23,7 @@ import { EventProbe, NotificationCategory } from '@app/Shared/Services/api.types import { ServiceContext } from '@app/Shared/Services/Services'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { sortResources, TableColumn } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Button, Toolbar, @@ -51,7 +52,6 @@ import { } from '@patternfly/react-table'; import _ from 'lodash'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { combineLatest } from 'rxjs'; import { AboutAgentCard } from './AboutAgentCard'; @@ -89,7 +89,7 @@ export interface AgentLiveProbesProps {} export const AgentLiveProbes: React.FC = () => { const context = React.useContext(ServiceContext); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const addSubscription = useSubscriptions(); const [probes, setProbes] = React.useState([]); diff --git a/src/app/Agent/AgentProbeTemplates.tsx b/src/app/Agent/AgentProbeTemplates.tsx index d29c86d66..c3d1681ff 100644 --- a/src/app/Agent/AgentProbeTemplates.tsx +++ b/src/app/Agent/AgentProbeTemplates.tsx @@ -23,6 +23,7 @@ import { ProbeTemplate, NotificationCategory } from '@app/Shared/Services/api.ty import { ServiceContext } from '@app/Shared/Services/Services'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { TableColumn, portalRoot, sortResources } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { ActionGroup, Button, @@ -62,7 +63,6 @@ import { } from '@patternfly/react-table'; import _ from 'lodash'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { forkJoin, Observable, of } from 'rxjs'; import { catchError, defaultIfEmpty, first, tap } from 'rxjs/operators'; import { AboutAgentCard } from './AboutAgentCard'; @@ -86,7 +86,7 @@ export interface AgentProbeTemplatesProps { export const AgentProbeTemplates: React.FC = ({ agentDetected }) => { const context = React.useContext(ServiceContext); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const addSubscription = useSubscriptions(); const [templates, setTemplates] = React.useState([]); @@ -365,7 +365,7 @@ export interface AgentProbeTemplateUploadModalProps { } export const AgentProbeTemplateUploadModal: React.FC = ({ onClose, isOpen }) => { - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const addSubscription = useSubscriptions(); const context = React.useContext(ServiceContext); const submitRef = React.useRef(null); // Use ref to refer to submit trigger div @@ -478,7 +478,7 @@ export const AgentProbeTemplateUploadModal: React.FC {allOks && numOfFiles ? ( ) : ( <> @@ -488,10 +488,10 @@ export const AgentProbeTemplateUploadModal: React.FC - {t('SUBMIT', { ns: 'common' })} + {t('SUBMIT')} )} @@ -508,7 +508,7 @@ export interface AgentTemplateActionProps { } export const AgentTemplateAction: React.FC = ({ onInsert, onDelete, template }) => { - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const [isOpen, setIsOpen] = React.useState(false); const actionItems = React.useMemo(() => { diff --git a/src/app/AppLayout/AppLayout.tsx b/src/app/AppLayout/AppLayout.tsx index a8d482ba8..fda0024d8 100644 --- a/src/app/AppLayout/AppLayout.tsx +++ b/src/app/AppLayout/AppLayout.tsx @@ -34,6 +34,7 @@ import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { useTheme } from '@app/utils/hooks/useTheme'; import { saveToLocalStorage } from '@app/utils/LocalStorage'; import { cleanDataId, isAssetNew, openTabForUrl, portalRoot } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Alert, AlertActionCloseButton, @@ -79,7 +80,7 @@ import { } from '@patternfly/react-icons'; import _ from 'lodash'; import * as React from 'react'; -import { Trans, useTranslation } from 'react-i18next'; +import { Trans } from 'react-i18next'; import { Link, matchPath, NavLink, useLocation, useNavigate } from 'react-router-dom'; import { map } from 'rxjs/operators'; import { LogoutIcon } from './LogoutIcon'; @@ -93,7 +94,7 @@ export const AppLayout: React.FC = ({ children }) => { const serviceContext = React.useContext(ServiceContext); const notificationsContext = React.useContext(NotificationsContext); const addSubscription = useSubscriptions(); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const { setState: setJoyState, state: joyState, diff --git a/src/app/AppLayout/ThemeToggle.tsx b/src/app/AppLayout/ThemeToggle.tsx index 3f8e65064..e83925779 100644 --- a/src/app/AppLayout/ThemeToggle.tsx +++ b/src/app/AppLayout/ThemeToggle.tsx @@ -17,17 +17,17 @@ import { ThemeSetting } from '@app/Settings/types'; import { ServiceContext } from '@app/Shared/Services/Services'; import { useTheme } from '@app/utils/hooks/useTheme'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Icon, ToggleGroup, ToggleGroupItem } from '@patternfly/react-core'; import { SunIcon, MoonIcon } from '@patternfly/react-icons'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; export interface ThemeToggleProps {} export const ThemeToggle: React.FC = () => { const context = React.useContext(ServiceContext); const [_theme] = useTheme(); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const handleThemeSelect = React.useCallback( (_, setting: ThemeSetting) => { diff --git a/src/app/Archives/AllArchivedRecordingsTable.tsx b/src/app/Archives/AllArchivedRecordingsTable.tsx index 8b5aa83c5..c2a16ee3a 100644 --- a/src/app/Archives/AllArchivedRecordingsTable.tsx +++ b/src/app/Archives/AllArchivedRecordingsTable.tsx @@ -22,6 +22,7 @@ import { ServiceContext } from '@app/Shared/Services/Services'; import { useSort } from '@app/utils/hooks/useSort'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { TableColumn, portalRoot, sortResources } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Toolbar, ToolbarContent, @@ -54,7 +55,6 @@ import { } from '@patternfly/react-table'; import _ from 'lodash'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { Observable, of } from 'rxjs'; import { getTargetFromDirectory, includesDirectory, indexOfDirectory } from './utils'; @@ -82,7 +82,7 @@ export interface AllArchivedRecordingsTableProps {} export const AllArchivedRecordingsTable: React.FC = () => { const context = React.useContext(ServiceContext); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const [directories, setDirectories] = React.useState<_RecordingDirectory[]>([]); const [searchText, setSearchText] = React.useState(''); diff --git a/src/app/Archives/AllTargetsArchivedRecordingsTable.tsx b/src/app/Archives/AllTargetsArchivedRecordingsTable.tsx index addd02fce..07d76be93 100644 --- a/src/app/Archives/AllTargetsArchivedRecordingsTable.tsx +++ b/src/app/Archives/AllTargetsArchivedRecordingsTable.tsx @@ -23,6 +23,7 @@ import { ServiceContext } from '@app/Shared/Services/Services'; import { useSort } from '@app/utils/hooks/useSort'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { hashCode, sortResources, TableColumn } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Toolbar, ToolbarContent, @@ -53,7 +54,6 @@ import { import { TFunction } from 'i18next'; import _ from 'lodash'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -103,7 +103,7 @@ export interface AllTargetsArchivedRecordingsTableProps {} export const AllTargetsArchivedRecordingsTable: React.FC = () => { const context = React.useContext(ServiceContext); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const [searchText, setSearchText] = React.useState(''); const [archivesForTargets, setArchivesForTargets] = React.useState([]); diff --git a/src/app/Dashboard/AddCard.tsx b/src/app/Dashboard/AddCard.tsx index 0d07c683b..6896e9bc4 100644 --- a/src/app/Dashboard/AddCard.tsx +++ b/src/app/Dashboard/AddCard.tsx @@ -21,6 +21,7 @@ import { fakeChartContext, fakeServices } from '@app/utils/fakeData'; import { useFeatureLevel } from '@app/utils/hooks/useFeatureLevel'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { portalRoot } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { CatalogTile, CatalogTileBadge } from '@patternfly/react-catalog-view-extension'; import { Bullseye, @@ -79,7 +80,6 @@ import { PlusCircleIcon } from '@patternfly/react-icons'; import { TFunction } from 'i18next'; import { nanoid } from 'nanoid'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { Observable, of } from 'rxjs'; import { ChartContext } from './Charts/context'; @@ -92,7 +92,7 @@ export interface AddCardProps { export const AddCard: React.FC = ({ variant }) => { const dispatch = useDispatch(); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const [showWizard, setShowWizard] = React.useState(false); const [selection, setSelection] = React.useState(''); @@ -240,7 +240,7 @@ export const AddCard: React.FC = ({ variant }) => { > = ({ selection, onSelect }) => { - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const activeLevel = useFeatureLevel(); const [toViewCard, setToViewCard] = React.useState(); @@ -444,7 +444,7 @@ interface PropsConfigFormProps { } const PropsConfigForm: React.FC = ({ onChange, ...props }) => { - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const handleChange = React.useCallback( (k: string) => (e: unknown) => { const copy = { ...props.config }; diff --git a/src/app/Dashboard/AutomatedAnalysis/AutomatedAnalysisCard.tsx b/src/app/Dashboard/AutomatedAnalysis/AutomatedAnalysisCard.tsx index 7a298eb07..431464f46 100644 --- a/src/app/Dashboard/AutomatedAnalysis/AutomatedAnalysisCard.tsx +++ b/src/app/Dashboard/AutomatedAnalysis/AutomatedAnalysisCard.tsx @@ -51,6 +51,7 @@ import { automatedAnalysisConfigToRecordingAttributes } from '@app/Shared/Servic import { ServiceContext } from '@app/Shared/Services/Services'; import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { calculateAnalysisTimer, portalRoot } from '@app/utils/utils'; +import { useCryostatTranslation } from '@i18n/i18nextUtil'; import { Button, CardBody, @@ -96,7 +97,6 @@ import { } from '@patternfly/react-icons'; import _ from 'lodash'; import * as React from 'react'; -import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { concatMap, filter, first, map, tap } from 'rxjs'; import { DashboardCard } from '../DashboardCard'; @@ -119,7 +119,7 @@ export const AutomatedAnalysisCard: DashboardCardFC const context = React.useContext(ServiceContext); const addSubscription = useSubscriptions(); const dispatch = useDispatch(); - const { t } = useTranslation(); + const { t } = useCryostatTranslation(); const [targetConnectURL, setTargetConnectURL] = React.useState(''); const [results, setResults] = React.useState([]); @@ -445,7 +445,7 @@ export const AutomatedAnalysisCard: DashboardCardFC if (errorMessage === NO_RECORDINGS_MESSAGE) { return [undefined, undefined]; } else if (isAuthFail(errorMessage)) { - return [t('RETRY', { ns: 'common' }), generateReport]; + return [t('RETRY'), generateReport]; } else if (errorMessage === RECORDING_FAILURE_MESSAGE) { return [t('AutomatedAnalysisCard.RETRY_STARTING'), startProfilingRecording]; } else if (errorMessage === FAILED_REPORT_MESSAGE) { @@ -453,7 +453,7 @@ export const AutomatedAnalysisCard: DashboardCardFC } else if (errorMessage === TEMPLATE_UNSUPPORTED_MESSAGE) { return [undefined, undefined]; } else { - return [t('RETRY', { ns: 'common' }), generateReport]; + return [t('RETRY'), generateReport]; } } return [undefined, undefined]; @@ -619,7 +619,7 @@ export const AutomatedAnalysisCard: DashboardCardFC