feat: add Russian localization and independent STT languages
CI / Typecheck, tests, lint (push) Canceled after 0s
CI / Standalone (mac-arm64) (push) Canceled after 0s
CI / Standalone (linux-x64) (push) Canceled after 0s
CI / Standalone (windows-x64) (push) Canceled after 0s

This commit is contained in:
2026-10-25 17:18:44 +03:00
parent b277ee3e0f
commit a50ca4b867
93 changed files with 3261 additions and 904 deletions
+9 -6
View File
@@ -1,4 +1,6 @@
"use client";
import { useI18n } from "@/components/i18n";
import { useCallback, useEffect, useRef, useState, type RefObject } from "react";
import { ChevronDownIcon, ChevronUpIcon, SearchIcon, XIcon } from "lucide-react";
@@ -66,6 +68,7 @@ export function SessionFind({ scopeRef, scrollContextRef }: {
scopeRef: RefObject<HTMLDivElement | null>;
scrollContextRef: RefObject<SessionScrollContext | null>;
}) {
const { t } = useI18n();
const [open, setOpen] = useState(false);
const [query, setQuery] = useState("");
const [result, setResult] = useState({ index: -1, count: 0 });
@@ -163,7 +166,7 @@ export function SessionFind({ scopeRef, scrollContextRef }: {
return (
<div
role="search"
aria-label="Session Find"
aria-label={t("Session Find")}
data-testid="session-find"
className="lh-no-drag flex h-10 shrink-0 items-center gap-2 border-b border-border px-6 font-ui text-sm"
onKeyDown={(event) => {
@@ -182,8 +185,8 @@ export function SessionFind({ scopeRef, scrollContextRef }: {
<SearchIcon className="size-4 shrink-0 text-muted-foreground" aria-hidden />
<input
ref={inputRef}
aria-label="Find in session"
placeholder="Find in session…"
aria-label={t("Find in session")}
placeholder={t("Find in session…")}
value={query}
onChange={(event) => setQuery(event.target.value)}
spellCheck={false}
@@ -192,15 +195,15 @@ export function SessionFind({ scopeRef, scrollContextRef }: {
<output aria-live="polite" data-testid="session-find-count" className="shrink-0 text-xs tabular-nums text-muted-foreground">
{query ? `${result.index + 1}/${result.count}` : ""}
</output>
<button type="button" aria-label="Previous match" title="Previous match (Shift+Enter)" className={buttonClass}
<button type="button" aria-label={t("Previous match")} title={t("Previous match (Shift+Enter)")} className={buttonClass}
disabled={!result.count} onMouseDown={(event) => event.preventDefault()} onClick={() => step(-1)}>
<ChevronUpIcon className="size-4" aria-hidden />
</button>
<button type="button" aria-label="Next match" title="Next match (Enter)" className={buttonClass}
<button type="button" aria-label={t("Next match")} title={t("Next match (Enter)")} className={buttonClass}
disabled={!result.count} onMouseDown={(event) => event.preventDefault()} onClick={() => step(1)}>
<ChevronDownIcon className="size-4" aria-hidden />
</button>
<button type="button" aria-label="Close Find" title="Close Find (Esc)" className={buttonClass} onClick={close}>
<button type="button" aria-label={t("Close Find")} title={t("Close Find (Esc)")} className={buttonClass} onClick={close}>
<XIcon className="size-4" aria-hidden />
</button>
</div>