mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(help): render the help dialog from i18n instead of hardcoded English (#647)
The help dialog carried its 13 shortcut labels, its getting-started paragraph and its version line as hardcoded English, while fully translated strings for exactly those labels sat unused in all 21 locale files. Every non-English user read English there. The translations did not need writing, only reading: t.help.keyboardShortcuts already had focusSearchBar, goToTools, processFile and the rest, in every locale. Labels now index into t.help.keyboardShortcuts by key rather than carrying text. Getting-started reads t.help.gettingStarted.description, which drops the inline Kbd chip the hardcoded copy had, matching what all 21 locales already say. The version line goes through t.help.versionLabel. Also adds the type-to-search row that #644 left out, keyed help.keyboardShortcuts.typeToSearch, translated into all 21 locales, and regenerates the two darwin help-dialog baselines for the extra row. Nothing caught the original bug because the i18n context defaults to en, so asserting on English text passes whether or not the component reads i18n at all. The new test mocks the context with sentinel values instead: putting the hardcoded labels back fails 15 of its 19 cases. Verified: 19 new unit tests, full unit suite 7576 passed, help-dialog visual 3/3 against regenerated baselines, help accessibility e2e 7/7, typecheck and lint clean, all 18 CI checks green.
This commit is contained in:
@@ -4,27 +4,32 @@ import { useEffect, useRef } from "react";
|
||||
import { useTranslation } from "@/contexts/i18n-context";
|
||||
import { useFocusTrap } from "@/hooks/use-focus-trap";
|
||||
import { formatShortcut } from "@/hooks/use-keyboard-shortcuts";
|
||||
import { format } from "@/lib/format.js";
|
||||
|
||||
interface HelpDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
// Labels index into t.help.keyboardShortcuts rather than carrying English text,
|
||||
// which is what the rest of the app does. The translations for these already
|
||||
// existed in all 21 locales and simply were not being read.
|
||||
const SHORTCUTS = [
|
||||
{ keys: "mod+k", description: "Focus search bar" },
|
||||
{ keys: "mod+/", description: "Go to tools" },
|
||||
{ keys: "mod+enter", description: "Process file" },
|
||||
{ keys: "mod+s", description: "Download result" },
|
||||
{ keys: "mod+shift+d", description: "Toggle theme" },
|
||||
{ keys: "mod+alt+1", description: "Go to Resize" },
|
||||
{ keys: "mod+alt+2", description: "Go to Crop" },
|
||||
{ keys: "mod+alt+3", description: "Go to Compress" },
|
||||
{ keys: "mod+alt+4", description: "Go to Convert" },
|
||||
{ keys: "mod+alt+5", description: "Go to Remove Background" },
|
||||
{ keys: "mod+alt+6", description: "Go to Watermark Text" },
|
||||
{ keys: "mod+alt+7", description: "Go to Strip Metadata" },
|
||||
{ keys: "mod+alt+8", description: "Go to Image Info" },
|
||||
];
|
||||
{ keys: "mod+k", labelKey: "focusSearchBar" },
|
||||
{ keys: "a-z", labelKey: "typeToSearch" },
|
||||
{ keys: "mod+/", labelKey: "goToTools" },
|
||||
{ keys: "mod+enter", labelKey: "processFile" },
|
||||
{ keys: "mod+s", labelKey: "downloadResult" },
|
||||
{ keys: "mod+shift+d", labelKey: "toggleTheme" },
|
||||
{ keys: "mod+alt+1", labelKey: "goToResize" },
|
||||
{ keys: "mod+alt+2", labelKey: "goToCrop" },
|
||||
{ keys: "mod+alt+3", labelKey: "goToCompress" },
|
||||
{ keys: "mod+alt+4", labelKey: "goToConvert" },
|
||||
{ keys: "mod+alt+5", labelKey: "goToRemoveBackground" },
|
||||
{ keys: "mod+alt+6", labelKey: "goToWatermarkText" },
|
||||
{ keys: "mod+alt+7", labelKey: "goToStripMetadata" },
|
||||
{ keys: "mod+alt+8", labelKey: "goToImageInfo" },
|
||||
] as const;
|
||||
|
||||
export function HelpDialog({ open, onClose }: HelpDialogProps) {
|
||||
const { t } = useTranslation();
|
||||
@@ -80,9 +85,7 @@ export function HelpDialog({ open, onClose }: HelpDialogProps) {
|
||||
<h3 className="text-sm font-semibold">{t.help.gettingStarted.heading}</h3>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Select a tool from the sidebar or search for one with <Kbd keys="mod+k" />. Upload a
|
||||
file by dragging it onto the page or clicking the upload area. Adjust settings and
|
||||
download your result.
|
||||
{t.help.gettingStarted.description}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -100,7 +103,9 @@ export function HelpDialog({ open, onClose }: HelpDialogProps) {
|
||||
i !== SHORTCUTS.length - 1 ? "border-b border-border" : ""
|
||||
}`}
|
||||
>
|
||||
<span className="text-muted-foreground">{s.description}</span>
|
||||
<span className="text-muted-foreground">
|
||||
{t.help.keyboardShortcuts[s.labelKey]}
|
||||
</span>
|
||||
<Kbd keys={s.keys} />
|
||||
</div>
|
||||
))}
|
||||
@@ -155,7 +160,7 @@ export function HelpDialog({ open, onClose }: HelpDialogProps) {
|
||||
|
||||
{/* Version */}
|
||||
<div className="text-xs text-muted-foreground pt-2 border-t border-border">
|
||||
SnapOtter v{APP_VERSION}
|
||||
{format(t.help.versionLabel, { version: APP_VERSION })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user