From 899e4ff3bfecb93d68da2b2e7ab78f94e1bf794e Mon Sep 17 00:00:00 2001 From: Valentin Kirilov Date: Fri, 17 Jul 2026 10:25:19 +0300 Subject: [PATCH 1/2] feat(i18n): migrate rdi instance pipeline header to i18n (RI-8277) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route the RDI instance pipeline header through i18n under rdi.instance.* with Bulgarian translations: the deploy modal (confirm title, errors warning, overwrite/flush texts, reset checkbox + info, Deploy button), the start/stop/reset pipeline buttons (tooltips, aria-labels, labels), the current pipeline status title and the state labels (initial sync / streaming / not running / error), and the config-file action menu items (download deployed / import ZIP / save ZIP). Pipeline state labels resolve via the i18n singleton inside getStatusToShowFromState (called at render). The v1 status fallback (capitalized raw status) and shared rdiErrorMessages factory are left for the pipeline-management PR. bg: "Deploy"->"Внедряване", "snapshot"->"снапшот". Co-Authored-By: Claude Opus 4.8 --- redisinsight/ui/src/i18n/locales/bg.json | 25 ++++++++ redisinsight/ui/src/i18n/locales/en.json | 25 ++++++++ .../DeployPipelineButton.tsx | 24 ++++---- .../ResetPipelineButton.tsx | 57 +++++++++---------- .../StartPipelineButton.tsx | 37 ++++++------ .../StopPipelineButton.tsx | 37 ++++++------ .../CurrentPipelineStatus.tsx | 4 +- .../current-pipeline-status/utils.ts | 9 +-- .../RdiConfigFileActionMenu.tsx | 8 ++- 9 files changed, 143 insertions(+), 83 deletions(-) diff --git a/redisinsight/ui/src/i18n/locales/bg.json b/redisinsight/ui/src/i18n/locales/bg.json index becfbb7b51..5229b85ba4 100644 --- a/redisinsight/ui/src/i18n/locales/bg.json +++ b/redisinsight/ui/src/i18n/locales/bg.json @@ -571,6 +571,31 @@ "rdi.home.pageTitle": "Redis Data Integration", "rdi.home.search.ariaLabel": "Търсене в списъка с RDI инстанции", "rdi.home.search.placeholder": "Търсене в списъка с крайни точки", + "rdi.instance.configMenu.downloadDeployed": "Изтегляне на внедрения конвейер", + "rdi.instance.configMenu.importZip": "Импортиране на конвейер от ZIP файл", + "rdi.instance.configMenu.saveZip": "Запазване на конвейера в ZIP файл", + "rdi.instance.deploy.button": "Внедряване", + "rdi.instance.deploy.confirmTitle": "Сигурни ли сте, че искате да внедрите конвейера?", + "rdi.instance.deploy.errorsWarning": "Вашият RDI конвейер съдържа грешки. Сигурни ли сте, че искате да продължите?", + "rdi.instance.deploy.flushText": "След внедряването обмислете изчистване на целевата Redis база данни и нулиране на конвейера, за да сте сигурни, че всички данни са обработени наново.", + "rdi.instance.deploy.overwriteText": "При внедряване тази локална конфигурация ще замени всеки съществуващ конвейер.", + "rdi.instance.deploy.resetInfo": "Конвейерът ще направи нов снапшот на данните и ще ги обработи, след което ще продължи да следи промените.", + "rdi.instance.deploy.resetLabel": "Нулиране", + "rdi.instance.reset.ariaLabel": "Бутон за нулиране на конвейера", + "rdi.instance.reset.button": "Нулиране", + "rdi.instance.reset.tooltipLine1": "Конвейерът ще направи нов снапшот на данните и ще ги обработи, след което ще продължи да следи промените.", + "rdi.instance.reset.tooltipLine2": "Преди да нулирате RDI конвейера, обмислете спиране на конвейера и изчистване на целевата Redis база данни.", + "rdi.instance.start.ariaLabel": "Стартиране на конвейера", + "rdi.instance.start.button": "Старт", + "rdi.instance.start.tooltip": "Стартирайте конвейера, за да възобновите обработката на нови постъпващи данни.", + "rdi.instance.status.error": "Грешка", + "rdi.instance.status.initialSync": "Първоначална синхронизация", + "rdi.instance.status.notRunning": "Не работи", + "rdi.instance.status.streaming": "Стрийминг", + "rdi.instance.status.title": "Състояние на конвейера", + "rdi.instance.stop.ariaLabel": "Спиране на конвейера", + "rdi.instance.stop.button": "Стоп", + "rdi.instance.stop.tooltip": "Спрете конвейера, за да предотвратите обработката на нови постъпващи данни.", "rdi.statistics.empty.addButton": "Добавяне на конвейер", "rdi.statistics.empty.description": "Създайте първия си конвейер, за да започнете!", "rdi.statistics.empty.title": "Все още няма разгърнат конвейер", diff --git a/redisinsight/ui/src/i18n/locales/en.json b/redisinsight/ui/src/i18n/locales/en.json index b4798650b4..26a375620c 100644 --- a/redisinsight/ui/src/i18n/locales/en.json +++ b/redisinsight/ui/src/i18n/locales/en.json @@ -571,6 +571,31 @@ "rdi.home.pageTitle": "Redis Data Integration", "rdi.home.search.ariaLabel": "Search rdi instance list", "rdi.home.search.placeholder": "Endpoint List Search", + "rdi.instance.configMenu.downloadDeployed": "Download deployed pipeline", + "rdi.instance.configMenu.importZip": "Import pipeline from ZIP file", + "rdi.instance.configMenu.saveZip": "Save pipeline to ZIP file", + "rdi.instance.deploy.button": "Deploy", + "rdi.instance.deploy.confirmTitle": "Are you sure you want to deploy the pipeline?", + "rdi.instance.deploy.errorsWarning": "Your RDI pipeline contains errors. Are you sure you want to continue?", + "rdi.instance.deploy.flushText": "After deployment, consider flushing the target Redis database and resetting the pipeline to ensure that all data is reprocessed.", + "rdi.instance.deploy.overwriteText": "When deployed, this local configuration will overwrite any existing pipeline.", + "rdi.instance.deploy.resetInfo": "The pipeline will take a new snapshot of the data and process it, then continue tracking changes.", + "rdi.instance.deploy.resetLabel": "Reset", + "rdi.instance.reset.ariaLabel": "Reset pipeline button", + "rdi.instance.reset.button": "Reset", + "rdi.instance.reset.tooltipLine1": "The pipeline will take a new snapshot of the data and process it, then continue tracking changes.", + "rdi.instance.reset.tooltipLine2": "Before resetting the RDI pipeline, consider stopping the pipeline and flushing the target Redis database.", + "rdi.instance.start.ariaLabel": "Start running pipeline", + "rdi.instance.start.button": "Start", + "rdi.instance.start.tooltip": "Start the pipeline to resume processing new data arrivals.", + "rdi.instance.status.error": "Error", + "rdi.instance.status.initialSync": "Initial sync", + "rdi.instance.status.notRunning": "Not running", + "rdi.instance.status.streaming": "Streaming", + "rdi.instance.status.title": "Pipeline status", + "rdi.instance.stop.ariaLabel": "Stop running pipeline", + "rdi.instance.stop.button": "Stop", + "rdi.instance.stop.tooltip": "Stop the pipeline to prevent processing of new data arrivals.", "rdi.statistics.empty.addButton": "Add Pipeline", "rdi.statistics.empty.description": "Create your first pipeline to get started!", "rdi.statistics.empty.title": "No pipeline deployed yet", diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/deploy-pipeline-button/DeployPipelineButton.tsx b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/deploy-pipeline-button/DeployPipelineButton.tsx index 046757c16a..dc0d17eb13 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/deploy-pipeline-button/DeployPipelineButton.tsx +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/deploy-pipeline-button/DeployPipelineButton.tsx @@ -21,6 +21,7 @@ import { Checkbox } from 'uiSrc/components/base/forms/checkbox/Checkbox' import { RiTooltip } from 'uiSrc/components/base' import { Modal } from 'uiSrc/components/base/display/modal' import { UploadWarningBanner } from 'uiSrc/components/upload-warning/styles' +import { useTranslation } from 'uiSrc/i18n' export interface Props { loading?: boolean @@ -29,6 +30,7 @@ export interface Props { } const DeployPipelineButton = ({ loading, disabled, onReset }: Props) => { + const { t } = useTranslation() const [resetPipeline, setResetPipeline] = useState(false) const { config, jobs, resetChecked, isPipelineValid } = @@ -89,45 +91,39 @@ const DeployPipelineButton = ({ loading, disabled, onReset }: Props) => { return ( {!isPipelineValid && ( )} - - When deployed, this local configuration will overwrite any - existing pipeline. - - - After deployment, consider flushing the target Redis database and - resetting the pipeline to ensure that all data is reprocessed. - + {t('rdi.instance.deploy.overwriteText')} + {t('rdi.instance.deploy.flushText')} handleSelectReset(e.target.checked)} data-testid="reset-pipeline-checkbox" /> - + } - primaryButtonText="Deploy" + primaryButtonText={t('rdi.instance.deploy.button')} onPrimaryButtonClick={handleDeployPipeline} > { loading={loading} data-testid="deploy-rdi-pipeline" > - Deploy + {t('rdi.instance.deploy.button')} ) diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/reset-pipeline-button/ResetPipelineButton.tsx b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/reset-pipeline-button/ResetPipelineButton.tsx index cdd5351bff..186ec627e0 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/reset-pipeline-button/ResetPipelineButton.tsx +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/reset-pipeline-button/ResetPipelineButton.tsx @@ -2,6 +2,7 @@ import React from 'react' import { Spacer } from 'uiSrc/components/base/layout/spacer' import { RiTooltip } from 'uiSrc/components' +import { useTranslation } from 'uiSrc/i18n' import styles from '../styles.module.scss' import { Button, TextButton } from '@redis-ui/components' import { ResetIcon } from '@redis-ui/icons' @@ -16,35 +17,33 @@ const ResetPipelineButton = ({ onClick, disabled, loading, -}: PipelineButtonProps) => ( - -

- The pipeline will take a new snapshot of the data and process it, - then continue tracking changes. -

- -

- Before resetting the RDI pipeline, consider stopping the pipeline - and flushing the target Redis database. -

- - ) : null - } - anchorClassName={disabled || loading ? styles.disabled : styles.tooltip} - > - { + const { t } = useTranslation() + + return ( + +

{t('rdi.instance.reset.tooltipLine1')}

+ +

{t('rdi.instance.reset.tooltipLine2')}

+ + ) : null + } + anchorClassName={disabled || loading ? styles.disabled : styles.tooltip} > - - Reset -
-
-) + + + {t('rdi.instance.reset.button')} + + + ) +} export default ResetPipelineButton diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/start-pipeline-button/StartPipelineButton.tsx b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/start-pipeline-button/StartPipelineButton.tsx index b9c2a8c2cb..505e71dac9 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/start-pipeline-button/StartPipelineButton.tsx +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/start-pipeline-button/StartPipelineButton.tsx @@ -3,6 +3,7 @@ import React from 'react' import { SecondaryButton } from 'uiSrc/components/base/forms/buttons' import { PlayFilledIcon } from 'uiSrc/components/base/icons' import { RiTooltip } from 'uiSrc/components' +import { useTranslation } from 'uiSrc/i18n' import { PipelineButtonProps } from '../reset-pipeline-button/ResetPipelineButton' import styles from '../styles.module.scss' @@ -10,22 +11,26 @@ const StartPipelineButton = ({ onClick, disabled, loading, -}: PipelineButtonProps) => ( - - { + const { t } = useTranslation() + + return ( + - Start - - -) + + {t('rdi.instance.start.button')} + + + ) +} export default StartPipelineButton diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/stop-pipeline-button/StopPipelineButton.tsx b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/stop-pipeline-button/StopPipelineButton.tsx index a24e55b5ba..984d4da184 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/stop-pipeline-button/StopPipelineButton.tsx +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/buttons/stop-pipeline-button/StopPipelineButton.tsx @@ -3,6 +3,7 @@ import React from 'react' import { SecondaryButton } from 'uiSrc/components/base/forms/buttons' import { RiStopIcon } from 'uiSrc/components/base/icons' import { RiTooltip } from 'uiSrc/components' +import { useTranslation } from 'uiSrc/i18n' import { PipelineButtonProps } from '../reset-pipeline-button/ResetPipelineButton' import styles from '../styles.module.scss' @@ -10,22 +11,26 @@ const StopPipelineButton = ({ onClick, disabled, loading, -}: PipelineButtonProps) => ( - - { + const { t } = useTranslation() + + return ( + - Stop - - -) + + {t('rdi.instance.stop.button')} + + + ) +} export default StopPipelineButton diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/CurrentPipelineStatus.tsx b/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/CurrentPipelineStatus.tsx index 1697876a0e..b2590eeae1 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/CurrentPipelineStatus.tsx +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/CurrentPipelineStatus.tsx @@ -7,6 +7,7 @@ import { Loader } from 'uiSrc/components/base/display' import { RiTooltip } from 'uiSrc/components' import { FlexItem, Row } from 'uiSrc/components/base/layout/flex' import { Text } from 'uiSrc/components/base/text' +import { useTranslation } from 'uiSrc/i18n' import { getStatusToShowFromState, getStatusToShowFromStatus } from './utils' export interface Props { @@ -22,6 +23,7 @@ const CurrentPipelineStatus = ({ statusError, headerLoading, }: Props) => { + const { t } = useTranslation() const stateInfo = pipelineState ? getStatusToShowFromState(pipelineState) : getStatusToShowFromStatus(pipelineStatus) @@ -31,7 +33,7 @@ const CurrentPipelineStatus = ({ - Pipeline status + {t('rdi.instance.status.title')} diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts b/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts index bcad44db73..47c98fedc4 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts @@ -9,6 +9,7 @@ import { PipelineState, PipelineStatus } from 'uiSrc/slices/interfaces' import { IconProps } from 'uiSrc/components/base/icons' import { IconType } from 'uiSrc/components/base/forms/buttons' import { Maybe } from 'uiSrc/utils' +import i18n from 'uiSrc/i18n' export interface StatusInfo { label: string @@ -24,25 +25,25 @@ export const getStatusToShowFromState = ( return { icon: IndicatorSyncingIcon, iconColor: 'success300', - label: 'Initial sync', + label: i18n.t('rdi.instance.status.initialSync'), } case PipelineState.CDC: return { icon: IndicatorSyncedIcon, iconColor: 'success500', - label: 'Streaming', + label: i18n.t('rdi.instance.status.streaming'), } case PipelineState.NotRunning: return { icon: IndicatorSyncstoppedIcon, iconColor: 'attention500', - label: 'Not running', + label: i18n.t('rdi.instance.status.notRunning'), } default: return { icon: IndicatorSyncerrorIcon, iconColor: 'danger500', - label: 'Error', + label: i18n.t('rdi.instance.status.error'), } } } diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/rdi-config-file-action-menu/RdiConfigFileActionMenu.tsx b/redisinsight/ui/src/pages/rdi/instance/components/header/components/rdi-config-file-action-menu/RdiConfigFileActionMenu.tsx index fe28ff8e95..ffada3ddd3 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/rdi-config-file-action-menu/RdiConfigFileActionMenu.tsx +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/rdi-config-file-action-menu/RdiConfigFileActionMenu.tsx @@ -11,8 +11,10 @@ import { import { Menu } from '@redis-ui/components' import DownloadFromServerModal from 'uiSrc/pages/rdi/pipeline-management/components/download-from-server-modal/DownloadFromServerModal' +import { useTranslation } from 'uiSrc/i18n' const RdiConfigFileActionMenu = () => { + const { t } = useTranslation() const [isOpen, setIsOpen] = useState(false) const closeMenu = () => setIsOpen(false) @@ -34,7 +36,7 @@ const RdiConfigFileActionMenu = () => { onClose={closeMenu} trigger={ e.preventDefault()} aria-labelledby="Upload pipeline button" @@ -46,7 +48,7 @@ const RdiConfigFileActionMenu = () => { onClose={closeMenu} trigger={ e.preventDefault()} aria-labelledby="Upload file button" @@ -57,7 +59,7 @@ const RdiConfigFileActionMenu = () => { Date: Fri, 17 Jul 2026 17:55:51 +0300 Subject: [PATCH 2/2] fix(i18n): localize v1 pipeline status labels (RI-8277) Address review feedback: getStatusToShowFromStatus (used for the status-shape badge when pipelineState is absent) built labels via capitalize(status), leaving mixed-language output (e.g. Bulgarian header next to English "Started"/"Ready"). Map the known PipelineStatus values to rdi.instance.status.* keys resolved at render; unknown/arbitrary statuses keep the capitalized fallback. Co-Authored-By: Claude Opus 4.8 --- redisinsight/ui/src/i18n/locales/bg.json | 12 ++++++++++ redisinsight/ui/src/i18n/locales/en.json | 12 ++++++++++ .../current-pipeline-status/utils.ts | 22 ++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/i18n/locales/bg.json b/redisinsight/ui/src/i18n/locales/bg.json index 5229b85ba4..004a39f1b4 100644 --- a/redisinsight/ui/src/i18n/locales/bg.json +++ b/redisinsight/ui/src/i18n/locales/bg.json @@ -588,11 +588,23 @@ "rdi.instance.start.ariaLabel": "Стартиране на конвейера", "rdi.instance.start.button": "Старт", "rdi.instance.start.tooltip": "Стартирайте конвейера, за да възобновите обработката на нови постъпващи данни.", + "rdi.instance.status.creating": "Създаване", + "rdi.instance.status.deleting": "Изтриване", "rdi.instance.status.error": "Грешка", "rdi.instance.status.initialSync": "Първоначална синхронизация", + "rdi.instance.status.notReady": "Не е готов", "rdi.instance.status.notRunning": "Не работи", + "rdi.instance.status.pending": "В изчакване", + "rdi.instance.status.ready": "Готов", + "rdi.instance.status.resetting": "Нулиране", + "rdi.instance.status.started": "Стартиран", + "rdi.instance.status.starting": "Стартиране", + "rdi.instance.status.stopped": "Спрян", + "rdi.instance.status.stopping": "Спиране", "rdi.instance.status.streaming": "Стрийминг", "rdi.instance.status.title": "Състояние на конвейера", + "rdi.instance.status.unknown": "Неизвестно", + "rdi.instance.status.updating": "Обновяване", "rdi.instance.stop.ariaLabel": "Спиране на конвейера", "rdi.instance.stop.button": "Стоп", "rdi.instance.stop.tooltip": "Спрете конвейера, за да предотвратите обработката на нови постъпващи данни.", diff --git a/redisinsight/ui/src/i18n/locales/en.json b/redisinsight/ui/src/i18n/locales/en.json index 26a375620c..24becd408a 100644 --- a/redisinsight/ui/src/i18n/locales/en.json +++ b/redisinsight/ui/src/i18n/locales/en.json @@ -588,11 +588,23 @@ "rdi.instance.start.ariaLabel": "Start running pipeline", "rdi.instance.start.button": "Start", "rdi.instance.start.tooltip": "Start the pipeline to resume processing new data arrivals.", + "rdi.instance.status.creating": "Creating", + "rdi.instance.status.deleting": "Deleting", "rdi.instance.status.error": "Error", "rdi.instance.status.initialSync": "Initial sync", + "rdi.instance.status.notReady": "Not-ready", "rdi.instance.status.notRunning": "Not running", + "rdi.instance.status.pending": "Pending", + "rdi.instance.status.ready": "Ready", + "rdi.instance.status.resetting": "Resetting", + "rdi.instance.status.started": "Started", + "rdi.instance.status.starting": "Starting", + "rdi.instance.status.stopped": "Stopped", + "rdi.instance.status.stopping": "Stopping", "rdi.instance.status.streaming": "Streaming", "rdi.instance.status.title": "Pipeline status", + "rdi.instance.status.unknown": "Unknown", + "rdi.instance.status.updating": "Updating", "rdi.instance.stop.ariaLabel": "Stop running pipeline", "rdi.instance.stop.button": "Stop", "rdi.instance.stop.tooltip": "Stop the pipeline to prevent processing of new data arrivals.", diff --git a/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts b/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts index 47c98fedc4..eac31a4f23 100644 --- a/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts +++ b/redisinsight/ui/src/pages/rdi/instance/components/header/components/current-pipeline-status/utils.ts @@ -48,10 +48,30 @@ export const getStatusToShowFromState = ( } } +const STATUS_LABEL_KEYS: Record = { + [PipelineStatus.Ready]: 'rdi.instance.status.ready', + [PipelineStatus.NotReady]: 'rdi.instance.status.notReady', + [PipelineStatus.Stopping]: 'rdi.instance.status.stopping', + [PipelineStatus.Started]: 'rdi.instance.status.started', + [PipelineStatus.Stopped]: 'rdi.instance.status.stopped', + [PipelineStatus.Error]: 'rdi.instance.status.error', + [PipelineStatus.Creating]: 'rdi.instance.status.creating', + [PipelineStatus.Updating]: 'rdi.instance.status.updating', + [PipelineStatus.Deleting]: 'rdi.instance.status.deleting', + [PipelineStatus.Starting]: 'rdi.instance.status.starting', + [PipelineStatus.Resetting]: 'rdi.instance.status.resetting', + [PipelineStatus.Pending]: 'rdi.instance.status.pending', + [PipelineStatus.Unknown]: 'rdi.instance.status.unknown', +} + export const getStatusToShowFromStatus = ( status: Maybe, ): StatusInfo => { - const label = capitalize(status || 'Error') + const label = !status + ? i18n.t('rdi.instance.status.error') + : STATUS_LABEL_KEYS[status] + ? i18n.t(STATUS_LABEL_KEYS[status] as never) + : capitalize(status) switch (status) { case PipelineStatus.Creating: