feat(feedback): always-on nav button with GitHub/email handoff when analytics is off (#428)

Keep the top-nav feedback button always visible (icon plus label on desktop, icon-only on mobile) instead of hiding it when an instance opts out of analytics. When analytics is off, the dialog keeps the typed message and hands off to a prefilled GitHub issue plus a contact@snapotter.com email, with no fake Thanks. Adds a feedback.yml issue template, URL builders, and feedback strings across all 21 locales.

Claude-Session: https://claude.ai/code/session_01XVrHKXwzZDWBWgkGQdPZ3A
This commit is contained in:
SnapOtter
2026-07-04 17:37:12 +08:00
committed by GitHub
parent 7b04317ed2
commit 5dcc06a99e
28 changed files with 302 additions and 10 deletions
+6
View File
@@ -42,6 +42,7 @@ export const ar: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "ملاحظات",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const ar: TranslationKeys = {
searchMissTitle: "طلب أداة",
searchMissContext: "لقد بحثت عن: {query}",
searchMissDiscussionsFallback: "تعذّر تسجيل ذلك. افتح طلبًا في Discussions.",
offlineDescription:
"التحليلات معطّلة في هذا المثيل، لذلك لا تُسجَّل الملاحظات هنا. لا يزال بإمكانك التواصل مباشرةً مع فريق SnapOtter.",
offlinePublicNote: "مشكلات GitHub علنية.",
offlineGithubButton: "افتح مشكلة على GitHub",
offlineEmailButton: "راسلنا",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const de: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Feedback",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const de: TranslationKeys = {
searchMissContext: "Du hast gesucht nach: {query}",
searchMissDiscussionsFallback:
"Das konnten wir nicht speichern. Stelle eine Anfrage in Discussions.",
offlineDescription:
"Für diese Instanz ist die Analyse deaktiviert, daher wird Feedback hier nicht erfasst. Du kannst das SnapOtter-Team weiterhin direkt erreichen.",
offlinePublicNote: "GitHub-Issues sind öffentlich.",
offlineGithubButton: "Ein GitHub-Issue öffnen",
offlineEmailButton: "Schreib uns",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -40,6 +40,7 @@ export const en = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Feedback",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -63,6 +64,11 @@ export const en = {
searchMissTitle: "Request a tool",
searchMissContext: "You searched for: {query}",
searchMissDiscussionsFallback: "We couldn't record that. Open a request in Discussions.",
offlineDescription:
"This instance has analytics turned off, so feedback isn't recorded here. You can still reach the SnapOtter team directly.",
offlinePublicNote: "GitHub issues are public.",
offlineGithubButton: "Open a GitHub issue",
offlineEmailButton: "Email us",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const es: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Comentarios",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const es: TranslationKeys = {
searchMissTitle: "Solicitar una herramienta",
searchMissContext: "Buscaste: {query}",
searchMissDiscussionsFallback: "No pudimos registrarlo. Abre una solicitud en Discussions.",
offlineDescription:
"Esta instancia tiene la analítica desactivada, así que los comentarios no se registran aquí. Aún puedes contactar directamente con el equipo de SnapOtter.",
offlinePublicNote: "Las incidencias de GitHub son públicas.",
offlineGithubButton: "Abrir una incidencia en GitHub",
offlineEmailButton: "Escríbenos",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const fr: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Commentaires",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const fr: TranslationKeys = {
searchMissContext: "Vous avez recherché : {query}",
searchMissDiscussionsFallback:
"Nous n'avons pas pu l'enregistrer. Ouvrez une demande dans Discussions.",
offlineDescription:
"Cette instance a l'analytique désactivée, donc les commentaires ne sont pas enregistrés ici. Vous pouvez tout de même contacter directement l'équipe SnapOtter.",
offlinePublicNote: "Les tickets GitHub sont publics.",
offlineGithubButton: "Ouvrir un ticket GitHub",
offlineEmailButton: "Écrivez-nous",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const hi: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "प्रतिक्रिया",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const hi: TranslationKeys = {
searchMissTitle: "टूल का अनुरोध करें",
searchMissContext: "आपने खोजा: {query}",
searchMissDiscussionsFallback: "हम इसे रिकॉर्ड नहीं कर सके. Discussions में अनुरोध खोलें.",
offlineDescription:
"इस इंस्टेंस पर एनालिटिक्स बंद है, इसलिए प्रतिक्रिया यहाँ रिकॉर्ड नहीं होती. फिर भी आप SnapOtter टीम से सीधे संपर्क कर सकते हैं.",
offlinePublicNote: "GitHub issue सार्वजनिक होते हैं.",
offlineGithubButton: "GitHub issue खोलें",
offlineEmailButton: "हमें ईमेल करें",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const id: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Masukan",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const id: TranslationKeys = {
searchMissTitle: "Minta alat",
searchMissContext: "Anda mencari: {query}",
searchMissDiscussionsFallback: "Kami tidak dapat mencatatnya. Buka permintaan di Discussions.",
offlineDescription:
"Instance ini menonaktifkan analitik, jadi masukan tidak dicatat di sini. Anda tetap bisa menghubungi tim SnapOtter secara langsung.",
offlinePublicNote: "Issue GitHub bersifat publik.",
offlineGithubButton: "Buka issue GitHub",
offlineEmailButton: "Kirim email ke kami",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const it: TranslationKeys = {
},
feedback: {
navLabel: "Condividi feedback",
navButtonLabel: "Feedback",
dialogTitle: "Condividi feedback",
toolDialogTitle: "Come ha funzionato questo strumento?",
failedDialogTitle: "Segnala un problema dello strumento",
@@ -67,6 +68,11 @@ export const it: TranslationKeys = {
searchMissContext: "Hai cercato: {query}",
searchMissDiscussionsFallback:
"Non siamo riusciti a registrarlo. Apri una richiesta in Discussions.",
offlineDescription:
"Questa istanza ha l'analisi disattivata, quindi il feedback non viene registrato qui. Puoi comunque contattare direttamente il team di SnapOtter.",
offlinePublicNote: "Le issue di GitHub sono pubbliche.",
offlineGithubButton: "Apri una issue su GitHub",
offlineEmailButton: "Scrivici",
thanksTitle: "Grazie per il feedback.",
thanksDescription:
"Ci aiuta a migliorare SnapOtter senza raccogliere file o contenuti privati.",
+6
View File
@@ -42,6 +42,7 @@ export const ja: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "フィードバック",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const ja: TranslationKeys = {
searchMissContext: "検索した内容: {query}",
searchMissDiscussionsFallback:
"記録できませんでした。Discussions でリクエストを開いてください。",
offlineDescription:
"このインスタンスは分析が無効になっているため、フィードバックはここには記録されません。SnapOtter チームに直接連絡することもできます。",
offlinePublicNote: "GitHub の Issue は公開されます。",
offlineGithubButton: "GitHub で Issue を作成",
offlineEmailButton: "メールで連絡",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const ko: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "피드백",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const ko: TranslationKeys = {
searchMissTitle: "도구 요청",
searchMissContext: "검색한 내용: {query}",
searchMissDiscussionsFallback: "기록하지 못했습니다. Discussions에서 요청을 열어 주세요.",
offlineDescription:
"이 인스턴스는 분석이 꺼져 있어 피드백이 여기에 기록되지 않습니다. 그래도 SnapOtter 팀에 직접 연락할 수 있습니다.",
offlinePublicNote: "GitHub 이슈는 공개됩니다.",
offlineGithubButton: "GitHub 이슈 열기",
offlineEmailButton: "이메일 보내기",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const nl: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Feedback",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const nl: TranslationKeys = {
searchMissContext: "Je zocht op: {query}",
searchMissDiscussionsFallback:
"We konden dit niet vastleggen. Open een verzoek in Discussions.",
offlineDescription:
"Deze instantie heeft analyse uitgeschakeld, dus feedback wordt hier niet vastgelegd. Je kunt het SnapOtter-team nog steeds rechtstreeks bereiken.",
offlinePublicNote: "GitHub-issues zijn openbaar.",
offlineGithubButton: "Een GitHub-issue openen",
offlineEmailButton: "Mail ons",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const pl: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Opinie",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const pl: TranslationKeys = {
searchMissTitle: "Poproś o narzędzie",
searchMissContext: "Szukano: {query}",
searchMissDiscussionsFallback: "Nie udało się tego zapisać. Otwórz prośbę w Discussions.",
offlineDescription:
"Ta instancja ma wyłączoną analitykę, więc opinie nie są tu zapisywane. Nadal możesz skontaktować się bezpośrednio z zespołem SnapOtter.",
offlinePublicNote: "Zgłoszenia w GitHub są publiczne.",
offlineGithubButton: "Otwórz zgłoszenie w GitHub",
offlineEmailButton: "Napisz do nas",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const ptBR: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Feedback",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const ptBR: TranslationKeys = {
searchMissContext: "Você pesquisou: {query}",
searchMissDiscussionsFallback:
"Não conseguimos registrar. Abra uma solicitação no Discussions.",
offlineDescription:
"Esta instância está com a análise desativada, então o feedback não é registrado aqui. Mesmo assim, você pode falar diretamente com a equipe do SnapOtter.",
offlinePublicNote: "As issues do GitHub são públicas.",
offlineGithubButton: "Abrir uma issue no GitHub",
offlineEmailButton: "Envie um e-mail",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const ru: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Отзыв",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const ru: TranslationKeys = {
searchMissTitle: "Запросить инструмент",
searchMissContext: "Вы искали: {query}",
searchMissDiscussionsFallback: "Не удалось записать. Откройте запрос в Discussions.",
offlineDescription:
"В этом экземпляре аналитика отключена, поэтому отзывы здесь не записываются. Вы всё равно можете напрямую связаться с командой SnapOtter.",
offlinePublicNote: "Issue на GitHub публичны.",
offlineGithubButton: "Открыть issue на GitHub",
offlineEmailButton: "Напишите нам",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const sv: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Feedback",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const sv: TranslationKeys = {
searchMissContext: "Du sökte efter: {query}",
searchMissDiscussionsFallback:
"Vi kunde inte registrera det. Öppna en förfrågan i Discussions.",
offlineDescription:
"Den här instansen har stängt av analysen, så feedback registreras inte här. Du kan ändå nå SnapOtter-teamet direkt.",
offlinePublicNote: "GitHub-ärenden är offentliga.",
offlineGithubButton: "Öppna ett GitHub-ärende",
offlineEmailButton: "Mejla oss",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const th: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "ความคิดเห็น",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const th: TranslationKeys = {
searchMissTitle: "ขอเครื่องมือ",
searchMissContext: "คุณค้นหา: {query}",
searchMissDiscussionsFallback: "เราบันทึกไม่ได้ เปิดคำขอใน Discussions",
offlineDescription:
"อินสแตนซ์นี้ปิดการวิเคราะห์ไว้ ความคิดเห็นจึงไม่ถูกบันทึกที่นี่ คุณยังสามารถติดต่อทีม SnapOtter ได้โดยตรง",
offlinePublicNote: "Issue บน GitHub เป็นสาธารณะ",
offlineGithubButton: "เปิด Issue บน GitHub",
offlineEmailButton: "ส่งอีเมลถึงเรา",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const tr: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Geri bildirim",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const tr: TranslationKeys = {
searchMissTitle: "Araç iste",
searchMissContext: "Şunu aradın: {query}",
searchMissDiscussionsFallback: "Bunu kaydedemedik. Discussions'ta bir istek aç.",
offlineDescription:
"Bu örnekte analiz kapalı, bu yüzden geri bildirim burada kaydedilmez. Yine de SnapOtter ekibine doğrudan ulaşabilirsin.",
offlinePublicNote: "GitHub issue'ları herkese açıktır.",
offlineGithubButton: "GitHub'da issue aç",
offlineEmailButton: "Bize e-posta gönder",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const uk: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Відгук",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const uk: TranslationKeys = {
searchMissTitle: "Запитати інструмент",
searchMissContext: "Ви шукали: {query}",
searchMissDiscussionsFallback: "Не вдалося записати. Відкрийте запит у Discussions.",
offlineDescription:
"У цьому екземплярі аналітику вимкнено, тому відгуки тут не записуються. Ви все одно можете напряму звернутися до команди SnapOtter.",
offlinePublicNote: "Issue на GitHub є публічними.",
offlineGithubButton: "Відкрити issue на GitHub",
offlineEmailButton: "Напишіть нам",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const vi: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "Phản hồi",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -66,6 +67,11 @@ export const vi: TranslationKeys = {
searchMissContext: "Bạn đã tìm: {query}",
searchMissDiscussionsFallback:
"Chúng tôi không ghi lại được. Mở một yêu cầu trong Discussions.",
offlineDescription:
"Bản cài đặt này đã tắt phân tích, nên phản hồi không được ghi lại ở đây. Bạn vẫn có thể liên hệ trực tiếp với nhóm SnapOtter.",
offlinePublicNote: "Issue trên GitHub là công khai.",
offlineGithubButton: "Mở một issue trên GitHub",
offlineEmailButton: "Gửi email cho chúng tôi",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const zhCN: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "反馈",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const zhCN: TranslationKeys = {
searchMissTitle: "请求工具",
searchMissContext: "你搜索了:{query}",
searchMissDiscussionsFallback: "我们无法记录。请在 Discussions 中发起请求。",
offlineDescription:
"此实例已关闭分析功能,因此反馈不会记录在这里。你仍然可以直接联系 SnapOtter 团队。",
offlinePublicNote: "GitHub issue 是公开的。",
offlineGithubButton: "创建 GitHub issue",
offlineEmailButton: "给我们发邮件",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",
+6
View File
@@ -42,6 +42,7 @@ export const zhTW: TranslationKeys = {
},
feedback: {
navLabel: "Share feedback",
navButtonLabel: "意見回饋",
dialogTitle: "Share feedback",
toolDialogTitle: "How did this tool work?",
failedDialogTitle: "Report a tool issue",
@@ -65,6 +66,11 @@ export const zhTW: TranslationKeys = {
searchMissTitle: "請求工具",
searchMissContext: "你搜尋了:{query}",
searchMissDiscussionsFallback: "我們無法記錄。請在 Discussions 中發起請求。",
offlineDescription:
"此執行個體已關閉分析功能,因此意見回饋不會記錄在這裡。你仍然可以直接聯絡 SnapOtter 團隊。",
offlinePublicNote: "GitHub issue 是公開的。",
offlineGithubButton: "建立 GitHub issue",
offlineEmailButton: "寄電子郵件給我們",
thanksTitle: "Thanks for the feedback.",
thanksDescription: "It helps us improve SnapOtter without collecting files or private content.",
quickThanks: "Thanks for the signal.",