forked from akai/readest
feat(cjk): add an option to replace quotation marks in vertical layout for CJK languages (#2511)
This commit is contained in:
@@ -672,5 +672,8 @@
|
||||
"Current email": "البريد الإلكتروني الحالي",
|
||||
"Update Email": "تحديث البريد الإلكتروني",
|
||||
"All": "الكل",
|
||||
"Unable to open book": "غير قادر على فتح الكتاب"
|
||||
"Unable to open book": "غير قادر على فتح الكتاب",
|
||||
"Punctuation": "علامات الترقيم",
|
||||
"Replace Quotation Marks": "استبدال علامات الاقتباس",
|
||||
"Enabled only in vertical layout.": "مفعل فقط في التخطيط الرأسي."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "বর্তমান ইমেল",
|
||||
"Update Email": "ইমেল আপডেট করুন",
|
||||
"All": "সব",
|
||||
"Unable to open book": "বই খুলতে অক্ষম"
|
||||
"Unable to open book": "বই খুলতে অক্ষম",
|
||||
"Punctuation": "বিরামচিহ্ন",
|
||||
"Replace Quotation Marks": "উদ্ধৃতি চিহ্ন প্রতিস্থাপন করুন",
|
||||
"Enabled only in vertical layout.": "শুধুমাত্র উল্লম্ব বিন্যাসে সক্রিয়।"
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "མིག་སྔའི་ཡིག་འཕྲིན།",
|
||||
"Update Email": "ཡིག་འཕྲིན་གསར་བསྒྱུར།",
|
||||
"All": "ཆེན་མོ།",
|
||||
"Unable to open book": "དེབ་ཀྱི་སྤྱོད་བྱས་མ་ཐུབ།"
|
||||
"Unable to open book": "དེབ་ཀྱི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"Punctuation": "ཚིག་གྲུབ།",
|
||||
"Replace Quotation Marks": "འདྲེན་འབྲེལ་མཐུད་ཐིག་བརྗེ་བ།",
|
||||
"Enabled only in vertical layout.": "གཡས་སྒྲིག་ནང་མིང་བརྗེ་བ།"
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "Aktuelle E-Mail",
|
||||
"Update Email": "E-Mail aktualisieren",
|
||||
"All": "Alle",
|
||||
"Unable to open book": "Buch kann nicht geöffnet werden"
|
||||
"Unable to open book": "Buch kann nicht geöffnet werden",
|
||||
"Punctuation": "Interpunktion",
|
||||
"Replace Quotation Marks": "Anführungszeichen ersetzen",
|
||||
"Enabled only in vertical layout.": "Nur im vertikalen Layout aktiviert."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "Τρέχον email",
|
||||
"Update Email": "Ενημέρωση email",
|
||||
"All": "Όλα",
|
||||
"Unable to open book": "Αδύνατη η άνοιγμα του βιβλίου"
|
||||
"Unable to open book": "Αδύνατη η άνοιγμα του βιβλίου",
|
||||
"Punctuation": "Στίξη",
|
||||
"Replace Quotation Marks": "Αντικατάσταση εισαγωγικών",
|
||||
"Enabled only in vertical layout.": "Ενεργοποιημένο μόνο σε κάθετη διάταξη."
|
||||
}
|
||||
|
||||
@@ -660,5 +660,8 @@
|
||||
"Current email": "Correo electrónico actual",
|
||||
"Update Email": "Actualizar correo electrónico",
|
||||
"All": "Todos",
|
||||
"Unable to open book": "No se puede abrir el libro"
|
||||
"Unable to open book": "No se puede abrir el libro",
|
||||
"Punctuation": "Signos de puntuación",
|
||||
"Replace Quotation Marks": "Reemplazar comillas",
|
||||
"Enabled only in vertical layout.": "Habilitado solo en diseño vertical."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "ایمیل فعلی",
|
||||
"Update Email": "بهروزرسانی ایمیل",
|
||||
"All": "همه",
|
||||
"Unable to open book": "قادر به باز کردن کتاب نیست"
|
||||
"Unable to open book": "قادر به باز کردن کتاب نیست",
|
||||
"Punctuation": "علامت نگارشی",
|
||||
"Replace Quotation Marks": "جایگزینی علامت نقل قول",
|
||||
"Enabled only in vertical layout.": "فقط در طرح عمودی فعال است."
|
||||
}
|
||||
|
||||
@@ -660,5 +660,8 @@
|
||||
"Current email": "E-mail actuel",
|
||||
"Update Email": "Mettre à jour l’e-mail",
|
||||
"All": "Tous",
|
||||
"Unable to open book": "Impossible d'ouvrir le livre"
|
||||
"Unable to open book": "Impossible d'ouvrir le livre",
|
||||
"Punctuation": "Ponctuation",
|
||||
"Replace Quotation Marks": "Remplacer les guillemets",
|
||||
"Enabled only in vertical layout.": "Activé uniquement en disposition verticale."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "वर्तमान ईमेल",
|
||||
"Update Email": "ईमेल अपडेट करें",
|
||||
"All": "सभी",
|
||||
"Unable to open book": "पुस्तक खोलने में असमर्थ"
|
||||
"Unable to open book": "पुस्तक खोलने में असमर्थ",
|
||||
"Punctuation": "विराम चिह्न",
|
||||
"Replace Quotation Marks": "उद्धरण चिह्न बदलें",
|
||||
"Enabled only in vertical layout.": "केवल ऊर्ध्वाधर लेआउट में सक्षम।"
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "Email saat ini",
|
||||
"Update Email": "Perbarui email",
|
||||
"All": "Semua",
|
||||
"Unable to open book": "Tidak dapat membuka buku"
|
||||
"Unable to open book": "Tidak dapat membuka buku",
|
||||
"Punctuation": "Tanda Baca",
|
||||
"Replace Quotation Marks": "Ganti Tanda Kutip",
|
||||
"Enabled only in vertical layout.": "Hanya diaktifkan dalam tata letak vertikal."
|
||||
}
|
||||
|
||||
@@ -660,5 +660,8 @@
|
||||
"Current email": "Email attuale",
|
||||
"Update Email": "Aggiorna email",
|
||||
"All": "Tutti",
|
||||
"Unable to open book": "Impossibile aprire il libro"
|
||||
"Unable to open book": "Impossibile aprire il libro",
|
||||
"Punctuation": "Segni di punteggiatura",
|
||||
"Replace Quotation Marks": "Sostituisci le virgolette",
|
||||
"Enabled only in vertical layout.": "Abilitato solo in layout verticale."
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "現在のメールアドレス",
|
||||
"Update Email": "メールを更新",
|
||||
"All": "すべて",
|
||||
"Unable to open book": "本を開くことができません"
|
||||
"Unable to open book": "本を開くことができません",
|
||||
"Punctuation": "句読点",
|
||||
"Replace Quotation Marks": "引用符を置き換える",
|
||||
"Enabled only in vertical layout.": "縦書きレイアウトでのみ有効です。"
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "현재 이메일",
|
||||
"Update Email": "이메일 업데이트",
|
||||
"All": "전체",
|
||||
"Unable to open book": "책을 열 수 없습니다"
|
||||
"Unable to open book": "책을 열 수 없습니다",
|
||||
"Punctuation": "구두점",
|
||||
"Replace Quotation Marks": "인용 부호 바꾸기",
|
||||
"Enabled only in vertical layout.": "세로 레이아웃에서만 활성화됩니다."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "Huidig e-mailadres",
|
||||
"Update Email": "E-mail bijwerken",
|
||||
"All": "Alles",
|
||||
"Unable to open book": "Kan boek niet openen"
|
||||
"Unable to open book": "Kan boek niet openen",
|
||||
"Punctuation": "Interpunctie",
|
||||
"Replace Quotation Marks": "Aanhalingstekens vervangen",
|
||||
"Enabled only in vertical layout.": "Alleen ingeschakeld in verticale lay-out."
|
||||
}
|
||||
|
||||
@@ -664,5 +664,8 @@
|
||||
"Current email": "Obecny e-mail",
|
||||
"Update Email": "Zaktualizuj e-mail",
|
||||
"All": "Wszystkie",
|
||||
"Unable to open book": "Nie można otworzyć książki"
|
||||
"Unable to open book": "Nie można otworzyć książki",
|
||||
"Punctuation": "Interpunkcja",
|
||||
"Replace Quotation Marks": "Zamień cudzysłowy",
|
||||
"Enabled only in vertical layout.": "Włączone tylko w układzie pionowym."
|
||||
}
|
||||
|
||||
@@ -660,5 +660,8 @@
|
||||
"Current email": "E-mail atual",
|
||||
"Update Email": "Atualizar e-mail",
|
||||
"All": "Todos",
|
||||
"Unable to open book": "Não foi possível abrir o livro"
|
||||
"Unable to open book": "Não foi possível abrir o livro",
|
||||
"Punctuation": "Pontuação",
|
||||
"Replace Quotation Marks": "Substituir Aspas",
|
||||
"Enabled only in vertical layout.": "Habilitado apenas no layout vertical."
|
||||
}
|
||||
|
||||
@@ -664,5 +664,8 @@
|
||||
"Current email": "Текущий адрес электронной почты",
|
||||
"Update Email": "Обновить электронную почту",
|
||||
"All": "Все",
|
||||
"Unable to open book": "Не удалось открыть книгу"
|
||||
"Unable to open book": "Не удалось открыть книгу",
|
||||
"Punctuation": "Пунктуация",
|
||||
"Replace Quotation Marks": "Заменить кавычки",
|
||||
"Enabled only in vertical layout.": "Включено только в вертикальной раскладке."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "වත්මන් විද්යුත් තැපැල්",
|
||||
"Update Email": "විද්යුත් තැපැල් යාවත්කාලීන කරන්න",
|
||||
"All": "සියල්ල",
|
||||
"Unable to open book": "පොත විවෘත කිරීමට නොහැක"
|
||||
"Unable to open book": "පොත විවෘත කිරීමට නොහැක",
|
||||
"Punctuation": "ලකුණු",
|
||||
"Replace Quotation Marks": "උද්ධෘත ලකුණු ප්රතිස්ථාපනය කරන්න",
|
||||
"Enabled only in vertical layout.": "සිරස් ආකෘතියේ පමණක් සක්රීයයි."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "Nuvarande e-post",
|
||||
"Update Email": "Uppdatera e-post",
|
||||
"All": "Alla",
|
||||
"Unable to open book": "Kunde inte öppna bok"
|
||||
"Unable to open book": "Kunde inte öppna bok",
|
||||
"Punctuation": "Interpunktion",
|
||||
"Replace Quotation Marks": "Ersätt citattecken",
|
||||
"Enabled only in vertical layout.": "Aktiverad endast i vertikal layout."
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "தற்போதைய மின்னஞ்சல்",
|
||||
"Update Email": "மின்னஞ்சல் புதுப்பிக்கவும்",
|
||||
"All": "அனைத்து",
|
||||
"Unable to open book": "புத்தகத்தைத் திறக்க முடியவில்லை"
|
||||
"Unable to open book": "புத்தகத்தைத் திறக்க முடியவில்லை",
|
||||
"Punctuation": "விருத்தி",
|
||||
"Replace Quotation Marks": "உதயம்சுட்டிகளை மாற்றவும்",
|
||||
"Enabled only in vertical layout.": "செங்குத்து அமைப்பில் மட்டுமே இயலுமைப்படுத்தப்பட்டது."
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "อีเมลปัจจุบัน",
|
||||
"Update Email": "อัปเดตอีเมล",
|
||||
"All": "ทั้งหมด",
|
||||
"Unable to open book": "ไม่สามารถเปิดหนังสือได้"
|
||||
"Unable to open book": "ไม่สามารถเปิดหนังสือได้",
|
||||
"Punctuation": "เครื่องหมายวรรคตอน",
|
||||
"Replace Quotation Marks": "แทนที่เครื่องหมายคำพูด",
|
||||
"Enabled only in vertical layout.": "เปิดใช้งานเฉพาะในเค้าโครงแนวตั้งเท่านั้น"
|
||||
}
|
||||
|
||||
@@ -656,5 +656,8 @@
|
||||
"Current email": "Mevcut e-posta",
|
||||
"Update Email": "E-postayı güncelle",
|
||||
"All": "Tümü",
|
||||
"Unable to open book": "Kitap açılamıyor"
|
||||
"Unable to open book": "Kitap açılamıyor",
|
||||
"Punctuation": "Noktalama İşaretleri",
|
||||
"Replace Quotation Marks": "Tırnak İşaretlerini Değiştir",
|
||||
"Enabled only in vertical layout.": "Yalnızca dikey düzenle etkinleştirildi."
|
||||
}
|
||||
|
||||
@@ -664,5 +664,8 @@
|
||||
"Current email": "Поточна електронна пошта",
|
||||
"Update Email": "Оновити електронну пошту",
|
||||
"All": "Всі",
|
||||
"Unable to open book": "Не вдалося відкрити книгу"
|
||||
"Unable to open book": "Не вдалося відкрити книгу",
|
||||
"Punctuation": "Пунктуація",
|
||||
"Replace Quotation Marks": "Замінити лапки",
|
||||
"Enabled only in vertical layout.": "Активовано лише у вертикальному макеті."
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "Email hiện tại",
|
||||
"Update Email": "Cập nhật email",
|
||||
"All": "Tất cả",
|
||||
"Unable to open book": "Không thể mở sách"
|
||||
"Unable to open book": "Không thể mở sách",
|
||||
"Punctuation": "Dấu câu",
|
||||
"Replace Quotation Marks": "Thay thế dấu ngoặc kép",
|
||||
"Enabled only in vertical layout.": "Chỉ bật trong bố cục dọc."
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "当前邮箱",
|
||||
"Update Email": "更新邮箱",
|
||||
"All": "全部",
|
||||
"Unable to open book": "无法打开书籍"
|
||||
"Unable to open book": "无法打开书籍",
|
||||
"Punctuation": "标点符号",
|
||||
"Replace Quotation Marks": "替换引号",
|
||||
"Enabled only in vertical layout.": "仅在竖排布局中启用"
|
||||
}
|
||||
|
||||
@@ -652,5 +652,8 @@
|
||||
"Current email": "當前電子郵件",
|
||||
"Update Email": "更新電子郵件",
|
||||
"All": "全部",
|
||||
"Unable to open book": "無法打開書籍"
|
||||
"Unable to open book": "無法打開書籍",
|
||||
"Punctuation": "標點符號",
|
||||
"Replace Quotation Marks": "替換引號",
|
||||
"Enabled only in vertical layout.": "僅在直排佈局中啟用"
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ export async function POST(request: NextRequest) {
|
||||
ui_mode: embedded ? 'embedded' : 'hosted',
|
||||
customer: customerId,
|
||||
mode: planType === 'subscription' ? 'subscription' : 'payment',
|
||||
allow_promotion_codes: true,
|
||||
line_items: [
|
||||
{
|
||||
price: priceId,
|
||||
|
||||
@@ -46,7 +46,6 @@ import {
|
||||
} from '../utils/iframeEventHandlers';
|
||||
import { getMaxInlineSize } from '@/utils/config';
|
||||
import { getDirFromUILanguage } from '@/utils/rtl';
|
||||
import { isCJKLang } from '@/utils/lang';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
import { TransformContext } from '@/services/transformers/types';
|
||||
import { transformContent } from '@/services/transformService';
|
||||
@@ -56,6 +55,8 @@ import { useBookCoverAutoSave } from '../hooks/useAutoSaveBookCover';
|
||||
import { manageSyntaxHighlighting } from '@/utils/highlightjs';
|
||||
import { getViewInsets } from '@/utils/insets';
|
||||
import { removeTabIndex } from '@/utils/a11y';
|
||||
import { isCJKLang } from '@/utils/lang';
|
||||
import { getLocale } from '@/utils/misc';
|
||||
import Spinner from '@/components/Spinner';
|
||||
import KOSyncConflictResolver from './KOSyncResolver';
|
||||
|
||||
@@ -137,6 +138,7 @@ const FoliateViewer: React.FC<{
|
||||
width,
|
||||
height,
|
||||
primaryLanguage: bookData.book?.primaryLanguage,
|
||||
userLocale: getLocale(),
|
||||
content: data,
|
||||
transformers: [
|
||||
'style',
|
||||
|
||||
@@ -2,10 +2,11 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { getOSPlatform } from '@/utils/misc';
|
||||
import { getLocale, getOSPlatform } from '@/utils/misc';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
import { getTextFromRange, TextSelection } from '@/utils/sel';
|
||||
import { transformContent } from '@/services/transformService';
|
||||
import { TransformContext } from '@/services/transformers/types';
|
||||
|
||||
export const useTextSelector = (
|
||||
bookKey: string,
|
||||
@@ -31,9 +32,10 @@ export const useTextSelector = (
|
||||
return sel && sel.toString().trim().length > 0 && sel.rangeCount > 0;
|
||||
};
|
||||
|
||||
const transformCtx = {
|
||||
const transformCtx: TransformContext = {
|
||||
bookKey,
|
||||
viewSettings: getViewSettings(bookKey)!,
|
||||
userLocale: getLocale(),
|
||||
content: '',
|
||||
transformers: ['punctuation'],
|
||||
reversePunctuationTransform: true,
|
||||
|
||||
@@ -155,7 +155,7 @@ const PlansComparison: React.FC<PlansComparisonProps> = ({
|
||||
plan={plan}
|
||||
comingSoon={false}
|
||||
isUserPlan={plan.plan === userPlan}
|
||||
upgradable={index > userPlanIndex}
|
||||
upgradable={index > 0 && (index > userPlanIndex || userPlan === 'purchase')}
|
||||
index={index}
|
||||
currentPlanIndex={currentPlanIndex}
|
||||
onSubscribe={onSubscribe}
|
||||
|
||||
@@ -11,7 +11,6 @@ import { getStyles } from '@/utils/style';
|
||||
import { getMaxInlineSize } from '@/utils/config';
|
||||
import { saveSysSettings, saveViewSettings } from '@/helpers/settings';
|
||||
import { SettingsPanelPanelProp } from './SettingsDialog';
|
||||
import { RELOAD_BEFORE_SAVED_TIMEOUT_MS } from '@/services/constants';
|
||||
import NumberInput from './NumberInput';
|
||||
|
||||
const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }) => {
|
||||
@@ -143,10 +142,9 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
|
||||
useEffect(() => {
|
||||
if (viewSettings.allowScript === allowScript) return;
|
||||
saveViewSettings(envConfig, bookKey, 'allowScript', allowScript, true, false);
|
||||
setTimeout(() => {
|
||||
saveViewSettings(envConfig, bookKey, 'allowScript', allowScript, true, false).then(() => {
|
||||
recreateViewer(envConfig, bookKey);
|
||||
}, RELOAD_BEFORE_SAVED_TIMEOUT_MS);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [allowScript]);
|
||||
|
||||
|
||||
@@ -8,12 +8,9 @@ import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { saveViewSettings } from '@/helpers/settings';
|
||||
import { getTranslators } from '@/services/translators';
|
||||
import { useResetViewSettings } from '@/hooks/useResetSettings';
|
||||
import {
|
||||
RELOAD_BEFORE_SAVED_TIMEOUT_MS,
|
||||
TRANSLATED_LANGS,
|
||||
TRANSLATOR_LANGS,
|
||||
} from '@/services/constants';
|
||||
import { TRANSLATED_LANGS, TRANSLATOR_LANGS } from '@/services/constants';
|
||||
import { SettingsPanelPanelProp } from './SettingsDialog';
|
||||
import { isCJKEnv } from '@/utils/misc';
|
||||
import Select from '@/components/Select';
|
||||
|
||||
const LangPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }) => {
|
||||
@@ -30,6 +27,9 @@ const LangPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
|
||||
const [translateTargetLang, setTranslateTargetLang] = useState(viewSettings.translateTargetLang);
|
||||
const [showTranslateSource, setShowTranslateSource] = useState(viewSettings.showTranslateSource);
|
||||
const [ttsReadAloudText, setTtsReadAloudText] = useState(viewSettings.ttsReadAloudText);
|
||||
const [replaceQuotationMarks, setReplaceQuotationMarks] = useState(
|
||||
viewSettings.replaceQuotationMarks,
|
||||
);
|
||||
|
||||
const resetToDefaults = useResetViewSettings();
|
||||
|
||||
@@ -41,6 +41,7 @@ const LangPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
|
||||
translateTargetLang: setTranslateTargetLang,
|
||||
showTranslateSource: setShowTranslateSource,
|
||||
ttsReadAloudText: setTtsReadAloudText,
|
||||
replaceQuotationMarks: setReplaceQuotationMarks,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -143,17 +144,33 @@ const LangPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
|
||||
|
||||
useEffect(() => {
|
||||
if (translationEnabled === viewSettings.translationEnabled) return;
|
||||
saveViewSettings(envConfig, bookKey, 'translationEnabled', translationEnabled, true, false);
|
||||
if (!showTranslateSource && translationEnabled) {
|
||||
setTimeout(() => recreateViewer(envConfig, bookKey), RELOAD_BEFORE_SAVED_TIMEOUT_MS);
|
||||
}
|
||||
saveViewSettings(
|
||||
envConfig,
|
||||
bookKey,
|
||||
'translationEnabled',
|
||||
translationEnabled,
|
||||
true,
|
||||
false,
|
||||
).then(() => {
|
||||
if (!showTranslateSource && translationEnabled) {
|
||||
recreateViewer(envConfig, bookKey);
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [translationEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showTranslateSource === viewSettings.showTranslateSource) return;
|
||||
saveViewSettings(envConfig, bookKey, 'showTranslateSource', showTranslateSource, false, false);
|
||||
setTimeout(() => recreateViewer(envConfig, bookKey), RELOAD_BEFORE_SAVED_TIMEOUT_MS);
|
||||
saveViewSettings(
|
||||
envConfig,
|
||||
bookKey,
|
||||
'showTranslateSource',
|
||||
showTranslateSource,
|
||||
false,
|
||||
false,
|
||||
).then(() => {
|
||||
recreateViewer(envConfig, bookKey);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showTranslateSource]);
|
||||
|
||||
@@ -163,6 +180,21 @@ const LangPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [ttsReadAloudText]);
|
||||
|
||||
useEffect(() => {
|
||||
if (replaceQuotationMarks === viewSettings.replaceQuotationMarks) return;
|
||||
saveViewSettings(
|
||||
envConfig,
|
||||
bookKey,
|
||||
'replaceQuotationMarks',
|
||||
replaceQuotationMarks,
|
||||
true,
|
||||
false,
|
||||
).then(() => {
|
||||
recreateViewer(envConfig, bookKey);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [replaceQuotationMarks]);
|
||||
|
||||
return (
|
||||
<div className={clsx('my-4 w-full space-y-6')}>
|
||||
<div className='w-full'>
|
||||
@@ -234,6 +266,28 @@ const LangPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isCJKEnv() && (
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>{_('Punctuation')}</h2>
|
||||
<div className='card border-base-200 bg-base-100 border shadow'>
|
||||
<div className='divide-base-200'>
|
||||
<div className='config-item !h-16'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<span className=''>{_('Replace Quotation Marks')}</span>
|
||||
<span className='text-xs'>{_('Enabled only in vertical layout.')}</span>
|
||||
</div>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
checked={replaceQuotationMarks}
|
||||
onChange={() => setReplaceQuotationMarks(!replaceQuotationMarks)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ import { getMaxInlineSize } from '@/utils/config';
|
||||
import { lockScreenOrientation } from '@/utils/bridge';
|
||||
import { saveViewSettings } from '@/helpers/settings';
|
||||
import { getBookDirFromWritingMode, getBookLangCode } from '@/utils/book';
|
||||
import { MIGHT_BE_RTL_LANGS, RELOAD_BEFORE_SAVED_TIMEOUT_MS } from '@/services/constants';
|
||||
import { MIGHT_BE_RTL_LANGS } from '@/services/constants';
|
||||
import { SettingsPanelPanelProp } from './SettingsDialog';
|
||||
import Select from '@/components/Select';
|
||||
import NumberInput from './NumberInput';
|
||||
@@ -273,18 +273,19 @@ const LayoutPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRese
|
||||
} else {
|
||||
viewSettings.vertical = false;
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'writingMode', writingMode, true);
|
||||
if (view) {
|
||||
view.renderer.setStyles?.(getStyles(viewSettings));
|
||||
view.book.dir = getBookDirFromWritingMode(writingMode);
|
||||
}
|
||||
if (
|
||||
prevWritingMode !== writingMode &&
|
||||
(['horizontal-rl', 'vertical-rl'].includes(writingMode) ||
|
||||
['horizontal-rl', 'vertical-rl'].includes(prevWritingMode))
|
||||
) {
|
||||
setTimeout(() => recreateViewer(envConfig, bookKey), RELOAD_BEFORE_SAVED_TIMEOUT_MS);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'writingMode', writingMode, true).then(() => {
|
||||
if (view) {
|
||||
view.renderer.setStyles?.(getStyles(viewSettings));
|
||||
view.book.dir = getBookDirFromWritingMode(writingMode);
|
||||
}
|
||||
if (
|
||||
prevWritingMode !== writingMode &&
|
||||
(['horizontal-rl', 'vertical-rl'].includes(writingMode) ||
|
||||
['horizontal-rl', 'vertical-rl'].includes(prevWritingMode))
|
||||
) {
|
||||
recreateViewer(envConfig, bookKey);
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [writingMode]);
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ export const saveViewSettings = async <K extends keyof ViewSettings>(
|
||||
const { getView, getViewSettings, setViewSettings } = useReaderStore.getState();
|
||||
const { getConfig, saveConfig } = useBookDataStore.getState();
|
||||
const viewSettings = getViewSettings(bookKey);
|
||||
const config = getConfig(bookKey);
|
||||
if (bookKey && viewSettings && viewSettings[key] !== value) {
|
||||
viewSettings[key] = value;
|
||||
if (applyStyles) {
|
||||
@@ -33,9 +32,12 @@ export const saveViewSettings = async <K extends keyof ViewSettings>(
|
||||
await saveSettings(envConfig, settings);
|
||||
}
|
||||
|
||||
if (bookKey && config && viewSettings) {
|
||||
if (bookKey && viewSettings) {
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
await saveConfig(envConfig, bookKey, config, settings);
|
||||
const config = getConfig(bookKey);
|
||||
if (config) {
|
||||
await saveConfig(envConfig, bookKey, config, settings);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ export const DEFAULT_BOOK_LAYOUT: BookLayout = {
|
||||
writingMode: 'auto',
|
||||
vertical: false,
|
||||
rtl: false,
|
||||
replaceQuotationMarks: true,
|
||||
scrollingOverlap: 0,
|
||||
allowScript: false,
|
||||
};
|
||||
@@ -607,8 +608,6 @@ export const SYNC_NOTES_INTERVAL_SEC = 5;
|
||||
export const SYNC_BOOKS_INTERVAL_SEC = 5;
|
||||
export const CHECK_UPDATE_INTERVAL_SEC = 24 * 60 * 60;
|
||||
|
||||
export const RELOAD_BEFORE_SAVED_TIMEOUT_MS = 300;
|
||||
|
||||
export const MAX_ZOOM_LEVEL = 500;
|
||||
export const MIN_ZOOM_LEVEL = 50;
|
||||
export const ZOOM_STEP = 10;
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
import type { Transformer } from './types';
|
||||
|
||||
const punctuationMap: Record<string, string> = {
|
||||
const punctuationMapHans: Record<string, string> = {
|
||||
'“': '﹃',
|
||||
'”': '﹄',
|
||||
'‘': '﹁',
|
||||
'’': '﹂',
|
||||
};
|
||||
|
||||
const punctuationMapHant: Record<string, string> = {
|
||||
'“': '﹁',
|
||||
'”': '﹂',
|
||||
'‘': '﹃',
|
||||
'’': '﹄',
|
||||
};
|
||||
|
||||
export const punctuationTransformer: Transformer = {
|
||||
name: 'punctuation',
|
||||
|
||||
transform: async (ctx) => {
|
||||
const shouldTransform = ctx.viewSettings.vertical === true;
|
||||
const shouldTransform = ctx.viewSettings.vertical && ctx.viewSettings.replaceQuotationMarks;
|
||||
if (!shouldTransform) return ctx.content;
|
||||
|
||||
let result = ctx.content;
|
||||
const traditionalChineseLocales = ['zh-Hant', 'zh-TW', 'zh_TW'];
|
||||
let punctuationMap: Record<string, string> = punctuationMapHans;
|
||||
if (
|
||||
traditionalChineseLocales.includes(ctx.primaryLanguage || '') ||
|
||||
traditionalChineseLocales.includes(ctx.userLocale)
|
||||
) {
|
||||
punctuationMap = punctuationMapHant;
|
||||
}
|
||||
for (const [original, vertical] of Object.entries(punctuationMap)) {
|
||||
if (ctx.reversePunctuationTransform) {
|
||||
result = result.replace(new RegExp(vertical, 'g'), original);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ViewSettings } from '@/types/book';
|
||||
export type TransformContext = {
|
||||
bookKey: string;
|
||||
viewSettings: ViewSettings;
|
||||
userLocale: string;
|
||||
primaryLanguage?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
|
||||
@@ -112,6 +112,7 @@ export interface BookLayout {
|
||||
writingMode: WritingMode;
|
||||
vertical: boolean;
|
||||
rtl: boolean;
|
||||
replaceQuotationMarks: boolean;
|
||||
scrollingOverlap: number;
|
||||
allowScript: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user