diff --git a/client/simple/src/js/main/keyboard.ts b/client/simple/src/js/main/keyboard.ts index b4b8e0f92..c9054d619 100644 --- a/client/simple/src/js/main/keyboard.ts +++ b/client/simple/src/js/main/keyboard.ts @@ -8,67 +8,68 @@ export type KeyBindingLayout = "default" | "vim"; type KeyBinding = { key: string; fun: (event: KeyboardEvent) => void; - des: string; - cat: string; + des?: string; + cat?: string; }; type HighlightResultElement = "down" | "up" | "visible" | "bottom" | "top"; /* common base for layouts */ + const baseKeyBinding: Record = { Escape: { key: "ESC", fun: (event: KeyboardEvent) => removeFocus(event), - des: "remove focus from the focused input", - cat: "Control" + des: settings.translations?.hotkeys_remove_focus, + cat: settings.translations?.hotkeys_category_control }, c: { key: "c", fun: () => copyURLToClipboard(), - des: "copy url of the selected result to the clipboard", - cat: "Results" + des: settings.translations?.hotkeys_copy_url, + cat: settings.translations?.hotkeys_category_results }, h: { key: "h", fun: () => toggleHelp(keyBindings), - des: "toggle help window", - cat: "Other" + des: settings.translations?.hotkeys_toggle_help, + cat: settings.translations?.hotkeys_category_other }, i: { key: "i", fun: () => searchInputFocus(), - des: "focus on the search input", - cat: "Control" + des: settings.translations?.hotkeys_focus_search, + cat: settings.translations?.hotkeys_category_control }, n: { key: "n", fun: () => GoToNextPage(), - des: "go to next page", - cat: "Results" + des: settings.translations?.hotkeys_next_page, + cat: settings.translations?.hotkeys_category_results }, o: { key: "o", fun: () => openResult(false), - des: "open search result", - cat: "Results" + des: settings.translations?.hotkeys_open_result, + cat: settings.translations?.hotkeys_category_results }, p: { key: "p", fun: () => GoToPreviousPage(), - des: "go to previous page", - cat: "Results" + des: settings.translations?.hotkeys_previous_page, + cat: settings.translations?.hotkeys_category_results }, r: { key: "r", fun: () => reloadPage(), - des: "reload page from the server", - cat: "Control" + des: settings.translations?.hotkeys_reload_page, + cat: settings.translations?.hotkeys_category_control }, t: { key: "t", fun: () => openResult(true), - des: "open the result in a new tab", - cat: "Results" + des: settings.translations?.hotkeys_open_new_tab, + cat: settings.translations?.hotkeys_category_results } }; @@ -78,14 +79,14 @@ const keyBindingLayouts: Record> = ArrowLeft: { key: "←", fun: () => highlightResult("up")(), - des: "select previous search result", - cat: "Results" + des: settings.translations?.hotkeys_select_previous, + cat: settings.translations?.hotkeys_category_results }, ArrowRight: { key: "→", fun: () => highlightResult("down")(), - des: "select next search result", - cat: "Results" + des: settings.translations?.hotkeys_select_next, + cat: settings.translations?.hotkeys_category_results }, ...baseKeyBinding }, @@ -95,56 +96,56 @@ const keyBindingLayouts: Record> = b: { key: "b", fun: () => scrollPage(-window.innerHeight), - des: "scroll one page up", - cat: "Navigation" + des: settings.translations?.hotkeys_page_up, + cat: settings.translations?.hotkeys_category_navigation }, d: { key: "d", fun: () => scrollPage(window.innerHeight / 2), - des: "scroll half a page down", - cat: "Navigation" + des: settings.translations?.hotkeys_half_page_down, + cat: settings.translations?.hotkeys_category_navigation }, f: { key: "f", fun: () => scrollPage(window.innerHeight), - des: "scroll one page down", - cat: "Navigation" + des: settings.translations?.hotkeys_page_down, + cat: settings.translations?.hotkeys_category_navigation }, g: { key: "g", fun: () => scrollPageTo(-document.body.scrollHeight, "top"), - des: "scroll to the top of the page", - cat: "Navigation" + des: settings.translations?.hotkeys_scroll_top, + cat: settings.translations?.hotkeys_category_navigation }, j: { key: "j", fun: () => highlightResult("down")(), - des: "select next search result", - cat: "Results" + des: settings.translations?.hotkeys_select_next, + cat: settings.translations?.hotkeys_category_results }, k: { key: "k", fun: () => highlightResult("up")(), - des: "select previous search result", - cat: "Results" + des: settings.translations?.hotkeys_select_previous, + cat: settings.translations?.hotkeys_category_results }, u: { key: "u", fun: () => scrollPage(-window.innerHeight / 2), - des: "scroll half a page up", - cat: "Navigation" + des: settings.translations?.hotkeys_half_page_up, + cat: settings.translations?.hotkeys_category_navigation }, v: { key: "v", fun: () => scrollPageTo(document.body.scrollHeight, "bottom"), - des: "scroll to the bottom of the page", - cat: "Navigation" + des: settings.translations?.hotkeys_scroll_bottom, + cat: settings.translations?.hotkeys_category_navigation }, y: { key: "y", fun: () => copyURLToClipboard(), - des: "copy url of the selected result to the clipboard", - cat: "Results" + des: settings.translations?.hotkeys_copy_url, + cat: settings.translations?.hotkeys_category_results }, ...baseKeyBinding } @@ -344,6 +345,7 @@ const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBin for (const binding of Object.values(keyBindings)) { const { cat } = binding; + if (!cat) continue; categories[cat] ??= []; categories[cat].push(binding); } @@ -352,8 +354,8 @@ const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBin (a, b) => (categories[b]?.length ?? 0) - (categories[a]?.length ?? 0) ); - let html = '×'; - html += "

