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
+12 -13
View File
@@ -1,4 +1,6 @@
"use client";
import { useI18n } from "@/components/i18n";
/**
* The Keyboard section (thin settings wave): view / rebind / reset over
* core/keyboard.ts's registry. The overrides persist in localStorage
@@ -48,6 +50,7 @@ export function nextOverrides(
}
export function KeyboardSection() {
const { t } = useI18n();
const [overrides, setOverrides] = useState<Partial<Record<KeyAction, string>>>({});
const [rebinding, setRebinding] = useState<KeyAction | null>(null);
const [nonce, setNonce] = useState(0);
@@ -101,20 +104,20 @@ export function KeyboardSection() {
if (!actions.length) return null;
return (
<div key={scope} data-testid={`kbd-scope-${scope}`}>
<p className="mb-1 text-xs uppercase tracking-widest text-muted-foreground/70">{label}</p>
<p className="mb-1 text-xs uppercase tracking-widest text-muted-foreground/70">{t(label)}</p>
<div className="flex flex-col gap-2">
{actions.map((def) => {
const effective = overrides[def.id] ?? def.binding;
return (
<SettingsRow
key={def.id}
label={def.label}
hint={def.displayOnly ? "Fixed — part of this screen" : undefined}
label={t(def.label)}
hint={def.displayOnly ? t("Fixed — part of this screen") : undefined}
testid={`kbd-row-${def.id}`}
>
<span className="flex items-center gap-2">
<kbd className="rounded-sm border border-border bg-muted px-1.5 py-0.5 font-ui text-xs">
{rebinding === def.id ? "Press keys…" : formatBinding(effective)}
{rebinding === def.id ? t("Press keys…") : t(formatBinding(effective))}
</kbd>
{def.displayOnly ? null : rebinding === def.id ? (
<button
@@ -122,8 +125,7 @@ export function KeyboardSection() {
onClick={() => setRebinding(null)}
className="text-xs text-muted-foreground/70 underline-offset-2 hover:text-foreground hover:underline"
>
Cancel
</button>
{t("Cancel")}</button>
) : (
<>
<button
@@ -132,8 +134,7 @@ export function KeyboardSection() {
data-testid={`kbd-rebind-${def.id}`}
className="text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline"
>
Rebind
</button>
{t("Rebind")}</button>
{overridden(def.id) && (
<button
type="button"
@@ -141,8 +142,7 @@ export function KeyboardSection() {
data-testid={`kbd-reset-${def.id}`}
className="text-xs text-muted-foreground/70 underline-offset-2 hover:text-foreground hover:underline"
>
Reset
</button>
{t("Reset")}</button>
)}
</>
)}
@@ -155,15 +155,14 @@ export function KeyboardSection() {
);
})}
<div className="mt-1 flex items-center justify-between">
<span className="text-xs text-muted-foreground/70">Stored on this device (lh:keymap) — overrides only.</span>
<span className="text-xs text-muted-foreground/70">{t("Stored on this device (lh:keymap) — overrides only.")}</span>
<button
type="button"
onClick={resetAll}
data-testid="kbd-reset-all"
className="text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline"
>
Reset all to defaults
</button>
{t("Reset all to defaults")}</button>
</div>
</>
);