From 141c502c762d769a34060fea92d093273d469425 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Wed, 30 Apr 2025 14:52:19 +0800 Subject: [PATCH] fix: handle full CJK Unified Ideographs in search terms, closes #989 (#1002) --- .../src/app/reader/components/sidebar/SearchBar.tsx | 6 ++++-- .../src/app/reader/components/sidebar/SearchResults.tsx | 2 +- apps/readest-app/src/services/tts/WebSpeechClient.ts | 3 ++- apps/readest-app/src/utils/lang.ts | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 apps/readest-app/src/utils/lang.ts diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx index eb7b0785..f027e74d 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx @@ -9,6 +9,7 @@ import { useReaderStore } from '@/store/readerStore'; import { useTranslation } from '@/hooks/useTranslation'; import { BookSearchConfig, BookSearchResult } from '@/types/book'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; +import { isCJKStr } from '@/utils/lang'; import Dropdown from '@/components/Dropdown'; import SearchOptions from './SearchOptions'; @@ -104,8 +105,9 @@ const SearchBar: React.FC = ({ }; const exceedMinSearchTermLength = (searchTerm: string) => { - const isCJK = /[\u4e00-\u9fa5\u3040-\u30ff\uac00-\ud7af]/.test(searchTerm); - const minLength = isCJK ? MINIMUM_SEARCH_TERM_LENGTH_CJK : MINIMUM_SEARCH_TERM_LENGTH_DEFAULT; + const minLength = isCJKStr(searchTerm) + ? MINIMUM_SEARCH_TERM_LENGTH_CJK + : MINIMUM_SEARCH_TERM_LENGTH_DEFAULT; return searchTerm.length >= minLength; }; diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchResults.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchResults.tsx index 1c15b163..cb2649cc 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchResults.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchResults.tsx @@ -32,7 +32,7 @@ const SearchResultItem: React.FC = ({ >
{excerpt.pre} - {excerpt.match} + {excerpt.match} {excerpt.post}
diff --git a/apps/readest-app/src/services/tts/WebSpeechClient.ts b/apps/readest-app/src/services/tts/WebSpeechClient.ts index e9540ffe..9ee4f070 100644 --- a/apps/readest-app/src/services/tts/WebSpeechClient.ts +++ b/apps/readest-app/src/services/tts/WebSpeechClient.ts @@ -2,6 +2,7 @@ import { getUserLocale } from '@/utils/misc'; import { TTSClient, TTSMessageEvent, TTSVoice } from './TTSClient'; import { AsyncQueue } from '@/utils/queue'; import { findSSMLMark, parseSSMLLang, parseSSMLMarks } from '@/utils/ssml'; +import { isCJKStr } from '@/utils/lang'; import { TTSGranularity } from '@/types/view'; import { TTSUtils } from './TTSUtils'; @@ -123,7 +124,7 @@ async function* speakWithMarks( const isCJK = (lang: string | null) => { const cjkLangs = ['zh', 'ja', 'kr']; if (lang && cjkLangs.some((cjk) => lang.startsWith(cjk))) return true; - return /[\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]/.test(plainText); + return isCJKStr(plainText); }; if (!isCJK(lang)) { diff --git a/apps/readest-app/src/utils/lang.ts b/apps/readest-app/src/utils/lang.ts new file mode 100644 index 00000000..ea05970e --- /dev/null +++ b/apps/readest-app/src/utils/lang.ts @@ -0,0 +1,3 @@ +export const isCJKStr = (str: string) => { + return /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(str ?? ''); +};