How to navigate SearXNG with hotkeys

"; + let html = `×`; + html += `

${settings.translations?.hotkeys_navigation_title}

`; html += ""; for (const [i, categoryKey] of sortedCategoryKeys.entries()) { @@ -372,6 +374,7 @@ const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBin html += '
    '; for (const binding of bindings) { + if (!binding.des) continue; html += `
  • ${binding.key} ${binding.des}
  • `; } diff --git a/searx/webapp.py b/searx/webapp.py index 54701aa52..bbb4b1540 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -323,11 +323,35 @@ def image_proxify(url: str): def get_translations(): return { # when there is autocompletion - 'no_item_found': gettext('No item found'), + "no_item_found": gettext("No item found"), # /preferences: the source of the engine description (wikipedata, wikidata, website) - 'Source': gettext('Source'), + "Source": gettext("Source"), # infinite scroll - 'error_loading_next_page': gettext('Error loading the next page'), + "error_loading_next_page": gettext("Error loading the next page"), + # keyboard hotkeys help (client/simple/src/js/main/keyboard.ts) + "close": gettext("close"), + "hotkeys_navigation_title": gettext("How to navigate SearXNG with hotkeys"), + "hotkeys_category_control": gettext("Control"), + "hotkeys_category_results": gettext("Results"), + "hotkeys_category_navigation": gettext("Navigation"), + "hotkeys_category_other": gettext("Other"), + "hotkeys_remove_focus": gettext("remove focus from the focused input"), + "hotkeys_copy_url": gettext("copy url of the selected result to the clipboard"), + "hotkeys_toggle_help": gettext("toggle help window"), + "hotkeys_focus_search": gettext("focus on the search input"), + "hotkeys_next_page": gettext("go to next page"), + "hotkeys_open_result": gettext("open search result"), + "hotkeys_previous_page": gettext("go to previous page"), + "hotkeys_reload_page": gettext("reload page from the server"), + "hotkeys_open_new_tab": gettext("open the result in a new tab"), + "hotkeys_select_previous": gettext("select previous search result"), + "hotkeys_select_next": gettext("select next search result"), + "hotkeys_page_up": gettext("scroll one page up"), + "hotkeys_half_page_down": gettext("scroll half a page down"), + "hotkeys_page_down": gettext("scroll one page down"), + "hotkeys_scroll_top": gettext("scroll to the top of the page"), + "hotkeys_half_page_up": gettext("scroll half a page up"), + "hotkeys_scroll_bottom": gettext("scroll to the bottom of the page"), }