diff --git a/web/src/components/core/InstallButton.jsx b/web/src/components/core/InstallButton.jsx
index 9735bb21ca..6deaf4759d 100644
--- a/web/src/components/core/InstallButton.jsx
+++ b/web/src/components/core/InstallButton.jsx
@@ -41,10 +41,10 @@ const InstallConfirmationPopup = ({ hasIssues, onAccept, onClose }) => {
};
// TRANSLATORS: the installer reports some errors,
- // the part in curly brackets {} is a clickable link
+ // the text in square brackets [] is a clickable link
const [msgStart, msgLink, msgEnd] = _("There are some reported issues. \
-Please, check {the list of issues} \
-before proceeding with the installation.").split(/[{}]/);
+Please, check [the list of issues] \
+before proceeding with the installation.").split(/[[\]]/);
return (
diff --git a/web/src/components/core/Popup.jsx b/web/src/components/core/Popup.jsx
index 05b3c75200..e51cdacf6c 100644
--- a/web/src/components/core/Popup.jsx
+++ b/web/src/components/core/Popup.jsx
@@ -21,6 +21,8 @@
import React, { useLayoutEffect } from "react";
import { Button, Modal } from "@patternfly/react-core";
+
+import { _ } from "~/i18n";
import { partition } from "~/utils";
/**
@@ -85,7 +87,7 @@ const PrimaryAction = ({ children, ...props }) => (
* @param {React.ReactNode} [props.children="confirm"] - content of the action
* @param {object} [props] - {@link Action} props
*/
-const Confirm = ({ children = "Confirm", ...props }) => (
+const Confirm = ({ children = _("Confirm"), ...props }) => (
{ children }
);
@@ -123,7 +125,7 @@ const SecondaryAction = ({ children, ...props }) => (
* @param {React.ReactNode} [props.children="Cancel"] - content of the action
* @param {object} [props] - {@link Action} props
*/
-const Cancel = ({ children = "Cancel", ...props }) => (
+const Cancel = ({ children = _("Cancel"), ...props }) => (
{ children }
);
diff --git a/web/src/components/storage/DASDFormatProgress.jsx b/web/src/components/storage/DASDFormatProgress.jsx
index e7f7311e44..a97f34b3a8 100644
--- a/web/src/components/storage/DASDFormatProgress.jsx
+++ b/web/src/components/storage/DASDFormatProgress.jsx
@@ -21,6 +21,8 @@
import React, { useEffect, useState } from "react";
import { Progress, Skeleton } from '@patternfly/react-core';
+
+import { _ } from "~/i18n";
import { If, Popup } from "~/components/core";
import { useInstallerClient } from "~/context/installer";
@@ -56,7 +58,7 @@ export default function DASDFormatProgress({ job, devices, isOpen = true }) {
const WaitingProgress = () => (
-
Waiting for progress report
+
{_("Waiting for progress report")}
@@ -64,7 +66,7 @@ export default function DASDFormatProgress({ job, devices, isOpen = true }) {
return (
diff --git a/web/src/components/storage/DASDPage.jsx b/web/src/components/storage/DASDPage.jsx
index eceafb7045..5c40e0d723 100644
--- a/web/src/components/storage/DASDPage.jsx
+++ b/web/src/components/storage/DASDPage.jsx
@@ -22,6 +22,8 @@
import React, { useEffect, useReducer } from "react";
import { useNavigate } from "react-router-dom";
import { Button } from "@patternfly/react-core";
+
+import { _ } from "~/i18n";
import { MainActions } from "~/components/layout";
import { If, Page } from "~/components/core";
import { DASDFormatProgress, DASDTable } from "~/components/storage";
@@ -179,9 +181,10 @@ export default function DASDPage() {
}, [client.dasd]);
return (
-
+ // TRANSLATORS: DASD = Direct Access Storage Device, IBM mainframe storage technology
+
- navigate("/storage")}>Back
+ navigate("/storage")}>{_("Back")}
diff --git a/web/src/components/storage/DASDTable.jsx b/web/src/components/storage/DASDTable.jsx
index 82fff46735..528f80e42a 100644
--- a/web/src/components/storage/DASDTable.jsx
+++ b/web/src/components/storage/DASDTable.jsx
@@ -29,6 +29,7 @@ import {
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
import { sort } from 'fast-sort';
+import { _ } from "~/i18n";
import { Icon } from "~/components/layout";
import { If, SectionSkeleton } from "~/components/core";
import { hex } from "~/utils";
@@ -51,20 +52,20 @@ const columnData = (device, column) => {
}
if (typeof data === "boolean") {
- return data ? "Yes" : "No";
+ return data ? _("Yes") : _("No");
}
return data;
};
const columns = [
- { id: "channelId", sortId: "hexId", label: "Channel ID" },
- { id: "status", label: "Status" },
- { id: "name", label: "Device" },
- { id: "type", label: "Type" },
- { id: "diag", label: "Diag" },
- { id: "formatted", label: "Formatted" },
- { id: "partitionInfo", label: "Partition Info" }
+ { id: "channelId", sortId: "hexId", label: _("Channel ID") },
+ { id: "status", label: _("Status") },
+ { id: "name", label: _("Device") },
+ { id: "type", label: _("Type") },
+ { id: "diag", label: _("Diag") },
+ { id: "formatted", label: _("Formatted") },
+ { id: "partitionInfo", label: _("Partition Info") }
];
const Actions = ({ devices, isDisabled }) => {
@@ -97,17 +98,23 @@ const Actions = ({ devices, isDisabled }) => {
isOpen={isOpen}
onSelect={onSelect}
dropdownItems={[
- Activate ,
- Deactivate ,
+ // TRANSLATORS: drop down menu action, activate the device
+ {_("Activate")} ,
+ // TRANSLATORS: drop down menu action, deactivate the device
+ {_("Deactivate")} ,
,
- Set DIAG On ,
- Set DIAG Off ,
+ // TRANSLATORS: drop down menu action, enable DIAG access method
+ {_("Set DIAG On")} ,
+ // TRANSLATORS: drop down menu action, disable DIAG access method
+ {_("Set DIAG Off")} ,
,
- Format
+ // TRANSLATORS: drop down menu action, format the disk
+ {_("Format")}
]}
toggle={
- Perform an action
+ {/* TRANSLATORS: drop down menu label */}
+ {_("Perform an action")}
}
/>
@@ -185,15 +192,15 @@ export default function DASDTable({ state, dispatch }) {
{ state.minChannel !== "" &&
@@ -206,15 +213,15 @@ export default function DASDTable({ state, dispatch }) {
{ state.maxChannel !== "" &&
diff --git a/web/src/components/storage/DeviceSelector.jsx b/web/src/components/storage/DeviceSelector.jsx
index 8826405b50..bce1190af2 100644
--- a/web/src/components/storage/DeviceSelector.jsx
+++ b/web/src/components/storage/DeviceSelector.jsx
@@ -20,6 +20,9 @@
*/
import React, { useState } from "react";
+import format from "format-util";
+
+import { _ } from "~/i18n";
import { noop } from "~/utils";
import { Icon } from "~/components/layout";
import { If } from "~/components/core";
@@ -92,19 +95,25 @@ const ItemContent = ({ device }) => {
switch (device.type) {
case "multipath": {
- type = "Multipath";
+ // TRANSLATORS: multipath device type
+ type = _("Multipath");
break;
}
case "dasd": {
- type = `DASD ${device.busId}`;
+ // TRANSLATORS: %s is replaced by the device bus ID
+ type = format(_("DASD %s"), device.busId);
break;
}
case "md": {
- type = `Software ${device.level.toUpperCase()}`;
+ // TRANSLATORS: software RAID device, %s is replaced by the RAID level, e.g. RAID-1
+ type = format(_("Software %s"), device.level.toUpperCase());
break;
}
case "disk": {
- type = device.sdCard ? "SD Card" : `Transport ${device.transport}`;
+ type = device.sdCard
+ ? _("SD Card")
+ // TRANSLATORS: %s is replaced by the device transport name, e.g. USB, SATA, SCSI...
+ : format(_("Transport %s"), device.transport);
}
}
@@ -160,7 +169,9 @@ const ItemContent = ({ device }) => {
const type = device.partitionTable.type.toUpperCase();
const numPartitions = device.partitionTable.partitions.length;
- const text = `${type} with ${numPartitions} partitions`;
+ // TRANSLATORS: disk partition info, %s is replaced by partition table
+ // type (MS-DOS or GPT), %d is the number of the partitions
+ const text = format(_("%s with %d partitions"), type, numPartitions);
return (
@@ -182,7 +193,9 @@ const ItemContent = ({ device }) => {
};
const NotFound = () => {
- return
No content found
;
+ // TRANSLATORS: status message, no existing content was found on the disk,
+ // i.e. the disk is completely empty
+ return
{_("No content found")}
;
};
const hasContent = device.partitionTable || device.systems.length > 0;
@@ -230,7 +243,7 @@ export default function DeviceSelector ({ selected, devices = [], onSelect = noo
};
return (
-
+
{ devices.map(device => (
- Storage iSCSI
+ {/* TRANSLATORS: page title for iSCSI configuration */}
+ {_("Storage iSCSI")}
navigate("/storage")}>
- Back
+ {_("Back")}
diff --git a/web/src/components/storage/ProposalActionsSection.jsx b/web/src/components/storage/ProposalActionsSection.jsx
index ed3ccd386b..a30723752b 100644
--- a/web/src/components/storage/ProposalActionsSection.jsx
+++ b/web/src/components/storage/ProposalActionsSection.jsx
@@ -27,7 +27,9 @@ import {
Skeleton,
Text
} from "@patternfly/react-core";
+import format from "format-util";
+import { _, n_ } from "~/i18n";
import { If, Section } from "~/components/core";
import { partition } from "~/utils";
@@ -64,13 +66,16 @@ const ProposalActions = ({ actions = [] }) => {
if (actions.length === 0) return null;
const [generalActions, subvolActions] = partition(actions, a => !a.subvol);
- const userAction = isExpanded ? "Hide" : "Show";
- const toggleText = `${userAction} ${subvolActions.length} subvolumes actions`;
+ const toggleText = isExpanded
+ // TRANSLATORS: show/hide toggle action, this is a clickable link
+ ? format(n_("Hide %d subvolume action", "Hide %d subvolume actions", subvolActions.length), subvolActions.length)
+ // TRANSLATORS: show/hide toggle action, this is a clickable link
+ : format(n_("Show %d subvolume action", "Show %d subvolume actions", subvolActions.length), subvolActions.length);
return (
<>
- Actions to create the file systems and to ensure the system boots.
+ {_("Actions to create the file systems and to ensure the system boots.")}
{subvolActions.length > 0 && (
@@ -116,7 +121,9 @@ export default function ProposalActionsSection({ actions = [], errors = [], isLo
if (isLoading) errors = [];
return (
-
+ // TRANSLATORS: section title, list of planned actions for the selected device,
+ // e.g. "delete partition A", "create partition B with filesystem C", ...
+
}
diff --git a/web/src/components/storage/ProposalActionsSection.test.jsx b/web/src/components/storage/ProposalActionsSection.test.jsx
index 1f425aef7c..846e6fda20 100644
--- a/web/src/components/storage/ProposalActionsSection.test.jsx
+++ b/web/src/components/storage/ProposalActionsSection.test.jsx
@@ -114,14 +114,14 @@ describe("when there are actions", () => {
);
- const link = screen.getByText(/Show.*subvolumes actions/);
+ const link = screen.getByText(/Show.*subvolume actions/);
expect(screen.getAllByRole("list").length).toEqual(1);
await user.click(link);
waitForElementToBeRemoved(link);
- screen.getByText(/Hide.*subvolumes actions/);
+ screen.getByText(/Hide.*subvolume actions/);
// For now, we know that there are two lists and the subvolume list is the second one.
// The test could be simplified once we have aria-descriptions for the lists.
diff --git a/web/src/components/storage/ProposalPage.jsx b/web/src/components/storage/ProposalPage.jsx
index 44ddf89368..673e54ed60 100644
--- a/web/src/components/storage/ProposalPage.jsx
+++ b/web/src/components/storage/ProposalPage.jsx
@@ -22,6 +22,7 @@
import React, { useCallback, useReducer, useEffect } from "react";
import { Alert } from "@patternfly/react-core";
+import { _ } from "~/i18n";
import { useInstallerClient } from "~/context/installer";
import { toValidationError, useCancellablePromise } from "~/utils";
import { Icon } from "~/components/layout";
@@ -146,7 +147,7 @@ export default function ProposalPage() {
}
- title="Devices will not be modified until installation starts."
+ title={_("Devices will not be modified until installation starts.")}
/>
+ // TRANSLATORS: page title
+
diff --git a/web/src/components/storage/ProposalPageOptions.jsx b/web/src/components/storage/ProposalPageOptions.jsx
index 0ea11fc01b..447315c4fe 100644
--- a/web/src/components/storage/ProposalPageOptions.jsx
+++ b/web/src/components/storage/ProposalPageOptions.jsx
@@ -21,6 +21,8 @@
import React, { useEffect, useState } from "react";
import { useHref } from "react-router-dom";
+
+import { _ } from "~/i18n";
import { useInstallerClient } from "~/context/installer";
import { If, PageOptions } from "~/components/core";
@@ -35,7 +37,7 @@ const DASDLink = () => {
DASD
@@ -53,7 +55,7 @@ const ZFCPLink = () => {
zFCP
@@ -71,7 +73,7 @@ const ISCSILink = () => {
iSCSI
diff --git a/web/src/components/storage/ProposalSettingsSection.jsx b/web/src/components/storage/ProposalSettingsSection.jsx
index ed2506d236..072888928b 100644
--- a/web/src/components/storage/ProposalSettingsSection.jsx
+++ b/web/src/components/storage/ProposalSettingsSection.jsx
@@ -26,6 +26,7 @@ import {
Tooltip
} from "@patternfly/react-core";
+import { _ } from "~/i18n";
import { If, PasswordAndConfirmationInput, Section, Popup } from "~/components/core";
import { DeviceSelector, ProposalVolumes } from "~/components/storage";
import { Icon } from "~/components/layout";
@@ -108,7 +109,7 @@ const InstallationDeviceField = ({ current, devices, isLoading, onChange }) => {
};
const DeviceContent = ({ device }) => {
- const text = device || "No device selected yet";
+ const text = device || _("No device selected yet");
return {text} ;
};
@@ -117,23 +118,23 @@ const InstallationDeviceField = ({ current, devices, isLoading, onChange }) => {
return ;
}
- const description = "Select in which device to install the system. All the file systems will " +
- "be created on the selected device.";
+ const description = _("Select the device for installing the system. All the \
+file systems will be created on the selected device.");
return (
<>
- Installation device
+ {_("Installation device")}
No devices found }
+ then={{_("No devices found")}
}
else={
{
type="submit"
isDisabled={devices.length === 0}
>
- Accept
+ {_("Accept")}
@@ -183,7 +184,7 @@ const LVMField = ({ selected: selectedProp, isLoading, onChange }) => {
return (
{
return (
-
+
@@ -302,14 +303,14 @@ const EncryptionPasswordField = ({ selected: selectedProp, password: passwordPro
{ selected && }
-
+
- Accept
+ {_("Accept")}
@@ -370,7 +371,7 @@ export default function ProposalSettingsSection({
const encryption = settings.encryptionPassword !== undefined && settings.encryptionPassword.length > 0;
return (
-
+
{
return (
<>
- These limits are affected by:
+ {/* TRANSLATORS: header for a list of items */}
+ {_("These limits are affected by:")}
{volume.snapshotsAffectSizes &&
- The configuration of snapshots }
+ // TRANSLATORS: list item, this affects the computed partition size limits
+ {_("The configuration of snapshots")} }
{volume.sizeRelevantVolumes && volume.sizeRelevantVolumes.length > 0 &&
- Presence of other volumes ({volume.sizeRelevantVolumes.join(", ")}) }
+ // TRANSLATORS: list item, this affects the computed partition size limits
+ // %s is replaced by a list of the volumes (like "/home, /boot")
+ {format(_("Presence of other volumes (%s)"), volume.sizeRelevantVolumes.join(", "))} }
>
);
@@ -109,30 +115,33 @@ const GeneralActions = ({ templates, onAdd, onReset }) => {
key="reset"
onClick={onReset}
>
- Reset to defaults
+ {/* TRANSLATORS: dropdown menu label */}
+ {_("Reset to defaults")}
,
- Add file system
+ {/* TRANSLATORS: dropdown menu label */}
+ {_("Add file system")}
]}
toggle={
- Actions
+ {/* TRANSLATORS: dropdown label */}
+ {_("Actions")}
}
/>
-
+
- Accept
+ {_("Accept")}
@@ -173,12 +182,14 @@ const VolumeRow = ({ columns, volume, isLoading, onEdit, onDelete }) => {
let size = minSize;
if (minSize && maxSize && minSize !== maxSize) size = `${minSize} - ${maxSize}`;
- if (maxSize === undefined) size = `At least ${minSize}`;
+ // TRANSLATORS: minimum device size, %s is replaced by size string, e.g. "17.5 GiB"
+ if (maxSize === undefined) size = format(_("At least %s"), minSize);
return (
{size}
- auto} />
+ {/* TRANSLATORS: device flag, the partition size is automatically computed */}
+ {_("auto")}} />
);
};
@@ -187,15 +198,18 @@ const VolumeRow = ({ columns, volume, isLoading, onEdit, onDelete }) => {
const isLv = volume.deviceType === "lvm_lv";
const hasSnapshots = volume.fsType === "Btrfs" && volume.snapshots;
- const text = `${volume.fsType} ${isLv ? "logical volume" : "partition"}`;
+ // TRANSLATORS: the filesystem uses a logical volume (LVM)
+ const text = `${volume.fsType} ${isLv ? _("logical volume") : _("partition")}`;
const lockIcon = ;
const snapshotsIcon = ;
return (
{text}
- encrypted} />
- with snapshots} />
+ {/* TRANSLATORS: filesystem flag, it uses an encryption */}
+ {_("encrypted")}} />
+ {/* TRANSLATORS: filesystem flag, it allows creating snapshots */}
+ {_("with snapshots")}} />
);
};
@@ -204,12 +218,12 @@ const VolumeRow = ({ columns, volume, isLoading, onEdit, onDelete }) => {
const actions = () => {
const actions = {
delete: {
- title: "Delete",
+ title: _("Delete"),
onClick: () => onDelete(volume),
className: "danger-action"
},
edit: {
- title: "Edit",
+ title: _("Edit"),
onClick: () => onEdit(volume)
}
};
@@ -250,7 +264,7 @@ const VolumeRow = ({ columns, volume, isLoading, onEdit, onDelete }) => {
-
+
{
onSubmit={acceptForm}
/>
- Accept
+ {_("Accept")}
@@ -281,10 +295,10 @@ const VolumeRow = ({ columns, volume, isLoading, onEdit, onDelete }) => {
*/
const VolumesTable = ({ volumes, isLoading, onVolumesChange }) => {
const columns = {
- mountPoint: "At",
- details: "Details",
- size: "Size",
- actions: "Actions"
+ mountPoint: _("Mount point"),
+ details: _("Details"),
+ size: _("Size"),
+ actions: _("Actions")
};
const VolumesContent = ({ volumes, isLoading, onVolumesChange }) => {
@@ -318,7 +332,7 @@ const VolumesTable = ({ volumes, isLoading, onVolumesChange }) => {
};
return (
-
+
{columns.mountPoint}
@@ -374,7 +388,7 @@ export default function ProposalVolumes({
- File systems to create in your system
+ {_("File systems to create in your system")}
{
return (
- { units.map(unit => ) }
+ {/* the unit values are marked for translation in the utils.js file */}
+ { units.map(unit => ) }
);
};
@@ -89,16 +92,25 @@ const SizeAuto = ({ volume }) => {
const conditions = [];
if (volume.snapshotsAffectSizes)
- conditions.push("the configuration of snapshots");
+ // TRANSLATORS: item which affects the final computed partition size
+ conditions.push(_("the configuration of snapshots"));
if (volume.sizeRelevantVolumes && volume.sizeRelevantVolumes.length > 0)
- conditions.push(`the presence of the file system for ${volume.sizeRelevantVolumes.join(", ")}.`);
+ // TRANSLATORS: item which affects the final computed partition size
+ // %s is replaced by a list of mount points like "/home, /boot"
+ conditions.push(format(_("the presence of the file system for %s"),
+ // TRANSLATORS: conjunction for merging two list items
+ volume.sizeRelevantVolumes.join(_(", "))));
- const conditionsText = `The final size depends on ${conditions.join(" and ")}`;
+ // TRANSLATORS: the %s is replaced by the items which affect the computed size
+ const conditionsText = format(_("The final size depends on %s."),
+ // TRANSLATORS: conjunction for merging two texts
+ conditions.join(_(" and ")));
return (
<>
- Automatically calculated size according to the selected product. {conditionsText}
+ {/* TRANSLATORS: the partition size is automatically computed */}
+ {_("Automatically calculated size according to the selected product.")}{" "}{conditionsText}
>
);
};
@@ -118,7 +130,7 @@ const SizeManual = ({ errors, formData, onChange }) => {
return (
- Exact size for the file system.
+ {_("Exact size for the file system.")}
{
onChange({ size })}
validated={errors.size && 'error'}
/>
onChange({ sizeUnit })}
@@ -163,13 +182,14 @@ const SizeRange = ({ errors, formData, onChange }) => {
return (
- Limits for the file system size. The final size will be a value between the given minimum
- and maximum sizes. If no maximum is given, then the file system will be as big as possible.
+ {_("Limits for the file system size. The final size will be a value between the given minimum \
+and maximum. If no maximum is given then the file system will be as big as possible.")}
{
onChange({ minSize })}
validated={errors.minSize && 'error'}
/>
onChange({ minSizeUnit })}
@@ -194,7 +215,8 @@ const SizeRange = ({ errors, formData, onChange }) => {
{
id="maxSize"
name="maxSize"
validated={errors.maxSize && 'error'}
- aria-label="Maximum desired size"
+ // TRANSLATORS: the maximum partition size
+ aria-label={_("Maximum desired size")}
value={formData.maxSize}
onChange={(maxSize) => onChange({ maxSize })}
/>
onChange({ maxSizeUnit })}
@@ -224,6 +247,16 @@ const SizeRange = ({ errors, formData, onChange }) => {
);
};
+// constants need to be marked for translation with N_() and translated with _() later
+const SIZE_OPTION_LABELS = Object.freeze({
+ // TRANSLATORS: radio button label, fully automatically computed partition size, no user input
+ auto: N_("Auto"),
+ // TRANSLATORS: radio button label, exact partition size requested by user
+ fixed: N_("Fixed"),
+ // TRANSLATORS: radio button label, automatically computed partition size within the user provided min and max limits
+ range: N_("Range")
+});
+
/**
* Widget for rendering the volume size options
* @component
@@ -254,7 +287,7 @@ const SizeOptions = ({ errors, formData, volume, onChange }) => {
-
+
-
+
-
+
diff --git a/web/src/components/storage/VolumeForm.test.jsx b/web/src/components/storage/VolumeForm.test.jsx
index f72db4b80f..522a57239c 100644
--- a/web/src/components/storage/VolumeForm.test.jsx
+++ b/web/src/components/storage/VolumeForm.test.jsx
@@ -107,14 +107,14 @@ it("renders controls for setting the desired size", () => {
it("uses the default size unit when min size unit is missing", () => {
plainRender( );
- const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Max size unit" });
+ const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Unit for the maximum size" });
expect(maxSizeUnitSelector).toHaveValue(DEFAULT_SIZE_UNIT);
});
it("uses the min size unit as max size unit when it is missing", () => {
plainRender( );
- const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Max size unit" });
+ const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Unit for the maximum size" });
expect(maxSizeUnitSelector).toHaveValue("TiB");
});
@@ -144,10 +144,10 @@ it("calls the onSubmit callback with resulting volume when the form is submitted
await user.click(rangeSize);
const minSizeInput = screen.getByRole("textbox", { name: "Minimum desired size" });
- const minSizeUnitSelector = screen.getByRole("combobox", { name: "Min size unit" });
+ const minSizeUnitSelector = screen.getByRole("combobox", { name: "Unit for the minimum size" });
const minSizeGiBUnit = within(minSizeUnitSelector).getByRole("option", { name: "GiB" });
const maxSizeInput = screen.getByRole("textbox", { name: "Maximum desired size" });
- const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Max size unit" });
+ const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Unit for the maximum size" });
const maxSizeGiBUnit = within(maxSizeUnitSelector).getByRole("option", { name: "GiB" });
await user.clear(minSizeInput);
@@ -216,10 +216,10 @@ describe("size validations", () => {
await user.click(rangeSize);
const minSizeInput = screen.getByRole("textbox", { name: "Minimum desired size" });
- const minSizeUnitSelector = screen.getByRole("combobox", { name: "Min size unit" });
+ const minSizeUnitSelector = screen.getByRole("combobox", { name: "Unit for the minimum size" });
const minSizeMiBUnit = within(minSizeUnitSelector).getByRole("option", { name: "MiB" });
const maxSizeInput = screen.getByRole("textbox", { name: "Maximum desired size" });
- const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Max size unit" });
+ const maxSizeUnitSelector = screen.getByRole("combobox", { name: "Unit for the maximum size" });
const maxSizeGiBUnit = within(maxSizeUnitSelector).getByRole("option", { name: "GiB" });
const maxSizeMiBUnit = within(maxSizeUnitSelector).getByRole("option", { name: "MiB" });
diff --git a/web/src/components/storage/ZFCPDiskForm.jsx b/web/src/components/storage/ZFCPDiskForm.jsx
index ca4bfed716..38fa508187 100644
--- a/web/src/components/storage/ZFCPDiskForm.jsx
+++ b/web/src/components/storage/ZFCPDiskForm.jsx
@@ -26,6 +26,8 @@ import {
Alert,
Form, FormGroup, FormSelect, FormSelectOption
} from "@patternfly/react-core";
+
+import { _ } from "~/i18n";
import { If } from "~/components/core";
import { noop } from "~/utils";
@@ -107,13 +109,13 @@ export default function ZFCPDiskForm({ id, luns = [], onSubmit = noop, onLoading
- The zFCP disk was not activated.
+
+ {_("The zFCP disk was not activated.")}
}
/>