feat: add Russian localization and independent STT languages
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
"use client";
|
||||
import { useI18n } from "@/components/i18n";
|
||||
|
||||
|
||||
import { CheckIcon, CircleX } from "lucide-react";
|
||||
import type { PdfResult, ResearchResult, SubagentArtifactData } from "@/src/core";
|
||||
@@ -26,6 +28,7 @@ import { VisualOutputCard } from "@/components/artifacts/visual-card";
|
||||
* render; only a failure note does.
|
||||
*/
|
||||
export function SubagentSteerCard({ message }: { message: LhViewMessage }) {
|
||||
const { t } = useI18n();
|
||||
const artifactPart = message.parts.find((p) => p.type === "data-subagent-artifact");
|
||||
const data = artifactPart?.data as SubagentArtifactData | undefined;
|
||||
// The abort steer (2026-09 dock semantics): its message-type part is
|
||||
@@ -38,8 +41,7 @@ export function SubagentSteerCard({ message }: { message: LhViewMessage }) {
|
||||
if (aborted?.data) return <AbortedBadge kind={aborted.data.kind ?? "job"} />;
|
||||
return (
|
||||
<div className="rounded-xl border bg-card p-4 text-sm text-muted-foreground">
|
||||
A sub-agent finished, but its result could not be displayed.
|
||||
</div>
|
||||
{t("A sub-agent finished, but its result could not be displayed.")}</div>
|
||||
);
|
||||
}
|
||||
switch (data.kind) {
|
||||
@@ -66,11 +68,12 @@ export function SubagentSteerCard({ message }: { message: LhViewMessage }) {
|
||||
* teacher's wake turn acknowledges the abort in the lesson itself,
|
||||
* this just marks what happened. */
|
||||
function AbortedBadge({ kind }: { kind: string }) {
|
||||
const { t } = useI18n();
|
||||
return (
|
||||
<div data-testid="job-aborted-badge" className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<CircleX className="size-3.5" />
|
||||
<span className="font-medium uppercase tracking-wide">{kind}</span>
|
||||
<span>aborted by the learner</span>
|
||||
<span>{t("aborted by the learner")}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -80,6 +83,7 @@ function AbortedBadge({ kind }: { kind: string }) {
|
||||
* the badge marks delivery, the collapsed details carries the full text
|
||||
* + consulted pages. */
|
||||
function PdfCompleteBadge({ result }: { result: PdfResult }) {
|
||||
const { t } = useI18n();
|
||||
// The honest count is READ pages (extract/render — sources v1 split);
|
||||
// the ?? is runtime tolerance for pre-split persisted steers.
|
||||
const readPages = result.pagesRead ?? result.pagesConsulted;
|
||||
@@ -88,14 +92,14 @@ function PdfCompleteBadge({ result }: { result: PdfResult }) {
|
||||
<summary className="flex cursor-pointer select-none list-none items-center gap-2 [&::-webkit-details-marker]:hidden">
|
||||
<CheckIcon className="size-3.5" />
|
||||
<span className="font-medium uppercase tracking-wide">PDF</span>
|
||||
<span>reading complete</span>
|
||||
<span>{t("reading complete")}</span>
|
||||
{readPages.length > 0 && (
|
||||
<span>
|
||||
· read {readPages.length} page{readPages.length === 1 ? "" : "s"}
|
||||
{t("· read {count} pages", { count: readPages.length })}
|
||||
</span>
|
||||
)}
|
||||
<span className="ml-1 text-xs text-muted-foreground/70 group-open:hidden">view brief</span>
|
||||
<span className="ml-1 hidden text-xs text-muted-foreground/70 group-open:inline">hide brief</span>
|
||||
<span className="ml-1 text-xs text-muted-foreground/70 group-open:hidden">{t("view brief")}</span>
|
||||
<span className="ml-1 hidden text-xs text-muted-foreground/70 group-open:inline">{t("hide brief")}</span>
|
||||
</summary>
|
||||
<div className="mt-2">
|
||||
<PdfBriefCard output={result} />
|
||||
@@ -110,15 +114,16 @@ function PdfCompleteBadge({ result }: { result: PdfResult }) {
|
||||
* affordance): full markdown + sources, one click away, no extra fetch —
|
||||
* the artifact part in the record is the single source of truth. */
|
||||
function ResearchCompleteBadge({ result }: { result: ResearchResult }) {
|
||||
const { t } = useI18n();
|
||||
return (
|
||||
<details data-testid="research-complete-badge" className="group w-full text-xs text-muted-foreground">
|
||||
<summary className="flex cursor-pointer select-none list-none items-center gap-2 [&::-webkit-details-marker]:hidden">
|
||||
<CheckIcon className="size-3.5" />
|
||||
<span className="font-medium uppercase tracking-wide">Research</span>
|
||||
<span>complete</span>
|
||||
{result.sources.length > 0 && <span>· {result.sources.length} sources</span>}
|
||||
<span className="ml-1 text-xs text-muted-foreground/70 group-open:hidden">view brief</span>
|
||||
<span className="ml-1 hidden text-xs text-muted-foreground/70 group-open:inline">hide brief</span>
|
||||
<span className="font-medium uppercase tracking-wide">{t("Research")}</span>
|
||||
<span>{t("complete")}</span>
|
||||
{result.sources.length > 0 && <span>· {t("{count} sources", { count: result.sources.length })}</span>}
|
||||
<span className="ml-1 text-xs text-muted-foreground/70 group-open:hidden">{t("view brief")}</span>
|
||||
<span className="ml-1 hidden text-xs text-muted-foreground/70 group-open:inline">{t("hide brief")}</span>
|
||||
</summary>
|
||||
<div className="mt-2">
|
||||
<ResearchBriefCard output={result} />
|
||||
|
||||
Reference in New Issue
Block a user