From f26de3ab0dbe9a5ceb6a0a3df197e72f04fd5f52 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Wed, 8 Jan 2025 21:31:12 +0100 Subject: [PATCH] Add speech speed slider in the TTS panel (#128) --- apps/readest-app/i18next-scanner.config.js | 2 +- .../public/locales/de/translation.json | 3 ++ .../public/locales/es/translation.json | 3 ++ .../public/locales/fr/translation.json | 3 ++ .../public/locales/id/translation.json | 3 ++ .../public/locales/it/translation.json | 3 ++ .../public/locales/ja/translation.json | 3 ++ .../public/locales/ko/translation.json | 3 ++ .../public/locales/pt/translation.json | 3 ++ .../public/locales/ru/translation.json | 3 ++ .../public/locales/tr/translation.json | 3 ++ .../public/locales/vi/translation.json | 3 ++ .../public/locales/zh-CN/translation.json | 3 ++ .../public/locales/zh-TW/translation.json | 3 ++ .../app/reader/components/tts/TTSControl.tsx | 11 +++- .../app/reader/components/tts/TTSPanel.tsx | 51 +++++++++++++++++-- .../readest-app/src/services/tts/TTSClient.ts | 2 +- .../src/services/tts/TTSController.ts | 4 ++ .../src/services/tts/WebSpeechClient.ts | 49 +++++++++--------- 19 files changed, 129 insertions(+), 29 deletions(-) diff --git a/apps/readest-app/i18next-scanner.config.js b/apps/readest-app/i18next-scanner.config.js index a2400b9b..54eae66b 100644 --- a/apps/readest-app/i18next-scanner.config.js +++ b/apps/readest-app/i18next-scanner.config.js @@ -3,7 +3,7 @@ module.exports = { output: '.', options: { debug: false, - sort: true, + sort: false, func: { list: ['_'], extensions: ['.js', '.jsx', '.ts', '.tsx'], diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index e6ee0d21..6c74113a 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Geben Sie hier Ihr benutzerdefiniertes CSS ein...", "Excerpts": "Auszüge", "Failed to import book(s): {{filenames}}": "Fehler beim Importieren von Buch/Büchern: {{filenames}}", + "Fast": "Schnell", "Font": "Schriftart", "Font & Layout": "Schrift & Layout", "Font Face": "Schriftschnitt", @@ -108,10 +109,12 @@ "Sign In": "Anmelden", "Sign Out": "Abmelden", "Sky": "Himmelblau", + "Slow": "Langsam", "Solarized": "Solarisiert", "Speak": "Sprechen", "Subjects:": "Themen:", "System Fonts": "System-Schriftarten", + "TTS not supported in this device": "TTS wird auf diesem Gerät nicht unterstützt", "Theme Color": "Themenfarbe", "Theme Mode": "Themenmodus", "Translate": "Übersetzen", diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index b2d76dd7..56ec1956 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Introduce tu CSS personalizado aquí...", "Excerpts": "Extractos", "Failed to import book(s): {{filenames}}": "Error al importar libro(s): {{filenames}}", + "Fast": "Rápido", "Font": "Fuente", "Font & Layout": "Fuente y diseño", "Font Face": "Tipo de fuente", @@ -108,10 +109,12 @@ "Sign In": "Iniciar sesión", "Sign Out": "Cerrar sesión", "Sky": "Cielo", + "Slow": "Lento", "Solarized": "Solarizado", "Speak": "Leer", "Subjects:": "Temas:", "System Fonts": "Fuentes del sistema", + "TTS not supported in this device": "TTS no es compatible con este dispositivo", "Theme Color": "Color del tema", "Theme Mode": "Modo del tema", "Translate": "Traducir", diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 04e110c6..e87e9562 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Saisissez votre CSS personnalisé ici...", "Excerpts": "Extraits", "Failed to import book(s): {{filenames}}": "Échec de l'importation du/des livre(s) : {{filenames}}", + "Fast": "Rapide", "Font": "Police", "Font & Layout": "Police et mise en page", "Font Face": "Style de police", @@ -108,10 +109,12 @@ "Sign In": "Se connecter", "Sign Out": "Se déconnecter", "Sky": "Ciel", + "Slow": "Lent", "Solarized": "Solarisé", "Speak": "Lire", "Subjects:": "Sujets :", "System Fonts": "Polices système", + "TTS not supported in this device": "La synthèse vocale n'est pas prise en charge sur cet appareil", "Theme Color": "Couleur du thème", "Theme Mode": "Mode du thème", "Translate": "Traduire", diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 1cb23862..180c6358 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Masukkan CSS kustom Anda di sini...", "Excerpts": "Kutipan", "Failed to import book(s): {{filenames}}": "Gagal mengimpor buku: {{filenames}}", + "Fast": "Cepat", "Font": "Font", "Font & Layout": "Font & Tata Letak", "Font Face": "Jenis Font", @@ -108,10 +109,12 @@ "Sign In": "Masuk", "Sign Out": "Keluar", "Sky": "Langit", + "Slow": "Lambat", "Solarized": "Solarized", "Speak": "Bicara", "Subjects:": "Subjek:", "System Fonts": "Font Sistem", + "TTS not supported in this device": "TTS tidak didukung di perangkat ini", "Theme Color": "Warna Tema", "Theme Mode": "Mode Tema", "Translate": "Terjemahkan", diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index 8c44356b..49771fce 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Inserisci qui il tuo CSS personalizzato...", "Excerpts": "Estratti", "Failed to import book(s): {{filenames}}": "Impossibile importare il/i libro/i: {{filenames}}", + "Fast": "Veloce", "Font": "Font", "Font & Layout": "Font e Layout", "Font Face": "Tipo di carattere", @@ -108,10 +109,12 @@ "Sign In": "Accedi", "Sign Out": "Esci", "Sky": "Cielo", + "Slow": "Lento", "Solarized": "Solarizzato", "Speak": "Leggi", "Subjects:": "Argomenti:", "System Fonts": "Font di sistema", + "TTS not supported in this device": "TTS non supportato su questo dispositivo", "Theme Color": "Colore tema", "Theme Mode": "Modalità tema", "Translate": "Traduci", diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index 56c66e60..0b48c358 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "ここにカスタムCSSを入力...", "Excerpts": "抜粋", "Failed to import book(s): {{filenames}}": "書籍のインポートに失敗しました:{{filenames}}", + "Fast": "高速", "Font": "フォント", "Font & Layout": "フォントとレイアウト", "Font Face": "書体", @@ -108,10 +109,12 @@ "Sign In": "サインイン", "Sign Out": "サインアウト", "Sky": "スカイ", + "Slow": "低速", "Solarized": "ソーラライズド", "Speak": "読み上げ", "Subjects:": "主題:", "System Fonts": "システムフォント", + "TTS not supported in this device": "このデバイスではTTSがサポートされていません", "Theme Color": "テーマカラー", "Theme Mode": "テーマモード", "Translate": "翻訳", diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index e3684fe0..de9a05e8 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "여기에 사용자 정의 CSS를 입력하세요...", "Excerpts": "발췌", "Failed to import book(s): {{filenames}}": "책 가져오기 실패: {{filenames}}", + "Fast": "빠름", "Font": "글꼴", "Font & Layout": "글꼴 및 레이아웃", "Font Face": "글꼴 스타일", @@ -108,10 +109,12 @@ "Sign In": "로그인", "Sign Out": "로그아웃", "Sky": "하늘색", + "Slow": "느림", "Solarized": "솔라라이즈드", "Speak": "말하기", "Subjects:": "주제:", "System Fonts": "시스템 글꼴", + "TTS not supported in this device": "이 장치에서 TTS가 지원되지 않음", "Theme Color": "테마 색상", "Theme Mode": "테마 모드", "Translate": "번역", diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 43d7d14e..fc7869f4 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Insira seu CSS personalizado aqui...", "Excerpts": "Trechos", "Failed to import book(s): {{filenames}}": "Falha ao importar livro(s): {{filenames}}", + "Fast": "Rápido", "Font": "Fonte", "Font & Layout": "Fonte e Layout", "Font Face": "Estilo da Fonte", @@ -108,10 +109,12 @@ "Sign In": "Entrar", "Sign Out": "Sair", "Sky": "Céu", + "Slow": "Lento", "Solarized": "Solarizado", "Speak": "Falar", "Subjects:": "Assuntos:", "System Fonts": "Fontes do Sistema", + "TTS not supported in this device": "TTS não suportado neste dispositivo", "Theme Color": "Cor do Tema", "Theme Mode": "Modo do Tema", "Translate": "Traduzir", diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 2ef83557..4f81f5e3 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Введите ваш пользовательский CSS здесь...", "Excerpts": "Отрывки", "Failed to import book(s): {{filenames}}": "Не удалось импортировать книгу(и): {{filenames}}", + "Fast": "Быстро", "Font": "Шрифт", "Font & Layout": "Шрифт и макет", "Font Face": "Начертание шрифта", @@ -108,10 +109,12 @@ "Sign In": "Войти", "Sign Out": "Выйти", "Sky": "Небесный", + "Slow": "Медленно", "Solarized": "Солнечный", "Speak": "Произнести", "Subjects:": "Темы:", "System Fonts": "Системные шрифты", + "TTS not supported in this device": "TTS не поддерживается на этом устройстве", "Theme Color": "Цвет темы", "Theme Mode": "Режим темы", "Translate": "Перевести", diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 095e8fc0..d10cc6c0 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Özel CSS'nizi buraya girin...", "Excerpts": "Alıntılar", "Failed to import book(s): {{filenames}}": "Kitap(lar) içe aktarılamadı: {{filenames}}", + "Fast": "Hızlı", "Font": "Yazı Tipi", "Font & Layout": "Yazı Tipi ve Düzen", "Font Face": "Yazı Tipi Yüzü", @@ -108,10 +109,12 @@ "Sign In": "Giriş Yap", "Sign Out": "Çıkış Yap", "Sky": "Gökyüzü", + "Slow": "Yavaş", "Solarized": "Solarized", "Speak": "Konuş", "Subjects:": "Konular:", "System Fonts": "Sistem Yazı Tipleri", + "TTS not supported in this device": "Bu cihazda TTS desteklenmiyor", "Theme Color": "Tema Rengi", "Theme Mode": "Tema Modu", "Translate": "Çevir", diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index 7e38cb5e..2fd49330 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "Nhập CSS tùy chỉnh của bạn vào đây...", "Excerpts": "Trích dẫn", "Failed to import book(s): {{filenames}}": "Không thể nhập sách: {{filenames}}", + "Fast": "Nhanh", "Font": "Phông chữ", "Font & Layout": "Phông chữ & Bố cục", "Font Face": "Kiểu chữ", @@ -108,10 +109,12 @@ "Sign In": "Đăng nhập", "Sign Out": "Đăng xuất", "Sky": "Xanh trời", + "Slow": "Chậm", "Solarized": "Solarized", "Speak": "Đọc", "Subjects:": "Chủ đề:", "System Fonts": "Phông chữ hệ thống", + "TTS not supported in this device": "TTS không được hỗ trợ trên thiết bị này", "Theme Color": "Màu chủ đề", "Theme Mode": "Chế độ chủ đề", "Translate": "Dịch", diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index f595e18c..76dad697 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "在此处输入您的自定义 CSS...", "Excerpts": "摘录", "Failed to import book(s): {{filenames}}": "导入书籍失败:{{filenames}}", + "Fast": "快", "Font": "字体", "Font & Layout": "字体和布局", "Font Face": "字型", @@ -108,10 +109,12 @@ "Sign In": "登录", "Sign Out": "登出", "Sky": "天青", + "Slow": "慢", "Solarized": "日晖", "Speak": "朗读", "Subjects:": "主题", "System Fonts": "系统字体", + "TTS not supported in this device": "此设备不支持 TTS", "Theme Color": "主题颜色", "Theme Mode": "主题模式", "Translate": "翻译", diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index b6311645..6ecadbdb 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -33,6 +33,7 @@ "Enter your custom CSS here...": "在此處輸入您的自定義 CSS...", "Excerpts": "摘錄", "Failed to import book(s): {{filenames}}": "導入書籍失敗:{{filenames}}", + "Fast": "快", "Font": "字體", "Font & Layout": "字體和版面", "Font Face": "字型", @@ -108,10 +109,12 @@ "Sign In": "登入", "Sign Out": "登出", "Sky": "天青", + "Slow": "慢", "Solarized": "日暉", "Speak": "朗讀", "Subjects:": "主題", "System Fonts": "系統字體", + "TTS not supported in this device": "此設備不支持 TTS", "Theme Color": "主題顏色", "Theme Mode": "主題模式", "Translate": "翻譯", diff --git a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx index b3372331..93e439dd 100644 --- a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx +++ b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx @@ -11,7 +11,7 @@ import TTSPanel from './TTSPanel'; import TTSIcon from './TTSIcon'; const POPUP_WIDTH = 260; -const POPUP_HEIGHT = 80; +const POPUP_HEIGHT = 160; const POPUP_PADDING = 10; const TTSControl = () => { @@ -100,6 +100,14 @@ const TTSControl = () => { } }; + // rate range: 0.5 - 3, 1.0 is normal speed + const handleSetRate = async (rate: number) => { + const ttsController = ttsControllerRef.current; + if (ttsController) { + await ttsController.setRate(rate); + } + }; + const updatePanelPosition = () => { if (iconRef.current) { const rect = iconRef.current.getBoundingClientRect(); @@ -149,6 +157,7 @@ const TTSControl = () => { onBackward={handleBackward} onForward={handleForward} onStop={handleStop} + onSetRate={handleSetRate} /> )} diff --git a/apps/readest-app/src/app/reader/components/tts/TTSPanel.tsx b/apps/readest-app/src/app/reader/components/tts/TTSPanel.tsx index 3a7e071c..8bc4529b 100644 --- a/apps/readest-app/src/app/reader/components/tts/TTSPanel.tsx +++ b/apps/readest-app/src/app/reader/components/tts/TTSPanel.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { useTranslation } from '@/hooks/useTranslation'; import { MdPlayCircle, MdPauseCircle, MdFastRewind, MdFastForward, MdStop } from 'react-icons/md'; type TTSPanelProps = { @@ -7,11 +8,55 @@ type TTSPanelProps = { onBackward: () => void; onForward: () => void; onStop: () => void; + onSetRate: (rate: number) => void; }; -const TTSPanel = ({ isPlaying, onTogglePlay, onBackward, onForward, onStop }: TTSPanelProps) => { +const TTSPanel = ({ + isPlaying, + onTogglePlay, + onBackward, + onForward, + onStop, + onSetRate, +}: TTSPanelProps) => { + const _ = useTranslation(); + const [rate, setRate] = useState(1.0); + return ( -
+
+
+ { + const newRate = parseFloat(e.target.value); + setRate(newRate); + onSetRate(newRate); + }} + /> +
+ | + | + | + | + | + | + | +
+
+ {_('Slow')} + + 1.0 + 1.5 + 2.0 + + {_('Fast')} +
+