FN-6822: add dashboard i18n accessible-name fallbacks

Ensure dashboard accessibility labels render English defaults when i18n catalogs are unavailable.

- Add inline default text for the dashboard loader status label.
- Reuse the stash copy-reference fallback label for button accessibility and initial focus targeting.

Files changed:
 packages/dashboard/app/components/DashboardLoader.tsx    | 10 +++++++++-
 packages/dashboard/app/components/StashConflictModal.tsx | 12 +++++++++---
 2 files changed, 18 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6822

Fusion-Task-Lineage: 5057b051-43bd-467c-87b7-9ce86522c0c3
This commit is contained in:
gsxdsm
2026-06-21 02:02:19 -07:00
parent 19d60480db
commit 9d55f29c7a
2 changed files with 18 additions and 4 deletions

View File

@@ -75,12 +75,20 @@ export function DashboardLoader({ stage }: DashboardLoaderProps) {
return versionUpdated;
});
/**
* FNXC:DashboardI18n 2026-06-20-23:20:
* FN-6822 requires the loader status region accessible name to carry inline English defaults so backend-less test i18next and pre-catalog first paint render the localized label instead of the raw key.
*/
const statusLabel = isVersionUpdate
? t("dashboard.updatingMessage", "Updating Fusion dashboard")
: t("dashboard.loadingMessage", "Loading Fusion dashboard");
return (
<div
className="dashboard-loader"
role="status"
aria-live="polite"
aria-label={isVersionUpdate ? t("dashboard.updatingMessage") : t("dashboard.loadingMessage")}
aria-label={statusLabel}
data-stage={stage}
data-version-update={isVersionUpdate ? "true" : undefined}
>

View File

@@ -85,6 +85,12 @@ export default function StashConflictModal({
const [error, setError] = useState<string | null>(null);
const [copyState, setCopyState] = useState<"idle" | "copied" | "failed">("idle");
/**
* FNXC:StashConflictModalI18n 2026-06-20-23:22:
* FN-6822 requires the copy-reference accessible name to use the same inline English default for both the rendered button and the initial-focus selector so backend-less i18next does not expose raw keys or break focus targeting.
*/
const copyReferenceLabel = t("stash.copyReference", "Copy stash reference");
useEffect(() => {
if (open) {
setRemainingConflicts(autostashOutcome === "failed" ? [] : conflictedFiles);
@@ -103,7 +109,7 @@ export default function StashConflictModal({
const modalElement = modalRef.current;
if (modalElement) {
const focusable = getFocusableElements(modalElement);
const preferred = focusable.find((element) => element.getAttribute("aria-label") === t("stash.copyReference")) ?? focusable[0];
const preferred = focusable.find((element) => element.getAttribute("aria-label") === copyReferenceLabel) ?? focusable[0];
if (preferred) {
preferred.focus();
} else {
@@ -156,7 +162,7 @@ export default function StashConflictModal({
}
previousFocusRef.current = null;
};
}, [open, onClose]);
}, [copyReferenceLabel, open, onClose]);
const stashDescriptor = useMemo(() => `Stash ref: ${shortSha(stashSha)} (${stashLabel})`, [stashLabel, stashSha]);
@@ -241,7 +247,7 @@ export default function StashConflictModal({
) : null}
<div className="stash-conflict-modal__stash-row">
<span>{stashDescriptor}</span>
<button type="button" className="btn btn-sm btn-icon" onClick={copyRef} aria-label={t("stash.copyReference")}>
<button type="button" className="btn btn-sm btn-icon" onClick={copyRef} aria-label={copyReferenceLabel}>
<Copy aria-hidden="true" />
</button>
</div>