Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate the storage texts #726

Merged
merged 2 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions web/src/components/core/InstallButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<p className="bold">
Expand Down
6 changes: 4 additions & 2 deletions web/src/components/core/Popup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import React, { useLayoutEffect } from "react";
import { Button, Modal } from "@patternfly/react-core";

import { _ } from "~/i18n";
import { partition } from "~/utils";

/**
Expand Down Expand Up @@ -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 }) => (
<PrimaryAction key="confirm" { ...props }>{ children }</PrimaryAction>
);

Expand Down Expand Up @@ -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 }) => (
<SecondaryAction key="cancel" { ...props }>{ children }</SecondaryAction>
);

Expand Down
6 changes: 4 additions & 2 deletions web/src/components/storage/DASDFormatProgress.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -56,15 +58,15 @@ export default function DASDFormatProgress({ job, devices, isOpen = true }) {

const WaitingProgress = () => (
<div className="stack">
<div>Waiting for progress report</div>
<div>{_("Waiting for progress report")}</div>
<Skeleton height="10px" />
<Skeleton height="10px" />
</div>
);

return (
<Popup
title="Formatting DASD devices"
title={_("Formatting DASD devices")}
isOpen={isOpen}
disableFocusTrap
>
Expand Down
7 changes: 5 additions & 2 deletions web/src/components/storage/DASDPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -179,9 +181,10 @@ export default function DASDPage() {
}, [client.dasd]);

return (
<Page title="Storage DASD" icon="hard_drive">
// TRANSLATORS: DASD = Direct Access Storage Device, IBM mainframe storage technology
<Page title={_("Storage DASD")} icon="hard_drive">
<MainActions>
<Button isLarge variant="secondary" onClick={() => navigate("/storage")}>Back</Button>
<Button isLarge variant="secondary" onClick={() => navigate("/storage")}>{_("Back")}</Button>
</MainActions>

<DASDTable state={state} dispatch={dispatch} />
Expand Down
47 changes: 27 additions & 20 deletions web/src/components/storage/DASDTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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 }) => {
Expand Down Expand Up @@ -97,17 +98,23 @@ const Actions = ({ devices, isDisabled }) => {
isOpen={isOpen}
onSelect={onSelect}
dropdownItems={[
<Action key="activate" onClick={activate}>Activate</Action>,
<Action key="deactivate" onClick={deactivate}>Deactivate</Action>,
// TRANSLATORS: drop down menu action, activate the device
<Action key="activate" onClick={activate}>{_("Activate")}</Action>,
// TRANSLATORS: drop down menu action, deactivate the device
<Action key="deactivate" onClick={deactivate}>{_("Deactivate")}</Action>,
<DropdownSeparator key="first-separator" />,
<Action key="set_diag_on" onClick={setDiagOn}>Set DIAG On</Action>,
<Action key="set_diag_off" onClick={setDiagOff}>Set DIAG Off</Action>,
// TRANSLATORS: drop down menu action, enable DIAG access method
<Action key="set_diag_on" onClick={setDiagOn}>{_("Set DIAG On")}</Action>,
// TRANSLATORS: drop down menu action, disable DIAG access method
<Action key="set_diag_off" onClick={setDiagOff}>{_("Set DIAG Off")}</Action>,
<DropdownSeparator key="second-separator" />,
<Action key="format" onClick={format}>Format</Action>
// TRANSLATORS: drop down menu action, format the disk
<Action key="format" onClick={format}>{_("Format")}</Action>
]}
toggle={
<DropdownToggle toggleVariant="primary" isDisabled={isDisabled} onToggle={onToggle}>
Perform an action
{/* TRANSLATORS: drop down menu label */}
{_("Perform an action")}
</DropdownToggle>
}
/>
Expand Down Expand Up @@ -185,15 +192,15 @@ export default function DASDTable({ state, dispatch }) {
<TextInputGroupMain
value={state.minChannel}
type="text"
aria-label="Filter by min channel"
placeholder="Filter by min channel"
aria-label={_("Filter by min channel")}
placeholder={_("Filter by min channel")}
onChange={onMinChannelFilterChange}
/>
{ state.minChannel !== "" &&
<TextInputGroupUtilities>
<Button
variant="plain"
aria-label="Remove min channel filter"
aria-label={_("Remove min channel filter")}
onClick={removeMinChannelFilter}
>
<Icon name="backspace" size="24" />
Expand All @@ -206,15 +213,15 @@ export default function DASDTable({ state, dispatch }) {
<TextInputGroupMain
value={state.maxChannel}
type="text"
aria-label="Filter by max channel"
placeholder="Filter by max channel"
aria-label={_("Filter by max channel")}
placeholder={_("Filter by max channel")}
onChange={onMaxChannelFilterChange}
/>
{ state.maxChannel !== "" &&
<TextInputGroupUtilities>
<Button
variant="plain"
aria-label="Remove max channel filter"
aria-label={_("Remove max channel filter")}
onClick={removeMaxChannelFilter}
>
<Icon name="backspace" size="24" />
Expand Down
27 changes: 20 additions & 7 deletions web/src/components/storage/DeviceSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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 (
<div>
Expand All @@ -182,7 +193,9 @@ const ItemContent = ({ device }) => {
};

const NotFound = () => {
return <div><Icon name="folder_off" size="14" /> No content found</div>;
// TRANSLATORS: status message, no existing content was found on the disk,
// i.e. the disk is completely empty
return <div><Icon name="folder_off" size="14" /> {_("No content found")}</div>;
};

const hasContent = device.partitionTable || device.systems.length > 0;
Expand Down Expand Up @@ -230,7 +243,7 @@ export default function DeviceSelector ({ selected, devices = [], onSelect = noo
};

return (
<ListBox aria-label="Available devices" className="stack device-selector">
<ListBox aria-label={_("Available devices")} className="stack device-selector">
{ devices.map(device => (
<ListBoxItem
key={device.sid}
Expand Down
6 changes: 4 additions & 2 deletions web/src/components/storage/ISCSIPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import React from "react";
import { useNavigate } from "react-router-dom";
import { Button } from "@patternfly/react-core";

import { _ } from "~/i18n";
import { Title as PageTitle, MainActions } from "~/components/layout";
import { InitiatorSection, TargetsSection } from "~/components/storage/iscsi";

Expand All @@ -31,10 +32,11 @@ export default function ISCSIPage() {

return (
<>
<PageTitle>Storage iSCSI</PageTitle>
{/* TRANSLATORS: page title for iSCSI configuration */}
<PageTitle>{_("Storage iSCSI")}</PageTitle>
<MainActions>
<Button isLarge variant="secondary" form="storage-config" onClick={() => navigate("/storage")}>
Back
{_("Back")}
</Button>
</MainActions>

Expand Down
15 changes: 11 additions & 4 deletions web/src/components/storage/ProposalActionsSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 (
<>
<Text>
Actions to create the file systems and to ensure the system boots.
{_("Actions to create the file systems and to ensure the system boots.")}
</Text>
<ActionsList actions={generalActions} />
{subvolActions.length > 0 && (
Expand Down Expand Up @@ -116,7 +121,9 @@ export default function ProposalActionsSection({ actions = [], errors = [], isLo
if (isLoading) errors = [];

return (
<Section title="Planned Actions" errors={errors}>
// TRANSLATORS: section title, list of planned actions for the selected device,
// e.g. "delete partition A", "create partition B with filesystem C", ...
<Section title={_("Planned Actions")} errors={errors}>
<If
condition={isLoading}
then={<ActionsSkeleton />}
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/storage/ProposalActionsSection.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ describe("when there are actions", () => {
<ProposalActionsSection actions={[...actions, ...subvolumeActions]} />
);

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.
Expand Down
6 changes: 4 additions & 2 deletions web/src/components/storage/ProposalPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -146,7 +147,7 @@ export default function ProposalPage() {
<Alert
isInline
customIcon={<Icon name="info" size="16" />}
title="Devices will not be modified until installation starts."
title={_("Devices will not be modified until installation starts.")}
/>
<ProposalSettingsSection
availableDevices={state.availableDevices}
Expand All @@ -165,7 +166,8 @@ export default function ProposalPage() {
};

return (
<Page title="Storage" icon="hard_drive" actionLabel="Back" actionVariant="secondary">
// TRANSLATORS: page title
<Page title={_("Storage")} icon="hard_drive" actionLabel={_("Back")} actionVariant="secondary">
<PageContent />
<ProposalPageOptions />
</Page>
Expand Down
Loading
Loading