From 2b9132b4a878f820f8dd2a7abe36d2ab5052c8b8 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Thu, 4 Sep 2025 15:38:17 +0800 Subject: [PATCH] feat(translator): preprocess some common mistranslated publishing terms (#1964) --- apps/readest-app/src/hooks/useTranslator.ts | 6 ++-- .../src/services/translators/index.ts | 1 + .../src/services/translators/preprocess.ts | 31 +++++++++++++++++++ .../src/services/translators/types.ts | 1 + apps/readest-app/src/utils/walk.ts | 6 +++- 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 apps/readest-app/src/services/translators/preprocess.ts diff --git a/apps/readest-app/src/hooks/useTranslator.ts b/apps/readest-app/src/hooks/useTranslator.ts index cae6aaed..d50f9c81 100644 --- a/apps/readest-app/src/hooks/useTranslator.ts +++ b/apps/readest-app/src/hooks/useTranslator.ts @@ -1,7 +1,8 @@ import { useState, useCallback, useEffect } from 'react'; import { useAuth } from '@/context/AuthContext'; import { ErrorCodes, getTranslator, getTranslators, TranslatorName } from '@/services/translators'; -import { getFromCache, storeInCache, polish, UseTranslatorOptions } from '@/services/translators'; +import { getFromCache, storeInCache, UseTranslatorOptions } from '@/services/translators'; +import { polish, preprocess } from '@/services/translators'; import { eventDispatcher } from '@/utils/event'; import { useTranslation } from './useTranslation'; @@ -10,6 +11,7 @@ export function useTranslator({ sourceLang = 'AUTO', targetLang = 'EN', enablePolishing = true, + enablePreprocessing = true, }: UseTranslatorOptions = {}) { const _ = useTranslation(); const { token } = useAuth(); @@ -42,7 +44,7 @@ export function useTranslator({ const sourceLanguage = options?.source || sourceLang; const targetLanguage = options?.target || targetLang; const useCache = options?.useCache ?? false; - const textsToTranslate = input; + const textsToTranslate = enablePreprocessing ? preprocess(input) : input; if (textsToTranslate.length === 0 || textsToTranslate.every((t) => !t?.trim())) { return textsToTranslate; diff --git a/apps/readest-app/src/services/translators/index.ts b/apps/readest-app/src/services/translators/index.ts index 1f9b7b4c..aa8ac855 100644 --- a/apps/readest-app/src/services/translators/index.ts +++ b/apps/readest-app/src/services/translators/index.ts @@ -1,4 +1,5 @@ export * from './types'; export * from './cache'; export * from './polish'; +export * from './preprocess'; export * from './providers'; diff --git a/apps/readest-app/src/services/translators/preprocess.ts b/apps/readest-app/src/services/translators/preprocess.ts new file mode 100644 index 00000000..d26e109a --- /dev/null +++ b/apps/readest-app/src/services/translators/preprocess.ts @@ -0,0 +1,31 @@ +export type Preprocessor = (text: string) => string; +export type TextSubstitutions = Record; + +const defaultSubstitutions: TextSubstitutions = { + Cover: 'The Cover', + Dedication: 'Dedication Page', + Acknowledgements: 'The Acknowledgements', +}; + +export const basicSubstitute = (text: string, substitutions: TextSubstitutions): string => { + const allSubstitutions = { ...defaultSubstitutions, ...substitutions }; + + if (Object.keys(allSubstitutions).length === 0) { + return text; + } + + if (allSubstitutions[text]) { + return allSubstitutions[text]; + } + + return text; +}; + +export function createPreprocessor(substitutions: TextSubstitutions = {}): Preprocessor { + return (text: string) => basicSubstitute(text, substitutions); +} + +export function preprocess(texts: string[], substitutions: TextSubstitutions = {}): string[] { + const preprocessor = createPreprocessor(substitutions); + return texts.map(preprocessor); +} diff --git a/apps/readest-app/src/services/translators/types.ts b/apps/readest-app/src/services/translators/types.ts index 513e1b25..2590858a 100644 --- a/apps/readest-app/src/services/translators/types.ts +++ b/apps/readest-app/src/services/translators/types.ts @@ -23,6 +23,7 @@ export interface UseTranslatorOptions { sourceLang?: string; targetLang?: string; enablePolishing?: boolean; + enablePreprocessing?: boolean; } export const ErrorCodes = { diff --git a/apps/readest-app/src/utils/walk.ts b/apps/readest-app/src/utils/walk.ts index cd710edb..8809b096 100644 --- a/apps/readest-app/src/utils/walk.ts +++ b/apps/readest-app/src/utils/walk.ts @@ -30,7 +30,11 @@ export const walkTextNodes = (root: HTMLElement, rejectTags: string[] = []): HTM if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) { return true; } - if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === 'SPAN') { + if ( + node.nodeType === Node.ELEMENT_NODE && + (node as HTMLElement).tagName === 'SPAN' && + node.textContent?.trim() + ) { return true; } return false;