Repository: trussworks/react-uswds (ts)

Issue:
[fix] StepIndicator has hard-coded English status "[not] completed"
**ReactUSWDS Version & USWDS Version:**

react-uswds v9

**Describe the bug**

The StepIndicator has English "completed" and "not completed" hard-coded in its `sr-only` span, preventing i18n

**To Reproduce**
Steps to reproduce the behavior:

1. Use screen reader on an otherwise non-English page
2. Scan a step indicator with mixed statuses
3. Hear English words despite translators' best work

**Expected behavior**

A new `statusText` prop to pass in for these words

**Additional context**
#1742

Pull request description:
fix: add a statusText prop to StepIndicator to allow for i18n for the sr-only element Closes #2857
# Summary

Incorporates the option to use i18n for screen-reader only text regarding the status of each step in the StepIndicator. Updates tests and storybook.

## Related Issues or PRs

<!-- Link existing Github issue(s), e.g. closes #123 -->

Closes #2857 

## How To Test

<!-- Describe how a reviewer could test or verify your changes. -->
`yarn storybook`

In the 'Controls', create a `statusText` object (ex. {complete: "completado", incomplete: "no completado"}). 
Using a screen reader, listen to the stated status of each step. 
AND/OR
Look at the source code in the developer tools for each of the steps and see the sr-only element with the applied status text.

<!-- Does this change fix an issue or bug in an application you work on? Make sure you've tested this branch in your application to verify it works before merging & releasing. -->

### Screenshots (optional)


Patch:
diff --git a/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx b/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx
index 2c55610..06ab7ef 100644
--- a/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx
+++ b/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx
@@ -1,6 +1,6 @@
 import React from 'react'
 import { StepIndicatorStep } from '../StepIndicatorStep/StepIndicatorStep'
