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:
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user