fix(shortcuts): change bookmark shortcut from Ctrl+D to Ctrl+B (#3691)

* fix(shortcuts): change bookmark shortcut from Ctrl+D to Ctrl+B, closes #3675

Ctrl+D was bound to both Toggle Bookmark (General) and Dictionary
Lookup (Selection). When text was selected and Ctrl+D pressed, both
actions fired — opening the dictionary AND adding an unwanted bookmark.

Changed bookmark to Ctrl+B/Cmd+B to resolve the conflict. Added a
unit test that detects identical keybinding lists across actions to
prevent this class of bug in the future.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* i18n: mark shortcut section names for translation

Wrap SHORTCUT_SECTIONS values with stubTranslation() so i18next-scanner
picks them up. Translate the 4 new keys (General, Text to Speech, Zoom,
Window) across all 29 locales.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin
2026-03-30 21:35:40 +08:00
committed by GitHub
parent b872868136
commit ec26ef4f29
31 changed files with 187 additions and 36 deletions
@@ -1191,5 +1191,9 @@
"Scroll Half Page Down": "تمرير نصف صفحة لأسفل",
"Scroll Half Page Up": "تمرير نصف صفحة لأعلى",
"Save Note": "حفظ الملاحظة",
"Single Section Scroll": "التمرير بقسم واحد"
"Single Section Scroll": "التمرير بقسم واحد",
"General": "عام",
"Text to Speech": "تحويل النص إلى كلام",
"Zoom": "تكبير",
"Window": "نافذة"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "অর্ধেক পৃষ্ঠা নিচে স্ক্রল করুন",
"Scroll Half Page Up": "অর্ধেক পৃষ্ঠা উপরে স্ক্রল করুন",
"Save Note": "নোট সংরক্ষণ করুন",
"Single Section Scroll": "একক অধ্যায় স্ক্রল"
"Single Section Scroll": "একক অধ্যায় স্ক্রল",
"General": "সাধারণ",
"Text to Speech": "পাঠ থেকে বাক্য",
"Zoom": "জুম",
"Window": "উইন্ডো"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "ཤོག་ངོས་ཕྱེད་ཀ་འོག་ཏུ།",
"Scroll Half Page Up": "ཤོག་ངོས་ཕྱེད་ཀ་གོང་དུ།",
"Save Note": "ཟིན་བྲིས་ཉར་བ།",
"Single Section Scroll": "དོན་ཚན་གཅིག་འགུལ་བ།"
"Single Section Scroll": "དོན་ཚན་གཅིག་འགུལ་བ།",
"General": "སྤྱིར་བཏང་།",
"Text to Speech": "ཡི་གེ་ནས་སྒྲ།",
"Zoom": "ཆེ་རུ་གཏོང་།",
"Window": "སྒེའུ་ཁུང་།"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "Halbe Seite nach unten scrollen",
"Scroll Half Page Up": "Halbe Seite nach oben scrollen",
"Save Note": "Notiz speichern",
"Single Section Scroll": "Einzelabschnitt-Scrollen"
"Single Section Scroll": "Einzelabschnitt-Scrollen",
"General": "Allgemein",
"Text to Speech": "Sprachausgabe",
"Zoom": "Zoom",
"Window": "Fenster"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "Κύλιση μισής σελίδας κάτω",
"Scroll Half Page Up": "Κύλιση μισής σελίδας πάνω",
"Save Note": "Αποθήκευση σημείωσης",
"Single Section Scroll": "Κύλιση μεμονωμένης ενότητας"
"Single Section Scroll": "Κύλιση μεμονωμένης ενότητας",
"General": "Γενικά",
"Text to Speech": "Κείμενο σε ομιλία",
"Zoom": "Ζουμ",
"Window": "Παράθυρο"
}
@@ -1152,5 +1152,9 @@
"Scroll Half Page Down": "Desplazar media página abajo",
"Scroll Half Page Up": "Desplazar media página arriba",
"Save Note": "Guardar nota",
"Single Section Scroll": "Desplazamiento por sección"
"Single Section Scroll": "Desplazamiento por sección",
"General": "General",
"Text to Speech": "Texto a voz",
"Zoom": "Zoom",
"Window": "Ventana"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "پیمایش نیم صفحه پایین",
"Scroll Half Page Up": "پیمایش نیم صفحه بالا",
"Save Note": "ذخیره یادداشت",
"Single Section Scroll": "پیمایش تک‌بخشی"
"Single Section Scroll": "پیمایش تک‌بخشی",
"General": "عمومی",
"Text to Speech": "تبدیل متن به گفتار",
"Zoom": "بزرگ‌نمایی",
"Window": "پنجره"
}
@@ -1152,5 +1152,9 @@
"Scroll Half Page Down": "Défiler d'une demi-page vers le bas",
"Scroll Half Page Up": "Défiler d'une demi-page vers le haut",
"Save Note": "Enregistrer la note",
"Single Section Scroll": "Défilement par section"
"Single Section Scroll": "Défilement par section",
"General": "Général",
"Text to Speech": "Synthèse vocale",
"Zoom": "Zoom",
"Window": "Fenêtre"
}
@@ -1152,5 +1152,9 @@
"Scroll Half Page Down": "גלול חצי עמוד למטה",
"Scroll Half Page Up": "גלול חצי עמוד למעלה",
"Save Note": "שמור הערה",
"Single Section Scroll": "גלילת קטע בודד"
"Single Section Scroll": "גלילת קטע בודד",
"General": "כללי",
"Text to Speech": "טקסט לדיבור",
"Zoom": "זום",
"Window": "חלון"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "आधा पृष्ठ नीचे स्क्रॉल करें",
"Scroll Half Page Up": "आधा पृष्ठ ऊपर स्क्रॉल करें",
"Save Note": "नोट सहेजें",
"Single Section Scroll": "एकल अनुभाग स्क्रॉल"
"Single Section Scroll": "एकल अनुभाग स्क्रॉल",
"General": "सामान्य",
"Text to Speech": "पाठ से वाक्",
"Zoom": "ज़ूम",
"Window": "विंडो"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "Gulir setengah halaman ke bawah",
"Scroll Half Page Up": "Gulir setengah halaman ke atas",
"Save Note": "Simpan catatan",
"Single Section Scroll": "Gulir Satu Bagian"
"Single Section Scroll": "Gulir Satu Bagian",
"General": "Umum",
"Text to Speech": "Teks ke Suara",
"Zoom": "Zoom",
"Window": "Jendela"
}
@@ -1152,5 +1152,9 @@
"Scroll Half Page Down": "Scorri mezza pagina in basso",
"Scroll Half Page Up": "Scorri mezza pagina in alto",
"Save Note": "Salva nota",
"Single Section Scroll": "Scorrimento a sezione singola"
"Single Section Scroll": "Scorrimento a sezione singola",
"General": "Generale",
"Text to Speech": "Sintesi vocale",
"Zoom": "Zoom",
"Window": "Finestra"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "半ページ下にスクロール",
"Scroll Half Page Up": "半ページ上にスクロール",
"Save Note": "メモを保存",
"Single Section Scroll": "単一セクションスクロール"
"Single Section Scroll": "単一セクションスクロール",
"General": "一般",
"Text to Speech": "テキスト読み上げ",
"Zoom": "ズーム",
"Window": "ウィンドウ"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "반 페이지 아래로 스크롤",
"Scroll Half Page Up": "반 페이지 위로 스크롤",
"Save Note": "메모 저장",
"Single Section Scroll": "단일 섹션 스크롤"
"Single Section Scroll": "단일 섹션 스크롤",
"General": "일반",
"Text to Speech": "텍스트 음성 변환",
"Zoom": "확대/축소",
"Window": "창"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "Tatal separuh halaman ke bawah",
"Scroll Half Page Up": "Tatal separuh halaman ke atas",
"Save Note": "Simpan nota",
"Single Section Scroll": "Tatal Satu Bahagian"
"Single Section Scroll": "Tatal Satu Bahagian",
"General": "Umum",
"Text to Speech": "Teks ke Pertuturan",
"Zoom": "Zum",
"Window": "Tetingkap"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "Halve pagina naar beneden scrollen",
"Scroll Half Page Up": "Halve pagina naar boven scrollen",
"Save Note": "Notitie opslaan",
"Single Section Scroll": "Scrollen per sectie"
"Single Section Scroll": "Scrollen per sectie",
"General": "Algemeen",
"Text to Speech": "Tekst naar spraak",
"Zoom": "Zoom",
"Window": "Venster"
}
@@ -1165,5 +1165,9 @@
"Scroll Half Page Down": "Przewiń o pół strony w dół",
"Scroll Half Page Up": "Przewiń o pół strony w górę",
"Save Note": "Zapisz notatkę",
"Single Section Scroll": "Przewijanie pojedynczej sekcji"
"Single Section Scroll": "Przewijanie pojedynczej sekcji",
"General": "Ogólne",
"Text to Speech": "Tekst na mowę",
"Zoom": "Powiększenie",
"Window": "Okno"
}
@@ -1152,5 +1152,9 @@
"Scroll Half Page Down": "Rolar meia página para baixo",
"Scroll Half Page Up": "Rolar meia página para cima",
"Save Note": "Salvar nota",
"Single Section Scroll": "Rolagem por seção"
"Single Section Scroll": "Rolagem por seção",
"General": "Geral",
"Text to Speech": "Texto para fala",
"Zoom": "Zoom",
"Window": "Janela"
}
@@ -1165,5 +1165,9 @@
"Scroll Half Page Down": "Прокрутить на полстраницы вниз",
"Scroll Half Page Up": "Прокрутить на полстраницы вверх",
"Save Note": "Сохранить заметку",
"Single Section Scroll": "Прокрутка одного раздела"
"Single Section Scroll": "Прокрутка одного раздела",
"General": "Общие",
"Text to Speech": "Озвучивание",
"Zoom": "Масштаб",
"Window": "Окно"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "අඩ පිටුවක් පහළට අනුචලනය",
"Scroll Half Page Up": "අඩ පිටුවක් ඉහළට අනුචලනය",
"Save Note": "සටහන සුරකින්න",
"Single Section Scroll": "තනි කොටස අනුචලනය"
"Single Section Scroll": "තනි කොටස අනුචලනය",
"General": "සාමාන්‍ය",
"Text to Speech": "පෙළ කථනය",
"Zoom": "විශාලනය",
"Window": "කවුළුව"
}
@@ -1165,5 +1165,9 @@
"Scroll Half Page Down": "Drsi pol strani navzdol",
"Scroll Half Page Up": "Drsi pol strani navzgor",
"Save Note": "Shrani opombo",
"Single Section Scroll": "Drsenje posameznega razdelka"
"Single Section Scroll": "Drsenje posameznega razdelka",
"General": "Splošno",
"Text to Speech": "Besedilo v govor",
"Zoom": "Povečava",
"Window": "Okno"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "Rulla en halv sida nedåt",
"Scroll Half Page Up": "Rulla en halv sida uppåt",
"Save Note": "Spara anteckning",
"Single Section Scroll": "Rullning per avsnitt"
"Single Section Scroll": "Rullning per avsnitt",
"General": "Allmänt",
"Text to Speech": "Text till tal",
"Zoom": "Zoom",
"Window": "Fönster"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "அரை பக்கம் கீழே உருட்டுக",
"Scroll Half Page Up": "அரை பக்கம் மேலே உருட்டுக",
"Save Note": "குறிப்பைச் சேமிக்கவும்",
"Single Section Scroll": "ஒற்றைப் பகுதி உருட்டல்"
"Single Section Scroll": "ஒற்றைப் பகுதி உருட்டல்",
"General": "பொது",
"Text to Speech": "உரையிலிருந்து பேச்சு",
"Zoom": "பெரிதாக்கு",
"Window": "சாளரம்"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "เลื่อนลงครึ่งหน้า",
"Scroll Half Page Up": "เลื่อนขึ้นครึ่งหน้า",
"Save Note": "บันทึกโน้ต",
"Single Section Scroll": "เลื่อนทีละส่วน"
"Single Section Scroll": "เลื่อนทีละส่วน",
"General": "ทั่วไป",
"Text to Speech": "อ่านออกเสียง",
"Zoom": "ซูม",
"Window": "หน้าต่าง"
}
@@ -1139,5 +1139,9 @@
"Scroll Half Page Down": "Yarım sayfa aşağı kaydır",
"Scroll Half Page Up": "Yarım sayfa yukarı kaydır",
"Save Note": "Notu kaydet",
"Single Section Scroll": "Tek Bölüm Kaydırma"
"Single Section Scroll": "Tek Bölüm Kaydırma",
"General": "Genel",
"Text to Speech": "Metinden konuşmaya",
"Zoom": "Yakınlaştırma",
"Window": "Pencere"
}
@@ -1165,5 +1165,9 @@
"Scroll Half Page Down": "Прокрутити на півсторінки вниз",
"Scroll Half Page Up": "Прокрутити на півсторінки вгору",
"Save Note": "Зберегти нотатку",
"Single Section Scroll": "Прокрутка одного розділу"
"Single Section Scroll": "Прокрутка одного розділу",
"General": "Загальне",
"Text to Speech": "Озвучення",
"Zoom": "Масштаб",
"Window": "Вікно"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "Cuộn xuống nửa trang",
"Scroll Half Page Up": "Cuộn lên nửa trang",
"Save Note": "Lưu ghi chú",
"Single Section Scroll": "Cuộn từng phần"
"Single Section Scroll": "Cuộn từng phần",
"General": "Chung",
"Text to Speech": "Chuyển văn bản thành giọng nói",
"Zoom": "Thu phóng",
"Window": "Cửa sổ"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "向下滚动半页",
"Scroll Half Page Up": "向上滚动半页",
"Save Note": "保存笔记",
"Single Section Scroll": "单章节滚动"
"Single Section Scroll": "单章节滚动",
"General": "常规",
"Text to Speech": "文字转语音",
"Zoom": "缩放",
"Window": "窗口"
}
@@ -1126,5 +1126,9 @@
"Scroll Half Page Down": "向下捲動半頁",
"Scroll Half Page Up": "向上捲動半頁",
"Save Note": "儲存筆記",
"Single Section Scroll": "單章節捲動"
"Single Section Scroll": "單章節捲動",
"General": "一般",
"Text to Speech": "文字轉語音",
"Zoom": "縮放",
"Window": "視窗"
}
@@ -56,6 +56,41 @@ describe('TTS navigation shortcuts', () => {
});
});
describe('No identical keybinding lists across actions (#3675)', () => {
// Pre-existing pairs where two actions intentionally share the exact
// same key list — both handlers guard on runtime context.
// TODO: consider giving these distinct bindings to avoid the same
// class of bug as #3675.
const KNOWN_PAIRS: ReadonlySet<string> = new Set([
'onSearchSelection,onShowSearchBar', // ctrl+f / cmd+f
'onCloseWindow,onWikipediaSelection', // ctrl+w / cmd+w
]);
it('should not have two actions with exactly the same key list', async () => {
const shortcuts = await getDefaults();
const keyListToActions = new Map<string, string[]>();
for (const [name, entry] of Object.entries(shortcuts)) {
const id = [...entry.keys].sort().join(',').toLowerCase();
const actions = keyListToActions.get(id) ?? [];
actions.push(name);
keyListToActions.set(id, actions);
}
const duplicates: string[] = [];
for (const [keys, actions] of keyListToActions) {
if (actions.length > 1) {
const pairId = [...actions].sort().join(',');
if (!KNOWN_PAIRS.has(pairId)) {
duplicates.push(`[${keys}] is shared by: ${actions.join(', ')}`);
}
}
}
expect(
duplicates,
`Actions with identical keybinding lists:\n${duplicates.join('\n')}`,
).toEqual([]);
});
});
describe('getShortcutsForDisplay', () => {
it('returns sections in the correct order', async () => {
const mod = await getModule();
+7 -7
View File
@@ -39,7 +39,7 @@ const DEFAULT_SHORTCUTS = {
section: 'General',
},
onToggleBookmark: {
keys: ['ctrl+d', 'cmd+d'],
keys: ['ctrl+b', 'cmd+b'],
description: _('Toggle Bookmark'),
section: 'General',
},
@@ -270,12 +270,12 @@ export type ShortcutConfig = {
};
export const SHORTCUT_SECTIONS = [
'General',
'Navigation',
'Text to Speech',
'Selection',
'Zoom',
'Window',
_('General'),
_('Navigation'),
_('Text to Speech'),
_('Selection'),
_('Zoom'),
_('Window'),
] as const;
type ShortcutDisplayItem = {