diff --git a/.changeset/fn-013-i18n-lint-baseline.md b/.changeset/fn-013-i18n-lint-baseline.md new file mode 100644 index 0000000000..32f1ee84a2 --- /dev/null +++ b/.changeset/fn-013-i18n-lint-baseline.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Restore the production i18n catalog lint guardrail. +category: fix +dev: Adds a runLinter regression test and keeps all supported app catalogs structurally synchronized. diff --git a/docs/i18n-contributing.md b/docs/i18n-contributing.md index d9e82f03a1..7ba75f7a21 100644 --- a/docs/i18n-contributing.md +++ b/docs/i18n-contributing.md @@ -54,6 +54,17 @@ Any remaining user-facing copy must be localized with `t()` / `` and an specific files or a small cluster in `lint.ignore`, includes an `FNXC` rationale, and has a filed follow-up task that removes the ignore. The settings sections cluster is no longer deferred as of FN-6771; keep those files covered by lint. +The production catalog currently has a clean lint baseline: `pnpm i18n:lint` +must finish with `No issues found.`. Keep the executable regression alongside the +catalog tests so future shipping copy cannot reintroduce debt: + +```bash +pnpm --filter @fusion/i18n exec vitest run src/__tests__/i18n-lint-baseline.test.ts src/__tests__/i18n-gate-coverage.test.ts --silent=passed-only --reporter=dot +``` + +`i18n-lint-baseline.test.ts` imports the root `i18next.config.ts` and calls the +installed `runLinter` API directly. It therefore checks the same production +inputs as the CLI rather than relying on a mocked catalog or a source-text count. The `@fusion/i18n` regression tests also assert the lint-ignore scope and live catalog key parity so those guardrails cannot silently drift. diff --git a/packages/dashboard/app/components/ActiveAgentsPanel.tsx b/packages/dashboard/app/components/ActiveAgentsPanel.tsx index 5928f7e3a4..395d3eb0dd 100644 --- a/packages/dashboard/app/components/ActiveAgentsPanel.tsx +++ b/packages/dashboard/app/components/ActiveAgentsPanel.tsx @@ -164,7 +164,7 @@ function LiveAgentCard({ agent, projectId, onSelect, onOpenTaskLogs, activity }: {(activity?.summary || lastCompletedStep) && (
{activity?.summary &&
{activity.summary}
} - {lastCompletedStep &&
Last completed Step {lastCompletedStep.index}: {lastCompletedStep.step.name}
} + {lastCompletedStep &&
{t("agents.lastCompletedStep", "Last completed Step {{index}}: {{name}}", { index: lastCompletedStep.index, name: lastCompletedStep.step.name })}
}
)}
diff --git a/packages/dashboard/app/components/AgentDetailView.tsx b/packages/dashboard/app/components/AgentDetailView.tsx index 134585f265..748b179e33 100644 --- a/packages/dashboard/app/components/AgentDetailView.tsx +++ b/packages/dashboard/app/components/AgentDetailView.tsx @@ -1337,7 +1337,7 @@ export function AgentDetailView({ agentId, projectId, onClose, addToast, onChild ); if (inline) { - return
{detailContent}
; + return
{detailContent}
; } return ( diff --git a/packages/dashboard/app/components/Board.tsx b/packages/dashboard/app/components/Board.tsx index f81db38c7c..9dbe5a15d9 100644 --- a/packages/dashboard/app/components/Board.tsx +++ b/packages/dashboard/app/components/Board.tsx @@ -5,6 +5,8 @@ import "./Lane.css"; import "./Board.css"; import type { ToastType } from "../hooks/useToast"; import { useState, useMemo, useEffect, useCallback, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import type { TFunction } from "i18next"; import { createPortal } from "react-dom"; import { promoteTask, type ModelInfo, type BoardWorkflowsPayload, type BoardWorkflowColumn, type RevertTaskOptions, type RevertTaskResult } from "../api"; import { useBlockerFanout, type BlockerFanoutColumnFlags } from "../hooks/useBlockerFanout"; @@ -146,9 +148,9 @@ export { ALL_WORKFLOWS_BOARD_VIEW_ID } from "../utils/boardWorkflowSelection"; type AggregateBoardColumn = BoardWorkflowColumn & { sourceWorkflowIds: string[] }; type AggregateQuickCreateTarget = { columnId: string; workflowId: string }; -function BoardWorkflowSkeleton({ empty = false }: { empty?: boolean }) { +function BoardWorkflowSkeleton({ empty = false, t }: { empty?: boolean; t: TFunction<"app"> }) { return ( -
+
{[0, 1, 2].map((index) => (