-import { StepIndicator } from '../StepIndicator/StepIndicator'
+import { StepIndicator, StepStatusText } from '../StepIndicator/StepIndicator'
 
 export default {
   title: 'Components/Step Indicator',
@@ -35,6 +35,7 @@ Updates users on their progress through a multi-step process.
 type StorybookArguments = {
   stepText: string
   ofText: string
+  statusText: StepStatusText
 }
 
 export const DefaultStepIndicator = (
@@ -43,7 +44,8 @@ export const DefaultStepIndicator = (
   <StepIndicator
     headingLevel="h4"
     ofText={args.ofText}
-    stepText={args.stepText}>
+    stepText={args.stepText}
+    statusText={args.statusText}>
     <StepIndicatorStep label="Personal information" status="complete" />
     <StepIndicatorStep label="Household status" status="complete" />
     <StepIndicatorStep label="Supporting documents" status="current" />
@@ -57,7 +59,8 @@ export const NoLabels = (args: StorybookArguments): React.ReactElement => (
     showLabels={false}
     headingLevel="h4"
     ofText={args.ofText}
-    stepText={args.stepText}>
+    stepText={args.stepText}
+    statusText={args.statusText}>
     <StepIndicatorStep label="Personal information" status="complete" />
     <StepIndicatorStep label="Household status" status="complete" />
     <StepIndicatorStep label="Supporting documents" status="current" />
@@ -71,7 +74,8 @@ export const Centered = (args: StorybookArguments): React.ReactElement => (
     centered
     headingLevel="h4"
     ofText={args.ofText}
-    stepText={args.stepText}>
+    stepText={args.stepText}
+    statusText={args.statusText}>
     <StepIndicatorStep label="Personal information" status="complete" />
     <StepIndicatorStep label="Household status" status="complete" />
     <StepIndicatorStep label="Supporting documents" status="current" />
@@ -85,7 +89,8 @@ export const Counters = (args: StorybookArguments): React.ReactElement => (
     counters="default"
     headingLevel="h4"
     ofText={args.ofText}
-    stepText={args.stepText}>
+    stepText={args.stepText}
+    statusText={args.statusText}>
     <StepIndicatorStep label="Personal information" status="complete" />
     <StepIndicatorStep label="Household status" status="complete" />
     <StepIndicatorStep label="Supporting documents" status="current" />
@@ -99,7 +104,8 @@ export const SmallCounters = (args: StorybookArguments): React.ReactElement => (
     counters="small"
     headingLevel="h4"
     ofText={args.ofText}
-    stepText={args.stepText}>
+    stepText={args.stepText}
+    statusText={args.statusText}>
     <StepIndicatorStep label="Personal information" status="complete" />
     <StepIndicatorStep label="Household status" status="complete" />
     <StepIndicatorStep label="Supporting documents" status="current" />
@@ -114,7 +120,8 @@ export const DifferentHeadingLevel = (
   <StepIndicator
     headingLevel="h2"
     ofText={args.ofText}
-    stepText={args.stepText}>
+    stepText={args.stepText}
+    statusText={args.statusText}>
     <StepIndicatorStep label="Personal information" status="complete" />
     <StepIndicatorStep label="Household status" status="complete" />
     <StepIndicatorStep label="Supporting documents" status="current" />
diff --git a/src/components/stepindicator/StepIndicator/StepIndicator.tsx b/src/components/stepindicator/StepIndicator/StepIndicator.tsx
index 9dd8390..72dc4b7 100644
--- a/src/components/stepindicator/StepIndicator/StepIndicator.tsx
+++ b/src/components/stepindicator/StepIndicator/StepIndicator.tsx
@@ -3,6 +3,11 @@ import classnames from 'classnames'
 import { StepIndicatorStepProps } from '../StepIndicatorStep/StepIndicatorStep'
 import { HeadingLevel } from '../../../types/headingLevel'
 
+export type StepStatusText = {
+  complete: string
+  incomplete: string
+}
+
 type StepIndicatorProps = {
   showLabels?: boolean
   counters?: 'none' | 'default' | 'small'
@@ -18,6 +23,7 @@ type StepIndicatorProps = {
   headingLevel: HeadingLevel
   stepText?: string
   ofText?: string
+  statusText?: StepStatusText
 }
 export const StepIndicator = (
   props: StepIndicatorProps
@@ -34,6 +40,7 @@ export const StepIndicator = (
     headingLevel,
     stepText = 'Step',
     ofText = 'of',
+    statusText = { complete: 'completed', incomplete: 'not completed' },
   } = props
 
   const Heading = headingLevel
@@ -76,6 +83,10 @@ export const StepIndicator = (
   const currentStepLabel = children[parseInt(`${currentStepIndex}`)].props.label
   const totalNumberOfSteps = children.length
 
+  const stepChildren = React.Children.map(children, (child) =>
+    React.cloneElement(child, { statusText: statusText })
+  )
+
   return (
     <div
       className={divClasses}
@@ -83,7 +94,7 @@ export const StepIndicator = (
       aria-label="progress"
       {...remainingDivProps}>
       <ol className={listClasses} {...remainingListProps}>
-        {children}
+        {stepChildren}
       </ol>
       <div className="usa-step-indicator__header">
         <Heading className={headingClasses} {...remainingHeadingProps}>
diff --git a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx
index 8f29df0..ac157bb 100644
--- a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx
+++ b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx
@@ -1,16 +1,25 @@
 import classnames from 'classnames'
 import React from 'react'
 
+import { StepStatusText } from '../StepIndicator/StepIndicator'
+
 export interface StepIndicatorStepProps {
   label: string
   status?: 'complete' | 'current' | 'incomplete'
+  statusText?: StepStatusText
   className?: string
 }
 
 export const StepIndicatorStep = (
   props: StepIndicatorStepProps & JSX.IntrinsicElements['li']
 ): React.ReactElement => {
-  const { label, status = 'incomplete', className, ...liProps } = props
+  const {
+    label,
+    status = 'incomplete',
+    statusText = { complete: 'completed', incomplete: 'not completed' },
+    className,
+    ...liProps
+  } = props
 
   const classes = classnames(
     'usa-step-indicator__segment',
@@ -30,8 +39,10 @@ export const StepIndicatorStep = (
         {label}
         &nbsp;
         {status !== 'current' && (
-          <span className="usa-sr-only">
-            {status === 'complete' ? 'completed' : 'not completed'}
+          <span data-testid="srStatusText" className="usa-sr-only">
+            {status === 'complete'
+              ? statusText.complete
+              : statusText.incomplete}
           </span>
         )}
       </span>


Test patch:
diff --git a/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx b/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx
index 178434d..57cdf58 100644
--- a/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx
+++ b/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx
@@ -196,4 +196,26 @@ describe('StepIndicator component', () => {
     const stepSrOnly = within(stepIndicator).queryByText(stepText)
     expect(stepSrOnly).toHaveClass('usa-sr-only')
   })
+  it('renders properly with translated statusText for screen reader', () => {
+    const statusText = { complete: 'completado', incomplete: 'no completado' }
+
+    const { getByTestId } = render(
+      <StepIndicator headingLevel="h4" statusText={statusText}>
+        <StepIndicatorStep label={step1} status="complete" />
+        <StepIndicatorStep label={step2} status="current" />
+        <StepIndicatorStep label={step3} status="incomplete" />
+      </StepIndicator>
+    )
+    const stepIndicator = getByTestId('step-indicator')
+
+    const completedStatusSrOnly = within(stepIndicator).queryByText(
+      statusText.complete
+    )
+    expect(completedStatusSrOnly).toHaveClass('usa-sr-only')
+
+    const incompleteStatusSrOnly = within(stepIndicator).queryByText(
+      statusText.incomplete
+    )
+    expect(incompleteStatusSrOnly).toHaveClass('usa-sr-only')
+  })
 })
diff --git a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx
index 66a28f8..603adf9 100644
--- a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx
+++ b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx
@@ -12,14 +12,26 @@ describe('Step component', () => {
   })
 
   it('renders with incomplete status', () => {
-    const { getByRole, queryByText } = render(
+    const { getByRole, queryByText, queryByTestId } = render(
       <StepIndicatorStep label="Test Step" status="incomplete" />
     )
     expect(queryByText('Test Step')).toBeInTheDocument()
-    expect(queryByText('not completed')).toHaveClass('usa-sr-only')
+    expect(queryByTestId('srStatusText')).toHaveClass('usa-sr-only')
+    expect(queryByTestId('srStatusText')).toHaveTextContent('not completed')
     expect(getByRole('listitem')).toHaveClass('usa-step-indicator__segment')
   })
 
+  it('renders incomplete status with alternative language in screen reader element', () => {
+    const { queryByTestId } = render(
+      <StepIndicatorStep
+        label="Test Step"
+        status="incomplete"
+        statusText={{ complete: 'completado', incomplete: 'no completado' }}
+      />
+    )
+    expect(queryByTestId('srStatusText')).toHaveTextContent('no completado')
+  })
+
   it('renders with current status', () => {
     const { getByRole, queryByText } = render(
       <StepIndicatorStep label="Test Step" status="current" />
@@ -31,13 +43,25 @@ describe('Step component', () => {
   })
 
   it('renders with complete status', () => {
-    const { getByRole, queryByText } = render(
+    const { getByRole, queryByText, queryByTestId } = render(
       <StepIndicatorStep label="Test Step" status="complete" />
     )
     expect(queryByText('Test Step')).toBeInTheDocument()
-    expect(queryByText('completed')).toHaveClass('usa-sr-only')
+    expect(queryByTestId('srStatusText')).toHaveClass('usa-sr-only')
+    expect(queryByTestId('srStatusText')).toHaveTextContent('completed')
     expect(getByRole('listitem')).toHaveClass(
       'usa-step-indicator__segment usa-step-indicator__segment--complete'
     )
   })
+
+  it('renders complete status with alternative language in screen reader element', () => {
+    const { queryByTestId } = render(
+      <StepIndicatorStep
+        label="Test Step"
+        status="complete"
+        statusText={{ complete: 'completado', incomplete: 'no completado' }}
+      />
+    )
+    expect(queryByTestId('srStatusText')).toHaveTextContent('completado')
+  })
 })