refactor: consolidate English translations (#6640)

This commit is contained in:
Thomas authored and GitHub committed 2026-08-21 19:00:27 +02:00
1 parent 81aa704537
commit 9e14a07e64
449 files changed
+3515 -3922

No files matched your search

@@ -40,7 +40,7 @@ import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client";
import { backgroundImageAttachments, backgroundImageRepeats, backgroundImageSizes } from "@homarr/definitions";
import { useZodForm } from "@homarr/form";
import { useI18n, useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
import { boardSavePartialSettingsSchema } from "@homarr/validation/board";
import {
@@ -97,7 +97,8 @@ export const AssistantConfigureBoardSettingsTool = ({
status,
toolCallId,
}: ToolCallMessagePartProps<ConfigureBoardSettingsArgs, ConfigureBoardSettingsResult>) => {
const t = useScopedI18n("common.assistant.configureBoardSettings");
const t = useI18n("assistant.configureBoardSettings");
const actionT = useI18n("common.action");
const hasCompleteArguments = hasCompleteAssistantToolArguments(status);
const boardId = args?.boardId ?? "";
const settings = clientApi.board.getBoardSettings.useQuery(
@@ -150,7 +151,7 @@ export const AssistantConfigureBoardSettingsTool = ({
<Stack gap="sm">
<Text size="sm">{t("loadErrorDescription")}</Text>
<Button variant="light" color="red" size="compact-sm" w="fit-content" onClick={() => settings.refetch()}>
{t("retry")}
{actionT("tryAgain")}
</Button>
</Stack>
</Alert>
@@ -199,7 +200,8 @@ const BoardSettingsForm = ({
onSubmit: (changes: AssistantBoardSettingsChanges) => void;
onCancel: () => void;
}) => {
const t = useScopedI18n("common.assistant.configureBoardSettings");
const t = useI18n("assistant.configureBoardSettings");
const actionT = useI18n("common.action");
const boardT = useI18n();
const [submitting, setSubmitting] = useState(false);
const currentValues = useMemo(() => toCurrentValues(current), [current]);
@@ -297,7 +299,7 @@ const BoardSettingsForm = ({
leftSection={copied ? <IconCheck size={14} /> : <IconCopy size={14} />}
onClick={copy}
>
{copied ? t("copied") : t("copy")}
{copied ? t("copied") : actionT("copy")}
</Button>
</Tooltip>
)}
@@ -4,7 +4,7 @@ import type { PropsWithChildren } from "react";
import { useMemo } from "react";
import dynamic from "next/dynamic";
import { useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
import { AssistantWidgetRendererProvider } from "@homarr/widgets/assistant/context";
import { AssistantContext } from "./assistant-context";
@@ -73,7 +73,7 @@ const unavailableMessageKeys = {
} as const;
export const AssistantGate = ({ availability, children }: AssistantGateProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
if (availability === "enabled") {
return <EnabledAssistantRoot>{children}</EnabledAssistantRoot>;
@@ -26,7 +26,7 @@ import {
import type { z } from "zod/v4";
import { AppForm } from "@homarr/forms-collection";
import { useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
import type { appManageSchema } from "@homarr/validation/app";
import { getAssistantAskUserOptionKind } from "./assistant-ask-user";
@@ -54,7 +54,7 @@ export const getAssistantAppFormValues = (
) => (hasCompleteAssistantToolArguments(status) ? toAssistantAppValues(args) : null);
export const AssistantHumanToolError = () => {
const t = useScopedI18n("common.assistant.toolPreparationError");
const t = useI18n("assistant.toolPreparationError");
return (
<Alert color="red" variant="light" title={t("title")} icon={<IconAlertTriangle size={18} />}>
{t("description")}
@@ -68,7 +68,7 @@ export const AssistantAskUserTool = ({
addResult,
status,
}: ToolCallMessagePartProps<AskUserArgs, AskUserResult>) => {
const t = useScopedI18n("common.assistant.askUser");
const t = useI18n("assistant.askUser");
const [showOther, setShowOther] = useState(false);
const [other, setOther] = useState("");
const [submitting, setSubmitting] = useState(false);
@@ -272,7 +272,7 @@ export const AssistantConfigureAppTool = ({
status,
toolCallId,
}: ToolCallMessagePartProps<ConfigureAppArgs, AppValues>) => {
const t = useScopedI18n("common.assistant.configureApp");
const t = useI18n("assistant.configureApp");
const [submitting, setSubmitting] = useState(false);
const initialValues = getAssistantAppFormValues(args, status);
const autoConfirming = useAssistantAutomaticAction({
@@ -131,7 +131,7 @@ import { assistantProviderIds, assistantProviderPresets, assistantReasoningModes
import type { AssistantProvider } from "@homarr/definitions";
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
import { useConfirmModal } from "@homarr/modals";
import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useI18n } from "@homarr/translation/client";
import classes from "./assistant-panel.module.css";
import { getAssistantActivityState } from "./assistant-activity-state";
@@ -218,7 +218,7 @@ const ContextDirectiveChip = ({
label,
iconUrl,
}: DirectiveChipProps & { iconUrl?: string }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const Icon = contextIcons[directiveType as keyof typeof contextIcons] ?? IconAt;
const safeIconUrl = getSafeAssistantMarkdownImageSource(iconUrl);
const translationKey = getAssistantDirectiveTranslationKey(directiveType);
@@ -291,7 +291,7 @@ const MarkdownTable = ({ children, ...props }: ComponentPropsWithoutRef<"table">
);
const MarkdownImage = ({ src, alt = "", ...props }: ComponentPropsWithoutRef<"img">) => {
const t = useScopedI18n("common.assistant.image");
const t = useI18n("assistant.image");
const safeSource = getSafeAssistantMarkdownImageSource(src);
if (!safeSource) return null;
@@ -343,7 +343,7 @@ const AssistantSyntaxHighlighter = ({ code, components, language }: SyntaxHighli
};
const MermaidDiagram = ({ code, components }: SyntaxHighlighterProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const colorScheme = useComputedColorScheme("light");
const diagramId = `assistant-mermaid-${useId().replaceAll(/[^A-Za-z0-9_-]/gu, "")}`;
const [rendered, setRendered] = useState<{ code: string; svg?: string; failed?: boolean }>({ code });
@@ -541,7 +541,7 @@ const AttachmentPreview = () => {
};
const Attachment = ({ removable = false }: { removable?: boolean }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const attachment = useAuiState((state) => state.attachment);
return (
<AttachmentPrimitive.Root className={classes.attachment}>
@@ -583,7 +583,7 @@ const ReasoningPart = (_props: ReasoningMessagePartProps) => (
);
const AssistantMessagePending = ({ status }: EmptyMessagePartProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
if (status.type !== "running") return null;
return (
@@ -622,7 +622,7 @@ const SourcePart = (source: SourceMessagePartProps) => {
};
const FilePart = ({ data, filename, mimeType }: FileMessagePartProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const downloadable = data.startsWith("data:");
const displayName = filename ?? mimeType;
return (
@@ -649,7 +649,7 @@ const FilePart = ({ data, filename, mimeType }: FileMessagePartProps) => {
};
const ImagePart = ({ image, filename }: ImageMessagePartProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const source = getSafeAssistantAttachmentImageSource(
image,
typeof window === "undefined" ? undefined : window.location.origin,
@@ -814,7 +814,7 @@ const getToolResultNavigation = (result: unknown) => {
};
const ToolResultNavigation = ({ result }: { result: unknown }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const router = useRouter();
const links = getToolResultNavigation(result);
@@ -870,7 +870,7 @@ const ToolPart = ({
respondToApproval,
timing,
}: ToolCallMessagePartProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const compact = useContext(AgentTraceToolContext);
const [opened, setOpened] = useState(false);
const [approvalResponse, setApprovalResponse] = useState<"approve" | "deny" | null>(null);
@@ -1048,7 +1048,7 @@ const ChainOfThoughtLayout = ({ children }: { children?: ReactNode }) => (
);
const AssistantChainOfThought = ({ children }: { children?: ReactNode }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const contentId = useId();
const { collapsed: preferredCollapsed, setCollapsed: setPreferredCollapsed } = useContext(ReasoningVisibilityContext);
const { chainStatus, collapsed } = useAssistantReasoningState(preferredCollapsed);
@@ -1083,7 +1083,7 @@ const AssistantChainOfThought = ({ children }: { children?: ReactNode }) => {
};
const BranchPicker = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
return (
<BranchPickerPrimitive.Root hideWhenSingleBranch className={classes.branchPicker}>
<BranchPickerPrimitive.Previous asChild>
@@ -1116,7 +1116,7 @@ const downloadAssistantMarkdown = (markdown: string, filename: string) => {
};
const AssistantMessageActions = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const aui = useAui();
const exportMessage = () => {
const message = aui.message().getState();
@@ -1129,7 +1129,6 @@ const AssistantMessageActions = () => {
});
downloadAssistantMarkdown(markdown, `assistant-message-${message.id.slice(0, 8)}.md`);
};
return (
<Box className={classes.messageActions}>
<ActionBarPrimitive.Root
@@ -1211,7 +1210,7 @@ const AssistantMessageActions = () => {
};
const UserMessageActions = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
return (
<ActionBarPrimitive.Root hideWhenRunning autohide="not-last" className={classes.userActions}>
<Group gap={2}>
@@ -1235,14 +1234,15 @@ const UserMessageActions = () => {
};
const EditComposer = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const actionT = useI18n("common.action");
return (
<ComposerPrimitive.Root className={classes.editComposer}>
<ComposerPrimitive.Input className={classes.editComposerInput} rows={2} aria-label={t("editMessage")} />
<Group gap="xs" justify="flex-end">
<ComposerPrimitive.Cancel asChild>
<Button size="compact-sm" variant="default">
{t("cancelEdit")}
{actionT("cancel")}
</Button>
</ComposerPrimitive.Cancel>
<ComposerPrimitive.Send asChild>
@@ -1361,7 +1361,7 @@ const ConversationTurn = ({
threadId?: string;
turn: AssistantConversationTurnUsage;
}) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const detailsId = useId();
const [opened, setOpened] = useState(false);
const generationQuery = clientApi.assistant.getGenerationTelemetry.useQuery(
@@ -1657,7 +1657,7 @@ const ConversationTurn = ({
};
const ConversationContextBreakdown = ({ breakdown }: { breakdown: AssistantContextBreakdown }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const hasContext = breakdown.percentage !== undefined;
const categories = [
{ label: t("usage.input"), value: breakdown.inputTokens },
@@ -1715,7 +1715,7 @@ const ConversationContextBreakdown = ({ breakdown }: { breakdown: AssistantConte
};
const ConversationContext = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const [opened, setOpened] = useState(false);
const messages = useAuiState((state) => state.thread.messages);
const threadId = useAuiState((state) => state.threadListItem.remoteId);
@@ -1847,7 +1847,8 @@ const ConversationContext = () => {
);
};
const RuntimeError = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const actionT = useI18n("common.action");
return (
<MessagePrimitive.Error>
<ErrorPrimitive.Root className={classes.messageError}>
@@ -1868,7 +1869,7 @@ const RuntimeError = () => {
w="fit-content"
leftSection={<IconRefresh size={14} />}
>
{t("responseError.retry")}
{actionT("tryAgain")}
</Button>
</ActionBarPrimitive.Reload>
</Stack>
@@ -1879,7 +1880,7 @@ const RuntimeError = () => {
};
const WebSearchActivity = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const metadata = useAuiState((state) => state.message.metadata);
const telemetry = getAssistantTelemetry(metadata);
if (!telemetry) return null;
@@ -1997,7 +1998,8 @@ const assistantThreadMessageComponents = { UserMessage, AssistantMessage };
const HistorySelectContext = createContext<() => void>(() => undefined);
const ThreadListItem = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const actionT = useI18n("common.action");
const aui = useAui();
const { openConfirmModal } = useConfirmModal();
const onSelect = useContext(HistorySelectContext);
@@ -2057,7 +2059,7 @@ const ThreadListItem = () => {
title: t("deleteConversation.title"),
children: t("deleteConversation.description", { title: title ?? t("newConversation") }),
confirmProps: { color: "red" },
labels: { confirm: t("delete"), cancel: t("cancel") },
labels: { confirm: actionT("delete"), cancel: actionT("cancel") },
onConfirm: async () => {
try {
await aui.threadListItem().delete();
@@ -2103,7 +2105,7 @@ const ThreadListItem = () => {
variant="subtle"
color="gray"
size="sm"
aria-label={t("cancel")}
aria-label={actionT("cancel")}
disabled={renaming}
onClick={() => setRenameOpened(false)}
>
@@ -2154,8 +2156,8 @@ const ThreadListItem = () => {
variant="subtle"
color="red"
size="sm"
title={t("delete")}
aria-label={t("delete")}
title={actionT("delete")}
aria-label={actionT("delete")}
onClick={deleteConversation}
>
<IconTrash size={14} />
@@ -2179,7 +2181,7 @@ const ThreadListItem = () => {
};
const ThreadHistory = ({ onSelect }: { onSelect: () => void }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const [query, setQuery] = useState("");
const normalizedQuery = query.trim().toLocaleLowerCase();
const threadItems = useAuiState((state) => state.threads.threadItems);
@@ -2233,7 +2235,7 @@ const ThreadHistory = ({ onSelect }: { onSelect: () => void }) => {
};
const ConversationHistory = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const [opened, setOpened] = useState(false);
return (
<Popover
@@ -2272,7 +2274,7 @@ const ConversationHistory = () => {
};
const AutoApprovalControl = () => {
const t = useScopedI18n("common.assistant.autoApproval");
const t = useI18n("assistant.autoApproval");
const [opened, setOpened] = useState(false);
const { enabled, setEnabled } = useAssistantAutoApproval();
@@ -2331,7 +2333,7 @@ const ViewRefreshAction = ({
isRefreshing,
onRefresh,
}: Pick<AssistantConversationControls, "isRefreshing" | "onRefresh">) => {
const t = useScopedI18n("common.assistant.refresh");
const t = useI18n("assistant.refresh");
const refresh = async () => {
try {
@@ -2360,7 +2362,7 @@ const ViewRefreshAction = ({
};
const EmptyThread = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
return (
<ThreadPrimitive.Empty>
<Box className={classes.empty}>
@@ -2461,7 +2463,7 @@ const TriggerItem = ({ item, index }: { item: Unstable_TriggerItem; index: numbe
};
const ComposerTriggers = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const aui = useAui();
const mentionViewportRef = useRef<HTMLDivElement>(null);
const slashViewportRef = useRef<HTMLDivElement>(null);
@@ -2604,7 +2606,7 @@ const RuntimeControls = ({
onModelChange,
onReasoningChange,
}: ComposerProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const [modelSearch, setModelSearch] = useState("");
const selectedModel = models.find((model) => model.id === modelId);
const normalizedModelSearch = modelSearch.trim().toLocaleLowerCase();
@@ -2759,7 +2761,7 @@ const providerQuotaColors = {
} as const;
const HomarrProviderQuota = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const locale = useCurrentIntlLocale();
const preferences = useAssistantPreferences();
const quota = preferences.quota;
@@ -2882,7 +2884,7 @@ const HomarrProviderQuota = () => {
};
const Composer = (props: ComposerProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const preferences = useAssistantPreferences();
const running = useAuiState((state) => state.thread.isRunning);
const hasPendingAction = props.pendingAction !== undefined;
@@ -2987,7 +2989,7 @@ const Composer = (props: ComposerProps) => {
};
const usePendingActionCopy = (action: AssistantPendingAction | undefined) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
if (!action) return undefined;
if (action.kind === "question") {
return { title: t("pendingAction.answerTitle"), detail: action.detail ?? t("pendingAction.answerFallback") };
@@ -3004,7 +3006,7 @@ const usePendingActionCopy = (action: AssistantPendingAction | undefined) => {
};
const PendingActionBanner = ({ pendingAction }: { pendingAction: AssistantPendingAction | undefined }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const copy = usePendingActionCopy(pendingAction);
if (!copy || pendingAction?.kind === "question") return null;
@@ -3039,7 +3041,7 @@ const PendingQuestionDock = ({
pendingAction: AssistantPendingAction | undefined;
setTarget: (target: HTMLDivElement | null) => void;
}) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
if (pendingAction?.kind !== "question") return null;
return (
@@ -3073,7 +3075,7 @@ const AssistantActivityBar = ({
| "onDismissActivity"
| "activityDismissed"
>) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const pendingCopy = usePendingActionCopy(pendingAction);
const needsApproval = pendingAction !== undefined || latestStatus?.type === "requires-action";
const failed = latestStatus?.type === "incomplete" && latestStatus.reason !== "cancelled";
@@ -3161,7 +3163,7 @@ interface AssistantConversationSurfaceProps extends AssistantConversationControl
}
const AssistantPanelIdentity = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const threadTitle = useAuiState((state) => state.threadListItem.title);
return (
@@ -3197,7 +3199,7 @@ export const AssistantConversationSurface = ({
onMinimize,
onDismiss,
}: AssistantConversationSurfaceProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const reducedMotion = useReducedMotion();
const [questionPortalTarget, setQuestionPortalTarget] = useState<HTMLDivElement | null>(null);
const [reasoningCollapsed, setReasoningCollapsed] = useState(false);
@@ -3343,7 +3345,7 @@ export const AssistantPanel = ({
onModelChange,
onReasoningChange,
}: AssistantPanelProps) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const aui = useAui();
const previousFocusRef = useRef<HTMLElement | null>(null);
const panelRef = useRef<HTMLDialogElement>(null);
@@ -30,7 +30,7 @@ import { createId } from "@homarr/common";
import { assistantHomarrProviderTokenHeader, hotkeys } from "@homarr/definitions";
import { showErrorNotification, showWarningNotification } from "@homarr/notifications";
import { closeSpotlight } from "@homarr/spotlight/store";
import { useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
import { openMediaRequestSearch, openSpotlight, useRegisterSpotlightContextResults } from "@homarr/spotlight";
import { AssistantWidgetRendererProvider } from "@homarr/widgets";
import { createWorkshopClient } from "~/components/workshop/workshop-client";
@@ -135,7 +135,7 @@ const createAssistantAttachmentAdapter = (allowImages: boolean): AttachmentAdapt
};
const AssistantPreferencesProvider = ({ children }: PropsWithChildren) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const { data, isLoading } = clientApi.assistant.getRuntimeOptions.useQuery(undefined, {
staleTime: 10 * 60_000,
});
@@ -454,7 +454,7 @@ const createHistoryAdapter = (threadId: string | undefined): ThreadHistoryAdapte
});
const AssistantThreadRuntime = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const aui = useAui();
const localThreadId = useAuiState((state) => state.threadListItem.id);
const threadId = useAuiState((state) => state.threadListItem.remoteId);
@@ -652,7 +652,7 @@ const AssistantPreferenceSync = () => {
};
const AssistantRuntimeEvents = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
useAuiEvent("composer.attachmentAddError", ({ message }) => {
showErrorNotification({
title: t("attachments.errorTitle"),
@@ -679,7 +679,7 @@ const getNotificationKey = (message: ThreadMessage | undefined) => {
};
const EnabledAssistantProvider = ({ children }: PropsWithChildren) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const [opened, setOpened] = useState(false);
const [activityDismissed, setActivityDismissed] = useState(true);
const [unreadCount, setUnreadCount] = useState(0);
@@ -34,7 +34,7 @@ import {
} from "./assistant-runtime-provider";
vi.mock("@homarr/notifications", () => ({ showErrorNotification: vi.fn() }));
vi.mock("@homarr/translation/client", () => ({ useScopedI18n: () => (key: string) => key }));
vi.mock("@homarr/translation/client", () => ({ useI18n: () => (key: string) => key }));
(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
@@ -6,7 +6,7 @@ import type { AssistantRuntime, AttachmentAdapter, ThreadListRuntime, Toolkit }
import { AssistantRuntimeProvider, INTERNAL, Tools, useAui, useAuiEvent } from "@assistant-ui/react";
import { showErrorNotification } from "@homarr/notifications";
import { useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
interface AssistantRuntimeProviderWithToolsProps extends PropsWithChildren {
runtime: AssistantRuntime;
@@ -437,7 +437,7 @@ const getClipboardAttachmentName = (file: File, index: number) => {
};
const AssistantComposerSurfaceEvents = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
useAuiEvent("composer.attachmentAddError", ({ message }) => {
showErrorNotification({ title: t("attachments.errorTitle"), message });
});
@@ -445,7 +445,7 @@ const AssistantComposerSurfaceEvents = () => {
};
export const AssistantComposerSurfaceBoundary = ({ children, surfaceId }: PropsWithChildren<{ surfaceId: string }>) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const aui = useAui();
const instanceId = useId();
const resolvedSurfaceId = `${surfaceId}:${instanceId}`;
@@ -3,14 +3,14 @@
import { useMemo } from "react";
import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
import { useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
/**
* Keeps the assistant discoverable in the spotlight when it is unavailable, without loading the
* assistant runtime. Lives apart from `assistant-provider` so the disabled path stays cheap.
*/
export const useRegisterAssistantSpotlightPlaceholder = (description: string) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
const spotlightItem = useMemo(
() => ({
id: "homarr-assistant",
@@ -3,7 +3,7 @@
import { Group, Kbd, Stack, Text, ThemeIcon } from "@mantine/core";
import { IconArrowUp, IconRobot } from "@tabler/icons-react";
import { useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
interface AssistantPromptInteractionOptions {
sendPrompt: (prompt: string) => boolean;
@@ -13,7 +13,7 @@ interface AssistantPromptInteractionOptions {
}
const AssistantPromptDetail = () => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
return (
<Group px="md" py="sm" wrap="nowrap">
<ThemeIcon color="red" variant="light" radius="xl">
@@ -30,7 +30,7 @@ const AssistantPromptDetail = () => {
};
const AssistantPromptAction = ({ hasPrompt }: { hasPrompt: boolean }) => {
const t = useScopedI18n("common.assistant");
const t = useI18n("assistant");
return (
<Group w="100%" px="md" py="xs" justify="space-between" wrap="nowrap" opacity={hasPrompt ? 1 : 0.6}>
<Group gap="sm" wrap="nowrap">
@@ -7,11 +7,12 @@ import { IconAlertTriangle, IconCheck, IconSettings } from "@tabler/icons-react"
import { clientApi } from "@homarr/api/client";
import { useSession } from "@homarr/auth/client";
import { getWidgetName } from "@homarr/definitions";
import type { IntegrationKind } from "@homarr/definitions";
import { useModalAction } from "@homarr/modals";
import type { SettingsContextProps } from "@homarr/settings/creator";
import { useSettings } from "@homarr/settings";
import { useI18n, useScopedI18n } from "@homarr/translation/client";
import { useI18n } from "@homarr/translation/client";
import { reduceWidgetOptionsWithDefaultValues, widgetImports } from "@homarr/widgets";
import type { IntegrationSelectOption } from "@homarr/widgets/widget-integration-select";
import { WidgetEditModal } from "@homarr/widgets/modals";
@@ -66,7 +67,8 @@ export const AssistantConfigureWidgetTool = ({
status,
toolCallId,
}: ToolCallMessagePartProps<ConfigureWidgetArgs, ConfigureWidgetResult>) => {
const t = useScopedI18n("common.assistant.configureWidget");
const t = useI18n("assistant.configureWidget");
const actionT = useI18n("common.action");
const fullT = useI18n();
const { data: session } = useSession();
const settings = useSettings();
@@ -116,7 +118,7 @@ export const AssistantConfigureWidgetTool = ({
{cancelled ? t("cancelled") : t("ready")}
</Text>
<Text size="sm" fw={600} truncate>
{args?.kind ? fullT(`widget.${args.kind}.name`) : t("title")}
{args?.kind ? getWidgetName(args.kind, fullT) : t("title")}
</Text>
</Box>
</Box>
@@ -149,7 +151,7 @@ export const AssistantConfigureWidgetTool = ({
<Stack gap="sm">
<Text size="sm">{t("loadErrorDescription")}</Text>
<Button variant="light" color="red" size="compact-sm" w="fit-content" onClick={() => integrations.refetch()}>
{t("retry")}
{actionT("tryAgain")}
</Button>
</Stack>
</Alert>
@@ -174,7 +176,7 @@ export const AssistantConfigureWidgetTool = ({
addResult({ boardId: args.boardId, kind: args.kind, options, integrationIds }),
},
{
title: (titleT) => `${titleT("item.edit.title")} - ${titleT(`widget.${args.kind}.name`)}`,
title: (titleT) => `${titleT("item.edit.title")} - ${getWidgetName(args.kind, titleT)}`,
},
);
@@ -246,7 +248,7 @@ export const AssistantConfigureWidgetTool = ({
<WidgetIcon size={20} />
</ThemeIcon>
<Box miw={0} flex={1}>
<Text fw={700}>{fullT(`widget.${args.kind}.name`)}</Text>
<Text fw={700}>{getWidgetName(args.kind, fullT)}</Text>
<Text size="sm" c="dimmed">
{args.summary}
</Text>